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