Author: Bill Wendling Date: 2020-02-24T18:51:29-08:00 New Revision: 50cac248773c3a023e8f6ceb9938bdd5e9f15da2
URL: https://github.com/llvm/llvm-project/commit/50cac248773c3a023e8f6ceb9938bdd5e9f15da2 DIFF: https://github.com/llvm/llvm-project/commit/50cac248773c3a023e8f6ceb9938bdd5e9f15da2.diff LOG: Support output constraints on "asm goto" Summary: Clang's "asm goto" feature didn't initially support outputs constraints. That was the same behavior as gcc's implementation. The decision by gcc not to support outputs was based on a restriction in their IR regarding terminators. LLVM doesn't restrict terminators from returning values (e.g. 'invoke'), so it made sense to support this feature. Output values are valid only on the 'fallthrough' path. If an output value's used on an indirect branch, then it's 'poisoned'. In theory, outputs *could* be valid on the 'indirect' paths, but it's very difficult to guarantee that the original semantics would be retained. E.g. because indirect labels could be used as data, we wouldn't be able to split critical edges in situations where two 'callbr' instructions have the same indirect label, because the indirect branch's destination would no longer be the same. Reviewers: jyknight, nickdesaulniers, hfinkel Reviewed By: jyknight, nickdesaulniers Subscribers: MaskRay, rsmith, hiraditya, llvm-commits, cfe-commits, craig.topper, rnk Tags: #clang, #llvm Differential Revision: https://reviews.llvm.org/D69876 Added: clang/test/Analysis/uninit-asm-goto.cpp Modified: clang/docs/LanguageExtensions.rst clang/include/clang/AST/Stmt.h clang/include/clang/Basic/Features.def clang/lib/AST/Stmt.cpp clang/lib/Analysis/UninitializedValues.cpp clang/lib/CodeGen/CGStmt.cpp clang/lib/Parse/ParseStmtAsm.cpp clang/lib/Sema/SemaStmtAsm.cpp clang/test/CodeGen/asm-goto.c clang/test/Parser/asm-goto.c clang/test/Parser/asm-goto.cpp clang/test/Sema/asm-goto.cpp Removed: ################################################################################ diff --git a/clang/docs/LanguageExtensions.rst b/clang/docs/LanguageExtensions.rst index 7c7f86214a83..a15bf50f7c08 100644 --- a/clang/docs/LanguageExtensions.rst +++ b/clang/docs/LanguageExtensions.rst @@ -1255,6 +1255,34 @@ the clang implementation are in :doc:`Block-ABI-Apple<Block-ABI-Apple>`. Query for this feature with ``__has_extension(blocks)``. +ASM Goto with Output Constraints +================================ + +In addition to the functionality provided by `GCC's extended +assembly`<https://gcc.gnu.org/onlinedocs/gcc/Extended-Asm.html>`_, clang +supports output constraints with the `goto` form. + +The goto form of GCC's extended assembly allows the programmer to branch to a C +label from within an inline assembly block. Clang extends this behavior by +allowing the programmer to use output constraints: + +.. code-block:: c++ + + int foo(int x) { + int y; + asm goto("# %0 %1 %l2" : "=r"(y) : "r"(x) : : err); + return y; + err: + return -1; + } + +It's important to note that outputs are valid only on the "fallthrough" branch. +Using outputs on an indirect branch may result in undefined behavior. For +example, in the function above, use of the value assigned to `y` in the `err` +block is undefined behavior. + +Query for this feature with ``__has_extension(gnu_asm_goto_with_outputs)``. + Objective-C Features ==================== diff --git a/clang/include/clang/AST/Stmt.h b/clang/include/clang/AST/Stmt.h index 24c1abb2be54..5cc4eb8a46df 100644 --- a/clang/include/clang/AST/Stmt.h +++ b/clang/include/clang/AST/Stmt.h @@ -3032,7 +3032,7 @@ class GCCAsmStmt : public AsmStmt { } IdentifierInfo *getLabelIdentifier(unsigned i) const { - return Names[i + NumInputs]; + return Names[i + NumOutputs + NumInputs]; } AddrLabelExpr *getLabelExpr(unsigned i) const; @@ -3043,11 +3043,11 @@ class GCCAsmStmt : public AsmStmt { using labels_const_range = llvm::iterator_range<const_labels_iterator>; labels_iterator begin_labels() { - return &Exprs[0] + NumInputs; + return &Exprs[0] + NumOutputs + NumInputs; } labels_iterator end_labels() { - return &Exprs[0] + NumInputs + NumLabels; + return &Exprs[0] + NumOutputs + NumInputs + NumLabels; } labels_range labels() { @@ -3055,11 +3055,11 @@ class GCCAsmStmt : public AsmStmt { } const_labels_iterator begin_labels() const { - return &Exprs[0] + NumInputs; + return &Exprs[0] + NumOutputs + NumInputs; } const_labels_iterator end_labels() const { - return &Exprs[0] + NumInputs + NumLabels; + return &Exprs[0] + NumOutputs + NumInputs + NumLabels; } labels_const_range labels() const { diff --git a/clang/include/clang/Basic/Features.def b/clang/include/clang/Basic/Features.def index 28eb694ba9a8..20e1b141a3ef 100644 --- a/clang/include/clang/Basic/Features.def +++ b/clang/include/clang/Basic/Features.def @@ -252,6 +252,7 @@ EXTENSION(overloadable_unmarked, true) EXTENSION(pragma_clang_attribute_namespaces, true) EXTENSION(pragma_clang_attribute_external_declaration, true) EXTENSION(gnu_asm, LangOpts.GNUAsm) +EXTENSION(gnu_asm_goto_with_outputs, LangOpts.GNUAsm) #undef EXTENSION #undef FEATURE diff --git a/clang/lib/AST/Stmt.cpp b/clang/lib/AST/Stmt.cpp index 1aea9acc472b..550f5aa338f1 100644 --- a/clang/lib/AST/Stmt.cpp +++ b/clang/lib/AST/Stmt.cpp @@ -457,7 +457,7 @@ void GCCAsmStmt::setInputExpr(unsigned i, Expr *E) { } AddrLabelExpr *GCCAsmStmt::getLabelExpr(unsigned i) const { - return cast<AddrLabelExpr>(Exprs[i + NumInputs]); + return cast<AddrLabelExpr>(Exprs[i + NumOutputs + NumInputs]); } StringRef GCCAsmStmt::getLabelName(unsigned i) const { @@ -523,7 +523,7 @@ int GCCAsmStmt::getNamedOperand(StringRef SymbolicName) const { for (unsigned i = 0, e = getNumLabels(); i != e; ++i) if (getLabelName(i) == SymbolicName) - return i + getNumInputs(); + return i + getNumOutputs() + getNumInputs(); // Not found. return -1; diff --git a/clang/lib/Analysis/UninitializedValues.cpp b/clang/lib/Analysis/UninitializedValues.cpp index ff14e18ec144..a4a900c8146a 100644 --- a/clang/lib/Analysis/UninitializedValues.cpp +++ b/clang/lib/Analysis/UninitializedValues.cpp @@ -475,6 +475,7 @@ class TransferFunctions : public StmtVisitor<TransferFunctions> { void VisitCallExpr(CallExpr *ce); void VisitDeclRefExpr(DeclRefExpr *dr); void VisitDeclStmt(DeclStmt *ds); + void VisitGCCAsmStmt(GCCAsmStmt *as); void VisitObjCForCollectionStmt(ObjCForCollectionStmt *FS); void VisitObjCMessageExpr(ObjCMessageExpr *ME); void VisitOMPExecutableDirective(OMPExecutableDirective *ED); @@ -760,6 +761,16 @@ void TransferFunctions::VisitDeclStmt(DeclStmt *DS) { } } +void TransferFunctions::VisitGCCAsmStmt(GCCAsmStmt *as) { + // An "asm goto" statement is a terminator that may initialize some variables. + if (!as->isAsmGoto()) + return; + + for (const auto &o : as->outputs()) + if (const VarDecl *VD = findVar(o).getDecl()) + vals[VD] = Initialized; +} + void TransferFunctions::VisitObjCMessageExpr(ObjCMessageExpr *ME) { // If the Objective-C message expression is an implicit no-return that // is not modeled in the CFG, set the tracked dataflow values to Unknown. @@ -797,6 +808,10 @@ static bool runOnBlock(const CFGBlock *block, const CFG &cfg, if (Optional<CFGStmt> cs = I.getAs<CFGStmt>()) tf.Visit(const_cast<Stmt *>(cs->getStmt())); } + CFGTerminator terminator = block->getTerminator(); + if (GCCAsmStmt *as = dyn_cast_or_null<GCCAsmStmt>(terminator.getStmt())) + if (as->isAsmGoto()) + tf.Visit(as); return vals.updateValueVectorWithScratch(block); } diff --git a/clang/lib/CodeGen/CGStmt.cpp b/clang/lib/CodeGen/CGStmt.cpp index bf63a1f7128b..a49601f49936 100644 --- a/clang/lib/CodeGen/CGStmt.cpp +++ b/clang/lib/CodeGen/CGStmt.cpp @@ -2211,13 +2211,6 @@ void CodeGenFunction::EmitAsmStmt(const AsmStmt &S) { Constraints += InputConstraint; } - // Append the "input" part of inout constraints last. - for (unsigned i = 0, e = InOutArgs.size(); i != e; i++) { - ArgTypes.push_back(InOutArgTypes[i]); - Args.push_back(InOutArgs[i]); - } - Constraints += InOutConstraints; - // Labels SmallVector<llvm::BasicBlock *, 16> Transfer; llvm::BasicBlock *Fallthrough = nullptr; @@ -2225,7 +2218,7 @@ void CodeGenFunction::EmitAsmStmt(const AsmStmt &S) { if (const auto *GS = dyn_cast<GCCAsmStmt>(&S)) { IsGCCAsmGoto = GS->isAsmGoto(); if (IsGCCAsmGoto) { - for (auto *E : GS->labels()) { + for (const auto *E : GS->labels()) { JumpDest Dest = getJumpDestForLabel(E->getLabel()); Transfer.push_back(Dest.getBlock()); llvm::BlockAddress *BA = @@ -2236,11 +2229,17 @@ void CodeGenFunction::EmitAsmStmt(const AsmStmt &S) { Constraints += ','; Constraints += 'X'; } - StringRef Name = "asm.fallthrough"; - Fallthrough = createBasicBlock(Name); + Fallthrough = createBasicBlock("asm.fallthrough"); } } + // Append the "input" part of inout constraints last. + for (unsigned i = 0, e = InOutArgs.size(); i != e; i++) { + ArgTypes.push_back(InOutArgTypes[i]); + Args.push_back(InOutArgs[i]); + } + Constraints += InOutConstraints; + // Clobbers for (unsigned i = 0, e = S.getNumClobbers(); i != e; i++) { StringRef Clobber = S.getClobber(i); @@ -2293,9 +2292,9 @@ void CodeGenFunction::EmitAsmStmt(const AsmStmt &S) { if (IsGCCAsmGoto) { llvm::CallBrInst *Result = Builder.CreateCallBr(IA, Fallthrough, Transfer, Args); + EmitBlock(Fallthrough); UpdateAsmCallInst(cast<llvm::CallBase>(*Result), HasSideEffect, ReadOnly, ReadNone, S, ResultRegTypes, *this, RegResults); - EmitBlock(Fallthrough); } else { llvm::CallInst *Result = Builder.CreateCall(IA, Args, getBundlesForFunclet(IA)); diff --git a/clang/lib/Parse/ParseStmtAsm.cpp b/clang/lib/Parse/ParseStmtAsm.cpp index ea2c871d6a82..b596aded867d 100644 --- a/clang/lib/Parse/ParseStmtAsm.cpp +++ b/clang/lib/Parse/ParseStmtAsm.cpp @@ -781,12 +781,6 @@ StmtResult Parser::ParseAsmStatement(bool &msAsm) { AteExtraColon = Tok.is(tok::coloncolon); ConsumeToken(); - if (!AteExtraColon && isGotoAsm && Tok.isNot(tok::colon)) { - Diag(Tok, diag::err_asm_goto_cannot_have_output); - SkipUntil(tok::r_paren, StopAtSemi); - return StmtError(); - } - if (!AteExtraColon && ParseAsmOperandsOpt(Names, Constraints, Exprs)) return StmtError(); } diff --git a/clang/lib/Sema/SemaStmtAsm.cpp b/clang/lib/Sema/SemaStmtAsm.cpp index 93faf2d151f9..82a308f35c21 100644 --- a/clang/lib/Sema/SemaStmtAsm.cpp +++ b/clang/lib/Sema/SemaStmtAsm.cpp @@ -478,10 +478,10 @@ StmtResult Sema::ActOnGCCAsmStmt(SourceLocation AsmLoc, bool IsSimple, // Look for the correct constraint index. unsigned ConstraintIdx = Piece.getOperandNo(); + unsigned NumOperands = NS->getNumOutputs() + NS->getNumInputs(); // Labels are the last in the Exprs list. - if (NS->isAsmGoto() && ConstraintIdx >= NS->getNumInputs()) + if (NS->isAsmGoto() && ConstraintIdx >= NumOperands) continue; - unsigned NumOperands = NS->getNumOutputs() + NS->getNumInputs(); // Look for the (ConstraintIdx - NumOperands + 1)th constraint with // modifier '+'. if (ConstraintIdx >= NumOperands) { diff --git a/clang/test/Analysis/uninit-asm-goto.cpp b/clang/test/Analysis/uninit-asm-goto.cpp new file mode 100644 index 000000000000..ce2ca81d944f --- /dev/null +++ b/clang/test/Analysis/uninit-asm-goto.cpp @@ -0,0 +1,10 @@ +// RUN: %clang_cc1 -std=c++11 -Wuninitialized -verify %s +// expected-no-diagnostics + +int test1(int x) { + int y; + asm goto("# %0 %1 %2" : "=r"(y) : "r"(x) : : err); + return y; + err: + return -1; +} diff --git a/clang/test/CodeGen/asm-goto.c b/clang/test/CodeGen/asm-goto.c index 7692fbc6797b..c322d4560f5a 100644 --- a/clang/test/CodeGen/asm-goto.c +++ b/clang/test/CodeGen/asm-goto.c @@ -2,19 +2,104 @@ // RUN: %clang_cc1 -triple x86_64-pc-linux-gnu -O0 -emit-llvm %s -o - | FileCheck %s // RUN: %clang_cc1 -triple i386-pc-linux-gnu -O0 -emit-llvm %s -o - | FileCheck %s -int foo(int cond) -{ +int test1(int cond) { + // CHECK-LABEL: define i32 @test1( // CHECK: callbr void asm sideeffect // CHECK: to label %asm.fallthrough [label %label_true, label %loop] - // CHECK: asm.fallthrough: - asm volatile goto("testl %0, %0; jne %l1;" :: "r"(cond)::label_true, loop); + // CHECK-LABEL: asm.fallthrough: asm volatile goto("testl %0, %0; jne %l1;" :: "r"(cond)::label_true, loop); + asm volatile goto("testl %0, %0; jne %l2;" :: "r"(cond)::label_true, loop); // CHECK: callbr void asm sideeffect // CHECK: to label %asm.fallthrough1 [label %label_true, label %loop] - // CHECK: asm.fallthrough1: + // CHECK-LABEL: asm.fallthrough1: + return 0; +loop: + return 0; +label_true: + return 1; +} + +int test2(int cond) { + // CHECK-LABEL: define i32 @test2( + // CHECK: callbr i32 asm sideeffect + // CHECK: to label %asm.fallthrough [label %label_true, label %loop] + // CHECK-LABEL: asm.fallthrough: + asm volatile goto("testl %0, %0; jne %l2;" : "=r"(cond) : "r"(cond) :: label_true, loop); + asm volatile goto("testl %0, %0; jne %l3;" : "=r"(cond) : "r"(cond) :: label_true, loop); + // CHECK: callbr i32 asm sideeffect + // CHECK: to label %asm.fallthrough1 [label %label_true, label %loop] + // CHECK-LABEL: asm.fallthrough1: + return 0; +loop: + return 0; +label_true: + return 1; +} + +int test3(int out1, int out2) { + // CHECK-LABEL: define i32 @test3( + // CHECK: callbr { i32, i32 } asm sideeffect + // CHECK: to label %asm.fallthrough [label %label_true, label %loop] + // CHECK-LABEL: asm.fallthrough: + asm volatile goto("testl %0, %0; jne %l3;" : "=r"(out1), "=r"(out2) : "r"(out1) :: label_true, loop); + asm volatile goto("testl %0, %0; jne %l4;" : "=r"(out1), "=r"(out2) : "r"(out1) :: label_true, loop); + // CHECK: callbr { i32, i32 } asm sideeffect + // CHECK: to label %asm.fallthrough2 [label %label_true, label %loop] + // CHECK-LABEL: asm.fallthrough2: return 0; loop: return 0; label_true: return 1; } + +int test4(int out1, int out2) { + // CHECK-LABEL: define i32 @test4( + // CHECK: callbr { i32, i32 } asm sideeffect "jne ${3:l}", "={si},={di},r,X,X,0,1 + // CHECK: to label %asm.fallthrough [label %label_true, label %loop] + // CHECK-LABEL: asm.fallthrough: + if (out1 < out2) + asm volatile goto("jne %l3" : "+S"(out1), "+D"(out2) : "r"(out1) :: label_true, loop); + else + asm volatile goto("jne %l5" : "+S"(out1), "+D"(out2) : "r"(out1), "r"(out2) :: label_true, loop); + // CHECK: callbr { i32, i32 } asm sideeffect "jne ${5:l}", "={si},={di},r,r,X,X,0,1 + // CHECK: to label %asm.fallthrough2 [label %label_true, label %loop] + // CHECK-LABEL: asm.fallthrough2: + return out1 + out2; +loop: + return -1; +label_true: + return -2; +} + +int test5(int addr, int size, int limit) { + // CHECK-LABEL: define i32 @test5( + // CHECK: callbr i32 asm "add $1,$0 ; jc ${3:l} ; cmp $2,$0 ; ja ${3:l} ; ", "=r,imr,imr,X,0 + // CHECK: to label %asm.fallthrough [label %t_err] + // CHECK-LABEL: asm.fallthrough: + asm goto( + "add %1,%0 ; " + "jc %l[t_err] ; " + "cmp %2,%0 ; " + "ja %l[t_err] ; " + : "+r" (addr) + : "g" (size), "g" (limit) + : : t_err); + return 0; +t_err: + return 1; +} + +int test6(int out1) { + // CHECK-LABEL: define i32 @test6( + // CHECK: callbr i32 asm sideeffect "testl $0, $0; testl $1, $1; jne ${2:l}", "={si},r,X,X,0,{{.*}} i8* blockaddress(@test6, %label_true), i8* blockaddress(@test6, %landing) + // CHECK: to label %asm.fallthrough [label %label_true, label %landing] + // CHECK-LABEL: asm.fallthrough: + // CHECK-LABEL: landing: + int out2 = 42; + asm volatile goto("testl %0, %0; testl %1, %1; jne %l2" : "+S"(out2) : "r"(out1) :: label_true, landing); +landing: + return out1 + out2; +label_true: + return -2; +} diff --git a/clang/test/Parser/asm-goto.c b/clang/test/Parser/asm-goto.c index 7f8edb111563..f9ad6c5ee9a4 100644 --- a/clang/test/Parser/asm-goto.c +++ b/clang/test/Parser/asm-goto.c @@ -4,13 +4,13 @@ #if !__has_extension(gnu_asm) #error Extension 'gnu_asm' should be available by default #endif - +#if !__has_extension(gnu_asm_goto_with_outputs) +#error Extension 'gnu_asm_goto_with_outputs' should be available by default +#endif int a, b, c, d, e, f, g, h, i, j, k, l; -void -fgoto1 (void) -{ +void test(void) { __asm__ volatile goto ("" :: [a] "r" (a), [b] "r" (b), [c] "r" (c), [d] "r" (d), [e] "r" (e), [f] "r" (f), [g] "r" (g), [h] "r" (h), @@ -20,9 +20,7 @@ lab1: return; lab2: return; } -void -fgoto2 (void) -{ +void test2(void) { __asm__ volatile goto ("" :: [a] "r,m" (a), [b] "r,m" (b), [c] "r,m" (c), [d] "r,m" (d), [e] "r,m" (e), [f] "r,m" (f), [g] "r,m" (g), [h] "r,m" (h), @@ -31,14 +29,33 @@ fgoto2 (void) lab: return; } -int zoo () -{ +int test3(int x) { + __asm__ volatile goto ("decl %0; jnz %l[a]" + : "=r" (x) : "m" (x) : "memory" : a); +a: + return -x; +} + +int test4(int x) { + int y; + if (x > 42) + __asm__ volatile goto ("decl %0; jnz %l[a]" + : "=r" (x), "=r" (y) : "m" (x) : "memory" : a); + else + __asm__ volatile goto ("decl %0; jnz %l[b]" + : "=r" (x), "=r" (y) : "m" (x) : "memory" : b); + x = y + 42; +a: + return -x; +b: + return +x; +} + +int test5(void) { int x,cond,*e; // expected-error@+1 {{expected ')'}} asm ("mov %[e], %[e]" : : [e] "rm" (*e)::a) - // expected-error@+1 {{'asm goto' cannot have output constraints}} - asm goto ("decl %0; jnz %l[a]" :"=r"(x): "m"(x) : "memory" : a); - // expected-error@+1 {{expected identifie}} + // expected-error@+1 {{expected identifier}} asm goto ("decl %0;" :: "m"(x) : "memory" : ); // expected-error@+1 {{expected ':'}} asm goto ("decl %0;" :: "m"(x) : "memory" ); @@ -55,3 +72,25 @@ int zoo () loop: return 0; } + +int test6(int y) { + int x,cond,*e; + // expected-error@+1 {{expected ')'}} + asm ("mov %[e], %[e]" : "=r" (y) : [e] "rm" (*e), "r" (y) :: a) + // expected-error@+1 {{expected identifier}} + asm goto ("decl %0;" : "=r" (y) : "m" (x), "r" (y) : "memory" :); + // expected-error@+1 {{expected ':'}} + asm goto ("decl %0;" : "=r" (y) : "m" (x), "r" (y) : "memory"); + // expected-error@+1 {{use of undeclared label 'x'}} + asm goto ("decl %0;" : "=r" (y) : "m" (x), "r" (y) : "memory" : x); + // expected-error@+1 {{use of undeclared label 'b'}} + asm goto ("decl %0;" : "=r" (y) : "m" (x), "r" (y) : "memory" : b); + // expected-error@+1 {{invalid operand number in inline asm string}} + asm goto ("testl %0, %0; jne %l5;" : "=r" (y) : "r" (cond), "r" (y) :: label_true, loop); + // expected-error@+1 {{unknown symbolic operand name in inline assembly string}} + asm goto ("decl %0; jnz %l[b]" : "=r" (y) : "m" (x), "r" (y) : "memory" : a); +label_true: +loop: +a: + return 0; +} diff --git a/clang/test/Parser/asm-goto.cpp b/clang/test/Parser/asm-goto.cpp index f09466ca488d..faff6113cad6 100644 --- a/clang/test/Parser/asm-goto.cpp +++ b/clang/test/Parser/asm-goto.cpp @@ -1,14 +1,54 @@ // RUN: %clang_cc1 -triple i386-pc-linux-gnu -fsyntax-only -verify -std=c++11 %s // RUN: %clang_cc1 -triple x86_64-pc-linux-gnu -fsyntax-only -verify -std=c++11 %s -int zoo () -{ +int a, b, c, d, e, f, g, h, i, j, k, l; + +void test1(void) { + __asm__ volatile goto ("" + :: [a] "r" (a), [b] "r" (b), [c] "r" (c), [d] "r" (d), + [e] "r" (e), [f] "r" (f), [g] "r" (g), [h] "r" (h), + [i] "r" (i), [j] "r" (j), [k] "r" (k), [l] "r" (l) + ::lab1,lab2); +lab1: return; +lab2: return; +} + +void test2(void) { + __asm__ volatile goto ("" + :: [a] "r,m" (a), [b] "r,m" (b), [c] "r,m" (c), [d] "r,m" (d), + [e] "r,m" (e), [f] "r,m" (f), [g] "r,m" (g), [h] "r,m" (h), + [i] "r,m" (i), [j] "r,m" (j), [k] "r,m" (k), [l] "r,m" (l) + :: lab); + lab: return; +} + +int test3(int x) { + __asm__ volatile goto ("decl %0; jnz %l[a]" + : "=r" (x) : "m" (x) : "memory" : a); +a: + return -x; +} + +int test4(int x) { + int y; + if (x > 42) + __asm__ volatile goto ("decl %0; jnz %l[a]" + : "=r" (x), "=r" (y) : "m" (x) : "memory" : a); + else + __asm__ volatile goto ("decl %0; jnz %l[b]" + : "=r" (x), "=r" (y) : "m" (x) : "memory" : b); + x = y + 42; +a: + return -x; +b: + return +x; +} + +int test5(void) { int x,cond,*e; // expected-error@+1 {{expected ')'}} asm ("mov %[e], %[e]" : : [e] "rm" (*e)::a) - // expected-error@+1 {{'asm goto' cannot have output constraints}} - asm goto ("decl %0; jnz %l[a]" :"=r"(x): "m"(x) : "memory" : a); - // expected-error@+1 {{expected identifie}} + // expected-error@+1 {{expected identifier}} asm goto ("decl %0;" :: "m"(x) : "memory" : ); // expected-error@+1 {{expected ':'}} asm goto ("decl %0;" :: "m"(x) : "memory" ); @@ -26,28 +66,24 @@ int zoo () return 0; } - -int a, b, c, d, e, f, g, h, i, j, k, l; - -void -fgoto1 (void) -{ - __asm__ volatile goto ("" - :: [a] "r" (a), [b] "r" (b), [c] "r" (c), [d] "r" (d), - [e] "r" (e), [f] "r" (f), [g] "r" (g), [h] "r" (h), - [i] "r" (i), [j] "r" (j), [k] "r" (k), [l] "r" (l) - ::lab1,lab2); -lab1: return; -lab2: return; -} - -void -fgoto2 (void) -{ - __asm__ volatile goto ("" - :: [a] "r,m" (a), [b] "r,m" (b), [c] "r,m" (c), [d] "r,m" (d), - [e] "r,m" (e), [f] "r,m" (f), [g] "r,m" (g), [h] "r,m" (h), - [i] "r,m" (i), [j] "r,m" (j), [k] "r,m" (k), [l] "r,m" (l) - :: lab); - lab: return; +int test6(int y) { + int x,cond,*e; + // expected-error@+1 {{expected ')'}} + asm ("mov %[e], %[e]" : "=r" (y) : [e] "rm" (*e), "r" (y) :: a) + // expected-error@+1 {{expected identifier}} + asm goto ("decl %0;" : "=r" (y) : "m" (x), "r" (y) : "memory" :); + // expected-error@+1 {{expected ':'}} + asm goto ("decl %0;" : "=r" (y) : "m" (x), "r" (y) : "memory"); + // expected-error@+1 {{use of undeclared label 'x'}} + asm goto ("decl %0;" : "=r" (y) : "m" (x), "r" (y) : "memory" : x); + // expected-error@+1 {{use of undeclared label 'b'}} + asm goto ("decl %0;" : "=r" (y) : "m" (x), "r" (y) : "memory" : b); + // expected-error@+1 {{invalid operand number in inline asm string}} + asm goto ("testl %0, %0; jne %l5;" : "=r" (y) : "r" (cond), "r" (y) :: label_true, loop); + // expected-error@+1 {{unknown symbolic operand name in inline assembly string}} + asm goto ("decl %0; jnz %l[b]" : "=r" (y) : "m" (x), "r" (y) : "memory" : a); +label_true: +loop: +a: + return 0; } diff --git a/clang/test/Sema/asm-goto.cpp b/clang/test/Sema/asm-goto.cpp index d85730974359..64addd9d75b6 100644 --- a/clang/test/Sema/asm-goto.cpp +++ b/clang/test/Sema/asm-goto.cpp @@ -1,38 +1,38 @@ // RUN: %clang_cc1 %s -triple i386-pc-linux-gnu -verify -fsyntax-only // RUN: %clang_cc1 %s -triple x86_64-pc-linux-gnu -verify -fsyntax-only -struct NonTrivial { - ~NonTrivial(); +struct S { + ~S(); int f(int); private: int k; }; -void JumpDiagnostics(int n) { +void test1(int n) { // expected-error@+1 {{cannot jump from this goto statement to its label}} goto DirectJump; // expected-note@+1 {{jump bypasses variable with a non-trivial destructor}} - NonTrivial tnp1; + S s1; DirectJump: // expected-error@+1 {{cannot jump from this asm goto statement to one of its possible targets}} asm goto("jmp %l0;" ::::Later); // expected-note@+1 {{jump bypasses variable with a non-trivial destructor}} - NonTrivial tnp2; + S s2; // expected-note@+1 {{possible target of asm goto statement}} Later: return; } -struct S { ~S(); }; -void foo(int a) { +struct T { ~T(); }; +void test2(int a) { if (a) { FOO: // expected-note@+2 {{jump exits scope of variable with non-trivial destructor}} // expected-note@+1 {{jump exits scope of variable with non-trivial destructor}} - S s; + T t; void *p = &&BAR; // expected-error@+1 {{cannot jump from this asm goto statement to one of its possible targets}} - asm goto("jmp %l0;" ::::BAR); + asm goto("jmp %l0;" ::::BAR); // expected-error@+1 {{cannot jump from this indirect goto statement to one of its possible targets}} goto *p; p = &&FOO; @@ -45,9 +45,7 @@ void foo(int a) { return; } - -//Asm goto: -int test16(int n) +int test3(int n) { // expected-error@+2 {{cannot jump from this asm goto statement to one of its possible targets}} // expected-error@+1 {{cannot jump from this asm goto statement to one of its possible targets}} _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits