diff --git a/llvm/include/llvm/Transforms/Scalar/SeparateConstOffsetFromGEP.h b/llvm/include/llvm/Transforms/Scalar/SeparateConstOffsetFromGEP.h index 5bd6ce164dc320..7b37eb7118a04f 100644 --- a/llvm/include/llvm/Transforms/Scalar/SeparateConstOffsetFromGEP.h +++ b/llvm/include/llvm/Transforms/Scalar/SeparateConstOffsetFromGEP.h @@ -19,6 +19,8 @@ class SeparateConstOffsetFromGEPPass public: SeparateConstOffsetFromGEPPass(bool LowerGEP = false) : LowerGEP(LowerGEP) {} + void printPipeline(raw_ostream &OS, + function_ref MapClassName2PassName); PreservedAnalyses run(Function &F, FunctionAnalysisManager &); }; diff --git a/llvm/lib/Passes/PassBuilder.cpp b/llvm/lib/Passes/PassBuilder.cpp index 93771ea7064f57..dcd002d0be00c5 100644 --- a/llvm/lib/Passes/PassBuilder.cpp +++ b/llvm/lib/Passes/PassBuilder.cpp @@ -937,6 +937,11 @@ Expected parseDependenceAnalysisPrinterOptions(StringRef Params) { "DependenceAnalysisPrinter"); } +Expected parseSeparateConstOffsetFromGEPPassOptions(StringRef Params) { + return parseSinglePassOption(Params, "lower-gep", + "SeparateConstOffsetFromGEP"); +} + } // namespace /// Tests whether a pass name starts with a valid prefix for a default pipeline diff --git a/llvm/lib/Passes/PassRegistry.def b/llvm/lib/Passes/PassRegistry.def index e5aeb466b87b95..04126916a84b02 100644 --- a/llvm/lib/Passes/PassRegistry.def +++ b/llvm/lib/Passes/PassRegistry.def @@ -515,6 +515,13 @@ FUNCTION_PASS_WITH_PARAMS("print", }, parseDependenceAnalysisPrinterOptions, "normalized-results") +FUNCTION_PASS_WITH_PARAMS("separate-const-offset-from-gep", + "SeparateConstOffsetFromGEPPass", + [](bool LowerGEP) { + return SeparateConstOffsetFromGEPPass(LowerGEP); + }, + parseSeparateConstOffsetFromGEPPassOptions, + "lower-gep") #undef FUNCTION_PASS_WITH_PARAMS #ifndef LOOPNEST_PASS diff --git a/llvm/lib/Transforms/Scalar/SeparateConstOffsetFromGEP.cpp b/llvm/lib/Transforms/Scalar/SeparateConstOffsetFromGEP.cpp index 4fb90bcea4f0ab..19196c90699b05 100644 --- a/llvm/lib/Transforms/Scalar/SeparateConstOffsetFromGEP.cpp +++ b/llvm/lib/Transforms/Scalar/SeparateConstOffsetFromGEP.cpp @@ -1376,6 +1376,16 @@ void SeparateConstOffsetFromGEP::swapGEPOperand(GetElementPtrInst *First, First->setIsInBounds(true); } +void SeparateConstOffsetFromGEPPass::printPipeline( + raw_ostream &OS, function_ref MapClassName2PassName) { + static_cast *>(this) + ->printPipeline(OS, MapClassName2PassName); + OS << "<"; + if (LowerGEP) + OS << "lower-gep"; + OS << ">"; +} + PreservedAnalyses SeparateConstOffsetFromGEPPass::run(Function &F, FunctionAnalysisManager &AM) { auto *DT = &AM.getResult(F); diff --git a/llvm/test/Other/new-pm-print-pipeline.ll b/llvm/test/Other/new-pm-print-pipeline.ll index 85029d5cc6d3f3..b0374f99782263 100644 --- a/llvm/test/Other/new-pm-print-pipeline.ll +++ b/llvm/test/Other/new-pm-print-pipeline.ll @@ -89,3 +89,7 @@ ; RUN: opt -disable-output -passes='default' < %s ; RUN: opt -disable-output -passes='default' < %s ; RUN: opt -disable-output -passes='default' < %s + +;; Test SeparateConstOffsetFromGEPPass option. +; RUN: opt -disable-output -disable-verify -print-pipeline-passes -passes='separate-const-offset-from-gep' < %s | FileCheck %s --match-full-lines --check-prefixes=CHECK-27 +; CHECK-27: function(separate-const-offset-from-gep) \ No newline at end of file diff --git a/llvm/test/Transforms/SeparateConstOffsetFromGEP/split-gep-sub.ll b/llvm/test/Transforms/SeparateConstOffsetFromGEP/split-gep-sub.ll new file mode 100644 index 00000000000000..8bc8dbda546125 --- /dev/null +++ b/llvm/test/Transforms/SeparateConstOffsetFromGEP/split-gep-sub.ll @@ -0,0 +1,75 @@ +; NOTE: Assertions have been autogenerated by utils/update_test_checks.py +; RUN: opt -S -passes="separate-const-offset-from-gep" < %s | FileCheck %s + +; Check that GEP with an index 'A - B + [ConstantInt]' will be split into two +; GEPs. eg. +; %A = ... +; %B = ... +; %sub = %A - %B +; %idx = %sub + 10 +; %gep = getelementptr int, ptr %p, %idx +; will be transformed into: +; %A = ... +; %B = ... +; %sub = %A - %B +; %gep_base = getelementptr int, ptr %p, %sub +; %gep = getelementptr int, ptr %gep_base, 10 + +define void @test_A_sub_B_add_ConstantInt(ptr %p) { +; CHECK-LABEL: @test_A_sub_B_add_ConstantInt( +; CHECK-NEXT: entry: +; CHECK-NEXT: [[TMP0:%.*]] = tail call i32 @foo() +; CHECK-NEXT: [[REM:%.*]] = srem i32 [[TMP0]], 5 +; CHECK-NEXT: br label [[FOR_BODY:%.*]] +; CHECK: for.body: +; CHECK-NEXT: [[K:%.*]] = phi i32 [ 0, [[ENTRY:%.*]] ], [ [[INC:%.*]], [[COND_END:%.*]] ] +; CHECK-NEXT: [[MUL:%.*]] = mul nuw nsw i32 [[K]], 5 +; CHECK-NEXT: [[SUB1:%.*]] = sub nsw i32 [[MUL]], [[REM]] +; CHECK-NEXT: [[CMP26:%.*]] = icmp ult i32 [[SUB1]], 512 +; CHECK-NEXT: br i1 [[CMP26]], label [[COND_TRUE:%.*]], label [[COND_END]] +; CHECK: cond.true: +; CHECK-NEXT: [[SUB22:%.*]] = sext i32 [[SUB1]] to i64 +; CHECK-NEXT: [[TMP1:%.*]] = ptrtoint ptr [[P:%.*]] to i64 +; CHECK-NEXT: [[TMP2:%.*]] = shl i64 [[SUB22]], 2 +; CHECK-NEXT: [[TMP3:%.*]] = add i64 [[TMP1]], [[TMP2]] +; CHECK-NEXT: [[TMP4:%.*]] = add i64 [[TMP3]], 2044 +; CHECK-NEXT: [[TMP5:%.*]] = inttoptr i64 [[TMP4]] to ptr +; CHECK-NEXT: store float 1.000000e+00, ptr [[TMP5]], align 4 +; CHECK-NEXT: br label [[COND_END]] +; CHECK: cond.end: +; CHECK-NEXT: [[INC]] = add nuw nsw i32 [[K]], 1 +; CHECK-NEXT: [[EXITCOND:%.*]] = icmp ne i32 [[INC]], 100 +; CHECK-NEXT: br i1 [[EXITCOND]], label [[FOR_BODY]], label [[FOR_END:%.*]] +; CHECK: for.end: +; CHECK-NEXT: ret void +; +entry: + %0 = tail call i32 @foo() + %rem = srem i32 %0, 5 + %add = add nsw i32 %rem , 511 + br label %for.body + +for.body: + %k = phi i32 [ 0, %entry ], [ %inc, %cond.end ] + %mul = mul nuw nsw i32 %k, 5 + %sub1 = sub nsw i32 %mul, %rem + %cmp26 = icmp ult i32 %sub1, 512 + br i1 %cmp26, label %cond.true, label %cond.end + +cond.true: + %sub2 = sub nsw i32 %add, %mul + %idxprom = sext i32 %sub2 to i64 + %arryidx = getelementptr inbounds float, ptr %p, i64 %idxprom + store float 1.0, ptr %arryidx, align 4 + br label %cond.end + +cond.end: + %inc = add nuw nsw i32 %k, 1 + %exitcond = icmp ne i32 %inc, 100 + br i1 %exitcond, label %for.body, label %for.end + +for.end: + ret void +} + +declare i32 @foo()