| 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,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 than | 69 | /// TODO remove this; do this type selection in the language rather than |
| 70 | /// here in compiler-rt. | 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 | pub fn wideMultiply(comptime Z: type, a: Z, b: Z, hi: *Z, lo: *Z) void { | 77 | pub 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; |
| 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 | const err_return_tracing = fn_info.return_type.isError() and | 725 | 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; |
| 722 | 727 | ||
| ... | @@ -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 | } |
| 892 | 907 | ||
| ... | @@ -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 | }; |
| 2798 | 2816 | ||
| 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 | }; |
| 4238 | 4262 | ||
| 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 | }; |
| 8969 | 8994 | ||
| 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 | } |
| 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 | fn isByRef(ty: Type) bool { | 9201 | fn isByRef(ty: Type) bool { |
| 9139 | // For tuples and structs, if there are more than this many non-void | 9202 | // 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; // TODO | 1168 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO |
| 1169 | if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO | 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 | 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; // TODO | 1199 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO |
| 1205 | if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO | 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 | 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; // TODO | 1241 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO |
| 1252 | if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO | 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 | 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; // TODO | 1416 | if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO |
| 1432 | if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO | 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 | 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; // TODO | 1427 | if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO |
| 1448 | if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO | 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 | 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; // TODO | 1575 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO |
| 1601 | if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO | 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 | try testNanEqNan(f16); | 1578 | try testNanEqNan(f16); |
| 1609 | try testNanEqNan(f32); | 1579 | try testNanEqNan(f32); |
| 1610 | try testNanEqNan(f64); | 1580 | try testNanEqNan(f64); |