Index: include/clang/AST/APValue.h =================================================================== --- include/clang/AST/APValue.h +++ include/clang/AST/APValue.h @@ -262,6 +262,12 @@ return const_cast(this)->getInt(); } + /// Try to convert this value to an integral constant. This works if it's an + /// integer, null pointer, or offset from a null pointer. Returns true on + /// success. + bool toIntegralConstant(APSInt &Result, QualType SrcTy, + const ASTContext &Ctx) const; + APFloat &getFloat() { assert(isFloat() && "Invalid accessor"); return *(APFloat*)(char*)Data.buffer; Index: lib/AST/APValue.cpp =================================================================== --- lib/AST/APValue.cpp +++ lib/AST/APValue.cpp @@ -614,6 +614,26 @@ return Result; } +bool APValue::toIntegralConstant(APSInt &Result, QualType SrcTy, + const ASTContext &Ctx) const { + if (isInt()) { + Result = getInt(); + return true; + } + + if (isLValue() && isNullPointer()) { + Result = Ctx.MakeIntValue(Ctx.getTargetNullPointerValue(SrcTy), SrcTy); + return true; + } + + if (isLValue() && !getLValueBase()) { + Result = Ctx.MakeIntValue(getLValueOffset().getQuantity(), SrcTy); + return true; + } + + return false; +} + const APValue::LValueBase APValue::getLValueBase() const { assert(isLValue() && "Invalid accessor"); return ((const LV*)(const void*)Data.buffer)->Base; Index: lib/AST/ExprConstant.cpp =================================================================== --- lib/AST/ExprConstant.cpp +++ lib/AST/ExprConstant.cpp @@ -9872,13 +9872,12 @@ return true; } - uint64_t V; - if (LV.isNullPointer()) - V = Info.Ctx.getTargetNullPointerValue(SrcType); - else - V = LV.getLValueOffset().getQuantity(); + APSInt AsInt; + APValue V; + LV.moveInto(V); + if (!V.toIntegralConstant(AsInt, SrcType, Info.Ctx)) + llvm_unreachable("Can't cast this!"); - APSInt AsInt = Info.Ctx.MakeIntValue(V, SrcType); return Success(HandleIntToIntCast(Info, E, DestType, SrcType, AsInt), E); } Index: lib/CodeGen/CGStmt.cpp =================================================================== --- lib/CodeGen/CGStmt.cpp +++ lib/CodeGen/CGStmt.cpp @@ -1838,8 +1838,15 @@ // (immediate or symbolic), try to emit it as such. if (!Info.allowsRegister() && !Info.allowsMemory()) { if (Info.requiresImmediateConstant()) { - llvm::APSInt AsmConst = InputExpr->EvaluateKnownConstInt(getContext()); - return llvm::ConstantInt::get(getLLVMContext(), AsmConst); + Expr::EvalResult EVResult; + InputExpr->EvaluateAsRValue(EVResult, getContext(), true); + + llvm::APSInt IntResult; + if (!EVResult.Val.toIntegralConstant(IntResult, InputExpr->getType(), + getContext())) + llvm_unreachable("Invalid immediate constant!"); + + return llvm::ConstantInt::get(getLLVMContext(), IntResult); } Expr::EvalResult Result; Index: lib/Sema/SemaStmtAsm.cpp =================================================================== --- lib/Sema/SemaStmtAsm.cpp +++ lib/Sema/SemaStmtAsm.cpp @@ -385,11 +385,20 @@ return StmtError( Diag(InputExpr->getBeginLoc(), diag::err_asm_immediate_expected) << Info.getConstraintStr() << InputExpr->getSourceRange()); - llvm::APSInt Result = EVResult.Val.getInt(); - if (!Info.isValidAsmImmediate(Result)) + + // For compatibility with GCC, we also allow pointers that would be + // integral constant expressions if they were cast to int. + llvm::APSInt IntResult; + if (!EVResult.Val.toIntegralConstant(IntResult, InputExpr->getType(), + Context)) + return StmtError( + Diag(InputExpr->getBeginLoc(), diag::err_asm_immediate_expected) + << Info.getConstraintStr() << InputExpr->getSourceRange()); + + if (!Info.isValidAsmImmediate(IntResult)) return StmtError(Diag(InputExpr->getBeginLoc(), diag::err_invalid_asm_value_for_constraint) - << Result.toString(10) << Info.getConstraintStr() + << IntResult.toString(10) << Info.getConstraintStr() << InputExpr->getSourceRange()); } Index: test/CodeGen/x86-64-inline-asm.c =================================================================== --- test/CodeGen/x86-64-inline-asm.c +++ test/CodeGen/x86-64-inline-asm.c @@ -1,6 +1,7 @@ // REQUIRES: x86-registered-target // RUN: %clang_cc1 -triple x86_64 %s -S -o /dev/null -DWARN -verify // RUN: %clang_cc1 -triple x86_64 %s -S -o /dev/null -Werror -verify +// RUN: %clang_cc1 -triple x86_64-linux-gnu %s -S -o - | FileCheck %s void f() { asm("movaps %xmm3, (%esi, 2)"); // expected-note@1 {{instantiated into assembly here}} @@ -15,3 +16,17 @@ void g(void) { asm volatile("movd %%xmm0, %0" : : "m"(var)); } + +void pr40890(void) { + struct s { + int a, b; + } s; + __asm__ __volatile__("\n#define S_A abcd%0\n" : : "n"(&((struct s*)0)->a)); + __asm__ __volatile__("\n#define S_B abcd%0\n" : : "n"(&((struct s*)0)->b)); + __asm__ __volatile__("\n#define BEEF abcd%0\n" : : "n"((int*)0xdeadbeeeeeef)); + +// CHECK-LABEL: pr40890 +// CHECK: #define S_A abcd$0 +// CHECK: #define S_B abcd$4 +// CHECK: #define BEEF abcd$244837814038255 +} Index: test/Sema/inline-asm-validate-x86.c =================================================================== --- test/Sema/inline-asm-validate-x86.c +++ test/Sema/inline-asm-validate-x86.c @@ -1,5 +1,5 @@ // RUN: %clang_cc1 -triple i686 -fsyntax-only -verify %s -// RUN: %clang_cc1 -triple x86_64 -fsyntax-only -verify %s +// RUN: %clang_cc1 -triple x86_64 -fsyntax-only -verify -DAMD64 %s void I(int i, int j) { static const int BelowMin = -1; @@ -137,3 +137,21 @@ : "0"(i), "O"(64)); // expected-no-error } +void pr40890(void) { + struct s { + int a, b; + }; + static struct s s; + // This null pointer can be used as an integer constant expression. + __asm__ __volatile__("\n#define S_A abcd%0\n" : : "n"(&((struct s*)0)->a)); + // This offset-from-null pointer can be used as an integer constant expression. + __asm__ __volatile__("\n#define S_B abcd%0\n" : : "n"(&((struct s*)0)->b)); + // This pointer cannot be used as an integer constant expression. + __asm__ __volatile__("\n#define GLOBAL_A abcd%0\n" : : "n"(&s.a)); // expected-error{{constraint 'n' expects an integer constant expression}} + // Floating-point is also not okay. + __asm__ __volatile__("\n#define PI abcd%0\n" : : "n"(3.14f)); // expected-error{{constraint 'n' expects an integer constant expression}} +#ifdef AMD64 + // This arbitrary pointer is fine. + __asm__ __volatile__("\n#define BEEF abcd%0\n" : : "n"((int*)0xdeadbeeeeeef)); +#endif +}