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 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() 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: 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;