Index: lib/CodeGen/GlobalISel/LegalizerHelper.cpp =================================================================== --- lib/CodeGen/GlobalISel/LegalizerHelper.cpp +++ lib/CodeGen/GlobalISel/LegalizerHelper.cpp @@ -619,6 +619,32 @@ switch (MI.getOpcode()) { default: return UnableToLegalize; + case TargetOpcode::G_UADDO: + case TargetOpcode::G_USUBO: { + if (TypeIdx == 1) + return UnableToLegalize; // TODO + auto LHSZext = MIRBuilder.buildInstr(TargetOpcode::G_ZEXT, WideTy, + MI.getOperand(2).getReg()); + auto RHSZext = MIRBuilder.buildInstr(TargetOpcode::G_ZEXT, WideTy, + MI.getOperand(3).getReg()); + unsigned Opcode = MI.getOpcode() == TargetOpcode::G_UADDO + ? TargetOpcode::G_ADD + : TargetOpcode::G_SUB; + // Do the arithmetic in the larger type. + auto NewOp = MIRBuilder.buildInstr(Opcode, WideTy, LHSZext, RHSZext); + LLT OrigTy = MRI.getType(MI.getOperand(0).getReg()); + APInt Mask = APInt::getAllOnesValue(OrigTy.getSizeInBits()); + auto AndOp = MIRBuilder.buildInstr( + TargetOpcode::G_AND, WideTy, NewOp, + MIRBuilder.buildConstant(WideTy, Mask.getZExtValue())); + // There is no overflow if the AndOp is the same as NewOp. + MIRBuilder.buildICmp(CmpInst::ICMP_NE, MI.getOperand(1).getReg(), NewOp, + AndOp); + // Now trunc the NewOp to the original result. + MIRBuilder.buildTrunc(MI.getOperand(0).getReg(), NewOp); + MI.eraseFromParent(); + return Legalized; + } case TargetOpcode::G_CTTZ: case TargetOpcode::G_CTTZ_ZERO_UNDEF: case TargetOpcode::G_CTLZ: Index: unittests/CodeGen/GlobalISel/LegalizerHelperTest.cpp =================================================================== --- unittests/CodeGen/GlobalISel/LegalizerHelperTest.cpp +++ unittests/CodeGen/GlobalISel/LegalizerHelperTest.cpp @@ -342,4 +342,79 @@ // Check ASSERT_TRUE(CheckMachineFunction(*MF, CheckStr)); } +// UADDO widening. +TEST_F(LegalizerHelperTest, WidenUADDO) { + if (!TM) + return; + + // Declare your legalization info + DefineLegalizerInfo(A, + { getActionDefinitionsBuilder(G_ADD).legalFor({s16}); }); + // Build + // Trunc it to s8. + LLT s8{LLT::scalar(8)}; + LLT s16{LLT::scalar(16)}; + auto MIBTrunc = B.buildTrunc(s8, Copies[0]); + unsigned CarryReg = MRI->createGenericVirtualRegister(LLT::scalar(1)); + auto MIBUAddO = B.buildInstr(TargetOpcode::G_UADDO, s8) + .addDef(CarryReg) + .addUse(MIBTrunc->getOperand(0).getReg()) + .addUse(MIBTrunc->getOperand(0).getReg()); + AInfo Info(MF->getSubtarget()); + LegalizerHelper Helper(*MF, Info); + ASSERT_TRUE(Helper.widenScalar(*MIBUAddO, 0, s16) == + LegalizerHelper::LegalizeResult::Legalized); + + auto CheckStr = R"( + CHECK: [[Trunc:%[0-9]+]]:_(s8) = G_TRUNC + CHECK: [[LHS:%[0-9]+]]:_(s16) = G_ZEXT [[Trunc]] + CHECK: [[RHS:%[0-9]+]]:_(s16) = G_ZEXT [[Trunc]] + CHECK: [[ADD:%[0-9]+]]:_(s16) = G_ADD [[LHS]]:_, [[RHS]]:_ + CHECK: [[CST:%[0-9]+]]:_(s16) = G_CONSTANT i16 255 + CHECK: [[AND:%[0-9]+]]:_(s16) = G_AND [[ADD]]:_, [[CST]]:_ + CHECK: G_ICMP intpred(ne), [[ADD]]:_(s16), [[AND]]:_ + CHECK: G_TRUNC [[ADD]] + )"; + + // Check + ASSERT_TRUE(CheckMachineFunction(*MF, CheckStr)); +} + +// USUBO widening. +TEST_F(LegalizerHelperTest, WidenUSUBO) { + if (!TM) + return; + + // Declare your legalization info + DefineLegalizerInfo(A, + { getActionDefinitionsBuilder(G_SUB).legalFor({s16}); }); + // Build + // Trunc it to s8. + LLT s8{LLT::scalar(8)}; + LLT s16{LLT::scalar(16)}; + auto MIBTrunc = B.buildTrunc(s8, Copies[0]); + unsigned CarryReg = MRI->createGenericVirtualRegister(LLT::scalar(1)); + auto MIBUSUBO = B.buildInstr(TargetOpcode::G_USUBO, s8) + .addDef(CarryReg) + .addUse(MIBTrunc->getOperand(0).getReg()) + .addUse(MIBTrunc->getOperand(0).getReg()); + AInfo Info(MF->getSubtarget()); + LegalizerHelper Helper(*MF, Info); + ASSERT_TRUE(Helper.widenScalar(*MIBUSUBO, 0, s16) == + LegalizerHelper::LegalizeResult::Legalized); + + auto CheckStr = R"( + CHECK: [[Trunc:%[0-9]+]]:_(s8) = G_TRUNC + CHECK: [[LHS:%[0-9]+]]:_(s16) = G_ZEXT [[Trunc]] + CHECK: [[RHS:%[0-9]+]]:_(s16) = G_ZEXT [[Trunc]] + CHECK: [[SUB:%[0-9]+]]:_(s16) = G_SUB [[LHS]]:_, [[RHS]]:_ + CHECK: [[CST:%[0-9]+]]:_(s16) = G_CONSTANT i16 255 + CHECK: [[AND:%[0-9]+]]:_(s16) = G_AND [[SUB]]:_, [[CST]]:_ + CHECK: G_ICMP intpred(ne), [[SUB]]:_(s16), [[AND]]:_ + CHECK: G_TRUNC [[SUB]] + )"; + + // Check + ASSERT_TRUE(CheckMachineFunction(*MF, CheckStr)); +} } // namespace