Range Statement support

This commit is contained in:
gingerBill
2020-02-29 14:29:47 +00:00
parent f83e1b8b0a
commit 56240240f6
2 changed files with 659 additions and 7 deletions

View File

@@ -820,6 +820,13 @@ void lb_add_procedure_value(lbModule *m, lbProcedure *p) {
lbValue lb_emit_string(lbProcedure *p, lbValue str_elem, lbValue str_len) {
lbAddr res = lb_add_local_generated(p, t_string, false);
lb_emit_store(p, lb_emit_struct_ep(p, res.addr, 0), str_elem);
lb_emit_store(p, lb_emit_struct_ep(p, res.addr, 1), str_len);
return lb_addr_load(p, res);
}
LLVMAttributeRef lb_create_enum_attribute(LLVMContextRef ctx, char const *name, u64 value) {
unsigned kind = LLVMGetEnumAttributeKindForName(name, gb_strlen(name));
return LLVMCreateEnumAttribute(ctx, kind, value);
@@ -836,6 +843,7 @@ void lb_add_proc_attribute_at_index(lbProcedure *p, isize index, char const *nam
lbProcedure *lb_create_procedure(lbModule *m, Entity *entity) {
GB_ASSERT(entity != nullptr);
@@ -1738,6 +1746,627 @@ void lb_build_when_stmt(lbProcedure *p, AstWhenStmt *ws) {
}
}
void lb_build_range_indexed(lbProcedure *p, lbValue expr, Type *val_type, lbValue count_ptr,
lbValue *val_, lbValue *idx_, lbBlock **loop_, lbBlock **done_) {
lbModule *m = p->module;
lbValue count = {};
Type *expr_type = base_type(type_deref(expr.type));
switch (expr_type->kind) {
case Type_Array:
count = lb_const_int(m, t_int, expr_type->Array.count);
break;
}
lbValue val = {};
lbValue idx = {};
lbBlock *loop = nullptr;
lbBlock *done = nullptr;
lbBlock *body = nullptr;
lbAddr index = lb_add_local_generated(p, t_int, false);
lb_addr_store(p, index, lb_const_int(m, t_int, cast(u64)-1));
loop = lb_create_block(p, "for.index.loop");
lb_emit_jump(p, loop);
lb_start_block(p, loop);
lbValue incr = lb_emit_arith(p, Token_Add, lb_addr_load(p, index), lb_const_int(m, t_int, 1), t_int);
lb_addr_store(p, index, incr);
body = lb_create_block(p, "for.index.body");
done = lb_create_block(p, "for.index.done");
if (count.value == nullptr) {
GB_ASSERT(count_ptr.value != nullptr);
count = lb_emit_load(p, count_ptr);
}
lbValue cond = lb_emit_comp(p, Token_Lt, incr, count);
lb_emit_if(p, cond, body, done);
lb_start_block(p, body);
idx = lb_addr_load(p, index);
switch (expr_type->kind) {
case Type_Array: {
if (val_type != nullptr) {
val = lb_emit_load(p, lb_emit_array_ep(p, expr, idx));
}
break;
}
case Type_EnumeratedArray: {
if (val_type != nullptr) {
val = lb_emit_load(p, lb_emit_array_ep(p, expr, idx));
// NOTE(bill): Override the idx value for the enumeration
Type *index_type = expr_type->EnumeratedArray.index;
if (compare_exact_values(Token_NotEq, expr_type->EnumeratedArray.min_value, exact_value_u64(0))) {
idx = lb_emit_arith(p, Token_Add, idx, lb_const_value(m, index_type, expr_type->EnumeratedArray.min_value), index_type);
}
}
break;
}
case Type_Slice: {
if (val_type != nullptr) {
lbValue elem = lb_slice_elem(p, expr);
val = lb_emit_load(p, lb_emit_ptr_offset(p, elem, idx));
}
break;
}
case Type_DynamicArray: {
if (val_type != nullptr) {
lbValue elem = lb_emit_struct_ep(p, expr, 0);
elem = lb_emit_load(p, elem);
val = lb_emit_load(p, lb_emit_ptr_offset(p, elem, idx));
}
break;
}
case Type_Map: {
lbAddr key = lb_add_local_generated(p, expr_type->Map.key, true);
lbValue entries = lb_map_entries_ptr(p, expr);
lbValue elem = lb_emit_struct_ep(p, entries, 0);
elem = lb_emit_load(p, elem);
lbValue entry = lb_emit_ptr_offset(p, elem, idx);
val = lb_emit_load(p, lb_emit_struct_ep(p, entry, 2));
lbValue hash = lb_emit_struct_ep(p, entry, 0);
if (is_type_string(expr_type->Map.key)) {
lbValue str = lb_emit_struct_ep(p, hash, 1);
lb_addr_store(p, key, lb_emit_load(p, str));
} else {
lbValue hash_ptr = lb_emit_struct_ep(p, hash, 0);
hash_ptr = lb_emit_conv(p, hash_ptr, lb_addr_type(key));
lb_addr_store(p, key, lb_emit_load(p, hash_ptr));
}
idx = lb_addr_load(p, key);
break;
}
default:
GB_PANIC("Cannot do range_indexed of %s", type_to_string(expr_type));
break;
}
if (val_) *val_ = val;
if (idx_) *idx_ = idx;
if (loop_) *loop_ = loop;
if (done_) *done_ = done;
}
void lb_build_range_string(lbProcedure *p, lbValue expr, Type *val_type,
lbValue *val_, lbValue *idx_, lbBlock **loop_, lbBlock **done_) {
lbModule *m = p->module;
lbValue count = lb_const_int(m, t_int, 0);
Type *expr_type = base_type(expr.type);
switch (expr_type->kind) {
case Type_Basic:
count = lb_string_len(p, expr);
break;
default:
GB_PANIC("Cannot do range_string of %s", type_to_string(expr_type));
break;
}
lbValue val = {};
lbValue idx = {};
lbBlock *loop = nullptr;
lbBlock *done = nullptr;
lbBlock *body = nullptr;
lbAddr offset_ = lb_add_local_generated(p, t_int, false);
lb_addr_store(p, offset_, lb_const_int(m, t_int, 0));
loop = lb_create_block(p, "for.string.loop");
lb_emit_jump(p, loop);
lb_start_block(p, loop);
body = lb_create_block(p, "for.string.body");
done = lb_create_block(p, "for.string.done");
lbValue offset = lb_addr_load(p, offset_);
lbValue cond = lb_emit_comp(p, Token_Lt, offset, count);
lb_emit_if(p, cond, body, done);
lb_start_block(p, body);
lbValue str_elem = lb_emit_ptr_offset(p, lb_string_elem(p, expr), offset);
lbValue str_len = lb_emit_arith(p, Token_Sub, count, offset, t_int);
auto args = array_make<lbValue >(heap_allocator(), 1);
args[0] = lb_emit_string(p, str_elem, str_len);
lbValue rune_and_len = lb_emit_runtime_call(p, "string_decode_rune", args);
lbValue len = lb_emit_struct_ev(p, rune_and_len, 1);
lb_addr_store(p, offset_, lb_emit_arith(p, Token_Add, offset, len, t_int));
idx = offset;
if (val_type != nullptr) {
val = lb_emit_struct_ev(p, rune_and_len, 0);
}
if (val_) *val_ = val;
if (idx_) *idx_ = idx;
if (loop_) *loop_ = loop;
if (done_) *done_ = done;
}
void lb_build_range_interval(lbProcedure *p, AstBinaryExpr *node, Type *val_type,
lbValue *val_, lbValue *idx_, lbBlock **loop_, lbBlock **done_) {
lbModule *m = p->module;
// TODO(bill): How should the behaviour work for lower and upper bounds checking for iteration?
// If 'lower' is changed, should 'val' do so or is that not typical behaviour?
lbValue lower = lb_build_expr(p, node->left);
lbValue upper = {};
lbValue val = {};
lbValue idx = {};
lbBlock *loop = nullptr;
lbBlock *done = nullptr;
lbBlock *body = nullptr;
if (val_type == nullptr) {
val_type = lower.type;
}
lbAddr value = lb_add_local_generated(p, val_type, false);
lb_addr_store(p, value, lower);
lbAddr index = lb_add_local_generated(p, t_int, false);
lb_addr_store(p, index, lb_const_int(m, t_int, 0));
loop = lb_create_block(p, "for.interval.loop");
lb_emit_jump(p, loop);
lb_start_block(p, loop);
body = lb_create_block(p, "for.interval.body");
done = lb_create_block(p, "for.interval.done");
TokenKind op = Token_Lt;
switch (node->op.kind) {
case Token_Ellipsis: op = Token_LtEq; break;
case Token_RangeHalf: op = Token_Lt; break;
default: GB_PANIC("Invalid interval operator"); break;
}
upper = lb_build_expr(p, node->right);
lbValue curr_value = lb_addr_load(p, value);
lbValue cond = lb_emit_comp(p, op, curr_value, upper);
lb_emit_if(p, cond, body, done);
lb_start_block(p, body);
val = lb_addr_load(p, value);
idx = lb_addr_load(p, index);
lb_emit_increment(p, value.addr);
lb_emit_increment(p, index.addr);
if (val_) *val_ = val;
if (idx_) *idx_ = idx;
if (loop_) *loop_ = loop;
if (done_) *done_ = done;
}
void lb_build_range_enum(lbProcedure *p, Type *enum_type, Type *val_type, lbValue *val_, lbValue *idx_, lbBlock **loop_, lbBlock **done_) {
lbModule *m = p->module;
Type *t = enum_type;
GB_ASSERT(is_type_enum(t));
Type *enum_ptr = alloc_type_pointer(t);
t = base_type(t);
Type *core_elem = core_type(t);
GB_ASSERT(t->kind == Type_Enum);
i64 enum_count = t->Enum.fields.count;
lbValue max_count = lb_const_int(m, t_int, enum_count);
lbValue ti = lb_type_info(m, t);
lbValue variant = lb_emit_struct_ep(p, ti, 3);
lbValue eti_ptr = lb_emit_conv(p, variant, t_type_info_enum_ptr);
lbValue values = lb_emit_load(p, lb_emit_struct_ep(p, eti_ptr, 2));
lbValue values_data = lb_slice_elem(p, values);
lbAddr offset_ = lb_add_local_generated(p, t_int, false);
lb_addr_store(p, offset_, lb_const_int(m, t_int, 0));
lbBlock *loop = lb_create_block(p, "for.enum.loop");
lb_emit_jump(p, loop);
lb_start_block(p, loop);
lbBlock *body = lb_create_block(p, "for.enum.body");
lbBlock *done = lb_create_block(p, "for.enum.done");
lbValue offset = lb_addr_load(p, offset_);
lbValue cond = lb_emit_comp(p, Token_Lt, offset, max_count);
lb_emit_if(p, cond, body, done);
lb_start_block(p, body);
lbValue val_ptr = lb_emit_ptr_offset(p, values_data, offset);
lb_emit_increment(p, offset_.addr);
lbValue val = {};
if (val_type != nullptr) {
GB_ASSERT(are_types_identical(enum_type, val_type));
if (is_type_integer(core_elem)) {
lbValue i = lb_emit_load(p, lb_emit_conv(p, val_ptr, t_i64_ptr));
val = lb_emit_conv(p, i, t);
} else {
GB_PANIC("TODO(bill): enum core type %s", type_to_string(core_elem));
}
}
if (val_) *val_ = val;
if (idx_) *idx_ = offset;
if (loop_) *loop_ = loop;
if (done_) *done_ = done;
}
void lb_build_range_tuple(lbProcedure *p, Ast *expr, Type *val0_type, Type *val1_type,
lbValue *val0_, lbValue *val1_, lbBlock **loop_, lbBlock **done_) {
lbBlock *loop = lb_create_block(p, "for.tuple.loop");
lb_emit_jump(p, loop);
lb_start_block(p, loop);
lbBlock *body = lb_create_block(p, "for.tuple.body");
lbBlock *done = lb_create_block(p, "for.tuple.done");
lbValue tuple_value = lb_build_expr(p, expr);
Type *tuple = tuple_value.type;
GB_ASSERT(tuple->kind == Type_Tuple);
i32 tuple_count = cast(i32)tuple->Tuple.variables.count;
i32 cond_index = tuple_count-1;
lbValue cond = lb_emit_struct_ev(p, tuple_value, cond_index);
lb_emit_if(p, cond, body, done);
lb_start_block(p, body);
if (val0_) *val0_ = lb_emit_struct_ev(p, tuple_value, 0);
if (val1_) *val1_ = lb_emit_struct_ev(p, tuple_value, 1);
if (loop_) *loop_ = loop;
if (done_) *done_ = done;
}
void lb_build_range_stmt(lbProcedure *p, AstRangeStmt *rs) {
lb_open_scope(p);
Type *val0_type = nullptr;
Type *val1_type = nullptr;
if (rs->val0 != nullptr && !is_blank_ident(rs->val0)) {
val0_type = type_of_expr(rs->val0);
}
if (rs->val1 != nullptr && !is_blank_ident(rs->val1)) {
val1_type = type_of_expr(rs->val1);
}
if (val0_type != nullptr) {
Entity *e = entity_of_ident(rs->val0);
lb_add_local(p, e->type, e, true);
}
if (val1_type != nullptr) {
Entity *e = entity_of_ident(rs->val1);
lb_add_local(p, e->type, e, true);
}
lbValue val = {};
lbValue key = {};
lbBlock *loop = nullptr;
lbBlock *done = nullptr;
Ast *expr = unparen_expr(rs->expr);
bool is_map = false;
TypeAndValue tav = type_and_value_of_expr(expr);
if (is_ast_range(expr)) {
lb_build_range_interval(p, &expr->BinaryExpr, val0_type, &val, &key, &loop, &done);
} else if (tav.mode == Addressing_Type) {
lb_build_range_enum(p, type_deref(tav.type), val0_type, &val, &key, &loop, &done);
} else {
Type *expr_type = type_of_expr(expr);
Type *et = base_type(type_deref(expr_type));
switch (et->kind) {
case Type_Map: {
is_map = true;
gbAllocator a = heap_allocator();
lbAddr addr = lb_build_addr(p, expr);
lbValue map = lb_addr_get_ptr(p, addr);
if (is_type_pointer(type_deref(lb_addr_type(addr)))) {
map = lb_addr_load(p, addr);
}
lbValue entries_ptr = lb_map_entries_ptr(p, map);
lbValue count_ptr = lb_emit_struct_ep(p, entries_ptr, 1);
lb_build_range_indexed(p, map, val1_type, count_ptr, &val, &key, &loop, &done);
break;
}
case Type_Array: {
lbValue array = lb_build_addr_ptr(p, expr);
if (is_type_pointer(type_deref(array.type))) {
array = lb_emit_load(p, array);
}
lbAddr count_ptr = lb_add_local_generated(p, t_int, false);
lb_addr_store(p, count_ptr, lb_const_int(p->module, t_int, et->Array.count));
lb_build_range_indexed(p, array, val0_type, count_ptr.addr, &val, &key, &loop, &done);
break;
}
case Type_EnumeratedArray: {
lbValue array = lb_build_addr_ptr(p, expr);
if (is_type_pointer(type_deref(array.type))) {
array = lb_emit_load(p, array);
}
lbAddr count_ptr = lb_add_local_generated(p, t_int, false);
lb_addr_store(p, count_ptr, lb_const_int(p->module, t_int, et->EnumeratedArray.count));
lb_build_range_indexed(p, array, val0_type, count_ptr.addr, &val, &key, &loop, &done);
break;
}
case Type_DynamicArray: {
lbValue count_ptr = {};
lbValue array = lb_build_addr_ptr(p, expr);
if (is_type_pointer(type_deref(array.type))) {
array = lb_emit_load(p, array);
}
count_ptr = lb_emit_struct_ep(p, array, 1);
lb_build_range_indexed(p, array, val0_type, count_ptr, &val, &key, &loop, &done);
break;
}
case Type_Slice: {
lbValue count_ptr = {};
lbValue slice = lb_build_expr(p, expr);
if (is_type_pointer(slice.type)) {
count_ptr = lb_emit_struct_ep(p, slice, 1);
slice = lb_emit_load(p, slice);
} else {
count_ptr = lb_add_local_generated(p, t_int, false).addr;
lb_emit_store(p, count_ptr, lb_slice_len(p, slice));
}
lb_build_range_indexed(p, slice, val0_type, count_ptr, &val, &key, &loop, &done);
break;
}
case Type_Basic: {
lbValue string = lb_build_expr(p, expr);
if (is_type_pointer(string.type)) {
string = lb_emit_load(p, string);
}
if (is_type_untyped(expr_type)) {
lbAddr s = lb_add_local_generated(p, default_type(string.type), false);
lb_addr_store(p, s, string);
string = lb_addr_load(p, s);
}
Type *t = base_type(string.type);
GB_ASSERT(!is_type_cstring(t));
lb_build_range_string(p, string, val0_type, &val, &key, &loop, &done);
break;
}
case Type_Tuple:
lb_build_range_tuple(p, expr, val0_type, val1_type, &val, &key, &loop, &done);
break;
default:
GB_PANIC("Cannot range over %s", type_to_string(expr_type));
break;
}
}
lbAddr val0_addr = {};
lbAddr val1_addr = {};
if (val0_type) val0_addr = lb_build_addr(p, rs->val0);
if (val1_type) val1_addr = lb_build_addr(p, rs->val1);
if (is_map) {
if (val0_type) lb_addr_store(p, val0_addr, key);
if (val1_type) lb_addr_store(p, val1_addr, val);
} else {
if (val0_type) lb_addr_store(p, val0_addr, val);
if (val1_type) lb_addr_store(p, val1_addr, key);
}
lb_push_target_list(p, rs->label, done, loop, nullptr);
lb_build_stmt(p, rs->body);
lb_close_scope(p, lbDeferExit_Default, nullptr);
lb_pop_target_list(p);
lb_emit_jump(p, loop);
lb_start_block(p, done);
}
void lb_build_inline_range_stmt(lbProcedure *p, AstInlineRangeStmt *rs) {
lbModule *m = p->module;
lb_open_scope(p); // Open scope here
Type *val0_type = nullptr;
Type *val1_type = nullptr;
if (rs->val0 != nullptr && !is_blank_ident(rs->val0)) {
val0_type = type_of_expr(rs->val0);
}
if (rs->val1 != nullptr && !is_blank_ident(rs->val1)) {
val1_type = type_of_expr(rs->val1);
}
if (val0_type != nullptr) {
Entity *e = entity_of_ident(rs->val0);
lb_add_local(p, e->type, e, true);
}
if (val1_type != nullptr) {
Entity *e = entity_of_ident(rs->val1);
lb_add_local(p, e->type, e, true);
}
lbValue val = {};
lbValue key = {};
lbBlock *loop = nullptr;
lbBlock *done = nullptr;
Ast *expr = unparen_expr(rs->expr);
TypeAndValue tav = type_and_value_of_expr(expr);
if (is_ast_range(expr)) {
lbAddr val0_addr = {};
lbAddr val1_addr = {};
if (val0_type) val0_addr = lb_build_addr(p, rs->val0);
if (val1_type) val1_addr = lb_build_addr(p, rs->val1);
TokenKind op = expr->BinaryExpr.op.kind;
Ast *start_expr = expr->BinaryExpr.left;
Ast *end_expr = expr->BinaryExpr.right;
GB_ASSERT(start_expr->tav.mode == Addressing_Constant);
GB_ASSERT(end_expr->tav.mode == Addressing_Constant);
ExactValue start = start_expr->tav.value;
ExactValue end = end_expr->tav.value;
if (op == Token_Ellipsis) { // .. [start, end]
ExactValue index = exact_value_i64(0);
for (ExactValue val = start;
compare_exact_values(Token_LtEq, val, end);
val = exact_value_increment_one(val), index = exact_value_increment_one(index)) {
if (val0_type) lb_addr_store(p, val0_addr, lb_const_value(m, val0_type, val));
if (val1_type) lb_addr_store(p, val1_addr, lb_const_value(m, val1_type, index));
lb_build_stmt(p, rs->body);
}
} else if (op == Token_RangeHalf) { // ..< [start, end)
ExactValue index = exact_value_i64(0);
for (ExactValue val = start;
compare_exact_values(Token_Lt, val, end);
val = exact_value_increment_one(val), index = exact_value_increment_one(index)) {
if (val0_type) lb_addr_store(p, val0_addr, lb_const_value(m, val0_type, val));
if (val1_type) lb_addr_store(p, val1_addr, lb_const_value(m, val1_type, index));
lb_build_stmt(p, rs->body);
}
}
} else if (tav.mode == Addressing_Type) {
GB_ASSERT(is_type_enum(type_deref(tav.type)));
Type *et = type_deref(tav.type);
Type *bet = base_type(et);
lbAddr val0_addr = {};
lbAddr val1_addr = {};
if (val0_type) val0_addr = lb_build_addr(p, rs->val0);
if (val1_type) val1_addr = lb_build_addr(p, rs->val1);
for_array(i, bet->Enum.fields) {
Entity *field = bet->Enum.fields[i];
GB_ASSERT(field->kind == Entity_Constant);
if (val0_type) lb_addr_store(p, val0_addr, lb_const_value(m, val0_type, field->Constant.value));
if (val1_type) lb_addr_store(p, val1_addr, lb_const_value(m, val1_type, exact_value_i64(i)));
lb_build_stmt(p, rs->body);
}
} else {
lbAddr val0_addr = {};
lbAddr val1_addr = {};
if (val0_type) val0_addr = lb_build_addr(p, rs->val0);
if (val1_type) val1_addr = lb_build_addr(p, rs->val1);
GB_ASSERT(expr->tav.mode == Addressing_Constant);
Type *t = base_type(expr->tav.type);
switch (t->kind) {
case Type_Basic:
GB_ASSERT(is_type_string(t));
{
ExactValue value = expr->tav.value;
GB_ASSERT(value.kind == ExactValue_String);
String str = value.value_string;
Rune codepoint = 0;
isize offset = 0;
do {
isize width = gb_utf8_decode(str.text+offset, str.len-offset, &codepoint);
if (val0_type) lb_addr_store(p, val0_addr, lb_const_value(m, val0_type, exact_value_i64(codepoint)));
if (val1_type) lb_addr_store(p, val1_addr, lb_const_value(m, val1_type, exact_value_i64(offset)));
lb_build_stmt(p, rs->body);
offset += width;
} while (offset < str.len);
}
break;
case Type_Array:
if (t->Array.count > 0) {
lbValue val = lb_build_expr(p, expr);
lbValue val_addr = lb_address_from_load_or_generate_local(p, val);
for (i64 i = 0; i < t->Array.count; i++) {
if (val0_type) {
// NOTE(bill): Due to weird legacy issues in LLVM, this needs to be an i32
lbValue elem = lb_emit_array_epi(p, val_addr, cast(i32)i);
lb_addr_store(p, val0_addr, lb_emit_load(p, elem));
}
if (val1_type) lb_addr_store(p, val1_addr, lb_const_value(m, val1_type, exact_value_i64(i)));
lb_build_stmt(p, rs->body);
}
}
break;
case Type_EnumeratedArray:
if (t->EnumeratedArray.count > 0) {
lbValue val = lb_build_expr(p, expr);
lbValue val_addr = lb_address_from_load_or_generate_local(p, val);
for (i64 i = 0; i < t->EnumeratedArray.count; i++) {
if (val0_type) {
// NOTE(bill): Due to weird legacy issues in LLVM, this needs to be an i32
lbValue elem = lb_emit_array_epi(p, val_addr, cast(i32)i);
lb_addr_store(p, val0_addr, lb_emit_load(p, elem));
}
if (val1_type) {
ExactValue idx = exact_value_add(exact_value_i64(i), t->EnumeratedArray.min_value);
lb_addr_store(p, val1_addr, lb_const_value(m, val1_type, idx));
}
lb_build_stmt(p, rs->body);
}
}
break;
default:
GB_PANIC("Invalid inline for type");
break;
}
}
lb_close_scope(p, lbDeferExit_Default, nullptr);
}
void lb_build_stmt(lbProcedure *p, Ast *node) {
switch (node->kind) {
case_ast_node(bs, EmptyStmt, node);
@@ -2166,11 +2795,11 @@ void lb_build_stmt(lbProcedure *p, Ast *node) {
case_end;
case_ast_node(rs, RangeStmt, node);
// TODO(bill): RangeStmt
lb_build_range_stmt(p, rs);
case_end;
case_ast_node(rs, InlineRangeStmt, node);
// TODO(bill): InlineRangeStmt
lb_build_inline_range_stmt(p, rs);
case_end;
case_ast_node(ss, SwitchStmt, node);
@@ -2339,9 +2968,9 @@ lbValue lb_const_undef(lbModule *m, Type *type) {
}
lbValue lb_const_int(lbModule *m, Type *type, unsigned long long value) {
lbValue lb_const_int(lbModule *m, Type *type, u64 value) {
lbValue res = {};
res.value = LLVMConstInt(lb_type(m, type), value, !is_type_unsigned(type));
res.value = LLVMConstInt(lb_type(m, type), cast(unsigned long long)value, !is_type_unsigned(type));
res.type = type;
return res;
}
@@ -3441,8 +4070,8 @@ lbValue lb_emit_conv(lbProcedure *p, lbValue value, Type *t) {
// ev = exact_value_to_integer(ev);
// } else if (is_type_pointer(dst)) {
// // IMPORTANT NOTE(bill): LLVM doesn't support pointer constants expect 'null'
// lbValue i = ir_add_module_constant(p->module, t_uintptr, ev);
// return ir_emit(p, ir_instr_conv(p, irConv_inttoptr, i, t_uintptr, dst));
// lbValue i = lb_add_module_constant(p->module, t_uintptr, ev);
// return lb_emit(p, lb_instr_conv(p, irConv_inttoptr, i, t_uintptr, dst));
// }
// return lb_const_value(p->module, t, ev);
}
@@ -5141,7 +5770,7 @@ lbValue lb_build_builtin_proc(lbProcedure *p, Ast *expr, TypeAndValue const &tv,
case BuiltinProc_atomic_store_unordered: {
lbValue dst = lb_build_expr(p, ce->args[0]);
lbValue val = lb_build_expr(p, ce->args[1]);
val = lb_emit_conv(p, val, type_deref(ir_type(dst)));
val = lb_emit_conv(p, val, type_deref(lb_type(dst)));
return lb_emit(p, lb_instr_atomic_store(p, dst, val, id));
}

View File

@@ -280,6 +280,29 @@ lbAddr lb_add_local_generated(lbProcedure *p, Type *type, bool zero_init);
lbValue lb_emit_runtime_call(lbProcedure *p, char const *c_name, Array<lbValue> const &args);
lbValue lb_emit_ptr_offset(lbProcedure *p, lbValue ptr, lbValue index);
lbValue lb_string_elem(lbProcedure *p, lbValue string);
lbValue lb_string_len(lbProcedure *p, lbValue string);
lbValue lb_cstring_len(lbProcedure *p, lbValue value);
lbValue lb_array_elem(lbProcedure *p, lbValue array_ptr);
lbValue lb_slice_elem(lbProcedure *p, lbValue slice);
lbValue lb_slice_len(lbProcedure *p, lbValue slice);
lbValue lb_dynamic_array_elem(lbProcedure *p, lbValue da);
lbValue lb_dynamic_array_len(lbProcedure *p, lbValue da);
lbValue lb_dynamic_array_cap(lbProcedure *p, lbValue da);
lbValue lb_dynamic_array_allocator(lbProcedure *p, lbValue da);
lbValue lb_map_entries(lbProcedure *p, lbValue value);
lbValue lb_map_entries_ptr(lbProcedure *p, lbValue value);
lbValue lb_map_len(lbProcedure *p, lbValue value);
lbValue lb_map_cap(lbProcedure *p, lbValue value);
lbValue lb_soa_struct_len(lbProcedure *p, lbValue value);
void lb_emit_increment(lbProcedure *p, lbValue addr);
lbValue lb_type_info(lbModule *m, Type *type);
#define LB_STARTUP_RUNTIME_PROC_NAME "__$startup_runtime"
#define LB_TYPE_INFO_DATA_NAME "__$type_info_data"
#define LB_TYPE_INFO_TYPES_NAME "__$type_info_types_data"