Skip to content

Commit 6ecfd1f

Browse files
committed
Resolve review comments:
For the simple case where IR just checks the overflow, skip the check when we're sure that there is no overflow.
1 parent 9531133 commit 6ecfd1f

File tree

6 files changed

+146
-68
lines changed

6 files changed

+146
-68
lines changed

llvm/include/llvm/CodeGen/TargetLowering.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3470,6 +3470,10 @@ class LLVM_ABI TargetLoweringBase {
34703470
return MathUsed && (VT.isSimple() || !isOperationExpand(Opcode, VT));
34713471
}
34723472

3473+
// Return true if the target wants to optimize the mul overflow intrinsic
3474+
// by detecting if there is no overflow.
3475+
virtual bool shouldOptimizeMulOverflowIntrinsic() const { return false; }
3476+
34733477
// Return true if it is profitable to use a scalar input to a BUILD_VECTOR
34743478
// even if the vector itself has multiple uses.
34753479
virtual bool aggressivelyPreferBuildVectorSources(EVT VecVT) const {

llvm/lib/CodeGen/CodeGenPrepare.cpp

Lines changed: 111 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -6409,8 +6409,7 @@ bool CodeGenPrepare::optimizeGatherScatterInst(Instruction *MemoryInst,
64096409
// not doable there, we do it here.
64106410
bool CodeGenPrepare::optimizeMulWithOverflow(Instruction *I, bool IsSigned,
64116411
ModifyDT &ModifiedDT) {
6412-
// Enable this optimization only for aarch64.
6413-
if (!TLI->getTargetMachine().getTargetTriple().isAArch64())
6412+
if (!TLI->shouldOptimizeMulOverflowIntrinsic())
64146413
return false;
64156414
// If we have already seen this instruction, don't process it again.
64166415
if (!SeenMulWithOverflowInstrs.insert(std::make_pair(I, true)).second)
@@ -6440,29 +6439,42 @@ bool CodeGenPrepare::optimizeMulWithOverflow(Instruction *I, bool IsSigned,
64406439
if (!I->getType()->isStructTy() || I->getType()->getStructNumElements() != 2)
64416440
return false;
64426441

6443-
I->getParent()->setName("overflow.res");
6444-
BasicBlock *OverflowResBB = I->getParent();
6445-
BasicBlock *OverflowoEntryBB =
6446-
I->getParent()->splitBasicBlock(I, "overflow.entry", /*Before*/ true);
6447-
BasicBlock *NoOverflowBB = BasicBlock::Create(
6448-
I->getContext(), "overflow.no", I->getFunction(), OverflowResBB);
6449-
BasicBlock *OverflowBB = BasicBlock::Create(I->getContext(), "overflow",
6450-
I->getFunction(), OverflowResBB);
6451-
// new blocks should be:
6442+
// ----------------------------
6443+
6444+
// For the simple case where IR just checks the overflow flag, new blocks
6445+
// should be:
64526446
// entry:
64536447
// if signed:
64546448
// (lhs_lo ^ lhs_hi) || (rhs_lo ^ rhs_hi) ? overflow, overflow_no
64556449
// else:
64566450
// (lhs_hi != 0) || (rhs_hi != 0) ? overflow, overflow_no
6451+
// overflow_no:
6452+
// overflow:
64576453

6454+
// otherwise, new blocks should be:
6455+
// entry:
6456+
// if signed:
6457+
// (lhs_lo ^ lhs_hi) || (rhs_lo ^ rhs_hi) ? overflow, overflow_no
6458+
// else:
6459+
// (lhs_hi != 0) || (rhs_hi != 0) ? overflow, overflow_no
64586460
// overflow_no:
64596461
// overflow:
64606462
// overflow.res:
64616463

6462-
// ----------------------------
6464+
// New BBs:
6465+
BasicBlock *OverflowoEntryBB =
6466+
I->getParent()->splitBasicBlock(I, "overflow.entry", /*Before*/ true);
6467+
// Remove the 'br' instruction that is generated as a result of the split:
6468+
OverflowoEntryBB->getTerminator()->eraseFromParent();
6469+
BasicBlock *NoOverflowBB =
6470+
BasicBlock::Create(I->getContext(), "overflow.no", I->getFunction());
6471+
NoOverflowBB->moveAfter(OverflowoEntryBB);
6472+
I->getParent()->setName("overflow");
6473+
BasicBlock *OverflowBB = I->getParent();
6474+
64636475
// BB overflow.entry:
6464-
// get Lo and Hi of LHS & RHS:
6465-
IRBuilder<> Builder(OverflowoEntryBB->getTerminator());
6476+
// Get Lo and Hi of LHS & RHS:
6477+
IRBuilder<> Builder(OverflowoEntryBB);
64666478
Value *LoLHS = Builder.CreateTrunc(LHS, LegalTy, "lo.lhs");
64676479
Value *HiLHS = Builder.CreateLShr(LHS, VTHalfBitWidth, "lhs.lsr");
64686480
HiLHS = Builder.CreateTrunc(HiLHS, LegalTy, "hi.lhs");
@@ -6479,18 +6491,16 @@ bool CodeGenPrepare::optimizeMulWithOverflow(Instruction *I, bool IsSigned,
64796491
Value *XorLHS = Builder.CreateXor(HiLHS, SignLoLHS);
64806492
Value *XorRHS = Builder.CreateXor(HiRHS, SignLoRHS);
64816493
Value *Or = Builder.CreateOr(XorLHS, XorRHS, "or.lhs.rhs");
6482-
IsAnyBitTrue = Builder.CreateCmp(ICmpInst::ICMP_EQ, Or,
6483-
ConstantInt::get(Or->getType(), 1));
6494+
IsAnyBitTrue = Builder.CreateCmp(ICmpInst::ICMP_NE, Or,
6495+
ConstantInt::getNullValue(Or->getType()));
64846496
} else {
64856497
Value *CmpLHS = Builder.CreateCmp(ICmpInst::ICMP_NE, HiLHS,
64866498
ConstantInt::getNullValue(LegalTy));
64876499
Value *CmpRHS = Builder.CreateCmp(ICmpInst::ICMP_NE, HiRHS,
64886500
ConstantInt::getNullValue(LegalTy));
64896501
IsAnyBitTrue = Builder.CreateOr(CmpLHS, CmpRHS, "or.lhs.rhs");
64906502
}
6491-
64926503
Builder.CreateCondBr(IsAnyBitTrue, OverflowBB, NoOverflowBB);
6493-
OverflowoEntryBB->getTerminator()->eraseFromParent();
64946504

64956505
// BB overflow.no:
64966506
Builder.SetInsertPoint(NoOverflowBB);
@@ -6503,24 +6513,95 @@ bool CodeGenPrepare::optimizeMulWithOverflow(Instruction *I, bool IsSigned,
65036513
ExtLoRHS = Builder.CreateZExt(LoRHS, Ty, "lo.rhs.ext");
65046514
}
65056515

6506-
Value *Mul = Builder.CreateMul(ExtLoLHS, ExtLoRHS, "mul.no.overflow");
6516+
Value *Mul = Builder.CreateMul(ExtLoLHS, ExtLoRHS, "mul.overflow.no");
6517+
6518+
// In overflow.no BB: we are sure that the overflow flag is false.
6519+
// So, if we found this pattern:
6520+
// br (extractvalue (%mul, 1)), label %if.then, label %if.end
6521+
// then we can jump directly to %if.end as we're sure that there is no
6522+
// overflow.
6523+
BasicBlock *DetectNoOverflowBrBB = nullptr;
6524+
StructType *STy = StructType::get(
6525+
I->getContext(), {Ty, IntegerType::getInt1Ty(I->getContext())});
6526+
// Look for the pattern in the users of I, and make sure that all the users
6527+
// are either part of the pattern or NOT in the same BB as I.
6528+
for (User *U : I->users()) {
6529+
if (auto *Instr = dyn_cast<Instruction>(U);
6530+
Instr && Instr->getParent() != I->getParent())
6531+
continue;
6532+
6533+
if (auto *ExtUser = dyn_cast<ExtractValueInst>(U)) {
6534+
if (ExtUser->hasOneUse() && ExtUser->getNumIndices() == 1 &&
6535+
ExtUser->getIndices()[0] == 1) {
6536+
if (auto *Br = dyn_cast<BranchInst>(*ExtUser->user_begin())) {
6537+
DetectNoOverflowBrBB = Br->getSuccessor(1) /*if.end*/;
6538+
continue;
6539+
}
6540+
}
6541+
}
6542+
// If we come here, it means that either the pattern doesn't exist or
6543+
// there are multiple users in the same BB
6544+
DetectNoOverflowBrBB = nullptr;
6545+
break;
6546+
}
6547+
if (DetectNoOverflowBrBB) {
6548+
// BB overflow.no: jump directly to if.end BB
6549+
Builder.CreateBr(DetectNoOverflowBrBB);
6550+
// BB if.end:
6551+
Builder.SetInsertPoint(DetectNoOverflowBrBB,
6552+
DetectNoOverflowBrBB->getFirstInsertionPt());
6553+
// Create PHI node to get the results of multiplication from 'overflow.no'
6554+
// and 'overflow' BBs
6555+
PHINode *NoOverflowPHI = Builder.CreatePHI(Ty, 2);
6556+
NoOverflowPHI->addIncoming(Mul, NoOverflowBB);
6557+
// Create struct value to replace all uses of I
6558+
Value *StructValNoOverflow = PoisonValue::get(STy);
6559+
StructValNoOverflow =
6560+
Builder.CreateInsertValue(StructValNoOverflow, NoOverflowPHI, {0});
6561+
// Overflow flag is always false as we are sure it's not overflow.
6562+
StructValNoOverflow = Builder.CreateInsertValue(
6563+
StructValNoOverflow, ConstantInt::getFalse(I->getContext()), {1});
6564+
// Replace all uses of I, only uses dominated by the if.end BB
6565+
I->replaceUsesOutsideBlock(StructValNoOverflow, I->getParent());
6566+
// BB overflow:
6567+
Builder.SetInsertPoint(OverflowBB,
6568+
I->getParent()->getTerminator()->getIterator());
6569+
// Extract the multiplication result to add it to the PHI node in the if.end
6570+
// BB
6571+
Value *IntrinsicMulRes = Builder.CreateExtractValue(I, {0}, "mul.extract");
6572+
NoOverflowPHI->addIncoming(IntrinsicMulRes, OverflowBB);
6573+
ModifiedDT = ModifyDT::ModifyBBDT;
6574+
return true;
6575+
}
6576+
6577+
// Otherwise, we need to create the 'overflow.res' BB to merge the results of
6578+
// the two paths.
6579+
I->getParent()->setName("overflow.res");
6580+
BasicBlock *OverflowResBB = I->getParent();
6581+
OverflowBB = BasicBlock::Create(I->getContext(), "overflow", I->getFunction(),
6582+
OverflowResBB);
6583+
// Initially I->getParent() was the overflow BB, now it becomes the
6584+
// overflow.res BB. So we need to keep the old reference to the overflow BB.
6585+
OverflowResBB->replaceAllUsesWith(OverflowBB);
6586+
6587+
// BB overflow.no: jump to overflow.res BB
65076588
Builder.CreateBr(OverflowResBB);
65086589

65096590
// BB overflow.res:
65106591
Builder.SetInsertPoint(OverflowResBB, OverflowResBB->getFirstInsertionPt());
6511-
PHINode *PHINode1 = Builder.CreatePHI(Ty, 2);
6512-
PHINode1->addIncoming(Mul, NoOverflowBB);
6513-
PHINode *PHINode2 =
6514-
Builder.CreatePHI(IntegerType::getInt1Ty(I->getContext()), 2);
6515-
PHINode2->addIncoming(ConstantInt::getFalse(I->getContext()), NoOverflowBB);
6592+
PHINode *OverflowResPHI = Builder.CreatePHI(Ty, 2),
6593+
*OverflowFlagPHI =
6594+
Builder.CreatePHI(IntegerType::getInt1Ty(I->getContext()), 2);
65166595

6517-
StructType *STy = StructType::get(
6518-
I->getContext(), {Ty, IntegerType::getInt1Ty(I->getContext())});
65196596
Value *StructValOverflowRes = PoisonValue::get(STy);
65206597
StructValOverflowRes =
6521-
Builder.CreateInsertValue(StructValOverflowRes, PHINode1, {0});
6598+
Builder.CreateInsertValue(StructValOverflowRes, OverflowResPHI, {0});
65226599
StructValOverflowRes =
6523-
Builder.CreateInsertValue(StructValOverflowRes, PHINode2, {1});
6600+
Builder.CreateInsertValue(StructValOverflowRes, OverflowFlagPHI, {1});
6601+
OverflowResPHI->addIncoming(Mul, NoOverflowBB);
6602+
OverflowFlagPHI->addIncoming(ConstantInt::getFalse(I->getContext()),
6603+
NoOverflowBB);
6604+
65246605
// Before moving the mul.overflow intrinsic to the overflowBB, replace all its
65256606
// uses by StructValOverflowRes.
65266607
I->replaceAllUsesWith(StructValOverflowRes);
@@ -6534,9 +6615,8 @@ bool CodeGenPrepare::optimizeMulWithOverflow(Instruction *I, bool IsSigned,
65346615
Builder.CreateBr(OverflowResBB);
65356616

65366617
// Add The Extracted values to the PHINodes in the overflow.res block.
6537-
PHINode1->addIncoming(MulOverflow, OverflowBB);
6538-
PHINode2->addIncoming(OverflowFlag, OverflowBB);
6539-
6618+
OverflowResPHI->addIncoming(MulOverflow, OverflowBB);
6619+
OverflowFlagPHI->addIncoming(OverflowFlag, OverflowBB);
65406620
ModifiedDT = ModifyDT::ModifyBBDT;
65416621
return true;
65426622
}

llvm/lib/Target/AArch64/AArch64ISelLowering.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -321,6 +321,10 @@ class AArch64TargetLowering : public TargetLowering {
321321
return TargetLowering::shouldFormOverflowOp(Opcode, VT, true);
322322
}
323323

324+
// Return true if the target wants to optimize the mul overflow intrinsic
325+
// by detecting if there is no overflow.
326+
bool shouldOptimizeMulOverflowIntrinsic() const override { return true; }
327+
324328
Value *emitLoadLinked(IRBuilderBase &Builder, Type *ValueTy, Value *Addr,
325329
AtomicOrdering Ord) const override;
326330
Value *emitStoreConditional(IRBuilderBase &Builder, Value *Val, Value *Addr,

llvm/test/CodeGen/AArch64/i128-math.ll

Lines changed: 4 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -383,8 +383,7 @@ define { i128, i8 } @i128_checked_mul(i128 %x, i128 %y) {
383383
; CHECK-NEXT: eor x8, x3, x2, asr #63
384384
; CHECK-NEXT: eor x9, x1, x0, asr #63
385385
; CHECK-NEXT: orr x8, x9, x8
386-
; CHECK-NEXT: cmp x8, #1
387-
; CHECK-NEXT: b.ne .LBB21_2
386+
; CHECK-NEXT: cbz x8, .LBB21_2
388387
; CHECK-NEXT: // %bb.1: // %overflow
389388
; CHECK-NEXT: asr x9, x1, #63
390389
; CHECK-NEXT: umulh x10, x0, x2
@@ -418,7 +417,7 @@ define { i128, i8 } @i128_checked_mul(i128 %x, i128 %y) {
418417
; CHECK-NEXT: .LBB21_2: // %overflow.no
419418
; CHECK-NEXT: smulh x1, x0, x2
420419
; CHECK-NEXT: mul x0, x0, x2
421-
; CHECK-NEXT: eor w2, wzr, #0x1
420+
; CHECK-NEXT: eor w2, w8, #0x1
422421
; CHECK-NEXT: ret
423422
%1 = tail call { i128, i1 } @llvm.smul.with.overflow.i128(i128 %x, i128 %y)
424423
%2 = extractvalue { i128, i1 } %1, 0
@@ -436,8 +435,7 @@ define { i128, i8 } @i128_overflowing_mul(i128 %x, i128 %y) {
436435
; CHECK-NEXT: eor x8, x3, x2, asr #63
437436
; CHECK-NEXT: eor x9, x1, x0, asr #63
438437
; CHECK-NEXT: orr x8, x9, x8
439-
; CHECK-NEXT: cmp x8, #1
440-
; CHECK-NEXT: b.ne .LBB22_2
438+
; CHECK-NEXT: cbz x8, .LBB22_2
441439
; CHECK-NEXT: // %bb.1: // %overflow
442440
; CHECK-NEXT: asr x9, x1, #63
443441
; CHECK-NEXT: umulh x10, x0, x2
@@ -487,8 +485,7 @@ define i128 @i128_saturating_mul(i128 %x, i128 %y) {
487485
; CHECK-NEXT: eor x8, x3, x2, asr #63
488486
; CHECK-NEXT: eor x9, x1, x0, asr #63
489487
; CHECK-NEXT: orr x8, x9, x8
490-
; CHECK-NEXT: cmp x8, #1
491-
; CHECK-NEXT: b.ne .LBB23_2
488+
; CHECK-NEXT: cbz x8, .LBB23_2
492489
; CHECK-NEXT: // %bb.1: // %overflow
493490
; CHECK-NEXT: asr x9, x1, #63
494491
; CHECK-NEXT: umulh x10, x0, x2

llvm/test/CodeGen/AArch64/i128_with_overflow.ll

Lines changed: 22 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -225,7 +225,7 @@ define i128 @test_umul_i128(i128 noundef %x, i128 noundef %y) {
225225
; CHECK-LABEL: test_umul_i128:
226226
; CHECK: // %bb.0: // %overflow.entry
227227
; CHECK-NEXT: orr x8, x1, x3
228-
; CHECK-NEXT: cbz x8, .LBB4_2
228+
; CHECK-NEXT: cbz x8, .LBB4_3
229229
; CHECK-NEXT: // %bb.1: // %overflow
230230
; CHECK-NEXT: mul x9, x3, x0
231231
; CHECK-NEXT: cmp x1, #0
@@ -236,17 +236,12 @@ define i128 @test_umul_i128(i128 noundef %x, i128 noundef %y) {
236236
; CHECK-NEXT: ccmp xzr, x10, #0, eq
237237
; CHECK-NEXT: umulh x11, x0, x2
238238
; CHECK-NEXT: ccmp xzr, x8, #0, eq
239-
; CHECK-NEXT: mul x0, x0, x2
240239
; CHECK-NEXT: cset w8, ne
241240
; CHECK-NEXT: adds x1, x11, x9
242241
; CHECK-NEXT: csinc w8, w8, wzr, lo
243-
; CHECK-NEXT: cbnz w8, .LBB4_3
244-
; CHECK-NEXT: b .LBB4_4
245-
; CHECK-NEXT: .LBB4_2: // %overflow.no
246-
; CHECK-NEXT: umulh x1, x0, x2
247-
; CHECK-NEXT: mul x0, x0, x2
248-
; CHECK-NEXT: cbz w8, .LBB4_4
249-
; CHECK-NEXT: .LBB4_3: // %if.then
242+
; CHECK-NEXT: cmp w8, #1
243+
; CHECK-NEXT: b.ne .LBB4_4
244+
; CHECK-NEXT: // %bb.2: // %if.then
250245
; CHECK-NEXT: str x30, [sp, #-16]! // 8-byte Folded Spill
251246
; CHECK-NEXT: .cfi_def_cfa_offset 16
252247
; CHECK-NEXT: .cfi_offset w30, -16
@@ -255,7 +250,11 @@ define i128 @test_umul_i128(i128 noundef %x, i128 noundef %y) {
255250
; CHECK-NEXT: sxtw x0, w0
256251
; CHECK-NEXT: asr x1, x0, #63
257252
; CHECK-NEXT: ldr x30, [sp], #16 // 8-byte Folded Reload
258-
; CHECK-NEXT: .LBB4_4: // %cleanup
253+
; CHECK-NEXT: ret
254+
; CHECK-NEXT: .LBB4_3: // %overflow.no
255+
; CHECK-NEXT: umulh x1, x0, x2
256+
; CHECK-NEXT: .LBB4_4:
257+
; CHECK-NEXT: mul x0, x0, x2
259258
; CHECK-NEXT: ret
260259
entry:
261260
%0 = tail call { i128, i1 } @llvm.umul.with.overflow.i128(i128 %x, i128 %y)
@@ -282,8 +281,7 @@ define i128 @test_smul_i128(i128 noundef %x, i128 noundef %y) {
282281
; CHECK-NEXT: eor x8, x3, x2, asr #63
283282
; CHECK-NEXT: eor x9, x1, x0, asr #63
284283
; CHECK-NEXT: orr x8, x9, x8
285-
; CHECK-NEXT: cmp x8, #1
286-
; CHECK-NEXT: b.ne .LBB5_2
284+
; CHECK-NEXT: cbz x8, .LBB5_3
287285
; CHECK-NEXT: // %bb.1: // %overflow
288286
; CHECK-NEXT: asr x9, x1, #63
289287
; CHECK-NEXT: umulh x10, x0, x2
@@ -304,22 +302,14 @@ define i128 @test_smul_i128(i128 noundef %x, i128 noundef %y) {
304302
; CHECK-NEXT: adc x10, x12, x13
305303
; CHECK-NEXT: asr x12, x10, #63
306304
; CHECK-NEXT: adds x8, x8, x10
307-
; CHECK-NEXT: asr x10, x1, #63
308-
; CHECK-NEXT: mul x0, x0, x2
309-
; CHECK-NEXT: adc x11, x11, x12
305+
; CHECK-NEXT: adc x10, x11, x12
310306
; CHECK-NEXT: adds x8, x15, x8
311-
; CHECK-NEXT: adc x9, x9, x11
312-
; CHECK-NEXT: cmp x8, x10
313-
; CHECK-NEXT: ccmp x9, x10, #0, eq
314-
; CHECK-NEXT: cset w8, ne
315-
; CHECK-NEXT: cbnz w8, .LBB5_3
316-
; CHECK-NEXT: b .LBB5_4
317-
; CHECK-NEXT: .LBB5_2: // %overflow.no
318-
; CHECK-NEXT: smulh x1, x0, x2
319-
; CHECK-NEXT: mov w8, wzr
320-
; CHECK-NEXT: mul x0, x0, x2
321-
; CHECK-NEXT: cbz w8, .LBB5_4
322-
; CHECK-NEXT: .LBB5_3: // %if.then
307+
; CHECK-NEXT: asr x11, x1, #63
308+
; CHECK-NEXT: adc x9, x9, x10
309+
; CHECK-NEXT: cmp x9, x11
310+
; CHECK-NEXT: ccmp x8, x11, #0, eq
311+
; CHECK-NEXT: b.eq .LBB5_4
312+
; CHECK-NEXT: // %bb.2: // %if.then
323313
; CHECK-NEXT: str x30, [sp, #-16]! // 8-byte Folded Spill
324314
; CHECK-NEXT: .cfi_def_cfa_offset 16
325315
; CHECK-NEXT: .cfi_offset w30, -16
@@ -328,7 +318,11 @@ define i128 @test_smul_i128(i128 noundef %x, i128 noundef %y) {
328318
; CHECK-NEXT: sxtw x0, w0
329319
; CHECK-NEXT: asr x1, x0, #63
330320
; CHECK-NEXT: ldr x30, [sp], #16 // 8-byte Folded Reload
331-
; CHECK-NEXT: .LBB5_4: // %cleanup
321+
; CHECK-NEXT: ret
322+
; CHECK-NEXT: .LBB5_3: // %overflow.no
323+
; CHECK-NEXT: smulh x1, x0, x2
324+
; CHECK-NEXT: .LBB5_4:
325+
; CHECK-NEXT: mul x0, x0, x2
332326
; CHECK-NEXT: ret
333327
entry:
334328
%0 = tail call { i128, i1 } @llvm.smul.with.overflow.i128(i128 %x, i128 %y)

llvm/test/CodeGen/AArch64/umulo-128-legalisation-lowering.ll

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -47,8 +47,7 @@ define i128 @__muloti4(i128 %0, i128 %1, ptr nocapture nonnull writeonly align 4
4747
; AARCH-NEXT: eor x9, x1, x0, asr #63
4848
; AARCH-NEXT: str wzr, [x4]
4949
; AARCH-NEXT: orr x8, x9, x8
50-
; AARCH-NEXT: cmp x8, #1
51-
; AARCH-NEXT: b.ne .LBB1_2
50+
; AARCH-NEXT: cbz x8, .LBB1_2
5251
; AARCH-NEXT: // %bb.1: // %overflow
5352
; AARCH-NEXT: asr x9, x1, #63
5453
; AARCH-NEXT: umulh x10, x0, x2

0 commit comments

Comments
 (0)