c variadic calls

This commit is contained in:
2026-06-14 15:53:45 +02:00
parent 638ca57f5c
commit 2d3d0bd266
21 changed files with 409 additions and 35 deletions
+63 -7
View File
@@ -112,7 +112,7 @@ 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, .Weaken_Pointer, .Neg_Checked, .Add_Checked, .Pointer_Add, .Call:
.Widen, .C_Vararg_Promote, .Weaken_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:
@@ -275,14 +275,16 @@ emit_call_args :: proc(
if index > 0 {
strings.write_string(builder, ", ")
}
fmt.sbprintf(builder, "%s ", llvm_type(param_types[index], store))
if c_abi {
extension := c_abi_extension(param_types[index], store.selected)
arg_type := param_types[index] if index < len(param_types) && valid_instruction(instructions, arg) else
(instructions[arg].type if valid_instruction(instructions, arg) else types.INVALID)
fmt.sbprintf(builder, "%s ", llvm_type(arg_type, store))
if c_abi && index < len(param_types) {
extension := c_abi_extension(arg_type, store.selected)
if len(extension) > 0 {
fmt.sbprintf(builder, "%s ", extension)
}
}
write_operand(builder, instructions, arg, param_types[index], store)
write_operand(builder, instructions, arg, arg_type, store)
}
}
@@ -707,6 +709,31 @@ emit_instruction_stream :: proc(
fmt.sbprintf(&emitter.builder, " %%v%d = %s %s ", instruction_index, operation, llvm_type(from_type, &emitter.module.types))
write_operand(&emitter.builder, instructions, instruction.a, from_type, &emitter.module.types)
fmt.sbprintf(&emitter.builder, " to %s\n", llvm_type(instruction.type, &emitter.module.types))
case .C_Vararg_Promote:
if !valid_instruction(instructions, instruction.a) {
emit_recovery_value(emitter, instruction_index, instruction, "invalid C variadic promotion operand")
continue
}
from_type := instructions[instruction.a].type
if types.equal(from_type, instruction.type) ||
!types.equal(types.c_vararg_promotion(from_type, emitter.module.target), instruction.type) {
emit_recovery_value(emitter, instruction_index, instruction, "invalid C variadic promotion operand")
continue
}
if types.bits(from_type, emitter.module.target) == types.bits(instruction.type, emitter.module.target) {
type_name := llvm_type(instruction.type, &emitter.module.types)
fmt.sbprintf(&emitter.builder, " %%v%d = select i1 true, %s ", instruction_index, type_name)
write_operand(&emitter.builder, instructions, instruction.a, from_type, &emitter.module.types)
fmt.sbprintf(&emitter.builder, ", %s ", type_name)
write_operand(&emitter.builder, instructions, instruction.a, from_type, &emitter.module.types)
strings.write_string(&emitter.builder, "\n")
continue
}
operation := "fpext" if types.is_float(from_type, emitter.module.target) else
("sext" if types.is_signed(from_type, emitter.module.target) else "zext")
fmt.sbprintf(&emitter.builder, " %%v%d = %s %s ", instruction_index, operation, llvm_type(from_type, &emitter.module.types))
write_operand(&emitter.builder, instructions, instruction.a, from_type, &emitter.module.types)
fmt.sbprintf(&emitter.builder, " to %s\n", llvm_type(instruction.type, &emitter.module.types))
case .Weaken_Pointer:
if !valid_instruction(instructions, instruction.a) ||
!types.can_weaken_pointer(instructions[instruction.a].type, instruction.type, &emitter.module.types) {
@@ -806,10 +833,20 @@ emit_instruction_stream :: proc(
continue
}
target := emitter.module.functions[function_id]
valid_args := len(instruction.args) == len(target.param_types)
valid_args := (len(instruction.args) >= len(target.param_types) if target.variadic else
len(instruction.args) == len(target.param_types)) &&
(!target.variadic || target.calling_convention == .C)
if valid_args {
for arg, index in instruction.args {
if !valid_value(instructions, arg, target.param_types[index], &emitter.module.types) {
expected := target.param_types[index] if index < len(target.param_types) && valid_instruction(instructions, arg) else
(instructions[arg].type if valid_instruction(instructions, arg) else types.INVALID)
if index >= len(target.param_types) &&
(!types.is_c_vararg_type(expected, &emitter.module.types) ||
!types.equal(types.c_vararg_promotion(expected, emitter.module.target), expected)) {
valid_args = false
break
}
if !valid_value(instructions, arg, expected, &emitter.module.types) {
valid_args = false
break
}
@@ -833,6 +870,19 @@ emit_instruction_stream :: proc(
strings.write_string(&emitter.builder, "fastcc ")
}
emit_function_result(&emitter.builder, target, &emitter.module.types)
if target.variadic {
strings.write_string(&emitter.builder, " (")
for param_type, index in target.param_types {
if index > 0 {
strings.write_string(&emitter.builder, ", ")
}
strings.write_string(&emitter.builder, llvm_type(param_type, &emitter.module.types))
}
if len(target.param_types) > 0 {
strings.write_string(&emitter.builder, ", ")
}
strings.write_string(&emitter.builder, "...)")
}
fmt.sbprintf(&emitter.builder, " @%s(", target.link_name)
emit_call_args(
&emitter.builder, instructions, instruction.args, target.param_types,
@@ -1037,6 +1087,12 @@ emit_functions :: proc(emitter: ^Emitter) {
fmt.sbprintf(&emitter.builder, " %%v%d", index)
}
}
if function.variadic {
if len(function.param_types) > 0 {
strings.write_string(&emitter.builder, ", ")
}
strings.write_string(&emitter.builder, "...")
}
if function.implementation == .Declaration {
strings.write_string(&emitter.builder, ")\n\n")
continue