mirror of https://github.com/microsoft/clang.git
[X86, inlineasm] Improve analysis of x,Y0,Yi,Ym,Yt,L,e,Z,s asm constraints (patch by Alexey Frolov)
Improve Sema checking of 9 existing inline asm constraints (‘x’, ‘Y*’, ‘L’, ‘e’, ‘Z’, ‘s’). Differential Revision: http://reviews.llvm.org/D10536 git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@242665 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
parent
9de1936315
commit
f19106baad
|
@ -22,6 +22,8 @@
|
|||
#include "clang/Basic/TargetOptions.h"
|
||||
#include "clang/Basic/VersionTuple.h"
|
||||
#include "llvm/ADT/IntrusiveRefCntPtr.h"
|
||||
#include "llvm/ADT/APInt.h"
|
||||
#include "llvm/ADT/SmallSet.h"
|
||||
#include "llvm/ADT/StringMap.h"
|
||||
#include "llvm/ADT/StringRef.h"
|
||||
#include "llvm/ADT/StringSwitch.h"
|
||||
|
@ -556,6 +558,7 @@ public:
|
|||
int Min;
|
||||
int Max;
|
||||
} ImmRange;
|
||||
llvm::SmallSet<int, 4> ImmSet;
|
||||
|
||||
std::string ConstraintStr; // constraint: "=rm"
|
||||
std::string Name; // Operand name: [foo] with no []'s.
|
||||
|
@ -591,8 +594,10 @@ public:
|
|||
bool requiresImmediateConstant() const {
|
||||
return (Flags & CI_ImmediateConstant) != 0;
|
||||
}
|
||||
int getImmConstantMin() const { return ImmRange.Min; }
|
||||
int getImmConstantMax() const { return ImmRange.Max; }
|
||||
bool isValidAsmImmediate(const llvm::APInt &Value) const {
|
||||
return (Value.sge(ImmRange.Min) && Value.sle(ImmRange.Max)) ||
|
||||
ImmSet.count(Value.getZExtValue()) != 0;
|
||||
}
|
||||
|
||||
void setIsReadWrite() { Flags |= CI_ReadWrite; }
|
||||
void setEarlyClobber() { Flags |= CI_EarlyClobber; }
|
||||
|
@ -604,6 +609,20 @@ public:
|
|||
ImmRange.Min = Min;
|
||||
ImmRange.Max = Max;
|
||||
}
|
||||
void setRequiresImmediate(llvm::ArrayRef<int> Exacts) {
|
||||
Flags |= CI_ImmediateConstant;
|
||||
for (int Exact : Exacts)
|
||||
ImmSet.insert(Exact);
|
||||
}
|
||||
void setRequiresImmediate(int Exact) {
|
||||
Flags |= CI_ImmediateConstant;
|
||||
ImmSet.insert(Exact);
|
||||
}
|
||||
void setRequiresImmediate() {
|
||||
Flags |= CI_ImmediateConstant;
|
||||
ImmRange.Min = INT_MIN;
|
||||
ImmRange.Max = INT_MAX;
|
||||
}
|
||||
|
||||
/// \brief Indicate that this is an input operand that is tied to
|
||||
/// the specified output operand.
|
||||
|
|
|
@ -3447,6 +3447,14 @@ X86TargetInfo::validateAsmConstraint(const char *&Name,
|
|||
TargetInfo::ConstraintInfo &Info) const {
|
||||
switch (*Name) {
|
||||
default: return false;
|
||||
// Constant constraints.
|
||||
case 'e': // 32-bit signed integer constant for use with sign-extending x86_64
|
||||
// instructions.
|
||||
case 'Z': // 32-bit unsigned integer constant for use with zero-extending
|
||||
// x86_64 instructions.
|
||||
case 's':
|
||||
Info.setRequiresImmediate();
|
||||
return true;
|
||||
case 'I':
|
||||
Info.setRequiresImmediate(0, 31);
|
||||
return true;
|
||||
|
@ -3457,8 +3465,7 @@ X86TargetInfo::validateAsmConstraint(const char *&Name,
|
|||
Info.setRequiresImmediate(-128, 127);
|
||||
return true;
|
||||
case 'L':
|
||||
// FIXME: properly analyze this constraint:
|
||||
// must be one of 0xff, 0xffff, or 0xffffffff
|
||||
Info.setRequiresImmediate({ int(0xff), int(0xffff), int(0xffffffff) });
|
||||
return true;
|
||||
case 'M':
|
||||
Info.setRequiresImmediate(0, 3);
|
||||
|
@ -3469,20 +3476,24 @@ X86TargetInfo::validateAsmConstraint(const char *&Name,
|
|||
case 'O':
|
||||
Info.setRequiresImmediate(0, 127);
|
||||
return true;
|
||||
case 'Y': // first letter of a pair:
|
||||
switch (*(Name+1)) {
|
||||
default: return false;
|
||||
case '0': // First SSE register.
|
||||
case 't': // Any SSE register, when SSE2 is enabled.
|
||||
case 'i': // Any SSE register, when SSE2 and inter-unit moves enabled.
|
||||
case 'm': // any MMX register, when inter-unit moves enabled.
|
||||
break; // falls through to setAllowsRegister.
|
||||
}
|
||||
case 'f': // any x87 floating point stack register.
|
||||
// Register constraints.
|
||||
case 'Y': // 'Y' is the first character for several 2-character constraints.
|
||||
// Shift the pointer to the second character of the constraint.
|
||||
Name++;
|
||||
switch (*Name) {
|
||||
default:
|
||||
return false;
|
||||
case '0': // First SSE register.
|
||||
case 't': // Any SSE register, when SSE2 is enabled.
|
||||
case 'i': // Any SSE register, when SSE2 and inter-unit moves enabled.
|
||||
case 'm': // Any MMX register, when inter-unit moves enabled.
|
||||
Info.setAllowsRegister();
|
||||
return true;
|
||||
}
|
||||
case 'f': // Any x87 floating point stack register.
|
||||
// Constraint 'f' cannot be used for output operands.
|
||||
if (Info.ConstraintStr[0] == '=')
|
||||
return false;
|
||||
|
||||
Info.setAllowsRegister();
|
||||
return true;
|
||||
case 'a': // eax.
|
||||
|
@ -3492,8 +3503,8 @@ X86TargetInfo::validateAsmConstraint(const char *&Name,
|
|||
case 'S': // esi.
|
||||
case 'D': // edi.
|
||||
case 'A': // edx:eax.
|
||||
case 't': // top of floating point stack.
|
||||
case 'u': // second from top of floating point stack.
|
||||
case 't': // Top of floating point stack.
|
||||
case 'u': // Second from top of floating point stack.
|
||||
case 'q': // Any register accessible as [r]l: a, b, c, and d.
|
||||
case 'y': // Any MMX register.
|
||||
case 'x': // Any SSE register.
|
||||
|
@ -3503,12 +3514,9 @@ X86TargetInfo::validateAsmConstraint(const char *&Name,
|
|||
// index in a base+index memory access.
|
||||
Info.setAllowsRegister();
|
||||
return true;
|
||||
// Floating point constant constraints.
|
||||
case 'C': // SSE floating point constant.
|
||||
case 'G': // x87 floating point constant.
|
||||
case 'e': // 32-bit signed integer constant for use with zero-extending
|
||||
// x86_64 instructions.
|
||||
case 'Z': // 32-bit unsigned integer constant for use with zero-extending
|
||||
// x86_64 instructions.
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
@ -3540,8 +3548,30 @@ bool X86TargetInfo::validateOperandSize(StringRef Constraint,
|
|||
case 'u':
|
||||
return Size <= 128;
|
||||
case 'x':
|
||||
// 256-bit ymm registers can be used if target supports AVX.
|
||||
return Size <= (SSELevel >= AVX ? 256U : 128U);
|
||||
if (SSELevel >= AVX512F)
|
||||
// 512-bit zmm registers can be used if target supports AVX512F.
|
||||
return Size <= 512U;
|
||||
else if (SSELevel >= AVX)
|
||||
// 256-bit ymm registers can be used if target supports AVX.
|
||||
return Size <= 256U;
|
||||
return Size <= 128U;
|
||||
case 'Y':
|
||||
// 'Y' is the first character for several 2-character constraints.
|
||||
switch (Constraint[1]) {
|
||||
default: break;
|
||||
case 'm':
|
||||
// 'Ym' is synonymous with 'y'.
|
||||
return Size <= 64;
|
||||
case 'i':
|
||||
case 't':
|
||||
// 'Yi' and 'Yt' are synonymous with 'x' when SSE2 is enabled.
|
||||
if (SSELevel >= AVX512F)
|
||||
return Size <= 512U;
|
||||
else if (SSELevel >= AVX)
|
||||
return Size <= 256U;
|
||||
return SSELevel >= SSE2 && Size <= 128U;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return true;
|
||||
|
|
|
@ -260,8 +260,7 @@ StmtResult Sema::ActOnGCCAsmStmt(SourceLocation AsmLoc, bool IsSimple,
|
|||
return StmtError(
|
||||
Diag(InputExpr->getLocStart(), diag::err_asm_immediate_expected)
|
||||
<< Info.getConstraintStr() << InputExpr->getSourceRange());
|
||||
if (Result.slt(Info.getImmConstantMin()) ||
|
||||
Result.sgt(Info.getImmConstantMax()))
|
||||
if (!Info.isValidAsmImmediate(Result))
|
||||
return StmtError(Diag(InputExpr->getLocStart(),
|
||||
diag::err_invalid_asm_value_for_constraint)
|
||||
<< Result.toString(10) << Info.getConstraintStr()
|
||||
|
|
|
@ -110,9 +110,9 @@ void single_x()
|
|||
}
|
||||
|
||||
// CHECK: @single_Y
|
||||
void single_Y0()
|
||||
void single_Y()
|
||||
{
|
||||
// Y constraint currently broken.
|
||||
// 'Y' constraint currently broken.
|
||||
//asm("foo %1,%0" : "=Y0" (mout0) : "Y0" (min1));
|
||||
//asm("foo %1,%0" : "=Yz" (mout0) : "Yz" (min1));
|
||||
//asm("foo %1,%0" : "=Yt" (mout0) : "Yt" (min1));
|
||||
|
@ -144,8 +144,12 @@ void single_K()
|
|||
// CHECK: @single_L
|
||||
void single_L()
|
||||
{
|
||||
// CHECK: asm "foo $1,$0", "=*m,L[[CLOBBERS]](i32* @mout0, i32 1)
|
||||
asm("foo %1,%0" : "=m" (mout0) : "L" (1));
|
||||
// CHECK: asm "foo $1,$0", "=*m,L[[CLOBBERS]](i32* @mout0, i32 255)
|
||||
asm("foo %1,%0" : "=m" (mout0) : "L" (0xff));
|
||||
// CHECK: asm "foo $1,$0", "=*m,L[[CLOBBERS]](i32* @mout0, i32 65535)
|
||||
asm("foo %1,%0" : "=m" (mout0) : "L" (0xffff));
|
||||
// CHECK: asm "foo $1,$0", "=*m,L[[CLOBBERS]](i32* @mout0, i32 -1)
|
||||
asm("foo %1,%0" : "=m" (mout0) : "L" (0xffffffff));
|
||||
}
|
||||
|
||||
// CHECK: @single_M
|
||||
|
|
|
@ -52,6 +52,32 @@ void K(int i, int j) {
|
|||
: "0"(i), "K"(96)); // expected-no-error
|
||||
}
|
||||
|
||||
void L(int i, int j) {
|
||||
static const int Invalid1 = 1;
|
||||
static const int Invalid2 = 42;
|
||||
static const int Valid1 = 0xff;
|
||||
static const int Valid2 = 0xffff;
|
||||
static const int Valid3 = 0xffffffff;
|
||||
__asm__("xorl %0,%2"
|
||||
: "=r"(i)
|
||||
: "0"(i), "L"(j)); // expected-error{{constraint 'L' expects an integer constant expression}}
|
||||
__asm__("xorl %0,%2"
|
||||
: "=r"(i)
|
||||
: "0"(i), "L"(Invalid1)); // expected-error{{value '1' out of range for constraint 'L'}}
|
||||
__asm__("xorl %0,%2"
|
||||
: "=r"(i)
|
||||
: "0"(i), "L"(Invalid2)); // expected-error{{value '42' out of range for constraint 'L'}}
|
||||
__asm__("xorl %0,%2"
|
||||
: "=r"(i)
|
||||
: "0"(i), "L"(Valid1)); // expected-no-error
|
||||
__asm__("xorl %0,%2"
|
||||
: "=r"(i)
|
||||
: "0"(i), "L"(Valid2)); // expected-no-error
|
||||
__asm__("xorl %0,%2"
|
||||
: "=r"(i)
|
||||
: "0"(i), "L"(Valid3)); // expected-no-error
|
||||
}
|
||||
|
||||
void M(int i, int j) {
|
||||
static const int BelowMin = -1;
|
||||
static const int AboveMax = 4;
|
||||
|
|
Loading…
Reference in New Issue