aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-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)
+}
+