aboutsummaryrefslogtreecommitdiff
path: root/src/ir.cpp
diff options
context:
space:
mode:
authorChris Heyes <rumcode@icloud.com>2019-11-01 19:18:33 +0000
committerChris Heyes <rumcode@icloud.com>2019-11-01 19:18:33 +0000
commit153e7525b5d64f12deb318d50aee1d9dbeb1fc8e (patch)
treeb8ac88c0788af31bcb3c5041d78306c2120714f6 /src/ir.cpp
parentd85893954dccc7833e3d954db641d9fd2a3c7451 (diff)
parent44a303e5778fb8564964d53523634f34f8589489 (diff)
Merge remote-tracking branch 'upstream/master'
Diffstat (limited to 'src/ir.cpp')
-rw-r--r--src/ir.cpp963
1 files changed, 830 insertions, 133 deletions
diff --git a/src/ir.cpp b/src/ir.cpp
index 82f9fa755..e7317a960 100644
--- a/src/ir.cpp
+++ b/src/ir.cpp
@@ -147,6 +147,7 @@ struct irProcedure {
Array<irContextData> context_stack;
+ i32 parameter_count;
irValue *return_ptr_hint_value;
Ast * return_ptr_hint_ast;
@@ -174,6 +175,7 @@ gbAllocator ir_allocator(void) {
#define IR_TYPE_INFO_NAMES_NAME "__$type_info_names_data"
#define IR_TYPE_INFO_OFFSETS_NAME "__$type_info_offsets_data"
#define IR_TYPE_INFO_USINGS_NAME "__$type_info_usings_data"
+#define IR_TYPE_INFO_TAGS_NAME "__$type_info_tags_data"
#define IR_INSTR_KINDS \
@@ -424,6 +426,7 @@ enum irParamPasskind {
irParamPass_Integer, // Pass as an integer of the same size
irParamPass_ConstRef, // Pass as a pointer but the value is immutable
irParamPass_BitCast, // Pass by value and bit cast to the correct type
+ irParamPass_Tuple, // Pass across multiple parameters (System V AMD64, up to 2)
};
struct irValueParam {
@@ -432,6 +435,7 @@ struct irValueParam {
Entity * entity;
Type * type;
Type * original_type;
+ i32 index;
Array<irValue *> referrers;
};
@@ -913,15 +917,18 @@ irValue *ir_value_global(Entity *e, irValue *value) {
if (value) value->uses += 1;
return v;
}
-irValue *ir_value_param(irProcedure *parent, Entity *e, Type *abi_type) {
+irValue *ir_value_param(irProcedure *parent, Entity *e, Type *abi_type, i32 index) {
irValue *v = ir_alloc_value(irValue_Param);
v->Param.kind = irParamPass_Value;
v->Param.parent = parent;
- v->Param.entity = e;
- v->Param.original_type = e->type;
+ if (e != nullptr) {
+ v->Param.entity = e;
+ v->Param.original_type = e->type;
+ }
v->Param.type = abi_type;
+ v->Param.index = index;
- if (abi_type != e->type) {
+ if (e != nullptr && abi_type != e->type) {
if (is_type_pointer(abi_type)) {
GB_ASSERT(e->kind == Entity_Variable);
v->Param.kind = irParamPass_Pointer;
@@ -934,8 +941,12 @@ irValue *ir_value_param(irProcedure *parent, Entity *e, Type *abi_type) {
v->Param.kind = irParamPass_Value;
} else if (is_type_simd_vector(abi_type)) {
v->Param.kind = irParamPass_BitCast;
+ } else if (is_type_float(abi_type)) {
+ v->Param.kind = irParamPass_BitCast;
+ } else if (is_type_tuple(abi_type)) {
+ v->Param.kind = irParamPass_Tuple;
} else {
- GB_PANIC("Invalid abi type pass kind");
+ GB_PANIC("Invalid abi type pass kind %s", type_to_string(abi_type));
}
}
array_init(&v->Param.referrers, heap_allocator()); // TODO(bill): Replace heap allocator here
@@ -1428,7 +1439,7 @@ irValue *ir_value_procedure(irModule *m, Entity *entity, Type *type, Ast *type_e
Type *t = base_type(type);
GB_ASSERT(is_type_proc(t));
- array_init(&v->Proc.params, ir_allocator(), 0, t->Proc.param_count);
+ array_init(&v->Proc.params, heap_allocator(), 0, t->Proc.param_count);
return v;
}
@@ -1498,7 +1509,9 @@ void ir_start_block(irProcedure *proc, irBlock *block) {
}
-
+irValue *ir_emit_transmute(irProcedure *proc, irValue *value, Type *t);
+irValue *ir_address_from_load_or_generate_local(irProcedure *proc, irValue *val);
+irValue *ir_emit_struct_ep(irProcedure *proc, irValue *s, i32 index);
@@ -1539,6 +1552,7 @@ irValue *ir_add_module_constant(irModule *m, Type *type, ExactValue value) {
if (count == 0) {
return ir_value_nil(type);
}
+ count = gb_max(cl->max_count, count);
Type *elem = base_type(type)->Slice.elem;
Type *t = alloc_type_array(elem, count);
irValue *backing_array = ir_add_module_constant(m, t, value);
@@ -1712,9 +1726,12 @@ irValue *ir_add_global_generated(irModule *m, Type *type, irValue *value) {
irValue *ir_add_param(irProcedure *proc, Entity *e, Ast *expr, Type *abi_type, i32 index) {
- irValue *v = ir_value_param(proc, e, abi_type);
+ irValue *v = ir_value_param(proc, e, abi_type, index);
+ array_add(&proc->params, v);
irValueParam *p = &v->Param;
+ irValue *res = nullptr;
+
ir_push_debug_location(proc->module, e ? e->identifier : nullptr, proc->debug_scope, e);
defer (ir_pop_debug_location(proc->module));
@@ -1749,6 +1766,24 @@ irValue *ir_add_param(irProcedure *proc, Entity *e, Ast *expr, Type *abi_type, i
ir_emit_store(proc, l, x);
return x;
}
+ case irParamPass_Tuple: {
+ irValue *l = ir_add_local(proc, e, expr, true, index);
+ Type *st = struct_type_from_systemv_distribute_struct_fields(abi_type);
+ irValue *ptr = ir_emit_bitcast(proc, l, alloc_type_pointer(st));
+ if (abi_type->Tuple.variables.count > 0) {
+ array_pop(&proc->params);
+ }
+ for_array(i, abi_type->Tuple.variables) {
+ Type *t = abi_type->Tuple.variables[i]->type;
+
+ irValue *elem = ir_value_param(proc, nullptr, t, index+cast(i32)i);
+ array_add(&proc->params, elem);
+
+ irValue *dst = ir_emit_struct_ep(proc, ptr, cast(i32)i);
+ ir_emit_store(proc, dst, elem);
+ }
+ return ir_emit_load(proc, l);
+ }
}
@@ -1872,10 +1907,12 @@ irDebugEncoding ir_debug_encoding_for_basic(BasicKind kind) {
case Basic_string:
case Basic_any:
case Basic_rawptr:
+ case Basic_quaternion128:
+ case Basic_quaternion256:
break; // not a "DIBasicType"
}
- GB_PANIC("Unreachable");
+ GB_PANIC("Unreachable %d", kind);
return irDebugBasicEncoding_Invalid;
}
@@ -2221,27 +2258,11 @@ irDebugInfo *ir_add_debug_info_type_complex(irModule *module, Type *type) {
di->CompositeType.tag = irDebugBasicEncoding_structure_type;
di->CompositeType.size = ir_debug_size_bits(type);
- Type *field_type = nullptr;
- if (type->Basic.kind == Basic_complex64) {
- field_type = t_f32;
- } else if (type->Basic.kind == Basic_complex128) {
- field_type = t_f64;
- } else {
- GB_PANIC("Unreachable");
- }
+ Type *field_type = base_complex_elem_type(type);
- // Field "real"
- irDebugInfo *real_di = ir_add_debug_info_field_internal(module, str_lit("real"), field_type,
- 0,
- nullptr,
- di);
+ irDebugInfo *real_di = ir_add_debug_info_field_internal(module, str_lit("real"), field_type, 0*cast(i32)type_size_of(field_type), nullptr, di);
+ irDebugInfo *imag_di = ir_add_debug_info_field_internal(module, str_lit("imag"), field_type, 1*cast(i32)type_size_of(field_type), nullptr, di);
map_set(&module->debug_info, hash_pointer(real_di), real_di);
-
- // Field "imag"
- irDebugInfo *imag_di = ir_add_debug_info_field_internal(module, str_lit("imag"), field_type,
- real_di->DerivedType.size,
- nullptr,
- di);
map_set(&module->debug_info, hash_pointer(imag_di), imag_di);
irDebugInfo *elements_di = ir_add_debug_info_array(module, 0, 2);
@@ -2253,6 +2274,40 @@ irDebugInfo *ir_add_debug_info_type_complex(irModule *module, Type *type) {
return di;
}
+irDebugInfo *ir_add_debug_info_type_quaternion(irModule *module, Type *type) {
+ GB_ASSERT(type->kind == Type_Basic && is_type_quaternion(type));
+
+ irDebugInfo *di = ir_alloc_debug_info(irDebugInfo_CompositeType);
+ map_set(&module->debug_info, hash_type(type), di);
+
+ di->CompositeType.name = type->Basic.name;
+ di->CompositeType.tag = irDebugBasicEncoding_structure_type;
+ di->CompositeType.size = ir_debug_size_bits(type);
+
+ Type *field_type = base_complex_elem_type(type);
+
+ // @QuaternionLayout
+ irDebugInfo *imag_di = ir_add_debug_info_field_internal(module, str_lit("imag"), field_type, 0*cast(i32)type_size_of(field_type), nullptr, di);
+ irDebugInfo *jmag_di = ir_add_debug_info_field_internal(module, str_lit("jmag"), field_type, 1*cast(i32)type_size_of(field_type), nullptr, di);
+ irDebugInfo *kmag_di = ir_add_debug_info_field_internal(module, str_lit("kmag"), field_type, 2*cast(i32)type_size_of(field_type), nullptr, di);
+ irDebugInfo *real_di = ir_add_debug_info_field_internal(module, str_lit("real"), field_type, 3*cast(i32)type_size_of(field_type), nullptr, di);
+
+ map_set(&module->debug_info, hash_pointer(imag_di), imag_di);
+ map_set(&module->debug_info, hash_pointer(jmag_di), jmag_di);
+ map_set(&module->debug_info, hash_pointer(kmag_di), kmag_di);
+ map_set(&module->debug_info, hash_pointer(real_di), real_di);
+
+ irDebugInfo *elements_di = ir_add_debug_info_array(module, 0, 4);
+ array_add(&elements_di->DebugInfoArray.elements, imag_di);
+ array_add(&elements_di->DebugInfoArray.elements, jmag_di);
+ array_add(&elements_di->DebugInfoArray.elements, kmag_di);
+ array_add(&elements_di->DebugInfoArray.elements, real_di);
+ di->CompositeType.elements = elements_di;
+ map_set(&module->debug_info, hash_pointer(elements_di), elements_di);
+
+ return di;
+}
+
irDebugInfo *ir_add_debug_info_proc_type(irModule *module, Type *type) {
GB_ASSERT(type->kind == Type_Proc);
@@ -2377,10 +2432,14 @@ irDebugInfo *ir_add_debug_info_type(irModule *module, Type *type, Entity *e, irD
if (type->kind == Type_Basic) {
switch (type->Basic.kind) {
// Composite basic types
- case Basic_complex64:
- case Basic_complex128: return ir_add_debug_info_type_complex(module, type);
- case Basic_string: return ir_add_debug_info_type_string(module, scope, e, type);
- case Basic_any: return ir_add_debug_info_type_any(module);
+ case Basic_complex64: case Basic_complex128:
+ return ir_add_debug_info_type_complex(module, type);
+ case Basic_quaternion128: case Basic_quaternion256:
+ return ir_add_debug_info_type_quaternion(module, type);
+ case Basic_string:
+ return ir_add_debug_info_type_string(module, scope, e, type);
+ case Basic_any:
+ return ir_add_debug_info_type_any(module);
// Derived basic types
case Basic_cstring:
@@ -2920,10 +2979,6 @@ void ir_emit_unreachable(irProcedure *proc) {
ir_emit(proc, ir_instr_unreachable(proc));
}
-irValue *ir_emit_transmute(irProcedure *proc, irValue *value, Type *t);
-irValue *ir_address_from_load_or_generate_local(irProcedure *proc, irValue *val);
-irValue *ir_emit_struct_ep(irProcedure *proc, irValue *s, i32 index);
-
irValue *ir_get_package_value(irModule *m, String package_name, String entity_name) {
AstPackage *rt_pkg = get_core_package(m->info, package_name);
@@ -2973,7 +3028,7 @@ Array<irValue *> ir_value_to_array(irProcedure *p, irValue *value) {
}
-irValue *ir_emit_call(irProcedure *p, irValue *value, Array<irValue *> args, ProcInlining inlining = ProcInlining_none, bool use_return_ptr_hint = false) {
+irValue *ir_emit_call(irProcedure *p, irValue *value, Array<irValue *> const &args, ProcInlining inlining = ProcInlining_none, bool use_return_ptr_hint = false) {
Type *pt = base_type(ir_type(value));
GB_ASSERT(pt->kind == Type_Proc);
Type *results = pt->Proc.results;
@@ -2983,6 +3038,8 @@ irValue *ir_emit_call(irProcedure *p, irValue *value, Array<irValue *> args, Pro
context_ptr = ir_find_or_generate_context_ptr(p);
}
+ set_procedure_abi_types(heap_allocator(), pt);
+
bool is_c_vararg = pt->Proc.c_vararg;
isize param_count = pt->Proc.param_count;
if (is_c_vararg) {
@@ -2991,9 +3048,13 @@ irValue *ir_emit_call(irProcedure *p, irValue *value, Array<irValue *> args, Pro
} else {
GB_ASSERT_MSG(param_count == args.count, "%td == %td", param_count, args.count);
}
+
+ auto processed_args = array_make<irValue *>(heap_allocator(), 0, args.count);
+
for (isize i = 0; i < param_count; i++) {
Entity *e = pt->Proc.params->Tuple.variables[i];
if (e->kind != Entity_Variable) {
+ array_add(&processed_args, args[i]);
continue;
}
GB_ASSERT(e->flags & EntityFlag_Param);
@@ -3003,21 +3064,32 @@ irValue *ir_emit_call(irProcedure *p, irValue *value, Array<irValue *> args, Pro
Type *arg_type = ir_type(args[i]);
if (are_types_identical(arg_type, new_type)) {
// NOTE(bill): Done
+ array_add(&processed_args, args[i]);
} else if (!are_types_identical(original_type, new_type)) {
-
if (is_type_pointer(new_type) && !is_type_pointer(original_type)) {
- if (e->flags&EntityFlag_Value) {
- args[i] = ir_address_from_load_or_generate_local(p, args[i]);
+ if (e->flags&EntityFlag_ImplicitReference) {
+ array_add(&processed_args, ir_address_from_load_or_generate_local(p, args[i]));
} else if (!is_type_pointer(arg_type)) {
- args[i] = ir_copy_value_to_ptr(p, args[i], original_type, 16);
+ array_add(&processed_args, ir_copy_value_to_ptr(p, args[i], original_type, 16));
}
} else if (is_type_integer(new_type)) {
- args[i] = ir_emit_transmute(p, args[i], new_type);
+ array_add(&processed_args, ir_emit_transmute(p, args[i], new_type));
} else if (new_type == t_llvm_bool) {
- args[i] = ir_emit_conv(p, args[i], new_type);
+ array_add(&processed_args, ir_emit_conv(p, args[i], new_type));
} else if (is_type_simd_vector(new_type)) {
- args[i] = ir_emit_bitcast(p, args[i], new_type);
+ array_add(&processed_args, ir_emit_bitcast(p, args[i], new_type));
+ } else if (is_type_tuple(new_type)) {
+ Type *abi_type = pt->Proc.abi_compat_params[i];
+ Type *st = struct_type_from_systemv_distribute_struct_fields(abi_type);
+ irValue *x = ir_emit_transmute(p, args[i], st);
+ for (isize j = 0; j < new_type->Tuple.variables.count; j++) {
+ irValue *xx = ir_emit_struct_ev(p, x, cast(i32)j);
+ array_add(&processed_args, xx);
+ }
}
+ } else {
+ irValue *x = ir_emit_conv(p, args[i], new_type);
+ array_add(&processed_args, x);
}
}
@@ -3042,10 +3114,10 @@ irValue *ir_emit_call(irProcedure *p, irValue *value, Array<irValue *> args, Pro
return_ptr = ir_add_local_generated(p, rt, true);
}
GB_ASSERT(is_type_pointer(ir_type(return_ptr)));
- ir_emit(p, ir_instr_call(p, value, return_ptr, args, nullptr, context_ptr, inlining));
+ ir_emit(p, ir_instr_call(p, value, return_ptr, processed_args, nullptr, context_ptr, inlining));
result = ir_emit_load(p, return_ptr);
} else {
- result = ir_emit(p, ir_instr_call(p, value, nullptr, args, abi_rt, context_ptr, inlining));
+ result = ir_emit(p, ir_instr_call(p, value, nullptr, processed_args, abi_rt, context_ptr, inlining));
if (abi_rt != results) {
result = ir_emit_transmute(p, result, rt);
}
@@ -3054,7 +3126,7 @@ irValue *ir_emit_call(irProcedure *p, irValue *value, Array<irValue *> args, Pro
if (value->kind == irValue_Proc) {
irProcedure *the_proc = &value->Proc;
Entity *e = the_proc->entity;
- if (entity_has_deferred_procedure(e)) {
+ if (e != nullptr && entity_has_deferred_procedure(e)) {
DeferredProcedureKind kind = e->Procedure.deferred_procedure.kind;
Entity *deferred_entity = e->Procedure.deferred_procedure.entity;
irValue **deferred_found = map_get(&p->module->values, hash_entity(deferred_entity));
@@ -3653,12 +3725,12 @@ struct irLoopData {
irBlock *loop;
};
-irLoopData ir_loop_start(irProcedure *proc, isize count) {
+irLoopData ir_loop_start(irProcedure *proc, isize count, Type *index_type=t_int) {
irLoopData data = {};
irValue *max = ir_const_int(count);
- data.idx_addr = ir_add_local_generated(proc, t_int, true);
+ data.idx_addr = ir_add_local_generated(proc, index_type, true);
data.body = ir_new_block(proc, nullptr, "loop.body");
data.done = ir_new_block(proc, nullptr, "loop.done");
@@ -3728,7 +3800,7 @@ irValue *ir_emit_unary_arith(irProcedure *proc, TokenKind op, irValue *x, Type *
ir_emit_store(proc, ir_emit_array_epi(proc, res, i), z);
}
} else {
- auto loop_data = ir_loop_start(proc, count);
+ auto loop_data = ir_loop_start(proc, count, t_i32);
irValue *e = ir_emit_load(proc, ir_emit_array_ep(proc, val, loop_data.idx));
irValue *z = ir_emit_unary_arith(proc, op, e, elem_type);
@@ -3787,7 +3859,7 @@ irValue *ir_emit_arith(irProcedure *proc, TokenKind op, irValue *left, irValue *
ir_emit_store(proc, ir_emit_array_epi(proc, res, i), z);
}
} else {
- auto loop_data = ir_loop_start(proc, count);
+ auto loop_data = ir_loop_start(proc, count, t_i32);
irValue *x = ir_emit_load(proc, ir_emit_array_ep(proc, lhs, loop_data.idx));
irValue *y = ir_emit_load(proc, ir_emit_array_ep(proc, rhs, loop_data.idx));
@@ -3853,6 +3925,60 @@ irValue *ir_emit_arith(irProcedure *proc, TokenKind op, irValue *left, irValue *
return ir_emit_load(proc, res);
}
+ if (is_type_quaternion(t_left)) {
+ ir_emit_comment(proc, str_lit("complex.arith.begin"));
+ defer (ir_emit_comment(proc, str_lit("complex.arith.end")));
+
+ right = ir_emit_conv(proc, right, t_left);
+
+ Type *ft = base_complex_elem_type(t_left);
+
+ if (op == Token_Add || op == Token_Sub) {
+ irValue *res = ir_add_local_generated(proc, type, false); // NOTE: initialized in full later
+ irValue *x0 = ir_emit_struct_ev(proc, left, 0);
+ irValue *x1 = ir_emit_struct_ev(proc, left, 1);
+ irValue *x2 = ir_emit_struct_ev(proc, left, 2);
+ irValue *x3 = ir_emit_struct_ev(proc, left, 3);
+
+ irValue *y0 = ir_emit_struct_ev(proc, right, 0);
+ irValue *y1 = ir_emit_struct_ev(proc, right, 1);
+ irValue *y2 = ir_emit_struct_ev(proc, right, 2);
+ irValue *y3 = ir_emit_struct_ev(proc, right, 3);
+
+ irValue *z0 = ir_emit_arith(proc, op, x0, y0, ft);
+ irValue *z1 = ir_emit_arith(proc, op, x1, y1, ft);
+ irValue *z2 = ir_emit_arith(proc, op, x2, y2, ft);
+ irValue *z3 = ir_emit_arith(proc, op, x3, y3, ft);
+
+ ir_emit_store(proc, ir_emit_struct_ep(proc, res, 0), z0);
+ ir_emit_store(proc, ir_emit_struct_ep(proc, res, 1), z1);
+ ir_emit_store(proc, ir_emit_struct_ep(proc, res, 2), z2);
+ ir_emit_store(proc, ir_emit_struct_ep(proc, res, 3), z3);
+
+ return ir_emit_load(proc, res);
+ } else if (op == Token_Mul) {
+ auto args = array_make<irValue *>(heap_allocator(), 2);
+ args[0] = left;
+ args[1] = right;
+
+ switch (8*type_size_of(ft)) {
+ case 32: return ir_emit_runtime_call(proc, "mul_quaternion128", args);
+ case 64: return ir_emit_runtime_call(proc, "mul_quaternion256", args);
+ default: GB_PANIC("Unknown float type"); break;
+ }
+ } else if (op == Token_Quo) {
+ auto args = array_make<irValue *>(heap_allocator(), 2);
+ args[0] = left;
+ args[1] = right;
+
+ switch (8*type_size_of(ft)) {
+ case 32: return ir_emit_runtime_call(proc, "quo_quaternion128", args);
+ case 64: return ir_emit_runtime_call(proc, "quo_quaternion256", args);
+ default: GB_PANIC("Unknown float type"); break;
+ }
+ }
+ }
+
#if 0
if (op == Token_Add) {
@@ -4018,6 +4144,15 @@ irValue *ir_emit_comp_against_nil(irProcedure *proc, TokenKind op_kind, irValue
} else if (is_type_typeid(t)) {
irValue *invalid_typeid = ir_value_constant(t_typeid, exact_value_i64(0));
return ir_emit_comp(proc, op_kind, x, invalid_typeid);
+ } else if (is_type_bit_field(t)) {
+ auto args = array_make<irValue *>(heap_allocator(), 2);
+ irValue *lhs = ir_address_from_load_or_generate_local(proc, x);
+ args[0] = ir_emit_conv(proc, lhs, t_rawptr);
+ args[1] = ir_const_int(type_size_of(t));
+ irValue *val = ir_emit_runtime_call(proc, "memory_compare_zero", args);
+ irValue *res = ir_emit_comp(proc, op_kind, val, v_zero);
+ return ir_emit_conv(proc, res, t_bool);
+
}
return nullptr;
}
@@ -4105,6 +4240,9 @@ irValue *ir_emit_comp(irProcedure *proc, TokenKind op_kind, irValue *left, irVal
if (op_kind == Token_NotEq) {
res = v_false;
cmp_op = Token_Or;
+ } else if (op_kind == Token_CmpEq) {
+ res = v_true;
+ cmp_op = Token_And;
}
bool inline_array_arith = type_size_of(tl) <= build_context.max_align;
@@ -4112,28 +4250,43 @@ irValue *ir_emit_comp(irProcedure *proc, TokenKind op_kind, irValue *left, irVal
if (inline_array_arith) {
// inline
+ irValue *val = ir_add_local_generated(proc, t_bool, false);
+ ir_emit_store(proc, val, res);
for (i32 i = 0; i < count; i++) {
irValue *x = ir_emit_load(proc, ir_emit_array_epi(proc, lhs, i));
irValue *y = ir_emit_load(proc, ir_emit_array_epi(proc, rhs, i));
irValue *cmp = ir_emit_comp(proc, op_kind, x, y);
- res = ir_emit_arith(proc, cmp_op, res, cmp, t_bool);
- }
-
- return ir_emit_conv(proc, res, t_bool);
- } else {
- irValue *val = ir_add_local_generated(proc, t_bool, false);
- ir_emit_store(proc, val, res);
- auto loop_data = ir_loop_start(proc, count);
- {
- irValue *x = ir_emit_load(proc, ir_emit_array_ep(proc, lhs, loop_data.idx));
- irValue *y = ir_emit_load(proc, ir_emit_array_ep(proc, rhs, loop_data.idx));
- irValue *cmp = ir_emit_comp(proc, op_kind, x, y);
- irValue *new_res = ir_emit_arith(proc, cmp_op, res, cmp, t_bool);
+ irValue *new_res = ir_emit_arith(proc, cmp_op, ir_emit_load(proc, val), cmp, t_bool);
ir_emit_store(proc, val, ir_emit_conv(proc, new_res, t_bool));
}
- ir_loop_end(proc, loop_data);
return ir_emit_load(proc, val);
+ } else {
+ if (is_type_simple_compare(tl) && (op_kind == Token_CmpEq || op_kind == Token_NotEq)) {
+ // TODO(bill): Test to see if this is actually faster!!!!
+ auto args = array_make<irValue *>(heap_allocator(), 3);
+ args[0] = ir_emit_conv(proc, lhs, t_rawptr);
+ args[1] = ir_emit_conv(proc, rhs, t_rawptr);
+ args[2] = ir_const_int(type_size_of(tl));
+ irValue *val = ir_emit_runtime_call(proc, "memory_compare", args);
+ irValue *res = ir_emit_comp(proc, op_kind, val, v_zero);
+ return ir_emit_conv(proc, res, t_bool);
+ } else {
+ irValue *val = ir_add_local_generated(proc, t_bool, false);
+ ir_emit_store(proc, val, res);
+ auto loop_data = ir_loop_start(proc, count, t_i32);
+ {
+ irValue *i = loop_data.idx;
+ irValue *x = ir_emit_load(proc, ir_emit_array_ep(proc, lhs, i));
+ irValue *y = ir_emit_load(proc, ir_emit_array_ep(proc, rhs, i));
+ irValue *cmp = ir_emit_comp(proc, op_kind, x, y);
+ irValue *new_res = ir_emit_arith(proc, cmp_op, ir_emit_load(proc, val), cmp, t_bool);
+ ir_emit_store(proc, val, ir_emit_conv(proc, new_res, t_bool));
+ }
+ ir_loop_end(proc, loop_data);
+
+ return ir_emit_load(proc, val);
+ }
}
}
@@ -4161,7 +4314,7 @@ irValue *ir_emit_comp(irProcedure *proc, TokenKind op_kind, irValue *left, irVal
}
if (is_type_complex(a)) {
- char *runtime_proc = "";
+ char const *runtime_proc = "";
i64 sz = 8*type_size_of(a);
switch (sz) {
case 64:
@@ -4185,6 +4338,31 @@ irValue *ir_emit_comp(irProcedure *proc, TokenKind op_kind, irValue *left, irVal
return ir_emit_runtime_call(proc, runtime_proc, args);
}
+ if (is_type_quaternion(a)) {
+ char const *runtime_proc = "";
+ i64 sz = 8*type_size_of(a);
+ switch (sz) {
+ case 128:
+ switch (op_kind) {
+ case Token_CmpEq: runtime_proc = "quaternion128_eq"; break;
+ case Token_NotEq: runtime_proc = "quaternion128_ne"; break;
+ }
+ break;
+ case 256:
+ switch (op_kind) {
+ case Token_CmpEq: runtime_proc = "quaternion256_eq"; break;
+ case Token_NotEq: runtime_proc = "quaternion256_ne"; break;
+ }
+ break;
+ }
+ GB_ASSERT(runtime_proc != nullptr);
+
+ auto args = array_make<irValue *>(ir_allocator(), 2);
+ args[0] = left;
+ args[1] = right;
+ return ir_emit_runtime_call(proc, runtime_proc, args);
+ }
+
if (is_type_bit_set(a)) {
switch (op_kind) {
case Token_Lt:
@@ -4268,11 +4446,18 @@ irValue *ir_emit_struct_ep(irProcedure *proc, irValue *s, i32 index) {
case 0: result_type = alloc_type_pointer(ft); break;
case 1: result_type = alloc_type_pointer(ft); break;
}
+ } else if (is_type_quaternion(t)) {
+ Type *ft = base_complex_elem_type(t);
+ switch (index) {
+ case 0: result_type = alloc_type_pointer(ft); break;
+ case 1: result_type = alloc_type_pointer(ft); break;
+ case 2: result_type = alloc_type_pointer(ft); break;
+ case 3: result_type = alloc_type_pointer(ft); break;
+ }
} else if (is_type_slice(t)) {
switch (index) {
case 0: result_type = alloc_type_pointer(alloc_type_pointer(t->Slice.elem)); break;
case 1: result_type = alloc_type_pointer(t_int); break;
- case 2: result_type = alloc_type_pointer(t_int); break;
}
} else if (is_type_string(t)) {
switch (index) {
@@ -4343,6 +4528,17 @@ irValue *ir_emit_struct_ev(irProcedure *proc, irValue *s, i32 index) {
}
break;
}
+ case Basic_quaternion128: case Basic_quaternion256:
+ {
+ Type *ft = base_complex_elem_type(t);
+ switch (index) {
+ case 0: result_type = ft; break;
+ case 1: result_type = ft; break;
+ case 2: result_type = ft; break;
+ case 3: result_type = ft; break;
+ }
+ break;
+ }
}
break;
case Type_Struct:
@@ -4401,13 +4597,14 @@ irValue *ir_emit_deep_field_gep(irProcedure *proc, irValue *e, Selection sel) {
if (is_type_pointer(type)) {
type = type_deref(type);
e = ir_emit_load(proc, e);
- e = ir_emit_ptr_offset(proc, e, v_zero); // TODO(bill): Do I need these copies?
+ // e = ir_emit_ptr_offset(proc, e, v_zero); // TODO(bill): Do I need these copies?
}
type = core_type(type);
if (is_type_raw_union(type)) {
type = type->Struct.fields[index]->type;
- e = ir_emit_conv(proc, e, alloc_type_pointer(type));
+ GB_ASSERT(is_type_pointer(ir_type(e)));
+ e = ir_emit_bitcast(proc, e, alloc_type_pointer(type));
} else if (is_type_struct(type)) {
type = type->Struct.fields[index]->type;
e = ir_emit_struct_ep(proc, e, index);
@@ -4725,6 +4922,8 @@ irValue *ir_emit_conv(irProcedure *proc, irValue *value, Type *t) {
ev = exact_value_to_float(ev);
} else if (is_type_complex(dst)) {
ev = exact_value_to_complex(ev);
+ } else if (is_type_quaternion(dst)) {
+ ev = exact_value_to_quaternion(ev);
} else if (is_type_string(dst)) {
// Handled elsewhere
GB_ASSERT_MSG(ev.kind == ExactValue_String, "%d", ev.kind);
@@ -4848,6 +5047,49 @@ irValue *ir_emit_conv(irProcedure *proc, irValue *value, Type *t) {
return ir_emit_load(proc, gen);
}
+ if (is_type_quaternion(src) && is_type_quaternion(dst)) {
+ // @QuaternionLayout
+ Type *ft = base_complex_elem_type(dst);
+ irValue *gen = ir_add_local_generated(proc, dst, false);
+ irValue *q0 = ir_emit_conv(proc, ir_emit_struct_ev(proc, value, 0), ft);
+ irValue *q1 = ir_emit_conv(proc, ir_emit_struct_ev(proc, value, 1), ft);
+ irValue *q2 = ir_emit_conv(proc, ir_emit_struct_ev(proc, value, 2), ft);
+ irValue *q3 = ir_emit_conv(proc, ir_emit_struct_ev(proc, value, 3), ft);
+ ir_emit_store(proc, ir_emit_struct_ep(proc, gen, 0), q0);
+ ir_emit_store(proc, ir_emit_struct_ep(proc, gen, 1), q1);
+ ir_emit_store(proc, ir_emit_struct_ep(proc, gen, 2), q2);
+ ir_emit_store(proc, ir_emit_struct_ep(proc, gen, 3), q3);
+ return ir_emit_load(proc, gen);
+ }
+
+ if (is_type_float(src) && is_type_complex(dst)) {
+ Type *ft = base_complex_elem_type(dst);
+ irValue *gen = ir_add_local_generated(proc, dst, true);
+ irValue *real = ir_emit_conv(proc, value, ft);
+ ir_emit_store(proc, ir_emit_struct_ep(proc, gen, 0), real);
+ return ir_emit_load(proc, gen);
+ }
+ if (is_type_float(src) && is_type_quaternion(dst)) {
+ Type *ft = base_complex_elem_type(dst);
+ irValue *gen = ir_add_local_generated(proc, dst, true);
+ irValue *real = ir_emit_conv(proc, value, ft);
+ // @QuaternionLayout
+ ir_emit_store(proc, ir_emit_struct_ep(proc, gen, 3), real);
+ return ir_emit_load(proc, gen);
+ }
+ if (is_type_complex(src) && is_type_quaternion(dst)) {
+ Type *ft = base_complex_elem_type(dst);
+ irValue *gen = ir_add_local_generated(proc, dst, true);
+ irValue *real = ir_emit_conv(proc, ir_emit_struct_ev(proc, value, 0), ft);
+ irValue *imag = ir_emit_conv(proc, ir_emit_struct_ev(proc, value, 1), ft);
+ // @QuaternionLayout
+ ir_emit_store(proc, ir_emit_struct_ep(proc, gen, 3), real);
+ ir_emit_store(proc, ir_emit_struct_ep(proc, gen, 0), imag);
+ return ir_emit_load(proc, gen);
+ }
+
+
+
// float <-> integer
if (is_type_float(src) && is_type_integer(dst)) {
irConvKind kind = irConv_fptosi;
@@ -5245,12 +5487,14 @@ gb_global irValue *ir_global_type_info_member_types = nullptr;
gb_global irValue *ir_global_type_info_member_names = nullptr;
gb_global irValue *ir_global_type_info_member_offsets = nullptr;
gb_global irValue *ir_global_type_info_member_usings = nullptr;
+gb_global irValue *ir_global_type_info_member_tags = nullptr;
gb_global i32 ir_global_type_info_data_index = 0;
gb_global i32 ir_global_type_info_member_types_index = 0;
gb_global i32 ir_global_type_info_member_names_index = 0;
gb_global i32 ir_global_type_info_member_offsets_index = 0;
gb_global i32 ir_global_type_info_member_usings_index = 0;
+gb_global i32 ir_global_type_info_member_tags_index = 0;
isize ir_type_info_count(CheckerInfo *info) {
return info->minimum_dependency_type_info_set.entries.count+1;
@@ -5286,6 +5530,7 @@ enum Typeid_Kind : u8 {
Typeid_Rune,
Typeid_Float,
Typeid_Complex,
+ Typeid_Quaternion,
Typeid_String,
Typeid_Boolean,
Typeid_Any,
@@ -5402,7 +5647,8 @@ irValue *ir_emit_logical_binary_expr(irProcedure *proc, TokenKind op, Ast *left,
}
ir_start_block(proc, rhs);
- array_add(&edges, ir_build_expr(proc, right));
+ irValue *edge = ir_build_expr(proc, right);
+ array_add(&edges, edge);
ir_emit_jump(proc, done);
ir_start_block(proc, done);
@@ -5411,8 +5657,6 @@ irValue *ir_emit_logical_binary_expr(irProcedure *proc, TokenKind op, Ast *left,
irValue *ir_emit_logical_binary_expr(irProcedure *proc, Ast *expr) {
ast_node(be, BinaryExpr, expr);
- irBlock *rhs = ir_new_block(proc, nullptr, "logical.cmp.rhs");
- irBlock *done = ir_new_block(proc, nullptr, "logical.cmp.done");
Type *type = type_of_expr(expr);
type = default_type(type);
@@ -6038,17 +6282,77 @@ irValue *ir_build_builtin_proc(irProcedure *proc, Ast *expr, TypeAndValue tv, Bu
return ir_emit_load(proc, dst);
}
+ case BuiltinProc_quaternion: {
+ ir_emit_comment(proc, str_lit("quaternion"));
+ irValue *real = ir_build_expr(proc, ce->args[0]);
+ irValue *imag = ir_build_expr(proc, ce->args[1]);
+ irValue *jmag = ir_build_expr(proc, ce->args[2]);
+ irValue *kmag = ir_build_expr(proc, ce->args[3]);
+
+ // @QuaternionLayout
+ irValue *dst = ir_add_local_generated(proc, tv.type, false);
+ Type *ft = base_complex_elem_type(tv.type);
+ real = ir_emit_conv(proc, real, ft);
+ imag = ir_emit_conv(proc, imag, ft);
+ jmag = ir_emit_conv(proc, jmag, ft);
+ kmag = ir_emit_conv(proc, kmag, ft);
+ ir_emit_store(proc, ir_emit_struct_ep(proc, dst, 3), real);
+ ir_emit_store(proc, ir_emit_struct_ep(proc, dst, 0), imag);
+ ir_emit_store(proc, ir_emit_struct_ep(proc, dst, 1), jmag);
+ ir_emit_store(proc, ir_emit_struct_ep(proc, dst, 2), kmag);
+
+ return ir_emit_load(proc, dst);
+ }
+
case BuiltinProc_real: {
ir_emit_comment(proc, str_lit("real"));
irValue *val = ir_build_expr(proc, ce->args[0]);
- irValue *real = ir_emit_struct_ev(proc, val, 0);
- return ir_emit_conv(proc, real, tv.type);
+ if (is_type_complex(ir_type(val))) {
+ irValue *real = ir_emit_struct_ev(proc, val, 0);
+ return ir_emit_conv(proc, real, tv.type);
+ } else if (is_type_quaternion(ir_type(val))) {
+ // @QuaternionLayout
+ irValue *real = ir_emit_struct_ev(proc, val, 3);
+ return ir_emit_conv(proc, real, tv.type);
+ }
+ GB_PANIC("invalid type for real");
+ return nullptr;
}
case BuiltinProc_imag: {
ir_emit_comment(proc, str_lit("imag"));
irValue *val = ir_build_expr(proc, ce->args[0]);
- irValue *imag = ir_emit_struct_ev(proc, val, 1);
- return ir_emit_conv(proc, imag, tv.type);
+ if (is_type_complex(ir_type(val))) {
+ irValue *imag = ir_emit_struct_ev(proc, val, 1);
+ return ir_emit_conv(proc, imag, tv.type);
+ } else if (is_type_quaternion(ir_type(val))) {
+ // @QuaternionLayout
+ irValue *imag = ir_emit_struct_ev(proc, val, 0);
+ return ir_emit_conv(proc, imag, tv.type);
+ }
+ GB_PANIC("invalid type for imag");
+ return nullptr;
+ }
+ case BuiltinProc_jmag: {
+ ir_emit_comment(proc, str_lit("jmag"));
+ irValue *val = ir_build_expr(proc, ce->args[0]);
+ if (is_type_quaternion(ir_type(val))) {
+ // @QuaternionLayout
+ irValue *imag = ir_emit_struct_ev(proc, val, 1);
+ return ir_emit_conv(proc, imag, tv.type);
+ }
+ GB_PANIC("invalid type for jmag");
+ return nullptr;
+ }
+ case BuiltinProc_kmag: {
+ ir_emit_comment(proc, str_lit("kmag"));
+ irValue *val = ir_build_expr(proc, ce->args[0]);
+ if (is_type_quaternion(ir_type(val))) {
+ // @QuaternionLayout
+ irValue *imag = ir_emit_struct_ev(proc, val, 2);
+ return ir_emit_conv(proc, imag, tv.type);
+ }
+ GB_PANIC("invalid type for kmag");
+ return nullptr;
}
case BuiltinProc_conj: {
@@ -6063,6 +6367,20 @@ irValue *ir_build_builtin_proc(irProcedure *proc, Ast *expr, TypeAndValue tv, Bu
imag = ir_emit_unary_arith(proc, Token_Sub, imag, ir_type(imag));
ir_emit_store(proc, ir_emit_struct_ep(proc, res, 0), real);
ir_emit_store(proc, ir_emit_struct_ep(proc, res, 1), imag);
+ } else if (is_type_quaternion(t)) {
+ // @QuaternionLayout
+ res = ir_add_local_generated(proc, tv.type, false);
+ irValue *real = ir_emit_struct_ev(proc, val, 3);
+ irValue *imag = ir_emit_struct_ev(proc, val, 0);
+ irValue *jmag = ir_emit_struct_ev(proc, val, 1);
+ irValue *kmag = ir_emit_struct_ev(proc, val, 2);
+ imag = ir_emit_unary_arith(proc, Token_Sub, imag, ir_type(imag));
+ jmag = ir_emit_unary_arith(proc, Token_Sub, jmag, ir_type(jmag));
+ kmag = ir_emit_unary_arith(proc, Token_Sub, kmag, ir_type(kmag));
+ ir_emit_store(proc, ir_emit_struct_ep(proc, res, 3), real);
+ ir_emit_store(proc, ir_emit_struct_ep(proc, res, 0), imag);
+ ir_emit_store(proc, ir_emit_struct_ep(proc, res, 1), jmag);
+ ir_emit_store(proc, ir_emit_struct_ep(proc, res, 2), kmag);
}
return ir_emit_load(proc, res);
}
@@ -6133,7 +6451,16 @@ irValue *ir_build_builtin_proc(irProcedure *proc, Ast *expr, TypeAndValue tv, Bu
return x;
}
ir_emit_comment(proc, str_lit("abs"));
- if (is_type_complex(t)) {
+ if (is_type_quaternion(t)) {
+ i64 sz = 8*type_size_of(t);
+ auto args = array_make<irValue *>(ir_allocator(), 1);
+ args[0] = x;
+ switch (sz) {
+ case 128: return ir_emit_runtime_call(proc, "abs_quaternion128", args);
+ case 256: return ir_emit_runtime_call(proc, "abs_quaternion256", args);
+ }
+ GB_PANIC("Unknown complex type");
+ } else if (is_type_complex(t)) {
i64 sz = 8*type_size_of(t);
auto args = array_make<irValue *>(ir_allocator(), 1);
args[0] = x;
@@ -6312,6 +6639,11 @@ irValue *ir_build_expr_internal(irProcedure *proc, Ast *expr) {
return ir_emit_conv(proc, x, tv.type);
}
+ if (tv.value.kind == ExactValue_Typeid) {
+ irValue *v = ir_typeid(proc->module, tv.value.value_typeid);
+ return ir_emit_conv(proc, v, tv.type);
+ }
+
return ir_add_module_constant(proc->module, tv.type, tv.value);
}
@@ -6546,9 +6878,6 @@ irValue *ir_build_expr_internal(irProcedure *proc, Ast *expr) {
case_end;
case_ast_node(be, BinaryExpr, expr);
- irValue *left = ir_build_expr(proc, be->left);
- Type *type = default_type(tv.type);
-
switch (be->op.kind) {
case Token_Add:
case Token_Sub:
@@ -6562,6 +6891,8 @@ irValue *ir_build_expr_internal(irProcedure *proc, Ast *expr) {
case Token_AndNot:
case Token_Shl:
case Token_Shr: {
+ irValue *left = ir_build_expr(proc, be->left);
+ Type *type = default_type(tv.type);
irValue *right = ir_build_expr(proc, be->right);
return ir_emit_arith(proc, be->op.kind, left, right, type);
}
@@ -6573,10 +6904,11 @@ irValue *ir_build_expr_internal(irProcedure *proc, Ast *expr) {
case Token_LtEq:
case Token_Gt:
case Token_GtEq: {
+ irValue *left = ir_build_expr(proc, be->left);
+ Type *type = default_type(tv.type);
irValue *right = ir_build_expr(proc, be->right);
irValue *cmp = ir_emit_comp(proc, be->op.kind, left, right);
return ir_emit_conv(proc, cmp, type);
- break;
}
case Token_CmpAnd:
@@ -6586,6 +6918,8 @@ irValue *ir_build_expr_internal(irProcedure *proc, Ast *expr) {
case Token_in:
case Token_notin: {
+ irValue *left = ir_build_expr(proc, be->left);
+ Type *type = default_type(tv.type);
irValue *right = ir_build_expr(proc, be->right);
Type *rt = base_type(ir_type(right));
switch (rt->kind) {
@@ -6687,7 +7021,34 @@ irValue *ir_build_expr_internal(irProcedure *proc, Ast *expr) {
}
// NOTE(bill): Regular call
- irValue *value = ir_build_expr(proc, ce->proc);
+ irValue *value = nullptr;
+ Ast *proc_expr = unparen_expr(ce->proc);
+ if (proc_expr->tav.mode == Addressing_Constant) {
+ ExactValue v = proc_expr->tav.value;
+ switch (v.kind) {
+ case ExactValue_Integer:
+ {
+ u64 u = big_int_to_u64(&v.value_integer);
+ irValue *x = ir_const_uintptr(u);
+ x = ir_emit_conv(proc, x, t_rawptr);
+ value = ir_emit_conv(proc, x, proc_expr->tav.type);
+ break;
+ }
+ case ExactValue_Pointer:
+ {
+ u64 u = cast(u64)v.value_pointer;
+ irValue *x = ir_const_uintptr(u);
+ x = ir_emit_conv(proc, x, t_rawptr);
+ value = ir_emit_conv(proc, x, proc_expr->tav.type);
+ break;
+ }
+ }
+ }
+
+ if (value == nullptr) {
+ value = ir_build_expr(proc, proc_expr);
+ }
+
GB_ASSERT(value != nullptr);
Type *proc_type_ = base_type(ir_type(value));
GB_ASSERT(proc_type_->kind == Type_Proc);
@@ -7501,13 +7862,55 @@ irAddr ir_build_addr(irProcedure *proc, Ast *expr) {
// NOTE(bill): Separate value, gep, store into their own chunks
for_array(i, cl->elems) {
Ast *elem = cl->elems[i];
- if (ir_is_elem_const(proc->module, elem, et)) {
- continue;
+ if (elem->kind == Ast_FieldValue) {
+ ast_node(fv, FieldValue, elem);
+ if (ir_is_elem_const(proc->module, fv->value, et)) {
+ continue;
+ }
+ if (is_ast_range(fv->field)) {
+ ast_node(ie, BinaryExpr, fv->field);
+ TypeAndValue lo_tav = ie->left->tav;
+ TypeAndValue hi_tav = ie->right->tav;
+ GB_ASSERT(lo_tav.mode == Addressing_Constant);
+ GB_ASSERT(hi_tav.mode == Addressing_Constant);
+
+ TokenKind op = ie->op.kind;
+ i64 lo = exact_value_to_i64(lo_tav.value);
+ i64 hi = exact_value_to_i64(hi_tav.value);
+ if (op == Token_Ellipsis) {
+ hi += 1;
+ }
+
+ irValue *value = ir_build_expr(proc, fv->value);
+
+ for (i64 k = lo; k < hi; k++) {
+ irCompoundLitElemTempData data = {};
+ data.value = value;
+ data.elem_index = cast(i32)k;
+ array_add(&temp_data, data);
+ }
+
+ } else {
+ auto tav = fv->field->tav;
+ GB_ASSERT(tav.mode == Addressing_Constant);
+ i64 index = exact_value_to_i64(tav.value);
+
+ irCompoundLitElemTempData data = {};
+ data.value = ir_emit_conv(proc, ir_build_expr(proc, fv->value), et);
+ data.expr = fv->value;
+ data.elem_index = cast(i32)index;
+ array_add(&temp_data, data);
+ }
+
+ } else {
+ if (ir_is_elem_const(proc->module, elem, et)) {
+ continue;
+ }
+ irCompoundLitElemTempData data = {};
+ data.expr = elem;
+ data.elem_index = cast(i32)i;
+ array_add(&temp_data, data);
}
- irCompoundLitElemTempData data = {};
- data.expr = elem;
- data.elem_index = cast(i32)i;
- array_add(&temp_data, data);
}
for_array(i, temp_data) {
@@ -7522,12 +7925,15 @@ irAddr ir_build_addr(irProcedure *proc, Ast *expr) {
defer (proc->return_ptr_hint_value = return_ptr_hint_value);
defer (proc->return_ptr_hint_used = return_ptr_hint_used);
+ irValue *field_expr = temp_data[i].value;
Ast *expr = temp_data[i].expr;
proc->return_ptr_hint_value = temp_data[i].gep;
proc->return_ptr_hint_ast = unparen_expr(expr);
- irValue *field_expr = ir_build_expr(proc, expr);
+ if (field_expr == nullptr) {
+ field_expr = ir_build_expr(proc, expr);
+ }
Type *t = ir_type(field_expr);
GB_ASSERT(t->kind != Type_Tuple);
irValue *ev = ir_emit_conv(proc, field_expr, et);
@@ -7560,18 +7966,64 @@ irAddr ir_build_addr(irProcedure *proc, Ast *expr) {
for_array(i, cl->elems) {
Ast *elem = cl->elems[i];
- if (ir_is_elem_const(proc->module, elem, et)) {
- continue;
- }
- irValue *field_expr = ir_build_expr(proc, elem);
- Type *t = ir_type(field_expr);
- GB_ASSERT(t->kind != Type_Tuple);
- irValue *ev = ir_emit_conv(proc, field_expr, et);
+ if (elem->kind == Ast_FieldValue) {
+ ast_node(fv, FieldValue, elem);
+
+ if (ir_is_elem_const(proc->module, fv->value, et)) {
+ continue;
+ }
+
+ if (is_ast_range(fv->field)) {
+ ast_node(ie, BinaryExpr, fv->field);
+ TypeAndValue lo_tav = ie->left->tav;
+ TypeAndValue hi_tav = ie->right->tav;
+ GB_ASSERT(lo_tav.mode == Addressing_Constant);
+ GB_ASSERT(hi_tav.mode == Addressing_Constant);
+
+ TokenKind op = ie->op.kind;
+ i64 lo = exact_value_to_i64(lo_tav.value);
+ i64 hi = exact_value_to_i64(hi_tav.value);
+ if (op == Token_Ellipsis) {
+ hi += 1;
+ }
+
+ irValue *value = ir_emit_conv(proc, ir_build_expr(proc, fv->value), et);
+
+ for (i64 k = lo; k < hi; k++) {
+ irCompoundLitElemTempData data = {};
+ data.value = value;
+ data.elem_index = cast(i32)k;
+ array_add(&temp_data, data);
+ }
+
+ } else {
+ GB_ASSERT(fv->field->tav.mode == Addressing_Constant);
+ i64 index = exact_value_to_i64(fv->field->tav.value);
- irCompoundLitElemTempData data = {};
- data.value = ev;
- data.elem_index = cast(i32)i;
- array_add(&temp_data, data);
+ irValue *field_expr = ir_build_expr(proc, fv->value);
+ GB_ASSERT(!is_type_tuple(ir_type(field_expr)));
+
+ irValue *ev = ir_emit_conv(proc, field_expr, et);
+
+ irCompoundLitElemTempData data = {};
+ data.value = ev;
+ data.elem_index = cast(i32)index;
+ array_add(&temp_data, data);
+ }
+ } else {
+ if (ir_is_elem_const(proc->module, elem, et)) {
+ continue;
+ }
+ irValue *field_expr = ir_build_expr(proc, elem);
+ GB_ASSERT(!is_type_tuple(ir_type(field_expr)));
+
+ irValue *ev = ir_emit_conv(proc, field_expr, et);
+
+ irCompoundLitElemTempData data = {};
+ data.value = ev;
+ data.elem_index = cast(i32)i;
+ array_add(&temp_data, data);
+ }
}
for_array(i, temp_data) {
@@ -7592,28 +8044,64 @@ irAddr ir_build_addr(irProcedure *proc, Ast *expr) {
if (cl->elems.count == 0) {
break;
}
- Type *elem = bt->DynamicArray.elem;
+ Type *et = bt->DynamicArray.elem;
gbAllocator a = ir_allocator();
- irValue *size = ir_const_int(type_size_of(elem));
- irValue *align = ir_const_int(type_align_of(elem));
+ irValue *size = ir_const_int(type_size_of(et));
+ irValue *align = ir_const_int(type_align_of(et));
+
+ i64 item_count = gb_max(cl->max_count, cl->elems.count);
{
+
auto args = array_make<irValue *>(a, 5);
args[0] = ir_emit_conv(proc, v, t_rawptr);
args[1] = size;
args[2] = align;
- args[3] = ir_const_int(2*cl->elems.count);
+ args[3] = ir_const_int(2*item_count); // TODO(bill): Is this too much waste?
args[4] = ir_emit_source_code_location(proc, proc_name, pos);
ir_emit_runtime_call(proc, "__dynamic_array_reserve", args);
}
- i64 item_count = cl->elems.count;
- irValue *items = ir_generate_array(proc->module, elem, item_count, str_lit("dacl$"), cast(i64)cast(intptr)expr);
+ irValue *items = ir_generate_array(proc->module, et, item_count, str_lit("dacl$"), cast(i64)cast(intptr)expr);
+
+ for_array(i, cl->elems) {
+ Ast *elem = cl->elems[i];
+ if (elem->kind == Ast_FieldValue) {
+ ast_node(fv, FieldValue, elem);
+ if (is_ast_range(fv->field)) {
+ ast_node(ie, BinaryExpr, fv->field);
+ TypeAndValue lo_tav = ie->left->tav;
+ TypeAndValue hi_tav = ie->right->tav;
+ GB_ASSERT(lo_tav.mode == Addressing_Constant);
+ GB_ASSERT(hi_tav.mode == Addressing_Constant);
+
+ TokenKind op = ie->op.kind;
+ i64 lo = exact_value_to_i64(lo_tav.value);
+ i64 hi = exact_value_to_i64(hi_tav.value);
+ if (op == Token_Ellipsis) {
+ hi += 1;
+ }
- for_array(field_index, cl->elems) {
- Ast *f = cl->elems[field_index];
- irValue *value = ir_emit_conv(proc, ir_build_expr(proc, f), elem);
- irValue *ep = ir_emit_array_epi(proc, items, cast(i32)field_index);
- ir_emit_store(proc, ep, value);
+ irValue *value = ir_emit_conv(proc, ir_build_expr(proc, fv->value), et);
+
+ for (i64 k = lo; k < hi; k++) {
+ irValue *ep = ir_emit_array_epi(proc, items, cast(i32)k);
+ ir_emit_store(proc, ep, value);
+ }
+ } else {
+ GB_ASSERT(fv->field->tav.mode == Addressing_Constant);
+
+ i64 field_index = exact_value_to_i64(fv->field->tav.value);
+
+ irValue *ev = ir_build_expr(proc, fv->value);
+ irValue *value = ir_emit_conv(proc, ev, et);
+ irValue *ep = ir_emit_array_epi(proc, items, cast(i32)field_index);
+ ir_emit_store(proc, ep, value);
+ }
+ } else {
+ irValue *value = ir_emit_conv(proc, ir_build_expr(proc, elem), et);
+ irValue *ep = ir_emit_array_epi(proc, items, cast(i32)i);
+ ir_emit_store(proc, ep, value);
+ }
}
{
@@ -7907,24 +8395,27 @@ void ir_build_constant_value_decl(irProcedure *proc, AstValueDecl *vd) {
name = e->Procedure.link_name;
}
+ HashKey key = hash_string(name);
+ irValue **prev_value = map_get(&proc->module->members, key);
+ if (prev_value != nullptr) {
+ // NOTE(bill): Don't do mutliple declarations in the IR
+ return;
+ }
+
+
irValue *value = ir_value_procedure(proc->module, e, e->type, pl->type, pl->body, name);
value->Proc.tags = pl->tags;
value->Proc.inlining = pl->inlining;
- ir_module_add_value(proc->module, e, value);
- ir_build_proc(value, proc);
-
if (value->Proc.is_foreign || value->Proc.is_export) {
- HashKey key = hash_string(name);
- irValue **prev_value = map_get(&proc->module->members, key);
- if (prev_value == nullptr) {
- // NOTE(bill): Don't do mutliple declarations in the IR
- map_set(&proc->module->members, key, value);
- }
+ map_set(&proc->module->members, key, value);
} else {
array_add(&proc->children, &value->Proc);
}
+
+ ir_module_add_value(proc->module, e, value);
+ ir_build_proc(value, proc);
}
}
}
@@ -8806,6 +9297,150 @@ void ir_build_stmt_internal(irProcedure *proc, Ast *node) {
ir_start_block(proc, done);
case_end;
+ case_ast_node(rs, InlineRangeStmt, node);
+ ir_emit_comment(proc, str_lit("InlineRangeStmt"));
+ ir_open_scope(proc); // 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) {
+ ir_add_local_for_identifier(proc, rs->val0, true);
+ }
+ if (val1_type != nullptr) {
+ ir_add_local_for_identifier(proc, rs->val1, true);
+ }
+
+ irValue *val = nullptr;
+ irValue *key = nullptr;
+ irBlock *loop = nullptr;
+ irBlock *done = nullptr;
+ Ast *expr = unparen_expr(rs->expr);
+
+ TypeAndValue tav = type_and_value_of_expr(expr);
+
+ if (is_ast_range(expr)) {
+
+ irAddr val0_addr = {};
+ irAddr val1_addr = {};
+ if (val0_type) val0_addr = ir_build_addr(proc, rs->val0);
+ if (val1_type) val1_addr = ir_build_addr(proc, 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) ir_addr_store(proc, val0_addr, ir_value_constant(val0_type, val));
+ if (val1_type) ir_addr_store(proc, val1_addr, ir_value_constant(val1_type, index));
+
+ ir_build_stmt(proc, 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) ir_addr_store(proc, val0_addr, ir_value_constant(val0_type, val));
+ if (val1_type) ir_addr_store(proc, val1_addr, ir_value_constant(val1_type, index));
+
+ ir_build_stmt(proc, 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);
+
+ irAddr val0_addr = {};
+ irAddr val1_addr = {};
+ if (val0_type) val0_addr = ir_build_addr(proc, rs->val0);
+ if (val1_type) val1_addr = ir_build_addr(proc, rs->val1);
+
+ for_array(i, bet->Enum.fields) {
+ Entity *field = bet->Enum.fields[i];
+ GB_ASSERT(field->kind == Entity_Constant);
+ if (val0_type) ir_addr_store(proc, val0_addr, ir_value_constant(val0_type, field->Constant.value));
+ if (val1_type) ir_addr_store(proc, val1_addr, ir_value_constant(val1_type, exact_value_i64(i)));
+
+ ir_build_stmt(proc, rs->body);
+ }
+ } else {
+ irAddr val0_addr = {};
+ irAddr val1_addr = {};
+ if (val0_type) val0_addr = ir_build_addr(proc, rs->val0);
+ if (val1_type) val1_addr = ir_build_addr(proc, 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) ir_addr_store(proc, val0_addr, ir_value_constant(val0_type, exact_value_i64(codepoint)));
+ if (val1_type) ir_addr_store(proc, val1_addr, ir_value_constant(val1_type, exact_value_i64(offset)));
+ ir_build_stmt(proc, rs->body);
+
+ offset += width;
+ } while (offset < str.len);
+ }
+ break;
+ case Type_Array:
+ if (t->Array.count > 0) {
+ irValue *val = ir_build_expr(proc, expr);
+ irValue *val_addr = ir_address_from_load_or_generate_local(proc, 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
+ irValue *elem = ir_emit_array_epi(proc, val_addr, cast(i32)i);
+ ir_addr_store(proc, val0_addr, ir_emit_load(proc, elem));
+ }
+ if (val1_type) ir_addr_store(proc, val1_addr, ir_value_constant(val1_type, exact_value_i64(i)));
+
+ ir_build_stmt(proc, rs->body);
+ }
+
+ }
+ break;
+ default:
+ GB_PANIC("Invalid inline for type");
+ break;
+ }
+ }
+
+
+ ir_close_scope(proc, irDeferExit_Default, nullptr);
+ case_end;
+
case_ast_node(ss, SwitchStmt, node);
ir_emit_comment(proc, str_lit("SwitchStmt"));
if (ss->init != nullptr) {
@@ -9084,6 +9719,7 @@ void ir_build_stmt_internal(irProcedure *proc, Ast *node) {
////////////////////////////////////////////////////////////////
void ir_number_proc_registers(irProcedure *proc) {
+ // i32 reg_index = proc->parameter_count;
i32 reg_index = 0;
for_array(i, proc->blocks) {
irBlock *b = proc->blocks[i];
@@ -9139,13 +9775,15 @@ void ir_begin_procedure_body(irProcedure *proc) {
proc->entry_block = ir_new_block(proc, proc->type_expr, "entry");
ir_start_block(proc, proc->entry_block);
+ i32 parameter_index = 0;
+
if (proc->type->Proc.return_by_pointer) {
// NOTE(bill): this must be the first parameter stored
Type *ptr_type = alloc_type_pointer(reduce_tuple_to_single_type(proc->type->Proc.results));
Entity *e = alloc_entity_param(nullptr, make_token_ident(str_lit("agg.result")), ptr_type, false, false);
e->flags |= EntityFlag_Sret | EntityFlag_NoAlias;
- irValue *param = ir_value_param(proc, e, ptr_type);
+ irValue *param = ir_value_param(proc, e, ptr_type, -1);
param->Param.kind = irParamPass_Pointer;
ir_module_add_value(proc->module, e, param);
@@ -9174,13 +9812,19 @@ void ir_begin_procedure_body(irProcedure *proc) {
Entity *e = params->variables[i];
if (e->kind != Entity_Variable) {
+ parameter_index += 1;
continue;
}
Type *abi_type = proc->type->Proc.abi_compat_params[i];
- if (e->token.string != "" && !is_blank_ident(e->token)) {
- irValue *param = ir_add_param(proc, e, name, abi_type, cast(i32)(i+1));
- array_add(&proc->params, param);
+ if (e->token.string != "") {
+ ir_add_param(proc, e, name, abi_type, parameter_index);
+ }
+
+ if (is_type_tuple(abi_type)) {
+ parameter_index += cast(i32)abi_type->Tuple.variables.count;
+ } else {
+ parameter_index += 1;
}
}
} else {
@@ -9189,15 +9833,20 @@ void ir_begin_procedure_body(irProcedure *proc) {
for_array(i, params->variables) {
Entity *e = params->variables[i];
if (e->kind != Entity_Variable) {
+ parameter_index += 1;
continue;
}
Type *abi_type = e->type;
if (abi_types.count > 0) {
abi_type = abi_types[i];
}
- if (e->token.string != "" && !is_blank_ident(e->token)) {
- irValue *param = ir_add_param(proc, e, nullptr, abi_type, cast(i32)(i+1));
- array_add(&proc->params, param);
+ if (e->token.string != "") {
+ ir_add_param(proc, e, nullptr, abi_type, parameter_index);
+ }
+ if (is_type_tuple(abi_type)) {
+ parameter_index += cast(i32)abi_type->Tuple.variables.count;
+ } else {
+ parameter_index += 1;
}
}
}
@@ -9239,11 +9888,13 @@ void ir_begin_procedure_body(irProcedure *proc) {
if (proc->type->Proc.calling_convention == ProcCC_Odin) {
Entity *e = alloc_entity_param(nullptr, make_token_ident(str_lit("__.context_ptr")), t_context_ptr, false, false);
e->flags |= EntityFlag_NoAlias;
- irValue *param = ir_value_param(proc, e, e->type);
+ irValue *param = ir_value_param(proc, e, e->type, -1);
ir_module_add_value(proc->module, e, param);
irContextData ctx = {param, proc->scope_index};
array_add(&proc->context_stack, ctx);
}
+
+ proc->parameter_count = parameter_index;
}
@@ -9370,6 +10021,8 @@ void ir_insert_code_before_proc(irProcedure* proc, irProcedure *parent) {
void ir_build_proc(irValue *value, irProcedure *parent) {
irProcedure *proc = &value->Proc;
+ set_procedure_abi_types(heap_allocator(), proc->type);
+
proc->parent = parent;
if (proc->body != nullptr) {
@@ -9561,13 +10214,27 @@ void ir_init_module(irModule *m, Checker *c) {
map_set(&m->members, hash_string(name), g);
ir_global_type_info_member_usings = g;
}
+
+ {
+ String name = str_lit(IR_TYPE_INFO_TAGS_NAME);
+ Entity *e = alloc_entity_variable(nullptr, make_token_ident(name),
+ alloc_type_array(t_string, count), false);
+ irValue *g = ir_value_global(e, nullptr);
+ ir_module_add_value(m, e, g);
+ map_set(&m->members, hash_string(name), g);
+ ir_global_type_info_member_tags = g;
+ }
}
}
}
{
irDebugInfo *di = ir_alloc_debug_info(irDebugInfo_CompileUnit);
- di->CompileUnit.file = m->info->files.entries[0].value; // Zeroth is the init file
+
+ GB_ASSERT(m->info->files.entries.count > 0);
+ AstFile *file = m->info->files.entries[0].value;
+
+ di->CompileUnit.file = file; // Zeroth is the init file
di->CompileUnit.producer = str_lit("odin");
map_set(&m->debug_info, hash_pointer(m), di);
@@ -9586,6 +10253,13 @@ void ir_init_module(irModule *m, Checker *c) {
array_init(&m->debug_location_stack, heap_allocator()); // TODO(lachsinc): ir_allocator() ??
}
+
+ {
+ for_array(i, m->info->files.entries) {
+ AstFile *file = m->info->files.entries[i].value;
+ ir_add_debug_info_file(m, file);
+ }
+ }
}
void ir_destroy_module(irModule *m) {
@@ -9694,6 +10368,11 @@ irValue *ir_type_info_member_usings_offset(irProcedure *proc, isize count) {
ir_global_type_info_member_usings_index += cast(i32)count;
return offset;
}
+irValue *ir_type_info_member_tags_offset(irProcedure *proc, isize count) {
+ irValue *offset = ir_emit_array_epi(proc, ir_global_type_info_member_tags, ir_global_type_info_member_tags_index);
+ ir_global_type_info_member_tags_index += cast(i32)count;
+ return offset;
+}
@@ -9832,6 +10511,11 @@ void ir_setup_type_info_data(irProcedure *proc) { // NOTE(bill): Setup type_info
tag = ir_emit_conv(proc, variant_ptr, t_type_info_complex_ptr);
break;
+ case Basic_quaternion128:
+ case Basic_quaternion256:
+ tag = ir_emit_conv(proc, variant_ptr, t_type_info_quaternion_ptr);
+ break;
+
case Basic_rawptr:
tag = ir_emit_conv(proc, variant_ptr, t_type_info_pointer_ptr);
break;
@@ -10039,9 +10723,9 @@ void ir_setup_type_info_data(irProcedure *proc) { // NOTE(bill): Setup type_info
irValue *is_packed = ir_const_bool(t->Struct.is_packed);
irValue *is_raw_union = ir_const_bool(t->Struct.is_raw_union);
irValue *is_custom_align = ir_const_bool(t->Struct.custom_align != 0);
- ir_emit_store(proc, ir_emit_struct_ep(proc, tag, 4), is_packed);
- ir_emit_store(proc, ir_emit_struct_ep(proc, tag, 5), is_raw_union);
- ir_emit_store(proc, ir_emit_struct_ep(proc, tag, 6), is_custom_align);
+ ir_emit_store(proc, ir_emit_struct_ep(proc, tag, 5), is_packed);
+ ir_emit_store(proc, ir_emit_struct_ep(proc, tag, 6), is_raw_union);
+ ir_emit_store(proc, ir_emit_struct_ep(proc, tag, 7), is_custom_align);
}
isize count = t->Struct.fields.count;
@@ -10050,6 +10734,7 @@ void ir_setup_type_info_data(irProcedure *proc) { // NOTE(bill): Setup type_info
irValue *memory_names = ir_type_info_member_names_offset (proc, count);
irValue *memory_offsets = ir_type_info_member_offsets_offset(proc, count);
irValue *memory_usings = ir_type_info_member_usings_offset (proc, count);
+ irValue *memory_tags = ir_type_info_member_tags_offset (proc, count);
type_set_offsets(t); // NOTE(bill): Just incase the offsets have not been set yet
for (isize source_index = 0; source_index < count; source_index++) {
@@ -10065,7 +10750,7 @@ void ir_setup_type_info_data(irProcedure *proc) { // NOTE(bill): Setup type_info
irValue *index = ir_const_int(source_index);
irValue *type_info = ir_emit_ptr_offset(proc, memory_types, index);
irValue *offset = ir_emit_ptr_offset(proc, memory_offsets, index);
- irValue *is_using = ir_emit_ptr_offset(proc, memory_usings, index);
+ irValue *is_using = ir_emit_ptr_offset(proc, memory_usings, index);
ir_emit_store(proc, type_info, ir_type_info(proc, f->type));
if (f->token.string.len > 0) {
@@ -10074,6 +10759,15 @@ void ir_setup_type_info_data(irProcedure *proc) { // NOTE(bill): Setup type_info
}
ir_emit_store(proc, offset, ir_const_uintptr(foffset));
ir_emit_store(proc, is_using, ir_const_bool((f->flags&EntityFlag_Using) != 0));
+
+ if (t->Struct.tags.count > 0) {
+ String tag_string = t->Struct.tags[source_index];
+ if (tag_string.len > 0) {
+ irValue *tag_ptr = ir_emit_ptr_offset(proc, memory_tags, index);
+ ir_emit_store(proc, tag_ptr, ir_const_string(tag_string));
+ }
+ }
+
}
irValue *cv = ir_const_int(count);
@@ -10081,6 +10775,7 @@ void ir_setup_type_info_data(irProcedure *proc) { // NOTE(bill): Setup type_info
ir_fill_slice(proc, ir_emit_struct_ep(proc, tag, 1), memory_names, cv);
ir_fill_slice(proc, ir_emit_struct_ep(proc, tag, 2), memory_offsets, cv);
ir_fill_slice(proc, ir_emit_struct_ep(proc, tag, 3), memory_usings, cv);
+ ir_fill_slice(proc, ir_emit_struct_ep(proc, tag, 4), memory_tags, cv);
}
break;
}
@@ -10482,12 +11177,14 @@ void ir_gen_tree(irGen *s) {
// main :: proc(argc: i32, argv: ^^u8) -> i32
String name = str_lit("main");
+#if 0
if (str_eq_ignore_case(cross_compile_target, str_lit("Essence"))) {
// This is a bit hacky,
// because this makes this function the first function run in the executable
// so it won't actually have the argc/argv arguments.
name = str_lit("ProgramEntry");
}
+#endif
Type *proc_params = alloc_type_tuple();
Type *proc_results = alloc_type_tuple();