c variadic calls
This commit is contained in:
+63
-7
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user