Skip to content

Commit 700d241

Browse files
committed
[CodeExtractor] Replace uses of extracted bitcasts in out-of-region lifetime markers
CodeExtractor handles bitcasts in the extracted region that have lifetime markers users in the outer region as outputs. That creates unnecessary alloca/reload instructions and extra lifetime markers. The patch identifies those cases, and replaces uses in out-of-region lifetime markers with new bitcasts in the outer region. **Example** ``` define void @foo() { entry: %0 = alloca i32 br label %extract extract: %1 = bitcast i32* %0 to i8* call void @llvm.lifetime.start.p0i8(i64 4, i8* %1) call void @use(i32* %0) br label %exit exit: call void @use(i32* %0) call void @llvm.lifetime.end.p0i8(i64 4, i8* %1) ret void } ``` **Current extraction** ``` define void @foo() { entry: %.loc = alloca i8*, align 8 %0 = alloca i32, align 4 br label %codeRepl codeRepl: ; preds = %entry %lt.cast = bitcast i8** %.loc to i8* call void @llvm.lifetime.start.p0i8(i64 -1, i8* %lt.cast) %lt.cast1 = bitcast i32* %0 to i8* call void @llvm.lifetime.start.p0i8(i64 -1, i8* %lt.cast1) call void @foo.extract(i32* %0, i8** %.loc) %.reload = load i8*, i8** %.loc, align 8 call void @llvm.lifetime.end.p0i8(i64 -1, i8* %lt.cast) br label %exit exit: ; preds = %codeRepl call void @use(i32* %0) call void @llvm.lifetime.end.p0i8(i64 4, i8* %.reload) ret void } define internal void @foo.extract(i32* %0, i8** %.out) { newFuncRoot: br label %extract exit.exitStub: ; preds = %extract ret void extract: ; preds = %newFuncRoot %1 = bitcast i32* %0 to i8* store i8* %1, i8** %.out, align 8 call void @use(i32* %0) br label %exit.exitStub } ``` **Extraction with patch** ``` define void @foo() { entry: %0 = alloca i32, align 4 br label %codeRepl codeRepl: ; preds = %entry %lt.cast1 = bitcast i32* %0 to i8* call void @llvm.lifetime.start.p0i8(i64 -1, i8* %lt.cast1) call void @foo.extract(i32* %0) br label %exit exit: ; preds = %codeRepl call void @use(i32* %0) %lt.cast = bitcast i32* %0 to i8* call void @llvm.lifetime.end.p0i8(i64 4, i8* %lt.cast) ret void } define internal void @foo.extract(i32* %0) { newFuncRoot: br label %extract exit.exitStub: ; preds = %extract ret void extract: ; preds = %newFuncRoot %1 = bitcast i32* %0 to i8* call void @use(i32* %0) br label %exit.exitStub } ``` Reviewed By: vsk Differential Revision: https://reviews.llvm.org/D90689
1 parent 65d15fe commit 700d241

File tree

2 files changed

+89
-0
lines changed

2 files changed

+89
-0
lines changed

llvm/lib/Transforms/Utils/CodeExtractor.cpp

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -535,6 +535,46 @@ void CodeExtractor::findAllocas(const CodeExtractorAnalysisCache &CEAC,
535535
continue;
536536
}
537537

538+
// Find bitcasts in the outlined region that have lifetime marker users
539+
// outside that region. Replace the lifetime marker use with an
540+
// outside region bitcast to avoid unnecessary alloca/reload instructions
541+
// and extra lifetime markers.
542+
SmallVector<Instruction *, 2> LifetimeBitcastUsers;
543+
for (User *U : AI->users()) {
544+
if (!definedInRegion(Blocks, U))
545+
continue;
546+
547+
if (U->stripInBoundsConstantOffsets() != AI)
548+
continue;
549+
550+
Instruction *Bitcast = cast<Instruction>(U);
551+
for (User *BU : Bitcast->users()) {
552+
IntrinsicInst *IntrInst = dyn_cast<IntrinsicInst>(BU);
553+
if (!IntrInst)
554+
continue;
555+
556+
if (!IntrInst->isLifetimeStartOrEnd())
557+
continue;
558+
559+
if (definedInRegion(Blocks, IntrInst))
560+
continue;
561+
562+
LLVM_DEBUG(dbgs() << "Replace use of extracted region bitcast"
563+
<< *Bitcast << " in out-of-region lifetime marker "
564+
<< *IntrInst << "\n");
565+
LifetimeBitcastUsers.push_back(IntrInst);
566+
}
567+
}
568+
569+
for (Instruction *I : LifetimeBitcastUsers) {
570+
Module *M = AIFunc->getParent();
571+
LLVMContext &Ctx = M->getContext();
572+
auto *Int8PtrTy = Type::getInt8PtrTy(Ctx);
573+
CastInst *CastI =
574+
CastInst::CreatePointerCast(AI, Int8PtrTy, "lt.cast", I);
575+
I->replaceUsesOfWith(I->getOperand(1), CastI);
576+
}
577+
538578
// Follow any bitcasts.
539579
SmallVector<Instruction *, 2> Bitcasts;
540580
SmallVector<LifetimeMarkerInfo, 2> BitcastLifetimeInfo;

llvm/unittests/Transforms/Utils/CodeExtractorTest.cpp

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -282,4 +282,53 @@ TEST(CodeExtractor, ExtractAndInvalidateAssumptionCache) {
282282
EXPECT_FALSE(verifyFunction(*Func));
283283
EXPECT_FALSE(CE.verifyAssumptionCache(*Func, *Outlined, &AC));
284284
}
285+
286+
TEST(CodeExtractor, RemoveBitcastUsesFromOuterLifetimeMarkers) {
287+
LLVMContext Ctx;
288+
SMDiagnostic Err;
289+
std::unique_ptr<Module> M(parseAssemblyString(R"ir(
290+
target datalayout = "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128"
291+
target triple = "x86_64-unknown-linux-gnu"
292+
293+
declare void @use(i32*)
294+
declare void @llvm.lifetime.start.p0i8(i64, i8*)
295+
declare void @llvm.lifetime.end.p0i8(i64, i8*)
296+
297+
define void @foo() {
298+
entry:
299+
%0 = alloca i32
300+
br label %extract
301+
302+
extract:
303+
%1 = bitcast i32* %0 to i8*
304+
call void @llvm.lifetime.start.p0i8(i64 4, i8* %1)
305+
call void @use(i32* %0)
306+
br label %exit
307+
308+
exit:
309+
call void @use(i32* %0)
310+
call void @llvm.lifetime.end.p0i8(i64 4, i8* %1)
311+
ret void
312+
}
313+
)ir",
314+
Err, Ctx));
315+
316+
Function *Func = M->getFunction("foo");
317+
SmallVector<BasicBlock *, 1> Blocks{getBlockByName(Func, "extract")};
318+
319+
CodeExtractor CE(Blocks);
320+
EXPECT_TRUE(CE.isEligible());
321+
322+
CodeExtractorAnalysisCache CEAC(*Func);
323+
SetVector<Value *> Inputs, Outputs, SinkingCands, HoistingCands;
324+
BasicBlock *CommonExit = nullptr;
325+
CE.findAllocas(CEAC, SinkingCands, HoistingCands, CommonExit);
326+
CE.findInputsOutputs(Inputs, Outputs, SinkingCands);
327+
EXPECT_EQ(Outputs.size(), 0U);
328+
329+
Function *Outlined = CE.extractCodeRegion(CEAC);
330+
EXPECT_TRUE(Outlined);
331+
EXPECT_FALSE(verifyFunction(*Outlined));
332+
EXPECT_FALSE(verifyFunction(*Func));
333+
}
285334
} // end anonymous namespace

0 commit comments

Comments
 (0)