]> granicus.if.org Git - clang/commitdiff
add one more case of mismatched input/output constraints.
authorChris Lattner <sabre@nondot.org>
Mon, 21 Feb 2011 22:09:29 +0000 (22:09 +0000)
committerChris Lattner <sabre@nondot.org>
Mon, 21 Feb 2011 22:09:29 +0000 (22:09 +0000)
When the mismatch is due to a larger input operand that is
a constant, truncate it down to the size of the output.  This
allows us to accept some cases in the linux kernel and elsewhere.
Pedantically speaking, we generate different code than GCC, though
I can't imagine how it would matter:

Clang:
movb $-1, %al
frob %al

GCC:

movl $255, %eax
frob %al

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@126148 91177308-0d34-0410-b5e6-96231b3b80d8

include/clang/AST/Stmt.h
lib/AST/Stmt.cpp
lib/Sema/SemaStmt.cpp
test/CodeGen/asm-inout.c

index 7ede9ce323f4ecc7e249525a1ca3bfcc03dbdf7a..d1f7d667f33d8d6bd130cbc6d8efd15f8d788338 100644 (file)
@@ -1328,7 +1328,8 @@ public:
   }
 
   Expr *getInputExpr(unsigned i);
-
+  void setInputExpr(unsigned i, Expr *E);
+  
   const Expr *getInputExpr(unsigned i) const {
     return const_cast<AsmStmt*>(this)->getInputExpr(i);
   }
index 7e73f02e67e7d48d0239f806432767dcf5c73bf4..8a80275aa1657f3ee85fbd629ab7b8295ea978e6 100644 (file)
@@ -218,6 +218,10 @@ unsigned AsmStmt::getNumPlusOperands() const {
 Expr *AsmStmt::getInputExpr(unsigned i) {
   return cast<Expr>(Exprs[i + NumOutputs]);
 }
+void AsmStmt::setInputExpr(unsigned i, Expr *E) {
+  Exprs[i + NumOutputs] = E;
+}
+
 
 /// getInputConstraint - Return the specified input constraint.  Unlike output
 /// constraints, these can be empty.
index 6801dd4c2ebe5b8ef3bd8ccd0c5f4527e5a8981b..3815deae58fb4b99f834e9afa6b25a76744175c1 100644 (file)
@@ -1542,8 +1542,9 @@ StmtResult Sema::ActOnAsmStmt(SourceLocation AsmLoc, bool IsSimple,
     if (!Info.hasTiedOperand()) continue;
 
     unsigned TiedTo = Info.getTiedOperand();
+    unsigned InputOpNo = i+NumOutputs;
     Expr *OutputExpr = Exprs[TiedTo];
-    Expr *InputExpr = Exprs[i+NumOutputs];
+    Expr *InputExpr = Exprs[InputOpNo];
     QualType InTy = InputExpr->getType();
     QualType OutTy = OutputExpr->getType();
     if (Context.hasSameType(InTy, OutTy))
@@ -1588,7 +1589,7 @@ StmtResult Sema::ActOnAsmStmt(SourceLocation AsmLoc, bool IsSimple,
     
     // If this is a reference to the input and if the input was the smaller
     // one, then we have to reject this asm.
-    if (isOperandMentioned(i+NumOutputs, Pieces)) {
+    if (isOperandMentioned(InputOpNo, Pieces)) {
       // This is a use in the asm string of the smaller operand.  Since we
       // codegen this by promoting to a wider value, the asm will get printed
       // "wrong".
@@ -1607,6 +1608,19 @@ StmtResult Sema::ActOnAsmStmt(SourceLocation AsmLoc, bool IsSimple,
         OutputConstraintInfos[TiedTo].allowsRegister())
       continue;
     
+    // Either both of the operands were mentioned or the smaller one was
+    // mentioned.  One more special case that we'll allow: if the tied input is
+    // integer, unmentioned, and is a constant, then we'll allow truncating it
+    // down to the size of the destination.
+    if (InputDomain == AD_Int && OutputDomain == AD_Int &&
+        !isOperandMentioned(InputOpNo, Pieces) &&
+        InputExpr->isEvaluatable(Context)) {
+      ImpCastExprToType(InputExpr, OutTy, CK_IntegralCast);
+      Exprs[InputOpNo] = InputExpr;
+      NS->setInputExpr(i, InputExpr);
+      continue;
+    }
+    
     Diag(InputExpr->getLocStart(),
          diag::err_asm_tying_incompatible_types)
       << InTy << OutTy << OutputExpr->getSourceRange()
index 5b0a5f7ef16adbe7297ae580e58159dca961a60d..29142f7c5592d47e066491e24ad58461464f4b5d 100644 (file)
@@ -29,3 +29,12 @@ asm(
                : "edi"
                );
 }
+
+// PR8959 - This should implicitly truncate the immediate to a byte.
+int test4(volatile int *addr) {
+  unsigned char oldval;
+  __asm__ ("frob %0" : "=r"(oldval) : "0"(0xff));
+  return (int)oldval;
+// CHECK: call i8 asm "frob $0", "=r,0{{.*}}"(i8 -1)
+}
+