diff --git a/src/ir.cpp b/src/ir.cpp index b45f6bf85..2127de7b4 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -516,6 +516,9 @@ struct irAddr { irValue *index; Ast *index_expr; } soa; + struct { + bool deref; + } relative; }; }; @@ -3523,6 +3526,15 @@ irValue *ir_address_from_load_or_generate_local(irProcedure *proc, irValue *val) ir_emit_store(proc, local, val); return local; } +irValue *ir_address_from_load(irProcedure *proc, irValue *val) { + if (val->kind == irValue_Instr) { + if (val->Instr.kind == irInstr_Load) { + return val->Instr.Load.address; + } + } + GB_PANIC("ir_address_from_load"); + return nullptr; +} Type *ir_addr_type(irAddr const &addr) { @@ -3636,11 +3648,16 @@ irValue *ir_soa_struct_cap(irProcedure *proc, irValue *value) { } +irValue *ir_addr_load(irProcedure *proc, irAddr const &addr); -void ir_addr_store(irProcedure *proc, irAddr const &addr, irValue *value) { +void ir_addr_store(irProcedure *proc, irAddr addr, irValue *value) { if (addr.addr == nullptr) { return; } + if (addr.kind == irAddr_RelativePointer && addr.relative.deref) { + addr = ir_addr(ir_address_from_load(proc, ir_addr_load(proc, addr))); + } + if (addr.kind == irAddr_RelativePointer) { Type *rel_ptr = base_type(ir_addr_type(addr)); GB_ASSERT(rel_ptr->kind == Type_RelativePointer); @@ -3658,6 +3675,11 @@ void ir_addr_store(irProcedure *proc, irAddr const &addr, irValue *value) { offset = ir_emit_conv(proc, offset, rel_ptr->RelativePointer.base_integer); irValue *offset_ptr = ir_emit_conv(proc, addr.addr, alloc_type_pointer(rel_ptr->RelativePointer.base_integer)); + offset = ir_emit_select(proc, + ir_emit_comp(proc, Token_CmpEq, val_ptr, ir_value_nil(t_uintptr)), + ir_value_nil(rel_ptr->RelativePointer.base_integer), + offset + ); ir_emit_store(proc, offset_ptr, offset); return; @@ -3677,8 +3699,12 @@ void ir_addr_store(irProcedure *proc, irAddr const &addr, irValue *value) { } offset = ir_emit_conv(proc, offset, rel_ptr->RelativePointer.base_integer); - irValue *offset_ptr = ir_emit_conv(proc, addr.addr, alloc_type_pointer(rel_ptr->RelativePointer.base_integer)); + offset = ir_emit_select(proc, + ir_emit_comp(proc, Token_CmpEq, val_ptr, ir_value_nil(t_uintptr)), + ir_value_nil(rel_ptr->RelativePointer.base_integer), + offset + ); ir_emit_store(proc, offset_ptr, offset); irValue *len = ir_slice_len(proc, value); @@ -8603,7 +8629,9 @@ irAddr ir_build_addr(irProcedure *proc, Ast *expr) { case_ast_node(de, DerefExpr, expr); if (is_type_relative_pointer(type_of_expr(de->expr))) { - return ir_build_addr(proc, de->expr); + irAddr addr = ir_build_addr(proc, de->expr); + addr.relative.deref = true; + return addr; } // TODO(bill): Is a ptr copy needed? diff --git a/src/llvm_backend.cpp b/src/llvm_backend.cpp index 0b1431472..c0d23019e 100644 --- a/src/llvm_backend.cpp +++ b/src/llvm_backend.cpp @@ -208,7 +208,7 @@ void lb_emit_slice_bounds_check(lbProcedure *p, Token token, lbValue low, lbValu } } -void lb_addr_store(lbProcedure *p, lbAddr const &addr, lbValue value) { +void lb_addr_store(lbProcedure *p, lbAddr addr, lbValue value) { if (addr.addr.value == nullptr) { return; } @@ -223,6 +223,10 @@ void lb_addr_store(lbProcedure *p, lbAddr const &addr, lbValue value) { value.value = LLVMConstNull(lb_type(p->module, t)); } + if (addr.kind == lbAddr_RelativePointer && addr.relative.deref) { + addr = lb_addr(lb_address_from_load(p, lb_addr_load(p, addr))); + } + if (addr.kind == lbAddr_RelativePointer) { Type *rel_ptr = base_type(lb_addr_type(addr)); GB_ASSERT(rel_ptr->kind == Type_RelativePointer); @@ -242,6 +246,11 @@ void lb_addr_store(lbProcedure *p, lbAddr const &addr, lbValue value) { offset = lb_emit_conv(p, offset, rel_ptr->RelativePointer.base_integer); lbValue offset_ptr = lb_emit_conv(p, addr.addr, alloc_type_pointer(rel_ptr->RelativePointer.base_integer)); + offset = lb_emit_select(p, + lb_emit_comp(p, Token_CmpEq, val_ptr, lb_const_nil(p->module, t_uintptr)), + lb_const_nil(p->module, rel_ptr->RelativePointer.base_integer), + offset + ); LLVMBuildStore(p->builder, offset.value, offset_ptr.value); return; @@ -265,6 +274,11 @@ void lb_addr_store(lbProcedure *p, lbAddr const &addr, lbValue value) { lbValue offset_ptr = lb_emit_conv(p, addr.addr, alloc_type_pointer(rel_ptr->RelativePointer.base_integer)); + offset = lb_emit_select(p, + lb_emit_comp(p, Token_CmpEq, val_ptr, lb_const_nil(p->module, t_uintptr)), + lb_const_nil(p->module, rel_ptr->RelativePointer.base_integer), + offset + ); LLVMBuildStore(p->builder, offset.value, offset_ptr.value); lbValue len = lb_slice_len(p, value); @@ -6358,6 +6372,17 @@ lbValue lb_address_from_load_or_generate_local(lbProcedure *p, lbValue value) { lb_addr_store(p, res, value); return res.addr; } +lbValue lb_address_from_load(lbProcedure *p, lbValue value) { + if (LLVMIsALoadInst(value.value)) { + lbValue res = {}; + res.value = LLVMGetOperand(value.value, 0); + res.type = alloc_type_pointer(value.type); + return res; + } + + GB_PANIC("lb_address_from_load"); + return {}; +} lbValue lb_copy_value_to_ptr(lbProcedure *p, lbValue val, Type *new_type, i64 alignment) { i64 type_alignment = type_align_of(new_type); @@ -9976,6 +10001,7 @@ lbAddr lb_build_addr(lbProcedure *p, Ast *expr) { case_ast_node(de, DerefExpr, expr); if (is_type_relative_pointer(type_of_expr(de->expr))) { lbAddr addr = lb_build_addr(p, de->expr); + addr.relative.deref = true; return addr; } lbValue addr = lb_build_expr(p, de->expr); diff --git a/src/llvm_backend.hpp b/src/llvm_backend.hpp index 6be248123..d18ecc2c3 100644 --- a/src/llvm_backend.hpp +++ b/src/llvm_backend.hpp @@ -57,6 +57,9 @@ struct lbAddr { lbValue index; Ast *node; } index_set; + struct { + bool deref; + } relative; }; }; @@ -253,7 +256,7 @@ lbValue lb_const_int(lbModule *m, Type *type, u64 value); lbAddr lb_addr(lbValue addr); Type *lb_addr_type(lbAddr const &addr); LLVMTypeRef lb_addr_lb_type(lbAddr const &addr); -void lb_addr_store(lbProcedure *p, lbAddr const &addr, lbValue value); +void lb_addr_store(lbProcedure *p, lbAddr addr, lbValue value); lbValue lb_addr_load(lbProcedure *p, lbAddr const &addr); lbValue lb_emit_load(lbProcedure *p, lbValue v); void lb_emit_store(lbProcedure *p, lbValue ptr, lbValue value); @@ -301,6 +304,7 @@ void lb_add_foreign_library_path(lbModule *m, Entity *e); lbValue lb_typeid(lbModule *m, Type *type, Type *typeid_type=t_typeid); lbValue lb_address_from_load_or_generate_local(lbProcedure *p, lbValue value); +lbValue lb_address_from_load(lbProcedure *p, lbValue value); lbDefer lb_add_defer_node(lbProcedure *p, isize scope_index, Ast *stmt); lbAddr lb_add_local_generated(lbProcedure *p, Type *type, bool zero_init); @@ -324,6 +328,7 @@ 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_emit_select(lbProcedure *p, lbValue cond, lbValue x, lbValue y); void lb_fill_slice(lbProcedure *p, lbAddr const &slice, lbValue base_elem, lbValue len);