compact compiler ids and spans to reduce memory usage

This commit is contained in:
2026-06-12 16:55:16 +02:00
parent 99ba907f59
commit 4112b79c6b
16 changed files with 972 additions and 573 deletions
+46 -43
View File
@@ -49,11 +49,11 @@ sentinel :: proc(value_type: types.Type) -> i64 {
}
}
valid_instruction :: proc(instructions: []ir.Instruction, instruction_id: int) -> bool {
return instruction_id >= 0 && instruction_id < len(instructions)
valid_instruction :: proc(instructions: []ir.Instruction, instruction_id: ir.Instruction_Id) -> bool {
return instruction_id != ir.INVALID_INSTRUCTION && int(instruction_id) < len(instructions)
}
valid_value :: proc(instructions: []ir.Instruction, value_id: int, expected: types.Type) -> bool {
valid_value :: proc(instructions: []ir.Instruction, value_id: ir.Instruction_Id, expected: types.Type) -> bool {
if !valid_instruction(instructions, value_id) ||
!types.is_concrete_integer(expected) ||
!types.equal(instructions[value_id].type, expected) {
@@ -68,7 +68,7 @@ valid_value :: proc(instructions: []ir.Instruction, value_id: int, expected: typ
return false
}
write_operand :: proc(builder: ^strings.Builder, instructions: []ir.Instruction, value_id: int, expected: types.Type) {
write_operand :: proc(builder: ^strings.Builder, instructions: []ir.Instruction, value_id: ir.Instruction_Id, expected: types.Type) {
if !valid_value(instructions, value_id, expected) {
fmt.sbprintf(builder, "%d", sentinel(expected))
return
@@ -88,8 +88,8 @@ register_message :: proc(emitter: ^Emitter, text: string) -> int {
return id
}
diagnostic_message :: proc(emitter: ^Emitter, diagnostic: int, span: source.Span, fallback: string) -> int {
if diagnostic >= 0 && diagnostic < len(emitter.diagnostics.items) {
diagnostic_message :: proc(emitter: ^Emitter, diagnostic: source.Diagnostic_Id, span: source.Span, fallback: string) -> int {
if _, ok := source.diagnostic_index(diagnostic, len(emitter.diagnostics.items)); ok {
message := source.format(emitter.diagnostics, diagnostic, emitter.allocator)
id := register_message(emitter, message)
delete(message, emitter.allocator)
@@ -137,7 +137,7 @@ emit_recovery_value :: proc(emitter: ^Emitter, instruction_id: int, instruction:
}
}
emit_call_args :: proc(builder: ^strings.Builder, instructions: []ir.Instruction, args: []int, param_types: []types.Type) {
emit_call_args :: proc(builder: ^strings.Builder, instructions: []ir.Instruction, args: []ir.Instruction_Id, param_types: []types.Type) {
for arg, index in args {
if index > 0 {
strings.write_string(builder, ", ")
@@ -152,60 +152,62 @@ emit_instruction_stream :: proc(
instructions: []ir.Instruction,
function: ir.Function,
global_initializer := false,
) -> int {
return_value := -1
) -> ir.Instruction_Id {
return_value := ir.INVALID_INSTRUCTION
after_return := false
for instruction, instruction_id in instructions {
for instruction, instruction_index in instructions {
instruction_id := ir.instruction_id(instruction_index)
if after_return {
fmt.sbprintf(&emitter.builder, "recover_after_return_%d:\n", instruction_id)
fmt.sbprintf(&emitter.builder, "recover_after_return_%d:\n", instruction_index)
after_return = false
}
switch instruction.op {
case .Param, .Const:
case .Load_Global:
if instruction.target < 0 || instruction.target >= len(emitter.module.globals) {
emit_recovery_value(emitter, instruction_id, instruction, "invalid global reference")
global_id := ir.as_global(instruction.target)
if global_id == ir.INVALID_GLOBAL || int(global_id) >= len(emitter.module.globals) {
emit_recovery_value(emitter, instruction_index, instruction, "invalid global reference")
continue
}
global := emitter.module.globals[instruction.target]
global := emitter.module.globals[global_id]
if !types.equal(instruction.type, global.type) {
emit_recovery_value(emitter, instruction_id, instruction, "invalid global reference type")
emit_recovery_value(emitter, instruction_index, instruction, "invalid global reference type")
continue
}
if global.is_static {
fmt.sbprintf(
&emitter.builder,
" %%v%d = load %s, ptr @bro.g.%d\n",
instruction_id,
instruction_index,
llvm_type(global.type),
instruction.target,
global_id,
)
} else {
fmt.sbprintf(
&emitter.builder,
" %%v%d = call %s @bro.get.%d()\n",
instruction_id,
instruction_index,
llvm_type(global.type),
instruction.target,
global_id,
)
}
case .Alloca:
if !types.is_concrete_integer(instruction.type) {
emit_recovery_value(emitter, instruction_id, instruction, "invalid allocation type")
emit_recovery_value(emitter, instruction_index, instruction, "invalid allocation type")
continue
}
fmt.sbprintf(&emitter.builder, " %%v%d = alloca %s\n", instruction_id, llvm_type(instruction.type))
fmt.sbprintf(&emitter.builder, " %%v%d = alloca %s\n", instruction_index, llvm_type(instruction.type))
case .Load:
if !valid_instruction(instructions, instruction.a) ||
instructions[instruction.a].op != .Alloca ||
!types.equal(instructions[instruction.a].type, instruction.type) {
emit_recovery_value(emitter, instruction_id, instruction, "invalid load slot")
emit_recovery_value(emitter, instruction_index, instruction, "invalid load slot")
continue
}
fmt.sbprintf(
&emitter.builder,
" %%v%d = load %s, ptr %%v%d\n",
instruction_id,
instruction_index,
llvm_type(instruction.type),
instruction.a,
)
@@ -214,7 +216,7 @@ emit_instruction_stream :: proc(
instructions[instruction.a].op != .Alloca ||
!types.equal(instructions[instruction.a].type, instruction.type) ||
!valid_value(instructions, instruction.b, instruction.type) {
emit_recovery_value(emitter, instruction_id, instruction, "invalid store operand")
emit_recovery_value(emitter, instruction_index, instruction, "invalid store operand")
continue
}
fmt.sbprintf(&emitter.builder, " store %s ", llvm_type(instruction.type))
@@ -225,50 +227,51 @@ emit_instruction_stream :: proc(
!types.is_concrete_integer(instructions[instruction.a].type) ||
!types.is_concrete_integer(instruction.type) ||
instructions[instruction.a].type.bits >= instruction.type.bits {
emit_recovery_value(emitter, instruction_id, instruction, "invalid widening operand")
emit_recovery_value(emitter, instruction_index, instruction, "invalid widening operand")
continue
}
from_type := instructions[instruction.a].type
fmt.sbprintf(&emitter.builder, " %%v%d = sext %s ", instruction_id, llvm_type(from_type))
fmt.sbprintf(&emitter.builder, " %%v%d = sext %s ", instruction_index, llvm_type(from_type))
write_operand(&emitter.builder, instructions, instruction.a, from_type)
fmt.sbprintf(&emitter.builder, " to %s\n", llvm_type(instruction.type))
case .Add_Checked:
if !valid_value(instructions, instruction.a, instruction.type) ||
!valid_value(instructions, instruction.b, instruction.type) {
emit_recovery_value(emitter, instruction_id, instruction, "invalid addition operand")
emit_recovery_value(emitter, instruction_index, instruction, "invalid addition operand")
continue
}
type_name := llvm_type(instruction.type)
fmt.sbprintf(&emitter.builder, " %%pair%d = call ", instruction_id)
fmt.sbprintf(&emitter.builder, " %%pair%d = call ", instruction_index)
strings.write_string(&emitter.builder, "{ ")
fmt.sbprintf(&emitter.builder, "%s, i1 } @llvm.sadd.with.overflow.%s(%s ", type_name, type_name, type_name)
write_operand(&emitter.builder, instructions, instruction.a, instruction.type)
fmt.sbprintf(&emitter.builder, ", %s ", type_name)
write_operand(&emitter.builder, instructions, instruction.b, instruction.type)
fmt.sbprintf(&emitter.builder, ")\n")
fmt.sbprintf(&emitter.builder, " %%v%d = extractvalue ", instruction_id)
fmt.sbprintf(&emitter.builder, " %%v%d = extractvalue ", instruction_index)
strings.write_string(&emitter.builder, "{ ")
fmt.sbprintf(&emitter.builder, "%s, i1 } %%pair%d, 0\n", type_name, instruction_id)
fmt.sbprintf(&emitter.builder, " %%overflow%d = extractvalue ", instruction_id)
fmt.sbprintf(&emitter.builder, "%s, i1 } %%pair%d, 0\n", type_name, instruction_index)
fmt.sbprintf(&emitter.builder, " %%overflow%d = extractvalue ", instruction_index)
strings.write_string(&emitter.builder, "{ ")
fmt.sbprintf(&emitter.builder, "%s, i1 } %%pair%d, 1\n", type_name, instruction_id)
fmt.sbprintf(&emitter.builder, "%s, i1 } %%pair%d, 1\n", type_name, instruction_index)
fmt.sbprintf(
&emitter.builder,
" br i1 %%overflow%d, label %%overflow_trap%d, label %%overflow_continue%d\n",
instruction_id,
instruction_id,
instruction_id,
instruction_index,
instruction_index,
instruction_index,
)
fmt.sbprintf(&emitter.builder, "overflow_trap%d:\n", instruction_id)
message := diagnostic_message(emitter, -1, instruction.span, "signed integer addition overflow")
fmt.sbprintf(&emitter.builder, "overflow_trap%d:\n", instruction_index)
message := diagnostic_message(emitter, source.INVALID_DIAGNOSTIC, instruction.span, "signed integer addition overflow")
emit_trap_call(emitter, message)
fmt.sbprintf(&emitter.builder, " unreachable\noverflow_continue%d:\n", instruction_id)
fmt.sbprintf(&emitter.builder, " unreachable\noverflow_continue%d:\n", instruction_index)
case .Call:
if instruction.target < 0 || instruction.target >= len(emitter.module.functions) {
emit_recovery_value(emitter, instruction_id, instruction, "invalid function specialization")
function_id := ir.as_function(instruction.target)
if function_id == ir.INVALID_FUNCTION || int(function_id) >= len(emitter.module.functions) {
emit_recovery_value(emitter, instruction_index, instruction, "invalid function specialization")
continue
}
target := emitter.module.functions[instruction.target]
target := emitter.module.functions[function_id]
valid_args := len(instruction.args) == len(target.param_types)
if valid_args {
for arg, index in instruction.args {
@@ -283,11 +286,11 @@ emit_instruction_stream :: proc(
target_result = types.I32
}
if !valid_args || !types.equal(instruction.type, target_result) {
emit_recovery_value(emitter, instruction_id, instruction, "invalid function call operands")
emit_recovery_value(emitter, instruction_index, instruction, "invalid function call operands")
continue
}
if instruction.type.kind != .Void {
fmt.sbprintf(&emitter.builder, " %%v%d = ", instruction_id)
fmt.sbprintf(&emitter.builder, " %%v%d = ", instruction_index)
} else {
strings.write_string(&emitter.builder, " ")
}