Commit dd822f5b authored by Alexey Bataev's avatar Alexey Bataev
Browse files

Merging r287227:

------------------------------------------------------------------------
r287227 | abataev | 2016-11-17 15:12:05 +0000 (Thu, 17 Nov 2016) | 4 lines

[OPENMP] Fixed codegen for 'omp cancel' construct.

If 'omp cancel' construct is used in a worksharing construct it may
cause hanging of the software in case if reduction clause is used. Patch fixes this problem by avoiding extra reduction processing for branches that were canceled.
------------------------------------------------------------------------

llvm-svn: 288048
parent 88f283a1
Loading
Loading
Loading
Loading
+19 −31
Original line number Diff line number Diff line
@@ -1767,17 +1767,11 @@ void CodeGenFunction::EmitOMPOuterLoop(bool DynamicOrOrdered, bool IsMonotonic,
  EmitBlock(LoopExit.getBlock());

  // Tell the runtime we are done.
  SourceLocation ELoc = S.getLocEnd();
  auto &&CodeGen = [DynamicOrOrdered, ELoc](CodeGenFunction &CGF) {
  auto &&CodeGen = [DynamicOrOrdered, &S](CodeGenFunction &CGF) {
    if (!DynamicOrOrdered)
      CGF.CGM.getOpenMPRuntime().emitForStaticFinish(CGF, ELoc);
      CGF.CGM.getOpenMPRuntime().emitForStaticFinish(CGF, S.getLocEnd());
  };
  CodeGen(*this);

  OpenMPDirectiveKind DKind = S.getDirectiveKind();
  if (DKind == OMPD_for || DKind == OMPD_parallel_for ||
      DKind == OMPD_distribute_parallel_for)
    OMPCancelStack.back().CodeGen = CodeGen;
  OMPCancelStack.emitExit(*this, S.getDirectiveKind(), CodeGen);
}

void CodeGenFunction::EmitOMPForOuterLoop(
@@ -1889,11 +1883,12 @@ void CodeGenFunction::EmitOMPDistributeOuterLoop(
void CodeGenFunction::EmitOMPDistributeParallelForDirective(
    const OMPDistributeParallelForDirective &S) {
  OMPLexicalScope Scope(*this, S, /*AsInlined=*/true);
  OMPCancelStackRAII CancelRegion(*this);
  CGM.getOpenMPRuntime().emitInlinedDirective(
      *this, OMPD_distribute_parallel_for,
      [&S](CodeGenFunction &CGF, PrePostActionTy &) {
        OMPLoopScope PreInitScope(CGF, S);
        OMPCancelStackRAII CancelRegion(CGF, OMPD_distribute_parallel_for,
                                        /*HasCancel=*/false);
        CGF.EmitStmt(
            cast<CapturedStmt>(S.getAssociatedStmt())->getCapturedStmt());
      });
@@ -2082,15 +2077,10 @@ bool CodeGenFunction::EmitOMPWorksharingLoop(const OMPLoopDirective &S) {
                         [](CodeGenFunction &) {});
        EmitBlock(LoopExit.getBlock());
        // Tell the runtime we are done.
        SourceLocation ELoc = S.getLocEnd();
        auto &&CodeGen = [ELoc](CodeGenFunction &CGF) {
          CGF.CGM.getOpenMPRuntime().emitForStaticFinish(CGF, ELoc);
        auto &&CodeGen = [&S](CodeGenFunction &CGF) {
          CGF.CGM.getOpenMPRuntime().emitForStaticFinish(CGF, S.getLocEnd());
        };
        CodeGen(*this);
        OpenMPDirectiveKind DKind = S.getDirectiveKind();
        if (DKind == OMPD_for || DKind == OMPD_parallel_for ||
            DKind == OMPD_distribute_parallel_for)
          OMPCancelStack.back().CodeGen = CodeGen;
        OMPCancelStack.emitExit(*this, S.getDirectiveKind(), CodeGen);
      } else {
        const bool IsMonotonic =
            Ordered || ScheduleKind.Schedule == OMPC_SCHEDULE_static ||
@@ -2140,11 +2130,11 @@ void CodeGenFunction::EmitOMPForDirective(const OMPForDirective &S) {
  bool HasLastprivates = false;
  auto &&CodeGen = [&S, &HasLastprivates](CodeGenFunction &CGF,
                                          PrePostActionTy &) {
    OMPCancelStackRAII CancelRegion(CGF, OMPD_for, S.hasCancel());
    HasLastprivates = CGF.EmitOMPWorksharingLoop(S);
  };
  {
    OMPLexicalScope Scope(*this, S, /*AsInlined=*/true);
    OMPCancelStackRAII CancelRegion(*this);
    CGM.getOpenMPRuntime().emitInlinedDirective(*this, OMPD_for, CodeGen,
                                                S.hasCancel());
  }
@@ -2187,7 +2177,6 @@ void CodeGenFunction::EmitSections(const OMPExecutableDirective &S) {
  bool HasLastprivates = false;
  auto &&CodeGen = [&S, Stmt, CS, &HasLastprivates](CodeGenFunction &CGF,
                                                    PrePostActionTy &) {
    OMPCancelStackRAII CancelRegion(CGF);
    auto &C = CGF.CGM.getContext();
    auto KmpInt32Ty = C.getIntTypeForBitwidth(/*DestWidth=*/32, /*Signed=*/1);
    // Emit helper vars inits.
@@ -2282,12 +2271,10 @@ void CodeGenFunction::EmitSections(const OMPExecutableDirective &S) {
    CGF.EmitOMPInnerLoop(S, /*RequiresCleanup=*/false, &Cond, &Inc, BodyGen,
                         [](CodeGenFunction &) {});
    // Tell the runtime we are done.
    SourceLocation ELoc = S.getLocEnd();
    auto &&FinalCodeGen = [ELoc](CodeGenFunction &CGF) {
      CGF.CGM.getOpenMPRuntime().emitForStaticFinish(CGF, ELoc);
    auto &&CodeGen = [&S](CodeGenFunction &CGF) {
      CGF.CGM.getOpenMPRuntime().emitForStaticFinish(CGF, S.getLocEnd());
    };
    FinalCodeGen(CGF);
    CGF.OMPCancelStack.back().CodeGen = FinalCodeGen;
    CGF.OMPCancelStack.emitExit(CGF, S.getDirectiveKind(), CodeGen);
    CGF.EmitOMPReductionClauseFinal(S);
    // Emit post-update of the reduction variables if IsLastIter != 0.
    emitPostUpdateForReductionClause(
@@ -2309,6 +2296,7 @@ void CodeGenFunction::EmitSections(const OMPExecutableDirective &S) {
    HasCancel = OSD->hasCancel();
  else if (auto *OPSD = dyn_cast<OMPParallelSectionsDirective>(&S))
    HasCancel = OPSD->hasCancel();
  OMPCancelStackRAII CancelRegion(*this, S.getDirectiveKind(), HasCancel);
  CGM.getOpenMPRuntime().emitInlinedDirective(*this, OMPD_sections, CodeGen,
                                              HasCancel);
  // Emit barrier for lastprivates only if 'sections' directive has 'nowait'
@@ -2412,7 +2400,7 @@ void CodeGenFunction::EmitOMPParallelForDirective(
  // Emit directive as a combined directive that consists of two implicit
  // directives: 'parallel' with 'for' directive.
  auto &&CodeGen = [&S](CodeGenFunction &CGF, PrePostActionTy &) {
    OMPCancelStackRAII CancelRegion(CGF);
    OMPCancelStackRAII CancelRegion(CGF, OMPD_parallel_for, S.hasCancel());
    CGF.EmitOMPWorksharingLoop(S);
  };
  emitCommonOMPParallelDirective(*this, S, OMPD_for, CodeGen);
@@ -3412,14 +3400,14 @@ void CodeGenFunction::EmitOMPCancelDirective(const OMPCancelDirective &S) {

CodeGenFunction::JumpDest
CodeGenFunction::getOMPCancelDestination(OpenMPDirectiveKind Kind) {
  if (Kind == OMPD_parallel || Kind == OMPD_task)
  if (Kind == OMPD_parallel || Kind == OMPD_task ||
      Kind == OMPD_target_parallel)
    return ReturnBlock;
  assert(Kind == OMPD_for || Kind == OMPD_section || Kind == OMPD_sections ||
         Kind == OMPD_parallel_sections || Kind == OMPD_parallel_for ||
         Kind == OMPD_distribute_parallel_for);
  if (!OMPCancelStack.back().ExitBlock.isValid())
    OMPCancelStack.back().ExitBlock = getJumpDestInCurrentScope("cancel.exit");
  return OMPCancelStack.back().ExitBlock;
         Kind == OMPD_distribute_parallel_for ||
         Kind == OMPD_target_parallel_for);
  return OMPCancelStack.getExitBlock();
}

// Generate the instructions for '#pragma omp target data' directive.
+78 −19
Original line number Diff line number Diff line
@@ -965,33 +965,92 @@ private:
  };
  SmallVector<BreakContinue, 8> BreakContinueStack;

  /// Data for exit block for proper support of OpenMP cancellation constructs.
  struct OMPCancel {
  /// Handles cancellation exit points in OpenMP-related constructs.
  class OpenMPCancelExitStack {
    /// Tracks cancellation exit point and join point for cancel-related exit
    /// and normal exit.
    struct CancelExit {
      CancelExit() = default;
      CancelExit(OpenMPDirectiveKind Kind, JumpDest ExitBlock,
                 JumpDest ContBlock)
          : Kind(Kind), ExitBlock(ExitBlock), ContBlock(ContBlock) {}
      OpenMPDirectiveKind Kind = OMPD_unknown;
      /// true if the exit block has been emitted already by the special
      /// emitExit() call, false if the default codegen is used.
      bool HasBeenEmitted = false;
      JumpDest ExitBlock;
    llvm::function_ref<void(CodeGenFunction &CGF)> CodeGen;
    OMPCancel() : CodeGen([](CodeGenFunction &CGF) {}) {}
      JumpDest ContBlock;
    };
  SmallVector<OMPCancel, 8> OMPCancelStack;

    SmallVector<CancelExit, 8> Stack;

  public:
    OpenMPCancelExitStack() : Stack(1) {}
    ~OpenMPCancelExitStack() = default;
    /// Fetches the exit block for the current OpenMP construct.
    JumpDest getExitBlock() const { return Stack.back().ExitBlock; }
    /// Emits exit block with special codegen procedure specific for the related
    /// OpenMP construct + emits code for normal construct cleanup.
    void emitExit(CodeGenFunction &CGF, OpenMPDirectiveKind Kind,
                  const llvm::function_ref<void(CodeGenFunction &)> &CodeGen) {
      if (Stack.back().Kind == Kind && getExitBlock().isValid()) {
        assert(CGF.getOMPCancelDestination(Kind).isValid());
        assert(CGF.HaveInsertPoint());
        assert(!Stack.back().HasBeenEmitted);
        auto IP = CGF.Builder.saveAndClearIP();
        CGF.EmitBlock(Stack.back().ExitBlock.getBlock());
        CodeGen(CGF);
        CGF.EmitBranchThroughCleanup(Stack.back().ContBlock);
        CGF.Builder.restoreIP(IP);
        Stack.back().HasBeenEmitted = true;
      }
      CodeGen(CGF);
    }
    /// Enter the cancel supporting \a Kind construct.
    /// \param Kind OpenMP directive that supports cancel constructs.
    /// \param HasCancel true, if the construct has inner cancel directive,
    /// false otherwise.
    void enter(CodeGenFunction &CGF, OpenMPDirectiveKind Kind, bool HasCancel) {
      Stack.push_back({Kind,
                       HasCancel ? CGF.getJumpDestInCurrentScope("cancel.exit")
                                 : JumpDest(),
                       HasCancel ? CGF.getJumpDestInCurrentScope("cancel.cont")
                                 : JumpDest()});
    }
    /// Emits default exit point for the cancel construct (if the special one
    /// has not be used) + join point for cancel/normal exits.
    void exit(CodeGenFunction &CGF) {
      if (getExitBlock().isValid()) {
        assert(CGF.getOMPCancelDestination(Stack.back().Kind).isValid());
        bool HaveIP = CGF.HaveInsertPoint();
        if (!Stack.back().HasBeenEmitted) {
          if (HaveIP)
            CGF.EmitBranchThroughCleanup(Stack.back().ContBlock);
          CGF.EmitBlock(Stack.back().ExitBlock.getBlock());
          CGF.EmitBranchThroughCleanup(Stack.back().ContBlock);
        }
        CGF.EmitBlock(Stack.back().ContBlock.getBlock());
        if (!HaveIP) {
          CGF.Builder.CreateUnreachable();
          CGF.Builder.ClearInsertionPoint();
        }
      }
      Stack.pop_back();
    }
  };
  OpenMPCancelExitStack OMPCancelStack;

  /// Controls insertion of cancellation exit blocks in worksharing constructs.
  class OMPCancelStackRAII {
    CodeGenFunction &CGF;

  public:
    OMPCancelStackRAII(CodeGenFunction &CGF) : CGF(CGF) {
      CGF.OMPCancelStack.push_back({});
    }
    ~OMPCancelStackRAII() {
      if (CGF.HaveInsertPoint() &&
          CGF.OMPCancelStack.back().ExitBlock.isValid()) {
        auto CJD = CGF.getJumpDestInCurrentScope("cancel.cont");
        CGF.EmitBranchThroughCleanup(CJD);
        CGF.EmitBlock(CGF.OMPCancelStack.back().ExitBlock.getBlock());
        CGF.OMPCancelStack.back().CodeGen(CGF);
        CGF.EmitBranchThroughCleanup(CJD);
        CGF.EmitBlock(CJD.getBlock());
      }
    OMPCancelStackRAII(CodeGenFunction &CGF, OpenMPDirectiveKind Kind,
                       bool HasCancel)
        : CGF(CGF) {
      CGF.OMPCancelStack.enter(CGF, Kind, HasCancel);
    }
    ~OMPCancelStackRAII() { CGF.OMPCancelStack.exit(CGF); }
  };

  CodeGenPGO PGO;
+1 −1

File changed.

Contains only whitespace changes.