Hi echristo,
Implement 5 missing inline constraints along with corresponding Sema logic
(‘v’, ‘k’, ‘Y2’, ‘Yk’, ‘Yz’) and improve Sema checking of 10 existing
constraints (‘x’, ‘Y*’, ‘L’, ‘e’, ‘Z’, ‘s’).
This fixes http://llvm.org/PR13199 and http://llvm.org/PR22013 for X86 targets.
REPOSITORY
rL LLVM
http://reviews.llvm.org/D10536
Files:
include/clang/Basic/TargetInfo.h
lib/Basic/Targets.cpp
lib/Sema/SemaStmtAsm.cpp
test/CodeGen/mult-alt-x86.c
test/Sema/inline-asm-validate-x86.c
EMAIL PREFERENCES
http://reviews.llvm.org/settings/panel/emailpreferences/
Index: test/Sema/inline-asm-validate-x86.c
===================================================================
--- test/Sema/inline-asm-validate-x86.c
+++ test/Sema/inline-asm-validate-x86.c
@@ -52,6 +52,32 @@
: "0"(i), "K"(96)); // expected-no-error
}
+void L(int i, int j) {
+ static const int NotValid1 = 1;
+ static const int NotValid2 = 42;
+ static const int ExactValue1 = 0xff;
+ static const int ExactValue2 = 0xffff;
+ static const int ExactValue3 = 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"(NotValid1)); // expected-error{{value '1' out of range for constraint 'L'}}
+ __asm__("xorl %0,%2"
+ : "=r"(i)
+ : "0"(i), "L"(NotValid2)); // expected-error{{value '42' out of range for constraint 'L'}}
+ __asm__("xorl %0,%2"
+ : "=r"(i)
+ : "0"(i), "L"(ExactValue1)); // expected-no-error
+ __asm__("xorl %0,%2"
+ : "=r"(i)
+ : "0"(i), "L"(ExactValue2)); // expected-no-error
+ __asm__("xorl %0,%2"
+ : "=r"(i)
+ : "0"(i), "L"(ExactValue3)); // expected-no-error
+}
+
void M(int i, int j) {
static const int BelowMin = -1;
static const int AboveMax = 4;
Index: test/CodeGen/mult-alt-x86.c
===================================================================
--- test/CodeGen/mult-alt-x86.c
+++ test/CodeGen/mult-alt-x86.c
@@ -110,14 +110,17 @@
}
// CHECK: @single_Y
-void single_Y0()
+void single_Y()
{
- // 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));
- //asm("foo %1,%0" : "=Yi" (mout0) : "Yi" (min1));
- //asm("foo %1,%0" : "=Ym" (mout0) : "Ym" (min1));
+ // 'Y' constraint currently broken.
+ // asm("foo %1,%0" : "=Y0" (mout0) : "Y0" (min1));
+ // asm("foo %1,%0" : "=Y2" (mout0) : "Y2" (min1));
+ // asm("foo %1,%0" : "=Yi" (mout0) : "Yi" (min1));
+ // 'Yk' constraint is AVX-512 specific.
+ // asm("foo %1,%0" : "=Yk" (mout0) : "Yk" (min1));
+ // asm("foo %1,%0" : "=Ym" (mout0) : "Ym" (min1));
+ // asm("foo %1,%0" : "=Yt" (mout0) : "Yt" (min1));
+ // asm("foo %1,%0" : "=Yz" (mout0) : "Yz" (min1));
}
// CHECK: @single_I
@@ -144,8 +147,12 @@
// 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
Index: include/clang/Basic/TargetInfo.h
===================================================================
--- include/clang/Basic/TargetInfo.h
+++ include/clang/Basic/TargetInfo.h
@@ -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"
@@ -550,6 +552,7 @@
int Min;
int Max;
} ImmRange;
+ llvm::SmallSet<int, 4> ImmSet;
std::string ConstraintStr; // constraint: "=rm"
std::string Name; // Operand name: [foo] with no []'s.
@@ -585,8 +588,10 @@
bool requiresImmediateConstant() const {
return (Flags & CI_ImmediateConstant) != 0;
}
- int getImmConstantMin() const { return ImmRange.Min; }
- int getImmConstantMax() const { return ImmRange.Max; }
+ bool isValidAsmValue(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; }
@@ -598,6 +603,15 @@
ImmRange.Min = Min;
ImmRange.Max = Max;
}
+ 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.
Index: lib/Basic/Targets.cpp
===================================================================
--- lib/Basic/Targets.cpp
+++ lib/Basic/Targets.cpp
@@ -3336,6 +3336,14 @@
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;
@@ -3346,8 +3354,9 @@
Info.setRequiresImmediate(-128, 127);
return true;
case 'L':
- // FIXME: properly analyze this constraint:
- // must be one of 0xff, 0xffff, or 0xffffffff
+ Info.setRequiresImmediate(0xff);
+ Info.setRequiresImmediate(0xffff);
+ Info.setRequiresImmediate(0xffffffff);
return true;
case 'M':
Info.setRequiresImmediate(0, 3);
@@ -3358,20 +3367,27 @@
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 '2': // Any SSE register.
+ case 'i': // Any SSE register, when SSE2 and inter-unit moves enabled.
+ case 'k': // k1-k7 mask registers, when AVX512F is enabled.
+ case 'm': // Any MMX register, when inter-unit moves enabled.
+ case 't': // Any SSE register, when SSE2 is enabled.
+ case 'z': // xmm0 register.
+ 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.
@@ -3381,23 +3397,22 @@
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.
+ case 'v': // Any SSE register. This is AVX-512 specific.
+ case 'k': // Any mask register. This is AVX-512 specific.
case 'Q': // Any register accessible as [r]h: a, b, c, and d.
case 'R': // "Legacy" registers: ax, bx, cx, dx, di, si, sp, bp.
case 'l': // "Index" registers: any general register that can be used as an
// 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;
}
}
@@ -3428,9 +3443,40 @@
case 't':
case 'u':
return Size <= 128;
+ case 'v':
+ case 'k':
+ // 'v' and 'k' constraints can be used if target supports AVX512F.
+ return SSELevel >= AVX512F && Size <= 512U;
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 'z':
+ case '2':
+ case 'i':
+ // 'Yz' constrains to xmm0.
+ // 'Y2' and 'Yi' are synonymous with 'x'.
+ if (SSELevel >= AVX512F)
+ return Size <= 512U;
+ else if (SSELevel >= AVX)
+ return Size <= 256U;
+ return Size <= 128U;
+ case 'k':
+ // 'Yk' denotes k1-k7 mask registers. This is AVX512F-only feature.
+ return SSELevel >= AVX512F && Size <= 512U;
+ }
+
}
return true;
Index: lib/Sema/SemaStmtAsm.cpp
===================================================================
--- lib/Sema/SemaStmtAsm.cpp
+++ lib/Sema/SemaStmtAsm.cpp
@@ -259,8 +259,7 @@
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.isValidAsmValue(Result))
return StmtError(Diag(InputExpr->getLocStart(),
diag::err_invalid_asm_value_for_constraint)
<< Result.toString(10) << Info.getConstraintStr()
_______________________________________________
cfe-commits mailing list
[email protected]
http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits