#include "clang/AST/ASTContext.h"
#include "clang/AST/Attr.h"
#include "clang/AST/Expr.h"
+#include "clang/Basic/CodeGenOptions.h"
#include "llvm/IR/BasicBlock.h"
#include "llvm/IR/CFG.h"
#include "llvm/IR/Constants.h"
}
void LoopInfoStack::push(BasicBlock *Header, clang::ASTContext &Ctx,
+ const clang::CodeGenOptions &CGOpts,
ArrayRef<const clang::Attr *> Attrs,
const llvm::DebugLoc &StartLoc,
const llvm::DebugLoc &EndLoc) {
}
}
+ if (CGOpts.OptimizationLevel > 0)
+ // Disable unrolling for the loop, if unrolling is disabled (via
+ // -fno-unroll-loops) and no pragmas override the decision.
+ if (!CGOpts.UnrollLoops &&
+ (StagedAttrs.UnrollEnable == LoopAttributes::Unspecified &&
+ StagedAttrs.UnrollCount == 0))
+ setUnrollState(LoopAttributes::Disable);
+
/// Stage the attributes.
push(Header, StartLoc, EndLoc);
}
namespace clang {
class Attr;
class ASTContext;
+class CodeGenOptions;
namespace CodeGen {
/// Attributes that may be specified on loops.
/// Begin a new structured loop. Stage attributes from the Attrs list.
/// The staged attributes are applied to the loop and then cleared.
void push(llvm::BasicBlock *Header, clang::ASTContext &Ctx,
+ const clang::CodeGenOptions &CGOpts,
llvm::ArrayRef<const Attr *> Attrs, const llvm::DebugLoc &StartLoc,
const llvm::DebugLoc &EndLoc);
EmitBlock(LoopHeader.getBlock());
const SourceRange &R = S.getSourceRange();
- LoopStack.push(LoopHeader.getBlock(), CGM.getContext(), WhileAttrs,
- SourceLocToDebugLoc(R.getBegin()),
+ LoopStack.push(LoopHeader.getBlock(), CGM.getContext(), CGM.getCodeGenOpts(),
+ WhileAttrs, SourceLocToDebugLoc(R.getBegin()),
SourceLocToDebugLoc(R.getEnd()));
// Create an exit block for when the condition fails, which will
EmitBlock(LoopCond.getBlock());
const SourceRange &R = S.getSourceRange();
- LoopStack.push(LoopBody, CGM.getContext(), DoAttrs,
+ LoopStack.push(LoopBody, CGM.getContext(), CGM.getCodeGenOpts(), DoAttrs,
SourceLocToDebugLoc(R.getBegin()),
SourceLocToDebugLoc(R.getEnd()));
EmitBlock(CondBlock);
const SourceRange &R = S.getSourceRange();
- LoopStack.push(CondBlock, CGM.getContext(), ForAttrs,
+ LoopStack.push(CondBlock, CGM.getContext(), CGM.getCodeGenOpts(), ForAttrs,
SourceLocToDebugLoc(R.getBegin()),
SourceLocToDebugLoc(R.getEnd()));
EmitBlock(CondBlock);
const SourceRange &R = S.getSourceRange();
- LoopStack.push(CondBlock, CGM.getContext(), ForAttrs,
+ LoopStack.push(CondBlock, CGM.getContext(), CGM.getCodeGenOpts(), ForAttrs,
SourceLocToDebugLoc(R.getBegin()),
SourceLocToDebugLoc(R.getEnd()));
--- /dev/null
+// RUN: %clang_cc1 -triple x86_64-apple-darwin -std=c++11 -emit-llvm -o - %s -O0 -disable-llvm-optzns -fno-unroll-loops | FileCheck --check-prefix=NO_UNROLL_MD %s
+// RUN: %clang_cc1 -triple x86_64-apple-darwin -std=c++11 -emit-llvm -o - %s -O1 -disable-llvm-optzns -fno-unroll-loops | FileCheck --check-prefix=UNROLL_DISABLED_MD %s
+// RUN: %clang_cc1 -triple x86_64-apple-darwin -std=c++11 -emit-llvm -o - %s -O2 -disable-llvm-optzns -fno-unroll-loops | FileCheck --check-prefix=UNROLL_DISABLED_MD %s
+// RUN: %clang_cc1 -triple x86_64-apple-darwin -std=c++11 -emit-llvm -o - %s -O3 -disable-llvm-optzns -fno-unroll-loops | FileCheck --check-prefix=UNROLL_DISABLED_MD %s
+// RUN: %clang_cc1 -triple x86_64-apple-darwin -std=c++11 -emit-llvm -o - %s -O3 -disable-llvm-optzns | FileCheck --check-prefix=NO_UNROLL_MD %s
+
+// NO_UNROLL_MD-NOT: llvm.loop
+
+// Verify unroll.disable metadata is added to while loop with -fno-unroll-loops
+// and optlevel > 0.
+void while_test(int *List, int Length) {
+ // UNROLL_DISABLED_MD: define {{.*}} @_Z10while_test
+ int i = 0;
+
+ while (i < Length) {
+ // UNROLL_DISABLED_MD: br label {{.*}}, !llvm.loop ![[LOOP_1:.*]]
+ List[i] = i * 2;
+ i++;
+ }
+}
+
+// Verify unroll.disable metadata is added to do-while loop with
+// -fno-unroll-loops and optlevel > 0.
+void do_test(int *List, int Length) {
+ // UNROLL_DISABLED_MD: define {{.*}} @_Z7do_test
+ int i = 0;
+
+ do {
+ // UNROLL_DISABLED_MD: br i1 {{.*}}, label {{.*}}, label {{.*}}, !llvm.loop ![[LOOP_2:.*]]
+ List[i] = i * 2;
+ i++;
+ } while (i < Length);
+}
+
+// Verify unroll.disable metadata is added to while loop with -fno-unroll-loops
+// and optlevel > 0.
+void for_test(int *List, int Length) {
+ // UNROLL_DISABLED_MD: define {{.*}} @_Z8for_test
+ for (int i = 0; i < Length; i++) {
+ // UNROLL_DISABLED_MD: br label {{.*}}, !llvm.loop ![[LOOP_3:.*]]
+ List[i] = i * 2;
+ }
+}
+
+// UNROLL_DISABLED_MD: ![[LOOP_1]] = distinct !{![[LOOP_1]], ![[UNROLL_DISABLE:.*]]}
+// UNROLL_DISABLED_MD: ![[UNROLL_DISABLE]] = !{!"llvm.loop.unroll.disable"}
+// UNROLL_DISABLED_MD: ![[LOOP_2]] = distinct !{![[LOOP_2:.*]], ![[UNROLL_DISABLE:.*]]}
+// UNROLL_DISABLED_MD: ![[LOOP_3]] = distinct !{![[LOOP_3]], ![[UNROLL_DISABLE:.*]]}
// RUN: %clang_cc1 -triple x86_64-apple-darwin -std=c++11 -emit-llvm -o - %s | FileCheck %s
+// Check that passing -fno-unroll-loops does not impact the decision made using pragmas.
+// RUN: %clang_cc1 -triple x86_64-apple-darwin -std=c++11 -emit-llvm -o - -O1 -disable-llvm-optzns -fno-unroll-loops %s | FileCheck %s
+
// Verify while loop is recognized after unroll pragma.
void while_test(int *List, int Length) {
// CHECK: define {{.*}} @_Z10while_test