@@ -202,6 +202,9 @@ class SPIRVInstructionSelector : public InstructionSelector {
202202 bool selectOverflowArith (Register ResVReg, const SPIRVType *ResType,
203203 MachineInstr &I, unsigned Opcode) const ;
204204
205+ bool selectSignedOverflowArith (Register ResVReg, const SPIRVType *ResType,
206+ MachineInstr &I, bool isVector) const ;
207+
205208 bool selectIntegerDot (Register ResVReg, const SPIRVType *ResType,
206209 MachineInstr &I, bool Signed) const ;
207210
@@ -509,7 +512,6 @@ static bool mayApplyGenericSelection(unsigned Opcode) {
509512 switch (Opcode) {
510513 case TargetOpcode::G_CONSTANT:
511514 return false ;
512- case TargetOpcode::G_SADDO:
513515 case TargetOpcode::G_SSUBO:
514516 return true ;
515517 }
@@ -728,6 +730,11 @@ bool SPIRVInstructionSelector::spvSelect(Register ResVReg,
728730 ResType->getOpcode () == SPIRV::OpTypeVector
729731 ? SPIRV::OpIAddCarryV
730732 : SPIRV::OpIAddCarryS);
733+ case TargetOpcode::G_SADDO:
734+ return selectSignedOverflowArith (ResVReg, ResType, I,
735+ ResType->getOpcode () == SPIRV::OpTypeVector
736+ ? true
737+ : false );
731738 case TargetOpcode::G_USUBO:
732739 return selectOverflowArith (ResVReg, ResType, I,
733740 ResType->getOpcode () == SPIRV::OpTypeVector
@@ -1376,6 +1383,182 @@ bool SPIRVInstructionSelector::selectOverflowArith(Register ResVReg,
13761383 .constrainAllUses (TII, TRI, RBI);
13771384}
13781385
1386+ bool SPIRVInstructionSelector::selectSignedOverflowArith (Register ResVReg,
1387+ const SPIRVType *ResType,
1388+ MachineInstr &I,
1389+ bool isVector) const {
1390+
1391+
1392+ // Checking overflow based on the logic that if two operands are positive and the sum is
1393+ // less than one of the operands then an overflow occured. Likewise if two operands are
1394+ // negative and if sum is greater than one operand then also overflow occured.
1395+
1396+ Type *ResTy = nullptr ;
1397+ StringRef ResName;
1398+ MachineIRBuilder MIRBuilder (I);
1399+ if (!GR.findValueAttrs (&I, ResTy, ResName))
1400+ report_fatal_error (
1401+ " Not enough info to select the signed arithmetic instruction" );
1402+ if (!ResTy || !ResTy->isStructTy ())
1403+ report_fatal_error (
1404+ " Expect struct type result for the signed arithmetic instruction" );
1405+
1406+ StructType *ResStructTy = cast<StructType>(ResTy);
1407+ Type *ResElemTy = ResStructTy->getElementType (0 );
1408+ Type *OverflowTy = ResStructTy->getElementType (1 );
1409+ ResTy = StructType::get (ResElemTy, OverflowTy);
1410+ SPIRVType *StructType = GR.getOrCreateSPIRVType (
1411+ ResTy, MIRBuilder, SPIRV::AccessQualifier::ReadWrite, false );
1412+ if (!StructType) {
1413+ report_fatal_error (" Failed to create SPIR-V type for struct" );
1414+ }
1415+ SPIRVType *BoolType = GR.getOrCreateSPIRVBoolType (I, TII);
1416+ unsigned N = GR.getScalarOrVectorComponentCount (ResType);
1417+ if (N > 1 )
1418+ BoolType = GR.getOrCreateSPIRVVectorType (BoolType, N, I, TII);
1419+ Register BoolTypeReg = GR.getSPIRVTypeID (BoolType);
1420+ Register ZeroReg = buildZerosVal (ResType, I);
1421+ Register StructVReg = MRI->createGenericVirtualRegister (LLT::scalar (64 ));
1422+ MRI->setRegClass (StructVReg, &SPIRV::IDRegClass);
1423+
1424+ if (ResName.size () > 0 )
1425+ buildOpName (StructVReg, ResName, MIRBuilder);
1426+
1427+ MachineBasicBlock &BB = *I.getParent ();
1428+ Register SumVReg = MRI->createGenericVirtualRegister (LLT::scalar (64 ));
1429+ MRI->setRegClass (SumVReg, &SPIRV::IDRegClass);
1430+ SPIRVType *IntType = GR.getOrCreateSPIRVType (ResElemTy,MIRBuilder,SPIRV::AccessQualifier::ReadWrite,true );
1431+
1432+ auto SumMIB = BuildMI (BB, MIRBuilder.getInsertPt (), I.getDebugLoc (), TII.get (isVector ? SPIRV::OpIAddV : SPIRV::OpIAddS))
1433+ .addDef (SumVReg)
1434+ .addUse (GR.getSPIRVTypeID (IntType));
1435+ for (unsigned i = I.getNumDefs (); i < I.getNumOperands (); ++i)
1436+ SumMIB.addUse (I.getOperand (i).getReg ());
1437+ bool Result = SumMIB.constrainAllUses (TII, TRI, RBI);
1438+
1439+ Register OverflowVReg = MRI->createGenericVirtualRegister (LLT::scalar (1 ));
1440+ MRI->setRegClass (OverflowVReg, &SPIRV::IDRegClass);
1441+ unsigned i = I.getNumDefs ();
1442+
1443+ Register posCheck1 = MRI->createGenericVirtualRegister (LLT::scalar (1 ));
1444+ MRI->setRegClass (posCheck1, &SPIRV::IDRegClass);
1445+ Register posCheck2 = MRI->createGenericVirtualRegister (LLT::scalar (1 ));
1446+ MRI->setRegClass (posCheck2, &SPIRV::IDRegClass);
1447+ Register posCheck3 = MRI->createGenericVirtualRegister (LLT::scalar (1 ));
1448+ MRI->setRegClass (posCheck3, &SPIRV::IDRegClass);
1449+ Register posOverflow = MRI->createGenericVirtualRegister (LLT::scalar (1 ));
1450+ MRI->setRegClass (posOverflow, &SPIRV::IDRegClass);
1451+ Register posOverflowCheck = MRI->createGenericVirtualRegister (LLT::scalar (1 ));
1452+ MRI->setRegClass (posOverflowCheck, &SPIRV::IDRegClass);
1453+
1454+ BuildMI (BB, I, I.getDebugLoc (), TII.get (SPIRV::OpSGreaterThan))
1455+ .addDef (posCheck1)
1456+ .addUse (GR.getSPIRVTypeID (BoolType))
1457+ .addUse (I.getOperand (i).getReg ())
1458+ .addUse (ZeroReg);
1459+ BuildMI (BB, I, I.getDebugLoc (), TII.get (SPIRV::OpSGreaterThan))
1460+ .addDef (posCheck2)
1461+ .addUse (GR.getSPIRVTypeID (BoolType))
1462+ .addUse (I.getOperand (i+1 ).getReg ())
1463+ .addUse (ZeroReg);
1464+ BuildMI (BB, I, I.getDebugLoc (), TII.get (SPIRV::OpSLessThan))
1465+ .addDef (posCheck3)
1466+ .addUse (GR.getSPIRVTypeID (BoolType))
1467+ .addUse (SumVReg)
1468+ .addUse (I.getOperand (i+1 ).getReg ());
1469+ BuildMI (BB, I, I.getDebugLoc (), TII.get (SPIRV::OpLogicalAnd))
1470+ .addDef (posOverflow)
1471+ .addUse (GR.getSPIRVTypeID (BoolType))
1472+ .addUse (posCheck1)
1473+ .addUse (posCheck2);
1474+ BuildMI (BB, I, I.getDebugLoc (), TII.get (SPIRV::OpLogicalAnd))
1475+ .addDef (posOverflowCheck)
1476+ .addUse (GR.getSPIRVTypeID (BoolType))
1477+ .addUse (posOverflow)
1478+ .addUse (posCheck3);
1479+
1480+ Register negCheck1 = MRI->createGenericVirtualRegister (LLT::scalar (1 ));
1481+ MRI->setRegClass (negCheck1, &SPIRV::IDRegClass);
1482+ Register negCheck2 = MRI->createGenericVirtualRegister (LLT::scalar (1 ));
1483+ MRI->setRegClass (negCheck2, &SPIRV::IDRegClass);
1484+ Register negCheck3 = MRI->createGenericVirtualRegister (LLT::scalar (1 ));
1485+ MRI->setRegClass (negCheck3, &SPIRV::IDRegClass);
1486+ Register negOverflow = MRI->createGenericVirtualRegister (LLT::scalar (1 ));
1487+ MRI->setRegClass (negOverflow, &SPIRV::IDRegClass);
1488+ Register negOverflowCheck = MRI->createGenericVirtualRegister (LLT::scalar (1 ));
1489+ MRI->setRegClass (negOverflowCheck, &SPIRV::IDRegClass);
1490+
1491+ BuildMI (BB, I, I.getDebugLoc (), TII.get (SPIRV::OpSLessThan))
1492+ .addDef (negCheck1)
1493+ .addUse (GR.getSPIRVTypeID (BoolType))
1494+ .addUse (I.getOperand (i).getReg ())
1495+ .addUse (ZeroReg);
1496+ BuildMI (BB, I, I.getDebugLoc (), TII.get (SPIRV::OpSLessThan))
1497+ .addDef (negCheck2)
1498+ .addUse (GR.getSPIRVTypeID (BoolType))
1499+ .addUse (I.getOperand (i+1 ).getReg ())
1500+ .addUse (ZeroReg);
1501+ BuildMI (BB, I, I.getDebugLoc (), TII.get (SPIRV::OpSGreaterThan))
1502+ .addDef (negCheck3)
1503+ .addUse (GR.getSPIRVTypeID (BoolType))
1504+ .addUse (SumVReg)
1505+ .addUse (I.getOperand (i+1 ).getReg ());
1506+ BuildMI (BB, I, I.getDebugLoc (), TII.get (SPIRV::OpLogicalAnd))
1507+ .addDef (negOverflow)
1508+ .addUse (GR.getSPIRVTypeID (BoolType))
1509+ .addUse (negCheck1)
1510+ .addUse (negCheck2);
1511+ BuildMI (BB, I, I.getDebugLoc (), TII.get (SPIRV::OpLogicalAnd))
1512+ .addDef (negOverflowCheck)
1513+ .addUse (GR.getSPIRVTypeID (BoolType))
1514+ .addUse (negOverflow)
1515+ .addUse (negCheck3);
1516+
1517+ BuildMI (BB, I, I.getDebugLoc (), TII.get (SPIRV::OpLogicalOr))
1518+ .addDef (OverflowVReg)
1519+ .addUse (GR.getSPIRVTypeID (BoolType))
1520+ .addUse (negOverflowCheck)
1521+ .addUse (posOverflowCheck);
1522+
1523+ // Construct the result struct containing sum and overflow flag
1524+ BuildMI (BB, I, I.getDebugLoc (), TII.get (SPIRV::OpCompositeConstruct))
1525+ .addDef (StructVReg)
1526+ .addUse (GR.getSPIRVTypeID (StructType))
1527+ .addUse (SumVReg)
1528+ .addUse (OverflowVReg);
1529+
1530+ Register HigherVReg = MRI->createGenericVirtualRegister (LLT::scalar (64 ));
1531+ MRI->setRegClass (HigherVReg, &SPIRV::iIDRegClass);
1532+
1533+ for (unsigned i = 0 ; i < I.getNumDefs (); ++i) {
1534+ auto MIB =
1535+ BuildMI (BB, I, I.getDebugLoc (), TII.get (SPIRV::OpCompositeExtract))
1536+ .addDef (i == 1 ? HigherVReg : I.getOperand (i).getReg ())
1537+ .addUse (i == 1 ? GR.getSPIRVTypeID (BoolType) : GR.getSPIRVTypeID (ResType))
1538+ .addUse (StructVReg)
1539+ .addImm (i);
1540+ Result &= MIB.constrainAllUses (TII, TRI, RBI);
1541+ }
1542+ Register FalseReg = MRI->createGenericVirtualRegister (LLT::scalar (1 ));
1543+ MRI->setRegClass (FalseReg, &SPIRV::IDRegClass);
1544+
1545+ // Use OpConstantFalse to initialize it
1546+ BuildMI (BB, I, I.getDebugLoc (), TII.get (SPIRV::OpConstantNull))
1547+ .addDef (FalseReg)
1548+ .addUse (GR.getSPIRVTypeID (BoolType));
1549+
1550+ BuildMI (BB, I, I.getDebugLoc (), TII.get (SPIRV::OpLogicalNotEqual))
1551+ .addDef (I.getOperand (1 ).getReg ())
1552+ .addUse (BoolTypeReg)
1553+ .addUse (HigherVReg)
1554+ .addUse (FalseReg)
1555+ .constrainAllUses (TII, TRI, RBI);
1556+ return true ;
1557+
1558+
1559+
1560+ }
1561+
13791562bool SPIRVInstructionSelector::selectAtomicCmpXchg (Register ResVReg,
13801563 const SPIRVType *ResType,
13811564 MachineInstr &I) const {
0 commit comments