diff --git a/src/LLVM.zig b/src/LLVM.zig index 34671d6..f9dc77c 100644 --- a/src/LLVM.zig +++ b/src/LLVM.zig @@ -944,6 +944,10 @@ pub const Builder = opaque { return api.LLVMBuildPtrToInt(builder, value, destination_type, ""); } + pub fn create_pointer_cast(builder: *Builder, value: *Value, destination_type: *Type) *Value { + return api.LLVMBuildPointerCast(builder, value, destination_type, ""); + } + pub fn create_truncate(builder: *Builder, value: *Value, destination_type: *Type) *Value { return api.LLVMBuildTrunc(builder, value, destination_type, ""); } diff --git a/src/compiler.bbb b/src/compiler.bbb index 34a865a..13dc3be 100644 --- a/src/compiler.bbb +++ b/src/compiler.bbb @@ -39,6 +39,7 @@ OS_Linux_MAP = bits u32 } [extern] mmap = fn [cc(c)] (address: u64, size: u64, protection: OS_Linux_PROT, map: OS_Linux_MAP, file_descriptor: s32, offset: s64) &u8; +[extern] mprotect = fn [cc(c)] (address: u64, size: u64, protection: OS_Linux_PROT) s32; OS_ProtectionFlags = bits { @@ -89,6 +90,16 @@ os_reserve = fn (base: u64, size: u64, protection: OS_ProtectionFlags, map: OS_M return address; } +os_commit = fn (address: u64, size: u64, protection: OS_ProtectionFlags) void +{ + >protection_flags = os_linux_protection_flags(protection); + >result = mprotect(address, size, protection_flags); + if (result != 0) + { + unreachable; + } +} + Arena = struct { reserved_size: u64, @@ -109,6 +120,35 @@ ArenaInitialization = struct arena_initialize = fn (initialization: ArenaInitialization) &Arena { + >protection_flags: OS_ProtectionFlags = { + .read = 1, + .write = 1, + zero, + }; + + >map_flags: OS_MapFlags = { + .private = 1, + .anonymous = 1, + .no_reserve = 1, + .populate = 0, + }; + + >arena: &Arena = #pointer_cast(os_reserve(0, initialization.reserved_size, protection_flags, map_flags)); + os_commit(#int_from_pointer(arena), initialization.initial_size, { + .read = 1, + .write = 1, + zero, + }); + + //arena.& = { + // .reserved_size = initialization.reserved_size, + // .os_position = initialization.initial_size, + // .position = minimum_position, + // .granularity = initialization.granularity, + // zero, + //}; + + return arena; } [export] main = fn [cc(c)] () s32 diff --git a/src/converter.zig b/src/converter.zig index 6a3088c..b2feb13 100644 --- a/src/converter.zig +++ b/src/converter.zig @@ -1114,6 +1114,7 @@ pub const Value = struct { return switch (value.bb) { .constant_integer, .constant_array => true, .struct_initialization => |si| si.is_constant, + .instruction => false, else => @trap(), }; } @@ -2203,8 +2204,6 @@ const Converter = struct { .@"return" => { converter.skip_space(); - const abi_return_type = current_function_type.abi_return_type; - _ = abi_return_type; const return_type_abi = ¤t_function_type.return_type_abi; const returns_nothing = converter.consume_character_if_match(';'); if (returns_nothing) { @@ -2225,12 +2224,13 @@ const Converter = struct { @trap(); }, else => { + assert(return_value.type.is_abi_equal(return_type_abi.semantic_type)); const return_alloca = current_function.return_alloca; _ = module.create_store(.{ .source_value = return_value.llvm, .destination_value = return_alloca, .source_type = return_type_abi.semantic_type, - .destination_type = current_function_type.abi_return_type, + .destination_type = return_type_abi.semantic_type, }); }, } @@ -2647,6 +2647,7 @@ const Converter = struct { integer_max, int_from_enum, int_from_pointer, + pointer_cast, select, trap, truncate, @@ -2825,6 +2826,30 @@ const Converter = struct { }; return value; }, + .pointer_cast => { + const ty = expected_type orelse converter.report_error(); + if (ty.bb != .pointer) { + converter.report_error(); + } + const source_value = converter.parse_value(module, null, .value); + converter.skip_space(); + converter.expect_character(right_parenthesis); + if (source_value.type.bb != .pointer) { + converter.report_error(); + } + if (ty == source_value.type) { + converter.report_error(); + } + const value = module.values.add(); + value.* = .{ + .llvm = module.llvm.builder.create_pointer_cast(source_value.llvm, ty.llvm.handle), + .type = ty, + .bb = .instruction, + .lvalue = true, + .dereference_to_assign = false, + }; + return value; + }, .select => { const condition_value = converter.parse_value(module, null, .value); @@ -3237,6 +3262,7 @@ const Converter = struct { if (field_count == struct_type.fields.len) { converter.report_error(); } + if (is_ordered and is_constant) { const zero_fields = struct_type.fields[field_count..]; const zero_field_values = field_value_buffer[field_count..][0..zero_fields.len]; @@ -3567,9 +3593,6 @@ const Converter = struct { const appointee_type = variable.value.type.bb.pointer.type; if (converter.consume_character_if_match(left_parenthesis)) { - if (value_kind == .pointer) { - converter.report_error(); - } const call = converter.parse_call(module, variable.value); break :b call; } else if (converter.consume_character_if_match('.')) { @@ -3642,15 +3665,47 @@ const Converter = struct { .pointer => |pointer_type| { const element_type = pointer_type.type; if (converter.consume_character_if_match('&')) { - const load = module.values.add(); - load.* = .{ + const pointer_load = module.values.add(); + pointer_load.* = .{ .llvm = module.create_load(.{ .type = appointee_type, .value = variable.value.llvm }), .type = appointee_type, .bb = .instruction, .lvalue = false, .dereference_to_assign = false, }; - break :b load; + switch (value_kind) { + .value => { + if (expected_type) |expected_ty| { + if (expected_ty == appointee_type) { + @trap(); + } else { + if (appointee_type.bb == .pointer and appointee_type.bb.pointer.type == expected_ty) { + const load = module.values.add(); + load.* = .{ + .llvm = module.create_load(.{ .type = expected_ty, .value = pointer_load.llvm }), + .type = expected_ty, + .bb = .instruction, + .lvalue = false, + .dereference_to_assign = false, + }; + break :b load; + } else { + converter.report_error(); + } + } + } else { + @trap(); + } + }, + .maybe_pointer, .pointer => { + if (expected_type) |expected_ty| { + _ = expected_ty; + @trap(); + } else { + break :b pointer_load; + } + }, + } } else { switch (element_type.bb) { .structure => |*struct_type| { diff --git a/src/converter_test.zig b/src/converter_test.zig index c13ec17..8ad6fca 100644 --- a/src/converter_test.zig +++ b/src/converter_test.zig @@ -408,3 +408,7 @@ test "integer_max" { test "unreachable" { try invsrc(@src()); } + +test "pointer_cast" { + try invsrc(@src()); +} diff --git a/src/llvm_api.zig b/src/llvm_api.zig index 0b92417..01f2e69 100644 --- a/src/llvm_api.zig +++ b/src/llvm_api.zig @@ -101,6 +101,7 @@ pub extern fn LLVMBuildZExt(builder: *llvm.Builder, value: *llvm.Value, destinat pub extern fn LLVMBuildSExt(builder: *llvm.Builder, value: *llvm.Value, destination_type: *llvm.Type, name: [*:0]const u8) *llvm.Value; pub extern fn LLVMBuildIntToPtr(builder: *llvm.Builder, value: *llvm.Value, destination_type: *llvm.Type, name: [*:0]const u8) *llvm.Value; pub extern fn LLVMBuildPtrToInt(builder: *llvm.Builder, value: *llvm.Value, destination_type: *llvm.Type, name: [*:0]const u8) *llvm.Value; +pub extern fn LLVMBuildPointerCast(builder: *llvm.Builder, value: *llvm.Value, ty: *llvm.Type, name: [*:0]const u8) *llvm.Value; pub extern fn LLVMBuildTrunc(builder: *llvm.Builder, value: *llvm.Value, destination_type: *llvm.Type, name: [*:0]const u8) *llvm.Value; pub extern fn LLVMSetCurrentDebugLocation2(builder: *llvm.Builder, location: ?*llvm.DI.Location) void; diff --git a/tests/pointer_cast.bbb b/tests/pointer_cast.bbb new file mode 100644 index 0000000..1146bea --- /dev/null +++ b/tests/pointer_cast.bbb @@ -0,0 +1,7 @@ +[export] main = fn [cc(c)] () s32 +{ + >result: u32 = 0; + >pointer = &result; + >signed_ptr: &s32 = #pointer_cast(pointer); + return signed_ptr.&; +}