gingerBill 5 years ago
parent
commit
c783840eab
2 changed files with 59 additions and 1 deletions
  1. 28 0
      src/ir.cpp
  2. 31 1
      src/llvm_backend.cpp

+ 28 - 0
src/ir.cpp

@@ -4227,6 +4227,28 @@ irValue *ir_addr_get_ptr(irProcedure *proc, irAddr const &addr, bool allow_refer
 		}
 		}
 	}
 	}
 
 
+	case irAddr_RelativePointer: {
+		Type *rel_ptr = base_type(ir_addr_type(addr));
+		GB_ASSERT(rel_ptr->kind == Type_RelativePointer);
+
+		irValue *ptr = ir_emit_conv(proc, addr.addr, t_uintptr);
+		irValue *offset = ir_emit_conv(proc, ptr, alloc_type_pointer(rel_ptr->RelativePointer.base_integer));
+		offset = ir_emit_load(proc, offset);
+
+		if (!is_type_unsigned(rel_ptr->RelativePointer.base_integer)) {
+			offset = ir_emit_conv(proc, offset, t_i64);
+		}
+		offset = ir_emit_conv(proc, offset, t_uintptr);
+		irValue *absolute_ptr = ir_emit_arith(proc, Token_Add, ptr, offset, t_uintptr);
+		absolute_ptr = ir_emit_conv(proc, absolute_ptr, rel_ptr->RelativePointer.pointer_type);
+
+		irValue *cond = ir_emit_comp(proc, Token_CmpEq, offset, ir_value_nil(rel_ptr->RelativePointer.base_integer));
+
+		// NOTE(bill): nil check
+		irValue *nil_ptr = ir_value_nil(rel_ptr->RelativePointer.pointer_type);
+		irValue *final_ptr = ir_emit_select(proc, cond, nil_ptr, absolute_ptr);
+		return final_ptr;
+	}
 
 
 	case irAddr_BitField: {
 	case irAddr_BitField: {
 		irValue *v = ir_addr_load(proc, addr);
 		irValue *v = ir_addr_load(proc, addr);
@@ -5101,6 +5123,10 @@ irValue *ir_emit_struct_ep(irProcedure *proc, irValue *s, i32 index) {
 		t = t->Opaque.elem;
 		t = t->Opaque.elem;
 	}
 	}
 
 
+	if (is_type_relative_pointer(t)) {
+		s = ir_addr_get_ptr(proc, ir_addr(s));
+	}
+
 	if (is_type_struct(t)) {
 	if (is_type_struct(t)) {
 		result_type = alloc_type_pointer(t->Struct.fields[index]->type);
 		result_type = alloc_type_pointer(t->Struct.fields[index]->type);
 	} else if (is_type_union(t)) {
 	} else if (is_type_union(t)) {
@@ -5337,6 +5363,8 @@ irValue *ir_emit_deep_field_gep(irProcedure *proc, irValue *e, Selection sel) {
 			e = ir_emit_array_epi(proc, e, index);
 			e = ir_emit_array_epi(proc, e, index);
 		} else if (type->kind == Type_Map) {
 		} else if (type->kind == Type_Map) {
 			e = ir_emit_struct_ep(proc, e, index);
 			e = ir_emit_struct_ep(proc, e, index);
+		} else if (type->kind == Type_RelativePointer) {
+			e = ir_emit_struct_ep(proc, e, index);
 		} else {
 		} else {
 			GB_PANIC("un-gep-able type %s", type_to_string(type));
 			GB_PANIC("un-gep-able type %s", type_to_string(type));
 		}
 		}

+ 31 - 1
src/llvm_backend.cpp

@@ -145,6 +145,30 @@ lbValue lb_addr_get_ptr(lbProcedure *p, lbAddr const &addr) {
 
 
 		return lb_emit_conv(p, ptr, alloc_type_pointer(map_type->Map.value));
 		return lb_emit_conv(p, ptr, alloc_type_pointer(map_type->Map.value));
 	}
 	}
+
+	case lbAddr_RelativePointer: {
+		Type *rel_ptr = base_type(lb_addr_type(addr));
+		GB_ASSERT(rel_ptr->kind == Type_RelativePointer);
+
+		lbValue ptr = lb_emit_conv(p, addr.addr, t_uintptr);
+		lbValue offset = lb_emit_conv(p, ptr, alloc_type_pointer(rel_ptr->RelativePointer.base_integer));
+		offset = lb_emit_load(p, offset);
+
+		if (!is_type_unsigned(rel_ptr->RelativePointer.base_integer)) {
+		offset = lb_emit_conv(p, offset, t_i64);
+		}
+		offset = lb_emit_conv(p, offset, t_uintptr);
+		lbValue absolute_ptr = lb_emit_arith(p, Token_Add, ptr, offset, t_uintptr);
+		absolute_ptr = lb_emit_conv(p, absolute_ptr, rel_ptr->RelativePointer.pointer_type);
+
+		lbValue cond = lb_emit_comp(p, Token_CmpEq, offset, lb_const_nil(p->module, rel_ptr->RelativePointer.base_integer));
+
+		// NOTE(bill): nil check
+		lbValue nil_ptr = lb_const_nil(p->module, rel_ptr->RelativePointer.pointer_type);
+		lbValue final_ptr = lb_emit_select(p, cond, nil_ptr, absolute_ptr);
+		return final_ptr;
+	}
+
 	case lbAddr_BitField: {
 	case lbAddr_BitField: {
 		lbValue v = lb_addr_load(p, addr);
 		lbValue v = lb_addr_load(p, addr);
 		return lb_address_from_load_or_generate_local(p, v);
 		return lb_address_from_load_or_generate_local(p, v);
@@ -6562,6 +6586,10 @@ lbValue lb_emit_struct_ep(lbProcedure *p, lbValue s, i32 index) {
 		t = t->Opaque.elem;
 		t = t->Opaque.elem;
 	}
 	}
 
 
+	if (is_type_relative_pointer(t)) {
+		s = lb_addr_get_ptr(p, lb_addr(s));
+	}
+
 	if (is_type_struct(t)) {
 	if (is_type_struct(t)) {
 		result_type = get_struct_field_type(t, index);
 		result_type = get_struct_field_type(t, index);
 	} else if (is_type_union(t)) {
 	} else if (is_type_union(t)) {
@@ -6809,7 +6837,7 @@ lbValue lb_emit_deep_field_gep(lbProcedure *p, lbValue e, Selection sel) {
 				break;
 				break;
 
 
 			default:
 			default:
-				GB_PANIC("un-gep-able type");
+				GB_PANIC("un-gep-able type %s", type_to_string(type));
 				break;
 				break;
 			}
 			}
 		} else if (type->kind == Type_Slice) {
 		} else if (type->kind == Type_Slice) {
@@ -6820,6 +6848,8 @@ lbValue lb_emit_deep_field_gep(lbProcedure *p, lbValue e, Selection sel) {
 			e = lb_emit_array_epi(p, e, index);
 			e = lb_emit_array_epi(p, e, index);
 		} else if (type->kind == Type_Map) {
 		} else if (type->kind == Type_Map) {
 			e = lb_emit_struct_ep(p, e, index);
 			e = lb_emit_struct_ep(p, e, index);
+		} else if (type->kind == Type_RelativePointer) {
+			e = lb_emit_struct_ep(p, e, index);
 		} else {
 		} else {
 			GB_PANIC("un-gep-able type %s", type_to_string(type));
 			GB_PANIC("un-gep-able type %s", type_to_string(type));
 		}
 		}