Skip to content

[RISCV] Support select optimization #80124

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

Open
wants to merge 7 commits into
base: users/wangpc-pp/spr/main.riscv-support-select-optimization
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions llvm/lib/Target/RISCV/RISCVFeatures.td
Original file line number Diff line number Diff line change
Expand Up @@ -1266,6 +1266,10 @@ def FeaturePredictableSelectIsExpensive
: SubtargetFeature<"predictable-select-expensive", "PredictableSelectIsExpensive", "true",
"Prefer likely predicted branches over selects">;

def FeatureEnableSelectOptimize
: SubtargetFeature<"enable-select-opt", "EnableSelectOptimize", "true",
"Enable the select optimize pass for select loop heuristics">;

def TuneNoOptimizedZeroStrideLoad
: SubtargetFeature<"no-optimized-zero-stride-load", "HasOptimizedZeroStrideLoad",
"false", "Hasn't optimized (perform fewer memory operations)"
Expand Down
8 changes: 8 additions & 0 deletions llvm/lib/Target/RISCV/RISCVTargetMachine.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,11 @@ static cl::opt<bool> EnableVSETVLIAfterRVVRegAlloc(
cl::desc("Insert vsetvls after vector register allocation"),
cl::init(true));

static cl::opt<bool>
EnableSelectOpt("riscv-select-opt", cl::Hidden,
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If no in tree targets use this, should we default to false?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We have already disabled it via enableSelectOptimize()?

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

But we added a bunch of passes to the pipeline. Does that have compile time impact?

Copy link
Contributor Author

@wangpc-pp wangpc-pp Feb 27, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, this point makes sence to me. This pass adds several analysis passes (most of them can be cached), so it may impact compile time.
I think the impact won't be large, since the pass is early out before these analysises actully run when enableSelectOptimize returns false .

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@topperc WDYT?

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think the impact won't be large, since the pass is early out before these analysises actully run when enableSelectOptimize returns false .

The pass manager will run the analysis passes before the runOnFunction in the select optimize pass gets called. Unless those analysis passes do lazy updates and only compute something when they are queried, they will run before the early out.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Most of the added passes have been run before, so they may be cached?

cl::desc("Enable select to branch optimizations"),
cl::init(true));

extern "C" LLVM_EXTERNAL_VISIBILITY void LLVMInitializeRISCVTarget() {
RegisterTargetMachine<RISCVTargetMachine> X(getTheRISCV32Target());
RegisterTargetMachine<RISCVTargetMachine> Y(getTheRISCV64Target());
Expand Down Expand Up @@ -427,6 +432,9 @@ void RISCVPassConfig::addIRPasses() {
}

TargetPassConfig::addIRPasses();

if (getOptLevel() == CodeGenOptLevel::Aggressive && EnableSelectOpt)
addPass(createSelectOptimizePass());
}

bool RISCVPassConfig::addPreISel() {
Expand Down
15 changes: 15 additions & 0 deletions llvm/lib/Target/RISCV/RISCVTargetTransformInfo.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,9 @@ static cl::opt<unsigned> SLPMaxVF(
"exclusively by SLP vectorizer."),
cl::Hidden);

static cl::opt<bool> EnableOrLikeSelectOpt("enable-riscv-or-like-select",
cl::init(true), cl::Hidden);

InstructionCost
RISCVTTIImpl::getRISCVInstructionCost(ArrayRef<unsigned> OpCodes, MVT VT,
TTI::TargetCostKind CostKind) {
Expand Down Expand Up @@ -1942,3 +1945,15 @@ bool RISCVTTIImpl::areInlineCompatible(const Function *Caller,
// target-features.
return (CallerBits & CalleeBits) == CalleeBits;
}

bool RISCVTTIImpl::shouldTreatInstructionLikeSelect(const Instruction *I) {
// For the binary operators (e.g. or) we need to be more careful than
// selects, here we only transform them if they are already at a natural
// break point in the code - the end of a block with an unconditional
// terminator.
if (EnableOrLikeSelectOpt && I->getOpcode() == Instruction::Or &&
isa<BranchInst>(I->getNextNode()) &&
cast<BranchInst>(I->getNextNode())->isUnconditional())
return true;
return BaseT::shouldTreatInstructionLikeSelect(I);
}
3 changes: 3 additions & 0 deletions llvm/lib/Target/RISCV/RISCVTargetTransformInfo.h
Original file line number Diff line number Diff line change
Expand Up @@ -399,6 +399,9 @@ class RISCVTTIImpl : public BasicTTIImplBase<RISCVTTIImpl> {
}

std::optional<unsigned> getMinPageSize() const { return 4096; }

bool enableSelectOptimize() { return ST->enableSelectOptimize(); }
bool shouldTreatInstructionLikeSelect(const Instruction *I);
};

} // end namespace llvm
Expand Down
9 changes: 9 additions & 0 deletions llvm/test/CodeGen/RISCV/O3-pipeline.ll
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,15 @@
; CHECK-NEXT: Expand reduction intrinsics
; CHECK-NEXT: Natural Loop Information
; CHECK-NEXT: TLS Variable Hoist
; CHECK-NEXT: Post-Dominator Tree Construction
; CHECK-NEXT: Branch Probability Analysis
; CHECK-NEXT: Block Frequency Analysis
; CHECK-NEXT: Lazy Branch Probability Analysis
; CHECK-NEXT: Lazy Block Frequency Analysis
; CHECK-NEXT: Optimization Remark Emitter
; CHECK-NEXT: Optimize selects
; CHECK-NEXT: Dominator Tree Construction
; CHECK-NEXT: Natural Loop Information
; CHECK-NEXT: Type Promotion
; CHECK-NEXT: CodeGen Prepare
; CHECK-NEXT: Dominator Tree Construction
Expand Down
289 changes: 289 additions & 0 deletions llvm/test/CodeGen/RISCV/selectopt.ll
Original file line number Diff line number Diff line change
@@ -0,0 +1,289 @@
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
; RUN: opt -select-optimize -mtriple=riscv64 -S < %s \
; RUN: | FileCheck %s --check-prefix=NO-SELECT-OPT
; RUN: opt -select-optimize -mtriple=riscv64 -mattr=+enable-select-opt -S < %s \
; RUN: | FileCheck %s --check-prefix=SELECT-OPT
; RUN: opt -select-optimize -mtriple=riscv64 -mattr=+enable-select-opt,+predictable-select-expensive -S < %s \
; RUN: | FileCheck %s --check-prefix=SELECT-OPT

%struct.st = type { i32, i64, ptr, ptr, i16, ptr, ptr, i64, i64 }

; This test has a select at the end of if.then, which is better transformed to a branch on OoO cores.
define void @replace(ptr %newst) {
; NO-SELECT-OPT-LABEL: @replace(
; NO-SELECT-OPT-NEXT: entry:
; NO-SELECT-OPT-NEXT: br label [[LAND_RHS:%.*]]
; NO-SELECT-OPT: land.rhs:
; NO-SELECT-OPT-NEXT: [[CMP_0151:%.*]] = phi i64 [ [[SPEC_SELECT:%.*]], [[LAND_RHS]] ], [ 0, [[ENTRY:%.*]] ]
; NO-SELECT-OPT-NEXT: [[FLOW81:%.*]] = getelementptr [[STRUCT_ST:%.*]], ptr [[NEWST:%.*]], i64 [[CMP_0151]], i32 7
; NO-SELECT-OPT-NEXT: [[TMP0:%.*]] = load i64, ptr [[FLOW81]], align 8
; NO-SELECT-OPT-NEXT: [[CMP84:%.*]] = icmp slt i64 [[TMP0]], 0
; NO-SELECT-OPT-NEXT: [[SPEC_SELECT]] = select i1 [[CMP84]], i64 0, i64 0
; NO-SELECT-OPT-NEXT: br label [[LAND_RHS]]
;
; SELECT-OPT-LABEL: @replace(
; SELECT-OPT-NEXT: entry:
; SELECT-OPT-NEXT: br label [[LAND_RHS:%.*]]
; SELECT-OPT: land.rhs:
; SELECT-OPT-NEXT: [[CMP_0151:%.*]] = phi i64 [ [[SPEC_SELECT:%.*]], [[SELECT_END:%.*]] ], [ 0, [[ENTRY:%.*]] ]
; SELECT-OPT-NEXT: [[FLOW81:%.*]] = getelementptr [[STRUCT_ST:%.*]], ptr [[NEWST:%.*]], i64 [[CMP_0151]], i32 7
; SELECT-OPT-NEXT: [[TMP0:%.*]] = load i64, ptr [[FLOW81]], align 8
; SELECT-OPT-NEXT: [[CMP84:%.*]] = icmp slt i64 [[TMP0]], 0
; SELECT-OPT-NEXT: [[CMP84_FROZEN:%.*]] = freeze i1 [[CMP84]]
; SELECT-OPT-NEXT: br i1 [[CMP84_FROZEN]], label [[SELECT_END]], label [[SELECT_FALSE:%.*]]
; SELECT-OPT: select.false:
; SELECT-OPT-NEXT: br label [[SELECT_END]]
; SELECT-OPT: select.end:
; SELECT-OPT-NEXT: [[SPEC_SELECT]] = phi i64 [ 0, [[LAND_RHS]] ], [ 0, [[SELECT_FALSE]] ]
; SELECT-OPT-NEXT: br label [[LAND_RHS]]
;
entry:
br label %land.rhs

land.rhs: ; preds = %land.rhs, %entry
%cmp.0151 = phi i64 [ %spec.select, %land.rhs ], [ 0, %entry ]
%flow81 = getelementptr %struct.st, ptr %newst, i64 %cmp.0151, i32 7
%0 = load i64, ptr %flow81, align 8
%cmp84 = icmp slt i64 %0, 0
%spec.select = select i1 %cmp84, i64 0, i64 0
br label %land.rhs
}

define void @replace_or(ptr %newst) {
; NO-SELECT-OPT-LABEL: @replace_or(
; NO-SELECT-OPT-NEXT: entry:
; NO-SELECT-OPT-NEXT: br label [[LAND_RHS:%.*]]
; NO-SELECT-OPT: land.rhs:
; NO-SELECT-OPT-NEXT: [[CMP_0151:%.*]] = phi i64 [ [[SPEC_SELECT:%.*]], [[LAND_RHS]] ], [ 0, [[ENTRY:%.*]] ]
; NO-SELECT-OPT-NEXT: [[MUL:%.*]] = shl i64 [[CMP_0151]], 0
; NO-SELECT-OPT-NEXT: [[SUB79:%.*]] = or i64 [[MUL]], 0
; NO-SELECT-OPT-NEXT: [[FLOW81:%.*]] = getelementptr [[STRUCT_ST:%.*]], ptr [[NEWST:%.*]], i64 [[SUB79]], i32 7
; NO-SELECT-OPT-NEXT: [[TMP0:%.*]] = load i64, ptr null, align 8
; NO-SELECT-OPT-NEXT: [[CMP84:%.*]] = icmp slt i64 [[TMP0]], 0
; NO-SELECT-OPT-NEXT: [[ADD:%.*]] = zext i1 [[CMP84]] to i64
; NO-SELECT-OPT-NEXT: [[SPEC_SELECT]] = or i64 0, [[ADD]]
; NO-SELECT-OPT-NEXT: br label [[LAND_RHS]]
;
; SELECT-OPT-LABEL: @replace_or(
; SELECT-OPT-NEXT: entry:
; SELECT-OPT-NEXT: br label [[LAND_RHS:%.*]]
; SELECT-OPT: land.rhs:
; SELECT-OPT-NEXT: [[CMP_0151:%.*]] = phi i64 [ [[SPEC_SELECT:%.*]], [[SELECT_END:%.*]] ], [ 0, [[ENTRY:%.*]] ]
; SELECT-OPT-NEXT: [[MUL:%.*]] = shl i64 [[CMP_0151]], 0
; SELECT-OPT-NEXT: [[SUB79:%.*]] = or i64 [[MUL]], 0
; SELECT-OPT-NEXT: [[FLOW81:%.*]] = getelementptr [[STRUCT_ST:%.*]], ptr [[NEWST:%.*]], i64 [[SUB79]], i32 7
; SELECT-OPT-NEXT: [[TMP0:%.*]] = load i64, ptr null, align 8
; SELECT-OPT-NEXT: [[CMP84:%.*]] = icmp slt i64 [[TMP0]], 0
; SELECT-OPT-NEXT: [[ADD:%.*]] = zext i1 [[CMP84]] to i64
; SELECT-OPT-NEXT: [[CMP84_FROZEN:%.*]] = freeze i1 [[CMP84]]
; SELECT-OPT-NEXT: br i1 [[CMP84_FROZEN]], label [[SELECT_END]], label [[SELECT_FALSE:%.*]]
; SELECT-OPT: select.false:
; SELECT-OPT-NEXT: br label [[SELECT_END]]
; SELECT-OPT: select.end:
; SELECT-OPT-NEXT: [[SPEC_SELECT]] = phi i64 [ 1, [[LAND_RHS]] ], [ 0, [[SELECT_FALSE]] ]
; SELECT-OPT-NEXT: br label [[LAND_RHS]]
;
entry:
br label %land.rhs

land.rhs: ; preds = %land.rhs, %entry
%cmp.0151 = phi i64 [ %spec.select, %land.rhs ], [ 0, %entry ]
%mul = shl i64 %cmp.0151, 0
%sub79 = or i64 %mul, 0
%flow81 = getelementptr %struct.st, ptr %newst, i64 %sub79, i32 7
%0 = load i64, ptr null, align 8
%cmp84 = icmp slt i64 %0, 0
%add = zext i1 %cmp84 to i64
%spec.select = or i64 0, %add
br label %land.rhs
}

; This `or` is not transformed as it is not the last instruction in the block
define void @or_notatendofblock(ptr %newst) {
; NO-SELECT-OPT-LABEL: @or_notatendofblock(
; NO-SELECT-OPT-NEXT: entry:
; NO-SELECT-OPT-NEXT: br label [[LAND_RHS:%.*]]
; NO-SELECT-OPT: land.rhs:
; NO-SELECT-OPT-NEXT: [[CMP_0151:%.*]] = phi i64 [ [[OR:%.*]], [[LAND_RHS]] ], [ 0, [[ENTRY:%.*]] ]
; NO-SELECT-OPT-NEXT: [[MUL:%.*]] = shl i64 [[CMP_0151]], 0
; NO-SELECT-OPT-NEXT: [[SUB79:%.*]] = or i64 [[MUL]], 0
; NO-SELECT-OPT-NEXT: [[FLOW81:%.*]] = getelementptr [[STRUCT_ST:%.*]], ptr [[NEWST:%.*]], i64 [[SUB79]], i32 7
; NO-SELECT-OPT-NEXT: [[TMP0:%.*]] = load i64, ptr null, align 8
; NO-SELECT-OPT-NEXT: [[CMP84:%.*]] = icmp slt i64 [[TMP0]], 0
; NO-SELECT-OPT-NEXT: [[ADD:%.*]] = zext i1 [[CMP84]] to i64
; NO-SELECT-OPT-NEXT: [[OR1:%.*]] = or i64 0, [[ADD]]
; NO-SELECT-OPT-NEXT: [[OR]] = add i64 [[OR1]], 1
; NO-SELECT-OPT-NEXT: br label [[LAND_RHS]]
;
; SELECT-OPT-LABEL: @or_notatendofblock(
; SELECT-OPT-NEXT: entry:
; SELECT-OPT-NEXT: br label [[LAND_RHS:%.*]]
; SELECT-OPT: land.rhs:
; SELECT-OPT-NEXT: [[CMP_0151:%.*]] = phi i64 [ [[OR:%.*]], [[LAND_RHS]] ], [ 0, [[ENTRY:%.*]] ]
; SELECT-OPT-NEXT: [[MUL:%.*]] = shl i64 [[CMP_0151]], 0
; SELECT-OPT-NEXT: [[SUB79:%.*]] = or i64 [[MUL]], 0
; SELECT-OPT-NEXT: [[FLOW81:%.*]] = getelementptr [[STRUCT_ST:%.*]], ptr [[NEWST:%.*]], i64 [[SUB79]], i32 7
; SELECT-OPT-NEXT: [[TMP0:%.*]] = load i64, ptr null, align 8
; SELECT-OPT-NEXT: [[CMP84:%.*]] = icmp slt i64 [[TMP0]], 0
; SELECT-OPT-NEXT: [[ADD:%.*]] = zext i1 [[CMP84]] to i64
; SELECT-OPT-NEXT: [[OR1:%.*]] = or i64 0, [[ADD]]
; SELECT-OPT-NEXT: [[OR]] = add i64 [[OR1]], 1
; SELECT-OPT-NEXT: br label [[LAND_RHS]]
;
entry:
br label %land.rhs

land.rhs: ; preds = %land.rhs, %entry
%cmp.0151 = phi i64 [ %or, %land.rhs ], [ 0, %entry ]
%mul = shl i64 %cmp.0151, 0
%sub79 = or i64 %mul, 0
%flow81 = getelementptr %struct.st, ptr %newst, i64 %sub79, i32 7
%0 = load i64, ptr null, align 8
%cmp84 = icmp slt i64 %0, 0
%add = zext i1 %cmp84 to i64
%or1 = or i64 0, %add
%or = add i64 %or1, 1
br label %land.rhs
}

; Similar to the last test, an artificial test with the or as the last instruction and a select in the same group.
define i32 @or_samegroup() {
; NO-SELECT-OPT-LABEL: @or_samegroup(
; NO-SELECT-OPT-NEXT: entry:
; NO-SELECT-OPT-NEXT: br label [[FOR_BODY:%.*]]
; NO-SELECT-OPT: for.body:
; NO-SELECT-OPT-NEXT: [[Y_020:%.*]] = phi i32 [ 0, [[ENTRY:%.*]] ], [ [[SEL:%.*]], [[FOR_BODY]] ]
; NO-SELECT-OPT-NEXT: [[DIV1:%.*]] = sdiv i32 [[Y_020]], 0
; NO-SELECT-OPT-NEXT: [[CMP5:%.*]] = icmp sgt i32 [[DIV1]], 0
; NO-SELECT-OPT-NEXT: [[CONV:%.*]] = zext i1 [[CMP5]] to i32
; NO-SELECT-OPT-NEXT: [[SEL]] = select i1 [[CMP5]], i32 0, i32 0
; NO-SELECT-OPT-NEXT: [[OR:%.*]] = or i32 [[CONV]], [[SEL]]
; NO-SELECT-OPT-NEXT: br label [[FOR_BODY]]
;
; SELECT-OPT-LABEL: @or_samegroup(
; SELECT-OPT-NEXT: entry:
; SELECT-OPT-NEXT: br label [[FOR_BODY:%.*]]
; SELECT-OPT: for.body:
; SELECT-OPT-NEXT: [[Y_020:%.*]] = phi i32 [ 0, [[ENTRY:%.*]] ], [ [[SEL:%.*]], [[SELECT_END1:%.*]] ]
; SELECT-OPT-NEXT: [[DIV1:%.*]] = sdiv i32 [[Y_020]], 0
; SELECT-OPT-NEXT: [[CMP5:%.*]] = icmp sgt i32 [[DIV1]], 0
; SELECT-OPT-NEXT: [[CONV:%.*]] = zext i1 [[CMP5]] to i32
; SELECT-OPT-NEXT: [[CMP5_FROZEN:%.*]] = freeze i1 [[CMP5]]
; SELECT-OPT-NEXT: br i1 [[CMP5_FROZEN]], label [[SELECT_END:%.*]], label [[SELECT_FALSE:%.*]]
; SELECT-OPT: select.false:
; SELECT-OPT-NEXT: br label [[SELECT_END]]
; SELECT-OPT: select.end:
; SELECT-OPT-NEXT: [[SEL]] = phi i32 [ 0, [[FOR_BODY]] ], [ 0, [[SELECT_FALSE]] ]
; SELECT-OPT-NEXT: [[CMP5_FROZEN3:%.*]] = freeze i1 [[CMP5]]
; SELECT-OPT-NEXT: [[TMP0:%.*]] = or i32 [[SEL]], 1
; SELECT-OPT-NEXT: br i1 [[CMP5_FROZEN3]], label [[SELECT_END1]], label [[SELECT_FALSE2:%.*]]
; SELECT-OPT: select.false2:
; SELECT-OPT-NEXT: br label [[SELECT_END1]]
; SELECT-OPT: select.end1:
; SELECT-OPT-NEXT: [[OR:%.*]] = phi i32 [ [[TMP0]], [[SELECT_END]] ], [ [[SEL]], [[SELECT_FALSE2]] ]
; SELECT-OPT-NEXT: br label [[FOR_BODY]]
;
entry:
br label %for.body

for.body: ; preds = %for.body, %entry
%y.020 = phi i32 [ 0, %entry ], [ %sel, %for.body ]
%div1 = sdiv i32 %y.020, 0
%cmp5 = icmp sgt i32 %div1, 0
%conv = zext i1 %cmp5 to i32
%sel = select i1 %cmp5, i32 0, i32 0
%or = or i32 %conv, %sel
br label %for.body
}

; Same test again with a one use value group of values on the or
define i32 @or_oneusevalue() {
; NO-SELECT-OPT-LABEL: @or_oneusevalue(
; NO-SELECT-OPT-NEXT: entry:
; NO-SELECT-OPT-NEXT: br label [[FOR_BODY:%.*]]
; NO-SELECT-OPT: for.body:
; NO-SELECT-OPT-NEXT: [[INDVARS_IV:%.*]] = phi i64 [ 0, [[ENTRY:%.*]] ], [ [[INDVARS_IV_NEXT:%.*]], [[IF_END:%.*]] ]
; NO-SELECT-OPT-NEXT: [[Y_020:%.*]] = phi i32 [ 0, [[ENTRY]] ], [ [[Y_1:%.*]], [[IF_END]] ]
; NO-SELECT-OPT-NEXT: [[TMP0:%.*]] = load i32, ptr null, align 4
; NO-SELECT-OPT-NEXT: [[ADD:%.*]] = add nsw i32 [[TMP0]], [[Y_020]]
; NO-SELECT-OPT-NEXT: [[TOBOOL_NOT:%.*]] = icmp eq i32 [[ADD]], 0
; NO-SELECT-OPT-NEXT: br i1 [[TOBOOL_NOT]], label [[IF_END]], label [[IF_THEN:%.*]]
; NO-SELECT-OPT: if.then:
; NO-SELECT-OPT-NEXT: [[TMP1:%.*]] = load i32, ptr null, align 4
; NO-SELECT-OPT-NEXT: [[DIV:%.*]] = sdiv i32 [[Y_020]], [[TMP1]]
; NO-SELECT-OPT-NEXT: [[DIV1:%.*]] = sdiv i32 [[DIV]], [[TMP1]]
; NO-SELECT-OPT-NEXT: [[CMP5:%.*]] = icmp sgt i32 [[DIV1]], 0
; NO-SELECT-OPT-NEXT: [[CONV:%.*]] = zext i1 [[CMP5]] to i32
; NO-SELECT-OPT-NEXT: [[ADD1:%.*]] = add i32 [[ADD]], 1
; NO-SELECT-OPT-NEXT: [[ADD2:%.*]] = or i32 [[ADD1]], 1
; NO-SELECT-OPT-NEXT: [[OR:%.*]] = or i32 [[CONV]], [[ADD2]]
; NO-SELECT-OPT-NEXT: br label [[IF_END]]
; NO-SELECT-OPT: if.end:
; NO-SELECT-OPT-NEXT: [[Y_1]] = phi i32 [ [[OR]], [[IF_THEN]] ], [ 0, [[FOR_BODY]] ]
; NO-SELECT-OPT-NEXT: store i32 [[Y_1]], ptr null, align 4
; NO-SELECT-OPT-NEXT: [[INDVARS_IV_NEXT]] = add nuw nsw i64 [[INDVARS_IV]], 1
; NO-SELECT-OPT-NEXT: [[EXITCOND_NOT:%.*]] = icmp eq i64 [[INDVARS_IV_NEXT]], 0
; NO-SELECT-OPT-NEXT: br label [[FOR_BODY]]
;
; SELECT-OPT-LABEL: @or_oneusevalue(
; SELECT-OPT-NEXT: entry:
; SELECT-OPT-NEXT: br label [[FOR_BODY:%.*]]
; SELECT-OPT: for.body:
; SELECT-OPT-NEXT: [[INDVARS_IV:%.*]] = phi i64 [ 0, [[ENTRY:%.*]] ], [ [[INDVARS_IV_NEXT:%.*]], [[IF_END:%.*]] ]
; SELECT-OPT-NEXT: [[Y_020:%.*]] = phi i32 [ 0, [[ENTRY]] ], [ [[Y_1:%.*]], [[IF_END]] ]
; SELECT-OPT-NEXT: [[TMP0:%.*]] = load i32, ptr null, align 4
; SELECT-OPT-NEXT: [[ADD:%.*]] = add nsw i32 [[TMP0]], [[Y_020]]
; SELECT-OPT-NEXT: [[TOBOOL_NOT:%.*]] = icmp eq i32 [[ADD]], 0
; SELECT-OPT-NEXT: br i1 [[TOBOOL_NOT]], label [[IF_END]], label [[IF_THEN:%.*]]
; SELECT-OPT: if.then:
; SELECT-OPT-NEXT: [[TMP1:%.*]] = load i32, ptr null, align 4
; SELECT-OPT-NEXT: [[DIV:%.*]] = sdiv i32 [[Y_020]], [[TMP1]]
; SELECT-OPT-NEXT: [[DIV1:%.*]] = sdiv i32 [[DIV]], [[TMP1]]
; SELECT-OPT-NEXT: [[CMP5:%.*]] = icmp sgt i32 [[DIV1]], 0
; SELECT-OPT-NEXT: [[CONV:%.*]] = zext i1 [[CMP5]] to i32
; SELECT-OPT-NEXT: [[ADD1:%.*]] = add i32 [[ADD]], 1
; SELECT-OPT-NEXT: [[ADD2:%.*]] = or i32 [[ADD1]], 1
; SELECT-OPT-NEXT: [[CMP5_FROZEN:%.*]] = freeze i1 [[CMP5]]
; SELECT-OPT-NEXT: [[TMP2:%.*]] = or i32 [[ADD2]], 1
; SELECT-OPT-NEXT: br i1 [[CMP5_FROZEN]], label [[SELECT_END:%.*]], label [[SELECT_FALSE:%.*]]
; SELECT-OPT: select.false:
; SELECT-OPT-NEXT: br label [[SELECT_END]]
; SELECT-OPT: select.end:
; SELECT-OPT-NEXT: [[OR:%.*]] = phi i32 [ [[TMP2]], [[IF_THEN]] ], [ [[ADD2]], [[SELECT_FALSE]] ]
; SELECT-OPT-NEXT: br label [[IF_END]]
; SELECT-OPT: if.end:
; SELECT-OPT-NEXT: [[Y_1]] = phi i32 [ [[OR]], [[SELECT_END]] ], [ 0, [[FOR_BODY]] ]
; SELECT-OPT-NEXT: store i32 [[Y_1]], ptr null, align 4
; SELECT-OPT-NEXT: [[INDVARS_IV_NEXT]] = add nuw nsw i64 [[INDVARS_IV]], 1
; SELECT-OPT-NEXT: [[EXITCOND_NOT:%.*]] = icmp eq i64 [[INDVARS_IV_NEXT]], 0
; SELECT-OPT-NEXT: br label [[FOR_BODY]]
;
entry:
br label %for.body

for.body: ; preds = %if.end, %entry
%indvars.iv = phi i64 [ 0, %entry ], [ %indvars.iv.next, %if.end ]
%y.020 = phi i32 [ 0, %entry ], [ %y.1, %if.end ]
%0 = load i32, ptr null, align 4
%add = add nsw i32 %0, %y.020
%tobool.not = icmp eq i32 %add, 0
br i1 %tobool.not, label %if.end, label %if.then

if.then: ; preds = %for.body
%1 = load i32, ptr null, align 4
%div = sdiv i32 %y.020, %1
%div1 = sdiv i32 %div, %1
%cmp5 = icmp sgt i32 %div1, 0
%conv = zext i1 %cmp5 to i32
%add1 = add i32 %add, 1
%add2 = or i32 %add1, 1
%or = or i32 %conv, %add2
br label %if.end

if.end: ; preds = %if.then, %for.body
%y.1 = phi i32 [ %or, %if.then ], [ 0, %for.body ]
store i32 %y.1, ptr null, align 4
%indvars.iv.next = add nuw nsw i64 %indvars.iv, 1
%exitcond.not = icmp eq i64 %indvars.iv.next, 0
br label %for.body
}
Loading