authorgravatar for robin@voetter.nlRobin Voetter <robin@voetter.nl> 2022-09-18 13:21:49+02:00
committergravatar for robin@voetter.nlRobin Voetter <robin@voetter.nl> 2022-10-12 20:36:14+02:00
log8894d1c45eb01fa3fbcc9173bac729e5812307ed
treedc9dd697bf30a1dc3e2d90f9b8e53983bc6ff2e0
parent76ad9cb10eeae5257eb51838953d0e3bcb993fa3
signaturelock-open Commit is signed but in an unrecognized format.

stage2: f128 improvements for targets that do not support it


1 files changed, 97 insertions(+), 1 deletions(-)

src/codegen/llvm.zig+97-1
......@@ -7576,6 +7576,8 @@ pub const FuncGen = struct {
75767576 const src_bits = operand_ty.floatBits(target);
75777577 if (!backendSupportsF80(target) and (src_bits == 80 or dest_bits == 80)) {
75787578 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);
75797581 }
75807582 const dest_llvm_ty = try self.dg.lowerType(dest_ty);
75817583 return self.builder.buildFPTrunc(operand, dest_llvm_ty, "");
......@@ -7594,6 +7596,8 @@ pub const FuncGen = struct {
75947596 const src_bits = operand_ty.floatBits(target);
75957597 if (!backendSupportsF80(target) and (src_bits == 80 or dest_bits == 80)) {
75967598 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);
75977601 }
75987602 const dest_llvm_ty = try self.dg.lowerType(self.air.typeOfIndex(inst));
75997603 return self.builder.buildFPExt(operand, dest_llvm_ty, "");
......@@ -9138,6 +9142,88 @@ pub const FuncGen = struct {
91389142 return self.builder.buildBitCast(result, final_cast_llvm_ty, "");
91399143 }
91409144
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
91419227 fn getErrorNameTable(self: *FuncGen) !*llvm.Value {
91429228 if (self.dg.object.error_name_table) |table| {
91439229 return table;
......@@ -10489,13 +10575,23 @@ fn backendSupportsF16(target: std.Target) bool {
1048910575 };
1049010576}
1049110577
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.
10581fn backendSupportsF128(target: std.Target) bool {
10582 return switch (target.cpu.arch) {
10583 .amdgcn => false,
10584 else => true,
10585 };
10586}
10587
1049210588/// LLVM does not support all relevant intrinsics for all targets, so we
1049310589/// may need to manually generate a libc call
1049410590fn intrinsicsAllowed(scalar_ty: Type, target: std.Target) bool {
1049510591 return switch (scalar_ty.tag()) {
1049610592 .f16 => backendSupportsF16(target),
1049710593 .f80 => target.longDoubleIs(f80) and backendSupportsF80(target),
10498 .f128 => target.longDoubleIs(f128),
10594 .f128 => target.longDoubleIs(f128) and backendSupportsF128(target),
1049910595 else => true,
1050010596 };
1050110597}