Skip to content

Commit d3ed84e

Browse files
authored
[Utils][mlir] Fix interaction between CodeExtractor and OpenMPIRBuilder (#145051)
CodeExtractor can currently erroneously insert an alloca into a different function than it inserts its users into, in cases where code is being extracted out of a function that has already been outlined. Add an assertion that the two blocks being inserted into are actually in the same function. Add a check to findAllocaInsertPoint in OpenMP to LLVMIR translation to prevent the aforementioned scenario from happening. OpenMPIRBuilder relies on a callback mechanism to fix-up a module later on during the finaliser step. In some cases this results in the module being invalid prior to the finalise step running. Remove calls to verifyModule wrapped in LLVM_DEBUG from CodeExtractor, as the presence of those results in the compiler crashing with -mllvm -debug due to premature module verification where it would not crash without -debug. Call ompBuilder->finalize() the end of mlir::translateModuleToLLVMIR, in order to make sure the module has actually been finalized prior to trying to verify it. Resolves #138102. --------- Signed-off-by: Kajetan Puchalski <[email protected]>
1 parent 2db3cc4 commit d3ed84e

File tree

7 files changed

+93
-10
lines changed

7 files changed

+93
-10
lines changed

llvm/include/llvm/Frontend/OpenMP/OMPIRBuilder.h

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -484,7 +484,7 @@ class OpenMPIRBuilder {
484484
/// not have an effect on \p M (see initialize)
485485
OpenMPIRBuilder(Module &M)
486486
: M(M), Builder(M.getContext()), OffloadInfoManager(this),
487-
T(M.getTargetTriple()) {}
487+
T(M.getTargetTriple()), IsFinalized(false) {}
488488
LLVM_ABI ~OpenMPIRBuilder();
489489

490490
class AtomicInfo : public llvm::AtomicInfo {
@@ -521,6 +521,10 @@ class OpenMPIRBuilder {
521521
/// all functions are finalized.
522522
LLVM_ABI void finalize(Function *Fn = nullptr);
523523

524+
/// Check whether the finalize function has already run
525+
/// \return true if the finalize function has already run
526+
LLVM_ABI bool isFinalized();
527+
524528
/// Add attributes known for \p FnID to \p Fn.
525529
LLVM_ABI void addAttributes(omp::RuntimeFunction FnID, Function &Fn);
526530

@@ -3286,6 +3290,8 @@ class OpenMPIRBuilder {
32863290
Value *emitRMWOpAsInstruction(Value *Src1, Value *Src2,
32873291
AtomicRMWInst::BinOp RMWOp);
32883292

3293+
bool IsFinalized;
3294+
32893295
public:
32903296
/// a struct to pack relevant information while generating atomic Ops
32913297
struct AtomicOpValue {

llvm/lib/Frontend/OpenMP/OMPIRBuilder.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -824,8 +824,12 @@ void OpenMPIRBuilder::finalize(Function *Fn) {
824824
M.getGlobalVariable("__openmp_nvptx_data_transfer_temporary_storage")};
825825
emitUsed("llvm.compiler.used", LLVMCompilerUsed);
826826
}
827+
828+
IsFinalized = true;
827829
}
828830

831+
bool OpenMPIRBuilder::isFinalized() { return IsFinalized; }
832+
829833
OpenMPIRBuilder::~OpenMPIRBuilder() {
830834
assert(OutlineInfos.empty() && "There must be no outstanding outlinings");
831835
}

llvm/lib/Transforms/Utils/CodeExtractor.cpp

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1528,12 +1528,10 @@ CodeExtractor::extractCodeRegion(const CodeExtractorAnalysisCache &CEAC,
15281528
fixupDebugInfoPostExtraction(*oldFunction, *newFunction, *TheCall, inputs,
15291529
NewValues);
15301530

1531-
LLVM_DEBUG(if (verifyFunction(*newFunction, &errs())) {
1532-
newFunction->dump();
1533-
report_fatal_error("verification of newFunction failed!");
1534-
});
1535-
LLVM_DEBUG(if (verifyFunction(*oldFunction))
1536-
report_fatal_error("verification of oldFunction failed!"));
1531+
LLVM_DEBUG(llvm::dbgs() << "After extractCodeRegion - newFunction:\n");
1532+
LLVM_DEBUG(newFunction->dump());
1533+
LLVM_DEBUG(llvm::dbgs() << "After extractCodeRegion - oldFunction:\n");
1534+
LLVM_DEBUG(oldFunction->dump());
15371535
LLVM_DEBUG(if (AC && verifyAssumptionCache(*oldFunction, *newFunction, AC))
15381536
report_fatal_error("Stale Asumption cache for old Function!"));
15391537
return newFunction;
@@ -1833,6 +1831,9 @@ CallInst *CodeExtractor::emitReplacerCall(
18331831
// This takes place of the original loop
18341832
BasicBlock *codeReplacer =
18351833
BasicBlock::Create(Context, "codeRepl", oldFunction, ReplIP);
1834+
if (AllocationBlock)
1835+
assert(AllocationBlock->getParent() == oldFunction &&
1836+
"AllocationBlock is not in the same function");
18361837
BasicBlock *AllocaBlock =
18371838
AllocationBlock ? AllocationBlock : &oldFunction->getEntryBlock();
18381839

llvm/test/Transforms/HotColdSplit/assumption-cache-invalidation.ll

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
; REQUIRES: asserts
2-
; RUN: opt -S -passes='function(instsimplify),hotcoldsplit' -hotcoldsplit-threshold=-1 -debug < %s 2>&1 | FileCheck %s
2+
; RUN: opt -S -passes='function(instsimplify),hotcoldsplit' -hotcoldsplit-threshold=-1 < %s 2>&1 | FileCheck %s
33
; RUN: opt -passes='function(instcombine),hotcoldsplit,function(instsimplify)' %s -o /dev/null
44

55
target datalayout = "e-m:e-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128"

mlir/lib/Target/LLVMIR/Dialect/OpenMP/OpenMPToLLVMIRTranslation.cpp

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -498,7 +498,13 @@ findAllocaInsertPoint(llvm::IRBuilderBase &builder,
498498
allocaInsertPoint = frame.allocaInsertPoint;
499499
return WalkResult::interrupt();
500500
});
501-
if (walkResult.wasInterrupted())
501+
// In cases with multiple levels of outlining, the tree walk might find an
502+
// alloca insertion point that is inside the original function while the
503+
// builder insertion point is inside the outlined function. We need to make
504+
// sure that we do not use it in those cases.
505+
if (walkResult.wasInterrupted() &&
506+
allocaInsertPoint.getBlock()->getParent() ==
507+
builder.GetInsertBlock()->getParent())
502508
return allocaInsertPoint;
503509

504510
// Otherwise, insert to the entry block of the surrounding function.

mlir/lib/Target/LLVMIR/ModuleTranslation.cpp

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -777,7 +777,7 @@ ModuleTranslation::ModuleTranslation(Operation *module,
777777
}
778778

779779
ModuleTranslation::~ModuleTranslation() {
780-
if (ompBuilder)
780+
if (ompBuilder && !ompBuilder->isFinalized())
781781
ompBuilder->finalize();
782782
}
783783

@@ -2331,6 +2331,10 @@ mlir::translateModuleToLLVMIR(Operation *module, llvm::LLVMContext &llvmContext,
23312331
// beforehand.
23322332
translator.debugTranslation->addModuleFlagsIfNotPresent();
23332333

2334+
// Call the OpenMP IR Builder callbacks prior to verifying the module
2335+
if (auto *ompBuilder = translator.getOpenMPBuilder())
2336+
ompBuilder->finalize();
2337+
23342338
if (!disableVerification &&
23352339
llvm::verifyModule(*translator.llvmModule, &llvm::errs()))
23362340
return nullptr;
Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
// RUN: mlir-translate -mlir-to-llvmir %s | FileCheck %s
2+
// This tests the fix for https://github.com/llvm/llvm-project/issues/138102
3+
// We are only interested in ensuring that the -mlir-to-llvmir pass doesn't crash
4+
5+
// CHECK-LABEL: define internal void @_QQmain..omp_par
6+
7+
omp.private {type = private} @_QFEi_private_i32 : i32
8+
omp.private {type = firstprivate} @_QFEc_firstprivate_i32 : i32 copy {
9+
^bb0(%arg0: !llvm.ptr, %arg1: !llvm.ptr):
10+
%0 = llvm.load %arg0 : !llvm.ptr -> i32
11+
llvm.store %0, %arg1 : i32, !llvm.ptr
12+
omp.yield(%arg1 : !llvm.ptr)
13+
}
14+
llvm.func @_QQmain() {
15+
%0 = llvm.mlir.constant(1 : i64) : i64
16+
%1 = llvm.alloca %0 x i32 {bindc_name = "i"} : (i64) -> !llvm.ptr
17+
%2 = llvm.mlir.constant(1 : i64) : i64
18+
%3 = llvm.alloca %2 x i32 {bindc_name = "c"} : (i64) -> !llvm.ptr
19+
%4 = llvm.mlir.constant(10 : index) : i64
20+
%5 = llvm.mlir.constant(0 : index) : i64
21+
%6 = llvm.mlir.constant(10000 : index) : i64
22+
%7 = llvm.mlir.constant(1 : index) : i64
23+
%8 = llvm.mlir.constant(1 : i64) : i64
24+
%9 = llvm.mlir.addressof @_QFECchunksz : !llvm.ptr
25+
%10 = llvm.mlir.constant(1 : i64) : i64
26+
%11 = llvm.trunc %7 : i64 to i32
27+
llvm.br ^bb1(%11, %4 : i32, i64)
28+
^bb1(%12: i32, %13: i64): // 2 preds: ^bb0, ^bb2
29+
%14 = llvm.icmp "sgt" %13, %5 : i64
30+
llvm.store %12, %3 : i32, !llvm.ptr
31+
omp.task private(@_QFEc_firstprivate_i32 %3 -> %arg0 : !llvm.ptr) {
32+
%19 = omp.map.info var_ptr(%1 : !llvm.ptr, i32) map_clauses(implicit, exit_release_or_enter_alloc) capture(ByCopy) -> !llvm.ptr {name = "i"}
33+
%20 = omp.map.info var_ptr(%arg0 : !llvm.ptr, i32) map_clauses(implicit, exit_release_or_enter_alloc) capture(ByCopy) -> !llvm.ptr {name = "c"}
34+
%21 = omp.map.info var_ptr(%9 : !llvm.ptr, i32) map_clauses(implicit, exit_release_or_enter_alloc) capture(ByCopy) -> !llvm.ptr {name = "chunksz"}
35+
omp.target map_entries(%19 -> %arg1, %20 -> %arg2, %21 -> %arg3 : !llvm.ptr, !llvm.ptr, !llvm.ptr) {
36+
%22 = llvm.mlir.constant(9999 : i32) : i32
37+
%23 = llvm.mlir.constant(1 : i32) : i32
38+
omp.parallel {
39+
%24 = llvm.load %arg2 : !llvm.ptr -> i32
40+
%25 = llvm.add %24, %22 : i32
41+
omp.wsloop private(@_QFEi_private_i32 %arg1 -> %arg4 : !llvm.ptr) {
42+
omp.loop_nest (%arg5) : i32 = (%24) to (%25) inclusive step (%23) {
43+
llvm.store %arg5, %arg4 : i32, !llvm.ptr
44+
omp.yield
45+
}
46+
}
47+
omp.terminator
48+
}
49+
omp.terminator
50+
}
51+
omp.terminator
52+
}
53+
llvm.return
54+
}
55+
llvm.mlir.global internal constant @_QFECchunksz() {addr_space = 0 : i32} : i32 {
56+
%0 = llvm.mlir.constant(10000 : i32) : i32
57+
llvm.return %0 : i32
58+
}
59+
llvm.mlir.global internal constant @_QFECn() {addr_space = 0 : i32} : i32 {
60+
%0 = llvm.mlir.constant(100000 : i32) : i32
61+
llvm.return %0 : i32
62+
}

0 commit comments

Comments
 (0)