diff --git a/mlir/include/mlir/Target/LLVMIR/ModuleTranslation.h b/mlir/include/mlir/Target/LLVMIR/ModuleTranslation.h --- a/mlir/include/mlir/Target/LLVMIR/ModuleTranslation.h +++ b/mlir/include/mlir/Target/LLVMIR/ModuleTranslation.h @@ -91,7 +91,15 @@ llvm::IRBuilder<> &builder); virtual LogicalResult convertOmpParallel(Operation &op, llvm::IRBuilder<> &builder); - + virtual LogicalResult convertOmpMaster(Operation &op, + llvm::IRBuilder<> &builder); + void convertOmpOpRegions(Region ®ion, + DenseMap &valueMapping, + DenseMap &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); diff --git a/mlir/lib/Target/LLVMIR/ModuleTranslation.cpp b/mlir/lib/Target/LLVMIR/ModuleTranslation.cpp --- a/mlir/lib/Target/LLVMIR/ModuleTranslation.cpp +++ b/mlir/lib/Target/LLVMIR/ModuleTranslation.cpp @@ -385,6 +385,9 @@ 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 @@ blockMapping[&bb] = llvmBB; } - // Then, convert blocks one by one in topological order to ensure - // defs are converted before uses. - llvm::SetVector 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 @@ // 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 ®ion, DenseMap &valueMapping, + DenseMap &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 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 ®ion = cast(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 @@ }) .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(); diff --git a/mlir/test/Target/openmp-llvm.mlir b/mlir/test/Target/openmp-llvm.mlir --- a/mlir/test/Target/openmp-llvm.mlir +++ b/mlir/test/Target/openmp-llvm.mlir @@ -264,3 +264,30 @@ } 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 +}