authorgravatar for jacobly@ziglang.orgJacob Young <jacobly@ziglang.org> 2026-07-16 12:48:14-04:00
committergravatar for jacobly@ziglang.orgJacob Young <jacobly@ziglang.org> 2026-07-27 14:44:41-04:00
log556e9a455c1372d39bf7e73513d879aa199acc07
tree689fb0884fa48a4c51aa01ac341bad03a07025bf
parente03056d45a864c8176cdd897d771457005ead592

llvm: work around bizarre upstream llvm behavior


1 files changed, 33 insertions(+), 17 deletions(-)

src/codegen/llvm/FuncGen.zig+33-17
...@@ -2040,7 +2040,7 @@ fn airFloatFromInt(fg: *FuncGen, inst: Air.Inst.Index) TodoError!Builder.Value {...@@ -2040,7 +2040,7 @@ fn airFloatFromInt(fg: *FuncGen, inst: Air.Inst.Index) TodoError!Builder.Value {
2040 const dest_scalar_ty = dest_ty.scalarType(zcu);2040 const dest_scalar_ty = dest_ty.scalarType(zcu);
2041 const target = zcu.getTarget();2041 const target = zcu.getTarget();
20422042
2043 if (intrinsicsAllowed(dest_scalar_ty, target))2043 if (intrinsicsAllowed(.compiler_rt, dest_scalar_ty, target))
2044 return fg.wip.conv(.fromStdLang(operand_scalar_info.signedness), operand, try o.lowerType(dest_ty, .as_value), "");2044 return fg.wip.conv(.fromStdLang(operand_scalar_info.signedness), operand, try o.lowerType(dest_ty, .as_value), "");
20452045
2046 const rt_int_ty = compilerRtPromoteInt(operand_scalar_info) orelse {2046 const rt_int_ty = compilerRtPromoteInt(operand_scalar_info) orelse {
...@@ -2093,7 +2093,7 @@ fn airIntFromFloat(...@@ -2093,7 +2093,7 @@ fn airIntFromFloat(
2093 const dest_llvm_ty = try o.lowerType(dest_ty, .as_value);2093 const dest_llvm_ty = try o.lowerType(dest_ty, .as_value);
2094 const dest_scalar_info = dest_scalar_ty.intInfo(zcu);2094 const dest_scalar_info = dest_scalar_ty.intInfo(zcu);
20952095
2096 if (intrinsicsAllowed(operand_scalar_ty, target)) {2096 if (intrinsicsAllowed(.compiler_rt, operand_scalar_ty, target)) {
2097 // TODO set fast math flag2097 // TODO set fast math flag
2098 return fg.wip.conv(.fromStdLang(dest_scalar_info.signedness), operand, dest_llvm_ty, "");2098 return fg.wip.conv(.fromStdLang(dest_scalar_info.signedness), operand, dest_llvm_ty, "");
2099 }2099 }
...@@ -3888,7 +3888,7 @@ fn buildFloatCmp(...@@ -3888,7 +3888,7 @@ fn buildFloatCmp(
3888 const target = zcu.getTarget();3888 const target = zcu.getTarget();
3889 const scalar_ty = ty.scalarType(zcu);3889 const scalar_ty = ty.scalarType(zcu);
38903890
3891 if (intrinsicsAllowed(scalar_ty, target)) {3891 if (intrinsicsAllowed(.compiler_rt, scalar_ty, target)) {
3892 const cond: Builder.FloatCondition = switch (pred) {3892 const cond: Builder.FloatCondition = switch (pred) {
3893 .eq => .oeq,3893 .eq => .oeq,
3894 .neq => .une,3894 .neq => .une,
...@@ -3968,10 +3968,14 @@ fn buildFloatOp(...@@ -3968,10 +3968,14 @@ fn buildFloatOp(
3968 const target = zcu.getTarget();3968 const target = zcu.getTarget();
3969 const scalar_ty = ty.scalarType(zcu);3969 const scalar_ty = ty.scalarType(zcu);
39703970
3971 if (op != .tan and intrinsicsAllowed(scalar_ty, target)) switch (op) {3971 switch (op) {
3972 // Some operations are dedicated LLVM instructions, not available as intrinsics3972 // Some operations are dedicated LLVM instructions, not available as intrinsics
3973 .neg => return fg.wip.un(.fneg, params[0], ""),3973 .neg => if (intrinsicsAllowed(.compiler_rt, scalar_ty, target)) return fg.wip.un(.fneg, params[0], ""),
3974 .add, .sub, .mul, .div, .fmod => return fg.wip.bin(switch (fast) {3974 .add, .sub, .mul, .div, .fmod => if (intrinsicsAllowed(switch (op) {
3975 else => unreachable,
3976 .add, .sub, .mul, .div => .compiler_rt,
3977 .fmod => .libc,
3978 }, scalar_ty, target)) return fg.wip.bin(switch (fast) {
3975 .normal => switch (op) {3979 .normal => switch (op) {
3976 .add => .fadd,3980 .add => .fadd,
3977 .sub => .fsub,3981 .sub => .fsub,
...@@ -3989,6 +3993,7 @@ fn buildFloatOp(...@@ -3989,6 +3993,7 @@ fn buildFloatOp(
3989 else => unreachable,3993 else => unreachable,
3990 },3994 },
3991 }, params[0], params[1], ""),3995 }, params[0], params[1], ""),
3996 .fma,
3992 .fmax,3997 .fmax,
3993 .fmin,3998 .fmin,
3994 .ceil,3999 .ceil,
...@@ -4003,9 +4008,10 @@ fn buildFloatOp(...@@ -4003,9 +4008,10 @@ fn buildFloatOp(
4003 .round,4008 .round,
4004 .sin,4009 .sin,
4005 .sqrt,4010 .sqrt,
4011 .tan,
4006 .trunc,4012 .trunc,
4007 .fma,4013 => if (intrinsicsAllowed(.libc, scalar_ty, target)) return fg.wip.callIntrinsic(fast, .none, switch (op) {
4008 => return fg.wip.callIntrinsic(fast, .none, switch (op) {4014 .fma => .fma,
4009 .fmax => .maxnum,4015 .fmax => .maxnum,
4010 .fmin => .minnum,4016 .fmin => .minnum,
4011 .ceil => .ceil,4017 .ceil => .ceil,
...@@ -4020,12 +4026,11 @@ fn buildFloatOp(...@@ -4020,12 +4026,11 @@ fn buildFloatOp(
4020 .round => .round,4026 .round => .round,
4021 .sin => .sin,4027 .sin => .sin,
4022 .sqrt => .sqrt,4028 .sqrt => .sqrt,
4029 .tan => .tan,
4023 .trunc => .trunc,4030 .trunc => .trunc,
4024 .fma => .fma,
4025 else => unreachable,4031 else => unreachable,
4026 }, &.{try o.lowerType(ty, .as_value)}, &params, ""),4032 }, &.{try o.lowerType(ty, .as_value)}, &params, ""),
4027 .tan => unreachable,4033 }
4028 };
40294034
4030 const float_bits = scalar_ty.floatBits(target);4035 const float_bits = scalar_ty.floatBits(target);
4031 const fn_name = switch (op) {4036 const fn_name = switch (op) {
...@@ -4589,7 +4594,8 @@ fn airFptrunc(self: *FuncGen, inst: Air.Inst.Index) Allocator.Error!Builder.Valu...@@ -4589,7 +4594,8 @@ fn airFptrunc(self: *FuncGen, inst: Air.Inst.Index) Allocator.Error!Builder.Valu
4589 const dest_scalar_ty = dest_ty.scalarType(zcu);4594 const dest_scalar_ty = dest_ty.scalarType(zcu);
4590 const target = zcu.getTarget();4595 const target = zcu.getTarget();
45914596
4592 if (intrinsicsAllowed(dest_scalar_ty, target) and intrinsicsAllowed(operand_scalar_ty, target))4597 if (intrinsicsAllowed(.compiler_rt, dest_scalar_ty, target) and
4598 intrinsicsAllowed(.compiler_rt, operand_scalar_ty, target))
4593 return self.wip.cast(.fptrunc, operand, try o.lowerType(dest_ty, .as_value), "");4599 return self.wip.cast(.fptrunc, operand, try o.lowerType(dest_ty, .as_value), "");
4594 const dest_bits = dest_scalar_ty.floatBits(target);4600 const dest_bits = dest_scalar_ty.floatBits(target);
4595 const src_bits = operand_scalar_ty.floatBits(target);4601 const src_bits = operand_scalar_ty.floatBits(target);
...@@ -4610,7 +4616,8 @@ fn airFpext(self: *FuncGen, inst: Air.Inst.Index) Allocator.Error!Builder.Value...@@ -4610,7 +4616,8 @@ fn airFpext(self: *FuncGen, inst: Air.Inst.Index) Allocator.Error!Builder.Value
4610 const dest_scalar_ty = dest_ty.scalarType(zcu);4616 const dest_scalar_ty = dest_ty.scalarType(zcu);
4611 const target = zcu.getTarget();4617 const target = zcu.getTarget();
46124618
4613 if (intrinsicsAllowed(dest_scalar_ty, target) and intrinsicsAllowed(operand_scalar_ty, target))4619 if (intrinsicsAllowed(.compiler_rt, dest_scalar_ty, target) and
4620 intrinsicsAllowed(.compiler_rt, operand_scalar_ty, target))
4614 return self.wip.cast(.fpext, operand, try o.lowerType(dest_ty, .as_value), "");4621 return self.wip.cast(.fpext, operand, try o.lowerType(dest_ty, .as_value), "");
4615 const dest_bits = dest_scalar_ty.floatBits(target);4622 const dest_bits = dest_scalar_ty.floatBits(target);
4616 const src_bits = operand_scalar_ty.floatBits(target);4623 const src_bits = operand_scalar_ty.floatBits(target);
...@@ -6161,7 +6168,7 @@ fn airReduce(fg: *FuncGen, inst: Air.Inst.Index, fast: Builder.FastMathKind) All...@@ -6161,7 +6168,7 @@ fn airReduce(fg: *FuncGen, inst: Air.Inst.Index, fast: Builder.FastMathKind) All
6161 .@"vector.reduce.umax",6168 .@"vector.reduce.umax",
6162 else => unreachable,6169 else => unreachable,
6163 }, &.{try o.lowerType(operand_ty, .as_value)}, &.{operand}, ""),6170 }, &.{try o.lowerType(operand_ty, .as_value)}, &.{operand}, ""),
6164 .float => if (intrinsicsAllowed(scalar_ty, target))6171 .float => if (intrinsicsAllowed(.libc, scalar_ty, target))
6165 return fg.wip.callIntrinsic(fast, .none, switch (reduce.operation) {6172 return fg.wip.callIntrinsic(fast, .none, switch (reduce.operation) {
6166 .Min => .@"vector.reduce.fmin",6173 .Min => .@"vector.reduce.fmin",
6167 .Max => .@"vector.reduce.fmax",6174 .Max => .@"vector.reduce.fmax",
...@@ -6175,7 +6182,7 @@ fn airReduce(fg: *FuncGen, inst: Air.Inst.Index, fast: Builder.FastMathKind) All...@@ -6175,7 +6182,7 @@ fn airReduce(fg: *FuncGen, inst: Air.Inst.Index, fast: Builder.FastMathKind) All
6175 .Mul => .@"vector.reduce.mul",6182 .Mul => .@"vector.reduce.mul",
6176 else => unreachable,6183 else => unreachable,
6177 }, &.{try o.lowerType(operand_ty, .as_value)}, &.{operand}, ""),6184 }, &.{try o.lowerType(operand_ty, .as_value)}, &.{operand}, ""),
6178 .float => if (intrinsicsAllowed(scalar_ty, target))6185 .float => if (intrinsicsAllowed(.compiler_rt, scalar_ty, target))
6179 return fg.wip.callIntrinsic(fast, .none, switch (reduce.operation) {6186 return fg.wip.callIntrinsic(fast, .none, switch (reduce.operation) {
6180 .Add => .@"vector.reduce.fadd",6187 .Add => .@"vector.reduce.fadd",
6181 .Mul => .@"vector.reduce.fmul",6188 .Mul => .@"vector.reduce.fmul",
...@@ -7936,9 +7943,18 @@ fn appendConstraints(...@@ -7936,9 +7943,18 @@ fn appendConstraints(
79367943
7937/// LLVM does not support all relevant intrinsics for all targets, so we7944/// LLVM does not support all relevant intrinsics for all targets, so we
7938/// may need to manually generate a compiler-rt call using a soft type.7945/// may need to manually generate a compiler-rt call using a soft type.
7939fn intrinsicsAllowed(scalar_ty: Type, target: *const std.Target) bool {7946fn intrinsicsAllowed(kind: enum { compiler_rt, libc }, scalar_ty: Type, target: *const std.Target) bool {
7940 if (!scalar_ty.isRuntimeFloat()) return true;7947 if (!scalar_ty.isRuntimeFloat()) return true;
7941 return switch (std.zig.target.compilerRtFloatAbi(target, scalar_ty.floatBits(target))) {7948 const bits = scalar_ty.floatBits(target);
7949 // Since upstream musl/msvc do not actually define the *f128 functions, llvm decides
7950 // that it is a much better idea to just emit a call to the entirely wrong function as
7951 // a fallback. We wouldn't want any linker errors when trying to perform an operation
7952 // that isn't actually implemented anywhere, now would we!
7953 if (bits == 128 and target.cpu.arch.isX86() and !target.abi.isGnu()) return switch (kind) {
7954 .compiler_rt => true,
7955 .libc => false,
7956 };
7957 return switch (std.zig.target.compilerRtFloatAbi(target, bits)) {
7942 .hard => true,7958 .hard => true,
7943 .soft => false,7959 .soft => false,
7944 };7960 };