refactor: precompute compiler enum mappings
This commit is contained in:
@@ -1,7 +1,64 @@
|
||||
import "@std/io"
|
||||
import "@std/enummap"
|
||||
import "@source/ir"
|
||||
import "@source/diagnostics"
|
||||
|
||||
@hide:file
|
||||
bitwise_opcodes :: $enummap.init_filled(ir.Op, []u8, "", {
|
||||
bit_and = "and",
|
||||
bit_or = "or",
|
||||
bit_xor = "xor",
|
||||
})
|
||||
|
||||
@hide:file
|
||||
float_opcodes :: $enummap.init_filled(ir.Op, []u8, "", {
|
||||
add = "fadd",
|
||||
subtract = "fsub",
|
||||
multiply = "fmul",
|
||||
divide = "fdiv",
|
||||
})
|
||||
|
||||
@hide:file
|
||||
integer_opcodes :: $enummap.init_filled(ir.Op, []u8, "", {
|
||||
add = "add",
|
||||
subtract = "sub",
|
||||
multiply = "mul",
|
||||
})
|
||||
|
||||
@hide:file
|
||||
float_predicates :: $enummap.init_filled(ir.Op, []u8, "", {
|
||||
equal = "oeq",
|
||||
not_equal = "une",
|
||||
less = "olt",
|
||||
less_equal = "ole",
|
||||
greater = "ogt",
|
||||
greater_equal = "oge",
|
||||
})
|
||||
|
||||
@hide:file
|
||||
integer_predicates :: $enummap.init_filled(ir.Op, []u8, "", {
|
||||
equal = "eq",
|
||||
not_equal = "ne",
|
||||
less = "lt",
|
||||
less_equal = "le",
|
||||
greater = "gt",
|
||||
greater_equal = "ge",
|
||||
})
|
||||
|
||||
@hide:file
|
||||
conversion_upper_bounds :: $enummap.init_filled(ir.Type, []u8, "", {
|
||||
i8 = "1.280000e+02",
|
||||
i16 = "3.276800e+04",
|
||||
i32 = "2.147483648e+09",
|
||||
int = "9.223372036854775808e+18",
|
||||
isize = "9.223372036854775808e+18",
|
||||
u8 = "2.560000e+02",
|
||||
u16 = "6.553600e+04",
|
||||
u32 = "4.294967296e+09",
|
||||
u64 = "1.8446744073709551616e+19",
|
||||
usize = "1.8446744073709551616e+19",
|
||||
})
|
||||
|
||||
@hide
|
||||
emit_instruction proc(state @mut State, block @ir.Block, instruction ir.Instruction) void ! io.WriteError {
|
||||
output :: state.output
|
||||
@@ -311,12 +368,7 @@ emit_instruction proc(state @mut State, block @ir.Block, instruction ir.Instruct
|
||||
.bit_and, .bit_or, .bit_xor: {
|
||||
left :: try load(state, instruction.left)
|
||||
right :: try load(state, instruction.right)
|
||||
opcode []u8 :: match instruction.op {
|
||||
.bit_and: "and"
|
||||
.bit_or: "or"
|
||||
.bit_xor: "xor"
|
||||
else: unreachable
|
||||
}
|
||||
opcode :: enummap.get(&bitwise_opcodes, instruction.op)?
|
||||
try io.print(" %r{} = {s} i{} %r{}, %r{}\n", output, {result, opcode, ir.integer_bits(instruction.type), left, right})
|
||||
}
|
||||
.shift_left, .shift_right, .shift_left_saturating: result = try emit_shift(state, instruction)
|
||||
@@ -324,13 +376,7 @@ emit_instruction proc(state @mut State, block @ir.Block, instruction ir.Instruct
|
||||
left :: try load(state, instruction.left)
|
||||
right :: try load(state, instruction.right)
|
||||
if (instruction.type == .float) {
|
||||
opcode []u8 :: match instruction.op {
|
||||
.add: "fadd"
|
||||
.subtract: "fsub"
|
||||
.multiply: "fmul"
|
||||
.divide: "fdiv"
|
||||
else: unreachable
|
||||
}
|
||||
opcode :: enummap.get(&float_opcodes, instruction.op)?
|
||||
try io.print(" %r{} = {s} double %r{}, %r{}\n", output, {result, opcode, left, right})
|
||||
} else if (instruction.op == .divide) {
|
||||
bits :: ir.integer_bits(instruction.type)
|
||||
@@ -349,12 +395,7 @@ emit_instruction proc(state @mut State, block @ir.Block, instruction ir.Instruct
|
||||
opcode []u8 :: if (ir.unsigned_integer(instruction.type)) "udiv" else "sdiv"
|
||||
try io.print(" %r{} = {s} i{} %r{}, %r{}\n", output, {result, opcode, bits, left, right})
|
||||
} else {
|
||||
opcode []u8 :: match instruction.op {
|
||||
.add: "add"
|
||||
.subtract: "sub"
|
||||
.multiply: "mul"
|
||||
else: unreachable
|
||||
}
|
||||
opcode :: enummap.get(&integer_opcodes, instruction.op)?
|
||||
bits :: ir.integer_bits(instruction.type)
|
||||
sign []u8 :: if (ir.unsigned_integer(instruction.type)) "u" else "s"
|
||||
pair :: fresh(state)
|
||||
@@ -370,15 +411,7 @@ emit_instruction proc(state @mut State, block @ir.Block, instruction ir.Instruct
|
||||
right :: try load(state, instruction.right)
|
||||
operand_type :: state.values[usize(instruction.left)]
|
||||
if (operand_type.kind == .float) {
|
||||
predicate []u8 :: match instruction.op {
|
||||
.equal: "oeq"
|
||||
.not_equal: "une"
|
||||
.less: "olt"
|
||||
.less_equal: "ole"
|
||||
.greater: "ogt"
|
||||
.greater_equal: "oge"
|
||||
else: unreachable
|
||||
}
|
||||
predicate :: enummap.get(&float_predicates, instruction.op)?
|
||||
try io.print(" %r{} = fcmp {s} double %r{}, %r{}\n", output, {result, predicate, left, right})
|
||||
} else {
|
||||
prefix []u8 := ""
|
||||
@@ -386,15 +419,7 @@ emit_instruction proc(state @mut State, block @ir.Block, instruction ir.Instruct
|
||||
if (ir.unsigned_integer(operand_type.kind)) prefix = "u"
|
||||
else prefix = "s"
|
||||
}
|
||||
predicate []u8 :: match instruction.op {
|
||||
.equal: "eq"
|
||||
.not_equal: "ne"
|
||||
.less: "lt"
|
||||
.less_equal: "le"
|
||||
.greater: "gt"
|
||||
.greater_equal: "ge"
|
||||
else: unreachable
|
||||
}
|
||||
predicate :: enummap.get(&integer_predicates, instruction.op)?
|
||||
try io.print(" %r{} = icmp {s}{s} ", output, {result, prefix, predicate})
|
||||
try write_type(output, state.module, operand_type)
|
||||
try io.print(" %r{}, %r{}\n", output, {left, right})
|
||||
@@ -644,17 +669,7 @@ emit_conversion proc(state @mut State, instruction ir.Instruction) usize ! io.Wr
|
||||
upper_valid :: fresh(state)
|
||||
valid :: fresh(state)
|
||||
failed :: fresh(state)
|
||||
upper []u8 :: match destination {
|
||||
.i8: "1.280000e+02"
|
||||
.i16: "3.276800e+04"
|
||||
.i32: "2.147483648e+09"
|
||||
.int, .isize: "9.223372036854775808e+18"
|
||||
.u8: "2.560000e+02"
|
||||
.u16: "6.553600e+04"
|
||||
.u32: "4.294967296e+09"
|
||||
.u64, .usize: "1.8446744073709551616e+19"
|
||||
else: unreachable
|
||||
}
|
||||
upper :: enummap.get(&conversion_upper_bounds, destination)?
|
||||
try io.print(" %r{} = call double @llvm.trunc.f64(double %r{})\n", output, {truncated, operand})
|
||||
if (destination_unsigned) try io.print(" %r{} = fcmp oge double %r{}, 0.0\n", output, {lower_valid, truncated})
|
||||
else try io.print(" %r{} = fcmp oge double %r{}, -{s}\n", output, {lower_valid, truncated, upper})
|
||||
|
||||
+33
-23
@@ -211,13 +211,19 @@ write_type proc(output io.Writer, module @ir.Module, type Type) void ! io.WriteE
|
||||
}
|
||||
}
|
||||
|
||||
@hide:file
|
||||
abi_extensions :: $enummap.init_filled(ir.Type, []u8, "", {
|
||||
i8 = "signext",
|
||||
i16 = "signext",
|
||||
u8 = "zeroext",
|
||||
u16 = "zeroext",
|
||||
bool = "zeroext",
|
||||
})
|
||||
|
||||
@hide:file
|
||||
abi_extension proc(kind ir.Type) []u8 {
|
||||
return match kind {
|
||||
.i8, .i16: "signext"
|
||||
.u8, .u16, .bool: "zeroext"
|
||||
else: ""
|
||||
}
|
||||
if (enummap.get(&abi_extensions, kind)) |extension| return extension
|
||||
return ""
|
||||
}
|
||||
|
||||
@hide
|
||||
@@ -495,34 +501,38 @@ check_local proc(state @State, slot u32, read bool, span diagnostics.Span) void
|
||||
try io.print(" call void @check_init(ptr %i{}, i1 {}, i64 {}, i64 {}, i64 {})\n", state.output, {slot, read, usize(span.source), position.line, position.column})
|
||||
}
|
||||
|
||||
@hide:file
|
||||
memory_symbols :: $enummap.init_filled(diagnostics.Code, []u8, "", {
|
||||
null_unwrap = "null_unwrap",
|
||||
invalid_slice_bounds = "invalid_slice_bounds",
|
||||
sentinel_mismatch = "sentinel_mismatch",
|
||||
overlapping_memory_copy = "overlapping_memory_copy",
|
||||
unsupported_foreign_call = "unsupported_foreign_call",
|
||||
invalid_pointer_access = "invalid_pointer_access",
|
||||
division_by_zero = "division_by_zero",
|
||||
invalid_shift_count = "invalid_shift_count",
|
||||
})
|
||||
|
||||
@hide:file
|
||||
trap_symbols :: $enummap.init_filled(diagnostics.Code, []u8, "", {
|
||||
integer_overflow = "overflow",
|
||||
index_out_of_bounds = "bounds",
|
||||
inactive_union_field = "inactive_union",
|
||||
})
|
||||
|
||||
@hide:file
|
||||
memory_symbol proc(code diagnostics.Code) []u8 {
|
||||
return match code {
|
||||
.null_unwrap: "null_unwrap"
|
||||
.invalid_slice_bounds: "invalid_slice_bounds"
|
||||
.sentinel_mismatch: "sentinel_mismatch"
|
||||
.overlapping_memory_copy: "overlapping_memory_copy"
|
||||
.unsupported_foreign_call: "unsupported_foreign_call"
|
||||
.invalid_pointer_access: "invalid_pointer_access"
|
||||
.division_by_zero: "division_by_zero"
|
||||
.invalid_shift_count: "invalid_shift_count"
|
||||
else: unreachable
|
||||
}
|
||||
return enummap.get(&memory_symbols, code)?
|
||||
}
|
||||
|
||||
@hide:file
|
||||
trap proc(state @State, code diagnostics.Code, span diagnostics.Span) void ! io.WriteError {
|
||||
position :: location(state.line_starts, span)
|
||||
symbol []u8 :: match code {
|
||||
.integer_overflow: "overflow"
|
||||
.index_out_of_bounds: "bounds"
|
||||
.inactive_union_field: "inactive_union"
|
||||
else: ""
|
||||
}
|
||||
symbol :: enummap.get(&trap_symbols, code)
|
||||
message :: enummap.get(diagnostics.Code, []u8, &diagnostics.messages, code)?
|
||||
length :: message.len
|
||||
try io.print(" call void @trap(i64 -1, i64 {}, i64 {}, i64 {}, ptr @", state.output, {usize(span.source), position.line, position.column})
|
||||
if (symbol.len != 0) try io.write_all(state.output, symbol)
|
||||
if (symbol) |name| try io.write_all(state.output, name)
|
||||
else try io.print("memory_{s}", state.output, {memory_symbol(code)})
|
||||
try io.print(", i64 {})\n unreachable\n", state.output, {length})
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user