| author | |
| committer | |
| log | 35e70111248f795fbdcefd5ae0d6fc494d1b0683 |
| tree | f0cef3dfa934eca690c41bd96027ab38f014884c |
| parent | efe34243c674a06ead171adcce67a71efdf057e3 |
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 #120543 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 | 68 | /// need for extending them to wider fp types. |
| 69 | 69 | /// TODO remove this; do this type selection in the language rather than |
| 70 | 70 | /// here in compiler-rt. |
| 71 | pub const F16T = if (builtin.cpu.arch.isAARCH64()) f16 else u16; | |
| 71 | pub 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 | }; | |
| 72 | 76 | |
| 73 | 77 | pub fn wideMultiply(comptime Z: type, a: Z, b: Z, hi: *Z, lo: *Z) void { |
| 74 | 78 | switch (Z) { |
src/codegen/llvm.zig+64-1| ... | ... | @@ -717,6 +717,11 @@ pub const Object = struct { |
| 717 | 717 | const ret_ptr = if (sret) llvm_func.getParam(0) else null; |
| 718 | 718 | const gpa = dg.gpa; |
| 719 | 719 | |
| 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 | 725 | const err_return_tracing = fn_info.return_type.isError() and |
| 721 | 726 | dg.module.comp.bin_file.options.error_return_tracing; |
| 722 | 727 | |
| ... | ... | @@ -774,7 +779,10 @@ pub const Object = struct { |
| 774 | 779 | ); |
| 775 | 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 | 787 | llvm_arg_i += 1; |
| 780 | 788 | }, |
| ... | ... | @@ -887,6 +895,13 @@ pub const Object = struct { |
| 887 | 895 | }; |
| 888 | 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 | } |
| 892 | 907 | |
| ... | ... | @@ -2794,6 +2809,9 @@ pub const DeclGen = struct { |
| 2794 | 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 | }; |
| 2798 | 2816 | |
| 2799 | 2817 | return llvm.functionType( |
| ... | ... | @@ -4234,6 +4252,12 @@ pub const FuncGen = struct { |
| 4234 | 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 | }; |
| 4238 | 4262 | |
| 4239 | 4263 | const call = self.builder.buildCall( |
| ... | ... | @@ -8965,6 +8989,7 @@ const ParamTypeIterator = struct { |
| 8965 | 8989 | abi_sized_int, |
| 8966 | 8990 | multiple_llvm_ints, |
| 8967 | 8991 | slice, |
| 8992 | as_u16, | |
| 8968 | 8993 | }; |
| 8969 | 8994 | |
| 8970 | 8995 | pub fn next(it: *ParamTypeIterator) ?Lowering { |
| ... | ... | @@ -9025,6 +9050,15 @@ const ParamTypeIterator = struct { |
| 9025 | 9050 | else => false, |
| 9026 | 9051 | }; |
| 9027 | 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 | 9062 | .mips, .mipsel => { |
| 9029 | 9063 | it.zig_index += 1; |
| 9030 | 9064 | it.llvm_index += 1; |
| ... | ... | @@ -9135,6 +9169,35 @@ fn iterateParamTypes(dg: *DeclGen, fn_info: Type.Payload.Function.Data) ParamTyp |
| 9135 | 9169 | }; |
| 9136 | 9170 | } |
| 9137 | 9171 | |
| 9172 | fn 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 | ||
| 9138 | 9201 | fn isByRef(ty: Type) bool { |
| 9139 | 9202 | // For tuples and structs, if there are more than this many non-void |
| 9140 | 9203 | // fields, then we make it byref, otherwise byval. |
test/behavior/math.zig-30| ... | ... | @@ -1168,11 +1168,6 @@ test "remainder division" { |
| 1168 | 1168 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO |
| 1169 | 1169 | if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO |
| 1170 | 1170 | |
| 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 | 1171 | comptime try remdiv(f16); |
| 1177 | 1172 | comptime try remdiv(f32); |
| 1178 | 1173 | comptime try remdiv(f64); |
| ... | ... | @@ -1204,11 +1199,6 @@ test "float remainder division using @rem" { |
| 1204 | 1199 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO |
| 1205 | 1200 | if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO |
| 1206 | 1201 | |
| 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 | 1202 | comptime try frem(f16); |
| 1213 | 1203 | comptime try frem(f32); |
| 1214 | 1204 | comptime try frem(f64); |
| ... | ... | @@ -1251,11 +1241,6 @@ test "float modulo division using @mod" { |
| 1251 | 1241 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO |
| 1252 | 1242 | if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO |
| 1253 | 1243 | |
| 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 | 1244 | comptime try fmod(f16); |
| 1260 | 1245 | comptime try fmod(f32); |
| 1261 | 1246 | comptime try fmod(f64); |
| ... | ... | @@ -1431,11 +1416,6 @@ test "@ceil f80" { |
| 1431 | 1416 | if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO |
| 1432 | 1417 | if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO |
| 1433 | 1418 | |
| 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 | 1419 | try testCeil(f80, 12.0); |
| 1440 | 1420 | comptime try testCeil(f80, 12.0); |
| 1441 | 1421 | } |
| ... | ... | @@ -1447,11 +1427,6 @@ test "@ceil f128" { |
| 1447 | 1427 | if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO |
| 1448 | 1428 | if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO |
| 1449 | 1429 | |
| 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 | 1430 | try testCeil(f128, 12.0); |
| 1456 | 1431 | comptime try testCeil(f128, 12.0); |
| 1457 | 1432 | } |
| ... | ... | @@ -1600,11 +1575,6 @@ test "NaN comparison" { |
| 1600 | 1575 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO |
| 1601 | 1576 | if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO |
| 1602 | 1577 | |
| 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 | 1578 | try testNanEqNan(f16); |
| 1609 | 1579 | try testNanEqNan(f32); |
| 1610 | 1580 | try testNanEqNan(f64); |