Skip to content

Commit 3425b1b

Browse files
committed
[mlir][OpenMP] omp.sections and omp.section lowering to LLVM IR
This patch adds lowering from omp.sections and omp.section (simple lowering along with the nowait clause) to LLVM IR. Tests for the same are also added. Reviewed By: ftynse, kiranchandramohan Differential Revision: https://reviews.llvm.org/D115030
1 parent 5298333 commit 3425b1b

File tree

4 files changed

+245
-1
lines changed

4 files changed

+245
-1
lines changed

llvm/lib/Frontend/OpenMP/OMPIRBuilder.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -996,7 +996,7 @@ OpenMPIRBuilder::InsertPointTy OpenMPIRBuilder::createSections(
996996
Builder.SetInsertPoint(AllocaIP.getBlock()->getTerminator());
997997
AllocaIP = Builder.saveIP();
998998
InsertPointTy AfterIP =
999-
applyStaticWorkshareLoop(Loc.DL, LoopInfo, AllocaIP, true);
999+
applyStaticWorkshareLoop(Loc.DL, LoopInfo, AllocaIP, !IsNowait);
10001000
BasicBlock *LoopAfterBB = AfterIP.getBlock();
10011001
Instruction *SplitPos = LoopAfterBB->getTerminator();
10021002
if (!isa_and_nonnull<BranchInst>(SplitPos))

llvm/unittests/Frontend/OpenMPIRBuilderTest.cpp

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3637,6 +3637,34 @@ TEST_F(OpenMPIRBuilderTest, CreateSections) {
36373637
EXPECT_FALSE(verifyModule(*M, &errs()));
36383638
}
36393639

3640+
TEST_F(OpenMPIRBuilderTest, CreateSectionsNoWait) {
3641+
using InsertPointTy = OpenMPIRBuilder::InsertPointTy;
3642+
using BodyGenCallbackTy = llvm::OpenMPIRBuilder::StorableBodyGenCallbackTy;
3643+
OpenMPIRBuilder OMPBuilder(*M);
3644+
OMPBuilder.initialize();
3645+
F->setName("func");
3646+
IRBuilder<> Builder(BB);
3647+
3648+
OpenMPIRBuilder::LocationDescription Loc({Builder.saveIP(), DL});
3649+
IRBuilder<>::InsertPoint AllocaIP(&F->getEntryBlock(),
3650+
F->getEntryBlock().getFirstInsertionPt());
3651+
llvm::SmallVector<BodyGenCallbackTy, 4> SectionCBVector;
3652+
auto PrivCB = [](InsertPointTy AllocaIP, InsertPointTy CodeGenIP,
3653+
llvm::Value &, llvm::Value &Val,
3654+
llvm::Value *&ReplVal) { return CodeGenIP; };
3655+
auto FiniCB = [&](InsertPointTy IP) {};
3656+
3657+
Builder.restoreIP(OMPBuilder.createSections(Loc, AllocaIP, SectionCBVector,
3658+
PrivCB, FiniCB, false, true));
3659+
Builder.CreateRetVoid(); // Required at the end of the function
3660+
for (auto &Inst : instructions(*F)) {
3661+
EXPECT_FALSE(isa<CallInst>(Inst) &&
3662+
cast<CallInst>(&Inst)->getCalledFunction()->getName() ==
3663+
"__kmpc_barrier" &&
3664+
"call to function __kmpc_barrier found with nowait");
3665+
}
3666+
}
3667+
36403668
TEST_F(OpenMPIRBuilderTest, CreateOffloadMaptypes) {
36413669
OpenMPIRBuilder OMPBuilder(*M);
36423670
OMPBuilder.initialize();

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

Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -547,6 +547,77 @@ convertOmpOrderedRegion(Operation &opInst, llvm::IRBuilderBase &builder,
547547
return bodyGenStatus;
548548
}
549549

550+
static LogicalResult
551+
convertOmpSections(Operation &opInst, llvm::IRBuilderBase &builder,
552+
LLVM::ModuleTranslation &moduleTranslation) {
553+
using InsertPointTy = llvm::OpenMPIRBuilder::InsertPointTy;
554+
using StorableBodyGenCallbackTy =
555+
llvm::OpenMPIRBuilder::StorableBodyGenCallbackTy;
556+
557+
auto sectionsOp = cast<omp::SectionsOp>(opInst);
558+
559+
// TODO: Support the following clauses: private, firstprivate, lastprivate,
560+
// reduction, allocate
561+
if (!sectionsOp.private_vars().empty() ||
562+
!sectionsOp.firstprivate_vars().empty() ||
563+
!sectionsOp.lastprivate_vars().empty() ||
564+
!sectionsOp.reduction_vars().empty() || sectionsOp.reductions() ||
565+
!sectionsOp.allocate_vars().empty() ||
566+
!sectionsOp.allocators_vars().empty())
567+
return emitError(sectionsOp.getLoc())
568+
<< "private, firstprivate, lastprivate, reduction and allocate "
569+
"clauses are not supported for sections construct";
570+
571+
LogicalResult bodyGenStatus = success();
572+
SmallVector<StorableBodyGenCallbackTy> sectionCBs;
573+
574+
for (Operation &op : *sectionsOp.region().begin()) {
575+
auto sectionOp = dyn_cast<omp::SectionOp>(op);
576+
if (!sectionOp) // omp.terminator
577+
continue;
578+
579+
Region &region = sectionOp.region();
580+
auto sectionCB = [&region, &builder, &moduleTranslation, &bodyGenStatus](
581+
InsertPointTy allocaIP, InsertPointTy codeGenIP,
582+
llvm::BasicBlock &finiBB) {
583+
builder.restoreIP(codeGenIP);
584+
builder.CreateBr(&finiBB);
585+
convertOmpOpRegions(region, "omp.section.region", *codeGenIP.getBlock(),
586+
finiBB, builder, moduleTranslation, bodyGenStatus);
587+
};
588+
sectionCBs.push_back(sectionCB);
589+
}
590+
591+
// No sections within omp.sections operation - skip generation. This situation
592+
// is only possible if there is only a terminator operation inside the
593+
// sections operation
594+
if (sectionCBs.size() == 0)
595+
return success();
596+
597+
assert(isa<omp::SectionOp>(*sectionsOp.region().op_begin()));
598+
599+
// TODO: Perform appropriate actions according to the data-sharing
600+
// attribute (shared, private, firstprivate, ...) of variables.
601+
// Currently defaults to shared.
602+
auto privCB = [&](InsertPointTy, InsertPointTy codeGenIP, llvm::Value &,
603+
llvm::Value &vPtr,
604+
llvm::Value *&replacementValue) -> InsertPointTy {
605+
replacementValue = &vPtr;
606+
return codeGenIP;
607+
};
608+
609+
// TODO: Perform finalization actions for variables. This has to be
610+
// called for variables which have destructors/finalizers.
611+
auto finiCB = [&](InsertPointTy codeGenIP) {};
612+
613+
llvm::OpenMPIRBuilder::LocationDescription ompLoc(
614+
builder.saveIP(), builder.getCurrentDebugLocation());
615+
builder.restoreIP(moduleTranslation.getOpenMPBuilder()->createSections(
616+
ompLoc, findAllocaInsertPoint(builder, moduleTranslation), sectionCBs,
617+
privCB, finiCB, false, sectionsOp.nowait()));
618+
return bodyGenStatus;
619+
}
620+
550621
/// Converts an OpenMP workshare loop into LLVM IR using OpenMPIRBuilder.
551622
static LogicalResult
552623
convertOmpWsLoop(Operation &opInst, llvm::IRBuilderBase &builder,
@@ -962,6 +1033,9 @@ LogicalResult OpenMPDialectLLVMIRTranslationInterface::convertOperation(
9621033
.Case([&](omp::AtomicReadOp) {
9631034
return convertOmpAtomicRead(*op, builder, moduleTranslation);
9641035
})
1036+
.Case([&](omp::SectionsOp) {
1037+
return convertOmpSections(*op, builder, moduleTranslation);
1038+
})
9651039
.Case<omp::YieldOp, omp::TerminatorOp, omp::ReductionDeclareOp,
9661040
omp::CriticalDeclareOp>([](auto op) {
9671041
// `yield` and `terminator` can be just omitted. The block structure

mlir/test/Target/LLVMIR/openmp-llvm.mlir

Lines changed: 142 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -736,3 +736,145 @@ llvm.func @omp_atomic_read(%arg0 : !llvm.ptr<i32>) -> () {
736736
%x4 = omp.atomic.read %arg0 memory_order(relaxed) : !llvm.ptr<i32> -> i32
737737
llvm.return
738738
}
739+
740+
// -----
741+
742+
// CHECK-LABEL: @omp_sections_empty
743+
llvm.func @omp_sections_empty() -> () {
744+
omp.sections {
745+
omp.terminator
746+
}
747+
// CHECK-NEXT: ret void
748+
llvm.return
749+
}
750+
751+
// -----
752+
753+
// Check IR generation for simple empty sections. This only checks the overall
754+
// shape of the IR, detailed checking is done by the OpenMPIRBuilder.
755+
756+
// CHECK-LABEL: @omp_sections_trivial
757+
llvm.func @omp_sections_trivial() -> () {
758+
// CHECK: br label %[[PREHEADER:.*]]
759+
760+
// CHECK: [[PREHEADER]]:
761+
// CHECK: %{{.*}} = call i32 @__kmpc_global_thread_num({{.*}})
762+
// CHECK: call void @__kmpc_for_static_init_4u({{.*}})
763+
// CHECK: br label %[[HEADER:.*]]
764+
765+
// CHECK: [[HEADER]]:
766+
// CHECK: br label %[[COND:.*]]
767+
768+
// CHECK: [[COND]]:
769+
// CHECK: br i1 %{{.*}}, label %[[BODY:.*]], label %[[EXIT:.*]]
770+
// CHECK: [[BODY]]:
771+
// CHECK: switch i32 %{{.*}}, label %[[INC:.*]] [
772+
// CHECK-NEXT: i32 0, label %[[SECTION1:.*]]
773+
// CHECK-NEXT: i32 1, label %[[SECTION2:.*]]
774+
// CHECK-NEXT: ]
775+
776+
// CHECK: [[INC]]:
777+
// CHECK: %{{.*}} = add {{.*}}, 1
778+
// CHECK: br label %[[HEADER]]
779+
780+
// CHECK: [[EXIT]]:
781+
// CHECK: call void @__kmpc_for_static_fini({{.*}})
782+
// CHECK: call void @__kmpc_barrier({{.*}})
783+
// CHECK: br label %[[AFTER:.*]]
784+
785+
// CHECK: [[AFTER]]:
786+
// CHECK: br label %[[END:.*]]
787+
788+
// CHECK: [[END]]:
789+
// CHECK: ret void
790+
omp.sections {
791+
omp.section {
792+
// CHECK: [[SECTION1]]:
793+
// CHECK-NEXT: br label %[[REGION1:[^ ,]*]]
794+
// CHECK: [[REGION1]]:
795+
// CHECK-NEXT: br label %[[EXIT]]
796+
omp.terminator
797+
}
798+
omp.section {
799+
// CHECK: [[SECTION2]]:
800+
// CHECK-NEXT: br label %[[REGION2:[^ ,]*]]
801+
// CHECK: [[REGION2]]:
802+
// CHECK-NEXT: br label %[[EXIT]]
803+
omp.terminator
804+
}
805+
omp.terminator
806+
}
807+
llvm.return
808+
}
809+
810+
// -----
811+
812+
// CHECK: declare void @foo()
813+
llvm.func @foo()
814+
815+
// CHECK: declare void @bar(i32)
816+
llvm.func @bar(%arg0 : i32)
817+
818+
// CHECK-LABEL: @omp_sections
819+
llvm.func @omp_sections(%arg0 : i32, %arg1 : i32, %arg2 : !llvm.ptr<i32>) -> () {
820+
821+
// CHECK: switch i32 %{{.*}}, label %{{.*}} [
822+
// CHECK-NEXT: i32 0, label %[[SECTION1:.*]]
823+
// CHECK-NEXT: i32 1, label %[[SECTION2:.*]]
824+
// CHECK-NEXT: i32 2, label %[[SECTION3:.*]]
825+
// CHECK-NEXT: ]
826+
omp.sections {
827+
omp.section {
828+
// CHECK: [[SECTION1]]:
829+
// CHECK: br label %[[REGION1:[^ ,]*]]
830+
// CHECK: [[REGION1]]:
831+
// CHECK: call void @foo()
832+
// CHECK: br label %{{.*}}
833+
llvm.call @foo() : () -> ()
834+
omp.terminator
835+
}
836+
omp.section {
837+
// CHECK: [[SECTION2]]:
838+
// CHECK: br label %[[REGION2:[^ ,]*]]
839+
// CHECK: [[REGION2]]:
840+
// CHECK: call void @bar(i32 %{{.*}})
841+
// CHECK: br label %{{.*}}
842+
llvm.call @bar(%arg0) : (i32) -> ()
843+
omp.terminator
844+
}
845+
omp.section {
846+
// CHECK: [[SECTION3]]:
847+
// CHECK: br label %[[REGION3:[^ ,]*]]
848+
// CHECK: [[REGION3]]:
849+
// CHECK: %11 = add i32 %{{.*}}, %{{.*}}
850+
%add = llvm.add %arg0, %arg1 : i32
851+
// CHECK: store i32 %{{.*}}, i32* %{{.*}}, align 4
852+
// CHECK: br label %{{.*}}
853+
llvm.store %add, %arg2 : !llvm.ptr<i32>
854+
omp.terminator
855+
}
856+
omp.terminator
857+
}
858+
llvm.return
859+
}
860+
861+
// -----
862+
863+
llvm.func @foo()
864+
865+
// CHECK-LABEL: @omp_sections_with_clauses
866+
llvm.func @omp_sections_with_clauses() -> () {
867+
// CHECK-NOT: call void @__kmpc_barrier
868+
omp.sections nowait {
869+
omp.section {
870+
llvm.call @foo() : () -> ()
871+
omp.terminator
872+
}
873+
omp.section {
874+
llvm.call @foo() : () -> ()
875+
omp.terminator
876+
}
877+
omp.terminator
878+
}
879+
llvm.return
880+
}

0 commit comments

Comments
 (0)