-
Notifications
You must be signed in to change notification settings - Fork 15.2k
[SimplifyCFG] Treat umul + extract pattern as cheap single instruction. #124933
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 6 commits
838e617
31dcf40
134ad7b
3fb1a07
5634169
3ed3573
63a3125
4d014d5
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -3286,7 +3286,24 @@ bool SimplifyCFGOpt::speculativelyExecuteBB(BranchInst *BI, | |
|
|
||
| SmallVector<Instruction *, 4> SpeculatedDbgIntrinsics; | ||
|
|
||
| // The number of already examined instructions. Debug instructions don't | ||
| // count. | ||
| unsigned SpeculatedInstructions = 0; | ||
|
|
||
| // By default the number of instructions that may be speculatively executed is | ||
| // one. Whenever `extract oneuse(op.with.overflow),1` pattern is found, | ||
| // we increase this threshold to the size of the pattern (how many instructions | ||
| // are there in that pattern). | ||
|
|
||
| unsigned MaxSpeculatedInstructionsToHoist = 1; | ||
|
|
||
| // In case we have found a cheap pattern, we don't want to do cost checking | ||
| // anymore. We are sure we want to hoist the pattern. To know, that we are | ||
| // only hoisting the cheap pattern only and not other expensive instructions | ||
| // too, we have the `MaxSpeculatedInstructionsToHoist` variable to track that | ||
| // the basic block truly only contains that pattern. | ||
| bool PartialInst = false; | ||
|
|
||
| bool HoistLoadsStores = HoistLoadsStoresWithCondFaulting && | ||
| Options.HoistLoadsStoresWithCondFaulting; | ||
| SmallVector<Instruction *, 2> SpeculatedConditionalLoadsStores; | ||
|
|
@@ -3316,34 +3333,45 @@ bool SimplifyCFGOpt::speculativelyExecuteBB(BranchInst *BI, | |
| if (EphTracker.track(&I)) | ||
| continue; | ||
|
|
||
| // Only speculatively execute a single instruction (not counting the | ||
| // terminator) for now. | ||
| bool IsSafeCheapLoadStore = HoistLoadsStores && | ||
| isSafeCheapLoadStore(&I, TTI) && | ||
| SpeculatedConditionalLoadsStores.size() < | ||
| HoistLoadsStoresWithCondFaultingThreshold; | ||
|
|
||
| // Overflow arithmetic instruction plus extract value are usually generated | ||
| // when a division is being replaced, but the zero check may still be there. | ||
| // In that case hoist these two instructions out of this basic block, and | ||
| // let later optimizations take care of the unnecessary zero checks. | ||
| WithOverflowInst *OverflowI; | ||
| if (match(&I, m_ExtractValue<1>(m_OneUse(m_WithOverflowInst(OverflowI))))) { | ||
| MaxSpeculatedInstructionsToHoist = 2; | ||
| PartialInst = true; | ||
| } | ||
| // Not count load/store into cost if target supports conditional faulting | ||
| // b/c it's cheap to speculate it. | ||
| if (IsSafeCheapLoadStore) | ||
| SpeculatedConditionalLoadsStores.push_back(&I); | ||
| else | ||
| ++SpeculatedInstructions; | ||
|
|
||
| if (SpeculatedInstructions > 1) | ||
| return false; | ||
|
|
||
| // Don't hoist the instruction if it's unsafe or expensive. | ||
| if (!IsSafeCheapLoadStore && | ||
| !isSafeToSpeculativelyExecute(&I, BI, Options.AC) && | ||
| !(HoistCondStores && !SpeculatedStoreValue && | ||
| (SpeculatedStoreValue = | ||
| isSafeToSpeculateStore(&I, BB, ThenBB, EndBB)))) | ||
| return false; | ||
| if (!IsSafeCheapLoadStore && !SpeculatedStoreValue && | ||
|
|
||
| if (!PartialInst && !IsSafeCheapLoadStore && !SpeculatedStoreValue && | ||
| computeSpeculationCost(&I, TTI) > | ||
| PHINodeFoldingThreshold * TargetTransformInfo::TCC_Basic) | ||
| return false; | ||
|
|
||
| // The number of instructions to be speculatively executed is limited. | ||
| // This limit is dependent on the found patterns. | ||
| if (SpeculatedInstructions > MaxSpeculatedInstructionsToHoist) | ||
| return false; | ||
|
||
|
|
||
| // Store the store speculation candidate. | ||
| if (!SpeculatedStore && SpeculatedStoreValue) | ||
| SpeculatedStore = cast<StoreInst>(&I); | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,59 @@ | ||
| ; NOTE: Assertions have been autogenerated by utils/update_test_checks.py | ||
| ; RUN: opt -passes=simplifycfg -simplifycfg-require-and-preserve-domtree=1 -S < %s | FileCheck %s | ||
| target triple = "riscv64-unknown-unknown-elf" | ||
|
|
||
| define i16 @func2(i64 %x, i64 %y) { | ||
| ; CHECK-LABEL: @func2( | ||
| ; CHECK-NEXT: entry: | ||
| ; CHECK-NEXT: [[CMP_NOT:%.*]] = icmp eq i64 [[Y:%.*]], 0 | ||
| ; CHECK-NEXT: [[MUL:%.*]] = tail call { i64, i1 } @llvm.umul.with.overflow.i64(i64 [[Y]], i64 [[X:%.*]]) | ||
| ; CHECK-NEXT: [[MUL_OV:%.*]] = extractvalue { i64, i1 } [[MUL]], 1 | ||
| ; CHECK-NEXT: [[SPEC_SELECT:%.*]] = select i1 [[CMP_NOT]], i1 false, i1 [[MUL_OV]] | ||
| ; CHECK-NEXT: [[CONV:%.*]] = zext i1 [[SPEC_SELECT]] to i16 | ||
| ; CHECK-NEXT: ret i16 [[CONV]] | ||
| ; | ||
| entry: | ||
| %cmp.not = icmp eq i64 %y, 0 | ||
| br i1 %cmp.not, label %land.end, label %land.rhs | ||
|
|
||
| land.rhs: ; preds = %entry | ||
| %mul = tail call { i64, i1 } @llvm.umul.with.overflow.i64(i64 %y, i64 %x) | ||
| %mul.ov = extractvalue { i64, i1 } %mul, 1 | ||
| br label %land.end | ||
|
|
||
| land.end: ; preds = %land.rhs, %entry | ||
| %0 = phi i1 [ false, %entry ], [ %mul.ov, %land.rhs ] | ||
| %conv = zext i1 %0 to i16 | ||
| ret i16 %conv | ||
| } | ||
|
|
||
| define i16 @noHoist(i64 %x, i64 %y) { | ||
| ; CHECK-LABEL: @noHoist( | ||
| ; CHECK-NEXT: entry: | ||
| ; CHECK-NEXT: [[CMP_NOT:%.*]] = icmp eq i64 [[Y:%.*]], 0 | ||
| ; CHECK-NEXT: br i1 [[CMP_NOT]], label [[LAND_END:%.*]], label [[LAND_RHS:%.*]] | ||
| ; CHECK: land.rhs: | ||
| ; CHECK-NEXT: [[ADD2:%.*]] = add nsw i64 [[Y]], [[X:%.*]] | ||
| ; CHECK-NEXT: [[MUL:%.*]] = tail call { i64, i1 } @llvm.umul.with.overflow.i64(i64 [[ADD2]], i64 [[X]]) | ||
| ; CHECK-NEXT: [[MUL_OV:%.*]] = extractvalue { i64, i1 } [[MUL]], 1 | ||
| ; CHECK-NEXT: br label [[LAND_END]] | ||
| ; CHECK: land.end: | ||
| ; CHECK-NEXT: [[SPEC_SELECT:%.*]] = phi i1 [ false, [[ENTRY:%.*]] ], [ [[MUL_OV]], [[LAND_RHS]] ] | ||
| ; CHECK-NEXT: [[CONV:%.*]] = zext i1 [[SPEC_SELECT]] to i16 | ||
| ; CHECK-NEXT: ret i16 [[CONV]] | ||
| ; | ||
| entry: | ||
| %cmp.not = icmp eq i64 %y, 0 | ||
| br i1 %cmp.not, label %land.end, label %land.rhs | ||
|
|
||
| land.rhs: ; preds = %entry | ||
| %add = add nsw i64 %y, %x | ||
spaits marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| %mul = tail call { i64, i1 } @llvm.umul.with.overflow.i64(i64 %add, i64 %x) | ||
| %mul.ov = extractvalue { i64, i1 } %mul, 1 | ||
| br label %land.end | ||
|
|
||
| land.end: ; preds = %land.rhs, %entry | ||
| %0 = phi i1 [ false, %entry ], [ %mul.ov, %land.rhs ] | ||
| %conv = zext i1 %0 to i16 | ||
| ret i16 %conv | ||
| } | ||
Uh oh!
There was an error while loading. Please reload this page.