aboutsummaryrefslogtreecommitdiff
path: root/src/codegen
diff options
context:
space:
mode:
authorAndrew Kelley <andrew@ziglang.org>2022-07-12 23:30:26 -0700
committerAndrew Kelley <andrew@ziglang.org>2022-07-13 11:14:46 -0700
commit35e70111248f795fbdcefd5ae0d6fc494d1b0683 (patch)
treef0cef3dfa934eca690c41bd96027ab38f014884c /src/codegen
parentefe34243c674a06ead171adcce67a71efdf057e3 (diff)
downloadzig-35e70111248f795fbdcefd5ae0d6fc494d1b0683.tar.gz
zig-35e70111248f795fbdcefd5ae0d6fc494d1b0683.zip
LLVM: implement signext/zeroext attributes
For calling convention ABI purposes, integer attributes and return values need to have an LLVM attribute signext or zeroext added sometimes. This commit implements that logic. It also implements a proof-of-concept of moving the F16T type from being a compiler_rt hack to being how the compiler lowers f16 in functions that need to match certain calling conventions. Closes #12054
Diffstat (limited to 'src/codegen')
-rw-r--r--src/codegen/llvm.zig65
1 files changed, 64 insertions, 1 deletions
diff --git a/src/codegen/llvm.zig b/src/codegen/llvm.zig
index 8857c96bc1..fe35620d38 100644
--- a/src/codegen/llvm.zig
+++ b/src/codegen/llvm.zig
@@ -717,6 +717,11 @@ pub const Object = struct {
const ret_ptr = if (sret) llvm_func.getParam(0) else null;
const gpa = dg.gpa;
+ if (ccAbiPromoteInt(fn_info.cc, target, fn_info.return_type)) |s| switch (s) {
+ .signed => dg.addAttr(llvm_func, 0, "signext"),
+ .unsigned => dg.addAttr(llvm_func, 0, "zeroext"),
+ };
+
const err_return_tracing = fn_info.return_type.isError() and
dg.module.comp.bin_file.options.error_return_tracing;
@@ -774,7 +779,10 @@ pub const Object = struct {
);
dg.addArgAttrInt(llvm_func, llvm_arg_i, "align", elem_align);
}
- }
+ } else if (ccAbiPromoteInt(fn_info.cc, target, param_ty)) |s| switch (s) {
+ .signed => dg.addArgAttr(llvm_func, llvm_arg_i, "signext"),
+ .unsigned => dg.addArgAttr(llvm_func, llvm_arg_i, "zeroext"),
+ };
}
llvm_arg_i += 1;
},
@@ -887,6 +895,13 @@ pub const Object = struct {
};
try args.append(loaded);
},
+ .as_u16 => {
+ const param = llvm_func.getParam(llvm_arg_i);
+ llvm_arg_i += 1;
+ const casted = builder.buildBitCast(param, dg.context.halfType(), "");
+ try args.ensureUnusedCapacity(1);
+ args.appendAssumeCapacity(casted);
+ },
};
}
@@ -2794,6 +2809,9 @@ pub const DeclGen = struct {
llvm_params.appendAssumeCapacity(big_int_ty);
}
},
+ .as_u16 => {
+ try llvm_params.append(dg.context.intType(16));
+ },
};
return llvm.functionType(
@@ -4234,6 +4252,12 @@ pub const FuncGen = struct {
llvm_args.appendAssumeCapacity(load_inst);
}
},
+ .as_u16 => {
+ const arg = args[it.zig_index - 1];
+ const llvm_arg = try self.resolveInst(arg);
+ const casted = self.builder.buildBitCast(llvm_arg, self.dg.context.intType(16), "");
+ try llvm_args.append(casted);
+ },
};
const call = self.builder.buildCall(
@@ -8965,6 +8989,7 @@ const ParamTypeIterator = struct {
abi_sized_int,
multiple_llvm_ints,
slice,
+ as_u16,
};
pub fn next(it: *ParamTypeIterator) ?Lowering {
@@ -9025,6 +9050,15 @@ const ParamTypeIterator = struct {
else => false,
};
switch (it.target.cpu.arch) {
+ .riscv32, .riscv64 => {
+ it.zig_index += 1;
+ it.llvm_index += 1;
+ if (ty.tag() == .f16) {
+ return .as_u16;
+ } else {
+ return .byval;
+ }
+ },
.mips, .mipsel => {
it.zig_index += 1;
it.llvm_index += 1;
@@ -9135,6 +9169,35 @@ fn iterateParamTypes(dg: *DeclGen, fn_info: Type.Payload.Function.Data) ParamTyp
};
}
+fn ccAbiPromoteInt(
+ cc: std.builtin.CallingConvention,
+ target: std.Target,
+ ty: Type,
+) ?std.builtin.Signedness {
+ switch (cc) {
+ .Unspecified, .Inline, .Async => return null,
+ else => {},
+ }
+ const int_info = switch (ty.zigTypeTag()) {
+ .Int, .Enum, .ErrorSet => ty.intInfo(target),
+ else => return null,
+ };
+ if (int_info.bits <= 16) return int_info.signedness;
+ switch (target.cpu.arch) {
+ .sparc64,
+ .riscv64,
+ .powerpc64,
+ .powerpc64le,
+ => {
+ if (int_info.bits < 64) {
+ return int_info.signedness;
+ }
+ },
+ else => {},
+ }
+ return null;
+}
+
fn isByRef(ty: Type) bool {
// For tuples and structs, if there are more than this many non-void
// fields, then we make it byref, otherwise byval.