| ... | ... | @@ -2040,7 +2040,7 @@ fn airFloatFromInt(fg: *FuncGen, inst: Air.Inst.Index) TodoError!Builder.Value { |
| 2040 | 2040 | const dest_scalar_ty = dest_ty.scalarType(zcu); |
| 2041 | 2041 | const target = zcu.getTarget(); |
| 2042 | 2042 | |
| 2043 | | if (intrinsicsAllowed(dest_scalar_ty, target)) |
| 2043 | if (intrinsicsAllowed(.compiler_rt, dest_scalar_ty, target)) |
| 2044 | 2044 | return fg.wip.conv(.fromStdLang(operand_scalar_info.signedness), operand, try o.lowerType(dest_ty, .as_value), ""); |
| 2045 | 2045 | |
| 2046 | 2046 | const rt_int_ty = compilerRtPromoteInt(operand_scalar_info) orelse { |
| ... | ... | @@ -2093,7 +2093,7 @@ fn airIntFromFloat( |
| 2093 | 2093 | const dest_llvm_ty = try o.lowerType(dest_ty, .as_value); |
| 2094 | 2094 | const dest_scalar_info = dest_scalar_ty.intInfo(zcu); |
| 2095 | 2095 | |
| 2096 | | if (intrinsicsAllowed(operand_scalar_ty, target)) { |
| 2096 | if (intrinsicsAllowed(.compiler_rt, operand_scalar_ty, target)) { |
| 2097 | 2097 | // TODO set fast math flag |
| 2098 | 2098 | return fg.wip.conv(.fromStdLang(dest_scalar_info.signedness), operand, dest_llvm_ty, ""); |
| 2099 | 2099 | } |
| ... | ... | @@ -3888,7 +3888,7 @@ fn buildFloatCmp( |
| 3888 | 3888 | const target = zcu.getTarget(); |
| 3889 | 3889 | const scalar_ty = ty.scalarType(zcu); |
| 3890 | 3890 | |
| 3891 | | if (intrinsicsAllowed(scalar_ty, target)) { |
| 3891 | if (intrinsicsAllowed(.compiler_rt, scalar_ty, target)) { |
| 3892 | 3892 | const cond: Builder.FloatCondition = switch (pred) { |
| 3893 | 3893 | .eq => .oeq, |
| 3894 | 3894 | .neq => .une, |
| ... | ... | @@ -3968,10 +3968,14 @@ fn buildFloatOp( |
| 3968 | 3968 | const target = zcu.getTarget(); |
| 3969 | 3969 | const scalar_ty = ty.scalarType(zcu); |
| 3970 | 3970 | |
| 3971 | | if (op != .tan and intrinsicsAllowed(scalar_ty, target)) switch (op) { |
| 3971 | switch (op) { |
| 3972 | 3972 | // Some operations are dedicated LLVM instructions, not available as intrinsics |
| 3973 | | .neg => return fg.wip.un(.fneg, params[0], ""), |
| 3974 | | .add, .sub, .mul, .div, .fmod => return fg.wip.bin(switch (fast) { |
| 3973 | .neg => if (intrinsicsAllowed(.compiler_rt, scalar_ty, target)) return fg.wip.un(.fneg, params[0], ""), |
| 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 | 3979 | .normal => switch (op) { |
| 3976 | 3980 | .add => .fadd, |
| 3977 | 3981 | .sub => .fsub, |
| ... | ... | @@ -3989,6 +3993,7 @@ fn buildFloatOp( |
| 3989 | 3993 | else => unreachable, |
| 3990 | 3994 | }, |
| 3991 | 3995 | }, params[0], params[1], ""), |
| 3996 | .fma, |
| 3992 | 3997 | .fmax, |
| 3993 | 3998 | .fmin, |
| 3994 | 3999 | .ceil, |
| ... | ... | @@ -4003,9 +4008,10 @@ fn buildFloatOp( |
| 4003 | 4008 | .round, |
| 4004 | 4009 | .sin, |
| 4005 | 4010 | .sqrt, |
| 4011 | .tan, |
| 4006 | 4012 | .trunc, |
| 4007 | | .fma, |
| 4008 | | => return fg.wip.callIntrinsic(fast, .none, switch (op) { |
| 4013 | => if (intrinsicsAllowed(.libc, scalar_ty, target)) return fg.wip.callIntrinsic(fast, .none, switch (op) { |
| 4014 | .fma => .fma, |
| 4009 | 4015 | .fmax => .maxnum, |
| 4010 | 4016 | .fmin => .minnum, |
| 4011 | 4017 | .ceil => .ceil, |
| ... | ... | @@ -4020,12 +4026,11 @@ fn buildFloatOp( |
| 4020 | 4026 | .round => .round, |
| 4021 | 4027 | .sin => .sin, |
| 4022 | 4028 | .sqrt => .sqrt, |
| 4029 | .tan => .tan, |
| 4023 | 4030 | .trunc => .trunc, |
| 4024 | | .fma => .fma, |
| 4025 | 4031 | else => unreachable, |
| 4026 | 4032 | }, &.{try o.lowerType(ty, .as_value)}, &params, ""), |
| 4027 | | .tan => unreachable, |
| 4028 | | }; |
| 4033 | } |
| 4029 | 4034 | |
| 4030 | 4035 | const float_bits = scalar_ty.floatBits(target); |
| 4031 | 4036 | const fn_name = switch (op) { |
| ... | ... | @@ -4589,7 +4594,8 @@ fn airFptrunc(self: *FuncGen, inst: Air.Inst.Index) Allocator.Error!Builder.Valu |
| 4589 | 4594 | const dest_scalar_ty = dest_ty.scalarType(zcu); |
| 4590 | 4595 | const target = zcu.getTarget(); |
| 4591 | 4596 | |
| 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 | 4599 | return self.wip.cast(.fptrunc, operand, try o.lowerType(dest_ty, .as_value), ""); |
| 4594 | 4600 | const dest_bits = dest_scalar_ty.floatBits(target); |
| 4595 | 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 | 4616 | const dest_scalar_ty = dest_ty.scalarType(zcu); |
| 4611 | 4617 | const target = zcu.getTarget(); |
| 4612 | 4618 | |
| 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 | 4621 | return self.wip.cast(.fpext, operand, try o.lowerType(dest_ty, .as_value), ""); |
| 4615 | 4622 | const dest_bits = dest_scalar_ty.floatBits(target); |
| 4616 | 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 | 6168 | .@"vector.reduce.umax", |
| 6162 | 6169 | else => unreachable, |
| 6163 | 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 | 6172 | return fg.wip.callIntrinsic(fast, .none, switch (reduce.operation) { |
| 6166 | 6173 | .Min => .@"vector.reduce.fmin", |
| 6167 | 6174 | .Max => .@"vector.reduce.fmax", |
| ... | ... | @@ -6175,7 +6182,7 @@ fn airReduce(fg: *FuncGen, inst: Air.Inst.Index, fast: Builder.FastMathKind) All |
| 6175 | 6182 | .Mul => .@"vector.reduce.mul", |
| 6176 | 6183 | else => unreachable, |
| 6177 | 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 | 6186 | return fg.wip.callIntrinsic(fast, .none, switch (reduce.operation) { |
| 6180 | 6187 | .Add => .@"vector.reduce.fadd", |
| 6181 | 6188 | .Mul => .@"vector.reduce.fmul", |
| ... | ... | @@ -7936,9 +7943,18 @@ fn appendConstraints( |
| 7936 | 7943 | |
| 7937 | 7944 | /// LLVM does not support all relevant intrinsics for all targets, so we |
| 7938 | 7945 | /// may need to manually generate a compiler-rt call using a soft type. |
| 7939 | | fn intrinsicsAllowed(scalar_ty: Type, target: *const std.Target) bool { |
| 7946 | fn intrinsicsAllowed(kind: enum { compiler_rt, libc }, scalar_ty: Type, target: *const std.Target) bool { |
| 7940 | 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 | 7958 | .hard => true, |
| 7943 | 7959 | .soft => false, |
| 7944 | 7960 | }; |