Index: test/CodeGen/asm-const-type-qualifier.c =================================================================== --- test/CodeGen/asm-const-type-qualifier.c (revision 0) +++ test/CodeGen/asm-const-type-qualifier.c (revision 0) @@ -0,0 +1,29 @@ +// RUN: %clang_cc1 -O3 -triple x86_64-apple-darwin10 -emit-llvm %s -o - | FileCheck %s + +void **foo(void) { + void *ptr; + asm const("mov $0x12345678, %0" : "=r" (ptr)); + return ptr; +} +// Check for the constant type-qualifier and readnone attribute +// CHECK: @foo +// CHECK: entry: +// CHECK: call i8* asm constant "mov $$0x12345678, $0", "=r,~{dirflag},~{fpsr},~{flags}"() nounwind readnone +// CHECK: ret + +static inline void **varptr(void) { + void *ptr; + asm const("mov $0x12345678, %0" : "=r" (ptr)); + return ptr; +} +static inline void *getvar(void) { return *varptr(); } +static inline void setvar(void *value) { *varptr() = value; } +void fn(void) { if (getvar()) setvar(0); } + +// Check to see if the second inline asm is CSE'ed after inlining +// CHECK: @fn +// CHECK: entry: +// CHECK: call i8* asm constant "mov $$0x12345678, $0", "=r,~{dirflag},~{fpsr},~{flags}"() nounwind readnone +// CHECK-NOT: call i8* asm constant "mov $$0x12345678, $0", "=r,~{dirflag},~{fpsr},~{flags}"() nounwind readnone +// CHECK: ret + Index: include/clang/Sema/Sema.h =================================================================== --- include/clang/Sema/Sema.h (revision 156383) +++ include/clang/Sema/Sema.h (working copy) @@ -2490,7 +2490,7 @@ StmtResult ActOnCapScopeReturnStmt(SourceLocation ReturnLoc, Expr *RetValExp); StmtResult ActOnAsmStmt(SourceLocation AsmLoc, - bool IsSimple, bool IsVolatile, + bool IsSimple, bool IsVolatile, bool IsConst, unsigned NumOutputs, unsigned NumInputs, IdentifierInfo **Names, MultiExprArg Constraints, Index: include/clang/AST/Stmt.h =================================================================== --- include/clang/AST/Stmt.h (revision 156383) +++ include/clang/AST/Stmt.h (working copy) @@ -1366,6 +1366,7 @@ bool IsSimple; bool IsVolatile; + bool IsConst; bool MSAsm; unsigned NumOutputs; @@ -1380,7 +1381,7 @@ public: AsmStmt(ASTContext &C, SourceLocation asmloc, bool issimple, bool isvolatile, - bool msasm, unsigned numoutputs, unsigned numinputs, + bool isconst, bool msasm, unsigned numoutputs, unsigned numinputs, IdentifierInfo **names, StringLiteral **constraints, Expr **exprs, StringLiteral *asmstr, unsigned numclobbers, StringLiteral **clobbers, SourceLocation rparenloc); @@ -1396,6 +1397,8 @@ bool isVolatile() const { return IsVolatile; } void setVolatile(bool V) { IsVolatile = V; } + bool isConst() const { return IsConst; } + void setConst(bool C) { IsConst = C; } bool isSimple() const { return IsSimple; } void setSimple(bool V) { IsSimple = V; } bool isMSAsm() const { return MSAsm; } Index: lib/Sema/TreeTransform.h =================================================================== --- lib/Sema/TreeTransform.h (revision 156383) +++ lib/Sema/TreeTransform.h (working copy) @@ -1164,6 +1164,7 @@ StmtResult RebuildAsmStmt(SourceLocation AsmLoc, bool IsSimple, bool IsVolatile, + bool IsConst, unsigned NumOutputs, unsigned NumInputs, IdentifierInfo **Names, @@ -1173,9 +1174,9 @@ MultiExprArg Clobbers, SourceLocation RParenLoc, bool MSAsm) { - return getSema().ActOnAsmStmt(AsmLoc, IsSimple, IsVolatile, NumOutputs, - NumInputs, Names, move(Constraints), - Exprs, AsmString, Clobbers, + return getSema().ActOnAsmStmt(AsmLoc, IsSimple, IsVolatile, IsConst, + NumOutputs, NumInputs, Names, + move(Constraints), Exprs, AsmString, Clobbers, RParenLoc, MSAsm); } @@ -5591,6 +5592,7 @@ return getDerived().RebuildAsmStmt(S->getAsmLoc(), S->isSimple(), S->isVolatile(), + S->isConst(), S->getNumOutputs(), S->getNumInputs(), Names.data(), Index: lib/Sema/SemaStmt.cpp =================================================================== --- lib/Sema/SemaStmt.cpp (revision 156383) +++ lib/Sema/SemaStmt.cpp (working copy) @@ -2420,7 +2420,7 @@ } StmtResult Sema::ActOnAsmStmt(SourceLocation AsmLoc, bool IsSimple, - bool IsVolatile, unsigned NumOutputs, + bool IsVolatile, bool IsConst,unsigned NumOutputs, unsigned NumInputs, IdentifierInfo **Names, MultiExprArg constraints, MultiExprArg exprs, Expr *asmString, MultiExprArg clobbers, @@ -2529,7 +2529,7 @@ } AsmStmt *NS = - new (Context) AsmStmt(Context, AsmLoc, IsSimple, IsVolatile, MSAsm, + new (Context) AsmStmt(Context, AsmLoc, IsSimple, IsVolatile, IsConst, MSAsm, NumOutputs, NumInputs, Names, Constraints, Exprs, AsmString, NumClobbers, Clobbers, RParenLoc); // Validate the asm string, ensuring it makes sense given the operands we Index: lib/AST/Stmt.cpp =================================================================== --- lib/AST/Stmt.cpp (revision 156383) +++ lib/AST/Stmt.cpp (working copy) @@ -526,13 +526,13 @@ //===----------------------------------------------------------------------===// AsmStmt::AsmStmt(ASTContext &C, SourceLocation asmloc, bool issimple, - bool isvolatile, bool msasm, + bool isvolatile, bool isconst, bool msasm, unsigned numoutputs, unsigned numinputs, IdentifierInfo **names, StringLiteral **constraints, Expr **exprs, StringLiteral *asmstr, unsigned numclobbers, StringLiteral **clobbers, SourceLocation rparenloc) : Stmt(AsmStmtClass), AsmLoc(asmloc), RParenLoc(rparenloc), AsmStr(asmstr) - , IsSimple(issimple), IsVolatile(isvolatile), MSAsm(msasm) + , IsSimple(issimple), IsVolatile(isvolatile), IsConst(isconst), MSAsm(msasm) , NumOutputs(numoutputs), NumInputs(numinputs), NumClobbers(numclobbers) { unsigned NumExprs = NumOutputs +NumInputs; Index: lib/CodeGen/CGStmt.cpp =================================================================== --- lib/CodeGen/CGStmt.cpp (revision 156383) +++ lib/CodeGen/CGStmt.cpp (working copy) @@ -1630,9 +1630,12 @@ llvm::InlineAsm *IA = llvm::InlineAsm::get(FTy, AsmString, Constraints, - S.isVolatile() || S.getNumOutputs() == 0); + S.isVolatile() || S.getNumOutputs() == 0, + /* isAlignStack */false, S.isConst()); llvm::CallInst *Result = Builder.CreateCall(IA, Args); Result->addAttribute(~0, llvm::Attribute::NoUnwind); + if (S.isConst()) + Result->addAttribute(~0, llvm::Attribute::ReadNone); // Slap the source location of the inline asm into a !srcloc metadata on the // call. Index: lib/Parse/ParseStmt.cpp =================================================================== --- lib/Parse/ParseStmt.cpp (revision 156383) +++ lib/Parse/ParseStmt.cpp (working copy) @@ -1733,7 +1733,7 @@ ExprVector Constraints(Actions); ExprVector Exprs(Actions); ExprVector Clobbers(Actions); - return Actions.ActOnAsmStmt(AsmLoc, true, true, 0, 0, 0, + return Actions.ActOnAsmStmt(AsmLoc, true, true, false, 0, 0, 0, move_arg(Constraints), move_arg(Exprs), AsmString.take(), move_arg(Clobbers), EndLoc, true); @@ -1783,12 +1783,12 @@ ParseTypeQualifierListOpt(DS, true, false); // GNU asms accept, but warn, about type-qualifiers other than volatile. - if (DS.getTypeQualifiers() & DeclSpec::TQ_const) - Diag(Loc, diag::w_asm_qualifier_ignored) << "const"; + // However, clang does support the const type-qualifier. if (DS.getTypeQualifiers() & DeclSpec::TQ_restrict) Diag(Loc, diag::w_asm_qualifier_ignored) << "restrict"; - // Remember if this was a volatile asm. + // Remember if this was a const/volatile asm. + bool isConst = DS.getTypeQualifiers() & DeclSpec::TQ_const; bool isVolatile = DS.getTypeQualifiers() & DeclSpec::TQ_volatile; if (Tok.isNot(tok::l_paren)) { Diag(Tok, diag::err_expected_lparen_after) << "asm"; @@ -1813,7 +1813,7 @@ if (Tok.is(tok::r_paren)) { // We have a simple asm expression like 'asm("foo")'. T.consumeClose(); - return Actions.ActOnAsmStmt(AsmLoc, /*isSimple*/ true, isVolatile, + return Actions.ActOnAsmStmt(AsmLoc, /*isSimple*/ true, isVolatile, isConst, /*NumOutputs*/ 0, /*NumInputs*/ 0, 0, move_arg(Constraints), move_arg(Exprs), AsmString.take(), move_arg(Clobbers), @@ -1878,7 +1878,7 @@ } T.consumeClose(); - return Actions.ActOnAsmStmt(AsmLoc, false, isVolatile, + return Actions.ActOnAsmStmt(AsmLoc, false, isVolatile, isConst, NumOutputs, NumInputs, Names.data(), move_arg(Constraints), move_arg(Exprs), AsmString.take(), move_arg(Clobbers),