aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorJacob Young <jacobly0@users.noreply.github.com>2023-08-05 23:05:02 -0400
committerGitHub <noreply@github.com>2023-08-05 23:05:02 -0400
commit1c7798a3cde9e8dad31c276aab4c1affb2043ad2 (patch)
tree870480a2191982b63e6b4a29152e26db373a286b /src
parent68f84964b3d80e5b976810208a14c31268a181e1 (diff)
parente149f1e1de8f79a66a97da1700d9a64fc2983211 (diff)
downloadzig-1c7798a3cde9e8dad31c276aab4c1affb2043ad2.tar.gz
zig-1c7798a3cde9e8dad31c276aab4c1affb2043ad2.zip
Merge pull request #16705 from antlilja/builder-intrinsics
Implement more intrinsics in new LLVM IR builder API and remove uses of LLVM owns API
Diffstat (limited to 'src')
-rw-r--r--src/codegen/llvm.zig216
-rw-r--r--src/codegen/llvm/Builder.zig198
-rw-r--r--src/codegen/llvm/bindings.zig57
-rw-r--r--src/zig_llvm.cpp100
-rw-r--r--src/zig_llvm.h23
5 files changed, 461 insertions, 133 deletions
diff --git a/src/codegen/llvm.zig b/src/codegen/llvm.zig
index 3104ea7023..d9b99ec6d0 100644
--- a/src/codegen/llvm.zig
+++ b/src/codegen/llvm.zig
@@ -5100,11 +5100,11 @@ pub const FuncGen = struct {
.memcpy => try self.airMemcpy(inst),
.set_union_tag => try self.airSetUnionTag(inst),
.get_union_tag => try self.airGetUnionTag(inst),
- .clz => try self.airClzCtz(inst, "llvm.ctlz"),
- .ctz => try self.airClzCtz(inst, "llvm.cttz"),
- .popcount => try self.airBitOp(inst, "llvm.ctpop"),
- .byte_swap => try self.airByteSwap(inst, "llvm.bswap"),
- .bit_reverse => try self.airBitOp(inst, "llvm.bitreverse"),
+ .clz => try self.airClzCtz(inst, .@"llvm.ctlz."),
+ .ctz => try self.airClzCtz(inst, .@"llvm.cttz."),
+ .popcount => try self.airBitOp(inst, .@"llvm.ctpop."),
+ .byte_swap => try self.airByteSwap(inst),
+ .bit_reverse => try self.airBitOp(inst, .@"llvm.bitreverse."),
.tag_name => try self.airTagName(inst),
.error_name => try self.airErrorName(inst),
.splat => try self.airSplat(inst),
@@ -8282,8 +8282,7 @@ pub const FuncGen = struct {
const scalar_ty = ty.scalarType(mod);
const llvm_ty = try o.lowerType(ty);
- const intrinsics_allowed = op != .tan and intrinsicsAllowed(scalar_ty, target);
- const strat: FloatOpStrat = if (intrinsics_allowed) switch (op) {
+ if (op != .tan and intrinsicsAllowed(scalar_ty, target)) switch (op) {
// Some operations are dedicated LLVM instructions, not available as intrinsics
.neg => return self.wip.un(.fneg, params[0], ""),
.add => return self.wip.bin(.fadd, params[0], params[1], ""),
@@ -8293,83 +8292,84 @@ pub const FuncGen = struct {
.fmod => return self.wip.bin(.frem, params[0], params[1], ""),
.fmax => return self.wip.bin(.@"llvm.maxnum.", params[0], params[1], ""),
.fmin => return self.wip.bin(.@"llvm.minnum.", params[0], params[1], ""),
- else => .{ .intrinsic = "llvm." ++ @tagName(op) },
- } else b: {
- const float_bits = scalar_ty.floatBits(target);
- break :b switch (op) {
- .neg => {
- // In this case we can generate a softfloat negation by XORing the
- // bits with a constant.
- const int_ty = try o.builder.intType(@intCast(float_bits));
- const cast_ty = try llvm_ty.changeScalar(int_ty, &o.builder);
- const sign_mask = try o.builder.splatValue(
- cast_ty,
- try o.builder.intConst(int_ty, @as(u128, 1) << @intCast(float_bits - 1)),
- );
- const bitcasted_operand = try self.wip.cast(.bitcast, params[0], cast_ty, "");
- const result = try self.wip.bin(.xor, bitcasted_operand, sign_mask, "");
- return self.wip.cast(.bitcast, result, llvm_ty, "");
- },
- .add, .sub, .div, .mul => .{ .libc = try o.builder.fmt("__{s}{s}f3", .{
- @tagName(op), compilerRtFloatAbbrev(float_bits),
- }) },
- .ceil,
- .cos,
- .exp,
- .exp2,
- .fabs,
- .floor,
- .fma,
- .fmax,
- .fmin,
- .fmod,
- .log,
- .log10,
- .log2,
- .round,
- .sin,
- .sqrt,
- .tan,
- .trunc,
- => .{ .libc = try o.builder.fmt("{s}{s}{s}", .{
- libcFloatPrefix(float_bits), @tagName(op), libcFloatSuffix(float_bits),
- }) },
- };
+ .ceil => return self.wip.un(.@"llvm.ceil.", params[0], ""),
+ .cos => return self.wip.un(.@"llvm.cos.", params[0], ""),
+ .exp => return self.wip.un(.@"llvm.exp.", params[0], ""),
+ .exp2 => return self.wip.un(.@"llvm.exp2.", params[0], ""),
+ .fabs => return self.wip.un(.@"llvm.fabs.", params[0], ""),
+ .floor => return self.wip.un(.@"llvm.floor.", params[0], ""),
+ .log => return self.wip.un(.@"llvm.log.", params[0], ""),
+ .log10 => return self.wip.un(.@"llvm.log10.", params[0], ""),
+ .log2 => return self.wip.un(.@"llvm.log2.", params[0], ""),
+ .round => return self.wip.un(.@"llvm.round.", params[0], ""),
+ .sin => return self.wip.un(.@"llvm.sin.", params[0], ""),
+ .sqrt => return self.wip.un(.@"llvm.sqrt.", params[0], ""),
+ .trunc => return self.wip.un(.@"llvm.trunc.", params[0], ""),
+ .fma => return self.wip.fusedMultiplyAdd(params[0], params[1], params[2]),
+ .tan => unreachable,
};
- const llvm_fn = switch (strat) {
- .intrinsic => |fn_name| try self.getIntrinsic(fn_name, &.{llvm_ty}),
- .libc => |fn_name| b: {
- const scalar_llvm_ty = llvm_ty.scalarType(&o.builder);
- const libc_fn = try self.getLibcFunction(
- fn_name,
- ([1]Builder.Type{scalar_llvm_ty} ** 3)[0..params.len],
- scalar_llvm_ty,
+ const float_bits = scalar_ty.floatBits(target);
+ const fn_name = switch (op) {
+ .neg => {
+ // In this case we can generate a softfloat negation by XORing the
+ // bits with a constant.
+ const int_ty = try o.builder.intType(@intCast(float_bits));
+ const cast_ty = try llvm_ty.changeScalar(int_ty, &o.builder);
+ const sign_mask = try o.builder.splatValue(
+ cast_ty,
+ try o.builder.intConst(int_ty, @as(u128, 1) << @intCast(float_bits - 1)),
);
- if (ty.zigTypeTag(mod) == .Vector) {
- const result = try o.builder.poisonValue(llvm_ty);
- return self.buildElementwiseCall(libc_fn, &params, result, ty.vectorLen(mod));
- }
-
- break :b libc_fn.toLlvm(&o.builder);
+ const bitcasted_operand = try self.wip.cast(.bitcast, params[0], cast_ty, "");
+ const result = try self.wip.bin(.xor, bitcasted_operand, sign_mask, "");
+ return self.wip.cast(.bitcast, result, llvm_ty, "");
},
+ .add, .sub, .div, .mul => try o.builder.fmt("__{s}{s}f3", .{
+ @tagName(op), compilerRtFloatAbbrev(float_bits),
+ }),
+ .ceil,
+ .cos,
+ .exp,
+ .exp2,
+ .fabs,
+ .floor,
+ .fma,
+ .fmax,
+ .fmin,
+ .fmod,
+ .log,
+ .log10,
+ .log2,
+ .round,
+ .sin,
+ .sqrt,
+ .tan,
+ .trunc,
+ => try o.builder.fmt("{s}{s}{s}", .{
+ libcFloatPrefix(float_bits), @tagName(op), libcFloatSuffix(float_bits),
+ }),
};
- const llvm_fn_ty = try o.builder.fnType(
- llvm_ty,
- ([1]Builder.Type{llvm_ty} ** 3)[0..params.len],
- .normal,
+
+ const scalar_llvm_ty = llvm_ty.scalarType(&o.builder);
+ const libc_fn = try self.getLibcFunction(
+ fn_name,
+ ([1]Builder.Type{scalar_llvm_ty} ** 3)[0..params.len],
+ scalar_llvm_ty,
);
- var llvm_params: [params_len]*llvm.Value = undefined;
- for (&llvm_params, params) |*llvm_param, param| llvm_param.* = param.toLlvm(&self.wip);
- return (try self.wip.unimplemented(llvm_ty, "")).finish(self.builder.buildCallOld(
- llvm_fn_ty.toLlvm(&o.builder),
- llvm_fn,
- &llvm_params,
- params_len,
- .C,
- .Auto,
+ if (ty.zigTypeTag(mod) == .Vector) {
+ const result = try o.builder.poisonValue(llvm_ty);
+ return self.buildElementwiseCall(libc_fn, &params, result, ty.vectorLen(mod));
+ }
+
+ return self.wip.call(
+ .normal,
+ .ccc,
+ .none,
+ libc_fn.typeOf(&o.builder),
+ libc_fn.toValue(&o.builder),
+ &params,
"",
- ), &self.wip);
+ );
}
fn airMulAdd(self: *FuncGen, inst: Air.Inst.Index) !Builder.Value {
@@ -9526,64 +9526,29 @@ pub const FuncGen = struct {
return self.buildFloatOp(.neg, operand_ty, 1, .{operand});
}
- fn airClzCtz(self: *FuncGen, inst: Air.Inst.Index, llvm_fn_name: []const u8) !Builder.Value {
+ fn airClzCtz(self: *FuncGen, inst: Air.Inst.Index, intrinsic: Builder.Function.Instruction.Tag) !Builder.Value {
const o = self.dg.object;
const ty_op = self.air.instructions.items(.data)[inst].ty_op;
- const operand_ty = self.typeOf(ty_op.operand);
const operand = try self.resolveInst(ty_op.operand);
- const llvm_operand_ty = try o.lowerType(operand_ty);
- const llvm_fn_ty = try o.builder.fnType(llvm_operand_ty, &.{ llvm_operand_ty, .i1 }, .normal);
- const fn_val = try self.getIntrinsic(llvm_fn_name, &.{llvm_operand_ty});
+ const wrong_size_result = try self.wip.bin(intrinsic, operand, (try o.builder.intConst(.i1, 0)).toValue(), "");
- const params = [_]*llvm.Value{
- operand.toLlvm(&self.wip),
- Builder.Constant.false.toLlvm(&o.builder),
- };
- const wrong_size_result = (try self.wip.unimplemented(llvm_operand_ty, "")).finish(
- self.builder.buildCallOld(
- llvm_fn_ty.toLlvm(&o.builder),
- fn_val,
- &params,
- params.len,
- .C,
- .Auto,
- "",
- ),
- &self.wip,
- );
const result_ty = self.typeOfIndex(inst);
return self.wip.conv(.unsigned, wrong_size_result, try o.lowerType(result_ty), "");
}
- fn airBitOp(self: *FuncGen, inst: Air.Inst.Index, llvm_fn_name: []const u8) !Builder.Value {
+ fn airBitOp(self: *FuncGen, inst: Air.Inst.Index, intrinsic: Builder.Function.Instruction.Tag) !Builder.Value {
const o = self.dg.object;
const ty_op = self.air.instructions.items(.data)[inst].ty_op;
- const operand_ty = self.typeOf(ty_op.operand);
const operand = try self.resolveInst(ty_op.operand);
- const llvm_operand_ty = try o.lowerType(operand_ty);
- const llvm_fn_ty = try o.builder.fnType(llvm_operand_ty, &.{llvm_operand_ty}, .normal);
- const fn_val = try self.getIntrinsic(llvm_fn_name, &.{llvm_operand_ty});
+ const wrong_size_result = try self.wip.un(intrinsic, operand, "");
- const params = [_]*llvm.Value{operand.toLlvm(&self.wip)};
- const wrong_size_result = (try self.wip.unimplemented(llvm_operand_ty, "")).finish(
- self.builder.buildCallOld(
- llvm_fn_ty.toLlvm(&o.builder),
- fn_val,
- &params,
- params.len,
- .C,
- .Auto,
- "",
- ),
- &self.wip,
- );
const result_ty = self.typeOfIndex(inst);
return self.wip.conv(.unsigned, wrong_size_result, try o.lowerType(result_ty), "");
}
- fn airByteSwap(self: *FuncGen, inst: Air.Inst.Index, llvm_fn_name: []const u8) !Builder.Value {
+ fn airByteSwap(self: *FuncGen, inst: Air.Inst.Index) !Builder.Value {
const o = self.dg.object;
const mod = o.module;
const ty_op = self.air.instructions.items(.data)[inst].ty_op;
@@ -9611,22 +9576,7 @@ pub const FuncGen = struct {
bits = bits + 8;
}
- const llvm_fn_ty = try o.builder.fnType(llvm_operand_ty, &.{llvm_operand_ty}, .normal);
- const fn_val = try self.getIntrinsic(llvm_fn_name, &.{llvm_operand_ty});
-
- const params = [_]*llvm.Value{operand.toLlvm(&self.wip)};
- const wrong_size_result = (try self.wip.unimplemented(llvm_operand_ty, "")).finish(
- self.builder.buildCallOld(
- llvm_fn_ty.toLlvm(&o.builder),
- fn_val,
- &params,
- params.len,
- .C,
- .Auto,
- "",
- ),
- &self.wip,
- );
+ const wrong_size_result = try self.wip.un(.@"llvm.bswap.", operand, "");
const result_ty = self.typeOfIndex(inst);
return self.wip.conv(.unsigned, wrong_size_result, try o.lowerType(result_ty), "");
diff --git a/src/codegen/llvm/Builder.zig b/src/codegen/llvm/Builder.zig
index 5c06995273..640cde8409 100644
--- a/src/codegen/llvm/Builder.zig
+++ b/src/codegen/llvm/Builder.zig
@@ -2416,6 +2416,25 @@ pub const Function = struct {
inttoptr,
@"llvm.maxnum.",
@"llvm.minnum.",
+ @"llvm.ceil.",
+ @"llvm.cos.",
+ @"llvm.exp.",
+ @"llvm.exp2.",
+ @"llvm.fabs.",
+ @"llvm.floor.",
+ @"llvm.log.",
+ @"llvm.log10.",
+ @"llvm.log2.",
+ @"llvm.round.",
+ @"llvm.sin.",
+ @"llvm.sqrt.",
+ @"llvm.trunc.",
+ @"llvm.fma.",
+ @"llvm.bitreverse.",
+ @"llvm.bswap.",
+ @"llvm.ctpop.",
+ @"llvm.ctlz.",
+ @"llvm.cttz.",
@"llvm.sadd.sat.",
@"llvm.smax.",
@"llvm.smin.",
@@ -2558,6 +2577,8 @@ pub const Function = struct {
.@"fsub fast",
.@"llvm.maxnum.",
.@"llvm.minnum.",
+ .@"llvm.ctlz.",
+ .@"llvm.cttz.",
.@"llvm.sadd.sat.",
.@"llvm.smax.",
.@"llvm.smin.",
@@ -2689,6 +2710,22 @@ pub const Function = struct {
.changeScalarAssumeCapacity(.i1, wip.builder),
.fneg,
.@"fneg fast",
+ .@"llvm.ceil.",
+ .@"llvm.cos.",
+ .@"llvm.exp.",
+ .@"llvm.exp2.",
+ .@"llvm.fabs.",
+ .@"llvm.floor.",
+ .@"llvm.log.",
+ .@"llvm.log10.",
+ .@"llvm.log2.",
+ .@"llvm.round.",
+ .@"llvm.sin.",
+ .@"llvm.sqrt.",
+ .@"llvm.trunc.",
+ .@"llvm.bitreverse.",
+ .@"llvm.bswap.",
+ .@"llvm.ctpop.",
=> @as(Value, @enumFromInt(instruction.data)).typeOfWip(wip),
.getelementptr,
.@"getelementptr inbounds",
@@ -2725,6 +2762,7 @@ pub const Function = struct {
},
.unimplemented => @enumFromInt(instruction.data),
.va_arg => wip.extraData(VaArg, instruction.data).type,
+ .@"llvm.fma." => wip.extraData(FusedMultiplyAdd, instruction.data).a.typeOfWip(wip),
};
}
@@ -2755,6 +2793,8 @@ pub const Function = struct {
.@"fsub fast",
.@"llvm.maxnum.",
.@"llvm.minnum.",
+ .@"llvm.ctlz.",
+ .@"llvm.cttz.",
.@"llvm.sadd.sat.",
.@"llvm.smax.",
.@"llvm.smin.",
@@ -2887,6 +2927,22 @@ pub const Function = struct {
.changeScalarAssumeCapacity(.i1, builder),
.fneg,
.@"fneg fast",
+ .@"llvm.ceil.",
+ .@"llvm.cos.",
+ .@"llvm.exp.",
+ .@"llvm.exp2.",
+ .@"llvm.fabs.",
+ .@"llvm.floor.",
+ .@"llvm.log.",
+ .@"llvm.log10.",
+ .@"llvm.log2.",
+ .@"llvm.round.",
+ .@"llvm.sin.",
+ .@"llvm.sqrt.",
+ .@"llvm.trunc.",
+ .@"llvm.bitreverse.",
+ .@"llvm.bswap.",
+ .@"llvm.ctpop.",
=> @as(Value, @enumFromInt(instruction.data)).typeOf(function_index, builder),
.getelementptr,
.@"getelementptr inbounds",
@@ -2925,6 +2981,7 @@ pub const Function = struct {
},
.unimplemented => @enumFromInt(instruction.data),
.va_arg => function.extraData(VaArg, instruction.data).type,
+ .@"llvm.fma." => function.extraData(FusedMultiplyAdd, instruction.data).a.typeOf(function_index, builder),
};
}
@@ -3017,6 +3074,12 @@ pub const Function = struct {
mask: Value,
};
+ pub const FusedMultiplyAdd = struct {
+ a: Value,
+ b: Value,
+ c: Value,
+ };
+
pub const ExtractValue = struct {
val: Value,
indices_len: u32,
@@ -3424,7 +3487,24 @@ pub const WipFunction = struct {
switch (tag) {
.fneg,
.@"fneg fast",
+ .@"llvm.ceil.",
+ .@"llvm.cos.",
+ .@"llvm.exp.",
+ .@"llvm.exp2.",
+ .@"llvm.fabs.",
+ .@"llvm.floor.",
+ .@"llvm.log.",
+ .@"llvm.log10.",
+ .@"llvm.log2.",
+ .@"llvm.round.",
+ .@"llvm.sin.",
+ .@"llvm.sqrt.",
+ .@"llvm.trunc.",
=> assert(val.typeOfWip(self).scalarType(self.builder).isFloatingPoint()),
+ .@"llvm.bitreverse.",
+ .@"llvm.bswap.",
+ .@"llvm.ctpop.",
+ => assert(val.typeOfWip(self).scalarType(self.builder).isInteger(self.builder)),
else => unreachable,
}
try self.ensureUnusedExtraCapacity(1, NoExtra, 0);
@@ -3433,10 +3513,43 @@ pub const WipFunction = struct {
switch (tag) {
.fneg => self.llvm.builder.setFastMath(false),
.@"fneg fast" => self.llvm.builder.setFastMath(true),
+ .@"llvm.ceil.",
+ .@"llvm.cos.",
+ .@"llvm.exp.",
+ .@"llvm.exp2.",
+ .@"llvm.fabs.",
+ .@"llvm.floor.",
+ .@"llvm.log.",
+ .@"llvm.log10.",
+ .@"llvm.log2.",
+ .@"llvm.round.",
+ .@"llvm.sin.",
+ .@"llvm.sqrt.",
+ .@"llvm.trunc.",
+ .@"llvm.bitreverse.",
+ .@"llvm.bswap.",
+ .@"llvm.ctpop.",
+ => {},
else => unreachable,
}
self.llvm.instructions.appendAssumeCapacity(switch (tag) {
.fneg, .@"fneg fast" => &llvm.Builder.buildFNeg,
+ .@"llvm.ceil." => &llvm.Builder.buildCeil,
+ .@"llvm.cos." => &llvm.Builder.buildCos,
+ .@"llvm.exp." => &llvm.Builder.buildExp,
+ .@"llvm.exp2." => &llvm.Builder.buildExp2,
+ .@"llvm.fabs." => &llvm.Builder.buildFAbs,
+ .@"llvm.floor." => &llvm.Builder.buildFloor,
+ .@"llvm.log." => &llvm.Builder.buildLog,
+ .@"llvm.log10." => &llvm.Builder.buildLog10,
+ .@"llvm.log2." => &llvm.Builder.buildLog2,
+ .@"llvm.round." => &llvm.Builder.buildRound,
+ .@"llvm.sin." => &llvm.Builder.buildSin,
+ .@"llvm.sqrt." => &llvm.Builder.buildSqrt,
+ .@"llvm.trunc." => &llvm.Builder.buildFTrunc,
+ .@"llvm.bitreverse." => &llvm.Builder.buildBitReverse,
+ .@"llvm.bswap." => &llvm.Builder.buildBSwap,
+ .@"llvm.ctpop." => &llvm.Builder.buildCTPop,
else => unreachable,
}(self.llvm.builder, val.toLlvm(self), instruction.llvmName(self)));
}
@@ -3514,6 +3627,9 @@ pub const WipFunction = struct {
.urem,
.xor,
=> assert(lhs.typeOfWip(self) == rhs.typeOfWip(self)),
+ .@"llvm.ctlz.",
+ .@"llvm.cttz.",
+ => assert(lhs.typeOfWip(self).scalarType(self.builder).isInteger(self.builder) and rhs.typeOfWip(self) == .i1),
else => unreachable,
}
try self.ensureUnusedExtraCapacity(1, Instruction.Binary, 0);
@@ -3551,6 +3667,8 @@ pub const WipFunction = struct {
.fsub, .@"fsub fast" => &llvm.Builder.buildFSub,
.@"llvm.maxnum." => &llvm.Builder.buildMaxNum,
.@"llvm.minnum." => &llvm.Builder.buildMinNum,
+ .@"llvm.ctlz." => &llvm.Builder.buildCTLZ,
+ .@"llvm.cttz." => &llvm.Builder.buildCTTZ,
.@"llvm.sadd.sat." => &llvm.Builder.buildSAddSat,
.@"llvm.smax." => &llvm.Builder.buildSMax,
.@"llvm.smin." => &llvm.Builder.buildSMin,
@@ -4330,6 +4448,29 @@ pub const WipFunction = struct {
return instruction.toValue();
}
+ pub fn fusedMultiplyAdd(self: *WipFunction, a: Value, b: Value, c: Value) Allocator.Error!Value {
+ assert(a.typeOfWip(self) == b.typeOfWip(self) and a.typeOfWip(self) == c.typeOfWip(self));
+ try self.ensureUnusedExtraCapacity(1, Instruction.FusedMultiplyAdd, 0);
+ const instruction = try self.addInst("", .{
+ .tag = .@"llvm.fma.",
+ .data = self.addExtraAssumeCapacity(Instruction.FusedMultiplyAdd{
+ .a = a,
+ .b = b,
+ .c = c,
+ }),
+ });
+ if (self.builder.useLibLlvm()) {
+ self.llvm.instructions.appendAssumeCapacity(llvm.Builder.buildFMA(
+ self.llvm.builder,
+ a.toLlvm(self),
+ b.toLlvm(self),
+ c.toLlvm(self),
+ instruction.llvmName(self),
+ ));
+ }
+ return instruction.toValue();
+ }
+
pub const WipUnimplemented = struct {
instruction: Instruction.Index,
@@ -4558,6 +4699,8 @@ pub const WipFunction = struct {
.@"icmp ult",
.@"llvm.maxnum.",
.@"llvm.minnum.",
+ .@"llvm.ctlz.",
+ .@"llvm.cttz.",
.@"llvm.sadd.sat.",
.@"llvm.smax.",
.@"llvm.smin.",
@@ -4685,6 +4828,22 @@ pub const WipFunction = struct {
.fneg,
.@"fneg fast",
.ret,
+ .@"llvm.ceil.",
+ .@"llvm.cos.",
+ .@"llvm.exp.",
+ .@"llvm.exp2.",
+ .@"llvm.fabs.",
+ .@"llvm.floor.",
+ .@"llvm.log.",
+ .@"llvm.log10.",
+ .@"llvm.log2.",
+ .@"llvm.round.",
+ .@"llvm.sin.",
+ .@"llvm.sqrt.",
+ .@"llvm.trunc.",
+ .@"llvm.bitreverse.",
+ .@"llvm.bswap.",
+ .@"llvm.ctpop.",
=> instruction.data = @intFromEnum(instructions.map(@enumFromInt(instruction.data))),
.getelementptr,
.@"getelementptr inbounds",
@@ -4790,6 +4949,14 @@ pub const WipFunction = struct {
.type = extra.type,
});
},
+ .@"llvm.fma." => {
+ const extra = self.extraData(Instruction.FusedMultiplyAdd, instruction.data);
+ instruction.data = wip_extra.addExtra(Instruction.FusedMultiplyAdd{
+ .a = instructions.map(extra.a),
+ .b = instructions.map(extra.b),
+ .c = instructions.map(extra.c),
+ });
+ },
}
function.instructions.appendAssumeCapacity(instruction);
names[@intFromEnum(new_instruction_index)] = wip_name.map(if (self.builder.strip)
@@ -7561,6 +7728,22 @@ pub fn printUnbuffered(
.fneg,
.@"fneg fast",
.ret,
+ .@"llvm.ceil.",
+ .@"llvm.cos.",
+ .@"llvm.exp.",
+ .@"llvm.exp2.",
+ .@"llvm.fabs.",
+ .@"llvm.floor.",
+ .@"llvm.log.",
+ .@"llvm.log10.",
+ .@"llvm.log2.",
+ .@"llvm.round.",
+ .@"llvm.sin.",
+ .@"llvm.sqrt.",
+ .@"llvm.trunc.",
+ .@"llvm.bitreverse.",
+ .@"llvm.bswap.",
+ .@"llvm.ctpop.",
=> |tag| {
const val: Value = @enumFromInt(instruction.data);
try writer.print(" {s} {%}\n", .{
@@ -7617,6 +7800,8 @@ pub fn printUnbuffered(
},
.@"llvm.maxnum.",
.@"llvm.minnum.",
+ .@"llvm.ctlz.",
+ .@"llvm.cttz.",
.@"llvm.sadd.sat.",
.@"llvm.smax.",
.@"llvm.smin.",
@@ -7781,6 +7966,19 @@ pub fn printUnbuffered(
extra.type.fmt(self),
});
},
+ .@"llvm.fma." => {
+ const extra =
+ function.extraData(Function.Instruction.FusedMultiplyAdd, instruction.data);
+ const ty = instruction_index.typeOf(function_index, self);
+ try writer.print(" %{} = call {%} @llvm.fma.{m}({%}, {%}, {%})\n", .{
+ instruction_index.name(&function).fmt(self),
+ ty.fmt(self),
+ ty.fmt(self),
+ extra.a.fmt(function_index, self),
+ extra.b.fmt(function_index, self),
+ extra.c.fmt(function_index, self),
+ });
+ },
}
}
try writer.writeByte('}');
diff --git a/src/codegen/llvm/bindings.zig b/src/codegen/llvm/bindings.zig
index 73473e2d43..fd111ac94f 100644
--- a/src/codegen/llvm/bindings.zig
+++ b/src/codegen/llvm/bindings.zig
@@ -1026,6 +1026,63 @@ pub const Builder = opaque {
pub const buildMinNum = ZigLLVMBuildMinNum;
extern fn ZigLLVMBuildMinNum(builder: *Builder, LHS: *Value, RHS: *Value, name: [*:0]const u8) *Value;
+ pub const buildCeil = ZigLLVMBuildCeil;
+ extern fn ZigLLVMBuildCeil(builder: *Builder, V: *Value, name: [*:0]const u8) *Value;
+
+ pub const buildCos = ZigLLVMBuildCos;
+ extern fn ZigLLVMBuildCos(builder: *Builder, V: *Value, name: [*:0]const u8) *Value;
+
+ pub const buildExp = ZigLLVMBuildExp;
+ extern fn ZigLLVMBuildExp(builder: *Builder, V: *Value, name: [*:0]const u8) *Value;
+
+ pub const buildExp2 = ZigLLVMBuildExp2;
+ extern fn ZigLLVMBuildExp2(builder: *Builder, V: *Value, name: [*:0]const u8) *Value;
+
+ pub const buildFAbs = ZigLLVMBuildFAbs;
+ extern fn ZigLLVMBuildFAbs(builder: *Builder, V: *Value, name: [*:0]const u8) *Value;
+
+ pub const buildFloor = ZigLLVMBuildFloor;
+ extern fn ZigLLVMBuildFloor(builder: *Builder, V: *Value, name: [*:0]const u8) *Value;
+
+ pub const buildLog = ZigLLVMBuildLog;
+ extern fn ZigLLVMBuildLog(builder: *Builder, V: *Value, name: [*:0]const u8) *Value;
+
+ pub const buildLog10 = ZigLLVMBuildLog10;
+ extern fn ZigLLVMBuildLog10(builder: *Builder, V: *Value, name: [*:0]const u8) *Value;
+
+ pub const buildLog2 = ZigLLVMBuildLog2;
+ extern fn ZigLLVMBuildLog2(builder: *Builder, V: *Value, name: [*:0]const u8) *Value;
+
+ pub const buildRound = ZigLLVMBuildRound;
+ extern fn ZigLLVMBuildRound(builder: *Builder, V: *Value, name: [*:0]const u8) *Value;
+
+ pub const buildSin = ZigLLVMBuildSin;
+ extern fn ZigLLVMBuildSin(builder: *Builder, V: *Value, name: [*:0]const u8) *Value;
+
+ pub const buildSqrt = ZigLLVMBuildSqrt;
+ extern fn ZigLLVMBuildSqrt(builder: *Builder, V: *Value, name: [*:0]const u8) *Value;
+
+ pub const buildFTrunc = ZigLLVMBuildFTrunc;
+ extern fn ZigLLVMBuildFTrunc(builder: *Builder, V: *Value, name: [*:0]const u8) *Value;
+
+ pub const buildBitReverse = ZigLLVMBuildBitReverse;
+ extern fn ZigLLVMBuildBitReverse(builder: *Builder, V: *Value, name: [*:0]const u8) *Value;
+
+ pub const buildBSwap = ZigLLVMBuildBSwap;
+ extern fn ZigLLVMBuildBSwap(builder: *Builder, V: *Value, name: [*:0]const u8) *Value;
+
+ pub const buildCTPop = ZigLLVMBuildCTPop;
+ extern fn ZigLLVMBuildCTPop(builder: *Builder, V: *Value, name: [*:0]const u8) *Value;
+
+ pub const buildCTLZ = ZigLLVMBuildCTLZ;
+ extern fn ZigLLVMBuildCTLZ(builder: *Builder, LHS: *Value, RHS: *Value, name: [*:0]const u8) *Value;
+
+ pub const buildCTTZ = ZigLLVMBuildCTTZ;
+ extern fn ZigLLVMBuildCTTZ(builder: *Builder, LHS: *Value, RHS: *Value, name: [*:0]const u8) *Value;
+
+ pub const buildFMA = ZigLLVMBuildFMA;
+ extern fn ZigLLVMBuildFMA(builder: *Builder, a: *Value, b: *Value, c: *Value, name: [*:0]const u8) *Value;
+
pub const buildUMax = ZigLLVMBuildUMax;
extern fn ZigLLVMBuildUMax(builder: *Builder, LHS: *Value, RHS: *Value, name: [*:0]const u8) *Value;
diff --git a/src/zig_llvm.cpp b/src/zig_llvm.cpp
index d22bfc1b47..e6568e97a8 100644
--- a/src/zig_llvm.cpp
+++ b/src/zig_llvm.cpp
@@ -481,6 +481,106 @@ LLVMValueRef ZigLLVMBuildMemSet(LLVMBuilderRef B, LLVMValueRef Ptr, LLVMValueRef
return wrap(call_inst);
}
+LLVMValueRef ZigLLVMBuildCeil(LLVMBuilderRef B, LLVMValueRef V, const char *name) {
+ CallInst *call_inst = unwrap(B)->CreateUnaryIntrinsic(Intrinsic::ceil, unwrap(V), nullptr, name);
+ return wrap(call_inst);
+}
+
+LLVMValueRef ZigLLVMBuildCos(LLVMBuilderRef B, LLVMValueRef V, const char *name) {
+ CallInst *call_inst = unwrap(B)->CreateUnaryIntrinsic(Intrinsic::cos, unwrap(V), nullptr, name);
+ return wrap(call_inst);
+}
+
+LLVMValueRef ZigLLVMBuildExp(LLVMBuilderRef B, LLVMValueRef V, const char *name) {
+ CallInst *call_inst = unwrap(B)->CreateUnaryIntrinsic(Intrinsic::exp, unwrap(V), nullptr, name);
+ return wrap(call_inst);
+}
+
+LLVMValueRef ZigLLVMBuildExp2(LLVMBuilderRef B, LLVMValueRef V, const char *name) {
+ CallInst *call_inst = unwrap(B)->CreateUnaryIntrinsic(Intrinsic::exp2, unwrap(V), nullptr, name);
+ return wrap(call_inst);
+}
+
+LLVMValueRef ZigLLVMBuildFAbs(LLVMBuilderRef B, LLVMValueRef V, const char *name) {
+ CallInst *call_inst = unwrap(B)->CreateUnaryIntrinsic(Intrinsic::fabs, unwrap(V), nullptr, name);
+ return wrap(call_inst);
+}
+
+LLVMValueRef ZigLLVMBuildFloor(LLVMBuilderRef B, LLVMValueRef V, const char *name) {
+ CallInst *call_inst = unwrap(B)->CreateUnaryIntrinsic(Intrinsic::floor, unwrap(V), nullptr, name);
+ return wrap(call_inst);
+}
+
+LLVMValueRef ZigLLVMBuildLog(LLVMBuilderRef B, LLVMValueRef V, const char *name) {
+ CallInst *call_inst = unwrap(B)->CreateUnaryIntrinsic(Intrinsic::log, unwrap(V), nullptr, name);
+ return wrap(call_inst);
+}
+
+LLVMValueRef ZigLLVMBuildLog10(LLVMBuilderRef B, LLVMValueRef V, const char *name) {
+ CallInst *call_inst = unwrap(B)->CreateUnaryIntrinsic(Intrinsic::log10, unwrap(V), nullptr, name);
+ return wrap(call_inst);
+}
+
+LLVMValueRef ZigLLVMBuildLog2(LLVMBuilderRef B, LLVMValueRef V, const char *name) {
+ CallInst *call_inst = unwrap(B)->CreateUnaryIntrinsic(Intrinsic::log2, unwrap(V), nullptr, name);
+ return wrap(call_inst);
+}
+
+LLVMValueRef ZigLLVMBuildRound(LLVMBuilderRef B, LLVMValueRef V, const char *name) {
+ CallInst *call_inst = unwrap(B)->CreateUnaryIntrinsic(Intrinsic::round, unwrap(V), nullptr, name);
+ return wrap(call_inst);
+}
+
+LLVMValueRef ZigLLVMBuildSin(LLVMBuilderRef B, LLVMValueRef V, const char *name) {
+ CallInst *call_inst = unwrap(B)->CreateUnaryIntrinsic(Intrinsic::sin, unwrap(V), nullptr, name);
+ return wrap(call_inst);
+}
+
+LLVMValueRef ZigLLVMBuildSqrt(LLVMBuilderRef B, LLVMValueRef V, const char *name) {
+ CallInst *call_inst = unwrap(B)->CreateUnaryIntrinsic(Intrinsic::sqrt, unwrap(V), nullptr, name);
+ return wrap(call_inst);
+}
+
+LLVMValueRef ZigLLVMBuildFTrunc(LLVMBuilderRef B, LLVMValueRef V, const char *name) {
+ CallInst *call_inst = unwrap(B)->CreateUnaryIntrinsic(Intrinsic::trunc, unwrap(V), nullptr, name);
+ return wrap(call_inst);
+}
+
+LLVMValueRef ZigLLVMBuildBitReverse(LLVMBuilderRef B, LLVMValueRef V, const char *name) {
+ CallInst *call_inst = unwrap(B)->CreateUnaryIntrinsic(Intrinsic::bitreverse, unwrap(V), nullptr, name);
+ return wrap(call_inst);
+}
+
+LLVMValueRef ZigLLVMBuildBSwap(LLVMBuilderRef B, LLVMValueRef V, const char *name) {
+ CallInst *call_inst = unwrap(B)->CreateUnaryIntrinsic(Intrinsic::bswap, unwrap(V), nullptr, name);
+ return wrap(call_inst);
+}
+
+LLVMValueRef ZigLLVMBuildCTPop(LLVMBuilderRef B, LLVMValueRef V, const char *name) {
+ CallInst *call_inst = unwrap(B)->CreateUnaryIntrinsic(Intrinsic::ctpop, unwrap(V), nullptr, name);
+ return wrap(call_inst);
+}
+
+LLVMValueRef ZigLLVMBuildCTLZ(LLVMBuilderRef B, LLVMValueRef LHS, LLVMValueRef RHS, const char *name) {
+ CallInst *call_inst = unwrap(B)->CreateBinaryIntrinsic(Intrinsic::ctlz, unwrap(LHS), unwrap(RHS), nullptr, name);
+ return wrap(call_inst);
+}
+
+LLVMValueRef ZigLLVMBuildCTTZ(LLVMBuilderRef B, LLVMValueRef LHS, LLVMValueRef RHS, const char *name) {
+ CallInst *call_inst = unwrap(B)->CreateBinaryIntrinsic(Intrinsic::cttz, unwrap(LHS), unwrap(RHS), nullptr, name);
+ return wrap(call_inst);
+}
+
+LLVMValueRef ZigLLVMBuildFMA(LLVMBuilderRef builder, LLVMValueRef A, LLVMValueRef B, LLVMValueRef C, const char *name) {
+ llvm::Type* types[1] = {
+ unwrap(A)->getType(),
+ };
+ llvm::Value* values[3] = {unwrap(A), unwrap(B), unwrap(C)};
+
+ CallInst *call_inst = unwrap(builder)->CreateIntrinsic(Intrinsic::fma, types, values, nullptr, name);
+ return wrap(call_inst);
+}
+
LLVMValueRef ZigLLVMBuildMaxNum(LLVMBuilderRef B, LLVMValueRef LHS, LLVMValueRef RHS, const char *name) {
CallInst *call_inst = unwrap(B)->CreateMaxNum(unwrap(LHS), unwrap(RHS), name);
return wrap(call_inst);
diff --git a/src/zig_llvm.h b/src/zig_llvm.h
index 74dcd10564..3f5fefb85b 100644
--- a/src/zig_llvm.h
+++ b/src/zig_llvm.h
@@ -141,6 +141,29 @@ ZIG_EXTERN_C LLVMValueRef ZigLLVMBuildMemCpy(LLVMBuilderRef B, LLVMValueRef Dst,
ZIG_EXTERN_C LLVMValueRef ZigLLVMBuildMemSet(LLVMBuilderRef B, LLVMValueRef Ptr, LLVMValueRef Val, LLVMValueRef Size,
unsigned Align, bool isVolatile);
+ZIG_EXTERN_C LLVMValueRef ZigLLVMBuildCeil(LLVMBuilderRef builder, LLVMValueRef V, const char* name);
+ZIG_EXTERN_C LLVMValueRef ZigLLVMBuildCos(LLVMBuilderRef builder, LLVMValueRef V, const char* name);
+ZIG_EXTERN_C LLVMValueRef ZigLLVMBuildExp(LLVMBuilderRef builder, LLVMValueRef V, const char* name);
+ZIG_EXTERN_C LLVMValueRef ZigLLVMBuildExp2(LLVMBuilderRef builder, LLVMValueRef V, const char* name);
+ZIG_EXTERN_C LLVMValueRef ZigLLVMBuildFAbs(LLVMBuilderRef builder, LLVMValueRef V, const char* name);
+ZIG_EXTERN_C LLVMValueRef ZigLLVMBuildFloor(LLVMBuilderRef builder, LLVMValueRef V, const char* name);
+ZIG_EXTERN_C LLVMValueRef ZigLLVMBuildLog(LLVMBuilderRef builder, LLVMValueRef V, const char* name);
+ZIG_EXTERN_C LLVMValueRef ZigLLVMBuildLog10(LLVMBuilderRef builder, LLVMValueRef V, const char* name);
+ZIG_EXTERN_C LLVMValueRef ZigLLVMBuildLog2(LLVMBuilderRef builder, LLVMValueRef V, const char* name);
+ZIG_EXTERN_C LLVMValueRef ZigLLVMBuildRound(LLVMBuilderRef builder, LLVMValueRef V, const char* name);
+ZIG_EXTERN_C LLVMValueRef ZigLLVMBuildSin(LLVMBuilderRef builder, LLVMValueRef V, const char* name);
+ZIG_EXTERN_C LLVMValueRef ZigLLVMBuildSqrt(LLVMBuilderRef builder, LLVMValueRef V, const char* name);
+ZIG_EXTERN_C LLVMValueRef ZigLLVMBuildFTrunc(LLVMBuilderRef builder, LLVMValueRef V, const char* name);
+
+ZIG_EXTERN_C LLVMValueRef ZigLLVMBuildBitReverse(LLVMBuilderRef builder, LLVMValueRef V, const char* name);
+ZIG_EXTERN_C LLVMValueRef ZigLLVMBuildBSwap(LLVMBuilderRef builder, LLVMValueRef V, const char* name);
+ZIG_EXTERN_C LLVMValueRef ZigLLVMBuildCTPop(LLVMBuilderRef builder, LLVMValueRef V, const char* name);
+
+ZIG_EXTERN_C LLVMValueRef ZigLLVMBuildCTLZ(LLVMBuilderRef builder, LLVMValueRef LHS, LLVMValueRef RHS, const char* name);
+ZIG_EXTERN_C LLVMValueRef ZigLLVMBuildCTTZ(LLVMBuilderRef builder, LLVMValueRef LHS, LLVMValueRef RHS, const char* name);
+
+ZIG_EXTERN_C LLVMValueRef ZigLLVMBuildFMA(LLVMBuilderRef builder, LLVMValueRef A, LLVMValueRef B, LLVMValueRef C, const char* name);
+
ZIG_EXTERN_C LLVMValueRef ZigLLVMBuildMaxNum(LLVMBuilderRef builder, LLVMValueRef LHS, LLVMValueRef RHS, const char* name);
ZIG_EXTERN_C LLVMValueRef ZigLLVMBuildMinNum(LLVMBuilderRef builder, LLVMValueRef LHS, LLVMValueRef RHS, const char* name);