Skip to content

Commit 2cc470a

Browse files
committed
Merging r355491:
------------------------------------------------------------------------ r355491 | hans | 2019-03-06 11:26:19 +0100 (Wed, 06 Mar 2019) | 9 lines Inline asm constraints: allow ICE-like pointers for the "n" constraint (PR40890) Apparently GCC allows this, and there's code relying on it (see bug). The idea is to allow expression that would have been allowed if they were cast to int. So I based the code on how such a cast would be done (the CK_PointerToIntegral case in IntExprEvaluator::VisitCastExpr()). Differential Revision: https://reviews.llvm.org/D58821 ------------------------------------------------------------------------ llvm-svn: 355674
1 parent 7681975 commit 2cc470a

File tree

7 files changed

+86
-12
lines changed

7 files changed

+86
-12
lines changed

clang/include/clang/AST/APValue.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -257,6 +257,12 @@ class APValue {
257257
return const_cast<APValue*>(this)->getInt();
258258
}
259259

260+
/// Try to convert this value to an integral constant. This works if it's an
261+
/// integer, null pointer, or offset from a null pointer. Returns true on
262+
/// success.
263+
bool toIntegralConstant(APSInt &Result, QualType SrcTy,
264+
const ASTContext &Ctx) const;
265+
260266
APFloat &getFloat() {
261267
assert(isFloat() && "Invalid accessor");
262268
return *(APFloat*)(char*)Data.buffer;

clang/lib/AST/APValue.cpp

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -600,6 +600,26 @@ std::string APValue::getAsString(ASTContext &Ctx, QualType Ty) const {
600600
return Result;
601601
}
602602

603+
bool APValue::toIntegralConstant(APSInt &Result, QualType SrcTy,
604+
const ASTContext &Ctx) const {
605+
if (isInt()) {
606+
Result = getInt();
607+
return true;
608+
}
609+
610+
if (isLValue() && isNullPointer()) {
611+
Result = Ctx.MakeIntValue(Ctx.getTargetNullPointerValue(SrcTy), SrcTy);
612+
return true;
613+
}
614+
615+
if (isLValue() && !getLValueBase()) {
616+
Result = Ctx.MakeIntValue(getLValueOffset().getQuantity(), SrcTy);
617+
return true;
618+
}
619+
620+
return false;
621+
}
622+
603623
const APValue::LValueBase APValue::getLValueBase() const {
604624
assert(isLValue() && "Invalid accessor");
605625
return ((const LV*)(const void*)Data.buffer)->Base;

clang/lib/AST/ExprConstant.cpp

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -9821,13 +9821,12 @@ bool IntExprEvaluator::VisitCastExpr(const CastExpr *E) {
98219821
return true;
98229822
}
98239823

9824-
uint64_t V;
9825-
if (LV.isNullPointer())
9826-
V = Info.Ctx.getTargetNullPointerValue(SrcType);
9827-
else
9828-
V = LV.getLValueOffset().getQuantity();
9824+
APSInt AsInt;
9825+
APValue V;
9826+
LV.moveInto(V);
9827+
if (!V.toIntegralConstant(AsInt, SrcType, Info.Ctx))
9828+
llvm_unreachable("Can't cast this!");
98299829

9830-
APSInt AsInt = Info.Ctx.MakeIntValue(V, SrcType);
98319830
return Success(HandleIntToIntCast(Info, E, DestType, SrcType, AsInt), E);
98329831
}
98339832

clang/lib/CodeGen/CGStmt.cpp

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1821,8 +1821,15 @@ llvm::Value* CodeGenFunction::EmitAsmInput(
18211821
// (immediate or symbolic), try to emit it as such.
18221822
if (!Info.allowsRegister() && !Info.allowsMemory()) {
18231823
if (Info.requiresImmediateConstant()) {
1824-
llvm::APSInt AsmConst = InputExpr->EvaluateKnownConstInt(getContext());
1825-
return llvm::ConstantInt::get(getLLVMContext(), AsmConst);
1824+
Expr::EvalResult EVResult;
1825+
InputExpr->EvaluateAsRValue(EVResult, getContext(), true);
1826+
1827+
llvm::APSInt IntResult;
1828+
if (!EVResult.Val.toIntegralConstant(IntResult, InputExpr->getType(),
1829+
getContext()))
1830+
llvm_unreachable("Invalid immediate constant!");
1831+
1832+
return llvm::ConstantInt::get(getLLVMContext(), IntResult);
18261833
}
18271834

18281835
Expr::EvalResult Result;

clang/lib/Sema/SemaStmtAsm.cpp

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -383,11 +383,20 @@ StmtResult Sema::ActOnGCCAsmStmt(SourceLocation AsmLoc, bool IsSimple,
383383
return StmtError(
384384
Diag(InputExpr->getBeginLoc(), diag::err_asm_immediate_expected)
385385
<< Info.getConstraintStr() << InputExpr->getSourceRange());
386-
llvm::APSInt Result = EVResult.Val.getInt();
387-
if (!Info.isValidAsmImmediate(Result))
386+
387+
// For compatibility with GCC, we also allow pointers that would be
388+
// integral constant expressions if they were cast to int.
389+
llvm::APSInt IntResult;
390+
if (!EVResult.Val.toIntegralConstant(IntResult, InputExpr->getType(),
391+
Context))
392+
return StmtError(
393+
Diag(InputExpr->getBeginLoc(), diag::err_asm_immediate_expected)
394+
<< Info.getConstraintStr() << InputExpr->getSourceRange());
395+
396+
if (!Info.isValidAsmImmediate(IntResult))
388397
return StmtError(Diag(InputExpr->getBeginLoc(),
389398
diag::err_invalid_asm_value_for_constraint)
390-
<< Result.toString(10) << Info.getConstraintStr()
399+
<< IntResult.toString(10) << Info.getConstraintStr()
391400
<< InputExpr->getSourceRange());
392401
}
393402

clang/test/CodeGen/x86-64-inline-asm.c

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
// REQUIRES: x86-registered-target
22
// RUN: %clang_cc1 -triple x86_64 %s -S -o /dev/null -DWARN -verify
33
// RUN: %clang_cc1 -triple x86_64 %s -S -o /dev/null -Werror -verify
4+
// RUN: %clang_cc1 -triple x86_64-linux-gnu %s -S -o - | FileCheck %s
45
void f() {
56
asm("movaps %xmm3, (%esi, 2)");
67
// expected-note@1 {{instantiated into assembly here}}
@@ -15,3 +16,17 @@ static unsigned var[1] = {};
1516
void g(void) { asm volatile("movd %%xmm0, %0"
1617
:
1718
: "m"(var)); }
19+
20+
void pr40890(void) {
21+
struct s {
22+
int a, b;
23+
} s;
24+
__asm__ __volatile__("\n#define S_A abcd%0\n" : : "n"(&((struct s*)0)->a));
25+
__asm__ __volatile__("\n#define S_B abcd%0\n" : : "n"(&((struct s*)0)->b));
26+
__asm__ __volatile__("\n#define BEEF abcd%0\n" : : "n"((int*)0xdeadbeeeeeef));
27+
28+
// CHECK-LABEL: pr40890
29+
// CHECK: #define S_A abcd$0
30+
// CHECK: #define S_B abcd$4
31+
// CHECK: #define BEEF abcd$244837814038255
32+
}

clang/test/Sema/inline-asm-validate-x86.c

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
// RUN: %clang_cc1 -triple i686 -fsyntax-only -verify %s
2-
// RUN: %clang_cc1 -triple x86_64 -fsyntax-only -verify %s
2+
// RUN: %clang_cc1 -triple x86_64 -fsyntax-only -verify -DAMD64 %s
33

44
void I(int i, int j) {
55
static const int BelowMin = -1;
@@ -133,3 +133,21 @@ void O(int i, int j) {
133133
: "0"(i), "O"(64)); // expected-no-error
134134
}
135135

136+
void pr40890(void) {
137+
struct s {
138+
int a, b;
139+
};
140+
static struct s s;
141+
// This null pointer can be used as an integer constant expression.
142+
__asm__ __volatile__("\n#define S_A abcd%0\n" : : "n"(&((struct s*)0)->a));
143+
// This offset-from-null pointer can be used as an integer constant expression.
144+
__asm__ __volatile__("\n#define S_B abcd%0\n" : : "n"(&((struct s*)0)->b));
145+
// This pointer cannot be used as an integer constant expression.
146+
__asm__ __volatile__("\n#define GLOBAL_A abcd%0\n" : : "n"(&s.a)); // expected-error{{constraint 'n' expects an integer constant expression}}
147+
// Floating-point is also not okay.
148+
__asm__ __volatile__("\n#define PI abcd%0\n" : : "n"(3.14f)); // expected-error{{constraint 'n' expects an integer constant expression}}
149+
#ifdef AMD64
150+
// This arbitrary pointer is fine.
151+
__asm__ __volatile__("\n#define BEEF abcd%0\n" : : "n"((int*)0xdeadbeeeeeef));
152+
#endif
153+
}

0 commit comments

Comments
 (0)