Index: cfe/trunk/lib/Basic/Targets/X86.cpp =================================================================== --- cfe/trunk/lib/Basic/Targets/X86.cpp +++ cfe/trunk/lib/Basic/Targets/X86.cpp @@ -864,6 +864,9 @@ /// definitions for this particular subtarget. void X86TargetInfo::getTargetDefines(const LangOptions &Opts, MacroBuilder &Builder) const { + // Inline assembly supports X86 flag outputs. + Builder.defineMacro("__GCC_ASM_FLAG_OUTPUTS__"); + std::string CodeModel = getTargetOpts().CodeModel; if (CodeModel == "default") CodeModel = "small"; @@ -1553,6 +1556,40 @@ .Default(false); } +static unsigned matchAsmCCConstraint(const char *&Name) { + auto RV = llvm::StringSwitch(Name) + .Case("@cca", 4) + .Case("@ccae", 5) + .Case("@ccb", 4) + .Case("@ccbe", 5) + .Case("@ccc", 4) + .Case("@cce", 4) + .Case("@ccz", 4) + .Case("@ccg", 4) + .Case("@ccge", 5) + .Case("@ccl", 4) + .Case("@ccle", 5) + .Case("@ccna", 5) + .Case("@ccnae", 6) + .Case("@ccnb", 5) + .Case("@ccnbe", 6) + .Case("@ccnc", 5) + .Case("@ccne", 5) + .Case("@ccnz", 5) + .Case("@ccng", 5) + .Case("@ccnge", 6) + .Case("@ccnl", 5) + .Case("@ccnle", 6) + .Case("@ccno", 5) + .Case("@ccnp", 5) + .Case("@ccns", 5) + .Case("@cco", 4) + .Case("@ccp", 4) + .Case("@ccs", 4) + .Default(0); + return RV; +} + bool X86TargetInfo::validateAsmConstraint( const char *&Name, TargetInfo::ConstraintInfo &Info) const { switch (*Name) { @@ -1635,6 +1672,14 @@ case 'C': // SSE floating point constant. case 'G': // x87 floating point constant. return true; + case '@': + // CC condition changes. + if (auto Len = matchAsmCCConstraint(Name)) { + Name += Len - 1; + Info.setAllowsRegister(); + return true; + } + return false; } } @@ -1706,6 +1751,13 @@ std::string X86TargetInfo::convertConstraint(const char *&Constraint) const { switch (*Constraint) { + case '@': + if (auto Len = matchAsmCCConstraint(Constraint)) { + std::string Converted = "{" + std::string(Constraint, Len) + "}"; + Constraint += Len - 1; + return Converted; + } + return std::string(1, *Constraint); case 'a': return std::string("{ax}"); case 'b': Index: cfe/trunk/test/CodeGen/inline-asm-x86-flag-output.c =================================================================== --- cfe/trunk/test/CodeGen/inline-asm-x86-flag-output.c +++ cfe/trunk/test/CodeGen/inline-asm-x86-flag-output.c @@ -0,0 +1,365 @@ +// RUN: %clang_cc1 -O2 -emit-llvm %s -o - -triple x86_64-unknown-linux-gnu | FileCheck %s + +int test_cca(long nr, volatile long *addr) { + //CHECK-LABEL: @test_cca + //CHECK: = tail call i32 asm "cmp $2,$1", "={@cca},=*m,r,~{cc},~{dirflag},~{fpsr},~{flags}"(i64* %addr, i64 %nr) + int x; + asm("cmp %2,%1" + : "=@cca"(x), "=m"(*(volatile long *)(addr)) + : "r"(nr) + : "cc"); + if (x) + return 0; + return 1; +} + +int test_ccae(long nr, volatile long *addr) { + //CHECK-LABEL: @test_ccae + //CHECK: = tail call i32 asm "cmp $2,$1", "={@ccae},=*m,r,~{cc},~{dirflag},~{fpsr},~{flags}"(i64* %addr, i64 %nr) + int x; + asm("cmp %2,%1" + : "=@ccae"(x), "=m"(*(volatile long *)(addr)) + : "r"(nr) + : "cc"); + if (x) + return 0; + return 1; +} + +int test_ccb(long nr, volatile long *addr) { + //CHECK-LABEL: @test_ccb + //CHECK: = tail call i32 asm "cmp $2,$1", "={@ccb},=*m,r,~{cc},~{dirflag},~{fpsr},~{flags}"(i64* %addr, i64 %nr) + int x; + asm("cmp %2,%1" + : "=@ccb"(x), "=m"(*(volatile long *)(addr)) + : "r"(nr) + : "cc"); + if (x) + return 0; + return 1; +} + +int test_ccbe(long nr, volatile long *addr) { + //CHECK-LABEL: @test_ccbe + //CHECK: tail call i32 asm "cmp $2,$1", "={@ccbe},=*m,r,~{cc},~{dirflag},~{fpsr},~{flags}"(i64* %addr, i64 %nr) + int x; + asm("cmp %2,%1" + : "=@ccbe"(x), "=m"(*(volatile long *)(addr)) + : "r"(nr) + : "cc"); + if (x) + return 0; + return 1; +} + +int test_ccc(long nr, volatile long *addr) { + //CHECK-LABEL: @test_ccc + //CHECK: = tail call i32 asm "cmp $2,$1", "={@ccc},=*m,r,~{cc},~{dirflag},~{fpsr},~{flags}"(i64* %addr, i64 %nr) + int x; + asm("cmp %2,%1" + : "=@ccc"(x), "=m"(*(volatile long *)(addr)) + : "r"(nr) + : "cc"); + if (x) + return 0; + return 1; +} + +int test_cce(long nr, volatile long *addr) { + //CHECK-LABEL: @test_cce + //CHECK: = tail call i32 asm "cmp $2,$1", "={@cce},=*m,r,~{cc},~{dirflag},~{fpsr},~{flags}"(i64* %addr, i64 %nr) + int x; + asm("cmp %2,%1" + : "=@cce"(x), "=m"(*(volatile long *)(addr)) + : "r"(nr) + : "cc"); + if (x) + return 0; + return 1; +} + +int test_ccz(long nr, volatile long *addr) { + //CHECK-LABEL: @test_ccz + //CHECK: = tail call i32 asm "cmp $2,$1", "={@ccz},=*m,r,~{cc},~{dirflag},~{fpsr},~{flags}"(i64* %addr, i64 %nr) + int x; + asm("cmp %2,%1" + : "=@ccz"(x), "=m"(*(volatile long *)(addr)) + : "r"(nr) + : "cc"); + if (x) + return 0; + return 1; +} + +int test_ccg(long nr, volatile long *addr) { + //CHECK-LABEL: @test_ccg + //CHECK: = tail call i32 asm "cmp $2,$1", "={@ccg},=*m,r,~{cc},~{dirflag},~{fpsr},~{flags}"(i64* %addr, i64 %nr) + int x; + asm("cmp %2,%1" + : "=@ccg"(x), "=m"(*(volatile long *)(addr)) + : "r"(nr) + : "cc"); + if (x) + return 0; + return 1; +} + +int test_ccge(long nr, volatile long *addr) { + //CHECK-LABEL: @test_ccge + //CHECK: = tail call i32 asm "cmp $2,$1", "={@ccge},=*m,r,~{cc},~{dirflag},~{fpsr},~{flags}"(i64* %addr, i64 %nr) + int x; + asm("cmp %2,%1" + : "=@ccge"(x), "=m"(*(volatile long *)(addr)) + : "r"(nr) + : "cc"); + if (x) + return 0; + return 1; +} + +int test_ccl(long nr, volatile long *addr) { + //CHECK-LABEL: @test_ccl + //CHECK: = tail call i32 asm "cmp $2,$1", "={@ccl},=*m,r,~{cc},~{dirflag},~{fpsr},~{flags}"(i64* %addr, i64 %nr) + int x; + asm("cmp %2,%1" + : "=@ccl"(x), "=m"(*(volatile long *)(addr)) + : "r"(nr) + : "cc"); + if (x) + return 0; + return 1; +} + +int test_ccle(long nr, volatile long *addr) { + //CHECK-LABEL: @test_ccle + //CHECK: = tail call i32 asm "cmp $2,$1", "={@ccle},=*m,r,~{cc},~{dirflag},~{fpsr},~{flags}"(i64* %addr, i64 %nr) + int x; + asm("cmp %2,%1" + : "=@ccle"(x), "=m"(*(volatile long *)(addr)) + : "r"(nr) + : "cc"); + if (x) + return 0; + return 1; +} + +int test_ccna(long nr, volatile long *addr) { + //CHECK-LABEL: @test_ccna + //CHECK: = tail call i32 asm "cmp $2,$1", "={@ccna},=*m,r,~{cc},~{dirflag},~{fpsr},~{flags}"(i64* %addr, i64 %nr) + int x; + asm("cmp %2,%1" + : "=@ccna"(x), "=m"(*(volatile long *)(addr)) + : "r"(nr) + : "cc"); + if (x) + return 0; + return 1; +} + +int test_ccnae(long nr, volatile long *addr) { + //CHECK-LABEL: @test_ccnae + //CHECK: = tail call i32 asm "cmp $2,$1", "={@ccnae},=*m,r,~{cc},~{dirflag},~{fpsr},~{flags}"(i64* %addr, i64 %nr) + int x; + asm("cmp %2,%1" + : "=@ccnae"(x), "=m"(*(volatile long *)(addr)) + : "r"(nr) + : "cc"); + if (x) + return 0; + return 1; +} + +int test_ccnb(long nr, volatile long *addr) { + //CHECK-LABEL: @test_ccnb + //CHECK: = tail call i32 asm "cmp $2,$1", "={@ccnb},=*m,r,~{cc},~{dirflag},~{fpsr},~{flags}"(i64* %addr, i64 %nr) + int x; + asm("cmp %2,%1" + : "=@ccnb"(x), "=m"(*(volatile long *)(addr)) + : "r"(nr) + : "cc"); + if (x) + return 0; + return 1; +} + +int test_ccnbe(long nr, volatile long *addr) { + //CHECK-LABEL: @test_ccnbe + //CHECK: = tail call i32 asm "cmp $2,$1", "={@ccnbe},=*m,r,~{cc},~{dirflag},~{fpsr},~{flags}"(i64* %addr, i64 %nr) + int x; + asm("cmp %2,%1" + : "=@ccnbe"(x), "=m"(*(volatile long *)(addr)) + : "r"(nr) + : "cc"); + if (x) + return 0; + return 1; +} + +int test_ccnc(long nr, volatile long *addr) { + //CHECK-LABEL: @test_ccnc + //CHECK: = tail call i32 asm "cmp $2,$1", "={@ccnc},=*m,r,~{cc},~{dirflag},~{fpsr},~{flags}"(i64* %addr, i64 %nr) + int x; + asm("cmp %2,%1" + : "=@ccnc"(x), "=m"(*(volatile long *)(addr)) + : "r"(nr) + : "cc"); + if (x) + return 0; + return 1; +} + +int test_ccne(long nr, volatile long *addr) { + //CHECK-LABEL: @test_ccne + //CHECK: = tail call i32 asm "cmp $2,$1", "={@ccne},=*m,r,~{cc},~{dirflag},~{fpsr},~{flags}"(i64* %addr, i64 %nr) + int x; + asm("cmp %2,%1" + : "=@ccne"(x), "=m"(*(volatile long *)(addr)) + : "r"(nr) + : "cc"); + if (x) + return 0; + return 1; +} + +int test_ccnz(long nr, volatile long *addr) { + //CHECK-LABEL: @test_ccnz + //CHECK: = tail call i32 asm "cmp $2,$1", "={@ccnz},=*m,r,~{cc},~{dirflag},~{fpsr},~{flags}"(i64* %addr, i64 %nr) + int x; + asm("cmp %2,%1" + : "=@ccnz"(x), "=m"(*(volatile long *)(addr)) + : "r"(nr) + : "cc"); + if (x) + return 0; + return 1; +} + +int test_ccng(long nr, volatile long *addr) { + //CHECK-LABEL: @test_ccng + //CHECK: = tail call i32 asm "cmp $2,$1", "={@ccng},=*m,r,~{cc},~{dirflag},~{fpsr},~{flags}"(i64* %addr, i64 %nr) + int x; + asm("cmp %2,%1" + : "=@ccng"(x), "=m"(*(volatile long *)(addr)) + : "r"(nr) + : "cc"); + if (x) + return 0; + return 1; +} + +int test_ccnge(long nr, volatile long *addr) { + //CHECK-LABEL: @test_ccnge + //CHECK: = tail call i32 asm "cmp $2,$1", "={@ccnge},=*m,r,~{cc},~{dirflag},~{fpsr},~{flags}"(i64* %addr, i64 %nr) + int x; + asm("cmp %2,%1" + : "=@ccnge"(x), "=m"(*(volatile long *)(addr)) + : "r"(nr) + : "cc"); + if (x) + return 0; + return 1; +} + +int test_ccnl(long nr, volatile long *addr) { + //CHECK-LABEL: @test_ccnl + //CHECK: = tail call i32 asm "cmp $2,$1", "={@ccnl},=*m,r,~{cc},~{dirflag},~{fpsr},~{flags}"(i64* %addr, i64 %nr) + int x; + asm("cmp %2,%1" + : "=@ccnl"(x), "=m"(*(volatile long *)(addr)) + : "r"(nr) + : "cc"); + if (x) + return 0; + return 1; +} + +int test_ccnle(long nr, volatile long *addr) { + //CHECK-LABEL: @test_ccnle + //CHECK: = tail call i32 asm "cmp $2,$1", "={@ccnle},=*m,r,~{cc},~{dirflag},~{fpsr},~{flags}"(i64* %addr, i64 %nr) + int x; + asm("cmp %2,%1" + : "=@ccnle"(x), "=m"(*(volatile long *)(addr)) + : "r"(nr) + : "cc"); + if (x) + return 0; + return 1; +} + +int test_ccno(long nr, volatile long *addr) { + //CHECK-LABEL: @test_ccno + //CHECK: = tail call i32 asm "cmp $2,$1", "={@ccno},=*m,r,~{cc},~{dirflag},~{fpsr},~{flags}"(i64* %addr, i64 %nr) + int x; + asm("cmp %2,%1" + : "=@ccno"(x), "=m"(*(volatile long *)(addr)) + : "r"(nr) + : "cc"); + if (x) + return 0; + return 1; +} + +int test_ccnp(long nr, volatile long *addr) { + //CHECK-LABEL: @test_ccnp + //CHECK: = tail call i32 asm "cmp $2,$1", "={@ccnp},=*m,r,~{cc},~{dirflag},~{fpsr},~{flags}"(i64* %addr, i64 %nr) + int x; + asm("cmp %2,%1" + : "=@ccnp"(x), "=m"(*(volatile long *)(addr)) + : "r"(nr) + : "cc"); + if (x) + return 0; + return 1; +} + +int test_ccns(long nr, volatile long *addr) { + //CHECK-LABEL: @test_ccns + //CHECK: = tail call i32 asm "cmp $2,$1", "={@ccns},=*m,r,~{cc},~{dirflag},~{fpsr},~{flags}"(i64* %addr, i64 %nr) + int x; + asm("cmp %2,%1" + : "=@ccns"(x), "=m"(*(volatile long *)(addr)) + : "r"(nr) + : "cc"); + if (x) + return 0; + return 1; +} + +int test_cco(long nr, volatile long *addr) { + //CHECK-LABEL: @test_cco + //CHECK: = tail call i32 asm "cmp $2,$1", "={@cco},=*m,r,~{cc},~{dirflag},~{fpsr},~{flags}"(i64* %addr, i64 %nr) + int x; + asm("cmp %2,%1" + : "=@cco"(x), "=m"(*(volatile long *)(addr)) + : "r"(nr) + : "cc"); + if (x) + return 0; + return 1; +} + +int test_ccp(long nr, volatile long *addr) { + //CHECK-LABEL: @test_ccp + //CHECK: = tail call i32 asm "cmp $2,$1", "={@ccp},=*m,r,~{cc},~{dirflag},~{fpsr},~{flags}"(i64* %addr, i64 %nr) + int x; + asm("cmp %2,%1" + : "=@ccp"(x), "=m"(*(volatile long *)(addr)) + : "r"(nr) + : "cc"); + if (x) + return 0; + return 1; +} + +int test_ccs(long nr, volatile long *addr) { + //CHECK-LABEL: @test_ccs + //CHECK: = tail call i32 asm "cmp $2,$1", "={@ccs},=*m,r,~{cc},~{dirflag},~{fpsr},~{flags}"(i64* %addr, i64 %nr) + int x; + asm("cmp %2,%1" + : "=@ccs"(x), "=m"(*(volatile long *)(addr)) + : "r"(nr) + : "cc"); + if (x) + return 0; + return 1; +} Index: cfe/trunk/test/Preprocessor/predefined-win-macros.c =================================================================== --- cfe/trunk/test/Preprocessor/predefined-win-macros.c +++ cfe/trunk/test/Preprocessor/predefined-win-macros.c @@ -2,6 +2,8 @@ // // RUN: %clang_cc1 %s -x c++ -E -dM -triple x86_64-pc-win32 -fms-extensions -fms-compatibility \ // RUN: -fms-compatibility-version=19.00 -std=c++14 -o - | FileCheck -match-full-lines %s --check-prefix=CHECK-MS64 +// RUN: %clang_cc1 %s -x c++ -E -dM -triple x86_64-pc-win32 -fms-extensions -fms-compatibility \ +// RUN: -fms-compatibility-version=19.00 -std=c++14 -o - | grep GCC | count 1 // CHECK-MS64: #define _INTEGRAL_MAX_BITS 64 // CHECK-MS64: #define _MSC_EXTENSIONS 1 // CHECK-MS64: #define _MSC_VER 1900 @@ -10,12 +12,16 @@ // CHECK-MS64: #define _M_X64 100 // CHECK-MS64: #define _WIN64 1 // CHECK-MS64-NOT: #define __STRICT_ANSI__ -// CHECK-MS64-NOT: GCC +// CHECK-MS64-NOT: GNU +// CHECK-MS64-NOT: GXX +// CHECK-MS64: #define __GCC_ASM_FLAG_OUTPUTS__ 1 // CHECK-MS64-NOT: GNU // CHECK-MS64-NOT: GXX // RUN: %clang_cc1 %s -x c++ -E -dM -triple i686-pc-win32 -fms-extensions -fms-compatibility \ // RUN: -fms-compatibility-version=19.00 -std=c++17 -o - | FileCheck -match-full-lines %s --check-prefix=CHECK-MS +// RUN: %clang_cc1 %s -x c++ -E -dM -triple i686-pc-win32 -fms-extensions -fms-compatibility \ +// RUN: -fms-compatibility-version=19.00 -std=c++17 -o - | grep GCC | count 1 // CHECK-MS: #define _INTEGRAL_MAX_BITS 64 // CHECK-MS: #define _MSC_EXTENSIONS 1 // CHECK-MS: #define _MSC_VER 1900 @@ -24,7 +30,9 @@ // CHECK-MS: #define _M_IX86_FP 0 // CHECK-MS: #define _WIN32 1 // CHECK-MS-NOT: #define __STRICT_ANSI__ -// CHECK-MS-NOT: GCC +// CHECK-MS-NOT: GNU +// CHECK-MS-NOT: GXX +// CHECK-MS: #define __GCC_ASM_FLAG_OUTPUTS__ 1 // CHECK-MS-NOT: GNU // CHECK-MS-NOT: GXX @@ -107,4 +115,3 @@ // CHECK-ARM64-MINGW: #define _WIN32 1 // CHECK-ARM64-MINGW: #define _WIN64 1 // CHECK-ARM64-MINGW: #define __aarch64__ 1 - Index: cfe/trunk/test/Preprocessor/x86_asm_flag_output.c =================================================================== --- cfe/trunk/test/Preprocessor/x86_asm_flag_output.c +++ cfe/trunk/test/Preprocessor/x86_asm_flag_output.c @@ -0,0 +1,4 @@ +// RUN: %clang -target i386-unknown-unknown -x c -E -dM -o - %s | FileCheck -match-full-lines %s +// RUN: %clang -target x86_64-unknown-unknown -x c -E -dM -o - %s | FileCheck -match-full-lines %s + +// CHECK: #define __GCC_ASM_FLAG_OUTPUTS__ 1