diff --git a/core/fmt/fmt.odin b/core/fmt/fmt.odin index b137e0eb8..89ac18068 100644 --- a/core/fmt/fmt.odin +++ b/core/fmt/fmt.odin @@ -8,6 +8,7 @@ import "core:unicode/utf8" import "core:strconv" import "core:strings" import "core:reflect" +import "intrinsics" @private @@ -1712,6 +1713,117 @@ fmt_value :: proc(fi: ^Info, v: any, verb: rune) { case runtime.Type_Info_Opaque: fmt_opaque(fi, v); + + case runtime.Type_Info_Relative_Pointer: + ptr_any := any{v.data, info.base_integer.id}; + ptr: rawptr; + switch i in &ptr_any { + case u8: ptr = handle_relative_pointer(&i); + case u16: ptr = handle_relative_pointer(&i); + case u32: ptr = handle_relative_pointer(&i); + case u64: ptr = handle_relative_pointer(&i); + case i8: ptr = handle_relative_pointer(&i); + case i16: ptr = handle_relative_pointer(&i); + case i32: ptr = handle_relative_pointer(&i); + case i64: ptr = handle_relative_pointer(&i); + case u16le: ptr = handle_relative_pointer(&i); + case u32le: ptr = handle_relative_pointer(&i); + case u64le: ptr = handle_relative_pointer(&i); + case i16le: ptr = handle_relative_pointer(&i); + case i32le: ptr = handle_relative_pointer(&i); + case i64le: ptr = handle_relative_pointer(&i); + case u16be: ptr = handle_relative_pointer(&i); + case u32be: ptr = handle_relative_pointer(&i); + case u64be: ptr = handle_relative_pointer(&i); + case i16be: ptr = handle_relative_pointer(&i); + case i32be: ptr = handle_relative_pointer(&i); + case i64be: ptr = handle_relative_pointer(&i); + } + absolute_ptr := any{ptr, info.pointer.id}; + + fmt_value(fi, absolute_ptr, verb); + + case runtime.Type_Info_Relative_Slice: + ptr_any := any{v.data, info.base_integer.id}; + ptr: rawptr; + switch i in &ptr_any { + case u8: ptr = handle_relative_pointer(&i); + case u16: ptr = handle_relative_pointer(&i); + case u32: ptr = handle_relative_pointer(&i); + case u64: ptr = handle_relative_pointer(&i); + case i8: ptr = handle_relative_pointer(&i); + case i16: ptr = handle_relative_pointer(&i); + case i32: ptr = handle_relative_pointer(&i); + case i64: ptr = handle_relative_pointer(&i); + case u16le: ptr = handle_relative_pointer(&i); + case u32le: ptr = handle_relative_pointer(&i); + case u64le: ptr = handle_relative_pointer(&i); + case i16le: ptr = handle_relative_pointer(&i); + case i32le: ptr = handle_relative_pointer(&i); + case i64le: ptr = handle_relative_pointer(&i); + case u16be: ptr = handle_relative_pointer(&i); + case u32be: ptr = handle_relative_pointer(&i); + case u64be: ptr = handle_relative_pointer(&i); + case i16be: ptr = handle_relative_pointer(&i); + case i32be: ptr = handle_relative_pointer(&i); + case i64be: ptr = handle_relative_pointer(&i); + } + + if verb == 'p' { + fmt_pointer(fi, ptr, 'p'); + } else if ptr == nil { + strings.write_string(fi.buf, "[]"); + } else { + len_ptr := uintptr(v.data) + uintptr(info.base_integer.size); + len_any := any{rawptr(len_ptr), info.base_integer.id}; + len: int = 0; + switch i in len_any { + case u8: len = int(i); + case u16: len = int(i); + case u32: len = int(i); + case u64: len = int(i); + case i8: len = int(i); + case i16: len = int(i); + case i32: len = int(i); + case i64: len = int(i); + case u16le: len = int(i); + case u32le: len = int(i); + case u64le: len = int(i); + case i16le: len = int(i); + case i32le: len = int(i); + case i64le: len = int(i); + case u16be: len = int(i); + case u32be: len = int(i); + case u64be: len = int(i); + case i16be: len = int(i); + case i32be: len = int(i); + case i64be: len = int(i); + } + + slice_type := reflect.type_info_base(info.slice).variant.(runtime.Type_Info_Slice); + + strings.write_byte(fi.buf, '['); + defer strings.write_byte(fi.buf, ']'); + + for i in 0.. 0 do strings.write_string(fi.buf, ", "); + + data := uintptr(ptr) + uintptr(i*slice_type.elem_size); + fmt_arg(fi, any{rawptr(data), slice_type.elem.id}, verb); + } + } + + } + + handle_relative_pointer :: proc(ptr: ^$T) -> rawptr where intrinsics.type_is_integer(T) { + if ptr^ == 0 { + return nil; + } + when intrinsics.type_is_unsigned(T) { + return rawptr(uintptr(ptr) + uintptr(ptr^)); + } else { + return rawptr(uintptr(ptr) + uintptr(i64(ptr^))); + } } } diff --git a/core/reflect/reflect.odin b/core/reflect/reflect.odin index f92dc1f39..c971a1011 100644 --- a/core/reflect/reflect.odin +++ b/core/reflect/reflect.odin @@ -30,6 +30,8 @@ Type_Info_Bit_Field :: runtime.Type_Info_Bit_Field; Type_Info_Bit_Set :: runtime.Type_Info_Bit_Set; Type_Info_Opaque :: runtime.Type_Info_Opaque; Type_Info_Simd_Vector :: runtime.Type_Info_Simd_Vector; +Type_Info_Relative_Pointer :: runtime.Type_Info_Relative_Pointer; +Type_Info_Relative_Slice :: runtime.Type_Info_Relative_Slice; Type_Kind :: enum { @@ -60,6 +62,8 @@ Type_Kind :: enum { Bit_Set, Opaque, Simd_Vector, + Relative_Pointer, + Relative_Slice, } @@ -92,6 +96,8 @@ type_kind :: proc(T: typeid) -> Type_Kind { case Type_Info_Bit_Set: return .Bit_Set; case Type_Info_Opaque: return .Opaque; case Type_Info_Simd_Vector: return .Simd_Vector; + case Type_Info_Relative_Pointer: return .Relative_Pointer; + case Type_Info_Relative_Slice: return .Relative_Slice; } } diff --git a/core/reflect/types.odin b/core/reflect/types.odin index cec2529ac..729a342d8 100644 --- a/core/reflect/types.odin +++ b/core/reflect/types.odin @@ -184,6 +184,16 @@ are_types_identical :: proc(a, b: ^Type_Info) -> bool { y, ok := b.variant.(Type_Info_Simd_Vector); if !ok do return false; return x.count == y.count && x.elem == y.elem; + + case Type_Info_Relative_Pointer: + y, ok := b.variant.(Type_Info_Relative_Pointer); + if !ok do return false; + return x.base_integer == y.base_integer && x.pointer == y.pointer; + + case Type_Info_Relative_Slice: + y, ok := b.variant.(Type_Info_Relative_Slice); + if !ok do return false; + return x.base_integer == y.base_integer && x.slice == y.slice; } return false; @@ -322,6 +332,16 @@ is_simd_vector :: proc(info: ^Type_Info) -> bool { _, ok := type_info_base(info).variant.(Type_Info_Simd_Vector); return ok; } +is_relative_pointer :: proc(info: ^Type_Info) -> bool { + if info == nil do return false; + _, ok := type_info_base(info).variant.(Type_Info_Relative_Pointer); + return ok; +} +is_relative_slice :: proc(info: ^Type_Info) -> bool { + if info == nil do return false; + _, ok := type_info_base(info).variant.(Type_Info_Relative_Slice); + return ok; +} @@ -567,6 +587,19 @@ write_type :: proc(buf: ^strings.Builder, ti: ^Type_Info) { write_byte(buf, ']'); write_type(buf, info.elem); } + + case Type_Info_Relative_Pointer: + write_string(buf, "#relative("); + write_type(buf, info.base_integer); + write_string(buf, ") "); + write_type(buf, info.pointer); + + case Type_Info_Relative_Slice: + write_string(buf, "#relative("); + write_type(buf, info.base_integer); + write_string(buf, ") "); + write_type(buf, info.slice); + } } diff --git a/core/runtime/core.odin b/core/runtime/core.odin index a40e6d005..11b267661 100644 --- a/core/runtime/core.odin +++ b/core/runtime/core.odin @@ -143,7 +143,15 @@ Type_Info_Simd_Vector :: struct { elem_size: int, count: int, is_x86_mmx: bool, -} +}; +Type_Info_Relative_Pointer :: struct { + pointer: ^Type_Info, + base_integer: ^Type_Info, +}; +Type_Info_Relative_Slice :: struct { + slice: ^Type_Info, + base_integer: ^Type_Info, +}; Type_Info :: struct { size: int, @@ -176,6 +184,8 @@ Type_Info :: struct { Type_Info_Bit_Set, Type_Info_Opaque, Type_Info_Simd_Vector, + Type_Info_Relative_Pointer, + Type_Info_Relative_Slice, }, } @@ -205,6 +215,9 @@ Typeid_Kind :: enum u8 { Bit_Field, Bit_Set, Opaque, + Simd_Vector, + Relative_Pointer, + Relative_Slice, } #assert(len(Typeid_Kind) < 32); diff --git a/core/runtime/internal.odin b/core/runtime/internal.odin index 9d148a6fa..75727814a 100644 --- a/core/runtime/internal.odin +++ b/core/runtime/internal.odin @@ -442,6 +442,18 @@ print_type :: proc(fd: os.Handle, ti: ^Type_Info) { os.write_byte(fd, ']'); print_type(fd, info.elem); } + + case Type_Info_Relative_Pointer: + os.write_string(fd, "#relative("); + print_type(fd, info.base_integer); + os.write_string(fd, ") "); + print_type(fd, info.pointer); + + case Type_Info_Relative_Slice: + os.write_string(fd, "#relative("); + print_type(fd, info.base_integer); + os.write_string(fd, ") "); + print_type(fd, info.slice); } } diff --git a/src/check_expr.cpp b/src/check_expr.cpp index e6812b81d..ab4755bd3 100644 --- a/src/check_expr.cpp +++ b/src/check_expr.cpp @@ -599,6 +599,20 @@ i64 check_distance_between_types(CheckerContext *c, Operand *operand, Type *type } } + if (is_type_relative_pointer(dst)) { + i64 score = check_distance_between_types(c, operand, dst->RelativePointer.pointer_type); + if (score >= 0) { + return score+2; + } + } + + if (is_type_relative_slice(dst)) { + i64 score = check_distance_between_types(c, operand, dst->RelativeSlice.slice_type); + if (score >= 0) { + return score+2; + } + } + if (is_type_proc(dst)) { if (are_types_identical(src, dst)) { return 3; @@ -3620,7 +3634,7 @@ Entity *check_selector(CheckerContext *c, Operand *operand, Ast *node, Type *typ case Entity_Constant: operand->value = entity->Constant.value; operand->mode = Addressing_Constant; - if (operand->value.kind == ExactValue_Procedure) { + if (operand->value.kind == ExactValue_Procedure) { Entity *proc = strip_entity_wrapping(operand->value.value_procedure); if (proc != nullptr) { operand->mode = Addressing_Value; @@ -5923,7 +5937,7 @@ bool check_unpack_arguments(CheckerContext *ctx, Entity **lhs, isize lhs_count, isize count = tuple->variables.count; tuple_index += add_dependencies_from_unpacking(c, lhs, lhs_count, tuple_index, count); - + add_type_and_value(c->info, val.expr, val.mode, val.type, val.value); } else { for_array(j, tuple->variables) { @@ -9205,7 +9219,7 @@ ExprKind check_expr_base_internal(CheckerContext *c, Operand *o, Ast *node, Type o->mode = Addressing_Invalid; o->expr = node; return kind; - } + } GB_ASSERT(e->identifier != nullptr); Ast *proc_ident = clone_ast(e->identifier); @@ -9480,6 +9494,22 @@ ExprKind check_expr_base_internal(CheckerContext *c, Operand *o, Ast *node, Type if (t->kind == Type_Pointer && !is_type_empty_union(t->Pointer.elem)) { o->mode = Addressing_Variable; o->type = t->Pointer.elem; + } else if (t->kind == Type_RelativePointer) { + if (o->mode != Addressing_Variable) { + gbString str = expr_to_string(o->expr); + gbString typ = type_to_string(o->type); + error(o->expr, "Cannot dereference relative pointer '%s' of type '%s' as it does not have a variable addressing mode", str, typ); + gb_string_free(typ); + gb_string_free(str); + } + + // NOTE(bill): This is required because when dereferencing, the original type has been lost + add_type_info_type(c, o->type); + + Type *ptr_type = base_type(t->RelativePointer.pointer_type); + GB_ASSERT(ptr_type->kind == Type_Pointer); + o->mode = Addressing_Variable; + o->type = ptr_type->Pointer.elem; } else { gbString str = expr_to_string(o->expr); gbString typ = type_to_string(o->type); @@ -10001,6 +10031,12 @@ gbString write_expr_to_string(gbString str, Ast *node) { } str = gb_string_append_rune(str, '}'); case_end; + + case_ast_node(rt, RelativeType, node); + str = write_expr_to_string(str, rt->tag); + str = gb_string_appendc(str, "" ); + str = write_expr_to_string(str, rt->type); + case_end; } return str; diff --git a/src/check_type.cpp b/src/check_type.cpp index 8aa24a752..3829694a0 100644 --- a/src/check_type.cpp +++ b/src/check_type.cpp @@ -329,7 +329,7 @@ void add_polymorphic_record_entity(CheckerContext *ctx, Ast *node, Type *named_t auto *found_gen_types = map_get(&ctx->checker->info.gen_types, hash_pointer(original_type)); if (found_gen_types) { - array_add(found_gen_types, e); + array_add(found_gen_types, e); } else { auto array = array_make(heap_allocator()); array_add(&array, e); @@ -2501,7 +2501,7 @@ bool check_procedure_type(CheckerContext *ctx, Type *type, Ast *proc_type_node, c->curr_proc_sig = type; c->in_proc_sig = true; - + ProcCallingConvention cc = pt->calling_convention; if (cc == ProcCC_ForeignBlockDefault) { cc = ProcCC_CDecl; @@ -3284,6 +3284,46 @@ bool check_type_internal(CheckerContext *ctx, Ast *e, Type **type, Type *named_t return true; case_end; + case_ast_node(rt, RelativeType, e); + GB_ASSERT(rt->tag->kind == Ast_CallExpr); + ast_node(ce, CallExpr, rt->tag); + + Type *base_integer = nullptr; + + if (ce->args.count != 1) { + error(rt->type, "#relative expected 1 type argument, got %td", ce->args.count); + } else { + base_integer = check_type(ctx, ce->args[0]); + if (!is_type_integer(base_integer)) { + error(rt->type, "#relative base types must be an integer"); + base_integer = nullptr; + } else if (type_size_of(base_integer) > 64) { + error(rt->type, "#relative base integer types be less than or equal to 64-bits"); + base_integer = nullptr; + } + } + + Type *relative_type = nullptr; + Type *base_type = check_type(ctx, rt->type); + if (!is_type_pointer(base_type) && !is_type_slice(base_type)) { + error(rt->type, "#relative types can only be a pointer or slice"); + relative_type = base_type; + } else if (base_integer == nullptr) { + relative_type = base_type; + } else { + if (is_type_pointer(base_type)) { + relative_type = alloc_type_relative_pointer(base_type, base_integer); + } else if (is_type_slice(base_type)) { + relative_type = alloc_type_relative_slice(base_type, base_integer); + } + } + GB_ASSERT(relative_type != nullptr); + + *type = relative_type; + set_base_type(named_type, *type); + return true; + case_end; + case_ast_node(ot, OpaqueType, e); Type *elem = strip_opaque_type(check_type_expr(ctx, ot->type, nullptr)); *type = alloc_type_opaque(elem); diff --git a/src/checker.cpp b/src/checker.cpp index bb54fd903..ae9a6e56e 100644 --- a/src/checker.cpp +++ b/src/checker.cpp @@ -1430,6 +1430,16 @@ void add_type_info_type(CheckerContext *c, Type *t) { add_type_info_type(c, bt->SimdVector.elem); break; + case Type_RelativePointer: + add_type_info_type(c, bt->RelativePointer.pointer_type); + add_type_info_type(c, bt->RelativePointer.base_integer); + break; + + case Type_RelativeSlice: + add_type_info_type(c, bt->RelativeSlice.slice_type); + add_type_info_type(c, bt->RelativeSlice.base_integer); + break; + default: GB_PANIC("Unhandled type: %*.s %d", LIT(type_strings[bt->kind]), bt->kind); break; @@ -1626,6 +1636,16 @@ void add_min_dep_type_info(Checker *c, Type *t) { add_min_dep_type_info(c, bt->SimdVector.elem); break; + case Type_RelativePointer: + add_min_dep_type_info(c, bt->RelativePointer.pointer_type); + add_min_dep_type_info(c, bt->RelativePointer.base_integer); + break; + + case Type_RelativeSlice: + add_min_dep_type_info(c, bt->RelativeSlice.slice_type); + add_min_dep_type_info(c, bt->RelativeSlice.base_integer); + break; + default: GB_PANIC("Unhandled type: %*.s", LIT(type_strings[bt->kind])); break; @@ -2055,6 +2075,8 @@ void init_core_type_info(Checker *c) { t_type_info_bit_set = find_core_type(c, str_lit("Type_Info_Bit_Set")); t_type_info_opaque = find_core_type(c, str_lit("Type_Info_Opaque")); t_type_info_simd_vector = find_core_type(c, str_lit("Type_Info_Simd_Vector")); + t_type_info_relative_pointer = find_core_type(c, str_lit("Type_Info_Relative_Pointer")); + t_type_info_relative_slice = find_core_type(c, str_lit("Type_Info_Relative_Slice")); t_type_info_named_ptr = alloc_type_pointer(t_type_info_named); t_type_info_integer_ptr = alloc_type_pointer(t_type_info_integer); @@ -2081,6 +2103,8 @@ void init_core_type_info(Checker *c) { t_type_info_bit_set_ptr = alloc_type_pointer(t_type_info_bit_set); t_type_info_opaque_ptr = alloc_type_pointer(t_type_info_opaque); t_type_info_simd_vector_ptr = alloc_type_pointer(t_type_info_simd_vector); + t_type_info_relative_pointer_ptr = alloc_type_pointer(t_type_info_relative_pointer); + t_type_info_relative_slice_ptr = alloc_type_pointer(t_type_info_relative_slice); } void init_mem_allocator(Checker *c) { diff --git a/src/ir.cpp b/src/ir.cpp index e2c9f90ed..2036c94ab 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -20,7 +20,7 @@ struct irModule { PtrSet min_dep_set; Map values; // Key: Entity * - StringMap members; + StringMap members; Map entity_names; // Key: Entity * of the typename Map debug_info; // Key: Unique pointer Map anonymous_proc_lits; // Key: Ast * @@ -7399,7 +7399,7 @@ irValue *ir_build_expr_internal(irProcedure *proc, Ast *expr) { // HACK TODO(bill): This is hack but it should be safe in virtually all cases irValue *v = ir_typeid(proc->module, tv.type); return ir_emit_conv(proc, v, t_typeid); - } + } if (tv.value.kind != ExactValue_Invalid) { // NOTE(bill): Edge case @@ -11514,7 +11514,7 @@ void ir_setup_type_info_data(irProcedure *proc) { // NOTE(bill): Setup type_info case Basic_f64le: case Basic_f32be: case Basic_f64be: - { + { tag = ir_emit_conv(proc, variant_ptr, t_type_info_float_ptr); // NOTE(bill): This is matches the runtime layout diff --git a/src/llvm_backend.cpp b/src/llvm_backend.cpp index 06209a35e..48ae4705b 100644 --- a/src/llvm_backend.cpp +++ b/src/llvm_backend.cpp @@ -56,6 +56,10 @@ LLVMValueRef llvm_cstring(lbModule *m, String const &str) { lbAddr lb_addr(lbValue addr) { lbAddr v = {lbAddr_Default, addr}; + if (is_type_relative_pointer(type_deref(addr.type))) { + GB_ASSERT(is_type_pointer(addr.type)); + v.kind = lbAddr_RelativePointer; + } return v; } @@ -160,7 +164,29 @@ void lb_addr_store(lbProcedure *p, lbAddr const &addr, lbValue value) { value.value = LLVMConstNull(lb_type(p->module, t)); } - if (addr.kind == lbAddr_AtomOp_index_set) { + if (addr.kind == lbAddr_RelativePointer) { + Type *rel_ptr = base_type(lb_addr_type(addr)); + GB_ASSERT(rel_ptr->kind == Type_RelativePointer); + + value = lb_emit_conv(p, value, rel_ptr->RelativePointer.pointer_type); + + GB_ASSERT(is_type_pointer(addr.addr.type)); + lbValue ptr = lb_emit_conv(p, addr.addr, t_uintptr); + lbValue val_ptr = lb_emit_conv(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); + return; + + } else if (addr.kind == lbAddr_AtomOp_index_set) { lbValue ptr = addr.addr; lbValue index = addr.index_set.index; Ast *node = addr.index_set.node; @@ -341,7 +367,34 @@ lbValue lb_emit_load(lbProcedure *p, lbValue value) { lbValue lb_addr_load(lbProcedure *p, lbAddr const &addr) { GB_ASSERT(addr.addr.value != nullptr); - if (addr.kind == lbAddr_Map) { + + if (addr.kind == 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 = {}; + final_ptr.type = absolute_ptr.type; + final_ptr.value = LLVMBuildSelect(p->builder, cond.value, nil_ptr.value, absolute_ptr.value, ""); + + return lb_emit_load(p, final_ptr); + + } else if (addr.kind == lbAddr_Map) { Type *map_type = base_type(addr.map.type); lbAddr v = lb_add_local_generated(p, map_type->Map.lookup_result_type, true); lbValue h = lb_gen_map_header(p, addr.addr, map_type); @@ -1181,6 +1234,20 @@ LLVMTypeRef lb_type_internal(lbModule *m, Type *type) { return LLVMX86MMXTypeInContext(ctx); } return LLVMVectorType(lb_type(m, type->SimdVector.elem), cast(unsigned)type->SimdVector.count); + + case Type_RelativePointer: + return lb_type_internal(m, type->RelativePointer.base_integer); + + case Type_RelativeSlice: + { + LLVMTypeRef base_integer = lb_type_internal(m, type->RelativeSlice.base_integer); + + unsigned field_count = 2; + LLVMTypeRef *fields = gb_alloc_array(heap_allocator(), LLVMTypeRef, field_count); + fields[0] = base_integer; + fields[1] = base_integer; + return LLVMStructTypeInContext(ctx, fields, field_count, false); + } } GB_PANIC("Invalid type %s", type_to_string(type)); @@ -3970,7 +4037,7 @@ void lb_build_stmt(lbProcedure *p, Ast *node) { } lb_emit_defer_stmts(p, lbDeferExit_Return, nullptr); - + LLVMBuildRet(p->builder, res.value); } case_end; @@ -4323,19 +4390,23 @@ lbValue lb_typeid(lbModule *m, Type *type, Type *typeid_type) { if (flags & BasicFlag_String) kind = Typeid_String; if (flags & BasicFlag_Rune) kind = Typeid_Rune; } break; - case Type_Pointer: kind = Typeid_Pointer; break; - case Type_Array: kind = Typeid_Array; break; + case Type_Pointer: kind = Typeid_Pointer; break; + case Type_Array: kind = Typeid_Array; break; case Type_EnumeratedArray: kind = Typeid_Enumerated_Array; break; - case Type_Slice: kind = Typeid_Slice; break; - case Type_DynamicArray: kind = Typeid_Dynamic_Array; break; - case Type_Map: kind = Typeid_Map; break; - case Type_Struct: kind = Typeid_Struct; break; - case Type_Enum: kind = Typeid_Enum; break; - case Type_Union: kind = Typeid_Union; break; - case Type_Tuple: kind = Typeid_Tuple; break; - case Type_Proc: kind = Typeid_Procedure; break; - case Type_BitField: kind = Typeid_Bit_Field; break; - case Type_BitSet: kind = Typeid_Bit_Set; break; + case Type_Slice: kind = Typeid_Slice; break; + case Type_DynamicArray: kind = Typeid_Dynamic_Array; break; + case Type_Map: kind = Typeid_Map; break; + case Type_Struct: kind = Typeid_Struct; break; + case Type_Enum: kind = Typeid_Enum; break; + case Type_Union: kind = Typeid_Union; break; + case Type_Tuple: kind = Typeid_Tuple; break; + case Type_Proc: kind = Typeid_Procedure; break; + case Type_BitField: kind = Typeid_Bit_Field; break; + case Type_BitSet: kind = Typeid_Bit_Set; break; + case Type_Opaque: kind = Typeid_Opaque; break; + case Type_SimdVector: kind = Typeid_Simd_Vector; break; + case Type_RelativePointer: kind = Typeid_Relative_Pointer; break; + case Type_RelativeSlice: kind = Typeid_Relative_Slice; break; } if (is_type_cstring(type)) { @@ -4495,7 +4566,7 @@ lbValue lb_const_value(lbModule *m, Type *type, ExactValue value) { res.value = LLVMConstArray(lb_type(m, elem), elems, cast(unsigned)count); return res; - } + } switch (value.kind) { case ExactValue_Invalid: @@ -9723,6 +9794,10 @@ lbAddr lb_build_addr(lbProcedure *p, Ast *expr) { case_end; case_ast_node(de, DerefExpr, expr); + if (is_type_relative_pointer(type_of_expr(de->expr))) { + lbAddr addr = lb_build_addr(p, de->expr); + return addr; + } lbValue addr = lb_build_expr(p, de->expr); return lb_addr(addr); case_end; @@ -11192,6 +11267,36 @@ void lb_setup_type_info_data(lbProcedure *p) { // NOTE(bill): Setup type_info da lb_emit_store(p, tag, res); } break; + + case Type_RelativePointer: + { + tag = lb_const_ptr_cast(m, variant_ptr, t_type_info_relative_pointer_ptr); + LLVMValueRef vals[2] = { + lb_get_type_info_ptr(m, t->RelativePointer.pointer_type).value, + lb_get_type_info_ptr(m, t->RelativePointer.base_integer).value, + }; + + lbValue res = {}; + res.type = type_deref(tag.type); + res.value = LLVMConstNamedStruct(lb_type(m, res.type), vals, gb_count_of(vals)); + lb_emit_store(p, tag, res); + } + break; + case Type_RelativeSlice: + { + tag = lb_const_ptr_cast(m, variant_ptr, t_type_info_relative_slice_ptr); + LLVMValueRef vals[2] = { + lb_get_type_info_ptr(m, t->RelativeSlice.slice_type).value, + lb_get_type_info_ptr(m, t->RelativeSlice.base_integer).value, + }; + + lbValue res = {}; + res.type = type_deref(tag.type); + res.value = LLVMConstNamedStruct(lb_type(m, res.type), vals, gb_count_of(vals)); + lb_emit_store(p, tag, res); + } + break; + } @@ -11554,6 +11659,25 @@ void lb_generate_code(lbGenerator *gen) { LLVMAddMergedLoadStoreMotionPass(default_function_pass_manager); LLVMAddPromoteMemoryToRegisterPass(default_function_pass_manager); // LLVMAddUnifyFunctionExitNodesPass(default_function_pass_manager); + if (build_context.optimization_level >= 2) { + LLVMAddAggressiveInstCombinerPass(default_function_pass_manager); + LLVMAddEarlyCSEPass(default_function_pass_manager); + LLVMAddEarlyCSEMemSSAPass(default_function_pass_manager); + LLVMAddLowerExpectIntrinsicPass(default_function_pass_manager); + + LLVMAddAlignmentFromAssumptionsPass(default_function_pass_manager); + LLVMAddLoopRotatePass(default_function_pass_manager); + LLVMAddDeadStoreEliminationPass(default_function_pass_manager); + LLVMAddScalarizerPass(default_function_pass_manager); + LLVMAddReassociatePass(default_function_pass_manager); + LLVMAddAddDiscriminatorsPass(default_function_pass_manager); + LLVMAddPromoteMemoryToRegisterPass(default_function_pass_manager); + LLVMAddCorrelatedValuePropagationPass(default_function_pass_manager); + + LLVMAddSLPVectorizePass(default_function_pass_manager); + LLVMAddLoopVectorizePass(default_function_pass_manager); + + } } LLVMPassManagerRef default_function_pass_manager_without_memcpy = LLVMCreateFunctionPassManagerForModule(mod); @@ -11784,10 +11908,12 @@ void lb_generate_code(lbGenerator *gen) { for_array(i, m->procedures_to_generate) { lbProcedure *p = m->procedures_to_generate[i]; if (p->body != nullptr) { // Build Procedure - if (p->flags & lbProcedureFlag_WithoutMemcpyPass) { - LLVMRunFunctionPassManager(default_function_pass_manager_without_memcpy, p->value); - } else { - LLVMRunFunctionPassManager(default_function_pass_manager, p->value); + for (i32 i = 0; i <= build_context.optimization_level; i++) { + if (p->flags & lbProcedureFlag_WithoutMemcpyPass) { + LLVMRunFunctionPassManager(default_function_pass_manager_without_memcpy, p->value); + } else { + LLVMRunFunctionPassManager(default_function_pass_manager, p->value); + } } } } @@ -11799,7 +11925,12 @@ void lb_generate_code(lbGenerator *gen) { defer (LLVMDisposePassManager(module_pass_manager)); LLVMAddAlwaysInlinerPass(module_pass_manager); LLVMAddStripDeadPrototypesPass(module_pass_manager); - // LLVMAddConstantMergePass(module_pass_manager); + // if (build_context.optimization_level >= 2) { + // LLVMAddArgumentPromotionPass(module_pass_manager); + // LLVMAddConstantMergePass(module_pass_manager); + // LLVMAddGlobalDCEPass(module_pass_manager); + // LLVMAddDeadArgEliminationPass(module_pass_manager); + // } LLVMPassManagerBuilderRef pass_manager_builder = LLVMPassManagerBuilderCreate(); defer (LLVMPassManagerBuilderDispose(pass_manager_builder)); diff --git a/src/llvm_backend.hpp b/src/llvm_backend.hpp index 1fd81fcab..0b1c331ea 100644 --- a/src/llvm_backend.hpp +++ b/src/llvm_backend.hpp @@ -28,6 +28,8 @@ enum lbAddrKind { lbAddr_Context, lbAddr_SoaVariable, + lbAddr_RelativePointer, + lbAddr_AtomOp_index_set, }; @@ -68,11 +70,11 @@ struct lbModule { Map types; // Key: Type * Map values; // Key: Entity * - StringMap members; - StringMap procedures; + StringMap members; + StringMap procedures; Map procedure_values; // Key: LLVMValueRef - StringMap const_strings; + StringMap const_strings; Map anonymous_proc_lits; // Key: Ast * diff --git a/src/parser.cpp b/src/parser.cpp index ab38951e5..c08325c26 100644 --- a/src/parser.cpp +++ b/src/parser.cpp @@ -87,6 +87,7 @@ Token ast_token(Ast *node) { case Ast_OpaqueType: return node->OpaqueType.token; case Ast_PolyType: return node->PolyType.token; case Ast_ProcType: return node->ProcType.token; + case Ast_RelativeType: return ast_token(node->RelativeType.tag); case Ast_PointerType: return node->PointerType.token; case Ast_ArrayType: return node->ArrayType.token; case Ast_DynamicArrayType: return node->DynamicArrayType.token; @@ -343,6 +344,10 @@ Ast *clone_ast(Ast *node) { n->ProcType.params = clone_ast(n->ProcType.params); n->ProcType.results = clone_ast(n->ProcType.results); break; + case Ast_RelativeType: + n->RelativeType.tag = clone_ast(n->RelativeType.tag); + n->RelativeType.type = clone_ast(n->RelativeType.type); + break; case Ast_PointerType: n->PointerType.type = clone_ast(n->PointerType.type); break; @@ -922,7 +927,12 @@ Ast *ast_proc_type(AstFile *f, Token token, Ast *params, Ast *results, u64 tags, return result; } - +Ast *ast_relative_type(AstFile *f, Ast *tag, Ast *type) { + Ast *result = alloc_ast_node(f, Ast_RelativeType); + result->RelativeType.tag = tag; + result->RelativeType.type = type; + return result; +} Ast *ast_pointer_type(AstFile *f, Token token, Ast *type) { Ast *result = alloc_ast_node(f, Ast_PointerType); result->PointerType.token = token; @@ -1825,6 +1835,11 @@ Ast *parse_operand(AstFile *f, bool lhs) { syntax_error(token, "#bounds_check and #no_bounds_check cannot be applied together"); } return operand; + } else if (name.string == "relative") { + Ast *tag = ast_basic_directive(f, token, name.string); + tag = parse_call_expr(f, tag); + Ast *type = parse_type(f); + return ast_relative_type(f, tag, type); } else { operand = ast_tag_expr(f, token, name, parse_expr(f, false)); } diff --git a/src/parser.hpp b/src/parser.hpp index 61be8c54a..7cb380ffb 100644 --- a/src/parser.hpp +++ b/src/parser.hpp @@ -497,6 +497,10 @@ AST_KIND(_TypeBegin, "", bool) \ Token token; \ Ast *type; \ }) \ + AST_KIND(RelativeType, "relative type", struct { \ + Ast *tag; \ + Ast *type; \ + }) \ AST_KIND(ArrayType, "array type", struct { \ Token token; \ Ast *count; \ diff --git a/src/types.cpp b/src/types.cpp index 990ca8387..9a109741f 100644 --- a/src/types.cpp +++ b/src/types.cpp @@ -126,7 +126,7 @@ enum StructSoaKind { enum TypeAtomOpKind { TypeAtomOp_Invalid, - + TypeAtomOp_index_get, TypeAtomOp_index_set, TypeAtomOp_slice, @@ -151,7 +151,7 @@ struct TypeStruct { i64 custom_align; Entity * names; - + TypeAtomOpTable *atom_op_table; Type * soa_elem; @@ -290,8 +290,14 @@ struct TypeProc { Type *elem; \ bool is_x86_mmx; \ }) \ - - + TYPE_KIND(RelativePointer, struct { \ + Type *pointer_type; \ + Type *base_integer; \ + }) \ + TYPE_KIND(RelativeSlice, struct { \ + Type *slice_type; \ + Type *base_integer; \ + }) enum TypeKind { @@ -358,6 +364,10 @@ enum Typeid_Kind : u8 { Typeid_Map, Typeid_Bit_Field, Typeid_Bit_Set, + Typeid_Opaque, + Typeid_Simd_Vector, + Typeid_Relative_Pointer, + Typeid_Relative_Slice, }; @@ -611,6 +621,8 @@ gb_global Type *t_type_info_bit_field = nullptr; gb_global Type *t_type_info_bit_set = nullptr; gb_global Type *t_type_info_opaque = nullptr; gb_global Type *t_type_info_simd_vector = nullptr; +gb_global Type *t_type_info_relative_pointer = nullptr; +gb_global Type *t_type_info_relative_slice = nullptr; gb_global Type *t_type_info_named_ptr = nullptr; gb_global Type *t_type_info_integer_ptr = nullptr; @@ -637,6 +649,8 @@ gb_global Type *t_type_info_bit_field_ptr = nullptr; gb_global Type *t_type_info_bit_set_ptr = nullptr; gb_global Type *t_type_info_opaque_ptr = nullptr; gb_global Type *t_type_info_simd_vector_ptr = nullptr; +gb_global Type *t_type_info_relative_pointer_ptr = nullptr; +gb_global Type *t_type_info_relative_slice_ptr = nullptr; gb_global Type *t_allocator = nullptr; gb_global Type *t_allocator_ptr = nullptr; @@ -661,6 +675,9 @@ void init_map_internal_types(Type *type); Type * bit_set_to_int(Type *t); bool are_types_identical(Type *x, Type *y); +bool is_type_pointer(Type *t); +bool is_type_slice(Type *t); +bool is_type_integer(Type *t); bool type_ptr_set_exists(PtrSet *s, Type *t) { if (ptr_set_exists(s, t)) { @@ -837,9 +854,23 @@ Type *alloc_type_enum() { return t; } +Type *alloc_type_relative_pointer(Type *pointer_type, Type *base_integer) { + GB_ASSERT(is_type_pointer(pointer_type)); + GB_ASSERT(is_type_integer(base_integer)); + Type *t = alloc_type(Type_RelativePointer); + t->RelativePointer.pointer_type = pointer_type; + t->RelativePointer.base_integer = base_integer; + return t; +} - - +Type *alloc_type_relative_slice(Type *slice_type, Type *base_integer) { + GB_ASSERT(is_type_slice(slice_type)); + GB_ASSERT(is_type_integer(base_integer)); + Type *t = alloc_type(Type_RelativeSlice); + t->RelativeSlice.slice_type = slice_type; + t->RelativeSlice.base_integer = base_integer; + return t; +} Type *alloc_type_named(String name, Type *base, Entity *type_name) { Type *t = alloc_type(Type_Named); @@ -1197,6 +1228,14 @@ bool is_type_generic(Type *t) { return t->kind == Type_Generic; } +bool is_type_relative_pointer(Type *t) { + t = base_type(t); + return t->kind == Type_RelativePointer; +} +bool is_type_relative_slice(Type *t) { + t = base_type(t); + return t->kind == Type_RelativeSlice; +} Type *core_array_type(Type *t) { @@ -1756,6 +1795,10 @@ bool type_has_nil(Type *t) { return false; case Type_Opaque: return true; + + case Type_RelativePointer: + case Type_RelativeSlice: + return true; } return false; } @@ -2865,6 +2908,11 @@ i64 type_align_of_internal(Type *t, TypePath *path) { // IMPORTANT TODO(bill): Figure out the alignment of vector types return gb_clamp(next_pow2(type_size_of_internal(t, path)), 1, build_context.max_align); } + + case Type_RelativePointer: + return type_align_of_internal(t->RelativePointer.base_integer, path); + case Type_RelativeSlice: + return type_align_of_internal(t->RelativeSlice.base_integer, path); } // return gb_clamp(next_pow2(type_size_of(t)), 1, build_context.max_align); @@ -3138,6 +3186,11 @@ i64 type_size_of_internal(Type *t, TypePath *path) { Type *elem = t->SimdVector.elem; return count * type_size_of_internal(elem, path); } + + case Type_RelativePointer: + return type_size_of_internal(t->RelativePointer.base_integer, path); + case Type_RelativeSlice: + return 2*type_size_of_internal(t->RelativeSlice.base_integer, path); } // Catch all @@ -3536,6 +3589,19 @@ gbString write_type_to_string(gbString str, Type *type) { str = write_type_to_string(str, type->SimdVector.elem); } break; + + case Type_RelativePointer: + str = gb_string_append_fmt(str, "#relative("); + str = write_type_to_string(str, type->RelativePointer.base_integer); + str = gb_string_append_fmt(str, ") "); + str = write_type_to_string(str, type->RelativePointer.pointer_type); + break; + case Type_RelativeSlice: + str = gb_string_append_fmt(str, "#relative("); + str = write_type_to_string(str, type->RelativeSlice.base_integer); + str = gb_string_append_fmt(str, ") "); + str = write_type_to_string(str, type->RelativeSlice.slice_type); + break; } return str;