[MLIR,OpenMP] Added support for lowering MasterOp to LLVMIR

Some Ops in OMP dialect have regions associated with them i.e
`ParallelOp` `MasterOp`. Lowering of these regions involves interfacing
with `OMPIRBuilder` using callbacks, yet there still exist opportunities
for sharing common code in between.

This patch factors out common code into a separate function and adds
support for lowering `MasterOp` using that. Lowering of `ParallelOp` is
also modified appropriately.

Reviewed By: ftynse

Differential Revision: https://reviews.llvm.org/D87247
This commit is contained in:
Sourabh Singh Tomar 2020-10-20 14:23:00 +05:30
parent 5755522b5a
commit c11d868a39
3 changed files with 109 additions and 24 deletions

View File

@ -91,7 +91,15 @@ protected:
llvm::IRBuilder<> &builder);
virtual LogicalResult convertOmpParallel(Operation &op,
llvm::IRBuilder<> &builder);
virtual LogicalResult convertOmpMaster(Operation &op,
llvm::IRBuilder<> &builder);
void convertOmpOpRegions(Region &region,
DenseMap<Value, llvm::Value *> &valueMapping,
DenseMap<Block *, llvm::BasicBlock *> &blockMapping,
llvm::Instruction *codeGenIPBBTI,
llvm::BasicBlock &continuationIP,
llvm::IRBuilder<> &builder,
LogicalResult &bodyGenStatus);
/// Converts the type from MLIR LLVM dialect to LLVM.
llvm::Type *convertType(LLVMType type);

View File

@ -385,6 +385,9 @@ LogicalResult
ModuleTranslation::convertOmpParallel(Operation &opInst,
llvm::IRBuilder<> &builder) {
using InsertPointTy = llvm::OpenMPIRBuilder::InsertPointTy;
// TODO: support error propagation in OpenMPIRBuilder and use it instead of
// relying on captured variables.
LogicalResult bodyGenStatus = success();
auto bodyGenCB = [&](InsertPointTy allocaIP, InsertPointTy codeGenIP,
llvm::BasicBlock &continuationIP) {
@ -402,31 +405,10 @@ ModuleTranslation::convertOmpParallel(Operation &opInst,
blockMapping[&bb] = llvmBB;
}
// Then, convert blocks one by one in topological order to ensure
// defs are converted before uses.
llvm::SetVector<Block *> blocks = topologicalSort(region);
for (auto indexedBB : llvm::enumerate(blocks)) {
Block *bb = indexedBB.value();
llvm::BasicBlock *curLLVMBB = blockMapping[bb];
if (bb->isEntryBlock()) {
assert(codeGenIPBBTI->getNumSuccessors() == 1 &&
"OpenMPIRBuilder provided entry block has multiple successors");
assert(codeGenIPBBTI->getSuccessor(0) == &continuationIP &&
"ContinuationIP is not the successor of OpenMPIRBuilder "
"provided entry block");
codeGenIPBBTI->setSuccessor(0, curLLVMBB);
}
// TODO: Error not returned up the hierarchy
if (failed(convertBlock(*bb, /*ignoreArguments=*/indexedBB.index() == 0)))
return;
}
convertOmpOpRegions(region, valueMapping, blockMapping, codeGenIPBBTI,
continuationIP, builder, bodyGenStatus);
ompContinuationIPStack.pop_back();
// Finally, after all blocks have been traversed and values mapped,
// connect the PHI nodes to the results of preceding blocks.
connectPHINodes(region, valueMapping, blockMapping);
};
// TODO: Perform appropriate actions according to the data-sharing
@ -459,12 +441,79 @@ ModuleTranslation::convertOmpParallel(Operation &opInst,
// entry or the alloca insertion point as provided by the body callback
// above.
llvm::OpenMPIRBuilder::InsertPointTy allocaIP(builder.saveIP());
if (failed(bodyGenStatus))
return failure();
builder.restoreIP(
ompBuilder->createParallel(builder, allocaIP, bodyGenCB, privCB, finiCB,
ifCond, numThreads, pbKind, isCancellable));
return success();
}
void ModuleTranslation::convertOmpOpRegions(
Region &region, DenseMap<Value, llvm::Value *> &valueMapping,
DenseMap<Block *, llvm::BasicBlock *> &blockMapping,
llvm::Instruction *codeGenIPBBTI, llvm::BasicBlock &continuationIP,
llvm::IRBuilder<> &builder, LogicalResult &bodyGenStatus) {
// Convert blocks one by one in topological order to ensure
// defs are converted before uses.
llvm::SetVector<Block *> blocks = topologicalSort(region);
for (auto indexedBB : llvm::enumerate(blocks)) {
Block *bb = indexedBB.value();
llvm::BasicBlock *curLLVMBB = blockMapping[bb];
if (bb->isEntryBlock()) {
assert(codeGenIPBBTI->getNumSuccessors() == 1 &&
"OpenMPIRBuilder provided entry block has multiple successors");
assert(codeGenIPBBTI->getSuccessor(0) == &continuationIP &&
"ContinuationIP is not the successor of OpenMPIRBuilder "
"provided entry block");
codeGenIPBBTI->setSuccessor(0, curLLVMBB);
}
if (failed(convertBlock(*bb, /*ignoreArguments=*/indexedBB.index() == 0))) {
bodyGenStatus = failure();
return;
}
}
// Finally, after all blocks have been traversed and values mapped,
// connect the PHI nodes to the results of preceding blocks.
connectPHINodes(region, valueMapping, blockMapping);
}
LogicalResult ModuleTranslation::convertOmpMaster(Operation &opInst,
llvm::IRBuilder<> &builder) {
using InsertPointTy = llvm::OpenMPIRBuilder::InsertPointTy;
// TODO: support error propagation in OpenMPIRBuilder and use it instead of
// relying on captured variables.
LogicalResult bodyGenStatus = success();
auto bodyGenCB = [&](InsertPointTy allocaIP, InsertPointTy codeGenIP,
llvm::BasicBlock &continuationIP) {
llvm::LLVMContext &llvmContext = llvmModule->getContext();
llvm::BasicBlock *codeGenIPBB = codeGenIP.getBlock();
llvm::Instruction *codeGenIPBBTI = codeGenIPBB->getTerminator();
ompContinuationIPStack.push_back(&continuationIP);
// MasterOp has only `1` region associated with it.
auto &region = cast<omp::MasterOp>(opInst).getRegion();
for (auto &bb : region) {
auto *llvmBB = llvm::BasicBlock::Create(
llvmContext, "omp.master.region", codeGenIP.getBlock()->getParent());
blockMapping[&bb] = llvmBB;
}
convertOmpOpRegions(region, valueMapping, blockMapping, codeGenIPBBTI,
continuationIP, builder, bodyGenStatus);
ompContinuationIPStack.pop_back();
};
// TODO: Perform finalization actions for variables. This has to be
// called for variables which have destructors/finalizers.
auto finiCB = [&](InsertPointTy codeGenIP) {};
builder.restoreIP(ompBuilder->createMaster(builder, bodyGenCB, finiCB));
return success();
}
/// Given an OpenMP MLIR operation, create the corresponding LLVM IR
/// (including OpenMP runtime calls).
LogicalResult
@ -505,6 +554,7 @@ ModuleTranslation::convertOmpOperation(Operation &opInst,
})
.Case(
[&](omp::ParallelOp) { return convertOmpParallel(opInst, builder); })
.Case([&](omp::MasterOp) { return convertOmpMaster(opInst, builder); })
.Default([&](Operation *inst) {
return inst->emitError("unsupported OpenMP operation: ")
<< inst->getName();

View File

@ -264,3 +264,30 @@ llvm.func @test_omp_parallel_5() -> () {
}
llvm.return
}
// CHECK-LABEL: define void @test_omp_master()
llvm.func @test_omp_master() -> () {
// CHECK: call void {{.*}}@__kmpc_fork_call{{.*}} @{{.*}} to
// CHECK: omp.par.region1:
omp.parallel {
omp.master {
// CHECK: [[OMP_THREAD_3_4:%.*]] = call i32 @__kmpc_global_thread_num(%struct.ident_t* @{{[0-9]+}})
// CHECK: {{[0-9]+}} = call i32 @__kmpc_master(%struct.ident_t* @{{[0-9]+}}, i32 [[OMP_THREAD_3_4]])
// CHECK: omp.master.region
// CHECK: call void @__kmpc_end_master(%struct.ident_t* @{{[0-9]+}}, i32 [[OMP_THREAD_3_4]])
// CHECK: br label %omp_region.end
omp.terminator
}
omp.terminator
}
omp.parallel {
omp.parallel {
omp.master {
omp.terminator
}
omp.terminator
}
omp.terminator
}
llvm.return
}