Commit 63dcffdf9f

antlilja <liljaanton2001@gmail.com>
2023-08-05 23:57:39
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
1 parent b8c9d5a
Changed files (4)
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;
 
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('}');
src/zig_llvm.cpp
@@ -481,6 +481,81 @@ 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 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);
src/zig_llvm.h
@@ -141,6 +141,22 @@ 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 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);