From 63dcffdf9ff146e05a374cdb4d2e5097def8c202 Mon Sep 17 00:00:00 2001 From: antlilja Date: Sat, 5 Aug 2023 23:57:39 +0200 Subject: Implement fp intrinsics in new LLVM IR builder Intrinsics implemented * llvm.ceil * llvm.cos * llvm.exp * llvm.exp2 * llvm.fabs * llvm.floor * llvm.log * llvm.log10 * llvm.log2 * llvm.round * llvm.sin * llvm.trunc * llvm.fma --- src/codegen/llvm/Builder.zig | 158 ++++++++++++++++++++++++++++++++++++++++++ src/codegen/llvm/bindings.zig | 42 +++++++++++ 2 files changed, 200 insertions(+) (limited to 'src/codegen') diff --git a/src/codegen/llvm/Builder.zig b/src/codegen/llvm/Builder.zig index c0c01b9f15..d5caff72b0 100644 --- a/src/codegen/llvm/Builder.zig +++ b/src/codegen/llvm/Builder.zig @@ -2416,6 +2416,20 @@ 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.sadd.sat.", @"llvm.smax.", @"llvm.smin.", @@ -2689,6 +2703,19 @@ 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.", => @as(Value, @enumFromInt(instruction.data)).typeOfWip(wip), .getelementptr, .@"getelementptr inbounds", @@ -2725,6 +2752,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), }; } @@ -2887,6 +2915,19 @@ 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.", => @as(Value, @enumFromInt(instruction.data)).typeOf(function_index, builder), .getelementptr, .@"getelementptr inbounds", @@ -2925,6 +2966,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 +3059,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,6 +3472,19 @@ 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()), else => unreachable, } @@ -3433,10 +3494,37 @@ 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.", + => {}, 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, else => unreachable, }(self.llvm.builder, val.toLlvm(self), instruction.llvmName(self))); } @@ -4330,6 +4418,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, @@ -4685,6 +4796,19 @@ 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.", => instruction.data = @intFromEnum(instructions.map(@enumFromInt(instruction.data))), .getelementptr, .@"getelementptr inbounds", @@ -4790,6 +4914,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 +7693,19 @@ 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.", => |tag| { const val: Value = @enumFromInt(instruction.data); try writer.print(" {s} {%}\n", .{ @@ -7781,6 +7926,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..cde4990b92 100644 --- a/src/codegen/llvm/bindings.zig +++ b/src/codegen/llvm/bindings.zig @@ -1026,6 +1026,48 @@ 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 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; -- cgit v1.2.3 From 2b4ac7c6b3563905178b791f2e15631a9a38f7ff Mon Sep 17 00:00:00 2001 From: antlilja Date: Sun, 6 Aug 2023 00:10:43 +0200 Subject: Use new LLVM builder API in buildFloatOP --- src/codegen/llvm.zig | 144 +++++++++++++++++++++++++-------------------------- 1 file changed, 72 insertions(+), 72 deletions(-) (limited to 'src/codegen') diff --git a/src/codegen/llvm.zig b/src/codegen/llvm.zig index 3104ea7023..2becaa4030 100644 --- a/src/codegen/llvm.zig +++ b/src/codegen/llvm.zig @@ -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 { -- cgit v1.2.3 From 86f61a9d2641300a733eee2edc10f57bb3243c57 Mon Sep 17 00:00:00 2001 From: antlilja Date: Sun, 6 Aug 2023 00:58:10 +0200 Subject: Implement bitop intrinsics in new LLVM IR builder * llvm.bitreverse * llvm.bswap * llvm.ctpop * llvm.ctlz * llvm.cttz --- src/codegen/llvm/Builder.zig | 40 ++++++++++++++++++++++++++++++++++++++++ src/codegen/llvm/bindings.zig | 15 +++++++++++++++ src/zig_llvm.cpp | 25 +++++++++++++++++++++++++ src/zig_llvm.h | 7 +++++++ 4 files changed, 87 insertions(+) (limited to 'src/codegen') diff --git a/src/codegen/llvm/Builder.zig b/src/codegen/llvm/Builder.zig index d5caff72b0..5e473cdf7d 100644 --- a/src/codegen/llvm/Builder.zig +++ b/src/codegen/llvm/Builder.zig @@ -2430,6 +2430,11 @@ pub const Function = struct { @"llvm.sqrt.", @"llvm.trunc.", @"llvm.fma.", + @"llvm.bitreverse.", + @"llvm.bswap.", + @"llvm.ctpop.", + @"llvm.ctlz.", + @"llvm.cttz.", @"llvm.sadd.sat.", @"llvm.smax.", @"llvm.smin.", @@ -2572,6 +2577,8 @@ pub const Function = struct { .@"fsub fast", .@"llvm.maxnum.", .@"llvm.minnum.", + .@"llvm.ctlz.", + .@"llvm.cttz.", .@"llvm.sadd.sat.", .@"llvm.smax.", .@"llvm.smin.", @@ -2716,6 +2723,9 @@ pub const Function = struct { .@"llvm.sin.", .@"llvm.sqrt.", .@"llvm.trunc.", + .@"llvm.bitreverse.", + .@"llvm.bswap.", + .@"llvm.ctpop.", => @as(Value, @enumFromInt(instruction.data)).typeOfWip(wip), .getelementptr, .@"getelementptr inbounds", @@ -2783,6 +2793,8 @@ pub const Function = struct { .@"fsub fast", .@"llvm.maxnum.", .@"llvm.minnum.", + .@"llvm.ctlz.", + .@"llvm.cttz.", .@"llvm.sadd.sat.", .@"llvm.smax.", .@"llvm.smin.", @@ -2928,6 +2940,9 @@ pub const Function = struct { .@"llvm.sin.", .@"llvm.sqrt.", .@"llvm.trunc.", + .@"llvm.bitreverse.", + .@"llvm.bswap.", + .@"llvm.ctpop.", => @as(Value, @enumFromInt(instruction.data)).typeOf(function_index, builder), .getelementptr, .@"getelementptr inbounds", @@ -3486,6 +3501,10 @@ pub const WipFunction = struct { .@"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); @@ -3507,6 +3526,9 @@ pub const WipFunction = struct { .@"llvm.sin.", .@"llvm.sqrt.", .@"llvm.trunc.", + .@"llvm.bitreverse.", + .@"llvm.bswap.", + .@"llvm.ctpop.", => {}, else => unreachable, } @@ -3525,6 +3547,9 @@ pub const WipFunction = struct { .@"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))); } @@ -3602,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); @@ -3639,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, @@ -4669,6 +4699,8 @@ pub const WipFunction = struct { .@"icmp ult", .@"llvm.maxnum.", .@"llvm.minnum.", + .@"llvm.ctlz.", + .@"llvm.cttz.", .@"llvm.sadd.sat.", .@"llvm.smax.", .@"llvm.smin.", @@ -4809,6 +4841,9 @@ pub const WipFunction = struct { .@"llvm.sin.", .@"llvm.sqrt.", .@"llvm.trunc.", + .@"llvm.bitreverse.", + .@"llvm.bswap.", + .@"llvm.ctpop.", => instruction.data = @intFromEnum(instructions.map(@enumFromInt(instruction.data))), .getelementptr, .@"getelementptr inbounds", @@ -7706,6 +7741,9 @@ pub fn printUnbuffered( .@"llvm.sin.", .@"llvm.sqrt.", .@"llvm.trunc.", + .@"llvm.bitreverse.", + .@"llvm.bswap.", + .@"llvm.ctpop.", => |tag| { const val: Value = @enumFromInt(instruction.data); try writer.print(" {s} {%}\n", .{ @@ -7762,6 +7800,8 @@ pub fn printUnbuffered( }, .@"llvm.maxnum.", .@"llvm.minnum.", + .@"llvm.ctlz.", + .@"llvm.cttz.", .@"llvm.sadd.sat.", .@"llvm.smax.", .@"llvm.smin.", diff --git a/src/codegen/llvm/bindings.zig b/src/codegen/llvm/bindings.zig index cde4990b92..fd111ac94f 100644 --- a/src/codegen/llvm/bindings.zig +++ b/src/codegen/llvm/bindings.zig @@ -1065,6 +1065,21 @@ pub const Builder = opaque { 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; diff --git a/src/zig_llvm.cpp b/src/zig_llvm.cpp index 51eabf9661..e6568e97a8 100644 --- a/src/zig_llvm.cpp +++ b/src/zig_llvm.cpp @@ -546,6 +546,31 @@ LLVMValueRef ZigLLVMBuildFTrunc(LLVMBuilderRef B, LLVMValueRef V, const char *na 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(), diff --git a/src/zig_llvm.h b/src/zig_llvm.h index 93fd1aea75..3f5fefb85b 100644 --- a/src/zig_llvm.h +++ b/src/zig_llvm.h @@ -155,6 +155,13 @@ ZIG_EXTERN_C LLVMValueRef ZigLLVMBuildSin(LLVMBuilderRef builder, LLVMValueRef V 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); -- cgit v1.2.3 From e149f1e1de8f79a66a97da1700d9a64fc2983211 Mon Sep 17 00:00:00 2001 From: antlilja Date: Sun, 6 Aug 2023 00:59:56 +0200 Subject: Use new LLVM IR builder API in bit op lowering --- src/codegen/llvm.zig | 72 ++++++++-------------------------------------------- 1 file changed, 11 insertions(+), 61 deletions(-) (limited to 'src/codegen') diff --git a/src/codegen/llvm.zig b/src/codegen/llvm.zig index 2becaa4030..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), @@ -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), ""); -- cgit v1.2.3