Browse Source

Fix edge cases of relative pointers

gingerBill 5 years ago
parent
commit
3f23a0b3b0
3 changed files with 64 additions and 5 deletions
  1. 31 3
      src/ir.cpp
  2. 27 1
      src/llvm_backend.cpp
  3. 6 1
      src/llvm_backend.hpp

+ 31 - 3
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?

+ 27 - 1
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);

+ 6 - 1
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);