[llvm] Add support for converstion of intrinsic @llvm.fptosi.sat.* and @llvm.fptoui.sat.* (PR #125472)

Vishakh Prakash via llvm-commits llvm-commits at lists.llvm.org
Mon Feb 3 01:47:18 PST 2025


https://github.com/Vishakh2012 created https://github.com/llvm/llvm-project/pull/125472

- add legalizer for the Generic MIR G_FPTOSI_SAT and G_FPTOUI_SAT 
- add function to add saturatedConversion on these instructions
- add InstructionSelector for both of the gMIR

>From c8c3975a12b3307702faf43a641be8b44539bc17 Mon Sep 17 00:00:00 2001
From: vishakh prakash <vishakhpro2002 at gmail.com>
Date: Mon, 3 Feb 2025 14:55:31 +0530
Subject: [PATCH] FEAT: - add function for adding saturation decoration to sat
 intrinsics - add test for fp to int intrinsic - add legalization for
 G_FPTOSI_SAT and G_FPTOUI_SAT - add instruction selection logic for
 G_FPTOSI_SAT and G_FPTOUI_SAT

---
 llvm/lib/Target/SPIRV/SPIRVEmitIntrinsics.cpp |  22 ++
 .../Target/SPIRV/SPIRVInstructionSelector.cpp |   4 +
 llvm/lib/Target/SPIRV/SPIRVLegalizerInfo.cpp  |   4 +
 .../llvm-intrinsics/fp_to_int_intrinsic.ll    | 220 ++++++++++++++++++
 4 files changed, 250 insertions(+)
 create mode 100644 llvm/test/CodeGen/SPIRV/llvm-intrinsics/fp_to_int_intrinsic.ll

diff --git a/llvm/lib/Target/SPIRV/SPIRVEmitIntrinsics.cpp b/llvm/lib/Target/SPIRV/SPIRVEmitIntrinsics.cpp
index 702206b8e0dc56e..cec3e2dba14e068 100644
--- a/llvm/lib/Target/SPIRV/SPIRVEmitIntrinsics.cpp
+++ b/llvm/lib/Target/SPIRV/SPIRVEmitIntrinsics.cpp
@@ -18,12 +18,15 @@
 #include "SPIRVTargetMachine.h"
 #include "SPIRVUtils.h"
 #include "llvm/ADT/DenseSet.h"
+#include "llvm/ADT/STLExtras.h"
 #include "llvm/IR/IRBuilder.h"
 #include "llvm/IR/InstIterator.h"
 #include "llvm/IR/InstVisitor.h"
 #include "llvm/IR/IntrinsicsSPIRV.h"
 #include "llvm/IR/TypedPointerType.h"
+#include "llvm/Support/Casting.h"
 
+#include <iostream>
 #include <queue>
 #include <unordered_set>
 
@@ -1337,6 +1340,24 @@ static void createSaturatedConversionDecoration(Instruction *I,
   createDecorationIntrinsic(I, SaturatedConversionNode, B);
 }
 
+static void addSaturatedDecorationToIntrinsic(Instruction *I, IRBuilder<> &B) {
+  // llvm::errs() << "this function is running successfully";
+  if (auto *CI = dyn_cast<CallInst>(I)) {
+    Function *F = CI->getCalledFunction();
+    if (F->isIntrinsic()) {
+      StringRef S = F->getName();
+      SmallVector<StringRef, 8> Parts;
+      S.split(Parts, ".", -1, false);
+
+      if (Parts.size() > 1) {
+        if (std::find(Parts.begin(), Parts.end(), "sat") != Parts.end()) {
+          createSaturatedConversionDecoration(I, B);
+        }
+      }
+    }
+  }
+}
+
 Instruction *SPIRVEmitIntrinsics::visitCallInst(CallInst &Call) {
   if (!Call.isInlineAsm())
     return &Call;
@@ -2400,6 +2421,7 @@ bool SPIRVEmitIntrinsics::runOnFunction(Function &Func) {
     if (isConvergenceIntrinsic(I))
       continue;
 
+    addSaturatedDecorationToIntrinsic(I, B);
     processInstrAfterVisit(I, B);
   }
 
diff --git a/llvm/lib/Target/SPIRV/SPIRVInstructionSelector.cpp b/llvm/lib/Target/SPIRV/SPIRVInstructionSelector.cpp
index e7d8fe5bd8015b1..49642126d34cfdc 100644
--- a/llvm/lib/Target/SPIRV/SPIRVInstructionSelector.cpp
+++ b/llvm/lib/Target/SPIRV/SPIRVInstructionSelector.cpp
@@ -602,6 +602,10 @@ bool SPIRVInstructionSelector::spvSelect(Register ResVReg,
     return selectUnOp(ResVReg, ResType, I, SPIRV::OpConvertFToS);
   case TargetOpcode::G_FPTOUI:
     return selectUnOp(ResVReg, ResType, I, SPIRV::OpConvertFToU);
+  case TargetOpcode::G_FPTOSI_SAT:
+    return selectUnOp(ResVReg, ResType, I, SPIRV::OpConvertFToS);
+  case TargetOpcode::G_FPTOUI_SAT:
+    return selectUnOp(ResVReg, ResType, I, SPIRV::OpConvertFToU);
 
   case TargetOpcode::G_SITOFP:
     return selectIToF(ResVReg, ResType, I, true, SPIRV::OpConvertSToF);
diff --git a/llvm/lib/Target/SPIRV/SPIRVLegalizerInfo.cpp b/llvm/lib/Target/SPIRV/SPIRVLegalizerInfo.cpp
index fa5e0a80576d01b..694d584c26e04eb 100644
--- a/llvm/lib/Target/SPIRV/SPIRVLegalizerInfo.cpp
+++ b/llvm/lib/Target/SPIRV/SPIRVLegalizerInfo.cpp
@@ -236,6 +236,10 @@ SPIRVLegalizerInfo::SPIRVLegalizerInfo(const SPIRVSubtarget &ST) {
       .legalForCartesianProduct(allIntScalarsAndVectors,
                                 allFloatScalarsAndVectors);
 
+  getActionDefinitionsBuilder({G_FPTOSI_SAT, G_FPTOUI_SAT})
+      .legalForCartesianProduct(allIntScalarsAndVectors,
+                                allFloatScalarsAndVectors);
+
   getActionDefinitionsBuilder({G_SITOFP, G_UITOFP})
       .legalForCartesianProduct(allFloatScalarsAndVectors,
                                 allScalarsAndVectors);
diff --git a/llvm/test/CodeGen/SPIRV/llvm-intrinsics/fp_to_int_intrinsic.ll b/llvm/test/CodeGen/SPIRV/llvm-intrinsics/fp_to_int_intrinsic.ll
new file mode 100644
index 000000000000000..1f0feee1d914cd8
--- /dev/null
+++ b/llvm/test/CodeGen/SPIRV/llvm-intrinsics/fp_to_int_intrinsic.ll
@@ -0,0 +1,220 @@
+; RUN: llc -O0 -verify-machineinstrs -mtriple=spirv64-unkown-unknown %s -o - | FileCheck %s
+; RUN: %if spirv-tools %{ llc -O0 -mtriple=spirv64-unkown-unknown %s -o - -filetype=obj | spirv-val %}
+
+; CHECK: OpDecorate %[[#SAT1:]] SaturatedConversion
+; CHECK: OpDecorate %[[#SAT2:]] SaturatedConversion
+; CHECK: OpDecorate %[[#SAT3:]] SaturatedConversion
+; CHECK: OpDecorate %[[#SAT4:]] SaturatedConversion
+; CHECK: OpDecorate %[[#SAT5:]] SaturatedConversion
+; CHECK: OpDecorate %[[#SAT6:]] SaturatedConversion
+; CHECK: OpDecorate %[[#SAT7:]] SaturatedConversion
+; CHECK: OpDecorate %[[#SAT8:]] SaturatedConversion
+; CHECK: OpDecorate %[[#SAT9:]] SaturatedConversion
+; CHECK: OpDecorate %[[#SAT10:]] SaturatedConversion
+; CHECK: OpDecorate %[[#SAT11:]] SaturatedConversion
+; CHECK: OpDecorate %[[#SAT12:]] SaturatedConversion
+; CHECK: OpDecorate %[[#SAT13:]] SaturatedConversion
+; CHECK: OpDecorate %[[#SAT14:]] SaturatedConversion
+; CHECK: OpDecorate %[[#SAT15:]] SaturatedConversion
+
+
+; CHECK: %[[#SAT1:]] = OpConvertFToS %{{[0-9]+}} %[[#]]
+define spir_kernel void @testfunction_float_to_signed_i8(float %input) {
+entry:
+    %ptr = alloca i8
+   %0 = call i8 @llvm.fptosi.sat.i8.f32(float %input)
+   store i8 %0, i8* %ptr
+   ret void
+}
+declare i8 @llvm.fptosi.sat.i8.f32(float)
+
+
+; CHECK: %[[#SAT2:]] = OpConvertFToS %{{[0-9]+}} %[[#]]
+define spir_kernel void @testfunction_float_to_signed_i16(float %input) {
+entry:
+   %ptr = alloca i16
+   %0 = call i16 @llvm.fptosi.sat.i16.f32(float %input)
+   store i16 %0, i16* %ptr
+   ret void
+}
+declare i16 @llvm.fptosi.sat.i16.f32(float)
+
+;;;;;;; output i32
+
+; CHECK: %[[#SAT3:]] = OpConvertFToS %{{[0-9]+}} %[[#]]
+define spir_kernel void @testfunction_float_to_signed_i32(float %input) {
+entry:
+   %ptr = alloca i32
+   %0 = call i32 @llvm.fptosi.sat.i32.f32(float %input)
+   store i32 %0, i32* %ptr
+   ret void
+}
+declare i32 @llvm.fptosi.sat.i32.f32(float)
+
+;;;;;;; output i64
+; CHECK: %[[#SAT4:]] = OpConvertFToS %{{[0-9]+}} %[[#]]
+define spir_kernel void @testfunction_float_to_signed_i64(float %input) {
+entry:
+   %ptr = alloca i64
+   %0 = call i64 @llvm.fptosi.sat.i64.f32(float %input)
+   store i64 %0, i64* %ptr
+   ret void
+}
+declare i64 @llvm.fptosi.sat.i64.f32(float)
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+; double input
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+;;;;;;; output i8
+; CHECK: %[[#SAT5:]] = OpConvertFToS %{{[0-9]+}} %[[#]]
+define spir_kernel void @testfunction_double_to_signed_i8(double %input) {
+entry:
+   %ptr = alloca i8
+   %0 = call i8 @llvm.fptosi.sat.i8.f64(double %input)
+   store i8 %0, i8* %ptr
+   ret void
+}
+declare i8 @llvm.fptosi.sat.i8.f64(double)
+
+
+; CHECK: %[[#SAT6:]] = OpConvertFToS %{{[0-9]+}} %[[#]]
+define spir_kernel void @testfunction_double_to_signed_i16(double %input) {
+entry:
+   %ptr = alloca i16
+   %0 = call i16 @llvm.fptosi.sat.i16.f64(double %input)
+   store i16 %0, i16* %ptr
+   ret void
+}
+declare i16 @llvm.fptosi.sat.i16.f64(double)
+
+
+; CHECK: %[[#SAT7:]] = OpConvertFToS %{{[0-9]+}} %[[#]]
+define spir_kernel void @testfunction_double_to_signed_i32(double %input) {
+entry:
+   %ptr = alloca i32
+   %0 = call i32 @llvm.fptosi.sat.i32.f64(double %input)
+   store i32 %0, i32* %ptr
+   ret void
+}
+declare i32 @llvm.fptosi.sat.i32.f64(double)
+
+
+; CHECK: %[[#SAT8:]] = OpConvertFToS %{{[0-9]+}} %[[#]]
+define spir_kernel void @testfunction_double_to_signed_i64(double %input) {
+entry:
+   %ptr = alloca i64
+   %0 = call i64 @llvm.fptosi.sat.i64.f64(double %input)
+   store i64 %0, i64* %ptr
+   ret void
+}
+declare i64 @llvm.fptosi.sat.i64.f64(double)
+
+
+
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+; unsigned output
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+; float input
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+;;;;;;; output i8
+; CHECK: %[[#SAT8:]] = OpConvertFToU %{{[0-9]+}} %[[#]]
+define spir_kernel void @testfunction_float_to_unsigned_i8(float %input) {
+entry:
+   %ptr = alloca i8
+   %0 = call i8 @llvm.fptoui.sat.i8.f32(float %input)
+   store i8 %0, i8* %ptr
+   ret void
+}
+declare i8 @llvm.fptoui.sat.i8.f32(float)
+
+;;;;;;; output i16
+; CHECK: %[[#SAT9:]] = OpConvertFToU %{{[0-9]+}} %[[#]]
+define spir_kernel void @testfunction_float_to_unsigned_i16(float %input) {
+entry:
+   %ptr = alloca i16
+   %0 = call i16 @llvm.fptoui.sat.i16.f32(float %input)
+   store i16 %0, i16* %ptr
+   ret void
+}
+declare i16 @llvm.fptoui.sat.i16.f32(float)
+
+;;;;;;; output i32
+; CHECK: %[[#SAT10:]] = OpConvertFToU %{{[0-9]+}} %[[#]]
+define spir_kernel void @testfunction_float_to_unsigned_i32(float %input) {
+entry:
+   %ptr = alloca i32
+   %0 = call i32 @llvm.fptoui.sat.i32.f32(float %input)
+   store i32 %0, i32* %ptr
+   ret void
+}
+declare i32 @llvm.fptoui.sat.i32.f32(float)
+
+;;;;;;; output i64
+; CHECK: %[[#SAT11:]] = OpConvertFToU %{{[0-9]+}} %[[#]]
+define spir_kernel void @testfunction_float_to_unsigned_i64(float %input) {
+entry:
+   %ptr = alloca i64
+   %0 = call i64 @llvm.fptoui.sat.i64.f32(float %input)
+   store i64 %0, i64* %ptr
+   ret void
+}
+declare i64 @llvm.fptoui.sat.i64.f32(float)
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+; double input
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+;;;;;;; output i8
+; CHECK: %[[#SAT12:]] = OpConvertFToU %{{[0-9]+}} %[[#]]
+define spir_kernel void @testfunction_double_to_unsigned_i8(double %input) {
+entry:
+   %ptr = alloca i8
+   %0 = call i8 @llvm.fptoui.sat.i8.f64(double %input)
+   store i8 %0, i8* %ptr
+   ret void
+}
+declare i8 @llvm.fptoui.sat.i8.f64(double)
+
+;;;;;;; output i16
+; CHECK: %[[#SAT13:]] = OpConvertFToU %{{[0-9]+}} %[[#]]
+define spir_kernel void @testfunction_double_to_unsigned_i16(double %input) {
+entry:
+   %ptr = alloca i16
+   %0 = call i16 @llvm.fptoui.sat.i16.f64(double %input)
+   store i16 %0, i16* %ptr
+   ret void
+}
+declare i16 @llvm.fptoui.sat.i16.f64(double)
+
+;;;;;;; output i32
+; CHECK: %[[#SAT14:]] = OpConvertFToU %{{[0-9]+}} %[[#]]
+define spir_kernel void @testfunction_double_to_unsigned_i32(double %input) {
+entry:
+   %ptr = alloca i32
+   %0 = call i32 @llvm.fptoui.sat.i32.f64(double %input)
+   store i32 %0, i32* %ptr
+   ret void
+}
+declare i32 @llvm.fptoui.sat.i32.f64(double)
+
+;;;;;;; output i64
+; CHECK: %[[#SAT15:]] = OpConvertFToU %{{[0-9]+}} %[[#]]
+define spir_kernel void @testfunction_double_to_unsigned_i64(double %input) {
+entry:
+   %ptr = alloca i64
+   %0 = call i64 @llvm.fptoui.sat.i64.f64(double %input)
+   store i64 %0, i64* %ptr
+   ret void
+}
+declare i64 @llvm.fptoui.sat.i64.f64(double)
+
+
+
+



More information about the llvm-commits mailing list