-
Notifications
You must be signed in to change notification settings - Fork 15.4k
[spirv] Added lowering for llvm.sadd.with.overflow intrinsic #129475
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
Conversation
EbinJose2002
commented
Mar 3, 2025
- Added lowering for llvm intrinsic sadd.with.overflow
- Used the logic that overflow occurs when both operands are greater than zero and sum is less than any of the operands.
- Likewise overflow occurs when both operands are less than zero and sum is greater than any of the operands.
- Used a series of logical and comparison operations for this
- Added lowering for llvm intrinsic sadd.with.overflow - Used the logic that overflow occurs when both operands are greater than zero and sum is less than any of the operands. - Likewise overflow occurs when both operands are less than zero and sum is greater than any of the operands.
|
Thank you for submitting a Pull Request (PR) to the LLVM Project! This PR will be automatically labeled and the relevant teams will be notified. If you wish to, you can add reviewers by using the "Reviewers" section on this page. If this is not working for you, it is probably because you do not have write permissions for the repository. In which case you can instead tag reviewers by name in a comment by using If you have received no comments on your PR for a week, you can request a review by "ping"ing the PR by adding a comment “Ping”. The common courtesy "ping" rate is once a week. Please remember that you are asking for valuable time from other developers. If you have further questions, they may be answered by the LLVM GitHub User Guide. You can also ask questions in a comment on this PR, on the LLVM Discord or on the forums. |
|
@llvm/pr-subscribers-backend-spir-v Author: None (EbinJose2002) Changes
Full diff: https://github.com/llvm/llvm-project/pull/129475.diff 2 Files Affected:
diff --git a/llvm/lib/Target/SPIRV/SPIRVInstructionSelector.cpp b/llvm/lib/Target/SPIRV/SPIRVInstructionSelector.cpp
index c52b67e72a88c..8f6efc3b5f43c 100644
--- a/llvm/lib/Target/SPIRV/SPIRVInstructionSelector.cpp
+++ b/llvm/lib/Target/SPIRV/SPIRVInstructionSelector.cpp
@@ -202,6 +202,9 @@ class SPIRVInstructionSelector : public InstructionSelector {
bool selectOverflowArith(Register ResVReg, const SPIRVType *ResType,
MachineInstr &I, unsigned Opcode) const;
+ bool selectSignedOverflowArith(Register ResVReg, const SPIRVType *ResType,
+ MachineInstr &I, bool isVector) const;
+
bool selectIntegerDot(Register ResVReg, const SPIRVType *ResType,
MachineInstr &I, bool Signed) const;
@@ -509,7 +512,6 @@ static bool mayApplyGenericSelection(unsigned Opcode) {
switch (Opcode) {
case TargetOpcode::G_CONSTANT:
return false;
- case TargetOpcode::G_SADDO:
case TargetOpcode::G_SSUBO:
return true;
}
@@ -728,6 +730,11 @@ bool SPIRVInstructionSelector::spvSelect(Register ResVReg,
ResType->getOpcode() == SPIRV::OpTypeVector
? SPIRV::OpIAddCarryV
: SPIRV::OpIAddCarryS);
+ case TargetOpcode::G_SADDO:
+ return selectSignedOverflowArith(ResVReg, ResType, I,
+ ResType->getOpcode() == SPIRV::OpTypeVector
+ ? true
+ : false);
case TargetOpcode::G_USUBO:
return selectOverflowArith(ResVReg, ResType, I,
ResType->getOpcode() == SPIRV::OpTypeVector
@@ -1376,6 +1383,182 @@ bool SPIRVInstructionSelector::selectOverflowArith(Register ResVReg,
.constrainAllUses(TII, TRI, RBI);
}
+bool SPIRVInstructionSelector::selectSignedOverflowArith(Register ResVReg,
+ const SPIRVType *ResType,
+ MachineInstr &I,
+ bool isVector) const {
+
+
+//Checking overflow based on the logic that if two operands are positive and the sum is
+//less than one of the operands then an overflow occured. Likewise if two operands are
+//negative and if sum is greater than one operand then also overflow occured.
+
+ Type *ResTy = nullptr;
+ StringRef ResName;
+ MachineIRBuilder MIRBuilder(I);
+ if (!GR.findValueAttrs(&I, ResTy, ResName))
+ report_fatal_error(
+ "Not enough info to select the signed arithmetic instruction");
+ if (!ResTy || !ResTy->isStructTy())
+ report_fatal_error(
+ "Expect struct type result for the signed arithmetic instruction");
+
+ StructType *ResStructTy = cast<StructType>(ResTy);
+ Type *ResElemTy = ResStructTy->getElementType(0);
+ Type *OverflowTy = ResStructTy->getElementType(1);
+ ResTy = StructType::get(ResElemTy, OverflowTy);
+ SPIRVType *StructType = GR.getOrCreateSPIRVType(
+ ResTy, MIRBuilder, SPIRV::AccessQualifier::ReadWrite, false);
+ if (!StructType) {
+ report_fatal_error("Failed to create SPIR-V type for struct");
+ }
+ SPIRVType *BoolType = GR.getOrCreateSPIRVBoolType(I, TII);
+ unsigned N = GR.getScalarOrVectorComponentCount(ResType);
+ if (N > 1)
+ BoolType = GR.getOrCreateSPIRVVectorType(BoolType, N, I, TII);
+ Register BoolTypeReg = GR.getSPIRVTypeID(BoolType);
+ Register ZeroReg = buildZerosVal(ResType, I);
+ Register StructVReg = MRI->createGenericVirtualRegister(LLT::scalar(64));
+ MRI->setRegClass(StructVReg, &SPIRV::IDRegClass);
+
+ if (ResName.size() > 0)
+ buildOpName(StructVReg, ResName, MIRBuilder);
+
+ MachineBasicBlock &BB = *I.getParent();
+ Register SumVReg = MRI->createGenericVirtualRegister(LLT::scalar(64));
+ MRI->setRegClass(SumVReg, &SPIRV::IDRegClass);
+ SPIRVType *IntType = GR.getOrCreateSPIRVType(ResElemTy,MIRBuilder,SPIRV::AccessQualifier::ReadWrite,true);
+
+ auto SumMIB = BuildMI(BB, MIRBuilder.getInsertPt(), I.getDebugLoc(), TII.get(isVector ? SPIRV::OpIAddV : SPIRV::OpIAddS))
+ .addDef(SumVReg)
+ .addUse(GR.getSPIRVTypeID(IntType));
+ for (unsigned i = I.getNumDefs(); i < I.getNumOperands(); ++i)
+ SumMIB.addUse(I.getOperand(i).getReg());
+ bool Result = SumMIB.constrainAllUses(TII, TRI, RBI);
+
+ Register OverflowVReg = MRI->createGenericVirtualRegister(LLT::scalar(1));
+ MRI->setRegClass(OverflowVReg, &SPIRV::IDRegClass);
+ unsigned i = I.getNumDefs();
+
+ Register posCheck1 = MRI->createGenericVirtualRegister(LLT::scalar(1));
+ MRI->setRegClass(posCheck1, &SPIRV::IDRegClass);
+ Register posCheck2 = MRI->createGenericVirtualRegister(LLT::scalar(1));
+ MRI->setRegClass(posCheck2, &SPIRV::IDRegClass);
+ Register posCheck3 = MRI->createGenericVirtualRegister(LLT::scalar(1));
+ MRI->setRegClass(posCheck3, &SPIRV::IDRegClass);
+ Register posOverflow = MRI->createGenericVirtualRegister(LLT::scalar(1));
+ MRI->setRegClass(posOverflow, &SPIRV::IDRegClass);
+ Register posOverflowCheck = MRI->createGenericVirtualRegister(LLT::scalar(1));
+ MRI->setRegClass(posOverflowCheck, &SPIRV::IDRegClass);
+
+ BuildMI(BB, I, I.getDebugLoc(), TII.get(SPIRV::OpSGreaterThan))
+ .addDef(posCheck1)
+ .addUse(GR.getSPIRVTypeID(BoolType))
+ .addUse(I.getOperand(i).getReg())
+ .addUse(ZeroReg);
+ BuildMI(BB, I, I.getDebugLoc(), TII.get(SPIRV::OpSGreaterThan))
+ .addDef(posCheck2)
+ .addUse(GR.getSPIRVTypeID(BoolType))
+ .addUse(I.getOperand(i+1).getReg())
+ .addUse(ZeroReg);
+ BuildMI(BB, I, I.getDebugLoc(), TII.get(SPIRV::OpSLessThan))
+ .addDef(posCheck3)
+ .addUse(GR.getSPIRVTypeID(BoolType))
+ .addUse(SumVReg)
+ .addUse(I.getOperand(i+1).getReg());
+ BuildMI(BB, I, I.getDebugLoc(), TII.get(SPIRV::OpLogicalAnd))
+ .addDef(posOverflow)
+ .addUse(GR.getSPIRVTypeID(BoolType))
+ .addUse(posCheck1)
+ .addUse(posCheck2);
+ BuildMI(BB, I, I.getDebugLoc(), TII.get(SPIRV::OpLogicalAnd))
+ .addDef(posOverflowCheck)
+ .addUse(GR.getSPIRVTypeID(BoolType))
+ .addUse(posOverflow)
+ .addUse(posCheck3);
+
+ Register negCheck1 = MRI->createGenericVirtualRegister(LLT::scalar(1));
+ MRI->setRegClass(negCheck1, &SPIRV::IDRegClass);
+ Register negCheck2 = MRI->createGenericVirtualRegister(LLT::scalar(1));
+ MRI->setRegClass(negCheck2, &SPIRV::IDRegClass);
+ Register negCheck3 = MRI->createGenericVirtualRegister(LLT::scalar(1));
+ MRI->setRegClass(negCheck3, &SPIRV::IDRegClass);
+ Register negOverflow = MRI->createGenericVirtualRegister(LLT::scalar(1));
+ MRI->setRegClass(negOverflow, &SPIRV::IDRegClass);
+ Register negOverflowCheck = MRI->createGenericVirtualRegister(LLT::scalar(1));
+ MRI->setRegClass(negOverflowCheck, &SPIRV::IDRegClass);
+
+ BuildMI(BB, I, I.getDebugLoc(), TII.get(SPIRV::OpSLessThan))
+ .addDef(negCheck1)
+ .addUse(GR.getSPIRVTypeID(BoolType))
+ .addUse(I.getOperand(i).getReg())
+ .addUse(ZeroReg);
+ BuildMI(BB, I, I.getDebugLoc(), TII.get(SPIRV::OpSLessThan))
+ .addDef(negCheck2)
+ .addUse(GR.getSPIRVTypeID(BoolType))
+ .addUse(I.getOperand(i+1).getReg())
+ .addUse(ZeroReg);
+ BuildMI(BB, I, I.getDebugLoc(), TII.get(SPIRV::OpSGreaterThan))
+ .addDef(negCheck3)
+ .addUse(GR.getSPIRVTypeID(BoolType))
+ .addUse(SumVReg)
+ .addUse(I.getOperand(i+1).getReg());
+ BuildMI(BB, I, I.getDebugLoc(), TII.get(SPIRV::OpLogicalAnd))
+ .addDef(negOverflow)
+ .addUse(GR.getSPIRVTypeID(BoolType))
+ .addUse(negCheck1)
+ .addUse(negCheck2);
+ BuildMI(BB, I, I.getDebugLoc(), TII.get(SPIRV::OpLogicalAnd))
+ .addDef(negOverflowCheck)
+ .addUse(GR.getSPIRVTypeID(BoolType))
+ .addUse(negOverflow)
+ .addUse(negCheck3);
+
+ BuildMI(BB, I, I.getDebugLoc(), TII.get(SPIRV::OpLogicalOr))
+ .addDef(OverflowVReg)
+ .addUse(GR.getSPIRVTypeID(BoolType))
+ .addUse(negOverflowCheck)
+ .addUse(posOverflowCheck);
+
+ // Construct the result struct containing sum and overflow flag
+ BuildMI(BB, I, I.getDebugLoc(), TII.get(SPIRV::OpCompositeConstruct))
+ .addDef(StructVReg)
+ .addUse(GR.getSPIRVTypeID(StructType))
+ .addUse(SumVReg)
+ .addUse(OverflowVReg);
+
+ Register HigherVReg = MRI->createGenericVirtualRegister(LLT::scalar(64));
+ MRI->setRegClass(HigherVReg, &SPIRV::iIDRegClass);
+
+ for (unsigned i = 0; i < I.getNumDefs(); ++i) {
+ auto MIB =
+ BuildMI(BB, I, I.getDebugLoc(), TII.get(SPIRV::OpCompositeExtract))
+ .addDef(i == 1 ? HigherVReg : I.getOperand(i).getReg())
+ .addUse(i == 1 ? GR.getSPIRVTypeID(BoolType) : GR.getSPIRVTypeID(ResType))
+ .addUse(StructVReg)
+ .addImm(i);
+ Result &= MIB.constrainAllUses(TII, TRI, RBI);
+ }
+ Register FalseReg = MRI->createGenericVirtualRegister(LLT::scalar(1));
+ MRI->setRegClass(FalseReg, &SPIRV::IDRegClass);
+
+ // Use OpConstantFalse to initialize it
+ BuildMI(BB, I, I.getDebugLoc(), TII.get(SPIRV::OpConstantNull))
+ .addDef(FalseReg)
+ .addUse(GR.getSPIRVTypeID(BoolType));
+
+ BuildMI(BB, I, I.getDebugLoc(), TII.get(SPIRV::OpLogicalNotEqual))
+ .addDef(I.getOperand(1).getReg())
+ .addUse(BoolTypeReg)
+ .addUse(HigherVReg)
+ .addUse(FalseReg)
+ .constrainAllUses(TII, TRI, RBI);
+ return true;
+
+
+
+}
+
bool SPIRVInstructionSelector::selectAtomicCmpXchg(Register ResVReg,
const SPIRVType *ResType,
MachineInstr &I) const {
diff --git a/llvm/test/CodeGen/SPIRV/llvm-intrinsics/sadd.with.overflow.ll b/llvm/test/CodeGen/SPIRV/llvm-intrinsics/sadd.with.overflow.ll
new file mode 100644
index 0000000000000..a2ccfa1d11523
--- /dev/null
+++ b/llvm/test/CodeGen/SPIRV/llvm-intrinsics/sadd.with.overflow.ll
@@ -0,0 +1,161 @@
+; RUN: llc -verify-machineinstrs -O0 -mtriple=spirv32-unknown-unknown %s -o - | FileCheck %s
+; RUN: %if spirv-tools %{ llc -verify-machineinstrs -O0 -mtriple=spirv32-unknown-unknown %s -o - -filetype=obj | spirv-val %}
+
+; RUN: llc -verify-machineinstrs -O0 -mtriple=spirv64-unknown-unknown %s -o - | FileCheck %s
+; RUN: %if spirv-tools %{ llc -verify-machineinstrs -O0 -mtriple=spirv64-unknown-unknown %s -o - -filetype=obj | spirv-val %}
+
+;===---------------------------------------------------------------------===//
+; Type definitions.
+; CHECK-DAG: %[[I16:.*]] = OpTypeInt 16 0
+; CHECK-DAG: %[[Bool:.*]] = OpTypeBool
+; CHECK-DAG: %[[I32:.*]] = OpTypeInt 32 0
+; CHECK-DAG: %[[I64:.*]] = OpTypeInt 64 0
+; CHECK-DAG: %[[PtrI16:.*]] = OpTypePointer Function %[[I16]]
+; CHECK-DAG: %[[PtrI32:.*]] = OpTypePointer Function %[[I32]]
+; CHECK-DAG: %[[PtrI64:.*]] = OpTypePointer Function %[[I64]]
+; CHECK-DAG: %[[StructI16:.*]] = OpTypeStruct %[[I16]] %[[Bool]]
+; CHECK-DAG: %[[StructI32:.*]] = OpTypeStruct %[[I32]] %[[Bool]]
+; CHECK-DAG: %[[StructI64:.*]] = OpTypeStruct %[[I64]] %[[Bool]]
+; CHECK-DAG: %[[ZeroI16:.*]] = OpConstant %[[I16]] 0
+; CHECK-DAG: %[[ZeroI32:.*]] = OpConstant %[[I32]] 0
+; CHECK-DAG: %[[ZeroI64:.*]] = OpConstantNull %[[I64]]
+; CHECK-DAG: %[[V4I32:.*]] = OpTypeVector %[[I32]] 4
+; CHECK-DAG: %[[V4Bool:.*]] = OpTypeVector %[[Bool]] 4
+; CHECK-DAG: %[[PtrV4I32:.*]] = OpTypePointer Function %[[V4I32]]
+; CHECK-DAG: %[[StructV4I32:.*]] = OpTypeStruct %[[V4I32]] %[[V4Bool]]
+; CHECK-DAG: %[[ZeroV4I32:.*]] = OpConstantNull %[[V4I32]]
+;===---------------------------------------------------------------------===//
+; Function for i16 sadd.with.overflow.
+; CHECK: OpFunction
+; CHECK: %[[A16:.*]] = OpFunctionParameter %[[I16]]
+; CHECK: %[[B16:.*]] = OpFunctionParameter %[[I16]]
+; CHECK: %[[Ptr16:.*]] = OpFunctionParameter %[[PtrI16]]
+; CHECK: %[[Sum16:.*]] = OpIAdd %[[I16]] %[[A16]] %[[B16]]
+; CHECK: %[[PosCmp16_1:.*]] = OpSGreaterThan %[[Bool]] %[[A16]] %[[ZeroI16]]
+; CHECK: %[[PosCmp16_2:.*]] = OpSGreaterThan %[[Bool]] %[[B16]] %[[ZeroI16]]
+; CHECK: %[[PosCmp16_3:.*]] = OpSLessThan %[[Bool]] %[[Sum16]] %[[B16]]
+; CHECK: %[[PosCond16:.*]] = OpLogicalAnd %[[Bool]] %[[PosCmp16_1]] %[[PosCmp16_2]]
+; CHECK: %[[PosOverflow16:.*]] = OpLogicalAnd %[[Bool]] %[[PosCond16]] %[[PosCmp16_3]]
+; CHECK: %[[NegCmp16_1:.*]] = OpSLessThan %[[Bool]] %[[A16]] %[[ZeroI16]]
+; CHECK: %[[NegCmp16_2:.*]] = OpSLessThan %[[Bool]] %[[B16]] %[[ZeroI16]]
+; CHECK: %[[NegCmp16_3:.*]] = OpSGreaterThan %[[Bool]] %[[Sum16]] %[[B16]]
+; CHECK: %[[NegCond16:.*]] = OpLogicalAnd %[[Bool]] %[[NegCmp16_1]] %[[NegCmp16_2]]
+; CHECK: %[[NegOverflow16:.*]] = OpLogicalAnd %[[Bool]] %[[NegCond16]] %[[NegCmp16_3]]
+; CHECK: %[[Overflow16:.*]] = OpLogicalOr %[[Bool]] %[[NegOverflow16]] %[[PosOverflow16]]
+; CHECK: %[[Comp16:.*]] = OpCompositeConstruct %[[StructI16]] %[[Sum16]] %[[Overflow16]]
+; CHECK: %[[ExtOver16:.*]] = OpCompositeExtract %[[Bool]] %[[Comp16]] 1
+; CHECK: %[[Final16:.*]] = OpLogicalNotEqual %[[Bool]] %[[ExtOver16]] %[[#]]
+; CHECK: OpReturn
+define spir_func void @smulo_i16(i16 %a, i16 %b, ptr nocapture %c) {
+entry:
+ %umul = tail call { i16, i1 } @llvm.sadd.with.overflow.i16(i16 %a, i16 %b)
+ %cmp = extractvalue { i16, i1 } %umul, 1
+ %umul.value = extractvalue { i16, i1 } %umul, 0
+ %storemerge = select i1 %cmp, i16 0, i16 %umul.value
+ store i16 %storemerge, ptr %c, align 1
+ ret void
+}
+
+;===---------------------------------------------------------------------===//
+; Function for i32 sadd.with.overflow.
+; CHECK: OpFunction
+; CHECK: %[[A32:.*]] = OpFunctionParameter %[[I32]]
+; CHECK: %[[B32:.*]] = OpFunctionParameter %[[I32]]
+; CHECK: %[[Ptr32:.*]] = OpFunctionParameter %[[PtrI32]]
+; CHECK: %[[Sum32:.*]] = OpIAdd %[[I32]] %[[A32]] %[[B32]]
+; CHECK: %[[PosCmp32_1:.*]] = OpSGreaterThan %[[Bool]] %[[A32]] %[[ZeroI32]]
+; CHECK: %[[PosCmp32_2:.*]] = OpSGreaterThan %[[Bool]] %[[B32]] %[[ZeroI32]]
+; CHECK: %[[PosCmp32_3:.*]] = OpSLessThan %[[Bool]] %[[Sum32]] %[[B32]]
+; CHECK: %[[PosCond32:.*]] = OpLogicalAnd %[[Bool]] %[[PosCmp32_1]] %[[PosCmp32_2]]
+; CHECK: %[[PosOverflow32:.*]] = OpLogicalAnd %[[Bool]] %[[PosCond32]] %[[PosCmp32_3]]
+; CHECK: %[[NegCmp32_1:.*]] = OpSLessThan %[[Bool]] %[[A32]] %[[ZeroI32]]
+; CHECK: %[[NegCmp32_2:.*]] = OpSLessThan %[[Bool]] %[[B32]] %[[ZeroI32]]
+; CHECK: %[[NegCmp32_3:.*]] = OpSGreaterThan %[[Bool]] %[[Sum32]] %[[B32]]
+; CHECK: %[[NegCond32:.*]] = OpLogicalAnd %[[Bool]] %[[NegCmp32_1]] %[[NegCmp32_2]]
+; CHECK: %[[NegOverflow32:.*]] = OpLogicalAnd %[[Bool]] %[[NegCond32]] %[[NegCmp32_3]]
+; CHECK: %[[Overflow32:.*]] = OpLogicalOr %[[Bool]] %[[NegOverflow32]] %[[PosOverflow32]]
+; CHECK: %[[Comp32:.*]] = OpCompositeConstruct %[[StructI32]] %[[Sum32]] %[[Overflow32]]
+; CHECK: %[[ExtOver32:.*]] = OpCompositeExtract %[[Bool]] %[[Comp32]] 1
+; CHECK: %[[Final32:.*]] = OpLogicalNotEqual %[[Bool]] %[[ExtOver32]] %[[#]]
+; CHECK: OpReturn
+define spir_func void @smulo_i32(i32 %a, i32 %b, ptr nocapture %c) {
+entry:
+ %umul = tail call { i32, i1 } @llvm.sadd.with.overflow.i32(i32 %a, i32 %b)
+ %cmp = extractvalue { i32, i1 } %umul, 1
+ %umul.value = extractvalue { i32, i1 } %umul, 0
+ %storemerge = select i1 %cmp, i32 0, i32 %umul.value
+ store i32 %storemerge, ptr %c, align 4
+ ret void
+}
+
+;===---------------------------------------------------------------------===//
+; Function for i64 sadd.with.overflow.
+; CHECK: OpFunction
+; CHECK: %[[A64:.*]] = OpFunctionParameter %[[I64]]
+; CHECK: %[[B64:.*]] = OpFunctionParameter %[[I64]]
+; CHECK: %[[Ptr64:.*]] = OpFunctionParameter %[[PtrI64]]
+; CHECK: %[[Sum64:.*]] = OpIAdd %[[I64]] %[[A64]] %[[B64]]
+; CHECK: %[[PosCmp64_1:.*]] = OpSGreaterThan %[[Bool]] %[[A64]] %[[ZeroI64]]
+; CHECK: %[[PosCmp64_2:.*]] = OpSGreaterThan %[[Bool]] %[[B64]] %[[ZeroI64]]
+; CHECK: %[[PosCmp64_3:.*]] = OpSLessThan %[[Bool]] %[[Sum64]] %[[B64]]
+; CHECK: %[[PosCond64:.*]] = OpLogicalAnd %[[Bool]] %[[PosCmp64_1]] %[[PosCmp64_2]]
+; CHECK: %[[PosOverflow64:.*]] = OpLogicalAnd %[[Bool]] %[[PosCond64]] %[[PosCmp64_3]]
+; CHECK: %[[NegCmp64_1:.*]] = OpSLessThan %[[Bool]] %[[A64]] %[[ZeroI64]]
+; CHECK: %[[NegCmp64_2:.*]] = OpSLessThan %[[Bool]] %[[B64]] %[[ZeroI64]]
+; CHECK: %[[NegCmp64_3:.*]] = OpSGreaterThan %[[Bool]] %[[Sum64]] %[[B64]]
+; CHECK: %[[NegCond64:.*]] = OpLogicalAnd %[[Bool]] %[[NegCmp64_1]] %[[NegCmp64_2]]
+; CHECK: %[[NegOverflow64:.*]] = OpLogicalAnd %[[Bool]] %[[NegCond64]] %[[NegCmp64_3]]
+; CHECK: %[[Overflow64:.*]] = OpLogicalOr %[[Bool]] %[[NegOverflow64]] %[[PosOverflow64]]
+; CHECK: %[[Comp64:.*]] = OpCompositeConstruct %[[StructI64]] %[[Sum64]] %[[Overflow64]]
+; CHECK: %[[ExtOver64:.*]] = OpCompositeExtract %[[Bool]] %[[Comp64]] 1
+; CHECK: %[[Final64:.*]] = OpLogicalNotEqual %[[Bool]] %[[ExtOver64]] %[[#]]
+; CHECK: OpReturn
+define spir_func void @smulo_i64(i64 %a, i64 %b, ptr nocapture %c) {
+entry:
+ %umul = tail call { i64, i1 } @llvm.sadd.with.overflow.i64(i64 %a, i64 %b)
+ %cmp = extractvalue { i64, i1 } %umul, 1
+ %umul.value = extractvalue { i64, i1 } %umul, 0
+ %storemerge = select i1 %cmp, i64 0, i64 %umul.value
+ store i64 %storemerge, ptr %c, align 8
+ ret void
+}
+
+;===---------------------------------------------------------------------===//
+; Function for vector (4 x i32) sadd.with.overflow.
+
+; CHECK: OpFunction
+; CHECK: %[[A4:.*]] = OpFunctionParameter %[[V4I32]]
+; CHECK: %[[B4:.*]] = OpFunctionParameter %[[V4I32]]
+; CHECK: %[[Ptr4:.*]] = OpFunctionParameter %[[PtrV4I32]]
+; CHECK: %[[Sum4:.*]] = OpIAdd %[[V4I32]] %[[A4]] %[[B4]]
+; CHECK: %[[PosCmp4_1:.*]] = OpSGreaterThan %[[V4Bool]] %[[A4]] %[[ZeroV4I32]]
+; CHECK: %[[PosCmp4_2:.*]] = OpSGreaterThan %[[V4Bool]] %[[B4]] %[[ZeroV4I32]]
+; CHECK: %[[PosCmp4_3:.*]] = OpSLessThan %[[V4Bool]] %[[Sum4]] %[[B4]]
+; CHECK: %[[PosCond4:.*]] = OpLogicalAnd %[[V4Bool]] %[[PosCmp4_1]] %[[PosCmp4_2]]
+; CHECK: %[[PosOverflow4:.*]] = OpLogicalAnd %[[V4Bool]] %[[PosCond4]] %[[PosCmp4_3]]
+; CHECK: %[[NegCmp4_1:.*]] = OpSLessThan %[[V4Bool]] %[[A4]] %[[ZeroV4I32]]
+; CHECK: %[[NegCmp4_2:.*]] = OpSLessThan %[[V4Bool]] %[[B4]] %[[ZeroV4I32]]
+; CHECK: %[[NegCmp4_3:.*]] = OpSGreaterThan %[[V4Bool]] %[[Sum4]] %[[B4]]
+; CHECK: %[[NegCond4:.*]] = OpLogicalAnd %[[V4Bool]] %[[NegCmp4_1]] %[[NegCmp4_2]]
+; CHECK: %[[NegOverflow4:.*]] = OpLogicalAnd %[[V4Bool]] %[[NegCond4]] %[[NegCmp4_3]]
+; CHECK: %[[Overflow4:.*]] = OpLogicalOr %[[V4Bool]] %[[NegOverflow4]] %[[PosOverflow4]]
+; CHECK: %[[Comp4:.*]] = OpCompositeConstruct %[[StructV4I32]] %[[Sum4]] %[[Overflow4]]
+; CHECK: %[[ExtOver4:.*]] = OpCompositeExtract %[[V4Bool]] %[[Comp4]] 1
+; CHECK: %[[Final4:.*]] = OpLogicalNotEqual %[[V4Bool]] %[[ExtOver4]] %[[#]]
+; CHECK: OpReturn
+define spir_func void @smulo_v4i32(<4 x i32> %a, <4 x i32> %b, ptr nocapture %c) {
+entry:
+ %umul = tail call { <4 x i32>, <4 x i1> } @llvm.sadd.with.overflow.v4i32(<4 x i32> %a, <4 x i32> %b)
+ %cmp = extractvalue { <4 x i32>, <4 x i1> } %umul, 1
+ %umul.value = extractvalue { <4 x i32>, <4 x i1> } %umul, 0
+ %storemerge = select <4 x i1> %cmp, <4 x i32> zeroinitializer, <4 x i32> %umul.value
+ store <4 x i32> %storemerge, ptr %c, align 16
+ ret void
+}
+
+;===---------------------------------------------------------------------===//
+; Declarations of the intrinsics.
+declare { i16, i1 } @llvm.sadd.with.overflow.i16(i16, i16)
+declare { i32, i1 } @llvm.sadd.with.overflow.i32(i32, i32)
+declare { i64, i1 } @llvm.sadd.with.overflow.i64(i64, i64)
+declare { <4 x i32>, <4 x i1> } @llvm.sadd.with.overflow.v4i32(<4 x i32>, <4 x i32>)
|
|
See discussion on #125805 |
You can test this locally with the following command:git-clang-format --diff e42ab4c54eca0e792a0ae461481f9acbd0260363 1dfb08ce291171de681c35905b874351569bafca --extensions cpp -- llvm/lib/Target/SPIRV/SPIRVInstructionSelector.cppView the diff from clang-format here.diff --git a/llvm/lib/Target/SPIRV/SPIRVInstructionSelector.cpp b/llvm/lib/Target/SPIRV/SPIRVInstructionSelector.cpp
index dce53b07b5..31749c45d6 100644
--- a/llvm/lib/Target/SPIRV/SPIRVInstructionSelector.cpp
+++ b/llvm/lib/Target/SPIRV/SPIRVInstructionSelector.cpp
@@ -203,7 +203,7 @@ private:
MachineInstr &I, unsigned Opcode) const;
bool selectSignedOverflowArith(Register ResVReg, const SPIRVType *ResType,
- MachineInstr &I, bool isVector) const;
+ MachineInstr &I, bool isVector) const;
bool selectIntegerDot(Register ResVReg, const SPIRVType *ResType,
MachineInstr &I, bool Signed) const;
@@ -1535,7 +1535,7 @@ bool SPIRVInstructionSelector::selectSignedOverflowArith(
BuildMI(BB, I, I.getDebugLoc(), TII.get(SPIRV::OpCompositeExtract))
.addDef(i == 1 ? HigherVReg : I.getOperand(i).getReg())
.addUse(i == 1 ? GR.getSPIRVTypeID(BoolType)
- : GR.getSPIRVTypeID(ResType))
+ : GR.getSPIRVTypeID(ResType))
.addUse(StructVReg)
.addImm(i);
Result &= MIB.constrainAllUses(TII, TRI, RBI);
|