aboutsummaryrefslogtreecommitdiff
path: root/src/codegen/llvm.zig
diff options
context:
space:
mode:
authorAndrew Kelley <andrew@ziglang.org>2022-12-18 16:24:13 -0500
committerGitHub <noreply@github.com>2022-12-18 16:24:13 -0500
commitaca9c74e80e106309b9783ff251ab0cdd3fb9626 (patch)
tree16c65995ac6d3b434af61c4cd61a191b81dd93a0 /src/codegen/llvm.zig
parentd93edadead45e447e6bc16c0934a3031a06d0fd8 (diff)
parent9bb1104e373dec192fb2a22d48b023330ddbaeae (diff)
downloadzig-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.zig93
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(), &param_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(), &param_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(), &param_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);