Compare commits

...

2 Commits

Author SHA1 Message Date
6e36338eba wip 2025-06-27 20:52:48 -06:00
a0b2218cc3 Add breakpoint intrinsic
All checks were successful
CI / ci (Release, ubuntu-latest) (pull_request) Successful in 22s
CI / ci (Release-assertions, ubuntu-latest) (pull_request) Successful in 27s
CI / ci (Release, ubuntu-latest) (push) Successful in 1m22s
CI / ci (Release-assertions, ubuntu-latest) (push) Successful in 1m30s
CI / ci (Debug, ubuntu-latest) (push) Successful in 7m20s
CI / release (ubuntu-latest) (push) Successful in 9s
2025-06-27 20:47:02 -06:00
2 changed files with 114 additions and 21 deletions

63
src/compiler.bbb Normal file → Executable file
View File

@ -888,6 +888,7 @@ LLVMIntrinsicIndex = enum u32
{ {
"llvm.ctlz", "llvm.ctlz",
"llvm.cttz", "llvm.cttz",
"llvm.debugtrap",
"llvm.smax", "llvm.smax",
"llvm.smin", "llvm.smin",
"llvm.trap", "llvm.trap",
@ -2032,6 +2033,7 @@ ValueId = enum
macro_instantiation, macro_instantiation,
field_parent_pointer, field_parent_pointer,
build_mode, build_mode,
breakpoint,
} }
ValueConstantInteger = struct ValueConstantInteger = struct
@ -3733,7 +3735,7 @@ parse_name = fn (module: &Module) []u8
result = parse_identifier(module); result = parse_identifier(module);
} }
return result; return arena_duplicate_string(module.arena, result);
} }
new_value = fn (module: &Module) &Value new_value = fn (module: &Module) &Value
@ -4126,6 +4128,7 @@ ValueKeyword = enum
ValueIntrinsic = enum ValueIntrinsic = enum
{ {
align_of, align_of,
breakpoint,
build_mode, build_mode,
byte_size, byte_size,
enum_from_int, enum_from_int,
@ -5485,7 +5488,7 @@ parse_aggregate_initialization = fn (module: &Module, scope: &Scope, builder: Va
if (consume_character_if_match(module, '.')) if (consume_character_if_match(module, '.'))
{ {
>name = parse_identifier(module); >name = arena_duplicate_string(module.arena, parse_identifier(module));
skip_space(module); skip_space(module);
expect_character(module, '='); expect_character(module, '=');
skip_space(module); skip_space(module);
@ -5769,6 +5772,7 @@ parse_left = fn (module: &Module, scope: &Scope, builder: ValueBuilder) &Value
.trap, .trap,
.va_start, .va_start,
.has_debug_info, .has_debug_info,
.breakpoint,
=> =>
{ {
skip_space(module); skip_space(module);
@ -5782,6 +5786,7 @@ parse_left = fn (module: &Module, scope: &Scope, builder: ValueBuilder) &Value
.trap => { id = .trap; }, .trap => { id = .trap; },
.va_start => { id = .va_start; }, .va_start => { id = .va_start; },
.has_debug_info => { id = .has_debug_info; }, .has_debug_info => { id = .has_debug_info; },
.breakpoint => { id = .breakpoint; },
else => { unreachable; }, else => { unreachable; },
} }
@ -6494,7 +6499,7 @@ parse_right = fn (module: &Module, scope: &Scope, builder: ValueBuilder) &Value
skip_space(module); skip_space(module);
>identifier = parse_identifier(module); >identifier = arena_duplicate_string(module.arena, parse_identifier(module));
result = new_value(module); result = new_value(module);
result.& = { result.& = {
@ -7365,7 +7370,7 @@ parse = fn (module: &Module) void
} }
>field_line = get_line(module); >field_line = get_line(module);
>field_name = parse_identifier(module); >field_name = arena_duplicate_string(module.arena, parse_identifier(module));
skip_space(module); skip_space(module);
expect_character(module, ':'); expect_character(module, ':');
@ -7860,7 +7865,7 @@ parse = fn (module: &Module) void
>field_index = field_count; >field_index = field_count;
>field_line = get_line(module); >field_line = get_line(module);
>field_name = parse_identifier(module); >field_name = arena_duplicate_string(module.arena, parse_identifier(module));
skip_space(module); skip_space(module);
expect_character(module, ':'); expect_character(module, ':');
@ -7985,7 +7990,7 @@ parse = fn (module: &Module) void
field_count += 1; field_count += 1;
>field_line = get_line(module); >field_line = get_line(module);
>field_name = parse_identifier(module); >field_name = arena_duplicate_string(module.arena, parse_identifier(module));
skip_space(module); skip_space(module);
expect_character(module, ':'); expect_character(module, ':');
@ -12003,7 +12008,7 @@ analyze_type = fn (module: &Module, value: &Value, expected_type: &Type, analysi
zero, zero,
}); });
>element_length_pointer = LLVMBuildStructGEP2(module.llvm.builder, slice_struct_type.llvm.abi, array_element_pointer, 1, ""); >element_length_pointer = LLVMBuildStructGEP2(module.llvm.builder, slice_struct_type.llvm.abi, array_element_pointer, 1, "length");
>element_length = create_load(module, { >element_length = create_load(module, {
.type = u64_type, .type = u64_type,
.pointer = element_length_pointer, .pointer = element_length_pointer,
@ -12056,7 +12061,7 @@ analyze_type = fn (module: &Module, value: &Value, expected_type: &Type, analysi
zero, zero,
}); });
>element_pointer_pointer = LLVMBuildStructGEP2(module.llvm.builder, slice_struct_type.llvm.abi, length_array_element_pointer, 0, ""); >element_pointer_pointer = LLVMBuildStructGEP2(module.llvm.builder, slice_struct_type.llvm.abi, length_array_element_pointer, 0, "pointer");
>element_pointer = create_load(module, { >element_pointer = create_load(module, {
.type = get_pointer_type(module, u8_type), .type = get_pointer_type(module, u8_type),
.pointer = element_pointer_pointer, .pointer = element_pointer_pointer,
@ -12432,6 +12437,15 @@ analyze_type = fn (module: &Module, value: &Value, expected_type: &Type, analysi
value_type = uint1(module); value_type = uint1(module);
typecheck(module, expected_type, value_type); typecheck(module, expected_type, value_type);
}, },
.breakpoint =>
{
if (expected_type)
{
report_error();
}
value_type = void_type(module);
},
else => else =>
{ {
@trap(); @trap();
@ -12756,7 +12770,7 @@ create_coerced_store = fn (module: &Module, source_value: &LLVMValue, source_typ
{ {
>field = &fields[i]; >field = &fields[i];
>gep = LLVMBuildStructGEP2(module.llvm.builder, source_type.llvm.abi, destination_value, @truncate(i), ""); >gep = LLVMBuildStructGEP2(module.llvm.builder, source_type.llvm.abi, destination_value, @truncate(i), field.name.pointer);
>field_value = LLVMBuildExtractValue(module.llvm.builder, source_value, @truncate(i), ""); >field_value = LLVMBuildExtractValue(module.llvm.builder, source_value, @truncate(i), "");
create_store(module, { create_store(module, {
@ -13194,7 +13208,7 @@ emit_call = fn (module: &Module, value: &Value, left_llvm: &LLVMValue, left_type
for (i: 0..coerce_fields.length) for (i: 0..coerce_fields.length)
{ {
>field = &coerce_fields[i]; >field = &coerce_fields[i];
>gep = LLVMBuildStructGEP2(module.llvm.builder, coerce_to_type.llvm.memory, source, @truncate(i), ""); >gep = LLVMBuildStructGEP2(module.llvm.builder, coerce_to_type.llvm.memory, source, @truncate(i), field.name.pointer);
>maybe_undef: u1 = 0; >maybe_undef: u1 = 0;
if (maybe_undef) if (maybe_undef)
{ {
@ -13242,8 +13256,8 @@ emit_call = fn (module: &Module, value: &Value, left_llvm: &LLVMValue, left_type
for (i: 0..coerce_fields.length) for (i: 0..coerce_fields.length)
{ {
>gep = LLVMBuildStructGEP2(module.llvm.builder, coerce_to_type.llvm.abi, global, @truncate(i), "");
>field = &coerce_fields[i]; >field = &coerce_fields[i];
>gep = LLVMBuildStructGEP2(module.llvm.builder, coerce_to_type.llvm.abi, global, @truncate(i), field.name.pointer);
>maybe_undef: u1 = 0; >maybe_undef: u1 = 0;
if (maybe_undef) if (maybe_undef)
@ -13710,6 +13724,7 @@ emit_field_access = fn (module: &Module, value: &Value, left_llvm: &LLVMValue, l
assert(result_field != zero); assert(result_field != zero);
>field_index: u32 = @truncate(result_field - fields.pointer); >field_index: u32 = @truncate(result_field - fields.pointer);
>field = &fields[field_index];
field_access = { field_access = {
.type = resolved_aggregate_type.content.struct.fields[field_index].type, .type = resolved_aggregate_type.content.struct.fields[field_index].type,
@ -13746,7 +13761,7 @@ emit_field_access = fn (module: &Module, value: &Value, left_llvm: &LLVMValue, l
else => { unreachable; }, else => { unreachable; },
} }
>gep = LLVMBuildStructGEP2(module.llvm.builder, field_access.struct_type, v, field_access.field_index, ""); >gep = LLVMBuildStructGEP2(module.llvm.builder, field_access.struct_type, v, field_access.field_index, field_name.pointer);
if (left_llvm) if (left_llvm)
{ {
@ -14009,7 +14024,7 @@ emit_va_arg_from_memory = fn (module: &Module, va_list_pointer: &LLVMValue, va_l
{ {
assert(va_list_struct.id == .struct); assert(va_list_struct.id == .struct);
>overflow_arg_area_pointer = LLVMBuildStructGEP2(module.llvm.builder, va_list_struct.llvm.abi, va_list_pointer, 2, ""); >overflow_arg_area_pointer = LLVMBuildStructGEP2(module.llvm.builder, va_list_struct.llvm.abi, va_list_pointer, 2, "overflow_arg_area");
>overflow_arg_area_type = va_list_struct.content.struct.fields[2].type; >overflow_arg_area_type = va_list_struct.content.struct.fields[2].type;
>overflow_arg_area = create_load(module, { >overflow_arg_area = create_load(module, {
.type = overflow_arg_area_type, .type = overflow_arg_area_type,
@ -14102,7 +14117,7 @@ emit_va_arg = fn (module: &Module, value: &Value, left_llvm: &LLVMValue, left_ty
if (needed_registers.gpr != 0) if (needed_registers.gpr != 0)
{ {
gpr_offset_pointer = LLVMBuildStructGEP2(module.llvm.builder, va_list_struct_llvm, va_list_value_llvm, 0, ""); gpr_offset_pointer = LLVMBuildStructGEP2(module.llvm.builder, va_list_struct_llvm, va_list_value_llvm, 0, "gpr_offset");
gpr_offset = create_load(module, { gpr_offset = create_load(module, {
.type = va_list_struct.content.struct.fields[0].type, .type = va_list_struct.content.struct.fields[0].type,
.pointer = gpr_offset_pointer, .pointer = gpr_offset_pointer,
@ -14176,7 +14191,7 @@ emit_va_arg = fn (module: &Module, value: &Value, left_llvm: &LLVMValue, left_ty
>reg_save_area_type = va_list_struct.content.struct.fields[3].type; >reg_save_area_type = va_list_struct.content.struct.fields[3].type;
>reg_save_area = create_load(module, { >reg_save_area = create_load(module, {
.type = reg_save_area_type, .type = reg_save_area_type,
.pointer = LLVMBuildStructGEP2(module.llvm.builder, va_list_struct_llvm, va_list_value_llvm, 3, ""), .pointer = LLVMBuildStructGEP2(module.llvm.builder, va_list_struct_llvm, va_list_value_llvm, 3, "reg_save_area"),
.alignment = 16, .alignment = 16,
zero, zero,
}); });
@ -15600,6 +15615,11 @@ emit_value = fn (module: &Module, value: &Value, type_kind: TypeKind, expect_con
{ {
llvm_value = LLVMConstInt(get_llvm_type(resolved_value_type, type_kind), @extend(module.has_debug_info), 0); llvm_value = LLVMConstInt(get_llvm_type(resolved_value_type, type_kind), @extend(module.has_debug_info), 0);
}, },
.breakpoint =>
{
>call = emit_intrinsic_call(module, ."llvm.debugtrap", zero, zero);
llvm_value = call;
},
else => else =>
{ {
@trap(); @trap();
@ -15712,11 +15732,12 @@ emit_assignment = fn (module: &Module, left_llvm: &LLVMValue, left_type: &Type,
{ {
>string_literal = emit_string_literal(module, right); >string_literal = emit_string_literal(module, right);
>slice_type = get_slice_type(module, uint8(module)); >slice_type = get_slice_type(module, uint8(module));
>slice_fields = slice_type.content.struct.fields;
for (i: 0..string_literal.length) for (i: 0..string_literal.length)
{ {
>member_pointer = LLVMBuildStructGEP2(module.llvm.builder, slice_type.llvm.abi, left_llvm, @truncate(i), ""); >slice_field = &slice_fields[i];
>slice_member_type = slice_type.content.struct.fields[i].type; >member_pointer = LLVMBuildStructGEP2(module.llvm.builder, slice_type.llvm.abi, left_llvm, @truncate(i), slice_field.name.pointer);
>slice_member_type = slice_field.type;
create_store(module, { create_store(module, {
.source = string_literal[i], .source = string_literal[i],
.destination = member_pointer, .destination = member_pointer,
@ -15815,7 +15836,7 @@ emit_assignment = fn (module: &Module, left_llvm: &LLVMValue, left_type: &Type,
>field = &fields[declaration_index]; >field = &fields[declaration_index];
>destination_pointer = LLVMBuildStructGEP2(module.llvm.builder, resolved_value_type.llvm.memory, left_llvm, @truncate(declaration_index), ""); >destination_pointer = LLVMBuildStructGEP2(module.llvm.builder, resolved_value_type.llvm.memory, left_llvm, @truncate(declaration_index), field.name.pointer);
emit_assignment(module, destination_pointer, get_pointer_type(module, field.type), value); emit_assignment(module, destination_pointer, get_pointer_type(module, field.type), value);
} }
@ -15887,7 +15908,7 @@ emit_assignment = fn (module: &Module, left_llvm: &LLVMValue, left_type: &Type,
zero, zero,
}); });
>slice_length_destination = LLVMBuildStructGEP2(module.llvm.builder, resolved_value_type.llvm.abi, left_llvm, 1, ""); >slice_length_destination = LLVMBuildStructGEP2(module.llvm.builder, resolved_value_type.llvm.abi, left_llvm, 1, "length");
create_store(module, { create_store(module, {
.source = slice_values[1], .source = slice_values[1],
.destination = slice_length_destination, .destination = slice_length_destination,
@ -17840,7 +17861,7 @@ emit = fn (module: &Module) void
for (i: 0..fields.length) for (i: 0..fields.length)
{ {
>field = &fields[i]; >field = &fields[i];
>gep = LLVMBuildStructGEP2(module.llvm.builder, coerce_to_type.llvm.abi, address, @truncate(i), ""); >gep = LLVMBuildStructGEP2(module.llvm.builder, coerce_to_type.llvm.abi, address, @truncate(i), field.name.pointer);
create_store(module, { create_store(module, {
.source = argument_abi_arguments[i], .source = argument_abi_arguments[i],
.destination = gep, .destination = gep,

View File

@ -2061,6 +2061,74 @@ pointer_sub = fn () void
require(sub == 1); require(sub == 1);
} }
breakpoint = fn () void
{
>ok: u1 = 1;
if (!ok)
{
@breakpoint();
}
}
CPUArchitecture = enum
{
x86_64,
}
OperatingSystem = enum
{
linux,
}
Target = struct
{
cpu: CPUArchitecture,
os: OperatingSystem,
host_cpu_model: u1,
}
target_get_native = fn [cc(c)] (host_cpu_model: u1) Target
{
return {
.cpu = .x86_64,
.os = .linux,
.host_cpu_model = host_cpu_model,
};
}
StructArbitraryIntAbiContainer = struct
{
a: u8,
b: u8,
c: Target,
d: u8,
e: u8
f: u8,
g: u8,
}
struct_arbitrary_int_abi = fn () void
{
>some_struct: StructArbitraryIntAbiContainer = {
.f = 45,
.g = 46,
.e = 123,
.d = 231,
.c = target_get_native(0),
.a = 123,
.b = 231,
};
require(some_struct.a == 123);
require(some_struct.b == 231);
require(some_struct.c.cpu == .x86_64);
require(some_struct.c.os == .linux);
require(!some_struct.c.host_cpu_model);
require(some_struct.d == 231);
require(some_struct.e == 123);
require(some_struct.f == 45);
require(some_struct.g == 46);
[export] main = fn [cc(c)] (argc: s32, argv: &&u8, envp: &&u8) s32 [export] main = fn [cc(c)] (argc: s32, argv: &&u8, envp: &&u8) s32
{ {
>rc = return_constant(); >rc = return_constant();
@ -2324,5 +2392,9 @@ pointer_sub = fn () void
pointer_sub(); pointer_sub();
breakpoint();
struct_arbitrary_int_abi();
return 0; return 0;
} }