Index: llvm/trunk/lib/Target/AArch64/AArch64InstructionSelector.cpp =================================================================== --- llvm/trunk/lib/Target/AArch64/AArch64InstructionSelector.cpp +++ llvm/trunk/lib/Target/AArch64/AArch64InstructionSelector.cpp @@ -124,6 +124,10 @@ MachineInstr *emitFMovForFConstant(MachineInstr &MI, MachineRegisterInfo &MRI) const; + /// Emit a CSet for a compare. + MachineInstr *emitCSetForICMP(unsigned DefReg, unsigned Pred, + MachineIRBuilder &MIRBuilder) const; + ComplexRendererFns selectArithImmed(MachineOperand &Root) const; ComplexRendererFns selectAddrModeUnscaled(MachineOperand &Root, @@ -173,6 +177,7 @@ bool tryOptVectorShuffle(MachineInstr &I) const; bool tryOptVectorDup(MachineInstr &MI) const; bool tryOptSelect(MachineInstr &MI) const; + bool tryOptCMN(MachineInstr &MI) const; const AArch64TargetMachine &TM; const AArch64Subtarget &STI; @@ -1847,6 +1852,11 @@ unsigned CmpOpc = 0; unsigned ZReg = 0; + // Check if this compare can be represented as a cmn, and perform any + // necessary transformations to do so. + if (tryOptCMN(I)) + return true; + LLT CmpTy = MRI.getType(I.getOperand(2).getReg()); if (CmpTy == LLT::scalar(32)) { CmpOpc = AArch64::SUBSWrr; @@ -1863,13 +1873,6 @@ if (ImmFns) CmpOpc = CmpOpc == AArch64::SUBSWrr ? AArch64::SUBSWri : AArch64::SUBSXri; - // CSINC increments the result by one when the condition code is false. - // Therefore, we have to invert the predicate to get an increment by 1 when - // the predicate is true. - const AArch64CC::CondCode invCC = - changeICMPPredToAArch64CC(CmpInst::getInversePredicate( - (CmpInst::Predicate)I.getOperand(1).getPredicate())); - auto CmpMI = BuildMI(MBB, I, I.getDebugLoc(), TII.get(CmpOpc)) .addDef(ZReg) .addUse(I.getOperand(2).getReg()); @@ -1882,16 +1885,10 @@ CmpMI.addUse(I.getOperand(3).getReg()); } - MachineInstr &CSetMI = - *BuildMI(MBB, I, I.getDebugLoc(), TII.get(AArch64::CSINCWr)) - .addDef(I.getOperand(0).getReg()) - .addUse(AArch64::WZR) - .addUse(AArch64::WZR) - .addImm(invCC); - + MachineIRBuilder MIRBuilder(I); + emitCSetForICMP(I.getOperand(0).getReg(), I.getOperand(1).getPredicate(), + MIRBuilder); constrainSelectedInstRegOperands(*CmpMI, TII, TRI, RBI); - constrainSelectedInstRegOperands(CSetMI, TII, TRI, RBI); - I.eraseFromParent(); return true; } @@ -2854,6 +2851,20 @@ return &I; } +MachineInstr * +AArch64InstructionSelector::emitCSetForICMP(unsigned DefReg, unsigned Pred, + MachineIRBuilder &MIRBuilder) const { + // CSINC increments the result when the predicate is false. Invert it. + const AArch64CC::CondCode InvCC = changeICMPPredToAArch64CC( + CmpInst::getInversePredicate((CmpInst::Predicate)Pred)); + auto I = + MIRBuilder + .buildInstr(AArch64::CSINCWr, {DefReg}, {AArch64::WZR, AArch64::WZR}) + .addImm(InvCC); + constrainSelectedInstRegOperands(*I, TII, TRI, RBI); + return &*I; +} + bool AArch64InstructionSelector::tryOptSelect(MachineInstr &I) const { MachineIRBuilder MIB(I); MachineRegisterInfo &MRI = *MIB.getMRI(); @@ -2938,6 +2949,123 @@ return true; } +bool AArch64InstructionSelector::tryOptCMN(MachineInstr &I) const { + assert(I.getOpcode() == TargetOpcode::G_ICMP && "Expected G_ICMP"); + MachineIRBuilder MIRBuilder(I); + MachineRegisterInfo &MRI = *MIRBuilder.getMRI(); + // We want to find this sort of thing: + // x = G_SUB 0, y + // G_ICMP z, x + // + // In this case, we can fold the G_SUB into the G_ICMP using a CMN instead. + // e.g: + // + // cmn z, y + + // Helper lambda to find the def. + auto FindDef = [&](unsigned VReg) { + MachineInstr *Def = MRI.getVRegDef(VReg); + while (Def) { + if (Def->getOpcode() != TargetOpcode::COPY) + break; + // Copies can be from physical registers. If we hit this, we're done. + if (TargetRegisterInfo::isPhysicalRegister(Def->getOperand(1).getReg())) + break; + Def = MRI.getVRegDef(Def->getOperand(1).getReg()); + } + return Def; + }; + + // Helper lambda to detect the subtract followed by the compare. + // Takes in the def of the LHS or RHS, and checks if it's a subtract from 0. + auto IsCMN = [&](MachineInstr *DefMI, const AArch64CC::CondCode &CC) { + if (!DefMI || DefMI->getOpcode() != TargetOpcode::G_SUB) + return false; + + // Need to make sure NZCV is the same at the end of the transformation. + if (CC != AArch64CC::EQ && CC != AArch64CC::NE) + return false; + + // We want to match against SUBs. + if (DefMI->getOpcode() != TargetOpcode::G_SUB) + return false; + + // Make sure that we're getting + // x = G_SUB 0, y + auto ValAndVReg = + getConstantVRegValWithLookThrough(DefMI->getOperand(1).getReg(), MRI); + if (!ValAndVReg || ValAndVReg->Value != 0) + return false; + + // This can safely be represented as a CMN. + return true; + }; + + // Check if the RHS or LHS of the G_ICMP is defined by a SUB + MachineInstr *LHSDef = FindDef(I.getOperand(2).getReg()); + MachineInstr *RHSDef = FindDef(I.getOperand(3).getReg()); + const AArch64CC::CondCode CC = changeICMPPredToAArch64CC( + (CmpInst::Predicate)I.getOperand(1).getPredicate()); + bool DidFold = false; + if (IsCMN(LHSDef, CC)) { + // We're doing this: + // + // Given: + // + // x = G_SUB 0, y + // G_ICMP x, z + // + // Update the G_ICMP: + // + // G_ICMP y, z + I.getOperand(2).setReg(LHSDef->getOperand(2).getReg()); + DidFold = true; + } else if (IsCMN(RHSDef, CC)) { + // Same idea here, but with the RHS of the compare instead: + // + // Given: + // + // x = G_SUB 0, y + // G_ICMP z, x + // + // Update the G_ICMP: + // + // G_ICMP z, y + I.getOperand(3).setReg(RHSDef->getOperand(2).getReg()); + DidFold = true; + } + + if (DidFold) { + // We can fold. Emit a CMN. + static const unsigned OpcTable[2][2]{{AArch64::ADDSXrr, AArch64::ADDSXri}, + {AArch64::ADDSWrr, AArch64::ADDSWri}}; + bool Is32Bit = + (MRI.getType(I.getOperand(2).getReg()).getSizeInBits() == 32); + auto ImmFns = selectArithImmed(I.getOperand(3)); + unsigned Opc = OpcTable[Is32Bit][ImmFns.hasValue()]; + unsigned ZReg = Is32Bit ? AArch64::WZR : AArch64::XZR; + + auto CmpMI = MIRBuilder.buildInstr(Opc, {ZReg}, {I.getOperand(2).getReg()}); + + // If we matched a valid constant immediate, add those operands. + if (ImmFns) { + for (auto &RenderFn : *ImmFns) + RenderFn(CmpMI); + } else { + CmpMI.addUse(I.getOperand(3).getReg()); + } + + constrainSelectedInstRegOperands(*CmpMI, TII, TRI, RBI); + + // Add a CSet after the CMN. + emitCSetForICMP(I.getOperand(0).getReg(), I.getOperand(1).getPredicate(), + MIRBuilder); + I.eraseFromParent(); + } + + return DidFold; +} + bool AArch64InstructionSelector::tryOptVectorDup(MachineInstr &I) const { // Try to match a vector splat operation into a dup instruction. // We're looking for this pattern: Index: llvm/trunk/test/CodeGen/AArch64/GlobalISel/opt-fold-cmn.mir =================================================================== --- llvm/trunk/test/CodeGen/AArch64/GlobalISel/opt-fold-cmn.mir +++ llvm/trunk/test/CodeGen/AArch64/GlobalISel/opt-fold-cmn.mir @@ -0,0 +1,291 @@ +# NOTE: Assertions have been autogenerated by utils/update_mir_test_checks.py +# RUN: llc -mtriple aarch64-unknown-unknown -run-pass=instruction-select -verify-machineinstrs %s -o - | FileCheck %s +# +# Verify that we can fold G_SUB into G_ICMP when we have a pattern like this: +# +# x = G_SUB 0, y +# G_ICMP intpred(something_safe) z, x +# +# Where "something_safe" is ne or eq. +# +# Tests whose names start with cmn_ should use ADDS for the G_ICMP. Tests whose +# names start with no_cmn should use SUBS. +# + +... +--- +name: cmn_s32_rhs +alignment: 2 +legalized: true +regBankSelected: true +tracksRegLiveness: true +body: | + bb.0: + liveins: $w0, $w1 + + ; CHECK-LABEL: name: cmn_s32_rhs + ; CHECK: liveins: $w0, $w1 + ; CHECK: [[COPY:%[0-9]+]]:gpr32 = COPY $w0 + ; CHECK: [[COPY1:%[0-9]+]]:gpr32 = COPY $w1 + ; CHECK: [[MOVi32imm:%[0-9]+]]:gpr32 = MOVi32imm 0 + ; CHECK: [[MOVi32imm1:%[0-9]+]]:gpr32 = MOVi32imm 1 + ; CHECK: $wzr = ADDSWrr [[COPY]], [[COPY1]], implicit-def $nzcv + ; CHECK: [[CSINCWr:%[0-9]+]]:gpr32 = CSINCWr $wzr, $wzr, 0, implicit $nzcv + ; CHECK: $wzr = ANDSWri [[CSINCWr]], 0, implicit-def $nzcv + ; CHECK: [[CSELWr:%[0-9]+]]:gpr32 = CSELWr [[MOVi32imm1]], [[MOVi32imm]], 1, implicit $nzcv + ; CHECK: $w0 = COPY [[CSELWr]] + ; CHECK: RET_ReallyLR implicit $w0 + %0:gpr(s32) = COPY $w0 + %1:gpr(s32) = COPY $w1 + %2:gpr(s32) = G_CONSTANT i32 0 + %6:gpr(s32) = G_CONSTANT i32 1 + %3:gpr(s32) = G_SUB %2, %1 + %7:gpr(s32) = G_ICMP intpred(ne), %0(s32), %3 + %4:gpr(s1) = G_TRUNC %7(s32) + %5:gpr(s32) = G_SELECT %4(s1), %6, %2 + $w0 = COPY %5(s32) + RET_ReallyLR implicit $w0 + +... +--- +name: cmn_s32_lhs +alignment: 2 +legalized: true +regBankSelected: true +tracksRegLiveness: true +body: | + bb.0: + liveins: $w0, $w1 + + ; CHECK-LABEL: name: cmn_s32_lhs + ; CHECK: liveins: $w0, $w1 + ; CHECK: [[COPY:%[0-9]+]]:gpr32 = COPY $w0 + ; CHECK: [[COPY1:%[0-9]+]]:gpr32 = COPY $w1 + ; CHECK: [[MOVi32imm:%[0-9]+]]:gpr32 = MOVi32imm 0 + ; CHECK: [[MOVi32imm1:%[0-9]+]]:gpr32 = MOVi32imm 1 + ; CHECK: $wzr = ADDSWrr [[COPY]], [[COPY1]], implicit-def $nzcv + ; CHECK: [[CSINCWr:%[0-9]+]]:gpr32 = CSINCWr $wzr, $wzr, 0, implicit $nzcv + ; CHECK: $wzr = ANDSWri [[CSINCWr]], 0, implicit-def $nzcv + ; CHECK: [[CSELWr:%[0-9]+]]:gpr32 = CSELWr [[MOVi32imm1]], [[MOVi32imm]], 1, implicit $nzcv + ; CHECK: $w0 = COPY [[CSELWr]] + ; CHECK: RET_ReallyLR implicit $w0 + %0:gpr(s32) = COPY $w0 + %1:gpr(s32) = COPY $w1 + %2:gpr(s32) = G_CONSTANT i32 0 + %6:gpr(s32) = G_CONSTANT i32 1 + %3:gpr(s32) = G_SUB %2, %0 + %7:gpr(s32) = G_ICMP intpred(ne), %3(s32), %1 + %4:gpr(s1) = G_TRUNC %7(s32) + %5:gpr(s32) = G_SELECT %4(s1), %6, %2 + $w0 = COPY %5(s32) + RET_ReallyLR implicit $w0 + +... +--- +name: no_cmn_s32_rhs +alignment: 2 +legalized: true +regBankSelected: true +tracksRegLiveness: true +body: | + bb.0: + liveins: $w0, $w1 + + ; CHECK-LABEL: name: no_cmn_s32_rhs + ; CHECK: liveins: $w0, $w1 + ; CHECK: [[COPY:%[0-9]+]]:gpr32 = COPY $w0 + ; CHECK: [[COPY1:%[0-9]+]]:gpr32 = COPY $w1 + ; CHECK: [[MOVi32imm:%[0-9]+]]:gpr32 = MOVi32imm 0 + ; CHECK: [[MOVi32imm1:%[0-9]+]]:gpr32 = MOVi32imm 1 + ; CHECK: [[SUBSWrr:%[0-9]+]]:gpr32 = SUBSWrr [[MOVi32imm]], [[COPY1]], implicit-def $nzcv + ; CHECK: $wzr = SUBSWrr [[COPY]], [[SUBSWrr]], implicit-def $nzcv + ; CHECK: [[CSINCWr:%[0-9]+]]:gpr32 = CSINCWr $wzr, $wzr, 10, implicit $nzcv + ; CHECK: $wzr = ANDSWri [[CSINCWr]], 0, implicit-def $nzcv + ; CHECK: [[CSELWr:%[0-9]+]]:gpr32 = CSELWr [[MOVi32imm1]], [[MOVi32imm]], 1, implicit $nzcv + ; CHECK: $w0 = COPY [[CSELWr]] + ; CHECK: RET_ReallyLR implicit $w0 + %0:gpr(s32) = COPY $w0 + %1:gpr(s32) = COPY $w1 + %2:gpr(s32) = G_CONSTANT i32 0 + %6:gpr(s32) = G_CONSTANT i32 1 + %3:gpr(s32) = G_SUB %2, %1 + %7:gpr(s32) = G_ICMP intpred(slt), %0(s32), %3 + %4:gpr(s1) = G_TRUNC %7(s32) + %5:gpr(s32) = G_SELECT %4(s1), %6, %2 + $w0 = COPY %5(s32) + RET_ReallyLR implicit $w0 + +... +--- +name: no_cmn_s32_lhs +alignment: 2 +legalized: true +regBankSelected: true +tracksRegLiveness: true +body: | + bb.0: + liveins: $w0, $w1 + + ; CHECK-LABEL: name: no_cmn_s32_lhs + ; CHECK: liveins: $w0, $w1 + ; CHECK: [[COPY:%[0-9]+]]:gpr32 = COPY $w0 + ; CHECK: [[COPY1:%[0-9]+]]:gpr32 = COPY $w1 + ; CHECK: [[MOVi32imm:%[0-9]+]]:gpr32 = MOVi32imm 0 + ; CHECK: [[MOVi32imm1:%[0-9]+]]:gpr32 = MOVi32imm 1 + ; CHECK: [[SUBSWrr:%[0-9]+]]:gpr32 = SUBSWrr [[MOVi32imm]], [[COPY]], implicit-def $nzcv + ; CHECK: $wzr = SUBSWrr [[SUBSWrr]], [[COPY1]], implicit-def $nzcv + ; CHECK: [[CSINCWr:%[0-9]+]]:gpr32 = CSINCWr $wzr, $wzr, 10, implicit $nzcv + ; CHECK: $wzr = ANDSWri [[CSINCWr]], 0, implicit-def $nzcv + ; CHECK: [[CSELWr:%[0-9]+]]:gpr32 = CSELWr [[MOVi32imm1]], [[MOVi32imm]], 1, implicit $nzcv + ; CHECK: $w0 = COPY [[CSELWr]] + ; CHECK: RET_ReallyLR implicit $w0 + %0:gpr(s32) = COPY $w0 + %1:gpr(s32) = COPY $w1 + %2:gpr(s32) = G_CONSTANT i32 0 + %6:gpr(s32) = G_CONSTANT i32 1 + %3:gpr(s32) = G_SUB %2, %0 + %7:gpr(s32) = G_ICMP intpred(slt), %3(s32), %1 + %4:gpr(s1) = G_TRUNC %7(s32) + %5:gpr(s32) = G_SELECT %4(s1), %6, %2 + $w0 = COPY %5(s32) + RET_ReallyLR implicit $w0 + +... +--- +name: cmn_s64_rhs +alignment: 2 +legalized: true +regBankSelected: true +tracksRegLiveness: true +body: | + bb.0: + liveins: $x0, $x1 + + ; CHECK-LABEL: name: cmn_s64_rhs + ; CHECK: liveins: $x0, $x1 + ; CHECK: [[COPY:%[0-9]+]]:gpr64 = COPY $x0 + ; CHECK: [[COPY1:%[0-9]+]]:gpr64 = COPY $x1 + ; CHECK: [[MOVi64imm:%[0-9]+]]:gpr64 = MOVi64imm 0 + ; CHECK: [[MOVi64imm1:%[0-9]+]]:gpr64 = MOVi64imm 1 + ; CHECK: $xzr = ADDSXrr [[COPY]], [[COPY1]], implicit-def $nzcv + ; CHECK: [[CSINCWr:%[0-9]+]]:gpr32 = CSINCWr $wzr, $wzr, 0, implicit $nzcv + ; CHECK: $wzr = ANDSWri [[CSINCWr]], 0, implicit-def $nzcv + ; CHECK: [[CSELXr:%[0-9]+]]:gpr64 = CSELXr [[MOVi64imm1]], [[MOVi64imm]], 1, implicit $nzcv + ; CHECK: $x0 = COPY [[CSELXr]] + ; CHECK: RET_ReallyLR implicit $x0 + %0:gpr(s64) = COPY $x0 + %1:gpr(s64) = COPY $x1 + %2:gpr(s64) = G_CONSTANT i64 0 + %6:gpr(s64) = G_CONSTANT i64 1 + %3:gpr(s64) = G_SUB %2, %1 + %7:gpr(s32) = G_ICMP intpred(ne), %0(s64), %3 + %4:gpr(s1) = G_TRUNC %7(s32) + %5:gpr(s64) = G_SELECT %4(s1), %6, %2 + $x0 = COPY %5(s64) + RET_ReallyLR implicit $x0 + +... +--- +name: cmn_s64_lhs +alignment: 2 +legalized: true +regBankSelected: true +tracksRegLiveness: true +body: | + bb.0: + liveins: $x0, $x1 + + ; CHECK-LABEL: name: cmn_s64_lhs + ; CHECK: liveins: $x0, $x1 + ; CHECK: [[COPY:%[0-9]+]]:gpr64 = COPY $x0 + ; CHECK: [[COPY1:%[0-9]+]]:gpr64 = COPY $x1 + ; CHECK: [[MOVi64imm:%[0-9]+]]:gpr64 = MOVi64imm 0 + ; CHECK: [[MOVi64imm1:%[0-9]+]]:gpr64 = MOVi64imm 1 + ; CHECK: $xzr = ADDSXrr [[COPY]], [[COPY1]], implicit-def $nzcv + ; CHECK: [[CSINCWr:%[0-9]+]]:gpr32 = CSINCWr $wzr, $wzr, 0, implicit $nzcv + ; CHECK: $wzr = ANDSWri [[CSINCWr]], 0, implicit-def $nzcv + ; CHECK: [[CSELXr:%[0-9]+]]:gpr64 = CSELXr [[MOVi64imm1]], [[MOVi64imm]], 1, implicit $nzcv + ; CHECK: $x0 = COPY [[CSELXr]] + ; CHECK: RET_ReallyLR implicit $x0 + %0:gpr(s64) = COPY $x0 + %1:gpr(s64) = COPY $x1 + %2:gpr(s64) = G_CONSTANT i64 0 + %6:gpr(s64) = G_CONSTANT i64 1 + %3:gpr(s64) = G_SUB %2, %0 + %7:gpr(s32) = G_ICMP intpred(ne), %3(s64), %1 + %4:gpr(s1) = G_TRUNC %7(s32) + %5:gpr(s64) = G_SELECT %4(s1), %6, %2 + $x0 = COPY %5(s64) + RET_ReallyLR implicit $x0 + +... +--- +name: no_cmn_s64_rhs +alignment: 2 +legalized: true +regBankSelected: true +tracksRegLiveness: true +body: | + bb.0: + liveins: $x0, $x1 + + ; CHECK-LABEL: name: no_cmn_s64_rhs + ; CHECK: liveins: $x0, $x1 + ; CHECK: [[COPY:%[0-9]+]]:gpr64 = COPY $x0 + ; CHECK: [[COPY1:%[0-9]+]]:gpr64 = COPY $x1 + ; CHECK: [[MOVi64imm:%[0-9]+]]:gpr64 = MOVi64imm 0 + ; CHECK: [[MOVi64imm1:%[0-9]+]]:gpr64 = MOVi64imm 1 + ; CHECK: [[SUBSXrr:%[0-9]+]]:gpr64 = SUBSXrr [[MOVi64imm]], [[COPY1]], implicit-def $nzcv + ; CHECK: $xzr = SUBSXrr [[COPY]], [[SUBSXrr]], implicit-def $nzcv + ; CHECK: [[CSINCWr:%[0-9]+]]:gpr32 = CSINCWr $wzr, $wzr, 10, implicit $nzcv + ; CHECK: $wzr = ANDSWri [[CSINCWr]], 0, implicit-def $nzcv + ; CHECK: [[CSELXr:%[0-9]+]]:gpr64 = CSELXr [[MOVi64imm1]], [[MOVi64imm]], 1, implicit $nzcv + ; CHECK: $x0 = COPY [[CSELXr]] + ; CHECK: RET_ReallyLR implicit $x0 + %0:gpr(s64) = COPY $x0 + %1:gpr(s64) = COPY $x1 + %2:gpr(s64) = G_CONSTANT i64 0 + %6:gpr(s64) = G_CONSTANT i64 1 + %3:gpr(s64) = G_SUB %2, %1 + %7:gpr(s32) = G_ICMP intpred(slt), %0(s64), %3 + %4:gpr(s1) = G_TRUNC %7(s32) + %5:gpr(s64) = G_SELECT %4(s1), %6, %2 + $x0 = COPY %5(s64) + RET_ReallyLR implicit $x0 + +... +--- +name: no_cmn_s64_lhs +alignment: 2 +legalized: true +regBankSelected: true +tracksRegLiveness: true +body: | + bb.0: + liveins: $x0, $x1 + + ; CHECK-LABEL: name: no_cmn_s64_lhs + ; CHECK: liveins: $x0, $x1 + ; CHECK: [[COPY:%[0-9]+]]:gpr64 = COPY $x0 + ; CHECK: [[COPY1:%[0-9]+]]:gpr64 = COPY $x1 + ; CHECK: [[MOVi64imm:%[0-9]+]]:gpr64 = MOVi64imm 0 + ; CHECK: [[MOVi64imm1:%[0-9]+]]:gpr64 = MOVi64imm 1 + ; CHECK: [[SUBSXrr:%[0-9]+]]:gpr64 = SUBSXrr [[MOVi64imm]], [[COPY]], implicit-def $nzcv + ; CHECK: $xzr = SUBSXrr [[SUBSXrr]], [[COPY1]], implicit-def $nzcv + ; CHECK: [[CSINCWr:%[0-9]+]]:gpr32 = CSINCWr $wzr, $wzr, 10, implicit $nzcv + ; CHECK: $wzr = ANDSWri [[CSINCWr]], 0, implicit-def $nzcv + ; CHECK: [[CSELXr:%[0-9]+]]:gpr64 = CSELXr [[MOVi64imm1]], [[MOVi64imm]], 1, implicit $nzcv + ; CHECK: $x0 = COPY [[CSELXr]] + ; CHECK: RET_ReallyLR implicit $x0 + %0:gpr(s64) = COPY $x0 + %1:gpr(s64) = COPY $x1 + %2:gpr(s64) = G_CONSTANT i64 0 + %6:gpr(s64) = G_CONSTANT i64 1 + %3:gpr(s64) = G_SUB %2, %0 + %7:gpr(s32) = G_ICMP intpred(slt), %3(s64), %1 + %4:gpr(s1) = G_TRUNC %7(s32) + %5:gpr(s64) = G_SELECT %4(s1), %6, %2 + $x0 = COPY %5(s64) + RET_ReallyLR implicit $x0 + +...