Browse Source

Relative pointer and relative slices

gingerBill 5 years ago
parent
commit
e1bdaa981a
6 changed files with 287 additions and 91 deletions
  1. 21 1
      examples/demo/demo.odin
  2. 26 0
      src/check_expr.cpp
  3. 116 46
      src/ir.cpp
  4. 118 43
      src/llvm_backend.cpp
  5. 2 1
      src/llvm_backend.hpp
  6. 4 0
      src/types.cpp

+ 21 - 1
examples/demo/demo.odin

@@ -1938,10 +1938,29 @@ dummy_procedure :: proc() {
 
 
 explicit_context_definition :: proc "c" () {
 explicit_context_definition :: proc "c" () {
 	// Try commenting the following statement out below
 	// Try commenting the following statement out below
-	context = runtime.default_context(); 
+	context = runtime.default_context();
+
+	fmt.println("\n#explicit context definition");
 	dummy_procedure();
 	dummy_procedure();
 }
 }
 
 
+relative_data_types :: proc() {
+	fmt.println("\n#relative data types");
+
+	x: int = 123;
+	ptr: #relative(i16) ^int;
+	ptr = &x;
+	fmt.println(ptr^);
+
+	arr := [3]int{1, 2, 3};
+	s := arr[:];
+	rel_slice: #relative(i16) []int;
+	rel_slice = s;
+	fmt.println(rel_slice);
+	fmt.println(rel_slice[:]);
+	fmt.println(rel_slice[1]);
+}
+
 main :: proc() {
 main :: proc() {
 	when true {
 	when true {
 		the_basics();
 		the_basics();
@@ -1973,5 +1992,6 @@ main :: proc() {
 		constant_literal_expressions();
 		constant_literal_expressions();
 		union_maybe();
 		union_maybe();
 		explicit_context_definition();
 		explicit_context_definition();
+		relative_data_types();
 	}
 	}
 }
 }

+ 26 - 0
src/check_expr.cpp

@@ -7563,6 +7563,17 @@ bool check_set_index_data(Operand *o, Type *t, bool indirection, i64 *max_count,
 		}
 		}
 		return true;
 		return true;
 
 
+	case Type_RelativeSlice:
+		{
+			Type *slice_type = base_type(t->RelativeSlice.slice_type);
+			GB_ASSERT(slice_type->kind == Type_Slice);
+			o->type = slice_type->Slice.elem;
+			if (o->mode != Addressing_Constant) {
+				o->mode = Addressing_Variable;
+			}
+		}
+		return true;
+
 	case Type_DynamicArray:
 	case Type_DynamicArray:
 		o->type = t->DynamicArray.elem;
 		o->type = t->DynamicArray.elem;
 		if (o->mode != Addressing_Constant) {
 		if (o->mode != Addressing_Constant) {
@@ -9250,6 +9261,8 @@ ExprKind check_expr_base_internal(CheckerContext *c, Operand *o, Ast *node, Type
 				// Okay
 				// Okay
 			} else if (is_type_string(t)) {
 			} else if (is_type_string(t)) {
 				// Okay
 				// Okay
+			} else if (is_type_relative_slice(t)) {
+				// Okay
 			} else {
 			} else {
 				valid = false;
 				valid = false;
 			}
 			}
@@ -9392,6 +9405,19 @@ ExprKind check_expr_base_internal(CheckerContext *c, Operand *o, Ast *node, Type
 				}
 				}
 			}
 			}
 			break;
 			break;
+
+		case Type_RelativeSlice:
+			valid = true;
+			o->type = t->RelativeSlice.slice_type;
+			if (o->mode != Addressing_Variable) {
+				gbString str = expr_to_string(node);
+				error(node, "Cannot relative slice '%s', value is not addressable", str);
+				gb_string_free(str);
+				o->mode = Addressing_Invalid;
+				o->expr = node;
+				return kind;
+			}
+			break;
 		}
 		}
 
 
 		if (!valid) {
 		if (!valid) {

+ 116 - 46
src/ir.cpp

@@ -494,6 +494,7 @@ enum irAddrKind {
 	irAddr_Context,
 	irAddr_Context,
 	irAddr_SoaVariable,
 	irAddr_SoaVariable,
 	irAddr_RelativePointer,
 	irAddr_RelativePointer,
+	irAddr_RelativeSlice,
 };
 };
 
 
 struct irAddr {
 struct irAddr {
@@ -525,6 +526,9 @@ irAddr ir_addr(irValue *addr) {
 	if (addr != nullptr && is_type_relative_pointer(type_deref(ir_type(addr)))) {
 	if (addr != nullptr && is_type_relative_pointer(type_deref(ir_type(addr)))) {
 		GB_ASSERT(is_type_pointer(ir_type(addr)));
 		GB_ASSERT(is_type_pointer(ir_type(addr)));
 		v.kind = irAddr_RelativePointer;
 		v.kind = irAddr_RelativePointer;
+	} else if (addr != nullptr && is_type_relative_slice(type_deref(ir_type(addr)))) {
+		GB_ASSERT(is_type_pointer(ir_type(addr)));
+		v.kind = irAddr_RelativeSlice;
 	}
 	}
 	return v;
 	return v;
 }
 }
@@ -912,7 +916,9 @@ irValue *ir_emit_bitcast(irProcedure *proc, irValue *data, Type *type);
 irValue *ir_emit_byte_swap(irProcedure *proc, irValue *value, Type *t);
 irValue *ir_emit_byte_swap(irProcedure *proc, irValue *value, Type *t);
 irValue *ir_find_or_add_entity_string(irModule *m, String str);
 irValue *ir_find_or_add_entity_string(irModule *m, String str);
 irValue *ir_find_or_add_entity_string_byte_slice(irModule *m, String str);
 irValue *ir_find_or_add_entity_string_byte_slice(irModule *m, String str);
-
+irValue *ir_slice_elem(irProcedure *proc, irValue *slice);
+irValue *ir_slice_len(irProcedure *proc, irValue *slice);
+void ir_fill_slice(irProcedure *proc, irValue *slice_ptr, irValue *data, irValue *len);
 
 
 
 
 irValue *ir_alloc_value(irValueKind kind) {
 irValue *ir_alloc_value(irValueKind kind) {
@@ -3655,6 +3661,34 @@ void ir_addr_store(irProcedure *proc, irAddr const &addr, irValue *value) {
 		ir_emit_store(proc, offset_ptr, offset);
 		ir_emit_store(proc, offset_ptr, offset);
 		return;
 		return;
 
 
+	} else if (addr.kind == irAddr_RelativeSlice) {
+		Type *rel_ptr = base_type(ir_addr_type(addr));
+		GB_ASSERT(rel_ptr->kind == Type_RelativeSlice);
+
+		value = ir_emit_conv(proc, value, rel_ptr->RelativeSlice.slice_type);
+
+		GB_ASSERT(is_type_pointer(ir_type(addr.addr)));
+		irValue *ptr = ir_emit_conv(proc, ir_emit_struct_ep(proc, addr.addr, 0), t_uintptr);
+		irValue *val_ptr = ir_emit_conv(proc, ir_slice_elem(proc, value), t_uintptr);
+		irValue *offset = ir_emit_arith(proc, Token_Sub, val_ptr, ptr, t_uintptr);
+
+		if (!is_type_unsigned(rel_ptr->RelativePointer.base_integer)) {
+			offset = ir_emit_conv(proc, offset, t_i64);
+		}
+		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));
+		ir_emit_store(proc, offset_ptr, offset);
+
+		irValue *len = ir_slice_len(proc, value);
+		len = ir_emit_conv(proc, len, rel_ptr->RelativePointer.base_integer);
+
+		irValue *len_ptr = ir_emit_struct_ep(proc, addr.addr, 1);
+		ir_emit_store(proc, len_ptr, len);
+
+		return;
+
 	} else if (addr.kind == irAddr_Map) {
 	} else if (addr.kind == irAddr_Map) {
 		ir_insert_dynamic_map_key_and_value(proc, addr.addr, addr.map_type, addr.map_key, value);
 		ir_insert_dynamic_map_key_and_value(proc, addr.addr, addr.map_type, addr.map_key, value);
 		return;
 		return;
@@ -3823,6 +3857,42 @@ irValue *ir_addr_load(irProcedure *proc, irAddr const &addr) {
 
 
 		return ir_emit_load(proc, final_ptr);
 		return ir_emit_load(proc, final_ptr);
 
 
+	} else if (addr.kind == irAddr_RelativeSlice) {
+		Type *rel_ptr = base_type(ir_addr_type(addr));
+		GB_ASSERT(rel_ptr->kind == Type_RelativeSlice);
+
+		irValue *offset_ptr = ir_emit_struct_ep(proc, addr.addr, 0);
+		irValue *ptr = ir_emit_conv(proc, offset_ptr, t_uintptr);
+		irValue *offset = ir_emit_load(proc, offset_ptr);
+
+
+		if (!is_type_unsigned(rel_ptr->RelativeSlice.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);
+
+		Type *slice_type = base_type(rel_ptr->RelativeSlice.slice_type);
+		GB_ASSERT(rel_ptr->RelativeSlice.slice_type->kind == Type_Slice);
+		Type *slice_elem = slice_type->Slice.elem;
+		Type *slice_elem_ptr = alloc_type_pointer(slice_elem);
+
+		absolute_ptr = ir_emit_conv(proc, absolute_ptr, slice_elem_ptr);
+
+		irValue *cond = ir_emit_comp(proc, Token_CmpEq, offset, ir_value_nil(rel_ptr->RelativeSlice.base_integer));
+
+		// NOTE(bill): nil check
+		irValue *nil_ptr = ir_value_nil(slice_elem_ptr);
+		irValue *data = ir_emit_select(proc, cond, nil_ptr, absolute_ptr);
+
+		irValue *len = ir_emit_load(proc, ir_emit_struct_ep(proc, addr.addr, 1));
+		len = ir_emit_conv(proc, len, t_int);
+
+		irValue *slice = ir_add_local_generated(proc, slice_type, false);
+		ir_fill_slice(proc, slice, data, len);
+		return ir_emit_load(proc, slice);
+
+
 	} else if (addr.kind == irAddr_Map) {
 	} else if (addr.kind == irAddr_Map) {
 		Type *map_type = base_type(addr.map_type);
 		Type *map_type = base_type(addr.map_type);
 		irValue *v = ir_add_local_generated(proc, map_type->Map.lookup_result_type, true);
 		irValue *v = ir_add_local_generated(proc, map_type->Map.lookup_result_type, true);
@@ -4872,6 +4942,11 @@ irValue *ir_emit_struct_ep(irProcedure *proc, irValue *s, i32 index) {
 		}
 		}
 	} else if (is_type_array(t)) {
 	} else if (is_type_array(t)) {
 		return ir_emit_array_epi(proc, s, index);
 		return ir_emit_array_epi(proc, s, index);
+	} else if (is_type_relative_slice(t)) {
+		switch (index) {
+		case 0: result_type = alloc_type_pointer(t->RelativeSlice.base_integer); break;
+		case 1: result_type = alloc_type_pointer(t->RelativeSlice.base_integer); break;
+		}
 	} else {
 	} else {
 		GB_PANIC("TODO(bill): struct_gep type: %s, %d", type_to_string(ir_type(s)), index);
 		GB_PANIC("TODO(bill): struct_gep type: %s, %d", type_to_string(ir_type(s)), index);
 	}
 	}
@@ -8245,18 +8320,12 @@ irAddr ir_build_addr(irProcedure *proc, Ast *expr) {
 			return ir_addr_map(map_val, key, t, result_type);
 			return ir_addr_map(map_val, key, t, result_type);
 		}
 		}
 
 
-		irValue *using_addr = nullptr;
-
 		switch (t->kind) {
 		switch (t->kind) {
 		case Type_Array: {
 		case Type_Array: {
 			irValue *array = nullptr;
 			irValue *array = nullptr;
-			if (using_addr != nullptr) {
-				array = using_addr;
-			} else {
-				array = ir_build_addr_ptr(proc, ie->expr);
-				if (deref) {
-					array = ir_emit_load(proc, array);
-				}
+			array = ir_build_addr_ptr(proc, ie->expr);
+			if (deref) {
+				array = ir_emit_load(proc, array);
 			}
 			}
 			irValue *index = ir_emit_conv(proc, ir_build_expr(proc, ie->index), t_int);
 			irValue *index = ir_emit_conv(proc, ir_build_expr(proc, ie->index), t_int);
 			irValue *elem = ir_emit_array_ep(proc, array, index);
 			irValue *elem = ir_emit_array_ep(proc, array, index);
@@ -8271,15 +8340,10 @@ irAddr ir_build_addr(irProcedure *proc, Ast *expr) {
 
 
 		case Type_EnumeratedArray: {
 		case Type_EnumeratedArray: {
 			irValue *array = nullptr;
 			irValue *array = nullptr;
-			if (using_addr != nullptr) {
-				array = using_addr;
-			} else {
-				array = ir_build_addr_ptr(proc, ie->expr);
-				if (deref) {
-					array = ir_emit_load(proc, array);
-				}
+			array = ir_build_addr_ptr(proc, ie->expr);
+			if (deref) {
+				array = ir_emit_load(proc, array);
 			}
 			}
-
 			Type *index_type = t->EnumeratedArray.index;
 			Type *index_type = t->EnumeratedArray.index;
 
 
 			auto index_tv = type_and_value_of_expr(ie->index);
 			auto index_tv = type_and_value_of_expr(ie->index);
@@ -8308,14 +8372,26 @@ irAddr ir_build_addr(irProcedure *proc, Ast *expr) {
 
 
 		case Type_Slice: {
 		case Type_Slice: {
 			irValue *slice = nullptr;
 			irValue *slice = nullptr;
-			if (using_addr != nullptr) {
-				slice = ir_emit_load(proc, using_addr);
-			} else {
-				slice = ir_build_expr(proc, ie->expr);
-				if (deref) {
-					slice = ir_emit_load(proc, slice);
-				}
+			slice = ir_build_expr(proc, ie->expr);
+			if (deref) {
+				slice = ir_emit_load(proc, slice);
 			}
 			}
+
+			irValue *elem = ir_slice_elem(proc, slice);
+			irValue *index = ir_emit_conv(proc, ir_build_expr(proc, ie->index), t_int);
+			irValue *len = ir_slice_len(proc, slice);
+			ir_emit_bounds_check(proc, ast_token(ie->index), index, len);
+			irValue *v = ir_emit_ptr_offset(proc, elem, index);
+			return ir_addr(v);
+		}
+
+		case Type_RelativeSlice: {
+			irAddr addr = ir_build_addr(proc, ie->expr);
+			if (deref) {
+				addr = ir_addr(ir_addr_load(proc, addr));
+			}
+			irValue *slice = ir_addr_load(proc, addr);
+
 			irValue *elem = ir_slice_elem(proc, slice);
 			irValue *elem = ir_slice_elem(proc, slice);
 			irValue *index = ir_emit_conv(proc, ir_build_expr(proc, ie->index), t_int);
 			irValue *index = ir_emit_conv(proc, ir_build_expr(proc, ie->index), t_int);
 			irValue *len = ir_slice_len(proc, slice);
 			irValue *len = ir_slice_len(proc, slice);
@@ -8326,14 +8402,11 @@ irAddr ir_build_addr(irProcedure *proc, Ast *expr) {
 
 
 		case Type_DynamicArray: {
 		case Type_DynamicArray: {
 			irValue *dynamic_array = nullptr;
 			irValue *dynamic_array = nullptr;
-			if (using_addr != nullptr) {
-				dynamic_array = ir_emit_load(proc, using_addr);
-			} else {
-				dynamic_array = ir_build_expr(proc, ie->expr);
-				if (deref) {
-					dynamic_array = ir_emit_load(proc, dynamic_array);
-				}
+			dynamic_array = ir_build_expr(proc, ie->expr);
+			if (deref) {
+				dynamic_array = ir_emit_load(proc, dynamic_array);
 			}
 			}
+
 			irValue *elem = ir_dynamic_array_elem(proc, dynamic_array);
 			irValue *elem = ir_dynamic_array_elem(proc, dynamic_array);
 			irValue *len = ir_dynamic_array_len(proc, dynamic_array);
 			irValue *len = ir_dynamic_array_len(proc, dynamic_array);
 			irValue *index = ir_emit_conv(proc, ir_build_expr(proc, ie->index), t_int);
 			irValue *index = ir_emit_conv(proc, ir_build_expr(proc, ie->index), t_int);
@@ -8349,14 +8422,11 @@ irAddr ir_build_addr(irProcedure *proc, Ast *expr) {
 			irValue *len;
 			irValue *len;
 			irValue *index;
 			irValue *index;
 
 
-			if (using_addr != nullptr) {
-				str = ir_emit_load(proc, using_addr);
-			} else {
-				str = ir_build_expr(proc, ie->expr);
-				if (deref) {
-					str = ir_emit_load(proc, str);
-				}
+			str = ir_build_expr(proc, ie->expr);
+			if (deref) {
+				str = ir_emit_load(proc, str);
 			}
 			}
+
 			elem = ir_string_elem(proc, str);
 			elem = ir_string_elem(proc, str);
 			len = ir_string_len(proc, str);
 			len = ir_string_len(proc, str);
 
 
@@ -8379,14 +8449,14 @@ irAddr ir_build_addr(irProcedure *proc, Ast *expr) {
 
 
 		bool no_indices = se->low == nullptr && se->high == nullptr;
 		bool no_indices = se->low == nullptr && se->high == nullptr;
 
 
-		irValue *addr = ir_build_addr_ptr(proc, se->expr);
-		irValue *base = ir_emit_load(proc, addr);
+		irAddr addr = ir_build_addr(proc, se->expr);
+		irValue *base = ir_addr_load(proc, addr);
 		Type *type = base_type(ir_type(base));
 		Type *type = base_type(ir_type(base));
 
 
 		if (is_type_pointer(type)) {
 		if (is_type_pointer(type)) {
 			type = base_type(type_deref(type));
 			type = base_type(type_deref(type));
-			addr = base;
-			base = ir_emit_load(proc, base);
+			addr = ir_addr(base);
+			base = ir_addr_load(proc, addr);
 		}
 		}
 		// TODO(bill): Cleanup like mad!
 		// TODO(bill): Cleanup like mad!
 
 
@@ -8442,7 +8512,7 @@ irAddr ir_build_addr(irProcedure *proc, Ast *expr) {
 					ir_emit_slice_bounds_check(proc, se->open, low, high, len, se->low != nullptr);
 					ir_emit_slice_bounds_check(proc, se->open, low, high, len, se->low != nullptr);
 				}
 				}
 			}
 			}
-			irValue *elem    = ir_emit_ptr_offset(proc, ir_array_elem(proc, addr), low);
+			irValue *elem    = ir_emit_ptr_offset(proc, ir_array_elem(proc, ir_addr_get_ptr(proc, addr)), low);
 			irValue *new_len = ir_emit_arith(proc, Token_Sub, high, low, t_int);
 			irValue *new_len = ir_emit_arith(proc, Token_Sub, high, low, t_int);
 
 
 			irValue *slice = ir_add_local_generated(proc, slice_type, false);
 			irValue *slice = ir_add_local_generated(proc, slice_type, false);
@@ -8470,7 +8540,7 @@ irAddr ir_build_addr(irProcedure *proc, Ast *expr) {
 
 
 		case Type_Struct:
 		case Type_Struct:
 			if (is_type_soa_struct(type)) {
 			if (is_type_soa_struct(type)) {
-				irValue *len = ir_soa_struct_len(proc, addr);
+				irValue *len = ir_soa_struct_len(proc, ir_addr_get_ptr(proc, addr));
 				if (high == nullptr) high = len;
 				if (high == nullptr) high = len;
 
 
 				if (!no_indices) {
 				if (!no_indices) {
@@ -8482,7 +8552,7 @@ irAddr ir_build_addr(irProcedure *proc, Ast *expr) {
 					i32 field_count = cast(i32)type->Struct.fields.count;
 					i32 field_count = cast(i32)type->Struct.fields.count;
 					for (i32 i = 0; i < field_count; i++) {
 					for (i32 i = 0; i < field_count; i++) {
 						irValue *field_dst = ir_emit_struct_ep(proc, dst, i);
 						irValue *field_dst = ir_emit_struct_ep(proc, dst, i);
-						irValue *field_src = ir_emit_struct_ep(proc, addr, i);
+						irValue *field_src = ir_emit_struct_ep(proc, ir_addr_get_ptr(proc, addr), i);
 						field_src = ir_emit_array_ep(proc, field_src, low);
 						field_src = ir_emit_array_ep(proc, field_src, low);
 						ir_emit_store(proc, field_dst, field_src);
 						ir_emit_store(proc, field_dst, field_src);
 					}
 					}

+ 118 - 43
src/llvm_backend.cpp

@@ -59,6 +59,9 @@ lbAddr lb_addr(lbValue addr) {
 	if (addr.type != nullptr && is_type_relative_pointer(type_deref(addr.type))) {
 	if (addr.type != nullptr && is_type_relative_pointer(type_deref(addr.type))) {
 		GB_ASSERT(is_type_pointer(addr.type));
 		GB_ASSERT(is_type_pointer(addr.type));
 		v.kind = lbAddr_RelativePointer;
 		v.kind = lbAddr_RelativePointer;
+	} else if (addr.type != nullptr && is_type_relative_slice(type_deref(addr.type))) {
+		GB_ASSERT(is_type_pointer(addr.type));
+		v.kind = lbAddr_RelativeSlice;
 	}
 	}
 	return v;
 	return v;
 }
 }
@@ -186,6 +189,36 @@ void lb_addr_store(lbProcedure *p, lbAddr const &addr, lbValue value) {
 		LLVMBuildStore(p->builder, offset.value, offset_ptr.value);
 		LLVMBuildStore(p->builder, offset.value, offset_ptr.value);
 		return;
 		return;
 
 
+	} else if (addr.kind == lbAddr_RelativeSlice) {
+		Type *rel_ptr = base_type(lb_addr_type(addr));
+		GB_ASSERT(rel_ptr->kind == Type_RelativeSlice);
+
+		value = lb_emit_conv(p, value, rel_ptr->RelativeSlice.slice_type);
+
+		GB_ASSERT(is_type_pointer(addr.addr.type));
+		lbValue ptr = lb_emit_conv(p, lb_emit_struct_ep(p, addr.addr, 0), t_uintptr);
+		lbValue val_ptr = lb_emit_conv(p, lb_slice_elem(p, value), t_uintptr);
+		lbValue offset = {};
+		offset.value = LLVMBuildSub(p->builder, val_ptr.value, ptr.value, "");
+		offset.type = t_uintptr;
+
+		if (!is_type_unsigned(rel_ptr->RelativePointer.base_integer)) {
+			offset = lb_emit_conv(p, offset, t_i64);
+		}
+		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));
+		LLVMBuildStore(p->builder, offset.value, offset_ptr.value);
+
+		lbValue len = lb_slice_len(p, value);
+		len = lb_emit_conv(p, len, rel_ptr->RelativePointer.base_integer);
+
+		lbValue len_ptr = lb_emit_struct_ep(p, addr.addr, 1);
+		LLVMBuildStore(p->builder, len.value, len_ptr.value);
+
+		return;
+
 	} else if (addr.kind == lbAddr_AtomOp_index_set) {
 	} else if (addr.kind == lbAddr_AtomOp_index_set) {
 		lbValue ptr = addr.addr;
 		lbValue ptr = addr.addr;
 		lbValue index = addr.index_set.index;
 		lbValue index = addr.index_set.index;
@@ -394,6 +427,44 @@ lbValue lb_addr_load(lbProcedure *p, lbAddr const &addr) {
 
 
 		return lb_emit_load(p, final_ptr);
 		return lb_emit_load(p, final_ptr);
 
 
+	} else if (addr.kind == lbAddr_RelativeSlice) {
+		Type *rel_ptr = base_type(lb_addr_type(addr));
+		GB_ASSERT(rel_ptr->kind == Type_RelativeSlice);
+
+		lbValue offset_ptr = lb_emit_struct_ep(p, addr.addr, 0);
+		lbValue ptr = lb_emit_conv(p, offset_ptr, t_uintptr);
+		lbValue offset = lb_emit_load(p, offset_ptr);
+
+
+		if (!is_type_unsigned(rel_ptr->RelativeSlice.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);
+
+		Type *slice_type = base_type(rel_ptr->RelativeSlice.slice_type);
+		GB_ASSERT(rel_ptr->RelativeSlice.slice_type->kind == Type_Slice);
+		Type *slice_elem = slice_type->Slice.elem;
+		Type *slice_elem_ptr = alloc_type_pointer(slice_elem);
+
+		absolute_ptr = lb_emit_conv(p, absolute_ptr, slice_elem_ptr);
+
+		lbValue cond = lb_emit_comp(p, Token_CmpEq, offset, lb_const_nil(p->module, rel_ptr->RelativeSlice.base_integer));
+
+		// NOTE(bill): nil check
+		lbValue nil_ptr = lb_const_nil(p->module, slice_elem_ptr);
+		lbValue data = {};
+		data.type = absolute_ptr.type;
+		data.value = LLVMBuildSelect(p->builder, cond.value, nil_ptr.value, absolute_ptr.value, "");
+
+		lbValue len = lb_emit_load(p, lb_emit_struct_ep(p, addr.addr, 1));
+		len = lb_emit_conv(p, len, t_int);
+
+		lbAddr slice = lb_add_local_generated(p, slice_type, false);
+		lb_fill_slice(p, slice, data, len);
+		return lb_addr_load(p, slice);
+
+
 	} else if (addr.kind == lbAddr_Map) {
 	} else if (addr.kind == lbAddr_Map) {
 		Type *map_type = base_type(addr.map.type);
 		Type *map_type = base_type(addr.map.type);
 		lbAddr v = lb_add_local_generated(p, map_type->Map.lookup_result_type, true);
 		lbAddr v = lb_add_local_generated(p, map_type->Map.lookup_result_type, true);
@@ -6282,6 +6353,11 @@ lbValue lb_emit_struct_ep(lbProcedure *p, lbValue s, i32 index) {
 		}
 		}
 	} else if (is_type_array(t)) {
 	} else if (is_type_array(t)) {
 		return lb_emit_array_epi(p, s, index);
 		return lb_emit_array_epi(p, s, index);
+	} else if (is_type_relative_slice(t)) {
+		switch (index) {
+		case 0: result_type = t->RelativeSlice.base_integer; break;
+		case 1: result_type = t->RelativeSlice.base_integer; break;
+		}
 	} else {
 	} else {
 		GB_PANIC("TODO(bill): struct_gep type: %s, %d", type_to_string(s.type), index);
 		GB_PANIC("TODO(bill): struct_gep type: %s, %d", type_to_string(s.type), index);
 	}
 	}
@@ -9476,18 +9552,12 @@ lbAddr lb_build_addr(lbProcedure *p, Ast *expr) {
 			return lb_addr_map(map_val, key, t, result_type);
 			return lb_addr_map(map_val, key, t, result_type);
 		}
 		}
 
 
-		lbValue using_addr = {};
-
 		switch (t->kind) {
 		switch (t->kind) {
 		case Type_Array: {
 		case Type_Array: {
 			lbValue array = {};
 			lbValue array = {};
-			if (using_addr.value != nullptr) {
-				array = using_addr;
-			} else {
-				array = lb_build_addr_ptr(p, ie->expr);
-				if (deref) {
-					array = lb_emit_load(p, array);
-				}
+			array = lb_build_addr_ptr(p, ie->expr);
+			if (deref) {
+				array = lb_emit_load(p, array);
 			}
 			}
 			lbValue index = lb_build_expr(p, ie->index);
 			lbValue index = lb_build_expr(p, ie->index);
 			index = lb_emit_conv(p, index, t_int);
 			index = lb_emit_conv(p, index, t_int);
@@ -9503,13 +9573,9 @@ lbAddr lb_build_addr(lbProcedure *p, Ast *expr) {
 
 
 		case Type_EnumeratedArray: {
 		case Type_EnumeratedArray: {
 			lbValue array = {};
 			lbValue array = {};
-			if (using_addr.value != nullptr) {
-				array = using_addr;
-			} else {
-				array = lb_build_addr_ptr(p, ie->expr);
-				if (deref) {
-					array = lb_emit_load(p, array);
-				}
+			array = lb_build_addr_ptr(p, ie->expr);
+			if (deref) {
+				array = lb_emit_load(p, array);
 			}
 			}
 
 
 			Type *index_type = t->EnumeratedArray.index;
 			Type *index_type = t->EnumeratedArray.index;
@@ -9540,14 +9606,27 @@ lbAddr lb_build_addr(lbProcedure *p, Ast *expr) {
 
 
 		case Type_Slice: {
 		case Type_Slice: {
 			lbValue slice = {};
 			lbValue slice = {};
-			if (using_addr.value != nullptr) {
-				slice = lb_emit_load(p, using_addr);
+			slice = lb_build_expr(p, ie->expr);
+			if (deref) {
+				slice = lb_emit_load(p, slice);
+			}
+			lbValue elem = lb_slice_elem(p, slice);
+			lbValue index = lb_emit_conv(p, lb_build_expr(p, ie->index), t_int);
+			lbValue len = lb_slice_len(p, slice);
+			// ir_emit_bounds_check(p, ast_token(ie->index), index, len);
+			lbValue v = lb_emit_ptr_offset(p, elem, index);
+			return lb_addr(v);
+		}
+
+		case Type_RelativeSlice: {
+			lbAddr slice_addr = {};
+			if (deref) {
+				slice_addr = lb_addr(lb_build_expr(p, ie->expr));
 			} else {
 			} else {
-				slice = lb_build_expr(p, ie->expr);
-				if (deref) {
-					slice = lb_emit_load(p, slice);
-				}
+				slice_addr = lb_build_addr(p, ie->expr);
 			}
 			}
+			lbValue slice = lb_addr_load(p, slice_addr);
+
 			lbValue elem = lb_slice_elem(p, slice);
 			lbValue elem = lb_slice_elem(p, slice);
 			lbValue index = lb_emit_conv(p, lb_build_expr(p, ie->index), t_int);
 			lbValue index = lb_emit_conv(p, lb_build_expr(p, ie->index), t_int);
 			lbValue len = lb_slice_len(p, slice);
 			lbValue len = lb_slice_len(p, slice);
@@ -9558,13 +9637,9 @@ lbAddr lb_build_addr(lbProcedure *p, Ast *expr) {
 
 
 		case Type_DynamicArray: {
 		case Type_DynamicArray: {
 			lbValue dynamic_array = {};
 			lbValue dynamic_array = {};
-			if (using_addr.value != nullptr) {
-				dynamic_array = lb_emit_load(p, using_addr);
-			} else {
-				dynamic_array = lb_build_expr(p, ie->expr);
-				if (deref) {
-					dynamic_array = lb_emit_load(p, dynamic_array);
-				}
+			dynamic_array = lb_build_expr(p, ie->expr);
+			if (deref) {
+				dynamic_array = lb_emit_load(p, dynamic_array);
 			}
 			}
 			lbValue elem = lb_dynamic_array_elem(p, dynamic_array);
 			lbValue elem = lb_dynamic_array_elem(p, dynamic_array);
 			lbValue len = lb_dynamic_array_len(p, dynamic_array);
 			lbValue len = lb_dynamic_array_len(p, dynamic_array);
@@ -9581,13 +9656,9 @@ lbAddr lb_build_addr(lbProcedure *p, Ast *expr) {
 			lbValue len;
 			lbValue len;
 			lbValue index;
 			lbValue index;
 
 
-			if (using_addr.value != nullptr) {
-				str = lb_emit_load(p, using_addr);
-			} else {
-				str = lb_build_expr(p, ie->expr);
-				if (deref) {
-					str = lb_emit_load(p, str);
-				}
+			str = lb_build_expr(p, ie->expr);
+			if (deref) {
+				str = lb_emit_load(p, str);
 			}
 			}
 			elem = lb_string_elem(p, str);
 			elem = lb_string_elem(p, str);
 			len = lb_string_len(p, str);
 			len = lb_string_len(p, str);
@@ -9640,14 +9711,14 @@ lbAddr lb_build_addr(lbProcedure *p, Ast *expr) {
 		}
 		}
 
 
 
 
-		lbValue addr = lb_build_addr_ptr(p, se->expr);
-		lbValue base = lb_emit_load(p, addr);
+		lbAddr addr = lb_build_addr(p, se->expr);
+		lbValue base = lb_addr_load(p, addr);
 		Type *type = base_type(base.type);
 		Type *type = base_type(base.type);
 
 
 		if (is_type_pointer(type)) {
 		if (is_type_pointer(type)) {
 			type = base_type(type_deref(type));
 			type = base_type(type_deref(type));
-			addr = base;
-			base = lb_emit_load(p, base);
+			addr = lb_addr(base);
+			base = lb_addr_load(p, addr);
 		}
 		}
 
 
 		switch (type->kind) {
 		switch (type->kind) {
@@ -9668,6 +9739,10 @@ lbAddr lb_build_addr(lbProcedure *p, Ast *expr) {
 			return slice;
 			return slice;
 		}
 		}
 
 
+		case Type_RelativeSlice:
+			GB_PANIC("TODO(bill): Type_RelativeSlice should be handled above already on the lb_addr_load");
+			break;
+
 		case Type_DynamicArray: {
 		case Type_DynamicArray: {
 			Type *elem_type = type->DynamicArray.elem;
 			Type *elem_type = type->DynamicArray.elem;
 			Type *slice_type = alloc_type_slice(elem_type);
 			Type *slice_type = alloc_type_slice(elem_type);
@@ -9702,7 +9777,7 @@ lbAddr lb_build_addr(lbProcedure *p, Ast *expr) {
 					lb_emit_slice_bounds_check(p, se->open, low, high, len, se->low != nullptr);
 					lb_emit_slice_bounds_check(p, se->open, low, high, len, se->low != nullptr);
 				}
 				}
 			}
 			}
-			lbValue elem    = lb_emit_ptr_offset(p, lb_array_elem(p, addr), low);
+			lbValue elem    = lb_emit_ptr_offset(p, lb_array_elem(p, lb_addr_get_ptr(p, addr)), low);
 			lbValue new_len = lb_emit_arith(p, Token_Sub, high, low, t_int);
 			lbValue new_len = lb_emit_arith(p, Token_Sub, high, low, t_int);
 
 
 			lbAddr slice = lb_add_local_generated(p, slice_type, false);
 			lbAddr slice = lb_add_local_generated(p, slice_type, false);
@@ -9730,7 +9805,7 @@ lbAddr lb_build_addr(lbProcedure *p, Ast *expr) {
 
 
 		case Type_Struct:
 		case Type_Struct:
 			if (is_type_soa_struct(type)) {
 			if (is_type_soa_struct(type)) {
-				lbValue len = lb_soa_struct_len(p, addr);
+				lbValue len = lb_soa_struct_len(p, lb_addr_get_ptr(p, addr));
 				if (high.value == nullptr) high = len;
 				if (high.value == nullptr) high = len;
 
 
 				if (!no_indices) {
 				if (!no_indices) {
@@ -9743,7 +9818,7 @@ lbAddr lb_build_addr(lbProcedure *p, Ast *expr) {
 					i32 field_count = cast(i32)type->Struct.fields.count;
 					i32 field_count = cast(i32)type->Struct.fields.count;
 					for (i32 i = 0; i < field_count; i++) {
 					for (i32 i = 0; i < field_count; i++) {
 						lbValue field_dst = lb_emit_struct_ep(p, dst.addr, i);
 						lbValue field_dst = lb_emit_struct_ep(p, dst.addr, i);
-						lbValue field_src = lb_emit_struct_ep(p, addr, i);
+						lbValue field_src = lb_emit_struct_ep(p, lb_addr_get_ptr(p, addr), i);
 						field_src = lb_emit_array_ep(p, field_src, low);
 						field_src = lb_emit_array_ep(p, field_src, low);
 						lb_emit_store(p, field_dst, field_src);
 						lb_emit_store(p, field_dst, field_src);
 					}
 					}

+ 2 - 1
src/llvm_backend.hpp

@@ -29,6 +29,7 @@ enum lbAddrKind {
 	lbAddr_SoaVariable,
 	lbAddr_SoaVariable,
 
 
 	lbAddr_RelativePointer,
 	lbAddr_RelativePointer,
+	lbAddr_RelativeSlice,
 
 
 	lbAddr_AtomOp_index_set,
 	lbAddr_AtomOp_index_set,
 };
 };
@@ -320,9 +321,9 @@ lbValue lb_map_entries_ptr(lbProcedure *p, lbValue value);
 lbValue lb_map_len(lbProcedure *p, lbValue value);
 lbValue lb_map_len(lbProcedure *p, lbValue value);
 lbValue lb_map_cap(lbProcedure *p, lbValue value);
 lbValue lb_map_cap(lbProcedure *p, lbValue value);
 lbValue lb_soa_struct_len(lbProcedure *p, lbValue value);
 lbValue lb_soa_struct_len(lbProcedure *p, lbValue value);
-
 void lb_emit_increment(lbProcedure *p, lbValue addr);
 void lb_emit_increment(lbProcedure *p, lbValue addr);
 
 
+void lb_fill_slice(lbProcedure *p, lbAddr const &slice, lbValue base_elem, lbValue len);
 
 
 lbValue lb_type_info(lbModule *m, Type *type);
 lbValue lb_type_info(lbModule *m, Type *type);
 
 

+ 4 - 0
src/types.cpp

@@ -1572,6 +1572,8 @@ bool is_type_indexable(Type *t) {
 		return true;
 		return true;
 	case Type_EnumeratedArray:
 	case Type_EnumeratedArray:
 		return true;
 		return true;
+	case Type_RelativeSlice:
+		return true;
 	}
 	}
 	return false;
 	return false;
 }
 }
@@ -1587,6 +1589,8 @@ bool is_type_sliceable(Type *t) {
 		return true;
 		return true;
 	case Type_EnumeratedArray:
 	case Type_EnumeratedArray:
 		return false;
 		return false;
+	case Type_RelativeSlice:
+		return true;
 	}
 	}
 	return false;
 	return false;
 }
 }