Skip to content

Commit ac73b73

Browse files
committed
[clang] Add mustprogress and llvm.loop.mustprogress attribute deduction
Since C++11, the C++ standard has a forward progress guarantee [intro.progress], so all such functions must have the `mustprogress` requirement. In addition, from C11 and onwards, loops without a non-zero constant conditional or no conditional are also required to make progress (C11 6.8.5p6). This patch implements these attribute deductions so they can be used by the optimization passes. Differential Revision: https://reviews.llvm.org/D86841
1 parent bbd4ebf commit ac73b73

40 files changed

+1038
-146
lines changed

clang/lib/CodeGen/CGLoopInfo.cpp

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -411,10 +411,14 @@ MDNode *LoopInfo::createMetadata(
411411
LoopProperties.push_back(EndLoc.getAsMDNode());
412412
}
413413

414+
LLVMContext &Ctx = Header->getContext();
415+
if (Attrs.MustProgress)
416+
LoopProperties.push_back(
417+
MDNode::get(Ctx, MDString::get(Ctx, "llvm.loop.mustprogress")));
418+
414419
assert(!!AccGroup == Attrs.IsParallel &&
415420
"There must be an access group iff the loop is parallel");
416421
if (Attrs.IsParallel) {
417-
LLVMContext &Ctx = Header->getContext();
418422
LoopProperties.push_back(MDNode::get(
419423
Ctx, {MDString::get(Ctx, "llvm.loop.parallel_accesses"), AccGroup}));
420424
}
@@ -431,7 +435,7 @@ LoopAttributes::LoopAttributes(bool IsParallel)
431435
VectorizePredicateEnable(LoopAttributes::Unspecified), VectorizeWidth(0),
432436
InterleaveCount(0), UnrollCount(0), UnrollAndJamCount(0),
433437
DistributeEnable(LoopAttributes::Unspecified), PipelineDisabled(false),
434-
PipelineInitiationInterval(0) {}
438+
PipelineInitiationInterval(0), MustProgress(false) {}
435439

436440
void LoopAttributes::clear() {
437441
IsParallel = false;
@@ -446,6 +450,7 @@ void LoopAttributes::clear() {
446450
DistributeEnable = LoopAttributes::Unspecified;
447451
PipelineDisabled = false;
448452
PipelineInitiationInterval = 0;
453+
MustProgress = false;
449454
}
450455

451456
LoopInfo::LoopInfo(BasicBlock *Header, const LoopAttributes &Attrs,
@@ -469,7 +474,7 @@ LoopInfo::LoopInfo(BasicBlock *Header, const LoopAttributes &Attrs,
469474
Attrs.UnrollEnable == LoopAttributes::Unspecified &&
470475
Attrs.UnrollAndJamEnable == LoopAttributes::Unspecified &&
471476
Attrs.DistributeEnable == LoopAttributes::Unspecified && !StartLoc &&
472-
!EndLoc)
477+
!EndLoc && !Attrs.MustProgress)
473478
return;
474479

475480
TempLoopID = MDNode::getTemporary(Header->getContext(), None);
@@ -570,8 +575,7 @@ void LoopInfoStack::push(BasicBlock *Header, clang::ASTContext &Ctx,
570575
const clang::CodeGenOptions &CGOpts,
571576
ArrayRef<const clang::Attr *> Attrs,
572577
const llvm::DebugLoc &StartLoc,
573-
const llvm::DebugLoc &EndLoc) {
574-
578+
const llvm::DebugLoc &EndLoc, bool MustProgress) {
575579
// Identify loop hint attributes from Attrs.
576580
for (const auto *Attr : Attrs) {
577581
const LoopHintAttr *LH = dyn_cast<LoopHintAttr>(Attr);
@@ -748,6 +752,8 @@ void LoopInfoStack::push(BasicBlock *Header, clang::ASTContext &Ctx,
748752
}
749753
}
750754

755+
setMustProgress(MustProgress);
756+
751757
if (CGOpts.OptimizationLevel > 0)
752758
// Disable unrolling for the loop, if unrolling is disabled (via
753759
// -fno-unroll-loops) and no pragmas override the decision.

clang/lib/CodeGen/CGLoopInfo.h

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,9 @@ struct LoopAttributes {
7575

7676
/// Value for llvm.loop.pipeline.iicount metadata.
7777
unsigned PipelineInitiationInterval;
78+
79+
/// Value for whether the loop is required to make progress.
80+
bool MustProgress;
7881
};
7982

8083
/// Information used when generating a structured loop.
@@ -205,7 +208,7 @@ class LoopInfoStack {
205208
void push(llvm::BasicBlock *Header, clang::ASTContext &Ctx,
206209
const clang::CodeGenOptions &CGOpts,
207210
llvm::ArrayRef<const Attr *> Attrs, const llvm::DebugLoc &StartLoc,
208-
const llvm::DebugLoc &EndLoc);
211+
const llvm::DebugLoc &EndLoc, bool MustProgress = false);
209212

210213
/// End the current loop.
211214
void pop();
@@ -272,6 +275,9 @@ class LoopInfoStack {
272275
StagedAttrs.PipelineInitiationInterval = C;
273276
}
274277

278+
/// Set no progress for the next loop pushed.
279+
void setMustProgress(bool P) { StagedAttrs.MustProgress = P; }
280+
275281
private:
276282
/// Returns true if there is LoopInfo on the stack.
277283
bool hasInfo() const { return !Active.empty(); }

clang/lib/CodeGen/CGStmt.cpp

Lines changed: 40 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -765,11 +765,6 @@ void CodeGenFunction::EmitWhileStmt(const WhileStmt &S,
765765
JumpDest LoopHeader = getJumpDestInCurrentScope("while.cond");
766766
EmitBlock(LoopHeader.getBlock());
767767

768-
const SourceRange &R = S.getSourceRange();
769-
LoopStack.push(LoopHeader.getBlock(), CGM.getContext(), CGM.getCodeGenOpts(),
770-
WhileAttrs, SourceLocToDebugLoc(R.getBegin()),
771-
SourceLocToDebugLoc(R.getEnd()));
772-
773768
// Create an exit block for when the condition fails, which will
774769
// also become the break target.
775770
JumpDest LoopExit = getJumpDestInCurrentScope("while.end");
@@ -797,9 +792,19 @@ void CodeGenFunction::EmitWhileStmt(const WhileStmt &S,
797792
// while(1) is common, avoid extra exit blocks. Be sure
798793
// to correctly handle break/continue though.
799794
bool EmitBoolCondBranch = true;
800-
if (llvm::ConstantInt *C = dyn_cast<llvm::ConstantInt>(BoolCondVal))
801-
if (C->isOne())
795+
bool LoopMustProgress = false;
796+
if (llvm::ConstantInt *C = dyn_cast<llvm::ConstantInt>(BoolCondVal)) {
797+
if (C->isOne()) {
802798
EmitBoolCondBranch = false;
799+
FnIsMustProgress = false;
800+
}
801+
} else if (LanguageRequiresProgress())
802+
LoopMustProgress = true;
803+
804+
const SourceRange &R = S.getSourceRange();
805+
LoopStack.push(LoopHeader.getBlock(), CGM.getContext(), CGM.getCodeGenOpts(),
806+
WhileAttrs, SourceLocToDebugLoc(R.getBegin()),
807+
SourceLocToDebugLoc(R.getEnd()), LoopMustProgress);
803808

804809
// As long as the condition is true, go to the loop body.
805810
llvm::BasicBlock *LoopBody = createBasicBlock("while.body");
@@ -875,11 +880,6 @@ void CodeGenFunction::EmitDoStmt(const DoStmt &S,
875880

876881
EmitBlock(LoopCond.getBlock());
877882

878-
const SourceRange &R = S.getSourceRange();
879-
LoopStack.push(LoopBody, CGM.getContext(), CGM.getCodeGenOpts(), DoAttrs,
880-
SourceLocToDebugLoc(R.getBegin()),
881-
SourceLocToDebugLoc(R.getEnd()));
882-
883883
// C99 6.8.5.2: "The evaluation of the controlling expression takes place
884884
// after each execution of the loop body."
885885

@@ -893,9 +893,19 @@ void CodeGenFunction::EmitDoStmt(const DoStmt &S,
893893
// "do {} while (0)" is common in macros, avoid extra blocks. Be sure
894894
// to correctly handle break/continue though.
895895
bool EmitBoolCondBranch = true;
896-
if (llvm::ConstantInt *C = dyn_cast<llvm::ConstantInt>(BoolCondVal))
896+
bool LoopMustProgress = false;
897+
if (llvm::ConstantInt *C = dyn_cast<llvm::ConstantInt>(BoolCondVal)) {
897898
if (C->isZero())
898899
EmitBoolCondBranch = false;
900+
else if (C->isOne())
901+
FnIsMustProgress = false;
902+
} else if (LanguageRequiresProgress())
903+
LoopMustProgress = true;
904+
905+
const SourceRange &R = S.getSourceRange();
906+
LoopStack.push(LoopBody, CGM.getContext(), CGM.getCodeGenOpts(), DoAttrs,
907+
SourceLocToDebugLoc(R.getBegin()),
908+
SourceLocToDebugLoc(R.getEnd()), LoopMustProgress);
899909

900910
// As long as the condition is true, iterate the loop.
901911
if (EmitBoolCondBranch) {
@@ -933,10 +943,21 @@ void CodeGenFunction::EmitForStmt(const ForStmt &S,
933943
llvm::BasicBlock *CondBlock = Continue.getBlock();
934944
EmitBlock(CondBlock);
935945

946+
bool LoopMustProgress = false;
947+
Expr::EvalResult Result;
948+
if (LanguageRequiresProgress()) {
949+
if (!S.getCond()) {
950+
LoopMustProgress = true;
951+
FnIsMustProgress = false;
952+
} else if (!S.getCond()->EvaluateAsInt(Result, getContext())) {
953+
LoopMustProgress = true;
954+
}
955+
}
956+
936957
const SourceRange &R = S.getSourceRange();
937958
LoopStack.push(CondBlock, CGM.getContext(), CGM.getCodeGenOpts(), ForAttrs,
938959
SourceLocToDebugLoc(R.getBegin()),
939-
SourceLocToDebugLoc(R.getEnd()));
960+
SourceLocToDebugLoc(R.getEnd()), LoopMustProgress);
940961

941962
// If the for loop doesn't have an increment we can just use the
942963
// condition as the continue block. Otherwise we'll need to create
@@ -972,6 +993,11 @@ void CodeGenFunction::EmitForStmt(const ForStmt &S,
972993
llvm::Value *BoolCondVal = EvaluateExprAsBool(S.getCond());
973994
llvm::MDNode *Weights = createProfileOrBranchWeightsForLoop(
974995
S.getCond(), getProfileCount(S.getBody()), S.getBody());
996+
997+
if (llvm::ConstantInt *C = dyn_cast<llvm::ConstantInt>(BoolCondVal))
998+
if (C->isOne())
999+
FnIsMustProgress = false;
1000+
9751001
Builder.CreateCondBr(BoolCondVal, ForBody, ExitBlock, Weights);
9761002

9771003
if (ExitBlock != LoopExit.getBlock()) {

clang/lib/CodeGen/CodeGenFunction.cpp

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1159,10 +1159,18 @@ void CodeGenFunction::StartFunction(GlobalDecl GD, QualType RetTy,
11591159

11601160
void CodeGenFunction::EmitFunctionBody(const Stmt *Body) {
11611161
incrementProfileCounter(Body);
1162+
if (CPlusPlusWithProgress())
1163+
FnIsMustProgress = true;
1164+
11621165
if (const CompoundStmt *S = dyn_cast<CompoundStmt>(Body))
11631166
EmitCompoundStmtWithoutScope(*S);
11641167
else
11651168
EmitStmt(Body);
1169+
1170+
// This is checked after emitting the function body so we know if there
1171+
// are any permitted infinite loops.
1172+
if (FnIsMustProgress)
1173+
CurFn->addFnAttr(llvm::Attribute::MustProgress);
11661174
}
11671175

11681176
/// When instrumenting to collect profile data, the counts for some blocks

clang/lib/CodeGen/CodeGenFunction.h

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -502,6 +502,26 @@ class CodeGenFunction : public CodeGenTypeCache {
502502
/// True if the current statement has nomerge attribute.
503503
bool InNoMergeAttributedStmt = false;
504504

505+
/// True if the current function should be marked mustprogress.
506+
bool FnIsMustProgress = false;
507+
508+
/// True if the C++ Standard Requires Progress.
509+
bool CPlusPlusWithProgress() {
510+
return getLangOpts().CPlusPlus11 || getLangOpts().CPlusPlus14 ||
511+
getLangOpts().CPlusPlus17 || getLangOpts().CPlusPlus20;
512+
}
513+
514+
/// True if the C Standard Requires Progress.
515+
bool CWithProgress() {
516+
return getLangOpts().C11 || getLangOpts().C17 || getLangOpts().C2x;
517+
}
518+
519+
/// True if the language standard requires progress in functions or
520+
/// in infinite loops with non-constant conditionals.
521+
bool LanguageRequiresProgress() {
522+
return CWithProgress() || CPlusPlusWithProgress();
523+
}
524+
505525
const CodeGen::CGBlockInfo *BlockInfo = nullptr;
506526
llvm::Value *BlockPointer = nullptr;
507527

clang/test/CodeGen/address-safety-attr-flavors.cpp

Lines changed: 30 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -25,51 +25,51 @@
2525
// RUN: FileCheck -check-prefix=CHECK-KHWASAN %s
2626

2727
int HasSanitizeAddress() { return 1; }
28-
// CHECK-NOASAN: {{Function Attrs: noinline nounwind$}}
29-
// CHECK-ASAN: Function Attrs: noinline nounwind sanitize_address
30-
// CHECK-KASAN: Function Attrs: noinline nounwind sanitize_address
31-
// CHECK-HWASAN: Function Attrs: noinline nounwind sanitize_hwaddress
32-
// CHECK-KHWASAN: Function Attrs: noinline nounwind sanitize_hwaddress
28+
// CHECK-NOASAN: {{Function Attrs: noinline nounwind mustprogress$}}
29+
// CHECK-ASAN: Function Attrs: noinline nounwind sanitize_address mustprogress
30+
// CHECK-KASAN: Function Attrs: noinline nounwind sanitize_address mustprogress
31+
// CHECK-HWASAN: Function Attrs: noinline nounwind sanitize_hwaddress mustprogress
32+
// CHECK-KHWASAN: Function Attrs: noinline nounwind sanitize_hwaddress mustprogress
3333

3434
__attribute__((no_sanitize("address"))) int NoSanitizeQuoteAddress() {
3535
return 0;
3636
}
37-
// CHECK-NOASAN: {{Function Attrs: noinline nounwind$}}
38-
// CHECK-ASAN: {{Function Attrs: noinline nounwind$}}
39-
// CHECK-KASAN: {{Function Attrs: noinline nounwind$}}
40-
// CHECK-HWASAN: {{Function Attrs: noinline nounwind sanitize_hwaddress$}}
41-
// CHECK-KHWASAN: {{Function Attrs: noinline nounwind sanitize_hwaddress$}}
37+
// CHECK-NOASAN: {{Function Attrs: noinline nounwind mustprogress$}}
38+
// CHECK-ASAN: {{Function Attrs: noinline nounwind mustprogress$}}
39+
// CHECK-KASAN: {{Function Attrs: noinline nounwind mustprogress$}}
40+
// CHECK-HWASAN: {{Function Attrs: noinline nounwind sanitize_hwaddress mustprogress$}}
41+
// CHECK-KHWASAN: {{Function Attrs: noinline nounwind sanitize_hwaddress mustprogress$}}
4242

4343
__attribute__((no_sanitize_address)) int NoSanitizeAddress() { return 0; }
44-
// CHECK-NOASAN: {{Function Attrs: noinline nounwind$}}
45-
// CHECK-ASAN: {{Function Attrs: noinline nounwind$}}
46-
// CHECK-KASAN: {{Function Attrs: noinline nounwind$}}
47-
// CHECK-HWASAN: {{Function Attrs: noinline nounwind sanitize_hwaddress$}}
48-
// CHECK-KHWASAN: {{Function Attrs: noinline nounwind sanitize_hwaddress$}}
44+
// CHECK-NOASAN: {{Function Attrs: noinline nounwind mustprogress$}}
45+
// CHECK-ASAN: {{Function Attrs: noinline nounwind mustprogress$}}
46+
// CHECK-KASAN: {{Function Attrs: noinline nounwind mustprogress$}}
47+
// CHECK-HWASAN: {{Function Attrs: noinline nounwind sanitize_hwaddress mustprogress$}}
48+
// CHECK-KHWASAN: {{Function Attrs: noinline nounwind sanitize_hwaddress mustprogress$}}
4949

5050
__attribute__((no_sanitize("kernel-address"))) int NoSanitizeKernelAddress() {
5151
return 0;
5252
}
53-
// CHECK-NOASAN: {{Function Attrs: noinline nounwind$}}
54-
// CHECK-ASAN: {{Function Attrs: noinline nounwind$}}
55-
// CHECK-KASAN: {{Function Attrs: noinline nounwind$}}
56-
// CHECK-HWASAN: {{Function Attrs: noinline nounwind sanitize_hwaddress$}}
57-
// CHECK-KHWASAN: {{Function Attrs: noinline nounwind sanitize_hwaddress$}}
53+
// CHECK-NOASAN: {{Function Attrs: noinline nounwind mustprogress$}}
54+
// CHECK-ASAN: {{Function Attrs: noinline nounwind mustprogress$}}
55+
// CHECK-KASAN: {{Function Attrs: noinline nounwind mustprogress$}}
56+
// CHECK-HWASAN: {{Function Attrs: noinline nounwind sanitize_hwaddress mustprogress$}}
57+
// CHECK-KHWASAN: {{Function Attrs: noinline nounwind sanitize_hwaddress mustprogress$}}
5858

5959
__attribute__((no_sanitize("hwaddress"))) int NoSanitizeHWAddress() {
6060
return 0;
6161
}
62-
// CHECK-NOASAN: {{Function Attrs: noinline nounwind$}}
63-
// CHECK-ASAN: {{Function Attrs: noinline nounwind sanitize_address$}}
64-
// CHECK-KASAN: {{Function Attrs: noinline nounwind sanitize_address$}}
65-
// CHECK-HWASAN: {{Function Attrs: noinline nounwind$}}
66-
// CHECK-KHWASAN: {{Function Attrs: noinline nounwind$}}
62+
// CHECK-NOASAN: {{Function Attrs: noinline nounwind mustprogress$}}
63+
// CHECK-ASAN: {{Function Attrs: noinline nounwind sanitize_address mustprogress$}}
64+
// CHECK-KASAN: {{Function Attrs: noinline nounwind sanitize_address mustprogress$}}
65+
// CHECK-HWASAN: {{Function Attrs: noinline nounwind mustprogress$}}
66+
// CHECK-KHWASAN: {{Function Attrs: noinline nounwind mustprogress$}}
6767

6868
__attribute__((no_sanitize("kernel-hwaddress"))) int NoSanitizeKernelHWAddress() {
6969
return 0;
7070
}
71-
// CHECK-NOASAN: {{Function Attrs: noinline nounwind$}}
72-
// CHECK-ASAN: {{Function Attrs: noinline nounwind sanitize_address$}}
73-
// CHECK-KASAN: {{Function Attrs: noinline nounwind sanitize_address$}}
74-
// CHECK-HWASAN: {{Function Attrs: noinline nounwind$}}
75-
// CHECK-KHWASAN: {{Function Attrs: noinline nounwind$}}
71+
// CHECK-NOASAN: {{Function Attrs: noinline nounwind mustprogress$}}
72+
// CHECK-ASAN: {{Function Attrs: noinline nounwind sanitize_address mustprogress$}}
73+
// CHECK-KASAN: {{Function Attrs: noinline nounwind sanitize_address mustprogress$}}
74+
// CHECK-HWASAN: {{Function Attrs: noinline nounwind mustprogress$}}
75+
// CHECK-KHWASAN: {{Function Attrs: noinline nounwind mustprogress$}}

clang/test/CodeGen/address-safety-attr.cpp

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -35,8 +35,7 @@ int DefinedInDifferentFile(int *a);
3535
// ASAN: @__cxx_global_var_init{{.*}}[[WITH:#[0-9]+]]
3636
// ASAN: @__cxx_global_array_dtor{{.*}}[[WITH]]
3737

38-
39-
// WITHOUT: NoAddressSafety1{{.*}}) [[NOATTR]]
38+
// WITHOUT: NoAddressSafety1{{.*}}) [[NOATTR:#[0-9]+]]
4039
// BLFILE: NoAddressSafety1{{.*}}) [[NOATTR:#[0-9]+]]
4140
// BLFUNC: NoAddressSafety1{{.*}}) [[NOATTR:#[0-9]+]]
4241
// ASAN: NoAddressSafety1{{.*}}) [[NOATTR:#[0-9]+]]
@@ -83,8 +82,8 @@ int NoAddressSafety6(int *a) { return *a; }
8382

8483
// WITHOUT: AddressSafetyOk{{.*}}) [[NOATTR]]
8584
// BLFILE: AddressSafetyOk{{.*}}) [[NOATTR]]
86-
// BLFUNC: AddressSafetyOk{{.*}}) [[WITH]]
87-
// ASAN: AddressSafetyOk{{.*}}) [[WITH]]
85+
// BLFUNC: AddressSafetyOk{{.*}}) [[WITH:#[0-9]+]]
86+
// ASAN: AddressSafetyOk{{.*}}) [[WITH:#[0-9]+]]
8887
int AddressSafetyOk(int *a) { return *a; }
8988

9089
// WITHOUT: BlacklistedFunction{{.*}}) [[NOATTR]]
@@ -138,10 +137,10 @@ int force_instance = TemplateAddressSafetyOk<42>()
138137
// Check that __cxx_global_var_init* get the sanitize_address attribute.
139138
int global1 = 0;
140139
int global2 = *(int*)((char*)&global1+1);
141-
// WITHOUT: @__cxx_global_var_init{{.*}}[[NOATTR]]
140+
// WITHOUT: @__cxx_global_var_init{{.*}}[[NOATTR:#[0-9]+]]
142141
// BLFILE: @__cxx_global_var_init{{.*}}[[NOATTR:#[0-9]+]]
143-
// BLFUNC: @__cxx_global_var_init{{.*}}[[WITH]]
144-
// ASAN: @__cxx_global_var_init{{.*}}[[WITH]]
142+
// BLFUNC: @__cxx_global_var_init{{.*}}[[WITH:#[0-9]+]]
143+
// ASAN: @__cxx_global_var_init{{.*}}[[WITH:#[0-9]+]]
145144

146145
// WITHOUT: attributes [[NOATTR]] = { noinline nounwind{{.*}} }
147146

0 commit comments

Comments
 (0)