[PATCH] D86841: [clang] Adds noprogress attribute deduction for infinite loops
atmnpatel updated this revision to Diff 288818. atmnpatel added a comment. Fixed comment in C++ test. Repository: rG LLVM Github Monorepo CHANGES SINCE LAST ACTION https://reviews.llvm.org/D86841/new/ https://reviews.llvm.org/D86841 Files: clang/lib/CodeGen/CGLoopInfo.cpp clang/lib/CodeGen/CGLoopInfo.h clang/lib/CodeGen/CGStmt.cpp clang/test/CodeGen/attr-noprogress.c clang/test/CodeGen/attr-noprogress.cpp Index: clang/test/CodeGen/attr-noprogress.cpp === --- /dev/null +++ clang/test/CodeGen/attr-noprogress.cpp @@ -0,0 +1,55 @@ +// NOTE: Assertions have been autogenerated by utils/update_cc_test_checks.py UTC_ARGS: --check-attributes +// RUN: %clang_cc1 -S -emit-llvm %s -o - | FileCheck %s + +// CHECK: Function Attrs: noinline nounwind optnone noprogress +// CHECK-LABEL: define {{[^@]+}}@_Z1fv +// CHECK-SAME: () [[ATTR0:#.*]] { +// CHECK-NEXT: entry: +// CHECK-NEXT:br label [[FOR_COND:%.*]] +// CHECK: for.cond: +// CHECK-NEXT:br i1 true, label [[FOR_BODY:%.*]], label [[FOR_END:%.*]] +// CHECK: for.body: +// CHECK-NEXT:br label [[FOR_COND]], !llvm.loop [[LOOP2:!.]] +// CHECK: for.end: +// CHECK-NEXT:ret void +// +void f() { + for (; 1;) { + } +} + +// CHECK: Function Attrs: noinline nounwind optnone noprogress +// CHECK-LABEL: define {{[^@]+}}@_Z1wv +// CHECK-SAME: () [[ATTR0]] { +// CHECK-NEXT: entry: +// CHECK-NEXT:br label [[WHILE_BODY:%.*]] +// CHECK: while.body: +// CHECK-NEXT:br label [[WHILE_BODY]], !llvm.loop [[LOOP4:!.]] +// +void w() { + while (1) { + } +} + +// CHECK: Function Attrs: noinline nounwind optnone noprogress +// CHECK-LABEL: define {{[^@]+}}@_Z1dv +// CHECK-SAME: () [[ATTR0]] { +// CHECK-NEXT: entry: +// CHECK-NEXT:br label [[DO_BODY:%.*]] +// CHECK: do.body: +// CHECK-NEXT:br label [[DO_COND:%.*]] +// CHECK: do.cond: +// CHECK-NEXT:br i1 true, label [[DO_BODY]], label [[DO_END:%.*]], !llvm.loop [[LOOP5:!.]] +// CHECK: do.end: +// CHECK-NEXT:ret void +// +void d() { + do { + + } while (1); +} + +// CHECK: [[LOOP2]] = distinct !{[[LOOP2]], [[LOOP_MD:!.]]} +// CHECK: [[LOOP_MD]] = !{!"llvm.loop.noprogress"} +// CHECK: [[LOOP4]] = distinct !{[[LOOP4]], [[LOOP_MD]]} +// CHECK: [[LOOP5]] = distinct !{[[LOOP5]], [[LOOP_MD]]} Index: clang/test/CodeGen/attr-noprogress.c === --- /dev/null +++ clang/test/CodeGen/attr-noprogress.c @@ -0,0 +1,52 @@ +// NOTE: Assertions have been autogenerated by utils/update_cc_test_checks.py UTC_ARGS: --check-attributes +// RUN: %clang_cc1 -S -emit-llvm %s -o - | FileCheck %s + +// CHECK: Function Attrs: noinline nounwind optnone noprogress +// CHECK-LABEL: @f( +// CHECK-NEXT: entry: +// CHECK-NEXT:br label [[FOR_COND:%.*]] +// CHECK: for.cond: +// CHECK-NEXT:br i1 true, label [[FOR_BODY:%.*]], label [[FOR_END:%.*]] +// CHECK: for.body: +// CHECK-NEXT:br label [[FOR_COND]], !llvm.loop [[LOOP2:!.]] +// CHECK: for.end: +// CHECK-NEXT:ret void +// +void f() { + for (; 1;) { + } +} + +// CHECK: Function Attrs: noinline nounwind optnone noprogress +// CHECK-LABEL: @w( +// CHECK-NEXT: entry: +// CHECK-NEXT:br label [[WHILE_BODY:%.*]] +// CHECK: while.body: +// CHECK-NEXT:br label [[WHILE_BODY]], !llvm.loop [[LOOP4:!.]] +// +void w() { + while (1) { + } +} + +// CHECK: Function Attrs: noinline nounwind optnone noprogress +// CHECK-LABEL: @d( +// CHECK-NEXT: entry: +// CHECK-NEXT:br label [[DO_BODY:%.*]] +// CHECK: do.body: +// CHECK-NEXT:br label [[DO_COND:%.*]] +// CHECK: do.cond: +// CHECK-NEXT:br i1 true, label [[DO_BODY]], label [[DO_END:%.*]], !llvm.loop [[LOOP5:!.]] +// CHECK: do.end: +// CHECK-NEXT:ret void +// +void d() { + do { + + } while (1); +} + +// CHECK: [[LOOP2]] = distinct !{[[LOOP2]], [[LOOP_MD:!.]]} +// CHECK: [[LOOP_MD]] = !{!"llvm.loop.noprogress"} +// CHECK: [[LOOP4]] = distinct !{[[LOOP4]], [[LOOP_MD]]} +// CHECK: [[LOOP5]] = distinct !{[[LOOP5]], [[LOOP_MD]]} Index: clang/lib/CodeGen/CGStmt.cpp === --- clang/lib/CodeGen/CGStmt.cpp +++ clang/lib/CodeGen/CGStmt.cpp @@ -736,10 +736,26 @@ JumpDest LoopHeader = getJumpDestInCurrentScope("while.cond"); EmitBlock(LoopHeader.getBlock()); + // Evaluate the conditional in the while header. C99 6.8.5.1: The + // evaluation of the controlling expression takes place before each + // execution of the loop body. + llvm::Value *BoolCondVal = EvaluateExprAsBool(S.getCond()); + + // while(1) is common, avoid extra exit blocks. Be sure + // to correctly handle break/continue though. + bool EmitBoolCondBranch = true; + bool NoProgress = false; + if (llvm::ConstantInt *C = dyn_cast(BoolCondVal)) +if (C->isOne()) { + EmitBoolCondBranch = false; + CurFn->addFnAttr(llvm::Attribute::NoProgress); +
[PATCH] D86841: [clang] Adds noprogress attribute deduction for infinite loops
atmnpatel updated this revision to Diff 288817. atmnpatel edited the summary of this revision. atmnpatel added a comment. Sorry, Fixed the test, added a C++ test. I checked the C++, OpenCL C, and OpenCL C++ specs and couldn't find anything that diverged from C spec in this regard, but none of them explicitly stated this behavior either. Repository: rG LLVM Github Monorepo CHANGES SINCE LAST ACTION https://reviews.llvm.org/D86841/new/ https://reviews.llvm.org/D86841 Files: clang/lib/CodeGen/CGLoopInfo.cpp clang/lib/CodeGen/CGLoopInfo.h clang/lib/CodeGen/CGStmt.cpp clang/test/CodeGen/attr-noprogress.c clang/test/CodeGen/attr-noprogress.cpp Index: clang/test/CodeGen/attr-noprogress.cpp === --- /dev/null +++ clang/test/CodeGen/attr-noprogress.cpp @@ -0,0 +1,55 @@ +// NOTE: Assertions have been autogenerated by utils/update_cc_test_checks.py UTC_ARGS: --function-signature --check-attributes --force-update +// RUN: %clang_cc1 -S -emit-llvm %s -o - | FileCheck %s + +// CHECK: Function Attrs: noinline nounwind optnone noprogress +// CHECK-LABEL: define {{[^@]+}}@_Z1fv +// CHECK-SAME: () [[ATTR0:#.*]] { +// CHECK-NEXT: entry: +// CHECK-NEXT:br label [[FOR_COND:%.*]] +// CHECK: for.cond: +// CHECK-NEXT:br i1 true, label [[FOR_BODY:%.*]], label [[FOR_END:%.*]] +// CHECK: for.body: +// CHECK-NEXT:br label [[FOR_COND]], !llvm.loop [[LOOP2:!.]] +// CHECK: for.end: +// CHECK-NEXT:ret void +// +void f() { + for (; 1;) { + } +} + +// CHECK: Function Attrs: noinline nounwind optnone noprogress +// CHECK-LABEL: define {{[^@]+}}@_Z1wv +// CHECK-SAME: () [[ATTR0]] { +// CHECK-NEXT: entry: +// CHECK-NEXT:br label [[WHILE_BODY:%.*]] +// CHECK: while.body: +// CHECK-NEXT:br label [[WHILE_BODY]], !llvm.loop [[LOOP4:!.]] +// +void w() { + while (1) { + } +} + +// CHECK: Function Attrs: noinline nounwind optnone noprogress +// CHECK-LABEL: define {{[^@]+}}@_Z1dv +// CHECK-SAME: () [[ATTR0]] { +// CHECK-NEXT: entry: +// CHECK-NEXT:br label [[DO_BODY:%.*]] +// CHECK: do.body: +// CHECK-NEXT:br label [[DO_COND:%.*]] +// CHECK: do.cond: +// CHECK-NEXT:br i1 true, label [[DO_BODY]], label [[DO_END:%.*]], !llvm.loop [[LOOP5:!.]] +// CHECK: do.end: +// CHECK-NEXT:ret void +// +void d() { + do { + + } while (1); +} + +// CHECK: [[LOOP2]] = distinct !{[[LOOP2]], [[LOOP_MD:!.]]} +// CHECK: [[LOOP_MD]] = !{!"llvm.loop.noprogress"} +// CHECK: [[LOOP4]] = distinct !{[[LOOP4]], [[LOOP_MD]]} +// CHECK: [[LOOP5]] = distinct !{[[LOOP5]], [[LOOP_MD]]} Index: clang/test/CodeGen/attr-noprogress.c === --- /dev/null +++ clang/test/CodeGen/attr-noprogress.c @@ -0,0 +1,52 @@ +// NOTE: Assertions have been autogenerated by utils/update_cc_test_checks.py UTC_ARGS: --check-attributes +// RUN: %clang_cc1 -S -emit-llvm %s -o - | FileCheck %s + +// CHECK: Function Attrs: noinline nounwind optnone noprogress +// CHECK-LABEL: @f( +// CHECK-NEXT: entry: +// CHECK-NEXT:br label [[FOR_COND:%.*]] +// CHECK: for.cond: +// CHECK-NEXT:br i1 true, label [[FOR_BODY:%.*]], label [[FOR_END:%.*]] +// CHECK: for.body: +// CHECK-NEXT:br label [[FOR_COND]], !llvm.loop [[LOOP2:!.]] +// CHECK: for.end: +// CHECK-NEXT:ret void +// +void f() { + for (; 1;) { + } +} + +// CHECK: Function Attrs: noinline nounwind optnone noprogress +// CHECK-LABEL: @w( +// CHECK-NEXT: entry: +// CHECK-NEXT:br label [[WHILE_BODY:%.*]] +// CHECK: while.body: +// CHECK-NEXT:br label [[WHILE_BODY]], !llvm.loop [[LOOP4:!.]] +// +void w() { + while (1) { + } +} + +// CHECK: Function Attrs: noinline nounwind optnone noprogress +// CHECK-LABEL: @d( +// CHECK-NEXT: entry: +// CHECK-NEXT:br label [[DO_BODY:%.*]] +// CHECK: do.body: +// CHECK-NEXT:br label [[DO_COND:%.*]] +// CHECK: do.cond: +// CHECK-NEXT:br i1 true, label [[DO_BODY]], label [[DO_END:%.*]], !llvm.loop [[LOOP5:!.]] +// CHECK: do.end: +// CHECK-NEXT:ret void +// +void d() { + do { + + } while (1); +} + +// CHECK: [[LOOP2]] = distinct !{[[LOOP2]], [[LOOP_MD:!.]]} +// CHECK: [[LOOP_MD]] = !{!"llvm.loop.noprogress"} +// CHECK: [[LOOP4]] = distinct !{[[LOOP4]], [[LOOP_MD]]} +// CHECK: [[LOOP5]] = distinct !{[[LOOP5]], [[LOOP_MD]]} Index: clang/lib/CodeGen/CGStmt.cpp === --- clang/lib/CodeGen/CGStmt.cpp +++ clang/lib/CodeGen/CGStmt.cpp @@ -736,10 +736,26 @@ JumpDest LoopHeader = getJumpDestInCurrentScope("while.cond"); EmitBlock(LoopHeader.getBlock()); + // Evaluate the conditional in the while header. C99 6.8.5.1: The + // evaluation of the controlling expression takes place before each + // execution of the loop body. + llvm::Value *BoolCondVal = EvaluateExprAsBool(S.getCond()); + + // while(1) is common, avoid extra exit blocks. Be sure + // t
[PATCH] D86841: [clang] Adds noprogress attribute deduction for infinite loops
lebedev.ri added a comment. Does that wording apply to both the C and C++ (OpenCL?)? Regardless, might be good to test that. Comment at: clang/test/CodeGen/attr-noprogress.c:1-2 +// RUN: %clang_cc1 -S -emit-llvm %s -o - | grep " noprogress " | count 1 +// RUN: %clang_cc1 -S -emit-llvm %s -o - | grep llvm.loop.noprogress | count 1 + Please just FileCheck the expected output. Bonus points for using `llvm/utils/update_cc_test_checks.py` Repository: rG LLVM Github Monorepo CHANGES SINCE LAST ACTION https://reviews.llvm.org/D86841/new/ https://reviews.llvm.org/D86841 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[PATCH] D86841: [clang] Adds noprogress attribute deduction for infinite loops
atmnpatel created this revision. atmnpatel added reviewers: jdoerfert, aqjune, RalfJung. Herald added subscribers: cfe-commits, danielkiss. Herald added a project: clang. atmnpatel requested review of this revision. The `noprogress` LLVM IR attribute currently under discussion is deduced for functions that contain loops that have a constant non-zero conditional as per the C Spec. In addition, these particular loops have an additional bit of metadata `llvm.loop.noprogress` so llvm can differentiate between the loops that can be optimized out and ones that can't be optimized out. The changes to the LoopDeletion pass is incoming. Repository: rG LLVM Github Monorepo https://reviews.llvm.org/D86841 Files: clang/lib/CodeGen/CGLoopInfo.cpp clang/lib/CodeGen/CGLoopInfo.h clang/lib/CodeGen/CGStmt.cpp clang/test/CodeGen/attr-noprogress.c Index: clang/test/CodeGen/attr-noprogress.c === --- /dev/null +++ clang/test/CodeGen/attr-noprogress.c @@ -0,0 +1,18 @@ +// RUN: %clang_cc1 -S -emit-llvm %s -o - | grep " noprogress " | count 1 +// RUN: %clang_cc1 -S -emit-llvm %s -o - | grep llvm.loop.noprogress | count 1 + +void f() { + for (; 1;) { + } +} + +void w() { + while (1) { + } +} + +void d() { + do { + + } while (1); +} Index: clang/lib/CodeGen/CGStmt.cpp === --- clang/lib/CodeGen/CGStmt.cpp +++ clang/lib/CodeGen/CGStmt.cpp @@ -736,10 +736,26 @@ JumpDest LoopHeader = getJumpDestInCurrentScope("while.cond"); EmitBlock(LoopHeader.getBlock()); + // Evaluate the conditional in the while header. C99 6.8.5.1: The + // evaluation of the controlling expression takes place before each + // execution of the loop body. + llvm::Value *BoolCondVal = EvaluateExprAsBool(S.getCond()); + + // while(1) is common, avoid extra exit blocks. Be sure + // to correctly handle break/continue though. + bool EmitBoolCondBranch = true; + bool NoProgress = false; + if (llvm::ConstantInt *C = dyn_cast(BoolCondVal)) +if (C->isOne()) { + EmitBoolCondBranch = false; + CurFn->addFnAttr(llvm::Attribute::NoProgress); + NoProgress = true; +} + const SourceRange &R = S.getSourceRange(); LoopStack.push(LoopHeader.getBlock(), CGM.getContext(), CGM.getCodeGenOpts(), WhileAttrs, SourceLocToDebugLoc(R.getBegin()), - SourceLocToDebugLoc(R.getEnd())); + SourceLocToDebugLoc(R.getEnd()), NoProgress); // Create an exit block for when the condition fails, which will // also become the break target. @@ -760,18 +776,6 @@ if (S.getConditionVariable()) EmitDecl(*S.getConditionVariable()); - // Evaluate the conditional in the while header. C99 6.8.5.1: The - // evaluation of the controlling expression takes place before each - // execution of the loop body. - llvm::Value *BoolCondVal = EvaluateExprAsBool(S.getCond()); - - // while(1) is common, avoid extra exit blocks. Be sure - // to correctly handle break/continue though. - bool EmitBoolCondBranch = true; - if (llvm::ConstantInt *C = dyn_cast(BoolCondVal)) -if (C->isOne()) - EmitBoolCondBranch = false; - // As long as the condition is true, go to the loop body. llvm::BasicBlock *LoopBody = createBasicBlock("while.body"); if (EmitBoolCondBranch) { @@ -838,27 +842,33 @@ EmitBlock(LoopCond.getBlock()); - const SourceRange &R = S.getSourceRange(); - LoopStack.push(LoopBody, CGM.getContext(), CGM.getCodeGenOpts(), DoAttrs, - SourceLocToDebugLoc(R.getBegin()), - SourceLocToDebugLoc(R.getEnd())); - - // C99 6.8.5.2: "The evaluation of the controlling expression takes place - // after each execution of the loop body." - // Evaluate the conditional in the while header. // C99 6.8.5p2/p4: The first substatement is executed if the expression // compares unequal to 0. The condition must be a scalar type. llvm::Value *BoolCondVal = EvaluateExprAsBool(S.getCond()); - BreakContinueStack.pop_back(); - // "do {} while (0)" is common in macros, avoid extra blocks. Be sure // to correctly handle break/continue though. bool EmitBoolCondBranch = true; - if (llvm::ConstantInt *C = dyn_cast(BoolCondVal)) + bool NoProgress = false; + if (llvm::ConstantInt *C = dyn_cast(BoolCondVal)) { if (C->isZero()) EmitBoolCondBranch = false; +if (C->isOne()) { + CurFn->addFnAttr(llvm::Attribute::NoProgress); + NoProgress = true; +} + } + + const SourceRange &R = S.getSourceRange(); + LoopStack.push(LoopBody, CGM.getContext(), CGM.getCodeGenOpts(), DoAttrs, + SourceLocToDebugLoc(R.getBegin()), + SourceLocToDebugLoc(R.getEnd()), NoProgress); + + // C99 6.8.5.2: "The evaluation of the controlling expression takes place + // after each execution of the loop body." + + BreakContinueStack.pop_back(); // As long as the condition