feat: support checked explicit sentinel slices
This commit is contained in:
+18
-1
@@ -1556,6 +1556,11 @@ emit_instruction_stream :: proc(
|
||||
emit_recovery_value(emitter, instruction_index, instruction, "invalid slice container")
|
||||
continue
|
||||
}
|
||||
check_sentinel := instruction.b != ir.INVALID_INSTRUCTION
|
||||
if check_sentinel && !valid_value(instructions, instruction.b, item.child, &emitter.module.types) {
|
||||
emit_recovery_value(emitter, instruction_index, instruction, "invalid slice sentinel")
|
||||
continue
|
||||
}
|
||||
pointer_name := fmt.tprintf("%%v%d", instruction.a)
|
||||
length_name := fmt.tprintf("%d", item.count)
|
||||
if item.kind == .Array {
|
||||
@@ -1597,13 +1602,25 @@ emit_instruction_stream :: proc(
|
||||
if item.kind == .Pointer {
|
||||
fmt.sbprintf(&emitter.builder, " %%slice_ok%d = or i1 false, %%slice_order%d\n", instruction_index, instruction_index)
|
||||
} else {
|
||||
fmt.sbprintf(&emitter.builder, " %%slice_end_ok%d = icmp ule i64 %s, %s\n", instruction_index, end_name, length_name)
|
||||
comparison := "ult" if check_sentinel && !item.has_sentinel else "ule"
|
||||
fmt.sbprintf(&emitter.builder, " %%slice_end_ok%d = icmp %s i64 %s, %s\n", instruction_index, comparison, end_name, length_name)
|
||||
fmt.sbprintf(&emitter.builder, " %%slice_ok%d = and i1 %%slice_order%d, %%slice_end_ok%d\n", instruction_index, instruction_index, instruction_index)
|
||||
}
|
||||
fmt.sbprintf(&emitter.builder, " br i1 %%slice_ok%d, label %%slice_continue%d, label %%slice_trap%d\nslice_trap%d:\n", instruction_index, instruction_index, instruction_index, instruction_index)
|
||||
message := diagnostic_message(emitter, source.INVALID_DIAGNOSTIC, instruction.span, "slice bounds out of range")
|
||||
emit_trap_call(emitter, message)
|
||||
fmt.sbprintf(&emitter.builder, " unreachable\nslice_continue%d:\n", instruction_index)
|
||||
if check_sentinel {
|
||||
element_type := llvm_type(item.child, &emitter.module.types)
|
||||
fmt.sbprintf(&emitter.builder, " %%slice_sentinel_ptr%d = getelementptr %s, ptr %s, i64 %s\n", instruction_index, element_type, pointer_name, end_name)
|
||||
fmt.sbprintf(&emitter.builder, " %%slice_sentinel_value%d = load %s, ptr %%slice_sentinel_ptr%d\n", instruction_index, element_type, instruction_index)
|
||||
fmt.sbprintf(&emitter.builder, " %%slice_sentinel_ok%d = icmp eq %s %%slice_sentinel_value%d, ", instruction_index, element_type, instruction_index)
|
||||
write_operand(&emitter.builder, instructions, instruction.b, item.child, &emitter.module.types)
|
||||
fmt.sbprintf(&emitter.builder, "\n br i1 %%slice_sentinel_ok%d, label %%slice_sentinel_continue%d, label %%slice_sentinel_trap%d\nslice_sentinel_trap%d:\n", instruction_index, instruction_index, instruction_index, instruction_index)
|
||||
sentinel_message := diagnostic_message(emitter, source.INVALID_DIAGNOSTIC, instruction.span, "slice sentinel mismatch")
|
||||
emit_trap_call(emitter, sentinel_message)
|
||||
fmt.sbprintf(&emitter.builder, " unreachable\nslice_sentinel_continue%d:\n", instruction_index)
|
||||
}
|
||||
fmt.sbprintf(&emitter.builder, " %%slice_start%d = getelementptr %s, ptr %s, i64 %s\n", instruction_index, llvm_type(item.child, &emitter.module.types), pointer_name, start_name)
|
||||
fmt.sbprintf(&emitter.builder, " %%slice_result%d = insertvalue %s poison, ptr %%slice_start%d, 0\n", instruction_index, llvm_type(instruction.type, &emitter.module.types), instruction_index)
|
||||
fmt.sbprintf(&emitter.builder, " %%slice_result_len%d = sub i64 %s, %s\n", instruction_index, end_name, start_name)
|
||||
|
||||
Reference in New Issue
Block a user