aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChris Lattner <sabre@nondot.org>2011-02-21 22:09:29 +0000
committerChris Lattner <sabre@nondot.org>2011-02-21 22:09:29 +0000
commit935f0f01c1ed3c2052b797ac035d57a85b78adc4 (patch)
treeb55ef3e832410363c4faa8fdba992a497c73b891
parentf0c4d28020fb13fdbf7d6fccfab1b7b6a118ad0e (diff)
add one more case of mismatched input/output constraints.
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
-rw-r--r--include/clang/AST/Stmt.h3
-rw-r--r--lib/AST/Stmt.cpp4
-rw-r--r--lib/Sema/SemaStmt.cpp18
-rw-r--r--test/CodeGen/asm-inout.c9
4 files changed, 31 insertions, 3 deletions
diff --git a/include/clang/AST/Stmt.h b/include/clang/AST/Stmt.h
index 7ede9ce323..d1f7d667f3 100644
--- a/include/clang/AST/Stmt.h
+++ b/include/clang/AST/Stmt.h
@@ -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);
}
diff --git a/lib/AST/Stmt.cpp b/lib/AST/Stmt.cpp
index 7e73f02e67..8a80275aa1 100644
--- a/lib/AST/Stmt.cpp
+++ b/lib/AST/Stmt.cpp
@@ -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.
diff --git a/lib/Sema/SemaStmt.cpp b/lib/Sema/SemaStmt.cpp
index 6801dd4c2e..3815deae58 100644
--- a/lib/Sema/SemaStmt.cpp
+++ b/lib/Sema/SemaStmt.cpp
@@ -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()
diff --git a/test/CodeGen/asm-inout.c b/test/CodeGen/asm-inout.c
index 5b0a5f7ef1..29142f7c55 100644
--- a/test/CodeGen/asm-inout.c
+++ b/test/CodeGen/asm-inout.c
@@ -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)
+}
+