Skip to content

Commit

Permalink
Stop wrapping GCCAsmStmts inside StmtExprs to destruct temporaries
Browse files Browse the repository at this point in the history
Instead, just pop the cleanups at the end of the asm statement.

This fixes an assertion failure in BuildStmtExpr. It also fixes a bug
where blocks and C compound literals were destructed at the end of the
asm statement instead of at the end of the enclosing scope.

Differential Revision: https://reviews.llvm.org/D125936
  • Loading branch information
ahatanaka committed Jun 18, 2022
1 parent 121c645 commit 8fc3d71
Show file tree
Hide file tree
Showing 6 changed files with 86 additions and 2 deletions.
3 changes: 3 additions & 0 deletions clang/lib/CodeGen/CGStmt.cpp
Expand Up @@ -2289,6 +2289,9 @@ static void UpdateAsmCallInst(llvm::CallBase &Result, bool HasSideEffect,
}

void CodeGenFunction::EmitAsmStmt(const AsmStmt &S) {
// Pop all cleanup blocks at the end of the asm statement.
CodeGenFunction::RunCleanupsScope Cleanups(*this);

// Assemble the final asm string.
std::string AsmString = S.generateAsmString(getContext());

Expand Down
1 change: 0 additions & 1 deletion clang/lib/Parse/ParseStmt.cpp
Expand Up @@ -325,7 +325,6 @@ StmtResult Parser::ParseStatementOrDeclarationAfterAttributes(
ProhibitAttributes(GNUAttrs);
bool msAsm = false;
Res = ParseAsmStatement(msAsm);
Res = Actions.ActOnFinishFullStmt(Res.get());
if (msAsm) return Res;
SemiError = "asm";
break;
Expand Down
3 changes: 3 additions & 0 deletions clang/lib/Sema/SemaStmtAsm.cpp
Expand Up @@ -733,6 +733,9 @@ StmtResult Sema::ActOnGCCAsmStmt(SourceLocation AsmLoc, bool IsSimple,
}
if (NS->isAsmGoto())
setFunctionHasBranchIntoScope();

CleanupVarDeclMarking();
DiscardCleanupsInEvaluationContext();
return NS;
}

Expand Down
40 changes: 39 additions & 1 deletion clang/test/CodeGenCXX/asm.cpp
@@ -1,4 +1,6 @@
// RUN: %clang_cc1 -triple i386-unknown-unknown -emit-llvm %s -o - | FileCheck %s
// RUN: %clang_cc1 -triple i386-unknown-unknown -fblocks -emit-llvm %s -o - | FileCheck %s

// CHECK: %[[STRUCT_A:.*]] = type { i8 }

struct A
{
Expand All @@ -12,3 +14,39 @@ void bar(A &a)
asm("" : : "r"(foo(a)) ); // rdar://8540491
// CHECK: call void @_ZN1AD1Ev
}

namespace TestTemplate {
// Check that the temporary is destructed after the first asm statement.

// CHECK: define {{.*}}void @_ZN12TestTemplate4foo0IvEEvR1A(
// CHECK: %[[AGG_TMP:.*]] = alloca %[[STRUCT_A]],
// CHECK: %[[CALL:.*]] = call noundef i32 @_Z3foo1A({{.*}}%[[AGG_TMP]])
// CHECK: call void asm sideeffect "", "r,~{dirflag},~{fpsr},~{flags}"(i32 %[[CALL]])
// CHECK: call void @_ZN1AD1Ev({{.*}}%[[AGG_TMP]])
// CHECK: call void asm sideeffect "",

template <class T>
void foo0(A &a) {
asm("" : : "r"(foo(a)) );
asm("");
}

void test0(A &a) { foo0<void>(a); }

// Check that the block capture is destructed at the end of the enclosing scope.

// CHECK: define {{.*}}void @_ZN12TestTemplate4foo1IvEEv1A(
// CHECK: %[[BLOCK:.*]] = alloca <{ ptr, i32, i32, ptr, ptr, %[[STRUCT_A]] }>, align 4
// CHECK: %[[BLOCK_CAPTURED:.*]] = getelementptr inbounds <{ ptr, i32, i32, ptr, ptr, %[[STRUCT_A]] }>, ptr %[[BLOCK]], i32 0, i32 5
// CHECK: call void asm sideeffect "", "r,~{dirflag},~{fpsr},~{flags}"(i32 %{{.*}})
// CHECK: call void asm sideeffect "", "~{dirflag},~{fpsr},~{flags}"()
// CHECK: call void @_ZN1AD1Ev({{.*}} %[[BLOCK_CAPTURED]])

template <class T>
void foo1(A a) {
asm("" : : "r"(^{ (void)a; return 0; }()));
asm("");
}

void test1(A &a) { foo1<void>(a); }
} // namespace TestTemplate
25 changes: 25 additions & 0 deletions clang/test/CodeGenObjC/asm.m
@@ -0,0 +1,25 @@
// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -fblocks -fobjc-arc -emit-llvm -o - %s | FileCheck %s

// CHECK: %[[STRUCT_A:.*]] = type { ptr }

typedef struct {
id f;
} A;

id a;

// Check that the compound literal is destructed at the end of the enclosing scope.

// CHECK-LABEL: define void @foo0()
// CHECK: %[[_COMPOUNDLITERAL:.*]] = alloca %[[STRUCT_A]], align 8
// CHECK: getelementptr inbounds %[[STRUCT_A]], ptr %[[_COMPOUNDLITERAL]], i32 0, i32 0
// CHECK: %[[F1:.*]] = getelementptr inbounds %[[STRUCT_A]], ptr %[[_COMPOUNDLITERAL]], i32 0, i32 0
// CHECK: %[[V2:.*]] = load ptr, ptr %[[F1]], align 8
// CHECK: call void asm sideeffect "", "r,~{dirflag},~{fpsr},~{flags}"(ptr %[[V2]])
// CHECK: call void asm sideeffect "",
// CHECK: call void @__destructor_8_s0(ptr %[[_COMPOUNDLITERAL]])

void foo0() {
asm("" : : "r"(((A){a}).f) );
asm("");
}
16 changes: 16 additions & 0 deletions clang/test/SemaTemplate/instantiate-expr-1.cpp
Expand Up @@ -190,3 +190,19 @@ namespace PR10864 {
test_asm_tied(1.f); // expected-note {{instantiation of}}
}
}

namespace TestAsmCleanup {
struct S {
operator int() const { return 1; }
~S();
};

template <class T>
void foo() {
__asm__ __volatile__("%[i]"
:
: [i] "r"(-S()));
}

void test() { foo<void>(); }
} // namespace TestAsmCleanup

0 comments on commit 8fc3d71

Please sign in to comment.