| ... | @@ -7576,6 +7576,8 @@ pub const FuncGen = struct { | ... | @@ -7576,6 +7576,8 @@ pub const FuncGen = struct { |
| 7576 | const src_bits = operand_ty.floatBits(target); | 7576 | const src_bits = operand_ty.floatBits(target); |
| 7577 | if (!backendSupportsF80(target) and (src_bits == 80 or dest_bits == 80)) { | 7577 | if (!backendSupportsF80(target) and (src_bits == 80 or dest_bits == 80)) { |
| 7578 | return softF80TruncOrExt(self, operand, src_bits, dest_bits); | 7578 | return softF80TruncOrExt(self, operand, src_bits, dest_bits); |
| | 7579 | } else if (!backendSupportsF128(target) and (src_bits == 128 or dest_bits == 128)) { |
| | 7580 | return softF128TruncOrExt(self, operand, src_bits, dest_bits); |
| 7579 | } | 7581 | } |
| 7580 | const dest_llvm_ty = try self.dg.lowerType(dest_ty); | 7582 | const dest_llvm_ty = try self.dg.lowerType(dest_ty); |
| 7581 | return self.builder.buildFPTrunc(operand, dest_llvm_ty, ""); | 7583 | return self.builder.buildFPTrunc(operand, dest_llvm_ty, ""); |
| ... | @@ -7594,6 +7596,8 @@ pub const FuncGen = struct { | ... | @@ -7594,6 +7596,8 @@ pub const FuncGen = struct { |
| 7594 | const src_bits = operand_ty.floatBits(target); | 7596 | const src_bits = operand_ty.floatBits(target); |
| 7595 | if (!backendSupportsF80(target) and (src_bits == 80 or dest_bits == 80)) { | 7597 | if (!backendSupportsF80(target) and (src_bits == 80 or dest_bits == 80)) { |
| 7596 | return softF80TruncOrExt(self, operand, src_bits, dest_bits); | 7598 | return softF80TruncOrExt(self, operand, src_bits, dest_bits); |
| | 7599 | } else if (!backendSupportsF128(target) and (src_bits == 128 or dest_bits == 128)) { |
| | 7600 | return softF128TruncOrExt(self, operand, src_bits, dest_bits); |
| 7597 | } | 7601 | } |
| 7598 | const dest_llvm_ty = try self.dg.lowerType(self.air.typeOfIndex(inst)); | 7602 | const dest_llvm_ty = try self.dg.lowerType(self.air.typeOfIndex(inst)); |
| 7599 | return self.builder.buildFPExt(operand, dest_llvm_ty, ""); | 7603 | return self.builder.buildFPExt(operand, dest_llvm_ty, ""); |
| ... | @@ -9138,6 +9142,88 @@ pub const FuncGen = struct { | ... | @@ -9138,6 +9142,88 @@ pub const FuncGen = struct { |
| 9138 | return self.builder.buildBitCast(result, final_cast_llvm_ty, ""); | 9142 | return self.builder.buildBitCast(result, final_cast_llvm_ty, ""); |
| 9139 | } | 9143 | } |
| 9140 | | 9144 | |
| | 9145 | fn softF128TruncOrExt( |
| | 9146 | self: *FuncGen, |
| | 9147 | operand: *llvm.Value, |
| | 9148 | src_bits: u16, |
| | 9149 | dest_bits: u16, |
| | 9150 | ) !?*llvm.Value { |
| | 9151 | const target = self.dg.module.getTarget(); |
| | 9152 | |
| | 9153 | var param_llvm_ty: *llvm.Type = self.context.fp128Type(); |
| | 9154 | var ret_llvm_ty: *llvm.Type = param_llvm_ty; |
| | 9155 | var fn_name: [*:0]const u8 = undefined; |
| | 9156 | var arg = operand; |
| | 9157 | var final_cast: ?*llvm.Type = null; |
| | 9158 | |
| | 9159 | assert(src_bits == 128 or dest_bits == 128); |
| | 9160 | |
| | 9161 | // TODO: Implement proper names and compiler-rt functions for this!! |
| | 9162 | if (src_bits == 128) switch (dest_bits) { |
| | 9163 | 16 => { |
| | 9164 | // See corresponding condition at definition of |
| | 9165 | // __truncxfhf2 in compiler-rt. |
| | 9166 | if (target.cpu.arch.isAARCH64()) { |
| | 9167 | ret_llvm_ty = self.context.halfType(); |
| | 9168 | } else { |
| | 9169 | ret_llvm_ty = self.context.intType(16); |
| | 9170 | final_cast = self.context.halfType(); |
| | 9171 | } |
| | 9172 | fn_name = "__trunctfhf2"; |
| | 9173 | }, |
| | 9174 | 32 => { |
| | 9175 | ret_llvm_ty = self.context.floatType(); |
| | 9176 | fn_name = "__trunctfsf2"; |
| | 9177 | }, |
| | 9178 | 64 => { |
| | 9179 | ret_llvm_ty = self.context.doubleType(); |
| | 9180 | fn_name = "__trunctfdf2"; |
| | 9181 | }, |
| | 9182 | 80 => { |
| | 9183 | ret_llvm_ty = self.context.intType(80); |
| | 9184 | fn_name = "__trunctfxf2"; |
| | 9185 | }, |
| | 9186 | 128 => return operand, |
| | 9187 | else => unreachable, |
| | 9188 | } else switch (src_bits) { |
| | 9189 | 16 => { |
| | 9190 | // See corresponding condition at definition of |
| | 9191 | // __extendhftf2 in compiler-rt. |
| | 9192 | param_llvm_ty = if (target.cpu.arch.isAARCH64()) |
| | 9193 | self.context.halfType() |
| | 9194 | else |
| | 9195 | self.context.intType(16); |
| | 9196 | arg = self.builder.buildBitCast(arg, param_llvm_ty, ""); |
| | 9197 | fn_name = "__extendhftf2"; |
| | 9198 | }, |
| | 9199 | 32 => { |
| | 9200 | param_llvm_ty = self.context.floatType(); |
| | 9201 | fn_name = "__extendsftf2"; |
| | 9202 | }, |
| | 9203 | 64 => { |
| | 9204 | param_llvm_ty = self.context.doubleType(); |
| | 9205 | fn_name = "__extenddftf2"; |
| | 9206 | }, |
| | 9207 | 80 => { |
| | 9208 | param_llvm_ty = self.context.intType(80); |
| | 9209 | fn_name = "__extendxftf2"; |
| | 9210 | }, |
| | 9211 | 128 => return operand, |
| | 9212 | else => unreachable, |
| | 9213 | } |
| | 9214 | |
| | 9215 | const llvm_fn = self.dg.object.llvm_module.getNamedFunction(fn_name) orelse f: { |
| | 9216 | const param_types = [_]*llvm.Type{param_llvm_ty}; |
| | 9217 | const fn_type = llvm.functionType(ret_llvm_ty, &param_types, param_types.len, .False); |
| | 9218 | break :f self.dg.object.llvm_module.addFunction(fn_name, fn_type); |
| | 9219 | }; |
| | 9220 | |
| | 9221 | var args: [1]*llvm.Value = .{arg}; |
| | 9222 | const result = self.builder.buildCall(llvm_fn.globalGetValueType(), llvm_fn, &args, args.len, .C, .Auto, ""); |
| | 9223 | const final_cast_llvm_ty = final_cast orelse return result; |
| | 9224 | return self.builder.buildBitCast(result, final_cast_llvm_ty, ""); |
| | 9225 | } |
| | 9226 | |
| 9141 | fn getErrorNameTable(self: *FuncGen) !*llvm.Value { | 9227 | fn getErrorNameTable(self: *FuncGen) !*llvm.Value { |
| 9142 | if (self.dg.object.error_name_table) |table| { | 9228 | if (self.dg.object.error_name_table) |table| { |
| 9143 | return table; | 9229 | return table; |
| ... | @@ -10489,13 +10575,23 @@ fn backendSupportsF16(target: std.Target) bool { | ... | @@ -10489,13 +10575,23 @@ fn backendSupportsF16(target: std.Target) bool { |
| 10489 | }; | 10575 | }; |
| 10490 | } | 10576 | } |
| 10491 | | 10577 | |
| | 10578 | /// This function returns true if we expect LLVM to lower f128 correctly, |
| | 10579 | /// and false if we expect LLVm to crash if it encounters and f128 type |
| | 10580 | /// or if it produces miscompilations. |
| | 10581 | fn backendSupportsF128(target: std.Target) bool { |
| | 10582 | return switch (target.cpu.arch) { |
| | 10583 | .amdgcn => false, |
| | 10584 | else => true, |
| | 10585 | }; |
| | 10586 | } |
| | 10587 | |
| 10492 | /// LLVM does not support all relevant intrinsics for all targets, so we | 10588 | /// LLVM does not support all relevant intrinsics for all targets, so we |
| 10493 | /// may need to manually generate a libc call | 10589 | /// may need to manually generate a libc call |
| 10494 | fn intrinsicsAllowed(scalar_ty: Type, target: std.Target) bool { | 10590 | fn intrinsicsAllowed(scalar_ty: Type, target: std.Target) bool { |
| 10495 | return switch (scalar_ty.tag()) { | 10591 | return switch (scalar_ty.tag()) { |
| 10496 | .f16 => backendSupportsF16(target), | 10592 | .f16 => backendSupportsF16(target), |
| 10497 | .f80 => target.longDoubleIs(f80) and backendSupportsF80(target), | 10593 | .f80 => target.longDoubleIs(f80) and backendSupportsF80(target), |
| 10498 | .f128 => target.longDoubleIs(f128), | 10594 | .f128 => target.longDoubleIs(f128) and backendSupportsF128(target), |
| 10499 | else => true, | 10595 | else => true, |
| 10500 | }; | 10596 | }; |
| 10501 | } | 10597 | } |