authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2022-07-12 23:30:26-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2022-07-13 11:14:46-07:00
log35e70111248f795fbdcefd5ae0d6fc494d1b0683
treef0cef3dfa934eca690c41bd96027ab38f014884c
parentefe34243c674a06ead171adcce67a71efdf057e3

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

3 files changed, 69 insertions(+), 32 deletions(-)

lib/compiler_rt/common.zig+5-1
......@@ -68,7 +68,11 @@ pub fn panic(msg: []const u8, error_return_trace: ?*std.builtin.StackTrace) nore
6868/// need for extending them to wider fp types.
6969/// TODO remove this; do this type selection in the language rather than
7070/// here in compiler-rt.
71pub const F16T = if (builtin.cpu.arch.isAARCH64()) f16 else u16;
71pub const F16T = switch (builtin.cpu.arch) {
72 .aarch64, .aarch64_be, .aarch64_32 => f16,
73 .riscv64 => if (builtin.zig_backend == .stage1) u16 else f16,
74 else => u16,
75};
7276
7377pub fn wideMultiply(comptime Z: type, a: Z, b: Z, hi: *Z, lo: *Z) void {
7478 switch (Z) {
src/codegen/llvm.zig+64-1
......@@ -717,6 +717,11 @@ pub const Object = struct {
717717 const ret_ptr = if (sret) llvm_func.getParam(0) else null;
718718 const gpa = dg.gpa;
719719
720 if (ccAbiPromoteInt(fn_info.cc, target, fn_info.return_type)) |s| switch (s) {
721 .signed => dg.addAttr(llvm_func, 0, "signext"),
722 .unsigned => dg.addAttr(llvm_func, 0, "zeroext"),
723 };
724
720725 const err_return_tracing = fn_info.return_type.isError() and
721726 dg.module.comp.bin_file.options.error_return_tracing;
722727
......@@ -774,7 +779,10 @@ pub const Object = struct {
774779 );
775780 dg.addArgAttrInt(llvm_func, llvm_arg_i, "align", elem_align);
776781 }
777 }
782 } else if (ccAbiPromoteInt(fn_info.cc, target, param_ty)) |s| switch (s) {
783 .signed => dg.addArgAttr(llvm_func, llvm_arg_i, "signext"),
784 .unsigned => dg.addArgAttr(llvm_func, llvm_arg_i, "zeroext"),
785 };
778786 }
779787 llvm_arg_i += 1;
780788 },
......@@ -887,6 +895,13 @@ pub const Object = struct {
887895 };
888896 try args.append(loaded);
889897 },
898 .as_u16 => {
899 const param = llvm_func.getParam(llvm_arg_i);
900 llvm_arg_i += 1;
901 const casted = builder.buildBitCast(param, dg.context.halfType(), "");
902 try args.ensureUnusedCapacity(1);
903 args.appendAssumeCapacity(casted);
904 },
890905 };
891906 }
892907
......@@ -2794,6 +2809,9 @@ pub const DeclGen = struct {
27942809 llvm_params.appendAssumeCapacity(big_int_ty);
27952810 }
27962811 },
2812 .as_u16 => {
2813 try llvm_params.append(dg.context.intType(16));
2814 },
27972815 };
27982816
27992817 return llvm.functionType(
......@@ -4234,6 +4252,12 @@ pub const FuncGen = struct {
42344252 llvm_args.appendAssumeCapacity(load_inst);
42354253 }
42364254 },
4255 .as_u16 => {
4256 const arg = args[it.zig_index - 1];
4257 const llvm_arg = try self.resolveInst(arg);
4258 const casted = self.builder.buildBitCast(llvm_arg, self.dg.context.intType(16), "");
4259 try llvm_args.append(casted);
4260 },
42374261 };
42384262
42394263 const call = self.builder.buildCall(
......@@ -8965,6 +8989,7 @@ const ParamTypeIterator = struct {
89658989 abi_sized_int,
89668990 multiple_llvm_ints,
89678991 slice,
8992 as_u16,
89688993 };
89698994
89708995 pub fn next(it: *ParamTypeIterator) ?Lowering {
......@@ -9025,6 +9050,15 @@ const ParamTypeIterator = struct {
90259050 else => false,
90269051 };
90279052 switch (it.target.cpu.arch) {
9053 .riscv32, .riscv64 => {
9054 it.zig_index += 1;
9055 it.llvm_index += 1;
9056 if (ty.tag() == .f16) {
9057 return .as_u16;
9058 } else {
9059 return .byval;
9060 }
9061 },
90289062 .mips, .mipsel => {
90299063 it.zig_index += 1;
90309064 it.llvm_index += 1;
......@@ -9135,6 +9169,35 @@ fn iterateParamTypes(dg: *DeclGen, fn_info: Type.Payload.Function.Data) ParamTyp
91359169 };
91369170}
91379171
9172fn ccAbiPromoteInt(
9173 cc: std.builtin.CallingConvention,
9174 target: std.Target,
9175 ty: Type,
9176) ?std.builtin.Signedness {
9177 switch (cc) {
9178 .Unspecified, .Inline, .Async => return null,
9179 else => {},
9180 }
9181 const int_info = switch (ty.zigTypeTag()) {
9182 .Int, .Enum, .ErrorSet => ty.intInfo(target),
9183 else => return null,
9184 };
9185 if (int_info.bits <= 16) return int_info.signedness;
9186 switch (target.cpu.arch) {
9187 .sparc64,
9188 .riscv64,
9189 .powerpc64,
9190 .powerpc64le,
9191 => {
9192 if (int_info.bits < 64) {
9193 return int_info.signedness;
9194 }
9195 },
9196 else => {},
9197 }
9198 return null;
9199}
9200
91389201fn isByRef(ty: Type) bool {
91399202 // For tuples and structs, if there are more than this many non-void
91409203 // fields, then we make it byref, otherwise byval.
test/behavior/math.zig-30
......@@ -1168,11 +1168,6 @@ test "remainder division" {
11681168 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
11691169 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
11701170
1171 if (builtin.zig_backend == .stage2_llvm and builtin.cpu.arch == .riscv64) {
1172 // https://github.com/ziglang/zig/issues/12054
1173 return error.SkipZigTest;
1174 }
1175
11761171 comptime try remdiv(f16);
11771172 comptime try remdiv(f32);
11781173 comptime try remdiv(f64);
......@@ -1204,11 +1199,6 @@ test "float remainder division using @rem" {
12041199 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
12051200 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
12061201
1207 if (builtin.zig_backend == .stage2_llvm and builtin.cpu.arch == .riscv64) {
1208 // https://github.com/ziglang/zig/issues/12054
1209 return error.SkipZigTest;
1210 }
1211
12121202 comptime try frem(f16);
12131203 comptime try frem(f32);
12141204 comptime try frem(f64);
......@@ -1251,11 +1241,6 @@ test "float modulo division using @mod" {
12511241 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
12521242 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
12531243
1254 if (builtin.zig_backend == .stage2_llvm and builtin.cpu.arch == .riscv64) {
1255 // https://github.com/ziglang/zig/issues/12054
1256 return error.SkipZigTest;
1257 }
1258
12591244 comptime try fmod(f16);
12601245 comptime try fmod(f32);
12611246 comptime try fmod(f64);
......@@ -1431,11 +1416,6 @@ test "@ceil f80" {
14311416 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
14321417 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
14331418
1434 if (builtin.zig_backend == .stage2_llvm and builtin.cpu.arch == .riscv64) {
1435 // https://github.com/ziglang/zig/issues/12054
1436 return error.SkipZigTest;
1437 }
1438
14391419 try testCeil(f80, 12.0);
14401420 comptime try testCeil(f80, 12.0);
14411421}
......@@ -1447,11 +1427,6 @@ test "@ceil f128" {
14471427 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
14481428 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
14491429
1450 if (builtin.zig_backend == .stage2_llvm and builtin.cpu.arch == .riscv64) {
1451 // https://github.com/ziglang/zig/issues/12054
1452 return error.SkipZigTest;
1453 }
1454
14551430 try testCeil(f128, 12.0);
14561431 comptime try testCeil(f128, 12.0);
14571432}
......@@ -1600,11 +1575,6 @@ test "NaN comparison" {
16001575 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
16011576 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
16021577
1603 if (builtin.zig_backend == .stage2_llvm and builtin.cpu.arch == .riscv64) {
1604 // https://github.com/ziglang/zig/issues/12054
1605 return error.SkipZigTest;
1606 }
1607
16081578 try testNanEqNan(f16);
16091579 try testNanEqNan(f32);
16101580 try testNanEqNan(f64);