forked from M-Labs/nac3
core: irrt ErrorContext
This commit is contained in:
parent
9e78139373
commit
8863cd64a9
|
@ -163,7 +163,10 @@
|
|||
clippy
|
||||
pre-commit
|
||||
rustfmt
|
||||
rust-analyzer
|
||||
];
|
||||
# https://nixos.wiki/wiki/Rust#Shell.nix_example
|
||||
RUST_SRC_PATH = "${pkgs.rust.packages.stable.rustPlatform.rustLibSrc}";
|
||||
};
|
||||
devShells.x86_64-linux.msys2 = pkgs.mkShell {
|
||||
name = "nac3-dev-shell-msys2";
|
||||
|
|
|
@ -0,0 +1,69 @@
|
|||
#pragma once
|
||||
|
||||
#include "int_defs.hpp"
|
||||
#include "utils.hpp"
|
||||
|
||||
namespace {
|
||||
// nac3core's "str" struct type definition
|
||||
template <typename SizeT>
|
||||
struct Str {
|
||||
const char* content;
|
||||
SizeT length;
|
||||
};
|
||||
|
||||
struct ErrorContext {
|
||||
const char* message_template; // MUST BE `&'static`
|
||||
uint64_t param1;
|
||||
uint64_t param2;
|
||||
uint64_t param3;
|
||||
|
||||
void initialize() {
|
||||
clear_error();
|
||||
}
|
||||
|
||||
void clear_error() {
|
||||
// Point the message_template to an empty str. Don't set it to nullptr as a sentinel
|
||||
set_error("");
|
||||
}
|
||||
|
||||
void set_error(const char* message, uint64_t param1 = 0, uint64_t param2 = 0, uint64_t param3 = 0) {
|
||||
this->message_template = message;
|
||||
this->param1 = param1;
|
||||
this->param2 = param2;
|
||||
this->param3 = param3;
|
||||
}
|
||||
|
||||
bool has_error() {
|
||||
return !cstr_utils::is_empty(message_template);
|
||||
}
|
||||
|
||||
template <typename SizeT>
|
||||
void set_error_str(Str<SizeT> *dst_str) {
|
||||
dst_str->content = message_template;
|
||||
dst_str->length = (SizeT) cstr_utils::length(message_template);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
extern "C" {
|
||||
|
||||
void __nac3_error_context_initialize(ErrorContext* errctx) {
|
||||
errctx->initialize();
|
||||
}
|
||||
|
||||
uint8_t __nac3_error_context_has_no_error(ErrorContext* errctx) {
|
||||
return !errctx->has_error();
|
||||
}
|
||||
|
||||
void __nac3_error_context_get_error_str(ErrorContext* errctx, Str<int32_t> *dst_str) {
|
||||
errctx->set_error_str<int32_t>(dst_str);
|
||||
}
|
||||
|
||||
void __nac3_error_context_get_error_str64(ErrorContext* errctx, Str<int64_t> *dst_str) {
|
||||
errctx->set_error_str<int64_t>(dst_str);
|
||||
}
|
||||
|
||||
void __nac3_error_dummy_raise(ErrorContext* errctx) {
|
||||
errctx->set_error("THROWN FROM __nac3_error_dummy_raise!!!!!!");
|
||||
}
|
||||
}
|
|
@ -0,0 +1,60 @@
|
|||
#pragma once
|
||||
|
||||
#include "int_defs.hpp"
|
||||
|
||||
namespace {
|
||||
namespace string {
|
||||
bool is_empty(const char* str) {
|
||||
return str[0] == '\0';
|
||||
}
|
||||
|
||||
int8_t compare(const char* a, const char* b) {
|
||||
uint32_t i = 0;
|
||||
while (true) {
|
||||
if (a[i] < b[i]) {
|
||||
return -1;
|
||||
} else if (a[i] > b[i]) {
|
||||
return 1;
|
||||
} else { // a[i] == b[i]
|
||||
if (a[i] == '\0') {
|
||||
return 0;
|
||||
} else {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int8_t equal(const char* a, const char* b) {
|
||||
return compare(a, b) == 0;
|
||||
}
|
||||
|
||||
uint32_t length(const char* str) {
|
||||
uint32_t length = 0;
|
||||
while (*str != '\0') {
|
||||
length++;
|
||||
str++;
|
||||
}
|
||||
return length;
|
||||
}
|
||||
|
||||
bool copy(const char* src, char* dst, uint32_t dst_max_size) {
|
||||
for (uint32_t i = 0; i < dst_max_size; i++) {
|
||||
bool is_last = i + 1 == dst_max_size;
|
||||
if (is_last && src[i] != '\0') {
|
||||
dst[i] = '\0';
|
||||
return false;
|
||||
}
|
||||
|
||||
if (src[i] == '\0') {
|
||||
dst[i] = '\0';
|
||||
return true;
|
||||
}
|
||||
|
||||
dst[i] = src[i];
|
||||
}
|
||||
|
||||
__builtin_unreachable();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,5 +1,7 @@
|
|||
#pragma once
|
||||
|
||||
#include "int_defs.hpp"
|
||||
|
||||
namespace {
|
||||
template <typename T>
|
||||
const T& max(const T& a, const T& b) {
|
||||
|
@ -18,4 +20,69 @@ bool arrays_match(int len, T* as, T* bs) {
|
|||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
uint32_t int_log_floor(T value, T base) {
|
||||
uint32_t result = 0;
|
||||
while (value >= base) {
|
||||
result++;
|
||||
value /= base;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
namespace cstr_utils {
|
||||
bool is_empty(const char* str) {
|
||||
return str[0] == '\0';
|
||||
}
|
||||
|
||||
int8_t compare(const char* a, const char* b) {
|
||||
uint32_t i = 0;
|
||||
while (true) {
|
||||
if (a[i] < b[i]) {
|
||||
return -1;
|
||||
} else if (a[i] > b[i]) {
|
||||
return 1;
|
||||
} else { // a[i] == b[i]
|
||||
if (a[i] == '\0') {
|
||||
return 0;
|
||||
} else {
|
||||
i++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int8_t equal(const char* a, const char* b) {
|
||||
return compare(a, b) == 0;
|
||||
}
|
||||
|
||||
uint32_t length(const char* str) {
|
||||
uint32_t length = 0;
|
||||
while (*str != '\0') {
|
||||
length++;
|
||||
str++;
|
||||
}
|
||||
return length;
|
||||
}
|
||||
|
||||
bool copy(const char* src, char* dst, uint32_t dst_max_size) {
|
||||
for (uint32_t i = 0; i < dst_max_size; i++) {
|
||||
bool is_last = i + 1 == dst_max_size;
|
||||
if (is_last && src[i] != '\0') {
|
||||
dst[i] = '\0';
|
||||
return false;
|
||||
}
|
||||
|
||||
if (src[i] == '\0') {
|
||||
dst[i] = '\0';
|
||||
return true;
|
||||
}
|
||||
|
||||
dst[i] = src[i];
|
||||
}
|
||||
|
||||
__builtin_unreachable();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,3 +1,6 @@
|
|||
#pragma once
|
||||
|
||||
#include "irrt/core.hpp"
|
||||
#include "irrt/error_context.hpp"
|
||||
#include "irrt/int_defs.hpp"
|
||||
#include "irrt/utils.hpp"
|
|
@ -9,8 +9,11 @@
|
|||
|
||||
#include "test/core.hpp"
|
||||
#include "test/test_core.hpp"
|
||||
#include "test/test_utils.hpp"
|
||||
|
||||
int main() {
|
||||
test_int_exp();
|
||||
run_test_core();
|
||||
run_test_print();
|
||||
run_test_utils();
|
||||
return 0;
|
||||
}
|
|
@ -4,39 +4,39 @@
|
|||
#include <cstdio>
|
||||
|
||||
template <class T>
|
||||
void print_value(const T& value) {}
|
||||
void print_value(T value);
|
||||
|
||||
template <>
|
||||
void print_value(const int8_t& value) {
|
||||
void print_value(char value) {
|
||||
printf("'%c' (ord=%d)", value, value);
|
||||
}
|
||||
|
||||
template <>
|
||||
void print_value(int8_t value) {
|
||||
printf("%d", value);
|
||||
}
|
||||
|
||||
template <>
|
||||
void print_value(const int32_t& value) {
|
||||
void print_value(int32_t value) {
|
||||
printf("%d", value);
|
||||
}
|
||||
|
||||
template <>
|
||||
void print_value(const uint8_t& value) {
|
||||
void print_value(uint8_t value) {
|
||||
printf("%u", value);
|
||||
}
|
||||
|
||||
template <>
|
||||
void print_value(const uint32_t& value) {
|
||||
void print_value(uint32_t value) {
|
||||
printf("%u", value);
|
||||
}
|
||||
|
||||
template <>
|
||||
void print_value(const double& value) {
|
||||
void print_value(double value) {
|
||||
printf("%f", value);
|
||||
}
|
||||
|
||||
// template <double>
|
||||
// void print_value(const double& value) {
|
||||
// printf("%f", value);
|
||||
// }
|
||||
//
|
||||
// template <char *>
|
||||
// void print_value(const char*& value) {
|
||||
// printf("%f", value);
|
||||
// }
|
||||
template <>
|
||||
void print_value(char* value) {
|
||||
printf("%s", value);
|
||||
}
|
|
@ -9,3 +9,7 @@ void test_int_exp() {
|
|||
assert_values_match(125, __nac3_int_exp_impl<int32_t>(5, 3));
|
||||
assert_values_match(3125, __nac3_int_exp_impl<int32_t>(5, 5));
|
||||
}
|
||||
|
||||
void run_test_core() {
|
||||
test_int_exp();
|
||||
}
|
|
@ -0,0 +1,27 @@
|
|||
#pragma once
|
||||
|
||||
#include "core.hpp"
|
||||
#include "../irrt/utils.hpp"
|
||||
|
||||
void test_int_log_10() {
|
||||
BEGIN_TEST();
|
||||
|
||||
assert_values_match((uint32_t) 0, int_log_floor(0, 10));
|
||||
assert_values_match((uint32_t) 0, int_log_floor(9, 10));
|
||||
assert_values_match((uint32_t) 1, int_log_floor(10, 10));
|
||||
assert_values_match((uint32_t) 1, int_log_floor(11, 10));
|
||||
assert_values_match((uint32_t) 1, int_log_floor(99, 10));
|
||||
assert_values_match((uint32_t) 2, int_log_floor(100, 10));
|
||||
assert_values_match((uint32_t) 2, int_log_floor(101, 10));
|
||||
}
|
||||
|
||||
void test_cstr_utils() {
|
||||
BEGIN_TEST();
|
||||
|
||||
assert_values_match((uint32_t) 42, (uint32_t) cstr_utils::length("THROWN FROM __nac3_error_dummy_raise!!!!!!"));
|
||||
}
|
||||
|
||||
void run_test_utils() {
|
||||
test_int_log_10();
|
||||
test_cstr_utils();
|
||||
}
|
|
@ -1,10 +1,32 @@
|
|||
use inkwell::types::{BasicTypeEnum, IntType};
|
||||
|
||||
use crate::codegen::optics::{AddressLens, GepGetter, IntLens, StructureOptic};
|
||||
use crate::codegen::optics::{AddressLens, FieldBuilder, GepGetter, IntLens, StructureOptic};
|
||||
|
||||
// use crate::codegen::structure::{
|
||||
// FieldLensBuilder, IntLens, LensWithFieldInfo, PointerLens, StructFieldLens,
|
||||
// };
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct StrLens<'ctx> {
|
||||
pub size_type: IntType<'ctx>,
|
||||
}
|
||||
|
||||
// TODO: nac3core has hardcoded a lot of "str"
|
||||
pub struct StrFields<'ctx> {
|
||||
pub content: GepGetter<AddressLens<IntLens<'ctx>>>,
|
||||
pub length: GepGetter<IntLens<'ctx>>,
|
||||
}
|
||||
|
||||
impl<'ctx> StructureOptic<'ctx> for StrLens<'ctx> {
|
||||
type Fields = StrFields<'ctx>;
|
||||
|
||||
fn struct_name(&self) -> &'static str {
|
||||
"str"
|
||||
}
|
||||
|
||||
fn build_fields(&self, builder: &mut FieldBuilder<'ctx>) -> Self::Fields {
|
||||
StrFields {
|
||||
content: builder.add_field("content", AddressLens(IntLens(builder.ctx.i8_type()))),
|
||||
length: builder.add_field("length", IntLens(self.size_type)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct NpArrayFields<'ctx> {
|
||||
pub data: GepGetter<AddressLens<IntLens<'ctx>>>,
|
||||
|
@ -54,7 +76,7 @@ impl<'ctx> StructureOptic<'ctx> for IrrtStringLens {
|
|||
type Fields = IrrtStringFields<'ctx>;
|
||||
|
||||
fn struct_name(&self) -> &'static str {
|
||||
todo!()
|
||||
"String"
|
||||
}
|
||||
|
||||
fn build_fields(
|
||||
|
@ -71,15 +93,18 @@ impl<'ctx> StructureOptic<'ctx> for IrrtStringLens {
|
|||
}
|
||||
}
|
||||
|
||||
pub struct ErrorContextFields {
|
||||
pub message: GepGetter<IrrtStringLens>,
|
||||
pub struct ErrorContextFields<'ctx> {
|
||||
pub message_template: GepGetter<AddressLens<IntLens<'ctx>>>,
|
||||
pub param1: GepGetter<IntLens<'ctx>>,
|
||||
pub param2: GepGetter<IntLens<'ctx>>,
|
||||
pub param3: GepGetter<IntLens<'ctx>>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
pub struct ErrorContextLens;
|
||||
|
||||
impl<'ctx> StructureOptic<'ctx> for ErrorContextLens {
|
||||
type Fields = ErrorContextFields;
|
||||
type Fields = ErrorContextFields<'ctx>;
|
||||
|
||||
fn struct_name(&self) -> &'static str {
|
||||
"ErrorContext"
|
||||
|
@ -89,6 +114,12 @@ impl<'ctx> StructureOptic<'ctx> for ErrorContextLens {
|
|||
&self,
|
||||
builder: &mut crate::codegen::optics::FieldBuilder<'ctx>,
|
||||
) -> Self::Fields {
|
||||
ErrorContextFields { message: builder.add_field("message", IrrtStringLens) }
|
||||
ErrorContextFields {
|
||||
message_template: builder
|
||||
.add_field("message_template", AddressLens(IntLens(builder.ctx.i8_type()))),
|
||||
param1: builder.add_field("param1", IntLens(builder.ctx.i64_type())),
|
||||
param2: builder.add_field("param2", IntLens(builder.ctx.i64_type())),
|
||||
param3: builder.add_field("param3", IntLens(builder.ctx.i64_type())),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -23,6 +23,9 @@ use inkwell::{
|
|||
use itertools::Either;
|
||||
use nac3parser::ast::Expr;
|
||||
|
||||
pub mod classes;
|
||||
pub mod new;
|
||||
|
||||
#[must_use]
|
||||
pub fn load_irrt(ctx: &Context) -> Module {
|
||||
let bitcode_buf = MemoryBuffer::create_from_memory_range(
|
||||
|
|
|
@ -0,0 +1,154 @@
|
|||
use inkwell::{
|
||||
types::{BasicMetadataTypeEnum, BasicType, IntType},
|
||||
values::{AnyValue, BasicMetadataValueEnum, IntValue},
|
||||
};
|
||||
|
||||
use crate::{
|
||||
codegen::{
|
||||
optics::{Address, AddressLens, IntLens, Optic, OpticValue, Prism},
|
||||
CodeGenContext, CodeGenerator,
|
||||
},
|
||||
util::SizeVariant,
|
||||
};
|
||||
|
||||
use super::classes::{ErrorContextLens, StrLens};
|
||||
|
||||
fn get_size_variant(ty: IntType) -> SizeVariant {
|
||||
match ty.get_bit_width() {
|
||||
32 => SizeVariant::Bits32,
|
||||
64 => SizeVariant::Bits64,
|
||||
_ => unreachable!("Unsupported int type bit width {}", ty.get_bit_width()),
|
||||
}
|
||||
}
|
||||
|
||||
fn get_sized_dependent_function_name(ty: IntType, fn_name: &str) -> String {
|
||||
let mut fn_name = fn_name.to_owned();
|
||||
match get_size_variant(ty) {
|
||||
SizeVariant::Bits32 => {
|
||||
// Do nothing, `fn_name` already has the correct name
|
||||
}
|
||||
SizeVariant::Bits64 => {
|
||||
// Append "64", this is the naming convention
|
||||
fn_name.push_str("64");
|
||||
}
|
||||
}
|
||||
fn_name
|
||||
}
|
||||
|
||||
// TODO: Variadic argument?
|
||||
pub struct FunctionBuilder<'ctx, 'a> {
|
||||
ctx: &'a CodeGenContext<'ctx, 'a>,
|
||||
fn_name: &'a str,
|
||||
arguments: Vec<(BasicMetadataTypeEnum<'ctx>, BasicMetadataValueEnum<'ctx>)>,
|
||||
}
|
||||
|
||||
impl<'ctx, 'a> FunctionBuilder<'ctx, 'a> {
|
||||
pub fn begin(ctx: &'a CodeGenContext<'ctx, 'a>, fn_name: &'a str) -> Self {
|
||||
FunctionBuilder { ctx, fn_name, arguments: Vec::new() }
|
||||
}
|
||||
|
||||
// The name is for self-documentation
|
||||
#[must_use]
|
||||
pub fn arg<S: Optic<'ctx>>(mut self, _name: &'static str, optic: &S, arg: &S::Value) -> Self {
|
||||
self.arguments
|
||||
.push((optic.get_llvm_type(self.ctx.ctx).into(), arg.get_llvm_value().into()));
|
||||
self
|
||||
}
|
||||
|
||||
pub fn returning<S: Prism<'ctx>>(self, name: &'static str, return_prism: &S) -> S::Value {
|
||||
let (param_tys, param_vals): (Vec<_>, Vec<_>) = self.arguments.into_iter().unzip();
|
||||
|
||||
let function = self.ctx.module.get_function(self.fn_name).unwrap_or_else(|| {
|
||||
let return_type = return_prism.get_llvm_type(self.ctx.ctx);
|
||||
let fn_type = return_type.fn_type(¶m_tys, false);
|
||||
self.ctx.module.add_function(self.fn_name, fn_type, None)
|
||||
});
|
||||
|
||||
let ret = self.ctx.builder.build_call(function, ¶m_vals, name).unwrap();
|
||||
return_prism.review(ret.as_any_value_enum())
|
||||
}
|
||||
|
||||
// TODO: Code duplication, but otherwise returning<S: Optic<'ctx>> cannot resolve S if return_optic = None
|
||||
pub fn returning_void(self) {
|
||||
let (param_tys, param_vals): (Vec<_>, Vec<_>) = self.arguments.into_iter().unzip();
|
||||
|
||||
let function = self.ctx.module.get_function(self.fn_name).unwrap_or_else(|| {
|
||||
let return_type = self.ctx.ctx.void_type();
|
||||
let fn_type = return_type.fn_type(¶m_tys, false);
|
||||
self.ctx.module.add_function(self.fn_name, fn_type, None)
|
||||
});
|
||||
|
||||
self.ctx.builder.build_call(function, ¶m_vals, "").unwrap();
|
||||
}
|
||||
}
|
||||
|
||||
pub fn call_nac3_error_context_initialize<'ctx>(
|
||||
ctx: &CodeGenContext<'ctx, '_>,
|
||||
errctx: &Address<'ctx, ErrorContextLens>,
|
||||
) {
|
||||
FunctionBuilder::begin(ctx, "__nac3_error_context_initialize")
|
||||
.arg("errctx", &AddressLens(ErrorContextLens), errctx)
|
||||
.returning_void();
|
||||
}
|
||||
|
||||
pub fn call_nac3_error_context_has_no_error<'ctx>(
|
||||
ctx: &CodeGenContext<'ctx, '_>,
|
||||
errctx: &Address<'ctx, ErrorContextLens>,
|
||||
) -> IntValue<'ctx> {
|
||||
FunctionBuilder::begin(ctx, "__nac3_error_context_has_no_error")
|
||||
.arg("errctx", &AddressLens(ErrorContextLens), errctx)
|
||||
.returning("has_error", &IntLens(ctx.ctx.bool_type()))
|
||||
}
|
||||
|
||||
pub fn call_nac3_error_context_get_error_str<'ctx>(
|
||||
size_type: IntType<'ctx>,
|
||||
ctx: &CodeGenContext<'ctx, '_>,
|
||||
errctx: &Address<'ctx, ErrorContextLens>,
|
||||
dst_str: &Address<'ctx, StrLens<'ctx>>,
|
||||
) -> IntValue<'ctx> {
|
||||
FunctionBuilder::begin(
|
||||
ctx,
|
||||
&get_sized_dependent_function_name(size_type, "__nac3_error_context_get_error_str"),
|
||||
)
|
||||
.arg("errctx", &AddressLens(ErrorContextLens), errctx)
|
||||
.arg("dst_str", &AddressLens(StrLens { size_type }), dst_str)
|
||||
.returning("has_error", &IntLens(ctx.ctx.bool_type()))
|
||||
}
|
||||
|
||||
pub fn call_nac3_dummy_raise<'ctx>(
|
||||
ctx: &CodeGenContext<'ctx, '_>,
|
||||
errctx: &Address<'ctx, ErrorContextLens>,
|
||||
) {
|
||||
FunctionBuilder::begin(ctx, "__nac3_error_dummy_raise")
|
||||
.arg("errctx", &AddressLens(ErrorContextLens), errctx)
|
||||
.returning_void();
|
||||
}
|
||||
|
||||
pub fn test_dummy_raise<G: CodeGenerator + ?Sized>(
|
||||
generator: &mut G,
|
||||
ctx: &mut CodeGenContext<'_, '_>,
|
||||
) {
|
||||
let size_type = generator.get_size_type(ctx.ctx);
|
||||
|
||||
let errctx_ptr = ErrorContextLens.alloca(ctx, "errctx");
|
||||
|
||||
call_nac3_error_context_initialize(ctx, &errctx_ptr);
|
||||
call_nac3_dummy_raise(ctx, &errctx_ptr);
|
||||
|
||||
let has_error = call_nac3_error_context_has_no_error(ctx, &errctx_ptr);
|
||||
let error_str_ptr = StrLens { size_type }.alloca(ctx, "error_str");
|
||||
call_nac3_error_context_get_error_str(size_type, ctx, &errctx_ptr, &error_str_ptr);
|
||||
|
||||
let error_str = error_str_ptr.load(ctx, "error_str");
|
||||
let param1 = errctx_ptr.view(ctx, |fields| &fields.param1).load(ctx, "param1");
|
||||
let param2 = errctx_ptr.view(ctx, |fields| &fields.param2).load(ctx, "param2");
|
||||
let param3 = errctx_ptr.view(ctx, |fields| &fields.param3).load(ctx, "param3");
|
||||
ctx.make_assert_impl(
|
||||
generator,
|
||||
has_error,
|
||||
"0:RuntimeError", // TODO: Make this dynamic (within IRRT), but this is probably not trivial
|
||||
error_str.get_llvm_value(),
|
||||
[Some(param1), Some(param2), Some(param3)],
|
||||
ctx.current_loc,
|
||||
);
|
||||
}
|
|
@ -11,7 +11,6 @@ mod tests {
|
|||
|
||||
let irrt_test_out_path = Path::new(concat!(env!("OUT_DIR"), "/irrt_test.out"));
|
||||
let output = Command::new(irrt_test_out_path.to_str().unwrap()).output().unwrap();
|
||||
|
||||
if !output.status.success() {
|
||||
eprintln!("irrt_test failed with status {}:", output.status);
|
||||
eprintln!("====== stdout ======");
|
||||
|
|
|
@ -23,8 +23,10 @@ use inkwell::{
|
|||
values::{BasicValueEnum, FunctionValue, IntValue, PhiValue, PointerValue},
|
||||
AddressSpace, IntPredicate, OptimizationLevel,
|
||||
};
|
||||
use irrt::classes::StrLens;
|
||||
use itertools::Itertools;
|
||||
use nac3parser::ast::{Location, Stmt, StrRef};
|
||||
use optics::Optic;
|
||||
use parking_lot::{Condvar, Mutex};
|
||||
use std::collections::{HashMap, HashSet};
|
||||
use std::sync::{
|
||||
|
@ -647,6 +649,8 @@ pub fn gen_func_impl<
|
|||
..primitives
|
||||
};
|
||||
|
||||
let llvm_str_ty =
|
||||
StrLens { size_type: generator.get_size_type(context) }.get_llvm_type(context);
|
||||
let mut type_cache: HashMap<_, _> = [
|
||||
(primitives.int32, context.i32_type().into()),
|
||||
(primitives.int64, context.i64_type().into()),
|
||||
|
@ -654,21 +658,7 @@ pub fn gen_func_impl<
|
|||
(primitives.uint64, context.i64_type().into()),
|
||||
(primitives.float, context.f64_type().into()),
|
||||
(primitives.bool, context.i8_type().into()),
|
||||
(primitives.str, {
|
||||
let name = "str";
|
||||
match module.get_struct_type(name) {
|
||||
None => {
|
||||
let str_type = context.opaque_struct_type("str");
|
||||
let fields = [
|
||||
context.i8_type().ptr_type(AddressSpace::default()).into(),
|
||||
generator.get_size_type(context).into(),
|
||||
];
|
||||
str_type.set_body(&fields, false);
|
||||
str_type.into()
|
||||
}
|
||||
Some(t) => t.as_basic_type_enum(),
|
||||
}
|
||||
}),
|
||||
(primitives.str, llvm_str_ty),
|
||||
(primitives.range, RangeType::new(context).as_base_type().into()),
|
||||
(primitives.exception, {
|
||||
let name = "Exception";
|
||||
|
@ -678,7 +668,7 @@ pub fn gen_func_impl<
|
|||
let exception = context.opaque_struct_type("Exception");
|
||||
let int32 = context.i32_type().into();
|
||||
let int64 = context.i64_type().into();
|
||||
let str_ty = module.get_struct_type("str").unwrap().as_basic_type_enum();
|
||||
let str_ty = llvm_str_ty;
|
||||
let fields = [int32, str_ty, int32, int32, str_ty, str_ty, int64, int64, int64];
|
||||
exception.set_body(&fields, false);
|
||||
exception.ptr_type(AddressSpace::default()).as_basic_type_enum()
|
||||
|
|
|
@ -173,7 +173,7 @@ impl<'ctx, AddresseeOptic: MemoryGetter<'ctx>> Address<'ctx, AddresseeOptic> {
|
|||
// To make [`Address`] convenient to use
|
||||
impl<'ctx, AddresseeOptic: MemorySetter<'ctx>> Address<'ctx, AddresseeOptic> {
|
||||
pub fn set(&self, ctx: &CodeGenContext<'ctx, '_>, value: &AddresseeOptic::Value) {
|
||||
self.addressee_optic.set(ctx, self.address, value)
|
||||
self.addressee_optic.set(ctx, self.address, value);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -181,7 +181,7 @@ impl<'ctx, AddresseeOptic: MemorySetter<'ctx>> Address<'ctx, AddresseeOptic> {
|
|||
#[derive(Debug, Clone)]
|
||||
pub struct GepGetter<ElementOptic> {
|
||||
/// The LLVM GEP index
|
||||
pub gep_index: u32, // TODO: I think I'm not supposed to *just* use i32 for GEP like that
|
||||
pub gep_index: u64,
|
||||
/// Element (or field in the context of `struct`s) name. Used for cosmetics.
|
||||
pub name: &'static str,
|
||||
/// The lens to view the actual value after applying this [`FieldLens<T>`]
|
||||
|
@ -208,7 +208,7 @@ impl<'ctx, ElementOptic: Optic<'ctx>> MemoryGetter<'ctx> for GepGetter<ElementOp
|
|||
ctx.builder
|
||||
.build_in_bounds_gep(
|
||||
pointer,
|
||||
&[llvm_i32.const_zero(), llvm_i32.const_int(self.gep_index as u64, false)],
|
||||
&[llvm_i32.const_zero(), llvm_i32.const_int(self.gep_index, false)],
|
||||
name,
|
||||
)
|
||||
.unwrap()
|
||||
|
@ -220,7 +220,7 @@ impl<'ctx, ElementOptic: Optic<'ctx>> MemoryGetter<'ctx> for GepGetter<ElementOp
|
|||
// Only used by [`FieldBuilder`]
|
||||
#[derive(Debug)]
|
||||
struct FieldInfo<'ctx> {
|
||||
gep_index: u32,
|
||||
gep_index: u64,
|
||||
name: &'ctx str,
|
||||
llvm_type: BasicTypeEnum<'ctx>,
|
||||
}
|
||||
|
@ -228,17 +228,18 @@ struct FieldInfo<'ctx> {
|
|||
#[derive(Debug)]
|
||||
pub struct FieldBuilder<'ctx> {
|
||||
pub ctx: &'ctx Context,
|
||||
gep_index_counter: u32,
|
||||
gep_index_counter: u64,
|
||||
struct_name: &'ctx str,
|
||||
fields: Vec<FieldInfo<'ctx>>,
|
||||
}
|
||||
|
||||
impl<'ctx> FieldBuilder<'ctx> {
|
||||
#[must_use]
|
||||
pub fn new(ctx: &'ctx Context, struct_name: &'ctx str) -> Self {
|
||||
FieldBuilder { ctx, gep_index_counter: 0, struct_name, fields: Vec::new() }
|
||||
}
|
||||
|
||||
fn next_gep_index(&mut self) -> u32 {
|
||||
fn next_gep_index(&mut self) -> u64 {
|
||||
let index = self.gep_index_counter;
|
||||
self.gep_index_counter += 1;
|
||||
index
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
use std::iter::once;
|
||||
|
||||
use crate::util::SizeVariant;
|
||||
use helper::{debug_assert_prim_is_allowed, make_exception_fields, PrimDefDetails};
|
||||
use indexmap::IndexMap;
|
||||
use inkwell::{
|
||||
|
@ -23,7 +24,6 @@ use crate::{
|
|||
symbol_resolver::SymbolValue,
|
||||
toplevel::{helper::PrimDef, numpy::make_ndarray_ty},
|
||||
typecheck::typedef::{into_var_map, iter_type_vars, TypeVar, VarMap},
|
||||
util::SizeVariant,
|
||||
};
|
||||
|
||||
use super::*;
|
||||
|
|
Loading…
Reference in New Issue