sentinel pointers and c strings

This commit is contained in:
2026-06-14 19:21:49 +02:00
parent 2d3d0bd266
commit 3b7c3fcbd0
16 changed files with 512 additions and 55 deletions
+54 -14
View File
@@ -112,7 +112,8 @@ valid_value :: proc(
switch instructions[value_id].op {
case .Param, .Const, .String, .Aggregate, .None, .Optional_Some,
.Load_Global, .Address_Of, .Load, .Slice, .Length, .Slice_Ptr, .Unwrap, .Orelse,
.Widen, .C_Vararg_Promote, .Weaken_Pointer, .Neg_Checked, .Add_Checked, .Pointer_Add, .Call:
.Widen, .C_Vararg_Promote, .Weaken_Pointer, .Weaken_Slice, .Decay_Array_Pointer,
.Neg_Checked, .Add_Checked, .Pointer_Add, .Call:
return true
case .Address_Global, .Alloca, .Index_Address, .Field_Address, .Orelse_Begin,
.Store, .Trap, .Return, .Return_Void:
@@ -306,21 +307,17 @@ emit_instruction_stream :: proc(
case .Param, .Const:
case .String:
string_id := int(instruction.integer)
_, array, pointer_ok := types.array_pointer(instruction.type, &emitter.module.types)
if string_id < 0 || string_id >= len(emitter.module.strings) ||
!types.is_slice(instruction.type, &emitter.module.types) {
!pointer_ok || array.child != types.U8 || !array.has_sentinel ||
array.sentinel != 0 || array.count != u64(len(emitter.module.strings[string_id])) {
emit_recovery_value(emitter, instruction_index, instruction, "invalid string literal")
continue
}
type_name := llvm_type(instruction.type, &emitter.module.types)
fmt.sbprintf(
&emitter.builder,
" %%string_ptr%d = insertvalue %s poison, ptr @bro.str.%d, 0\n",
instruction_index, type_name, string_id,
)
fmt.sbprintf(
&emitter.builder,
" %%v%d = insertvalue %s %%string_ptr%d, i64 %d, 1\n",
instruction_index, type_name, instruction_index, len(emitter.module.strings[string_id]),
" %%v%d = getelementptr %s, ptr @bro.str.%d, i64 0\n",
instruction_index, llvm_type(types.child_type(instruction.type, &emitter.module.types), &emitter.module.types), string_id,
)
case .Aggregate:
item, ok := types.node(&emitter.module.types, instruction.type)
@@ -465,7 +462,7 @@ emit_instruction_stream :: proc(
continue
}
container := instructions[instruction.a]
container_node, container_ok := types.node(&emitter.module.types, container.type)
container_node, container_ok := types.container(container.type, &emitter.module.types)
if !container_ok {
emit_recovery_value(emitter, instruction_index, instruction, "invalid index container")
continue
@@ -504,7 +501,13 @@ emit_instruction_stream :: proc(
fmt.sbprintf(&emitter.builder, " unreachable\nindex_continue%d:\n", instruction_index)
}
if container_node.kind == .Array {
fmt.sbprintf(&emitter.builder, " %%v%d = getelementptr %s, ptr %s, i64 0, i64 ", instruction_index, llvm_type(container.type, &emitter.module.types), pointer_name)
array_type := container.type
_, array, array_pointer_ok := types.array_pointer(container.type, &emitter.module.types)
if array_pointer_ok {
array_type = types.child_type(container.type, &emitter.module.types)
container_node = array
}
fmt.sbprintf(&emitter.builder, " %%v%d = getelementptr %s, ptr %s, i64 0, i64 ", instruction_index, llvm_type(array_type, &emitter.module.types), pointer_name)
} else {
fmt.sbprintf(&emitter.builder, " %%v%d = getelementptr %s, ptr %s, i64 ", instruction_index, llvm_type(instruction.type, &emitter.module.types), pointer_name)
}
@@ -558,7 +561,7 @@ emit_instruction_stream :: proc(
continue
}
container := instructions[instruction.a]
item, ok := types.node(&emitter.module.types, container.type)
item, ok := types.container(container.type, &emitter.module.types)
if !ok || (item.kind != .Array && item.kind != .Slice) {
emit_recovery_value(emitter, instruction_index, instruction, "invalid slice container")
continue
@@ -566,7 +569,11 @@ emit_instruction_stream :: proc(
pointer_name := fmt.tprintf("%%v%d", instruction.a)
length_name := fmt.tprintf("%d", item.count)
if item.kind == .Array {
fmt.sbprintf(&emitter.builder, " %%slice_ptr%d = getelementptr %s, ptr %%v%d, i64 0, i64 0\n", instruction_index, llvm_type(container.type, &emitter.module.types), instruction.a)
array_type := container.type
if types.is_pointer(container.type, &emitter.module.types) {
array_type = types.child_type(container.type, &emitter.module.types)
}
fmt.sbprintf(&emitter.builder, " %%slice_ptr%d = getelementptr %s, ptr %%v%d, i64 0, i64 0\n", instruction_index, llvm_type(array_type, &emitter.module.types), instruction.a)
pointer_name = fmt.tprintf("%%slice_ptr%d", instruction_index)
} else if item.kind == .Slice {
fmt.sbprintf(&emitter.builder, " %%slice_ptr%d = extractvalue %s %%v%d, 0\n", instruction_index, llvm_type(container.type, &emitter.module.types), instruction.a)
@@ -621,12 +628,21 @@ emit_instruction_stream :: proc(
continue
}
container_type := instructions[instruction.a].type
_, _, array_pointer_ok := types.array_pointer(container_type, &emitter.module.types)
if types.is_array(container_type, &emitter.module.types) {
fmt.sbprintf(
&emitter.builder,
" %%v%d = getelementptr %s, ptr %%v%d, i64 0, i64 0\n",
instruction_index, llvm_type(container_type, &emitter.module.types), instruction.a,
)
} else if array_pointer_ok {
fmt.sbprintf(
&emitter.builder,
" %%v%d = getelementptr %s, ptr %%v%d, i64 0, i64 0\n",
instruction_index,
llvm_type(types.child_type(container_type, &emitter.module.types), &emitter.module.types),
instruction.a,
)
} else if types.is_slice(container_type, &emitter.module.types) {
fmt.sbprintf(
&emitter.builder,
@@ -741,6 +757,30 @@ emit_instruction_stream :: proc(
continue
}
fmt.sbprintf(&emitter.builder, " %%v%d = select i1 true, ptr %%v%d, ptr null\n", instruction_index, instruction.a)
case .Weaken_Slice:
if !valid_instruction(instructions, instruction.a) ||
!types.can_weaken_slice(instructions[instruction.a].type, instruction.type, &emitter.module.types) {
emit_recovery_value(emitter, instruction_index, instruction, "invalid slice weakening operand")
continue
}
type_name := llvm_type(instruction.type, &emitter.module.types)
fmt.sbprintf(&emitter.builder, " %%v%d = select i1 true, %s %%v%d, %s zeroinitializer\n", instruction_index, type_name, instruction.a, type_name)
case .Decay_Array_Pointer:
if !valid_instruction(instructions, instruction.a) ||
!types.can_decay_array_pointer(instructions[instruction.a].type, instruction.type, &emitter.module.types) {
emit_recovery_value(emitter, instruction_index, instruction, "invalid array pointer decay operand")
continue
}
array_type := types.child_type(instructions[instruction.a].type, &emitter.module.types)
array, _ := types.node(&emitter.module.types, array_type)
if types.is_pointer(instruction.type, &emitter.module.types) {
fmt.sbprintf(&emitter.builder, " %%v%d = getelementptr %s, ptr %%v%d, i64 0, i64 0\n", instruction_index, llvm_type(array_type, &emitter.module.types), instruction.a)
} else {
type_name := llvm_type(instruction.type, &emitter.module.types)
fmt.sbprintf(&emitter.builder, " %%decay_ptr%d = getelementptr %s, ptr %%v%d, i64 0, i64 0\n", instruction_index, llvm_type(array_type, &emitter.module.types), instruction.a)
fmt.sbprintf(&emitter.builder, " %%decay_slice%d = insertvalue %s poison, ptr %%decay_ptr%d, 0\n", instruction_index, type_name, instruction_index)
fmt.sbprintf(&emitter.builder, " %%v%d = insertvalue %s %%decay_slice%d, i64 %d, 1\n", instruction_index, type_name, instruction_index, array.count)
}
case .Neg_Checked:
if !valid_value(instructions, instruction.a, instruction.type, &emitter.module.types) {
emit_recovery_value(emitter, instruction_index, instruction, "invalid negation operand")