From 9bb1104e373dec192fb2a22d48b023330ddbaeae Mon Sep 17 00:00:00 2001 From: Veikka Tuominen Date: Tue, 13 Dec 2022 00:14:54 +0200 Subject: implement defining C variadic functions --- src/codegen/c.zig | 5 +++ src/codegen/llvm.zig | 93 +++++++++++++++++++++++++++++++++++++++++++ src/codegen/llvm/bindings.zig | 3 ++ 3 files changed, 101 insertions(+) (limited to 'src/codegen') diff --git a/src/codegen/c.zig b/src/codegen/c.zig index 97f67d3eec..a7a2b2cf2a 100644 --- a/src/codegen/c.zig +++ b/src/codegen/c.zig @@ -2909,6 +2909,11 @@ fn genBodyInner(f: *Function, body: []const Air.Inst.Index) error{ AnalysisFail, .is_named_enum_value => return f.fail("TODO: C backend: implement is_named_enum_value", .{}), .error_set_has_value => return f.fail("TODO: C backend: implement error_set_has_value", .{}), .vector_store_elem => return f.fail("TODO: C backend: implement vector_store_elem", .{}), + + .c_va_arg => return f.fail("TODO implement c_va_arg", .{}), + .c_va_copy => return f.fail("TODO implement c_va_copy", .{}), + .c_va_end => return f.fail("TODO implement c_va_end", .{}), + .c_va_start => return f.fail("TODO implement c_va_start", .{}), // zig fmt: on }; if (result_value == .local) { diff --git a/src/codegen/llvm.zig b/src/codegen/llvm.zig index cd9ef98e44..7af987f4d6 100644 --- a/src/codegen/llvm.zig +++ b/src/codegen/llvm.zig @@ -4699,6 +4699,11 @@ pub const FuncGen = struct { .dbg_block_end => try self.airDbgBlockEnd(), .dbg_var_ptr => try self.airDbgVarPtr(inst), .dbg_var_val => try self.airDbgVarVal(inst), + + .c_va_arg => try self.airCVaArg(inst), + .c_va_copy => try self.airCVaCopy(inst), + .c_va_end => try self.airCVaEnd(inst), + .c_va_start => try self.airCVaStart(inst), // zig fmt: on }; if (opt_value) |val| { @@ -5136,6 +5141,94 @@ pub const FuncGen = struct { return null; } + fn airCVaArg(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value { + if (self.liveness.isUnused(inst)) return null; + + const ty_op = self.air.instructions.items(.data)[inst].ty_op; + const list = try self.resolveInst(ty_op.operand); + const arg_ty = self.air.getRefType(ty_op.ty); + const llvm_arg_ty = try self.dg.lowerType(arg_ty); + + return self.builder.buildVAArg(list, llvm_arg_ty, ""); + } + + fn airCVaCopy(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value { + if (self.liveness.isUnused(inst)) return null; + + const ty_op = self.air.instructions.items(.data)[inst].ty_op; + const src_list = try self.resolveInst(ty_op.operand); + const va_list_ty = self.air.getRefType(ty_op.ty); + const llvm_va_list_ty = try self.dg.lowerType(va_list_ty); + + const target = self.dg.module.getTarget(); + const result_alignment = va_list_ty.abiAlignment(target); + const dest_list = self.buildAlloca(llvm_va_list_ty, result_alignment); + + const llvm_fn_name = "llvm.va_copy"; + const llvm_fn = self.dg.object.llvm_module.getNamedFunction(llvm_fn_name) orelse blk: { + const param_types = [_]*llvm.Type{ + self.dg.context.intType(8).pointerType(0), + self.dg.context.intType(8).pointerType(0), + }; + const fn_type = llvm.functionType(self.context.voidType(), ¶m_types, param_types.len, .False); + break :blk self.dg.object.llvm_module.addFunction(llvm_fn_name, fn_type); + }; + + const args: [2]*llvm.Value = .{ dest_list, src_list }; + _ = self.builder.buildCall(llvm_fn.globalGetValueType(), llvm_fn, &args, args.len, .Fast, .Auto, ""); + + if (isByRef(va_list_ty)) { + return dest_list; + } else { + const loaded = self.builder.buildLoad(llvm_va_list_ty, dest_list, ""); + loaded.setAlignment(result_alignment); + return loaded; + } + } + + fn airCVaEnd(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value { + const un_op = self.air.instructions.items(.data)[inst].un_op; + const list = try self.resolveInst(un_op); + + const llvm_fn_name = "llvm.va_end"; + const llvm_fn = self.dg.object.llvm_module.getNamedFunction(llvm_fn_name) orelse blk: { + const param_types = [_]*llvm.Type{self.dg.context.intType(8).pointerType(0)}; + const fn_type = llvm.functionType(self.context.voidType(), ¶m_types, param_types.len, .False); + break :blk self.dg.object.llvm_module.addFunction(llvm_fn_name, fn_type); + }; + const args: [1]*llvm.Value = .{list}; + _ = self.builder.buildCall(llvm_fn.globalGetValueType(), llvm_fn, &args, args.len, .Fast, .Auto, ""); + return null; + } + + fn airCVaStart(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value { + if (self.liveness.isUnused(inst)) return null; + + const va_list_ty = self.air.typeOfIndex(inst); + const llvm_va_list_ty = try self.dg.lowerType(va_list_ty); + + const target = self.dg.module.getTarget(); + const result_alignment = va_list_ty.abiAlignment(target); + const list = self.buildAlloca(llvm_va_list_ty, result_alignment); + + const llvm_fn_name = "llvm.va_start"; + const llvm_fn = self.dg.object.llvm_module.getNamedFunction(llvm_fn_name) orelse blk: { + const param_types = [_]*llvm.Type{self.dg.context.intType(8).pointerType(0)}; + const fn_type = llvm.functionType(self.context.voidType(), ¶m_types, param_types.len, .False); + break :blk self.dg.object.llvm_module.addFunction(llvm_fn_name, fn_type); + }; + const args: [1]*llvm.Value = .{list}; + _ = self.builder.buildCall(llvm_fn.globalGetValueType(), llvm_fn, &args, args.len, .Fast, .Auto, ""); + + if (isByRef(va_list_ty)) { + return list; + } else { + const loaded = self.builder.buildLoad(llvm_va_list_ty, list, ""); + loaded.setAlignment(result_alignment); + return loaded; + } + } + fn airCmp(self: *FuncGen, inst: Air.Inst.Index, op: math.CompareOperator, want_fast_math: bool) !?*llvm.Value { if (self.liveness.isUnused(inst)) return null; self.builder.setFastMath(want_fast_math); diff --git a/src/codegen/llvm/bindings.zig b/src/codegen/llvm/bindings.zig index 90d0f51c7b..fc12b4a8c1 100644 --- a/src/codegen/llvm/bindings.zig +++ b/src/codegen/llvm/bindings.zig @@ -965,6 +965,9 @@ pub const Builder = opaque { pub const buildAllocaInAddressSpace = ZigLLVMBuildAllocaInAddressSpace; extern fn ZigLLVMBuildAllocaInAddressSpace(B: *Builder, Ty: *Type, AddressSpace: c_uint, Name: [*:0]const u8) *Value; + + pub const buildVAArg = LLVMBuildVAArg; + extern fn LLVMBuildVAArg(*Builder, List: *Value, Ty: *Type, Name: [*:0]const u8) *Value; }; pub const MDString = opaque { -- cgit v1.2.3