authorgravatar for jacobly@ziglang.orgJacob Young <jacobly@ziglang.org> 2023-08-05 23:05:02-04:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2023-08-05 23:05:02-04:00
log1c7798a3cde9e8dad31c276aab4c1affb2043ad2
tree870480a2191982b63e6b4a29152e26db373a286b
parent68f84964b3d80e5b976810208a14c31268a181e1
parente149f1e1de8f79a66a97da1700d9a64fc2983211
signaturebadge-question-mark Signed by PGP key 4AEE18F83AFDEB23

Merge pull request #16705 from antlilja/builder-intrinsics

Implement more intrinsics in new LLVM IR builder API and remove uses of LLVM owns API

5 files changed, 461 insertions(+), 133 deletions(-)

src/codegen/llvm.zig+83-133
......@@ -5100,11 +5100,11 @@ pub const FuncGen = struct {
51005100 .memcpy => try self.airMemcpy(inst),
51015101 .set_union_tag => try self.airSetUnionTag(inst),
51025102 .get_union_tag => try self.airGetUnionTag(inst),
5103 .clz => try self.airClzCtz(inst, "llvm.ctlz"),
5104 .ctz => try self.airClzCtz(inst, "llvm.cttz"),
5105 .popcount => try self.airBitOp(inst, "llvm.ctpop"),
5106 .byte_swap => try self.airByteSwap(inst, "llvm.bswap"),
5107 .bit_reverse => try self.airBitOp(inst, "llvm.bitreverse"),
5103 .clz => try self.airClzCtz(inst, .@"llvm.ctlz."),
5104 .ctz => try self.airClzCtz(inst, .@"llvm.cttz."),
5105 .popcount => try self.airBitOp(inst, .@"llvm.ctpop."),
5106 .byte_swap => try self.airByteSwap(inst),
5107 .bit_reverse => try self.airBitOp(inst, .@"llvm.bitreverse."),
51085108 .tag_name => try self.airTagName(inst),
51095109 .error_name => try self.airErrorName(inst),
51105110 .splat => try self.airSplat(inst),
......@@ -8282,8 +8282,7 @@ pub const FuncGen = struct {
82828282 const scalar_ty = ty.scalarType(mod);
82838283 const llvm_ty = try o.lowerType(ty);
82848284
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) {
82878286 // Some operations are dedicated LLVM instructions, not available as intrinsics
82888287 .neg => return self.wip.un(.fneg, params[0], ""),
82898288 .add => return self.wip.bin(.fadd, params[0], params[1], ""),
......@@ -8293,83 +8292,84 @@ pub const FuncGen = struct {
82938292 .fmod => return self.wip.bin(.frem, params[0], params[1], ""),
82948293 .fmax => return self.wip.bin(.@"llvm.maxnum.", params[0], params[1], ""),
82958294 .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,
83388310 };
83398311
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)),
83488322 );
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, "");
83558326 },
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 }),
83568351 };
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,
83618358 );
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,
83718371 "",
8372 ), &self.wip);
8372 );
83738373 }
83748374
83758375 fn airMulAdd(self: *FuncGen, inst: Air.Inst.Index) !Builder.Value {
......@@ -9526,64 +9526,29 @@ pub const FuncGen = struct {
95269526 return self.buildFloatOp(.neg, operand_ty, 1, .{operand});
95279527 }
95289528
9529 fn airClzCtz(self: *FuncGen, inst: Air.Inst.Index, llvm_fn_name: []const u8) !Builder.Value {
9529 fn airClzCtz(self: *FuncGen, inst: Air.Inst.Index, intrinsic: Builder.Function.Instruction.Tag) !Builder.Value {
95309530 const o = self.dg.object;
95319531 const ty_op = self.air.instructions.items(.data)[inst].ty_op;
9532 const operand_ty = self.typeOf(ty_op.operand);
95339532 const operand = try self.resolveInst(ty_op.operand);
95349533
9535 const llvm_operand_ty = try o.lowerType(operand_ty);
9536 const llvm_fn_ty = try o.builder.fnType(llvm_operand_ty, &.{ llvm_operand_ty, .i1 }, .normal);
9537 const fn_val = try self.getIntrinsic(llvm_fn_name, &.{llvm_operand_ty});
9534 const wrong_size_result = try self.wip.bin(intrinsic, operand, (try o.builder.intConst(.i1, 0)).toValue(), "");
95389535
9539 const params = [_]*llvm.Value{
9540 operand.toLlvm(&self.wip),
9541 Builder.Constant.false.toLlvm(&o.builder),
9542 };
9543 const wrong_size_result = (try self.wip.unimplemented(llvm_operand_ty, "")).finish(
9544 self.builder.buildCallOld(
9545 llvm_fn_ty.toLlvm(&o.builder),
9546 fn_val,
9547 &params,
9548 params.len,
9549 .C,
9550 .Auto,
9551 "",
9552 ),
9553 &self.wip,
9554 );
95559536 const result_ty = self.typeOfIndex(inst);
95569537 return self.wip.conv(.unsigned, wrong_size_result, try o.lowerType(result_ty), "");
95579538 }
95589539
9559 fn airBitOp(self: *FuncGen, inst: Air.Inst.Index, llvm_fn_name: []const u8) !Builder.Value {
9540 fn airBitOp(self: *FuncGen, inst: Air.Inst.Index, intrinsic: Builder.Function.Instruction.Tag) !Builder.Value {
95609541 const o = self.dg.object;
95619542 const ty_op = self.air.instructions.items(.data)[inst].ty_op;
9562 const operand_ty = self.typeOf(ty_op.operand);
95639543 const operand = try self.resolveInst(ty_op.operand);
95649544
9565 const llvm_operand_ty = try o.lowerType(operand_ty);
9566 const llvm_fn_ty = try o.builder.fnType(llvm_operand_ty, &.{llvm_operand_ty}, .normal);
9567 const fn_val = try self.getIntrinsic(llvm_fn_name, &.{llvm_operand_ty});
9545 const wrong_size_result = try self.wip.un(intrinsic, operand, "");
95689546
9569 const params = [_]*llvm.Value{operand.toLlvm(&self.wip)};
9570 const wrong_size_result = (try self.wip.unimplemented(llvm_operand_ty, "")).finish(
9571 self.builder.buildCallOld(
9572 llvm_fn_ty.toLlvm(&o.builder),
9573 fn_val,
9574 &params,
9575 params.len,
9576 .C,
9577 .Auto,
9578 "",
9579 ),
9580 &self.wip,
9581 );
95829547 const result_ty = self.typeOfIndex(inst);
95839548 return self.wip.conv(.unsigned, wrong_size_result, try o.lowerType(result_ty), "");
95849549 }
95859550
9586 fn airByteSwap(self: *FuncGen, inst: Air.Inst.Index, llvm_fn_name: []const u8) !Builder.Value {
9551 fn airByteSwap(self: *FuncGen, inst: Air.Inst.Index) !Builder.Value {
95879552 const o = self.dg.object;
95889553 const mod = o.module;
95899554 const ty_op = self.air.instructions.items(.data)[inst].ty_op;
......@@ -9611,22 +9576,7 @@ pub const FuncGen = struct {
96119576 bits = bits + 8;
96129577 }
96139578
9614 const llvm_fn_ty = try o.builder.fnType(llvm_operand_ty, &.{llvm_operand_ty}, .normal);
9615 const fn_val = try self.getIntrinsic(llvm_fn_name, &.{llvm_operand_ty});
9616
9617 const params = [_]*llvm.Value{operand.toLlvm(&self.wip)};
9618 const wrong_size_result = (try self.wip.unimplemented(llvm_operand_ty, "")).finish(
9619 self.builder.buildCallOld(
9620 llvm_fn_ty.toLlvm(&o.builder),
9621 fn_val,
9622 &params,
9623 params.len,
9624 .C,
9625 .Auto,
9626 "",
9627 ),
9628 &self.wip,
9629 );
9579 const wrong_size_result = try self.wip.un(.@"llvm.bswap.", operand, "");
96309580
96319581 const result_ty = self.typeOfIndex(inst);
96329582 return self.wip.conv(.unsigned, wrong_size_result, try o.lowerType(result_ty), "");
src/codegen/llvm/Builder.zig+198
......@@ -2416,6 +2416,25 @@ pub const Function = struct {
24162416 inttoptr,
24172417 @"llvm.maxnum.",
24182418 @"llvm.minnum.",
2419 @"llvm.ceil.",
2420 @"llvm.cos.",
2421 @"llvm.exp.",
2422 @"llvm.exp2.",
2423 @"llvm.fabs.",
2424 @"llvm.floor.",
2425 @"llvm.log.",
2426 @"llvm.log10.",
2427 @"llvm.log2.",
2428 @"llvm.round.",
2429 @"llvm.sin.",
2430 @"llvm.sqrt.",
2431 @"llvm.trunc.",
2432 @"llvm.fma.",
2433 @"llvm.bitreverse.",
2434 @"llvm.bswap.",
2435 @"llvm.ctpop.",
2436 @"llvm.ctlz.",
2437 @"llvm.cttz.",
24192438 @"llvm.sadd.sat.",
24202439 @"llvm.smax.",
24212440 @"llvm.smin.",
......@@ -2558,6 +2577,8 @@ pub const Function = struct {
25582577 .@"fsub fast",
25592578 .@"llvm.maxnum.",
25602579 .@"llvm.minnum.",
2580 .@"llvm.ctlz.",
2581 .@"llvm.cttz.",
25612582 .@"llvm.sadd.sat.",
25622583 .@"llvm.smax.",
25632584 .@"llvm.smin.",
......@@ -2689,6 +2710,22 @@ pub const Function = struct {
26892710 .changeScalarAssumeCapacity(.i1, wip.builder),
26902711 .fneg,
26912712 .@"fneg fast",
2713 .@"llvm.ceil.",
2714 .@"llvm.cos.",
2715 .@"llvm.exp.",
2716 .@"llvm.exp2.",
2717 .@"llvm.fabs.",
2718 .@"llvm.floor.",
2719 .@"llvm.log.",
2720 .@"llvm.log10.",
2721 .@"llvm.log2.",
2722 .@"llvm.round.",
2723 .@"llvm.sin.",
2724 .@"llvm.sqrt.",
2725 .@"llvm.trunc.",
2726 .@"llvm.bitreverse.",
2727 .@"llvm.bswap.",
2728 .@"llvm.ctpop.",
26922729 => @as(Value, @enumFromInt(instruction.data)).typeOfWip(wip),
26932730 .getelementptr,
26942731 .@"getelementptr inbounds",
......@@ -2725,6 +2762,7 @@ pub const Function = struct {
27252762 },
27262763 .unimplemented => @enumFromInt(instruction.data),
27272764 .va_arg => wip.extraData(VaArg, instruction.data).type,
2765 .@"llvm.fma." => wip.extraData(FusedMultiplyAdd, instruction.data).a.typeOfWip(wip),
27282766 };
27292767 }
27302768
......@@ -2755,6 +2793,8 @@ pub const Function = struct {
27552793 .@"fsub fast",
27562794 .@"llvm.maxnum.",
27572795 .@"llvm.minnum.",
2796 .@"llvm.ctlz.",
2797 .@"llvm.cttz.",
27582798 .@"llvm.sadd.sat.",
27592799 .@"llvm.smax.",
27602800 .@"llvm.smin.",
......@@ -2887,6 +2927,22 @@ pub const Function = struct {
28872927 .changeScalarAssumeCapacity(.i1, builder),
28882928 .fneg,
28892929 .@"fneg fast",
2930 .@"llvm.ceil.",
2931 .@"llvm.cos.",
2932 .@"llvm.exp.",
2933 .@"llvm.exp2.",
2934 .@"llvm.fabs.",
2935 .@"llvm.floor.",
2936 .@"llvm.log.",
2937 .@"llvm.log10.",
2938 .@"llvm.log2.",
2939 .@"llvm.round.",
2940 .@"llvm.sin.",
2941 .@"llvm.sqrt.",
2942 .@"llvm.trunc.",
2943 .@"llvm.bitreverse.",
2944 .@"llvm.bswap.",
2945 .@"llvm.ctpop.",
28902946 => @as(Value, @enumFromInt(instruction.data)).typeOf(function_index, builder),
28912947 .getelementptr,
28922948 .@"getelementptr inbounds",
......@@ -2925,6 +2981,7 @@ pub const Function = struct {
29252981 },
29262982 .unimplemented => @enumFromInt(instruction.data),
29272983 .va_arg => function.extraData(VaArg, instruction.data).type,
2984 .@"llvm.fma." => function.extraData(FusedMultiplyAdd, instruction.data).a.typeOf(function_index, builder),
29282985 };
29292986 }
29302987
......@@ -3017,6 +3074,12 @@ pub const Function = struct {
30173074 mask: Value,
30183075 };
30193076
3077 pub const FusedMultiplyAdd = struct {
3078 a: Value,
3079 b: Value,
3080 c: Value,
3081 };
3082
30203083 pub const ExtractValue = struct {
30213084 val: Value,
30223085 indices_len: u32,
......@@ -3424,7 +3487,24 @@ pub const WipFunction = struct {
34243487 switch (tag) {
34253488 .fneg,
34263489 .@"fneg fast",
3490 .@"llvm.ceil.",
3491 .@"llvm.cos.",
3492 .@"llvm.exp.",
3493 .@"llvm.exp2.",
3494 .@"llvm.fabs.",
3495 .@"llvm.floor.",
3496 .@"llvm.log.",
3497 .@"llvm.log10.",
3498 .@"llvm.log2.",
3499 .@"llvm.round.",
3500 .@"llvm.sin.",
3501 .@"llvm.sqrt.",
3502 .@"llvm.trunc.",
34273503 => assert(val.typeOfWip(self).scalarType(self.builder).isFloatingPoint()),
3504 .@"llvm.bitreverse.",
3505 .@"llvm.bswap.",
3506 .@"llvm.ctpop.",
3507 => assert(val.typeOfWip(self).scalarType(self.builder).isInteger(self.builder)),
34283508 else => unreachable,
34293509 }
34303510 try self.ensureUnusedExtraCapacity(1, NoExtra, 0);
......@@ -3433,10 +3513,43 @@ pub const WipFunction = struct {
34333513 switch (tag) {
34343514 .fneg => self.llvm.builder.setFastMath(false),
34353515 .@"fneg fast" => self.llvm.builder.setFastMath(true),
3516 .@"llvm.ceil.",
3517 .@"llvm.cos.",
3518 .@"llvm.exp.",
3519 .@"llvm.exp2.",
3520 .@"llvm.fabs.",
3521 .@"llvm.floor.",
3522 .@"llvm.log.",
3523 .@"llvm.log10.",
3524 .@"llvm.log2.",
3525 .@"llvm.round.",
3526 .@"llvm.sin.",
3527 .@"llvm.sqrt.",
3528 .@"llvm.trunc.",
3529 .@"llvm.bitreverse.",
3530 .@"llvm.bswap.",
3531 .@"llvm.ctpop.",
3532 => {},
34363533 else => unreachable,
34373534 }
34383535 self.llvm.instructions.appendAssumeCapacity(switch (tag) {
34393536 .fneg, .@"fneg fast" => &llvm.Builder.buildFNeg,
3537 .@"llvm.ceil." => &llvm.Builder.buildCeil,
3538 .@"llvm.cos." => &llvm.Builder.buildCos,
3539 .@"llvm.exp." => &llvm.Builder.buildExp,
3540 .@"llvm.exp2." => &llvm.Builder.buildExp2,
3541 .@"llvm.fabs." => &llvm.Builder.buildFAbs,
3542 .@"llvm.floor." => &llvm.Builder.buildFloor,
3543 .@"llvm.log." => &llvm.Builder.buildLog,
3544 .@"llvm.log10." => &llvm.Builder.buildLog10,
3545 .@"llvm.log2." => &llvm.Builder.buildLog2,
3546 .@"llvm.round." => &llvm.Builder.buildRound,
3547 .@"llvm.sin." => &llvm.Builder.buildSin,
3548 .@"llvm.sqrt." => &llvm.Builder.buildSqrt,
3549 .@"llvm.trunc." => &llvm.Builder.buildFTrunc,
3550 .@"llvm.bitreverse." => &llvm.Builder.buildBitReverse,
3551 .@"llvm.bswap." => &llvm.Builder.buildBSwap,
3552 .@"llvm.ctpop." => &llvm.Builder.buildCTPop,
34403553 else => unreachable,
34413554 }(self.llvm.builder, val.toLlvm(self), instruction.llvmName(self)));
34423555 }
......@@ -3514,6 +3627,9 @@ pub const WipFunction = struct {
35143627 .urem,
35153628 .xor,
35163629 => assert(lhs.typeOfWip(self) == rhs.typeOfWip(self)),
3630 .@"llvm.ctlz.",
3631 .@"llvm.cttz.",
3632 => assert(lhs.typeOfWip(self).scalarType(self.builder).isInteger(self.builder) and rhs.typeOfWip(self) == .i1),
35173633 else => unreachable,
35183634 }
35193635 try self.ensureUnusedExtraCapacity(1, Instruction.Binary, 0);
......@@ -3551,6 +3667,8 @@ pub const WipFunction = struct {
35513667 .fsub, .@"fsub fast" => &llvm.Builder.buildFSub,
35523668 .@"llvm.maxnum." => &llvm.Builder.buildMaxNum,
35533669 .@"llvm.minnum." => &llvm.Builder.buildMinNum,
3670 .@"llvm.ctlz." => &llvm.Builder.buildCTLZ,
3671 .@"llvm.cttz." => &llvm.Builder.buildCTTZ,
35543672 .@"llvm.sadd.sat." => &llvm.Builder.buildSAddSat,
35553673 .@"llvm.smax." => &llvm.Builder.buildSMax,
35563674 .@"llvm.smin." => &llvm.Builder.buildSMin,
......@@ -4330,6 +4448,29 @@ pub const WipFunction = struct {
43304448 return instruction.toValue();
43314449 }
43324450
4451 pub fn fusedMultiplyAdd(self: *WipFunction, a: Value, b: Value, c: Value) Allocator.Error!Value {
4452 assert(a.typeOfWip(self) == b.typeOfWip(self) and a.typeOfWip(self) == c.typeOfWip(self));
4453 try self.ensureUnusedExtraCapacity(1, Instruction.FusedMultiplyAdd, 0);
4454 const instruction = try self.addInst("", .{
4455 .tag = .@"llvm.fma.",
4456 .data = self.addExtraAssumeCapacity(Instruction.FusedMultiplyAdd{
4457 .a = a,
4458 .b = b,
4459 .c = c,
4460 }),
4461 });
4462 if (self.builder.useLibLlvm()) {
4463 self.llvm.instructions.appendAssumeCapacity(llvm.Builder.buildFMA(
4464 self.llvm.builder,
4465 a.toLlvm(self),
4466 b.toLlvm(self),
4467 c.toLlvm(self),
4468 instruction.llvmName(self),
4469 ));
4470 }
4471 return instruction.toValue();
4472 }
4473
43334474 pub const WipUnimplemented = struct {
43344475 instruction: Instruction.Index,
43354476
......@@ -4558,6 +4699,8 @@ pub const WipFunction = struct {
45584699 .@"icmp ult",
45594700 .@"llvm.maxnum.",
45604701 .@"llvm.minnum.",
4702 .@"llvm.ctlz.",
4703 .@"llvm.cttz.",
45614704 .@"llvm.sadd.sat.",
45624705 .@"llvm.smax.",
45634706 .@"llvm.smin.",
......@@ -4685,6 +4828,22 @@ pub const WipFunction = struct {
46854828 .fneg,
46864829 .@"fneg fast",
46874830 .ret,
4831 .@"llvm.ceil.",
4832 .@"llvm.cos.",
4833 .@"llvm.exp.",
4834 .@"llvm.exp2.",
4835 .@"llvm.fabs.",
4836 .@"llvm.floor.",
4837 .@"llvm.log.",
4838 .@"llvm.log10.",
4839 .@"llvm.log2.",
4840 .@"llvm.round.",
4841 .@"llvm.sin.",
4842 .@"llvm.sqrt.",
4843 .@"llvm.trunc.",
4844 .@"llvm.bitreverse.",
4845 .@"llvm.bswap.",
4846 .@"llvm.ctpop.",
46884847 => instruction.data = @intFromEnum(instructions.map(@enumFromInt(instruction.data))),
46894848 .getelementptr,
46904849 .@"getelementptr inbounds",
......@@ -4790,6 +4949,14 @@ pub const WipFunction = struct {
47904949 .type = extra.type,
47914950 });
47924951 },
4952 .@"llvm.fma." => {
4953 const extra = self.extraData(Instruction.FusedMultiplyAdd, instruction.data);
4954 instruction.data = wip_extra.addExtra(Instruction.FusedMultiplyAdd{
4955 .a = instructions.map(extra.a),
4956 .b = instructions.map(extra.b),
4957 .c = instructions.map(extra.c),
4958 });
4959 },
47934960 }
47944961 function.instructions.appendAssumeCapacity(instruction);
47954962 names[@intFromEnum(new_instruction_index)] = wip_name.map(if (self.builder.strip)
......@@ -7561,6 +7728,22 @@ pub fn printUnbuffered(
75617728 .fneg,
75627729 .@"fneg fast",
75637730 .ret,
7731 .@"llvm.ceil.",
7732 .@"llvm.cos.",
7733 .@"llvm.exp.",
7734 .@"llvm.exp2.",
7735 .@"llvm.fabs.",
7736 .@"llvm.floor.",
7737 .@"llvm.log.",
7738 .@"llvm.log10.",
7739 .@"llvm.log2.",
7740 .@"llvm.round.",
7741 .@"llvm.sin.",
7742 .@"llvm.sqrt.",
7743 .@"llvm.trunc.",
7744 .@"llvm.bitreverse.",
7745 .@"llvm.bswap.",
7746 .@"llvm.ctpop.",
75647747 => |tag| {
75657748 const val: Value = @enumFromInt(instruction.data);
75667749 try writer.print(" {s} {%}\n", .{
......@@ -7617,6 +7800,8 @@ pub fn printUnbuffered(
76177800 },
76187801 .@"llvm.maxnum.",
76197802 .@"llvm.minnum.",
7803 .@"llvm.ctlz.",
7804 .@"llvm.cttz.",
76207805 .@"llvm.sadd.sat.",
76217806 .@"llvm.smax.",
76227807 .@"llvm.smin.",
......@@ -7781,6 +7966,19 @@ pub fn printUnbuffered(
77817966 extra.type.fmt(self),
77827967 });
77837968 },
7969 .@"llvm.fma." => {
7970 const extra =
7971 function.extraData(Function.Instruction.FusedMultiplyAdd, instruction.data);
7972 const ty = instruction_index.typeOf(function_index, self);
7973 try writer.print(" %{} = call {%} @llvm.fma.{m}({%}, {%}, {%})\n", .{
7974 instruction_index.name(&function).fmt(self),
7975 ty.fmt(self),
7976 ty.fmt(self),
7977 extra.a.fmt(function_index, self),
7978 extra.b.fmt(function_index, self),
7979 extra.c.fmt(function_index, self),
7980 });
7981 },
77847982 }
77857983 }
77867984 try writer.writeByte('}');
src/codegen/llvm/bindings.zig+57
......@@ -1026,6 +1026,63 @@ pub const Builder = opaque {
10261026 pub const buildMinNum = ZigLLVMBuildMinNum;
10271027 extern fn ZigLLVMBuildMinNum(builder: *Builder, LHS: *Value, RHS: *Value, name: [*:0]const u8) *Value;
10281028
1029 pub const buildCeil = ZigLLVMBuildCeil;
1030 extern fn ZigLLVMBuildCeil(builder: *Builder, V: *Value, name: [*:0]const u8) *Value;
1031
1032 pub const buildCos = ZigLLVMBuildCos;
1033 extern fn ZigLLVMBuildCos(builder: *Builder, V: *Value, name: [*:0]const u8) *Value;
1034
1035 pub const buildExp = ZigLLVMBuildExp;
1036 extern fn ZigLLVMBuildExp(builder: *Builder, V: *Value, name: [*:0]const u8) *Value;
1037
1038 pub const buildExp2 = ZigLLVMBuildExp2;
1039 extern fn ZigLLVMBuildExp2(builder: *Builder, V: *Value, name: [*:0]const u8) *Value;
1040
1041 pub const buildFAbs = ZigLLVMBuildFAbs;
1042 extern fn ZigLLVMBuildFAbs(builder: *Builder, V: *Value, name: [*:0]const u8) *Value;
1043
1044 pub const buildFloor = ZigLLVMBuildFloor;
1045 extern fn ZigLLVMBuildFloor(builder: *Builder, V: *Value, name: [*:0]const u8) *Value;
1046
1047 pub const buildLog = ZigLLVMBuildLog;
1048 extern fn ZigLLVMBuildLog(builder: *Builder, V: *Value, name: [*:0]const u8) *Value;
1049
1050 pub const buildLog10 = ZigLLVMBuildLog10;
1051 extern fn ZigLLVMBuildLog10(builder: *Builder, V: *Value, name: [*:0]const u8) *Value;
1052
1053 pub const buildLog2 = ZigLLVMBuildLog2;
1054 extern fn ZigLLVMBuildLog2(builder: *Builder, V: *Value, name: [*:0]const u8) *Value;
1055
1056 pub const buildRound = ZigLLVMBuildRound;
1057 extern fn ZigLLVMBuildRound(builder: *Builder, V: *Value, name: [*:0]const u8) *Value;
1058
1059 pub const buildSin = ZigLLVMBuildSin;
1060 extern fn ZigLLVMBuildSin(builder: *Builder, V: *Value, name: [*:0]const u8) *Value;
1061
1062 pub const buildSqrt = ZigLLVMBuildSqrt;
1063 extern fn ZigLLVMBuildSqrt(builder: *Builder, V: *Value, name: [*:0]const u8) *Value;
1064
1065 pub const buildFTrunc = ZigLLVMBuildFTrunc;
1066 extern fn ZigLLVMBuildFTrunc(builder: *Builder, V: *Value, name: [*:0]const u8) *Value;
1067
1068 pub const buildBitReverse = ZigLLVMBuildBitReverse;
1069 extern fn ZigLLVMBuildBitReverse(builder: *Builder, V: *Value, name: [*:0]const u8) *Value;
1070
1071 pub const buildBSwap = ZigLLVMBuildBSwap;
1072 extern fn ZigLLVMBuildBSwap(builder: *Builder, V: *Value, name: [*:0]const u8) *Value;
1073
1074 pub const buildCTPop = ZigLLVMBuildCTPop;
1075 extern fn ZigLLVMBuildCTPop(builder: *Builder, V: *Value, name: [*:0]const u8) *Value;
1076
1077 pub const buildCTLZ = ZigLLVMBuildCTLZ;
1078 extern fn ZigLLVMBuildCTLZ(builder: *Builder, LHS: *Value, RHS: *Value, name: [*:0]const u8) *Value;
1079
1080 pub const buildCTTZ = ZigLLVMBuildCTTZ;
1081 extern fn ZigLLVMBuildCTTZ(builder: *Builder, LHS: *Value, RHS: *Value, name: [*:0]const u8) *Value;
1082
1083 pub const buildFMA = ZigLLVMBuildFMA;
1084 extern fn ZigLLVMBuildFMA(builder: *Builder, a: *Value, b: *Value, c: *Value, name: [*:0]const u8) *Value;
1085
10291086 pub const buildUMax = ZigLLVMBuildUMax;
10301087 extern fn ZigLLVMBuildUMax(builder: *Builder, LHS: *Value, RHS: *Value, name: [*:0]const u8) *Value;
10311088
src/zig_llvm.cpp+100
......@@ -481,6 +481,106 @@ LLVMValueRef ZigLLVMBuildMemSet(LLVMBuilderRef B, LLVMValueRef Ptr, LLVMValueRef
481481 return wrap(call_inst);
482482}
483483
484LLVMValueRef ZigLLVMBuildCeil(LLVMBuilderRef B, LLVMValueRef V, const char *name) {
485 CallInst *call_inst = unwrap(B)->CreateUnaryIntrinsic(Intrinsic::ceil, unwrap(V), nullptr, name);
486 return wrap(call_inst);
487}
488
489LLVMValueRef ZigLLVMBuildCos(LLVMBuilderRef B, LLVMValueRef V, const char *name) {
490 CallInst *call_inst = unwrap(B)->CreateUnaryIntrinsic(Intrinsic::cos, unwrap(V), nullptr, name);
491 return wrap(call_inst);
492}
493
494LLVMValueRef ZigLLVMBuildExp(LLVMBuilderRef B, LLVMValueRef V, const char *name) {
495 CallInst *call_inst = unwrap(B)->CreateUnaryIntrinsic(Intrinsic::exp, unwrap(V), nullptr, name);
496 return wrap(call_inst);
497}
498
499LLVMValueRef ZigLLVMBuildExp2(LLVMBuilderRef B, LLVMValueRef V, const char *name) {
500 CallInst *call_inst = unwrap(B)->CreateUnaryIntrinsic(Intrinsic::exp2, unwrap(V), nullptr, name);
501 return wrap(call_inst);
502}
503
504LLVMValueRef ZigLLVMBuildFAbs(LLVMBuilderRef B, LLVMValueRef V, const char *name) {
505 CallInst *call_inst = unwrap(B)->CreateUnaryIntrinsic(Intrinsic::fabs, unwrap(V), nullptr, name);
506 return wrap(call_inst);
507}
508
509LLVMValueRef ZigLLVMBuildFloor(LLVMBuilderRef B, LLVMValueRef V, const char *name) {
510 CallInst *call_inst = unwrap(B)->CreateUnaryIntrinsic(Intrinsic::floor, unwrap(V), nullptr, name);
511 return wrap(call_inst);
512}
513
514LLVMValueRef ZigLLVMBuildLog(LLVMBuilderRef B, LLVMValueRef V, const char *name) {
515 CallInst *call_inst = unwrap(B)->CreateUnaryIntrinsic(Intrinsic::log, unwrap(V), nullptr, name);
516 return wrap(call_inst);
517}
518
519LLVMValueRef ZigLLVMBuildLog10(LLVMBuilderRef B, LLVMValueRef V, const char *name) {
520 CallInst *call_inst = unwrap(B)->CreateUnaryIntrinsic(Intrinsic::log10, unwrap(V), nullptr, name);
521 return wrap(call_inst);
522}
523
524LLVMValueRef ZigLLVMBuildLog2(LLVMBuilderRef B, LLVMValueRef V, const char *name) {
525 CallInst *call_inst = unwrap(B)->CreateUnaryIntrinsic(Intrinsic::log2, unwrap(V), nullptr, name);
526 return wrap(call_inst);
527}
528
529LLVMValueRef ZigLLVMBuildRound(LLVMBuilderRef B, LLVMValueRef V, const char *name) {
530 CallInst *call_inst = unwrap(B)->CreateUnaryIntrinsic(Intrinsic::round, unwrap(V), nullptr, name);
531 return wrap(call_inst);
532}
533
534LLVMValueRef ZigLLVMBuildSin(LLVMBuilderRef B, LLVMValueRef V, const char *name) {
535 CallInst *call_inst = unwrap(B)->CreateUnaryIntrinsic(Intrinsic::sin, unwrap(V), nullptr, name);
536 return wrap(call_inst);
537}
538
539LLVMValueRef ZigLLVMBuildSqrt(LLVMBuilderRef B, LLVMValueRef V, const char *name) {
540 CallInst *call_inst = unwrap(B)->CreateUnaryIntrinsic(Intrinsic::sqrt, unwrap(V), nullptr, name);
541 return wrap(call_inst);
542}
543
544LLVMValueRef ZigLLVMBuildFTrunc(LLVMBuilderRef B, LLVMValueRef V, const char *name) {
545 CallInst *call_inst = unwrap(B)->CreateUnaryIntrinsic(Intrinsic::trunc, unwrap(V), nullptr, name);
546 return wrap(call_inst);
547}
548
549LLVMValueRef ZigLLVMBuildBitReverse(LLVMBuilderRef B, LLVMValueRef V, const char *name) {
550 CallInst *call_inst = unwrap(B)->CreateUnaryIntrinsic(Intrinsic::bitreverse, unwrap(V), nullptr, name);
551 return wrap(call_inst);
552}
553
554LLVMValueRef ZigLLVMBuildBSwap(LLVMBuilderRef B, LLVMValueRef V, const char *name) {
555 CallInst *call_inst = unwrap(B)->CreateUnaryIntrinsic(Intrinsic::bswap, unwrap(V), nullptr, name);
556 return wrap(call_inst);
557}
558
559LLVMValueRef ZigLLVMBuildCTPop(LLVMBuilderRef B, LLVMValueRef V, const char *name) {
560 CallInst *call_inst = unwrap(B)->CreateUnaryIntrinsic(Intrinsic::ctpop, unwrap(V), nullptr, name);
561 return wrap(call_inst);
562}
563
564LLVMValueRef ZigLLVMBuildCTLZ(LLVMBuilderRef B, LLVMValueRef LHS, LLVMValueRef RHS, const char *name) {
565 CallInst *call_inst = unwrap(B)->CreateBinaryIntrinsic(Intrinsic::ctlz, unwrap(LHS), unwrap(RHS), nullptr, name);
566 return wrap(call_inst);
567}
568
569LLVMValueRef ZigLLVMBuildCTTZ(LLVMBuilderRef B, LLVMValueRef LHS, LLVMValueRef RHS, const char *name) {
570 CallInst *call_inst = unwrap(B)->CreateBinaryIntrinsic(Intrinsic::cttz, unwrap(LHS), unwrap(RHS), nullptr, name);
571 return wrap(call_inst);
572}
573
574LLVMValueRef ZigLLVMBuildFMA(LLVMBuilderRef builder, LLVMValueRef A, LLVMValueRef B, LLVMValueRef C, const char *name) {
575 llvm::Type* types[1] = {
576 unwrap(A)->getType(),
577 };
578 llvm::Value* values[3] = {unwrap(A), unwrap(B), unwrap(C)};
579
580 CallInst *call_inst = unwrap(builder)->CreateIntrinsic(Intrinsic::fma, types, values, nullptr, name);
581 return wrap(call_inst);
582}
583
484584LLVMValueRef ZigLLVMBuildMaxNum(LLVMBuilderRef B, LLVMValueRef LHS, LLVMValueRef RHS, const char *name) {
485585 CallInst *call_inst = unwrap(B)->CreateMaxNum(unwrap(LHS), unwrap(RHS), name);
486586 return wrap(call_inst);
src/zig_llvm.h+23
......@@ -141,6 +141,29 @@ ZIG_EXTERN_C LLVMValueRef ZigLLVMBuildMemCpy(LLVMBuilderRef B, LLVMValueRef Dst,
141141ZIG_EXTERN_C LLVMValueRef ZigLLVMBuildMemSet(LLVMBuilderRef B, LLVMValueRef Ptr, LLVMValueRef Val, LLVMValueRef Size,
142142 unsigned Align, bool isVolatile);
143143
144ZIG_EXTERN_C LLVMValueRef ZigLLVMBuildCeil(LLVMBuilderRef builder, LLVMValueRef V, const char* name);
145ZIG_EXTERN_C LLVMValueRef ZigLLVMBuildCos(LLVMBuilderRef builder, LLVMValueRef V, const char* name);
146ZIG_EXTERN_C LLVMValueRef ZigLLVMBuildExp(LLVMBuilderRef builder, LLVMValueRef V, const char* name);
147ZIG_EXTERN_C LLVMValueRef ZigLLVMBuildExp2(LLVMBuilderRef builder, LLVMValueRef V, const char* name);
148ZIG_EXTERN_C LLVMValueRef ZigLLVMBuildFAbs(LLVMBuilderRef builder, LLVMValueRef V, const char* name);
149ZIG_EXTERN_C LLVMValueRef ZigLLVMBuildFloor(LLVMBuilderRef builder, LLVMValueRef V, const char* name);
150ZIG_EXTERN_C LLVMValueRef ZigLLVMBuildLog(LLVMBuilderRef builder, LLVMValueRef V, const char* name);
151ZIG_EXTERN_C LLVMValueRef ZigLLVMBuildLog10(LLVMBuilderRef builder, LLVMValueRef V, const char* name);
152ZIG_EXTERN_C LLVMValueRef ZigLLVMBuildLog2(LLVMBuilderRef builder, LLVMValueRef V, const char* name);
153ZIG_EXTERN_C LLVMValueRef ZigLLVMBuildRound(LLVMBuilderRef builder, LLVMValueRef V, const char* name);
154ZIG_EXTERN_C LLVMValueRef ZigLLVMBuildSin(LLVMBuilderRef builder, LLVMValueRef V, const char* name);
155ZIG_EXTERN_C LLVMValueRef ZigLLVMBuildSqrt(LLVMBuilderRef builder, LLVMValueRef V, const char* name);
156ZIG_EXTERN_C LLVMValueRef ZigLLVMBuildFTrunc(LLVMBuilderRef builder, LLVMValueRef V, const char* name);
157
158ZIG_EXTERN_C LLVMValueRef ZigLLVMBuildBitReverse(LLVMBuilderRef builder, LLVMValueRef V, const char* name);
159ZIG_EXTERN_C LLVMValueRef ZigLLVMBuildBSwap(LLVMBuilderRef builder, LLVMValueRef V, const char* name);
160ZIG_EXTERN_C LLVMValueRef ZigLLVMBuildCTPop(LLVMBuilderRef builder, LLVMValueRef V, const char* name);
161
162ZIG_EXTERN_C LLVMValueRef ZigLLVMBuildCTLZ(LLVMBuilderRef builder, LLVMValueRef LHS, LLVMValueRef RHS, const char* name);
163ZIG_EXTERN_C LLVMValueRef ZigLLVMBuildCTTZ(LLVMBuilderRef builder, LLVMValueRef LHS, LLVMValueRef RHS, const char* name);
164
165ZIG_EXTERN_C LLVMValueRef ZigLLVMBuildFMA(LLVMBuilderRef builder, LLVMValueRef A, LLVMValueRef B, LLVMValueRef C, const char* name);
166
144167ZIG_EXTERN_C LLVMValueRef ZigLLVMBuildMaxNum(LLVMBuilderRef builder, LLVMValueRef LHS, LLVMValueRef RHS, const char* name);
145168ZIG_EXTERN_C LLVMValueRef ZigLLVMBuildMinNum(LLVMBuilderRef builder, LLVMValueRef LHS, LLVMValueRef RHS, const char* name);
146169