Index: lib/CodeGen/BackendUtil.cpp =================================================================== --- lib/CodeGen/BackendUtil.cpp +++ lib/CodeGen/BackendUtil.cpp @@ -450,6 +450,9 @@ BackendArgs.push_back("-limit-float-precision"); BackendArgs.push_back(CodeGenOpts.LimitFloatPrecision.c_str()); } + if (LangOpts.MSVCCompat) { + BackendArgs.push_back("-fms-compatibility"); + } for (const std::string &BackendOption : CodeGenOpts.BackendOptions) BackendArgs.push_back(BackendOption.c_str()); BackendArgs.push_back(nullptr); Index: lib/Target/X86/AsmParser/X86AsmParser.cpp =================================================================== --- lib/Target/X86/AsmParser/X86AsmParser.cpp +++ lib/Target/X86/AsmParser/X86AsmParser.cpp @@ -37,6 +37,9 @@ #include using namespace llvm; +static cl::opt + MSCompatibility("fms-compatibility", cl::Hidden, + cl::init(false)); namespace { @@ -2666,13 +2669,17 @@ MatchFPUWaitAlias(IDLoc, Op, Operands, Out, MatchingInlineAsm); MCInst Inst; - - // Find one unsized memory operand, if present. + + // Find one unsized memory operand, if present, or a memory operand that + // may need relaxation. X86Operand *UnsizedMemOp = nullptr; + X86Operand *RelaxedMemOp = nullptr; for (const auto &Op : Operands) { X86Operand *X86Op = static_cast(Op.get()); if (X86Op->isMemUnsized()) UnsizedMemOp = X86Op; + else if (MSCompatibility && X86Op->isMem()) + RelaxedMemOp = X86Op; } // Allow some instructions to have implicitly pointer-sized operands. This is @@ -2686,32 +2693,54 @@ } } } + // Set the pointer that we will want to strip of size information + uint64_t ErrorInfoIgnore; + X86Operand *StripSizeMemOp = nullptr; + bool DoRelaxation = false; + if (RelaxedMemOp) { + StripSizeMemOp = RelaxedMemOp; + // Determine if we'll need relaxation - if there are no matches with the + // original memory size + DoRelaxation = + !MatchInstructionImpl(Operands, Inst, ErrorInfoIgnore, + MatchingInlineAsm, isParsingIntelSyntax()); + // Erase Inst info + Inst.clear(); + Inst.setOpcode(0); + } else { + StripSizeMemOp = UnsizedMemOp; + } // If an unsized memory operand is present, try to match with each memory // operand size. In Intel assembly, the size is not part of the instruction // mnemonic. SmallVector Match; uint64_t ErrorInfoMissingFeature = 0; - if (UnsizedMemOp && UnsizedMemOp->isMemUnsized()) { + if ((UnsizedMemOp && UnsizedMemOp->isMemUnsized()) || DoRelaxation) { + // Save the original memory size so that it can be restored + unsigned OrigSize = StripSizeMemOp->Mem.Size; static const unsigned MopSizes[] = {8, 16, 32, 64, 80, 128, 256, 512}; for (unsigned Size : MopSizes) { - UnsizedMemOp->Mem.Size = Size; - uint64_t ErrorInfoIgnore; + StripSizeMemOp->Mem.Size = Size; unsigned LastOpcode = Inst.getOpcode(); unsigned M = MatchInstructionImpl(Operands, Inst, ErrorInfoIgnore, MatchingInlineAsm, isParsingIntelSyntax()); if (Match.empty() || LastOpcode != Inst.getOpcode()) Match.push_back(M); + // In case this is relaxation, we're only looking for the first match + if (DoRelaxation && M > 0) + break; // If this returned as a missing feature failure, remember that. if (Match.back() == Match_MissingFeature) ErrorInfoMissingFeature = ErrorInfoIgnore; } - // Restore the size of the unsized memory operand if we modified it. - if (UnsizedMemOp) - UnsizedMemOp->Mem.Size = 0; + // Restore the size of the relaxed/unsized memory + // operand if we modified it. + if (StripSizeMemOp) + StripSizeMemOp->Mem.Size = OrigSize; } // If we haven't matched anything yet, this is not a basic integer or FPU Index: test/CodeGen/not-Relaxation.c =================================================================== --- test/CodeGen/not-Relaxation.c +++ test/CodeGen/not-Relaxation.c @@ -0,0 +1,47 @@ +// RUN:%clang_cc1 -triple x86_64-pc-windows-msvc -fasm-blocks -fms-compatibility -mllvm --x86-asm-syntax=intel -S -o - %s \ +// RUN:| FileCheck %s -check-prefix FMSCOMP +// RUN:not %clang_cc1 -triple x86_64-pc-windows-msvc -fasm-blocks -mllvm --x86-asm-syntax=intel -S -o /dev/null %s 2>&1 %s \ +// RUN | FileCheck %s -check-prefix REGULARCOMP + +char test_mem[16]; + +void func(void) +{ + __asm { + //FMSCOMP:not cl + //REGULARCOMP:not cl + not cl + //FMSCOMP:not ax + //REGULARCOMP:not ax + not ax + //FMSCOMP:not eax + //REGULARCOMP:not eax + not eax + //FMSCOMP:not rax + //REGULARCOMP:not rax + not rax + //FMSCOMP:not qword ptr [rip + test_mem] + //REGULARCOMP:not qword ptr [rip + test_mem] + not QWORD PTR test_mem + //FMSCOMP:not dword ptr [rip + test_mem] + //REGULARCOMP:not dword ptr [rip + test_mem] + not DWORD PTR test_mem + //FMSCOMP:not word ptr [rip + test_mem] + //REGULARCOMP:not word ptr [rip + test_mem] + not WORD PTR test_mem + //FMSCOMP:not byte ptr [rip + test_mem] + //REGULARCOMP:not byte ptr [rip + test_mem] + not BYTE PTR test_mem + } +} +void Zf_NOT(void) +{ + __asm { + //FMSCOMP:not byte ptr [test_mem] + //REGULARCOMP: error: invalid operand for instruction + not XMMWORD PTR test_mem + //FMSCOMP:not byte ptr [test_mem] + //REGULARCOMP: error: invalid operand for instruction + not TBYTE PTR test_mem + } +}