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