fhahn created this revision. fhahn added reviewers: Meinersbur, hfinkel, dexonsmith, tejohnson. Herald added a subscriber: zzheng. Herald added a project: clang.
Currently Clang does not respect -fno-unroll-loops during LTO. During D76916 <https://reviews.llvm.org/D76916> it was suggested to respect -fno-unroll-loops on a TU basis. This patch uses the existing llvm.loop.unroll.disable metadata to disable loop unrolling explicitly for each loop in the TU if unrolling is disabled. This should ensure that loops from TUs compiled with -fno-unroll-loops are skipped by the unroller during LTO. This also means that if a loop from a TU with -fno-unroll-loops gets inlined into a TU without this option, the loop won't be unrolled. Due to the fact that some transforms might drop loop metadata, there potentially are cases in which we still unroll loops from TUs with -fno-unroll-loops. I think we should fix those issues rather than introducing a function attribute to disable loop unrolling during LTO. Improving the metadata handling will benefit other use cases, like various loop pragmas, too. And it is an improvement to clang completely ignoring -fno-unroll-loops during LTO. If that direction looks good, we can use a similar approach to also respect -fno-vectorize during LTO, at least for LoopVectorize. In the future, this might also allow us to remove the UnrollLoops option LLVM's PassManagerBuilder. Repository: rG LLVM Github Monorepo https://reviews.llvm.org/D77058 Files: clang/lib/CodeGen/CGLoopInfo.cpp clang/lib/CodeGen/CGLoopInfo.h clang/lib/CodeGen/CGStmt.cpp clang/test/CodeGenCXX/fno-unroll-loops-metadata.cpp clang/test/CodeGenCXX/pragma-unroll.cpp
Index: clang/test/CodeGenCXX/pragma-unroll.cpp =================================================================== --- clang/test/CodeGenCXX/pragma-unroll.cpp +++ clang/test/CodeGenCXX/pragma-unroll.cpp @@ -1,5 +1,8 @@ // 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 Index: clang/test/CodeGenCXX/fno-unroll-loops-metadata.cpp =================================================================== --- /dev/null +++ clang/test/CodeGenCXX/fno-unroll-loops-metadata.cpp @@ -0,0 +1,48 @@ +// 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:.*]]} Index: clang/lib/CodeGen/CGStmt.cpp =================================================================== --- clang/lib/CodeGen/CGStmt.cpp +++ clang/lib/CodeGen/CGStmt.cpp @@ -728,8 +728,8 @@ 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 @@ -830,7 +830,7 @@ 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())); @@ -888,7 +888,7 @@ 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())); @@ -989,7 +989,7 @@ 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())); Index: clang/lib/CodeGen/CGLoopInfo.h =================================================================== --- clang/lib/CodeGen/CGLoopInfo.h +++ clang/lib/CodeGen/CGLoopInfo.h @@ -29,6 +29,7 @@ namespace clang { class Attr; class ASTContext; +class CodeGenOptions; namespace CodeGen { /// Attributes that may be specified on loops. @@ -202,6 +203,7 @@ /// 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); Index: clang/lib/CodeGen/CGLoopInfo.cpp =================================================================== --- clang/lib/CodeGen/CGLoopInfo.cpp +++ clang/lib/CodeGen/CGLoopInfo.cpp @@ -10,6 +10,7 @@ #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" @@ -573,6 +574,7 @@ } 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) { @@ -753,6 +755,14 @@ } } + 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); }
_______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits