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...@@ -68,7 +68,11 @@ pub fn panic(msg: []const u8, error_return_trace: ?*std.builtin.StackTrace) nore
68/// need for extending them to wider fp types.68/// need for extending them to wider fp types.
69/// TODO remove this; do this type selection in the language rather than69/// TODO remove this; do this type selection in the language rather than
70/// here in compiler-rt.70/// 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
73pub fn wideMultiply(comptime Z: type, a: Z, b: Z, hi: *Z, lo: *Z) void {77pub fn wideMultiply(comptime Z: type, a: Z, b: Z, hi: *Z, lo: *Z) void {
74 switch (Z) {78 switch (Z) {
src/codegen/llvm.zig+64-1
...@@ -717,6 +717,11 @@ pub const Object = struct {...@@ -717,6 +717,11 @@ pub const Object = struct {
717 const ret_ptr = if (sret) llvm_func.getParam(0) else null;717 const ret_ptr = if (sret) llvm_func.getParam(0) else null;
718 const gpa = dg.gpa;718 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
720 const err_return_tracing = fn_info.return_type.isError() and725 const err_return_tracing = fn_info.return_type.isError() and
721 dg.module.comp.bin_file.options.error_return_tracing;726 dg.module.comp.bin_file.options.error_return_tracing;
722727
...@@ -774,7 +779,10 @@ pub const Object = struct {...@@ -774,7 +779,10 @@ pub const Object = struct {
774 );779 );
775 dg.addArgAttrInt(llvm_func, llvm_arg_i, "align", elem_align);780 dg.addArgAttrInt(llvm_func, llvm_arg_i, "align", elem_align);
776 }781 }
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 };
778 }786 }
779 llvm_arg_i += 1;787 llvm_arg_i += 1;
780 },788 },
...@@ -887,6 +895,13 @@ pub const Object = struct {...@@ -887,6 +895,13 @@ pub const Object = struct {
887 };895 };
888 try args.append(loaded);896 try args.append(loaded);
889 },897 },
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 },
890 };905 };
891 }906 }
892907
...@@ -2794,6 +2809,9 @@ pub const DeclGen = struct {...@@ -2794,6 +2809,9 @@ pub const DeclGen = struct {
2794 llvm_params.appendAssumeCapacity(big_int_ty);2809 llvm_params.appendAssumeCapacity(big_int_ty);
2795 }2810 }
2796 },2811 },
2812 .as_u16 => {
2813 try llvm_params.append(dg.context.intType(16));
2814 },
2797 };2815 };
27982816
2799 return llvm.functionType(2817 return llvm.functionType(
...@@ -4234,6 +4252,12 @@ pub const FuncGen = struct {...@@ -4234,6 +4252,12 @@ pub const FuncGen = struct {
4234 llvm_args.appendAssumeCapacity(load_inst);4252 llvm_args.appendAssumeCapacity(load_inst);
4235 }4253 }
4236 },4254 },
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 },
4237 };4261 };
42384262
4239 const call = self.builder.buildCall(4263 const call = self.builder.buildCall(
...@@ -8965,6 +8989,7 @@ const ParamTypeIterator = struct {...@@ -8965,6 +8989,7 @@ const ParamTypeIterator = struct {
8965 abi_sized_int,8989 abi_sized_int,
8966 multiple_llvm_ints,8990 multiple_llvm_ints,
8967 slice,8991 slice,
8992 as_u16,
8968 };8993 };
89698994
8970 pub fn next(it: *ParamTypeIterator) ?Lowering {8995 pub fn next(it: *ParamTypeIterator) ?Lowering {
...@@ -9025,6 +9050,15 @@ const ParamTypeIterator = struct {...@@ -9025,6 +9050,15 @@ const ParamTypeIterator = struct {
9025 else => false,9050 else => false,
9026 };9051 };
9027 switch (it.target.cpu.arch) {9052 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 },
9028 .mips, .mipsel => {9062 .mips, .mipsel => {
9029 it.zig_index += 1;9063 it.zig_index += 1;
9030 it.llvm_index += 1;9064 it.llvm_index += 1;
...@@ -9135,6 +9169,35 @@ fn iterateParamTypes(dg: *DeclGen, fn_info: Type.Payload.Function.Data) ParamTyp...@@ -9135,6 +9169,35 @@ fn iterateParamTypes(dg: *DeclGen, fn_info: Type.Payload.Function.Data) ParamTyp
9135 };9169 };
9136}9170}
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
9138fn isByRef(ty: Type) bool {9201fn isByRef(ty: Type) bool {
9139 // For tuples and structs, if there are more than this many non-void9202 // For tuples and structs, if there are more than this many non-void
9140 // fields, then we make it byref, otherwise byval.9203 // fields, then we make it byref, otherwise byval.
test/behavior/math.zig-30
...@@ -1168,11 +1168,6 @@ test "remainder division" {...@@ -1168,11 +1168,6 @@ test "remainder division" {
1168 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO1168 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
1169 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO1169 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
1176 comptime try remdiv(f16);1171 comptime try remdiv(f16);
1177 comptime try remdiv(f32);1172 comptime try remdiv(f32);
1178 comptime try remdiv(f64);1173 comptime try remdiv(f64);
...@@ -1204,11 +1199,6 @@ test "float remainder division using @rem" {...@@ -1204,11 +1199,6 @@ test "float remainder division using @rem" {
1204 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO1199 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
1205 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO1200 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
1212 comptime try frem(f16);1202 comptime try frem(f16);
1213 comptime try frem(f32);1203 comptime try frem(f32);
1214 comptime try frem(f64);1204 comptime try frem(f64);
...@@ -1251,11 +1241,6 @@ test "float modulo division using @mod" {...@@ -1251,11 +1241,6 @@ test "float modulo division using @mod" {
1251 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO1241 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
1252 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO1242 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
1259 comptime try fmod(f16);1244 comptime try fmod(f16);
1260 comptime try fmod(f32);1245 comptime try fmod(f32);
1261 comptime try fmod(f64);1246 comptime try fmod(f64);
...@@ -1431,11 +1416,6 @@ test "@ceil f80" {...@@ -1431,11 +1416,6 @@ test "@ceil f80" {
1431 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO1416 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
1432 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO1417 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
1439 try testCeil(f80, 12.0);1419 try testCeil(f80, 12.0);
1440 comptime try testCeil(f80, 12.0);1420 comptime try testCeil(f80, 12.0);
1441}1421}
...@@ -1447,11 +1427,6 @@ test "@ceil f128" {...@@ -1447,11 +1427,6 @@ test "@ceil f128" {
1447 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO1427 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
1448 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO1428 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
1455 try testCeil(f128, 12.0);1430 try testCeil(f128, 12.0);
1456 comptime try testCeil(f128, 12.0);1431 comptime try testCeil(f128, 12.0);
1457}1432}
...@@ -1600,11 +1575,6 @@ test "NaN comparison" {...@@ -1600,11 +1575,6 @@ test "NaN comparison" {
1600 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO1575 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
1601 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO1576 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
1608 try testNanEqNan(f16);1578 try testNanEqNan(f16);
1609 try testNanEqNan(f32);1579 try testNanEqNan(f32);
1610 try testNanEqNan(f64);1580 try testNanEqNan(f64);