-
Notifications
You must be signed in to change notification settings - Fork 16
Unstructured OpenMP code #1178
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Unstructured OpenMP code #1178
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -296,11 +296,11 @@ class PFTBuilder { | |
resetFunctionState(); | ||
} | ||
|
||
/// Initialize a new construct and make it the builder's focus. | ||
/// Initialize a new construct or directive and make it the builder's focus. | ||
template <typename A> | ||
bool enterConstructOrDirective(const A &construct) { | ||
auto &eval = | ||
addEvaluation(lower::pft::Evaluation{construct, pftParentStack.back()}); | ||
bool enterConstructOrDirective(const A &constructOrDirective) { | ||
auto &eval = addEvaluation( | ||
lower::pft::Evaluation{constructOrDirective, pftParentStack.back()}); | ||
eval.evaluationList.reset(new lower::pft::EvaluationList); | ||
pushEvaluationList(eval.evaluationList.get()); | ||
pftParentStack.emplace_back(eval); | ||
|
@@ -310,6 +310,17 @@ class PFTBuilder { | |
|
||
void exitConstructOrDirective() { | ||
rewriteIfGotos(); | ||
auto *eval = constructAndDirectiveStack.back(); | ||
if (eval->isExecutableDirective()) { | ||
// A construct at the end of an (unstructured) OpenACC or OpenMP | ||
// construct region must have an exit target inside the region. | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Is this the SS3 test? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This code is exercised by test subroutines ss2 and ss3. |
||
auto &evaluationList = *eval->evaluationList; | ||
if (!evaluationList.empty() && evaluationList.back().isConstruct()) { | ||
static const parser::ContinueStmt exitTarget{}; | ||
addEvaluation( | ||
lower::pft::Evaluation{exitTarget, pftParentStack.back(), {}, {}}); | ||
} | ||
} | ||
popEvaluationList(); | ||
pftParentStack.pop_back(); | ||
constructAndDirectiveStack.pop_back(); | ||
|
@@ -372,7 +383,8 @@ class PFTBuilder { | |
auto &entryPointList = eval.getOwningProcedure()->entryPointList; | ||
evaluationListStack.back()->emplace_back(std::move(eval)); | ||
lower::pft::Evaluation *p = &evaluationListStack.back()->back(); | ||
if (p->isActionStmt() || p->isConstructStmt() || p->isEndStmt()) { | ||
if (p->isActionStmt() || p->isConstructStmt() || p->isEndStmt() || | ||
p->isExecutableDirective()) { | ||
if (lastLexicalEvaluation) { | ||
lastLexicalEvaluation->lexicalSuccessor = p; | ||
p->printIndex = lastLexicalEvaluation->printIndex + 1; | ||
|
@@ -1017,33 +1029,32 @@ class PFTDumper { | |
const lower::pft::Evaluation &eval, | ||
const std::string &indentString, int indent = 1) { | ||
llvm::StringRef name = evaluationName(eval); | ||
std::string bang = eval.isUnstructured ? "!" : ""; | ||
if (eval.isConstruct() || eval.isDirective()) { | ||
outputStream << indentString << "<<" << name << bang << ">>"; | ||
if (eval.constructExit) | ||
outputStream << " -> " << eval.constructExit->printIndex; | ||
outputStream << '\n'; | ||
dumpEvaluationList(outputStream, *eval.evaluationList, indent + 1); | ||
outputStream << indentString << "<<End " << name << bang << ">>\n"; | ||
return; | ||
} | ||
llvm::StringRef newBlock = eval.isNewBlock ? "^" : ""; | ||
llvm::StringRef bang = eval.isUnstructured ? "!" : ""; | ||
outputStream << indentString; | ||
if (eval.printIndex) | ||
outputStream << eval.printIndex << ' '; | ||
if (eval.isNewBlock) | ||
outputStream << '^'; | ||
outputStream << name << bang; | ||
if (eval.isActionStmt() || eval.isConstructStmt()) { | ||
if (eval.negateCondition) | ||
outputStream << " [negate]"; | ||
if (eval.controlSuccessor) | ||
outputStream << " -> " << eval.controlSuccessor->printIndex; | ||
} else if (eval.isA<parser::EntryStmt>() && eval.lexicalSuccessor) { | ||
if (eval.hasNestedEvaluations()) | ||
outputStream << "<<" << newBlock << name << bang << ">>"; | ||
else | ||
outputStream << newBlock << name << bang; | ||
if (eval.negateCondition) | ||
outputStream << " [negate]"; | ||
if (eval.constructExit) | ||
outputStream << " -> " << eval.constructExit->printIndex; | ||
else if (eval.controlSuccessor) | ||
outputStream << " -> " << eval.controlSuccessor->printIndex; | ||
else if (eval.isA<parser::EntryStmt>() && eval.lexicalSuccessor) | ||
outputStream << " -> " << eval.lexicalSuccessor->printIndex; | ||
} | ||
if (!eval.position.empty()) | ||
outputStream << ": " << eval.position.ToString(); | ||
else if (auto *dir = eval.getIf<Fortran::parser::CompilerDirective>()) | ||
outputStream << ": !" << dir->source.ToString(); | ||
outputStream << '\n'; | ||
if (eval.hasNestedEvaluations()) { | ||
dumpEvaluationList(outputStream, *eval.evaluationList, indent + 1); | ||
outputStream << indentString << "<<End " << name << bang << ">>\n"; | ||
} | ||
} | ||
|
||
void dumpEvaluation(llvm::raw_ostream &ostream, | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,113 @@ | ||
! Test unstructured code adjacent to and inside OpenMP constructs. | ||
|
||
! RUN: bbc %s -fopenmp -o "-" | FileCheck %s | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Nit: A comment on what each of these test is testing might be helpful for future reference. Nit: It might also be good to have PFT tests for these cases like the one in 1077. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I've added comments for each test subroutine. Subroutine ss1 exercises the 1077 functionality. |
||
|
||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Nit: Suggestion for comment: Test that OpenMP constructs can be target of branches. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I've added a comment |
||
! CHECK-LABEL: func @_QPss1{{.*}} { | ||
! CHECK: br ^bb1 | ||
! CHECK: ^bb1: // 2 preds: ^bb0, ^bb3 | ||
! CHECK: cond_br %{{[0-9]*}}, ^bb2, ^bb4 | ||
! CHECK: ^bb2: // pred: ^bb1 | ||
! CHECK: cond_br %{{[0-9]*}}, ^bb4, ^bb3 | ||
! CHECK: ^bb3: // pred: ^bb2 | ||
! CHECK: @_FortranAioBeginExternalListOutput | ||
! CHECK: br ^bb1 | ||
! CHECK: ^bb4: // 2 preds: ^bb1, ^bb2 | ||
! CHECK: omp.master { | ||
! CHECK: @_FortranAioBeginExternalListOutput | ||
! CHECK: omp.terminator | ||
! CHECK: } | ||
! CHECK: @_FortranAioBeginExternalListOutput | ||
! CHECK: } | ||
subroutine ss1(n) ! unstructured code followed by a structured OpenMP construct | ||
do i = 1, 3 | ||
if (i .eq. n) exit | ||
print*, 'ss1-A', i | ||
enddo | ||
!$omp master | ||
print*, 'ss1-B', i | ||
!$omp end master | ||
print* | ||
end | ||
|
||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Nit: Suggestion for comment: Test unstructured code inside OpenMP construct. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I've added a comment |
||
! CHECK-LABEL: func @_QPss2{{.*}} { | ||
! CHECK: omp.master { | ||
! CHECK: @_FortranAioBeginExternalListOutput | ||
! CHECK: br ^bb1 | ||
! CHECK: ^bb1: // 2 preds: ^bb0, ^bb3 | ||
! CHECK: cond_br %{{[0-9]*}}, ^bb2, ^bb4 | ||
! CHECK: ^bb2: // pred: ^bb1 | ||
! CHECK: cond_br %{{[0-9]*}}, ^bb4, ^bb3 | ||
! CHECK: ^bb3: // pred: ^bb2 | ||
! CHECK: @_FortranAioBeginExternalListOutput | ||
! CHECK: br ^bb1 | ||
! CHECK: ^bb4: // 2 preds: ^bb1, ^bb2 | ||
! CHECK: omp.terminator | ||
! CHECK: } | ||
! CHECK: @_FortranAioBeginExternalListOutput | ||
! CHECK: @_FortranAioBeginExternalListOutput | ||
! CHECK: } | ||
subroutine ss2(n) ! unstructured OpenMP construct; loop exit inside construct | ||
!$omp master | ||
print*, 'ss2-A', n | ||
do i = 1, 3 | ||
if (i .eq. n) exit | ||
print*, 'ss2-B', i | ||
enddo | ||
!$omp end master | ||
print*, 'ss2-C', i | ||
print* | ||
end | ||
|
||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Nit: Suggestion for comment: Test unstructured code inside a do loop inside OpenMP do construct. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I've added a comment |
||
! CHECK-LABEL: func @_QPss3{{.*}} { | ||
! CHECK: omp.parallel { | ||
! CHECK: br ^bb1 | ||
! CHECK: ^bb1: // 2 preds: ^bb0, ^bb2 | ||
! CHECK: cond_br %{{[0-9]*}}, ^bb2, ^bb3 | ||
! CHECK: ^bb2: // pred: ^bb1 | ||
! CHECK: omp.wsloop {{.*}} { | ||
! CHECK: @_FortranAioBeginExternalListOutput | ||
! CHECK: omp.yield | ||
! CHECK: } | ||
! CHECK: omp.wsloop {{.*}} { | ||
! CHECK: br ^bb1 | ||
! CHECK: ^bb1: // 2 preds: ^bb0, ^bb3 | ||
! CHECK: cond_br %{{[0-9]*}}, ^bb2, ^bb4 | ||
! CHECK: ^bb2: // pred: ^bb1 | ||
! CHECK: cond_br %{{[0-9]*}}, ^bb4, ^bb3 | ||
! CHECK: ^bb3: // pred: ^bb2 | ||
! CHECK: @_FortranAioBeginExternalListOutput | ||
! CHECK: br ^bb1 | ||
! CHECK: ^bb4: // 2 preds: ^bb1, ^bb2 | ||
! CHECK: omp.yield | ||
! CHECK: } | ||
! CHECK: br ^bb1 | ||
! CHECK: ^bb3: // pred: ^bb1 | ||
! CHECK: omp.terminator | ||
! CHECK: } | ||
! CHECK: } | ||
subroutine ss3(n) ! nested unstructured OpenMP constructs | ||
!$omp parallel | ||
do i = 1, 3 | ||
!$omp do | ||
do k = 1, 3 | ||
print*, 'ss3-A', k | ||
enddo | ||
!$omp end do | ||
!$omp do | ||
do j = 1, 3 | ||
do k = 1, 3 | ||
if (k .eq. n) exit | ||
print*, 'ss3-B', k | ||
enddo | ||
enddo | ||
!$omp end do | ||
enddo | ||
!$omp end parallel | ||
end | ||
|
||
! CHECK-LABEL: func @_QQmain | ||
program p | ||
call ss1(2) | ||
call ss2(2) | ||
call ss3(2) | ||
end |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is this function called for each OpenMP construct/region?
I don't see it changing the current region. Will this work for nested OpenMP regions (where the outer and inner have unstructured code)?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It is intended to operate on the current region, as updated before the call in createBodyOfOp.