Skip to content

[SPIRV] Add sign intrinsic part 1 #101987

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Sep 9, 2024
Merged

[SPIRV] Add sign intrinsic part 1 #101987

merged 1 commit into from
Sep 9, 2024

Conversation

tgymnich
Copy link
Member

@tgymnich tgymnich commented Aug 5, 2024

partially fixes #70078

Changes

  • Added int_spv_sign intrinsic in IntrinsicsSPIRV.td
  • Added lowering and map to int_spv_sign in SPIRVInstructionSelector.cpp`
  • Added SPIR-V backend test case in llvm/test/CodeGen/SPIRV/hlsl-intrinsics/sign.ll

Related PRs

Copy link

github-actions bot commented Aug 5, 2024

✅ With the latest revision this PR passed the C/C++ code formatter.

@llvmbot
Copy link
Member

llvmbot commented Aug 5, 2024

@llvm/pr-subscribers-llvm-ir

Author: Tim Gymnich (tgymnich)

Changes

partially fixes #70078

Changes

  • Added int_spv_sign intrinsic in IntrinsicsSPIRV.td
  • Added lowering and map to int_spv_sign in SPIRVInstructionSelector.cpp`
  • Added SPIR-V backend test case in llvm/test/CodeGen/SPIRV/hlsl-intrinsics/sign.ll

Related PRs


Full diff: https://github.com/llvm/llvm-project/pull/101987.diff

3 Files Affected:

  • (modified) llvm/include/llvm/IR/IntrinsicsSPIRV.td (+1)
  • (modified) llvm/lib/Target/SPIRV/SPIRVInstructionSelector.cpp (+52)
  • (added) llvm/test/CodeGen/SPIRV/hlsl-intrinsics/sign.ll (+143)
diff --git a/llvm/include/llvm/IR/IntrinsicsSPIRV.td b/llvm/include/llvm/IR/IntrinsicsSPIRV.td
index 3f77ef6bfcdbe..89eacf2ba70f9 100644
--- a/llvm/include/llvm/IR/IntrinsicsSPIRV.td
+++ b/llvm/include/llvm/IR/IntrinsicsSPIRV.td
@@ -65,4 +65,5 @@ let TargetPrefix = "spv" in {
     [IntrNoMem, IntrWillReturn] >;
   def int_spv_length : DefaultAttrsIntrinsic<[LLVMVectorElementType<0>], [llvm_anyfloat_ty]>;
   def int_spv_rsqrt : DefaultAttrsIntrinsic<[LLVMMatchType<0>], [llvm_anyfloat_ty]>;
+  def int_spv_sign : DefaultAttrsIntrinsic<[LLVMScalarOrSameVectorWidth<0, llvm_i32_ty>], [llvm_any_ty]>;
 }
diff --git a/llvm/lib/Target/SPIRV/SPIRVInstructionSelector.cpp b/llvm/lib/Target/SPIRV/SPIRVInstructionSelector.cpp
index ed786bd33aa05..47e4b3dd40339 100644
--- a/llvm/lib/Target/SPIRV/SPIRVInstructionSelector.cpp
+++ b/llvm/lib/Target/SPIRV/SPIRVInstructionSelector.cpp
@@ -28,6 +28,7 @@
 #include "llvm/CodeGen/MachineInstrBuilder.h"
 #include "llvm/CodeGen/MachineModuleInfoImpls.h"
 #include "llvm/CodeGen/MachineRegisterInfo.h"
+#include "llvm/CodeGen/Register.h"
 #include "llvm/CodeGen/TargetOpcodes.h"
 #include "llvm/IR/IntrinsicsSPIRV.h"
 #include "llvm/Support/Debug.h"
@@ -178,6 +179,9 @@ class SPIRVInstructionSelector : public InstructionSelector {
   bool selectRsqrt(Register ResVReg, const SPIRVType *ResType,
                    MachineInstr &I) const;
 
+  bool selectSign(Register ResVReg, const SPIRVType *ResType,
+                  MachineInstr &I) const;
+
   void renderImm32(MachineInstrBuilder &MIB, const MachineInstr &I,
                    int OpIdx) const;
   void renderFImm32(MachineInstrBuilder &MIB, const MachineInstr &I,
@@ -1366,6 +1370,52 @@ bool SPIRVInstructionSelector::selectRsqrt(Register ResVReg,
       .constrainAllUses(TII, TRI, RBI);
 }
 
+bool SPIRVInstructionSelector::selectSign(Register ResVReg,
+                                          const SPIRVType *ResType,
+                                          MachineInstr &I) const {
+  assert(I.getNumOperands() == 3);
+  assert(I.getOperand(2).isReg());
+  MachineBasicBlock &BB = *I.getParent();
+  Register InputRegister = I.getOperand(2).getReg();
+  SPIRVType *InputType = GR.getSPIRVTypeForVReg(InputRegister);
+  auto &DL = I.getDebugLoc();
+
+  if (!InputType)
+    report_fatal_error("Input Type could not be determined.");
+
+  bool IsFloatTy = GR.isScalarOrVectorOfType(InputRegister, SPIRV::OpTypeFloat);
+
+  unsigned SignBitWidth = GR.getScalarOrVectorBitWidth(InputType);
+  unsigned ResBitWidth = GR.getScalarOrVectorBitWidth(ResType);
+
+  bool NeedsConversion = IsFloatTy || SignBitWidth != ResBitWidth;
+
+  auto SignOpcode = IsFloatTy ? GL::FSign : GL::SSign;
+  Register SignReg = NeedsConversion
+                         ? MRI->createVirtualRegister(&SPIRV::IDRegClass)
+                         : ResVReg;
+
+  bool Result =
+      BuildMI(BB, I, DL, TII.get(SPIRV::OpExtInst))
+          .addDef(SignReg)
+          .addUse(GR.getSPIRVTypeID(InputType))
+          .addImm(static_cast<uint32_t>(SPIRV::InstructionSet::GLSL_std_450))
+          .addImm(SignOpcode)
+          .addUse(InputRegister)
+          .constrainAllUses(TII, TRI, RBI);
+
+  if (NeedsConversion) {
+    auto ConvertOpcode = IsFloatTy ? SPIRV::OpConvertFToS : SPIRV::OpSConvert;
+    Result |= BuildMI(*I.getParent(), I, DL, TII.get(ConvertOpcode))
+                  .addDef(ResVReg)
+                  .addUse(GR.getSPIRVTypeID(ResType))
+                  .addUse(SignReg)
+                  .constrainAllUses(TII, TRI, RBI);
+  }
+
+  return Result;
+}
+
 bool SPIRVInstructionSelector::selectBitreverse(Register ResVReg,
                                                 const SPIRVType *ResType,
                                                 MachineInstr &I) const {
@@ -2082,6 +2132,8 @@ bool SPIRVInstructionSelector::selectIntrinsic(Register ResVReg,
     return selectFrac(ResVReg, ResType, I);
   case Intrinsic::spv_rsqrt:
     return selectRsqrt(ResVReg, ResType, I);
+  case Intrinsic::spv_sign:
+    return selectSign(ResVReg, ResType, I);
   case Intrinsic::spv_lifetime_start:
   case Intrinsic::spv_lifetime_end: {
     unsigned Op = IID == Intrinsic::spv_lifetime_start ? SPIRV::OpLifetimeStart
diff --git a/llvm/test/CodeGen/SPIRV/hlsl-intrinsics/sign.ll b/llvm/test/CodeGen/SPIRV/hlsl-intrinsics/sign.ll
new file mode 100644
index 0000000000000..52a41c3d3ad64
--- /dev/null
+++ b/llvm/test/CodeGen/SPIRV/hlsl-intrinsics/sign.ll
@@ -0,0 +1,143 @@
+; RUN: llc -O0 -mtriple=spirv-unknown-unknown %s -o - | FileCheck %s
+; RUN: %if spirv-tools %{ llc -O0 -mtriple=spirv-unknown-unknown %s -o - -filetype=obj | spirv-val %}
+
+; CHECK-DAG: %[[#op_ext_glsl:]] = OpExtInstImport "GLSL.std.450"
+
+; CHECK-DAG: %[[#float_16:]] = OpTypeFloat 16
+; CHECK-DAG: %[[#float_32:]] = OpTypeFloat 32
+; CHECK-DAG: %[[#float_64:]] = OpTypeFloat 64
+
+; CHECK-DAG: %[[#int_16:]] = OpTypeInt 16
+; CHECK-DAG: %[[#int_32:]] = OpTypeInt 32
+; CHECK-DAG: %[[#int_64:]] = OpTypeInt 64
+
+; CHECK-DAG: %[[#vec4_float_16:]] = OpTypeVector %[[#float_16]] 4
+; CHECK-DAG: %[[#vec4_float_32:]] = OpTypeVector %[[#float_32]] 4
+; CHECK-DAG: %[[#vec4_float_64:]] = OpTypeVector %[[#float_64]] 4
+
+; CHECK-DAG: %[[#vec4_int_16:]] = OpTypeVector %[[#int_16]] 4
+; CHECK-DAG: %[[#vec4_int_32:]] = OpTypeVector %[[#int_32]] 4
+; CHECK-DAG: %[[#vec4_int_64:]] = OpTypeVector %[[#int_64]] 4
+
+
+define noundef i32 @sign_half(half noundef %a) {
+entry:
+; CHECK: %[[#float_16_arg:]] = OpFunctionParameter %[[#float_16]]
+; CHECK: %[[#fsign:]] = OpExtInst %[[#float_16]] %[[#op_ext_glsl]] FSign %[[#float_16_arg]]
+; CHECK: %[[#]] = OpConvertFToS %[[#int_32]] %[[#fsign]]
+  %elt.sign = call i32 @llvm.spv.sign.f16(half %a)
+  ret i32 %elt.sign
+}
+
+define noundef i32 @sign_float(float noundef %a) {
+entry:
+; CHECK: %[[#float_32_arg:]] = OpFunctionParameter %[[#float_32]]
+; CHECK: %[[#fsign:]] = OpExtInst %[[#float_32]] %[[#op_ext_glsl]] FSign %[[#float_32_arg]]
+; CHECK: %[[#]] = OpConvertFToS %[[#int_32]] %[[#fsign]]
+  %elt.sign = call i32 @llvm.spv.sign.f32(float %a)
+  ret i32 %elt.sign
+}
+
+define noundef i32 @sign_double(double noundef %a) {
+entry:
+; CHECK: %[[#float_64_arg:]] = OpFunctionParameter %[[#float_64]]
+; CHECK: %[[#fsign:]] = OpExtInst %[[#float_64]] %[[#op_ext_glsl]] FSign %[[#float_64_arg]]
+; CHECK: %[[#]] = OpConvertFToS %[[#int_32]] %[[#fsign]]
+  %elt.sign = call i32 @llvm.spv.sign.f64(double %a)
+  ret i32 %elt.sign
+}
+
+define noundef i32 @sign_i16(i16 noundef %a) {
+entry:
+; CHECK: %[[#int_16_arg:]] = OpFunctionParameter %[[#int_16]]
+; CHECK: %[[#ssign:]] = OpExtInst %[[#int_16]] %[[#op_ext_glsl]] SSign %[[#int_16_arg]]
+; CHECK: %[[#]] = OpSConvert %[[#int_32]] %[[#ssign]]
+  %elt.sign = call i32 @llvm.spv.sign.i16(i16 %a)
+  ret i32 %elt.sign
+}
+
+define noundef i32 @sign_i32(i32 noundef %a) {
+entry:
+; CHECK: %[[#int_32_arg:]] = OpFunctionParameter %[[#int_32]]
+; CHECK: %[[#]] = OpExtInst %[[#int_32]] %[[#op_ext_glsl]] SSign %[[#int_32_arg]]
+  %elt.sign = call i32 @llvm.spv.sign.i32(i32 %a)
+  ret i32 %elt.sign
+}
+
+define noundef i32 @sign_i64(i64 noundef %a) {
+entry:
+; CHECK: %[[#int_64_arg:]] = OpFunctionParameter %[[#int_64]]
+; CHECK: %[[#ssign:]] = OpExtInst %[[#int_64]] %[[#op_ext_glsl]] SSign %[[#int_64_arg]]
+; CHECK: %[[#]] = OpSConvert %[[#int_32]] %[[#ssign]]
+  %elt.sign = call i32 @llvm.spv.sign.i64(i64 %a)
+  ret i32 %elt.sign
+}
+
+define noundef <4 x i32> @sign_half_vector(<4 x half> noundef %a) {
+entry:
+; CHECK: %[[#vec4_float_16_arg:]] = OpFunctionParameter %[[#vec4_float_16]]
+; CHECK: %[[#fsign:]] = OpExtInst %[[#vec4_float_16]] %[[#op_ext_glsl]] FSign %[[#vec4_float_16_arg]]
+; CHECK: %[[#]] = OpConvertFToS %[[#vec4_int_32]] %[[#fsign]]
+  %elt.sign = call <4 x i32> @llvm.spv.sign.v4f16(<4 x half> %a)
+  ret <4 x i32> %elt.sign
+}
+
+define noundef <4 x i32> @sign_float_vector(<4 x float> noundef %a) {
+entry:
+; CHECK: %[[#vec4_float_32_arg:]] = OpFunctionParameter %[[#vec4_float_32]]
+; CHECK: %[[#fsign:]] = OpExtInst %[[#vec4_float_32]] %[[#op_ext_glsl]] FSign %[[#vec4_float_32_arg]]
+; CHECK: %[[#]] = OpConvertFToS %[[#vec4_int_32]] %[[#fsign]]
+  %elt.sign = call <4 x i32> @llvm.spv.sign.v4f32(<4 x float> %a)
+  ret <4 x i32> %elt.sign
+}
+
+define noundef <4 x i32> @sign_double_vector(<4 x double> noundef %a) {
+entry:
+; CHECK: %[[#vec4_float_64_arg:]] = OpFunctionParameter %[[#vec4_float_64]]
+; CHECK: %[[#fsign:]] = OpExtInst %[[#vec4_float_64]] %[[#op_ext_glsl]] FSign %[[#vec4_float_64_arg]]
+; CHECK: %[[#]] = OpConvertFToS %[[#vec4_int_32]] %[[#fsign]]
+  %elt.sign = call <4 x i32> @llvm.spv.sign.v4f64(<4 x double> %a)
+  ret <4 x i32> %elt.sign
+}
+
+define noundef <4 x i32> @sign_i16_vector(<4 x i16> noundef %a) {
+entry:
+; CHECK: %[[#vec4_int_16_arg:]] = OpFunctionParameter %[[#vec4_int_16]]
+; CHECK: %[[#ssign:]] = OpExtInst %[[#vec4_int_16]] %[[#op_ext_glsl]] SSign %[[#vec4_int_16_arg]]
+; CHECK: %[[#]] = OpSConvert %[[#vec4_int_32]] %[[#ssign]]
+  %elt.sign = call <4 x i32> @llvm.spv.sign.v4i16(<4 x i16> %a)
+  ret <4 x i32> %elt.sign
+}
+
+define noundef <4 x i32> @sign_i32_vector(<4 x i32> noundef %a) {
+entry:
+; CHECK: %[[#vec4_int_32_arg:]] = OpFunctionParameter %[[#vec4_int_32]]
+; CHECK: %[[#]] = OpExtInst %[[#vec4_int_32]] %[[#op_ext_glsl]] SSign %[[#vec4_int_32_arg]]
+  %elt.sign = call <4 x i32> @llvm.spv.sign.v4i32(<4 x i32> %a)
+  ret <4 x i32> %elt.sign
+}
+
+define noundef <4 x i32> @sign_i64_vector(<4 x i64> noundef %a) {
+entry:
+; CHECK: %[[#vec4_int_64_arg:]] = OpFunctionParameter %[[#vec4_int_64]]
+; CHECK: %[[#ssign:]] = OpExtInst %[[#vec4_int_64]] %[[#op_ext_glsl]] SSign %[[#vec4_int_64_arg]]
+; CHECK: %[[#]] = OpSConvert %[[#vec4_int_32]] %[[#ssign]]
+  %elt.sign = call <4 x i32> @llvm.spv.sign.v4i64(<4 x i64> %a)
+  ret <4 x i32> %elt.sign
+}
+
+declare i32 @llvm.spv.sign.f16(half)
+declare i32 @llvm.spv.sign.f32(float)
+declare i32 @llvm.spv.sign.f64(double)
+
+declare i32 @llvm.spv.sign.i16(i16)
+declare i32 @llvm.spv.sign.i32(i32)
+declare i32 @llvm.spv.sign.i64(i64)
+
+declare <4 x i32> @llvm.spv.sign.v4f16(<4 x half>)
+declare <4 x i32> @llvm.spv.sign.v4f32(<4 x float>)
+declare <4 x i32> @llvm.spv.sign.v4f64(<4 x double>)
+
+declare <4 x i32> @llvm.spv.sign.v4i16(<4 x i16>)
+declare <4 x i32> @llvm.spv.sign.v4i32(<4 x i32>)
+declare <4 x i32> @llvm.spv.sign.v4i64(<4 x i64>)

@llvmbot
Copy link
Member

llvmbot commented Aug 5, 2024

@llvm/pr-subscribers-backend-spir-v

Author: Tim Gymnich (tgymnich)

Changes

partially fixes #70078

Changes

  • Added int_spv_sign intrinsic in IntrinsicsSPIRV.td
  • Added lowering and map to int_spv_sign in SPIRVInstructionSelector.cpp`
  • Added SPIR-V backend test case in llvm/test/CodeGen/SPIRV/hlsl-intrinsics/sign.ll

Related PRs


Full diff: https://github.com/llvm/llvm-project/pull/101987.diff

3 Files Affected:

  • (modified) llvm/include/llvm/IR/IntrinsicsSPIRV.td (+1)
  • (modified) llvm/lib/Target/SPIRV/SPIRVInstructionSelector.cpp (+52)
  • (added) llvm/test/CodeGen/SPIRV/hlsl-intrinsics/sign.ll (+143)
diff --git a/llvm/include/llvm/IR/IntrinsicsSPIRV.td b/llvm/include/llvm/IR/IntrinsicsSPIRV.td
index 3f77ef6bfcdbe..89eacf2ba70f9 100644
--- a/llvm/include/llvm/IR/IntrinsicsSPIRV.td
+++ b/llvm/include/llvm/IR/IntrinsicsSPIRV.td
@@ -65,4 +65,5 @@ let TargetPrefix = "spv" in {
     [IntrNoMem, IntrWillReturn] >;
   def int_spv_length : DefaultAttrsIntrinsic<[LLVMVectorElementType<0>], [llvm_anyfloat_ty]>;
   def int_spv_rsqrt : DefaultAttrsIntrinsic<[LLVMMatchType<0>], [llvm_anyfloat_ty]>;
+  def int_spv_sign : DefaultAttrsIntrinsic<[LLVMScalarOrSameVectorWidth<0, llvm_i32_ty>], [llvm_any_ty]>;
 }
diff --git a/llvm/lib/Target/SPIRV/SPIRVInstructionSelector.cpp b/llvm/lib/Target/SPIRV/SPIRVInstructionSelector.cpp
index ed786bd33aa05..47e4b3dd40339 100644
--- a/llvm/lib/Target/SPIRV/SPIRVInstructionSelector.cpp
+++ b/llvm/lib/Target/SPIRV/SPIRVInstructionSelector.cpp
@@ -28,6 +28,7 @@
 #include "llvm/CodeGen/MachineInstrBuilder.h"
 #include "llvm/CodeGen/MachineModuleInfoImpls.h"
 #include "llvm/CodeGen/MachineRegisterInfo.h"
+#include "llvm/CodeGen/Register.h"
 #include "llvm/CodeGen/TargetOpcodes.h"
 #include "llvm/IR/IntrinsicsSPIRV.h"
 #include "llvm/Support/Debug.h"
@@ -178,6 +179,9 @@ class SPIRVInstructionSelector : public InstructionSelector {
   bool selectRsqrt(Register ResVReg, const SPIRVType *ResType,
                    MachineInstr &I) const;
 
+  bool selectSign(Register ResVReg, const SPIRVType *ResType,
+                  MachineInstr &I) const;
+
   void renderImm32(MachineInstrBuilder &MIB, const MachineInstr &I,
                    int OpIdx) const;
   void renderFImm32(MachineInstrBuilder &MIB, const MachineInstr &I,
@@ -1366,6 +1370,52 @@ bool SPIRVInstructionSelector::selectRsqrt(Register ResVReg,
       .constrainAllUses(TII, TRI, RBI);
 }
 
+bool SPIRVInstructionSelector::selectSign(Register ResVReg,
+                                          const SPIRVType *ResType,
+                                          MachineInstr &I) const {
+  assert(I.getNumOperands() == 3);
+  assert(I.getOperand(2).isReg());
+  MachineBasicBlock &BB = *I.getParent();
+  Register InputRegister = I.getOperand(2).getReg();
+  SPIRVType *InputType = GR.getSPIRVTypeForVReg(InputRegister);
+  auto &DL = I.getDebugLoc();
+
+  if (!InputType)
+    report_fatal_error("Input Type could not be determined.");
+
+  bool IsFloatTy = GR.isScalarOrVectorOfType(InputRegister, SPIRV::OpTypeFloat);
+
+  unsigned SignBitWidth = GR.getScalarOrVectorBitWidth(InputType);
+  unsigned ResBitWidth = GR.getScalarOrVectorBitWidth(ResType);
+
+  bool NeedsConversion = IsFloatTy || SignBitWidth != ResBitWidth;
+
+  auto SignOpcode = IsFloatTy ? GL::FSign : GL::SSign;
+  Register SignReg = NeedsConversion
+                         ? MRI->createVirtualRegister(&SPIRV::IDRegClass)
+                         : ResVReg;
+
+  bool Result =
+      BuildMI(BB, I, DL, TII.get(SPIRV::OpExtInst))
+          .addDef(SignReg)
+          .addUse(GR.getSPIRVTypeID(InputType))
+          .addImm(static_cast<uint32_t>(SPIRV::InstructionSet::GLSL_std_450))
+          .addImm(SignOpcode)
+          .addUse(InputRegister)
+          .constrainAllUses(TII, TRI, RBI);
+
+  if (NeedsConversion) {
+    auto ConvertOpcode = IsFloatTy ? SPIRV::OpConvertFToS : SPIRV::OpSConvert;
+    Result |= BuildMI(*I.getParent(), I, DL, TII.get(ConvertOpcode))
+                  .addDef(ResVReg)
+                  .addUse(GR.getSPIRVTypeID(ResType))
+                  .addUse(SignReg)
+                  .constrainAllUses(TII, TRI, RBI);
+  }
+
+  return Result;
+}
+
 bool SPIRVInstructionSelector::selectBitreverse(Register ResVReg,
                                                 const SPIRVType *ResType,
                                                 MachineInstr &I) const {
@@ -2082,6 +2132,8 @@ bool SPIRVInstructionSelector::selectIntrinsic(Register ResVReg,
     return selectFrac(ResVReg, ResType, I);
   case Intrinsic::spv_rsqrt:
     return selectRsqrt(ResVReg, ResType, I);
+  case Intrinsic::spv_sign:
+    return selectSign(ResVReg, ResType, I);
   case Intrinsic::spv_lifetime_start:
   case Intrinsic::spv_lifetime_end: {
     unsigned Op = IID == Intrinsic::spv_lifetime_start ? SPIRV::OpLifetimeStart
diff --git a/llvm/test/CodeGen/SPIRV/hlsl-intrinsics/sign.ll b/llvm/test/CodeGen/SPIRV/hlsl-intrinsics/sign.ll
new file mode 100644
index 0000000000000..52a41c3d3ad64
--- /dev/null
+++ b/llvm/test/CodeGen/SPIRV/hlsl-intrinsics/sign.ll
@@ -0,0 +1,143 @@
+; RUN: llc -O0 -mtriple=spirv-unknown-unknown %s -o - | FileCheck %s
+; RUN: %if spirv-tools %{ llc -O0 -mtriple=spirv-unknown-unknown %s -o - -filetype=obj | spirv-val %}
+
+; CHECK-DAG: %[[#op_ext_glsl:]] = OpExtInstImport "GLSL.std.450"
+
+; CHECK-DAG: %[[#float_16:]] = OpTypeFloat 16
+; CHECK-DAG: %[[#float_32:]] = OpTypeFloat 32
+; CHECK-DAG: %[[#float_64:]] = OpTypeFloat 64
+
+; CHECK-DAG: %[[#int_16:]] = OpTypeInt 16
+; CHECK-DAG: %[[#int_32:]] = OpTypeInt 32
+; CHECK-DAG: %[[#int_64:]] = OpTypeInt 64
+
+; CHECK-DAG: %[[#vec4_float_16:]] = OpTypeVector %[[#float_16]] 4
+; CHECK-DAG: %[[#vec4_float_32:]] = OpTypeVector %[[#float_32]] 4
+; CHECK-DAG: %[[#vec4_float_64:]] = OpTypeVector %[[#float_64]] 4
+
+; CHECK-DAG: %[[#vec4_int_16:]] = OpTypeVector %[[#int_16]] 4
+; CHECK-DAG: %[[#vec4_int_32:]] = OpTypeVector %[[#int_32]] 4
+; CHECK-DAG: %[[#vec4_int_64:]] = OpTypeVector %[[#int_64]] 4
+
+
+define noundef i32 @sign_half(half noundef %a) {
+entry:
+; CHECK: %[[#float_16_arg:]] = OpFunctionParameter %[[#float_16]]
+; CHECK: %[[#fsign:]] = OpExtInst %[[#float_16]] %[[#op_ext_glsl]] FSign %[[#float_16_arg]]
+; CHECK: %[[#]] = OpConvertFToS %[[#int_32]] %[[#fsign]]
+  %elt.sign = call i32 @llvm.spv.sign.f16(half %a)
+  ret i32 %elt.sign
+}
+
+define noundef i32 @sign_float(float noundef %a) {
+entry:
+; CHECK: %[[#float_32_arg:]] = OpFunctionParameter %[[#float_32]]
+; CHECK: %[[#fsign:]] = OpExtInst %[[#float_32]] %[[#op_ext_glsl]] FSign %[[#float_32_arg]]
+; CHECK: %[[#]] = OpConvertFToS %[[#int_32]] %[[#fsign]]
+  %elt.sign = call i32 @llvm.spv.sign.f32(float %a)
+  ret i32 %elt.sign
+}
+
+define noundef i32 @sign_double(double noundef %a) {
+entry:
+; CHECK: %[[#float_64_arg:]] = OpFunctionParameter %[[#float_64]]
+; CHECK: %[[#fsign:]] = OpExtInst %[[#float_64]] %[[#op_ext_glsl]] FSign %[[#float_64_arg]]
+; CHECK: %[[#]] = OpConvertFToS %[[#int_32]] %[[#fsign]]
+  %elt.sign = call i32 @llvm.spv.sign.f64(double %a)
+  ret i32 %elt.sign
+}
+
+define noundef i32 @sign_i16(i16 noundef %a) {
+entry:
+; CHECK: %[[#int_16_arg:]] = OpFunctionParameter %[[#int_16]]
+; CHECK: %[[#ssign:]] = OpExtInst %[[#int_16]] %[[#op_ext_glsl]] SSign %[[#int_16_arg]]
+; CHECK: %[[#]] = OpSConvert %[[#int_32]] %[[#ssign]]
+  %elt.sign = call i32 @llvm.spv.sign.i16(i16 %a)
+  ret i32 %elt.sign
+}
+
+define noundef i32 @sign_i32(i32 noundef %a) {
+entry:
+; CHECK: %[[#int_32_arg:]] = OpFunctionParameter %[[#int_32]]
+; CHECK: %[[#]] = OpExtInst %[[#int_32]] %[[#op_ext_glsl]] SSign %[[#int_32_arg]]
+  %elt.sign = call i32 @llvm.spv.sign.i32(i32 %a)
+  ret i32 %elt.sign
+}
+
+define noundef i32 @sign_i64(i64 noundef %a) {
+entry:
+; CHECK: %[[#int_64_arg:]] = OpFunctionParameter %[[#int_64]]
+; CHECK: %[[#ssign:]] = OpExtInst %[[#int_64]] %[[#op_ext_glsl]] SSign %[[#int_64_arg]]
+; CHECK: %[[#]] = OpSConvert %[[#int_32]] %[[#ssign]]
+  %elt.sign = call i32 @llvm.spv.sign.i64(i64 %a)
+  ret i32 %elt.sign
+}
+
+define noundef <4 x i32> @sign_half_vector(<4 x half> noundef %a) {
+entry:
+; CHECK: %[[#vec4_float_16_arg:]] = OpFunctionParameter %[[#vec4_float_16]]
+; CHECK: %[[#fsign:]] = OpExtInst %[[#vec4_float_16]] %[[#op_ext_glsl]] FSign %[[#vec4_float_16_arg]]
+; CHECK: %[[#]] = OpConvertFToS %[[#vec4_int_32]] %[[#fsign]]
+  %elt.sign = call <4 x i32> @llvm.spv.sign.v4f16(<4 x half> %a)
+  ret <4 x i32> %elt.sign
+}
+
+define noundef <4 x i32> @sign_float_vector(<4 x float> noundef %a) {
+entry:
+; CHECK: %[[#vec4_float_32_arg:]] = OpFunctionParameter %[[#vec4_float_32]]
+; CHECK: %[[#fsign:]] = OpExtInst %[[#vec4_float_32]] %[[#op_ext_glsl]] FSign %[[#vec4_float_32_arg]]
+; CHECK: %[[#]] = OpConvertFToS %[[#vec4_int_32]] %[[#fsign]]
+  %elt.sign = call <4 x i32> @llvm.spv.sign.v4f32(<4 x float> %a)
+  ret <4 x i32> %elt.sign
+}
+
+define noundef <4 x i32> @sign_double_vector(<4 x double> noundef %a) {
+entry:
+; CHECK: %[[#vec4_float_64_arg:]] = OpFunctionParameter %[[#vec4_float_64]]
+; CHECK: %[[#fsign:]] = OpExtInst %[[#vec4_float_64]] %[[#op_ext_glsl]] FSign %[[#vec4_float_64_arg]]
+; CHECK: %[[#]] = OpConvertFToS %[[#vec4_int_32]] %[[#fsign]]
+  %elt.sign = call <4 x i32> @llvm.spv.sign.v4f64(<4 x double> %a)
+  ret <4 x i32> %elt.sign
+}
+
+define noundef <4 x i32> @sign_i16_vector(<4 x i16> noundef %a) {
+entry:
+; CHECK: %[[#vec4_int_16_arg:]] = OpFunctionParameter %[[#vec4_int_16]]
+; CHECK: %[[#ssign:]] = OpExtInst %[[#vec4_int_16]] %[[#op_ext_glsl]] SSign %[[#vec4_int_16_arg]]
+; CHECK: %[[#]] = OpSConvert %[[#vec4_int_32]] %[[#ssign]]
+  %elt.sign = call <4 x i32> @llvm.spv.sign.v4i16(<4 x i16> %a)
+  ret <4 x i32> %elt.sign
+}
+
+define noundef <4 x i32> @sign_i32_vector(<4 x i32> noundef %a) {
+entry:
+; CHECK: %[[#vec4_int_32_arg:]] = OpFunctionParameter %[[#vec4_int_32]]
+; CHECK: %[[#]] = OpExtInst %[[#vec4_int_32]] %[[#op_ext_glsl]] SSign %[[#vec4_int_32_arg]]
+  %elt.sign = call <4 x i32> @llvm.spv.sign.v4i32(<4 x i32> %a)
+  ret <4 x i32> %elt.sign
+}
+
+define noundef <4 x i32> @sign_i64_vector(<4 x i64> noundef %a) {
+entry:
+; CHECK: %[[#vec4_int_64_arg:]] = OpFunctionParameter %[[#vec4_int_64]]
+; CHECK: %[[#ssign:]] = OpExtInst %[[#vec4_int_64]] %[[#op_ext_glsl]] SSign %[[#vec4_int_64_arg]]
+; CHECK: %[[#]] = OpSConvert %[[#vec4_int_32]] %[[#ssign]]
+  %elt.sign = call <4 x i32> @llvm.spv.sign.v4i64(<4 x i64> %a)
+  ret <4 x i32> %elt.sign
+}
+
+declare i32 @llvm.spv.sign.f16(half)
+declare i32 @llvm.spv.sign.f32(float)
+declare i32 @llvm.spv.sign.f64(double)
+
+declare i32 @llvm.spv.sign.i16(i16)
+declare i32 @llvm.spv.sign.i32(i32)
+declare i32 @llvm.spv.sign.i64(i64)
+
+declare <4 x i32> @llvm.spv.sign.v4f16(<4 x half>)
+declare <4 x i32> @llvm.spv.sign.v4f32(<4 x float>)
+declare <4 x i32> @llvm.spv.sign.v4f64(<4 x double>)
+
+declare <4 x i32> @llvm.spv.sign.v4i16(<4 x i16>)
+declare <4 x i32> @llvm.spv.sign.v4i32(<4 x i32>)
+declare <4 x i32> @llvm.spv.sign.v4i64(<4 x i64>)

@tgymnich tgymnich force-pushed the hlsl-sign-1 branch 2 times, most recently from cac6f19 to 87eb441 Compare August 29, 2024 18:18
farzonl pushed a commit that referenced this pull request Sep 5, 2024
makes progress on #70078

### Changes
- Added `int_dx_sign` intrinsic in `IntrinsicsDirectX.td`
- Added expansion for `int_dx_sign in `DXILIntrinsicExpansion.cpp`
- Added DXIL backend test case

### Related PRs
- #101987
- #101989
Copy link
Member

@farzonl farzonl left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

Copy link
Contributor

@pow2clk pow2clk left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good!

@farzonl farzonl merged commit a9a5a18 into llvm:main Sep 9, 2024
9 checks passed
@tgymnich tgymnich deleted the hlsl-sign-1 branch September 9, 2024 22:02
farzonl pushed a commit that referenced this pull request Sep 10, 2024
partially fixes #70078

### Changes
- Implemented `sign` clang builtin
- Linked `sign` clang builtin with `hlsl_intrinsics.h`
- Added sema checks for `sign` to `CheckHLSLBuiltinFunctionCall` in
`SemaChecking.cpp`
- Add codegen for `sign` to `EmitHLSLBuiltinExpr` in `CGBuiltin.cpp`
- Add codegen tests to `clang/test/CodeGenHLSL/builtins/sign.hlsl`
- Add sema tests to `clang/test/SemaHLSL/BuiltIns/sign-errors.hlsl`

### Related PRs
- #101987
- #101988

### Discussion
- Should there be a `usign` intrinsic that handles the unsigned cases?
farzonl pushed a commit that referenced this pull request Oct 10, 2024
- Add handling for unsigned integers to hlsl_elementwise_sign
- Use `select` instead of adding dx and spirv intrinsics for unsigned
integers as [discussed previously
](#101988 (comment))

fixes #70078

### Related PRs
- #101987
- #101988
- #101989

cc @farzonl @pow2clk @bob80905 @bogner @llvm-beanz
DanielCChen pushed a commit to DanielCChen/llvm-project that referenced this pull request Oct 16, 2024
- Add handling for unsigned integers to hlsl_elementwise_sign
- Use `select` instead of adding dx and spirv intrinsics for unsigned
integers as [discussed previously
](llvm#101988 (comment))

fixes llvm#70078

### Related PRs
- llvm#101987
- llvm#101988
- llvm#101989

cc @farzonl @pow2clk @bob80905 @bogner @llvm-beanz
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Implement the sign HLSL Function
4 participants