Skip to content

[Clang][CodeGen] Don't emit assumptions if current block is unreachable. #106936

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Sep 4, 2024

Conversation

dtcxzyw
Copy link
Member

@dtcxzyw dtcxzyw commented Sep 2, 2024

Fixes #106898.

When emitting an infinite loop, clang codegen will delete the whole block and leave builder's current block as nullptr:

if (IsFinished && BB->use_empty()) {
delete BB;
return;
}

Then clang will create zext (icmp slt %a, %b) without parent block for a < b. It will crash here:

// If there aren't any more uses, zap the instruction to save space.
// Note that there can be more uses, for example if this
// is the result of an assignment.
if (ZI->use_empty())
ZI->eraseFromParent();

Even if we disabled this optimization, it still crashes in Builder.CreateAssumption:

CallInst *
IRBuilderBase::CreateAssumption(Value *Cond,
ArrayRef<OperandBundleDef> OpBundles) {
assert(Cond->getType() == getInt1Ty() &&
"an assumption condition must be of type i1");
Value *Ops[] = { Cond };
Module *M = BB->getParent()->getParent();
Function *FnAssume = Intrinsic::getDeclaration(M, Intrinsic::assume);
return CreateCall(FnAssume, Ops, OpBundles);
}

This patch disables assumptions emission if current block is null. As an alternative, we can fix the optimization in EmitIntToBoolConversion and use CGM.getIntrinsic as we do for __builtin_assume:

case Builtin::BI__assume:
case Builtin::BI__builtin_assume: {
if (E->getArg(0)->HasSideEffects(getContext()))
return RValue::get(nullptr);
Value *ArgValue = EmitScalarExpr(E->getArg(0));
Function *FnAssume = CGM.getIntrinsic(Intrinsic::assume);
Builder.CreateCall(FnAssume, ArgValue);
return RValue::get(nullptr);
}

@llvmbot llvmbot added clang Clang issues not falling into any other category clang:codegen IR generation bugs: mangling, exceptions, etc. labels Sep 2, 2024
@llvmbot
Copy link
Member

llvmbot commented Sep 2, 2024

@llvm/pr-subscribers-clang

@llvm/pr-subscribers-clang-codegen

Author: Yingwei Zheng (dtcxzyw)

Changes

Fixes #106898.

When emitting an infinite loop, clang codegen will delete the whole block and leave builder's current block as nullptr:

if (IsFinished && BB->use_empty()) {
delete BB;
return;
}

Then clang will create zext (icmp slt %a, %b) without parent block for a &lt; b. It will crash here:

// If there aren't any more uses, zap the instruction to save space.
// Note that there can be more uses, for example if this
// is the result of an assignment.
if (ZI->use_empty())
ZI->eraseFromParent();

Even if we disabled this optimization, it still crashes in Builder.CreateAssumption:

CallInst *
IRBuilderBase::CreateAssumption(Value *Cond,
ArrayRef<OperandBundleDef> OpBundles) {
assert(Cond->getType() == getInt1Ty() &&
"an assumption condition must be of type i1");
Value *Ops[] = { Cond };
Module *M = BB->getParent()->getParent();
Function *FnAssume = Intrinsic::getDeclaration(M, Intrinsic::assume);
return CreateCall(FnAssume, Ops, OpBundles);
}

This patch disables assumptions emission if current block is null. As an alternative, we can fix the optimization in EmitIntToBoolConversion and use CGM.getIntrinsic as we do for __builtin_assume:

case Builtin::BI__assume:
case Builtin::BI__builtin_assume: {
if (E->getArg(0)->HasSideEffects(getContext()))
return RValue::get(nullptr);
Value *ArgValue = EmitScalarExpr(E->getArg(0));
Function *FnAssume = CGM.getIntrinsic(Intrinsic::assume);
Builder.CreateCall(FnAssume, ArgValue);
return RValue::get(nullptr);
}


Full diff: https://github.com/llvm/llvm-project/pull/106936.diff

2 Files Affected:

  • (modified) clang/lib/CodeGen/CGStmt.cpp (+1-1)
  • (modified) clang/test/SemaCXX/cxx23-assume.cpp (+9)
diff --git a/clang/lib/CodeGen/CGStmt.cpp b/clang/lib/CodeGen/CGStmt.cpp
index 7158a06e6bc3b3..b138c87a853495 100644
--- a/clang/lib/CodeGen/CGStmt.cpp
+++ b/clang/lib/CodeGen/CGStmt.cpp
@@ -752,7 +752,7 @@ void CodeGenFunction::EmitAttributedStmt(const AttributedStmt &S) {
     } break;
     case attr::CXXAssume: {
       const Expr *Assumption = cast<CXXAssumeAttr>(A)->getAssumption();
-      if (getLangOpts().CXXAssumptions &&
+      if (getLangOpts().CXXAssumptions && Builder.GetInsertBlock() &&
           !Assumption->HasSideEffects(getContext())) {
         llvm::Value *AssumptionVal = EvaluateExprAsBool(Assumption);
         Builder.CreateAssumption(AssumptionVal);
diff --git a/clang/test/SemaCXX/cxx23-assume.cpp b/clang/test/SemaCXX/cxx23-assume.cpp
index 9138501d726dd6..eeae59daea3f70 100644
--- a/clang/test/SemaCXX/cxx23-assume.cpp
+++ b/clang/test/SemaCXX/cxx23-assume.cpp
@@ -158,3 +158,12 @@ foo (int x, int y)
   return x + y;
 }
 }
+
+// Do not crash when assumptions are unreachable.
+namespace gh106898 {
+int foo () { 
+    while(1);
+    int a = 0, b = 1;
+    __attribute__((assume (a < b)));
+}
+}

Copy link
Collaborator

@efriedma-quic efriedma-quic left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

@dtcxzyw dtcxzyw merged commit c94bd96 into llvm:main Sep 4, 2024
11 checks passed
@dtcxzyw dtcxzyw deleted the fix-106898 branch September 4, 2024 05:36
@dtcxzyw dtcxzyw added this to the LLVM 19.X Release milestone Sep 4, 2024
@dtcxzyw
Copy link
Member Author

dtcxzyw commented Sep 4, 2024

/cherry-pick c94bd96

llvmbot pushed a commit to llvmbot/llvm-project that referenced this pull request Sep 4, 2024
…le. (llvm#106936)

Fixes llvm#106898.

When emitting an infinite loop, clang codegen will delete the whole
block and leave builder's current block as nullptr:

https://github.com/llvm/llvm-project/blob/837ee5b46a5f7f898f0de7e46a19600b896a0a1f/clang/lib/CodeGen/CGStmt.cpp#L597-L600

Then clang will create `zext (icmp slt %a, %b)` without parent block for
`a < b`. It will crash here:

https://github.com/llvm/llvm-project/blob/837ee5b46a5f7f898f0de7e46a19600b896a0a1f/clang/lib/CodeGen/CGExprScalar.cpp#L416-L420

Even if we disabled this optimization, it still crashes in
`Builder.CreateAssumption`:

https://github.com/llvm/llvm-project/blob/837ee5b46a5f7f898f0de7e46a19600b896a0a1f/llvm/lib/IR/IRBuilder.cpp#L551-L561

This patch disables assumptions emission if current block is null.

(cherry picked from commit c94bd96)
@llvmbot
Copy link
Member

llvmbot commented Sep 4, 2024

/pull-request #107183

tru pushed a commit to llvmbot/llvm-project that referenced this pull request Sep 10, 2024
…le. (llvm#106936)

Fixes llvm#106898.

When emitting an infinite loop, clang codegen will delete the whole
block and leave builder's current block as nullptr:

https://github.com/llvm/llvm-project/blob/837ee5b46a5f7f898f0de7e46a19600b896a0a1f/clang/lib/CodeGen/CGStmt.cpp#L597-L600

Then clang will create `zext (icmp slt %a, %b)` without parent block for
`a < b`. It will crash here:

https://github.com/llvm/llvm-project/blob/837ee5b46a5f7f898f0de7e46a19600b896a0a1f/clang/lib/CodeGen/CGExprScalar.cpp#L416-L420

Even if we disabled this optimization, it still crashes in
`Builder.CreateAssumption`:

https://github.com/llvm/llvm-project/blob/837ee5b46a5f7f898f0de7e46a19600b896a0a1f/llvm/lib/IR/IRBuilder.cpp#L551-L561

This patch disables assumptions emission if current block is null.

(cherry picked from commit c94bd96)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
clang:codegen IR generation bugs: mangling, exceptions, etc. clang Clang issues not falling into any other category
Projects
Development

Successfully merging this pull request may close these issues.

Crash at llvm::Instruction::eraseFromParent()
3 participants