diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/codegen/llvm.zig | 216 | ||||
| -rw-r--r-- | src/codegen/llvm/Builder.zig | 198 | ||||
| -rw-r--r-- | src/codegen/llvm/bindings.zig | 57 | ||||
| -rw-r--r-- | src/zig_llvm.cpp | 100 | ||||
| -rw-r--r-- | src/zig_llvm.h | 23 |
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, ¶ms, 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, ¶ms, result, ty.vectorLen(mod)); + } + + return self.wip.call( + .normal, + .ccc, + .none, + libc_fn.typeOf(&o.builder), + libc_fn.toValue(&o.builder), + ¶ms, "", - ), &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, - ¶ms, - 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, - ¶ms, - 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, - ¶ms, - 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); |
