diff options
| author | Andrew Kelley <andrew@ziglang.org> | 2022-12-18 16:24:13 -0500 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2022-12-18 16:24:13 -0500 |
| commit | aca9c74e80e106309b9783ff251ab0cdd3fb9626 (patch) | |
| tree | 16c65995ac6d3b434af61c4cd61a191b81dd93a0 /src/codegen/llvm.zig | |
| parent | d93edadead45e447e6bc16c0934a3031a06d0fd8 (diff) | |
| parent | 9bb1104e373dec192fb2a22d48b023330ddbaeae (diff) | |
| download | zig-aca9c74e80e106309b9783ff251ab0cdd3fb9626.tar.gz zig-aca9c74e80e106309b9783ff251ab0cdd3fb9626.zip | |
Merge pull request #13914 from Vexu/variadic
implement defining C variadic functions
Diffstat (limited to 'src/codegen/llvm.zig')
| -rw-r--r-- | src/codegen/llvm.zig | 93 |
1 files changed, 93 insertions, 0 deletions
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); |
