| ... | ... | @@ -8282,8 +8282,7 @@ pub const FuncGen = struct { |
| 8282 | 8282 | const scalar_ty = ty.scalarType(mod); |
| 8283 | 8283 | const llvm_ty = try o.lowerType(ty); |
| 8284 | 8284 | |
| 8285 | | const intrinsics_allowed = op != .tan and intrinsicsAllowed(scalar_ty, target); |
| 8286 | | const strat: FloatOpStrat = if (intrinsics_allowed) switch (op) { |
| 8285 | if (op != .tan and intrinsicsAllowed(scalar_ty, target)) switch (op) { |
| 8287 | 8286 | // Some operations are dedicated LLVM instructions, not available as intrinsics |
| 8288 | 8287 | .neg => return self.wip.un(.fneg, params[0], ""), |
| 8289 | 8288 | .add => return self.wip.bin(.fadd, params[0], params[1], ""), |
| ... | ... | @@ -8293,83 +8292,84 @@ pub const FuncGen = struct { |
| 8293 | 8292 | .fmod => return self.wip.bin(.frem, params[0], params[1], ""), |
| 8294 | 8293 | .fmax => return self.wip.bin(.@"llvm.maxnum.", params[0], params[1], ""), |
| 8295 | 8294 | .fmin => return self.wip.bin(.@"llvm.minnum.", params[0], params[1], ""), |
| 8296 | | else => .{ .intrinsic = "llvm." ++ @tagName(op) }, |
| 8297 | | } else b: { |
| 8298 | | const float_bits = scalar_ty.floatBits(target); |
| 8299 | | break :b switch (op) { |
| 8300 | | .neg => { |
| 8301 | | // In this case we can generate a softfloat negation by XORing the |
| 8302 | | // bits with a constant. |
| 8303 | | const int_ty = try o.builder.intType(@intCast(float_bits)); |
| 8304 | | const cast_ty = try llvm_ty.changeScalar(int_ty, &o.builder); |
| 8305 | | const sign_mask = try o.builder.splatValue( |
| 8306 | | cast_ty, |
| 8307 | | try o.builder.intConst(int_ty, @as(u128, 1) << @intCast(float_bits - 1)), |
| 8308 | | ); |
| 8309 | | const bitcasted_operand = try self.wip.cast(.bitcast, params[0], cast_ty, ""); |
| 8310 | | const result = try self.wip.bin(.xor, bitcasted_operand, sign_mask, ""); |
| 8311 | | return self.wip.cast(.bitcast, result, llvm_ty, ""); |
| 8312 | | }, |
| 8313 | | .add, .sub, .div, .mul => .{ .libc = try o.builder.fmt("__{s}{s}f3", .{ |
| 8314 | | @tagName(op), compilerRtFloatAbbrev(float_bits), |
| 8315 | | }) }, |
| 8316 | | .ceil, |
| 8317 | | .cos, |
| 8318 | | .exp, |
| 8319 | | .exp2, |
| 8320 | | .fabs, |
| 8321 | | .floor, |
| 8322 | | .fma, |
| 8323 | | .fmax, |
| 8324 | | .fmin, |
| 8325 | | .fmod, |
| 8326 | | .log, |
| 8327 | | .log10, |
| 8328 | | .log2, |
| 8329 | | .round, |
| 8330 | | .sin, |
| 8331 | | .sqrt, |
| 8332 | | .tan, |
| 8333 | | .trunc, |
| 8334 | | => .{ .libc = try o.builder.fmt("{s}{s}{s}", .{ |
| 8335 | | libcFloatPrefix(float_bits), @tagName(op), libcFloatSuffix(float_bits), |
| 8336 | | }) }, |
| 8337 | | }; |
| 8295 | .ceil => return self.wip.un(.@"llvm.ceil.", params[0], ""), |
| 8296 | .cos => return self.wip.un(.@"llvm.cos.", params[0], ""), |
| 8297 | .exp => return self.wip.un(.@"llvm.exp.", params[0], ""), |
| 8298 | .exp2 => return self.wip.un(.@"llvm.exp2.", params[0], ""), |
| 8299 | .fabs => return self.wip.un(.@"llvm.fabs.", params[0], ""), |
| 8300 | .floor => return self.wip.un(.@"llvm.floor.", params[0], ""), |
| 8301 | .log => return self.wip.un(.@"llvm.log.", params[0], ""), |
| 8302 | .log10 => return self.wip.un(.@"llvm.log10.", params[0], ""), |
| 8303 | .log2 => return self.wip.un(.@"llvm.log2.", params[0], ""), |
| 8304 | .round => return self.wip.un(.@"llvm.round.", params[0], ""), |
| 8305 | .sin => return self.wip.un(.@"llvm.sin.", params[0], ""), |
| 8306 | .sqrt => return self.wip.un(.@"llvm.sqrt.", params[0], ""), |
| 8307 | .trunc => return self.wip.un(.@"llvm.trunc.", params[0], ""), |
| 8308 | .fma => return self.wip.fusedMultiplyAdd(params[0], params[1], params[2]), |
| 8309 | .tan => unreachable, |
| 8338 | 8310 | }; |
| 8339 | 8311 | |
| 8340 | | const llvm_fn = switch (strat) { |
| 8341 | | .intrinsic => |fn_name| try self.getIntrinsic(fn_name, &.{llvm_ty}), |
| 8342 | | .libc => |fn_name| b: { |
| 8343 | | const scalar_llvm_ty = llvm_ty.scalarType(&o.builder); |
| 8344 | | const libc_fn = try self.getLibcFunction( |
| 8345 | | fn_name, |
| 8346 | | ([1]Builder.Type{scalar_llvm_ty} ** 3)[0..params.len], |
| 8347 | | scalar_llvm_ty, |
| 8312 | const float_bits = scalar_ty.floatBits(target); |
| 8313 | const fn_name = switch (op) { |
| 8314 | .neg => { |
| 8315 | // In this case we can generate a softfloat negation by XORing the |
| 8316 | // bits with a constant. |
| 8317 | const int_ty = try o.builder.intType(@intCast(float_bits)); |
| 8318 | const cast_ty = try llvm_ty.changeScalar(int_ty, &o.builder); |
| 8319 | const sign_mask = try o.builder.splatValue( |
| 8320 | cast_ty, |
| 8321 | try o.builder.intConst(int_ty, @as(u128, 1) << @intCast(float_bits - 1)), |
| 8348 | 8322 | ); |
| 8349 | | if (ty.zigTypeTag(mod) == .Vector) { |
| 8350 | | const result = try o.builder.poisonValue(llvm_ty); |
| 8351 | | return self.buildElementwiseCall(libc_fn, &params, result, ty.vectorLen(mod)); |
| 8352 | | } |
| 8353 | | |
| 8354 | | break :b libc_fn.toLlvm(&o.builder); |
| 8323 | const bitcasted_operand = try self.wip.cast(.bitcast, params[0], cast_ty, ""); |
| 8324 | const result = try self.wip.bin(.xor, bitcasted_operand, sign_mask, ""); |
| 8325 | return self.wip.cast(.bitcast, result, llvm_ty, ""); |
| 8355 | 8326 | }, |
| 8327 | .add, .sub, .div, .mul => try o.builder.fmt("__{s}{s}f3", .{ |
| 8328 | @tagName(op), compilerRtFloatAbbrev(float_bits), |
| 8329 | }), |
| 8330 | .ceil, |
| 8331 | .cos, |
| 8332 | .exp, |
| 8333 | .exp2, |
| 8334 | .fabs, |
| 8335 | .floor, |
| 8336 | .fma, |
| 8337 | .fmax, |
| 8338 | .fmin, |
| 8339 | .fmod, |
| 8340 | .log, |
| 8341 | .log10, |
| 8342 | .log2, |
| 8343 | .round, |
| 8344 | .sin, |
| 8345 | .sqrt, |
| 8346 | .tan, |
| 8347 | .trunc, |
| 8348 | => try o.builder.fmt("{s}{s}{s}", .{ |
| 8349 | libcFloatPrefix(float_bits), @tagName(op), libcFloatSuffix(float_bits), |
| 8350 | }), |
| 8356 | 8351 | }; |
| 8357 | | const llvm_fn_ty = try o.builder.fnType( |
| 8358 | | llvm_ty, |
| 8359 | | ([1]Builder.Type{llvm_ty} ** 3)[0..params.len], |
| 8360 | | .normal, |
| 8352 | |
| 8353 | const scalar_llvm_ty = llvm_ty.scalarType(&o.builder); |
| 8354 | const libc_fn = try self.getLibcFunction( |
| 8355 | fn_name, |
| 8356 | ([1]Builder.Type{scalar_llvm_ty} ** 3)[0..params.len], |
| 8357 | scalar_llvm_ty, |
| 8361 | 8358 | ); |
| 8362 | | var llvm_params: [params_len]*llvm.Value = undefined; |
| 8363 | | for (&llvm_params, params) |*llvm_param, param| llvm_param.* = param.toLlvm(&self.wip); |
| 8364 | | return (try self.wip.unimplemented(llvm_ty, "")).finish(self.builder.buildCallOld( |
| 8365 | | llvm_fn_ty.toLlvm(&o.builder), |
| 8366 | | llvm_fn, |
| 8367 | | &llvm_params, |
| 8368 | | params_len, |
| 8369 | | .C, |
| 8370 | | .Auto, |
| 8359 | if (ty.zigTypeTag(mod) == .Vector) { |
| 8360 | const result = try o.builder.poisonValue(llvm_ty); |
| 8361 | return self.buildElementwiseCall(libc_fn, &params, result, ty.vectorLen(mod)); |
| 8362 | } |
| 8363 | |
| 8364 | return self.wip.call( |
| 8365 | .normal, |
| 8366 | .ccc, |
| 8367 | .none, |
| 8368 | libc_fn.typeOf(&o.builder), |
| 8369 | libc_fn.toValue(&o.builder), |
| 8370 | &params, |
| 8371 | 8371 | "", |
| 8372 | | ), &self.wip); |
| 8372 | ); |
| 8373 | 8373 | } |
| 8374 | 8374 | |
| 8375 | 8375 | fn airMulAdd(self: *FuncGen, inst: Air.Inst.Index) !Builder.Value { |