Index: clang/include/clang/Basic/CodeGenOptions.h =================================================================== --- clang/include/clang/Basic/CodeGenOptions.h +++ clang/include/clang/Basic/CodeGenOptions.h @@ -97,6 +97,11 @@ Embed_Marker // Embed a marker as a placeholder for bitcode. }; + enum InlineAsmDialectKind { + IAD_ATT, + IAD_Intel, + }; + // This field stores one of the allowed values for the option // -fbasic-block-sections=. The allowed values with this option are: // {"labels", "all", "list=", "none"}. Index: clang/include/clang/Basic/CodeGenOptions.def =================================================================== --- clang/include/clang/Basic/CodeGenOptions.def +++ clang/include/clang/Basic/CodeGenOptions.def @@ -92,6 +92,8 @@ CODEGENOPT(ExplicitEmulatedTLS , 1, 0) ///< Set if -f[no-]emulated-tls is used. /// Embed Bitcode mode (off/all/bitcode/marker). ENUM_CODEGENOPT(EmbedBitcode, EmbedBitcodeKind, 2, Embed_Off) +/// Inline asm dialect, -masm=(att|intel) +ENUM_CODEGENOPT(InlineAsmDialect, InlineAsmDialectKind, 1, IAD_ATT) CODEGENOPT(ForbidGuardVariables , 1, 0) ///< Issue errors if C++ guard variables ///< are required. CODEGENOPT(FunctionSections , 1, 0) ///< Set when -ffunction-sections is enabled. Index: clang/include/clang/Driver/Options.td =================================================================== --- clang/include/clang/Driver/Options.td +++ clang/include/clang/Driver/Options.td @@ -3131,6 +3131,7 @@ def mwatchsimulator_version_min_EQ : Joined<["-"], "mwatchsimulator-version-min=">, Alias; def march_EQ : Joined<["-"], "march=">, Group, Flags<[CoreOption]>; def masm_EQ : Joined<["-"], "masm=">, Group, Flags<[NoXarchOption]>; +def inline_asm_EQ : Joined<["-"], "inline-asm=">, Group, Flags<[CC1Option]>; def mcmodel_EQ : Joined<["-"], "mcmodel=">, Group, Flags<[CC1Option]>, MarshallingInfoString, [{"default"}]>; def mtls_size_EQ : Joined<["-"], "mtls-size=">, Group, Flags<[NoXarchOption, CC1Option]>, Index: clang/lib/CodeGen/CGStmt.cpp =================================================================== --- clang/lib/CodeGen/CGStmt.cpp +++ clang/lib/CodeGen/CGStmt.cpp @@ -2629,8 +2629,14 @@ llvm::FunctionType::get(ResultType, ArgTypes, false); bool HasSideEffect = S.isVolatile() || S.getNumOutputs() == 0; + + llvm::InlineAsm::AsmDialect GnuAsmDialect = + CGM.getCodeGenOpts().getInlineAsmDialect() == CodeGenOptions::IAD_ATT + ? llvm::InlineAsm::AD_ATT + : llvm::InlineAsm::AD_Intel; llvm::InlineAsm::AsmDialect AsmDialect = isa(&S) ? - llvm::InlineAsm::AD_Intel : llvm::InlineAsm::AD_ATT; + llvm::InlineAsm::AD_Intel : GnuAsmDialect; + llvm::InlineAsm *IA = llvm::InlineAsm::get( FTy, AsmString, Constraints, HasSideEffect, /* IsAlignStack */ false, AsmDialect, HasUnwindClobber); Index: clang/lib/Driver/ToolChains/Clang.cpp =================================================================== --- clang/lib/Driver/ToolChains/Clang.cpp +++ clang/lib/Driver/ToolChains/Clang.cpp @@ -2200,6 +2200,7 @@ if (Value == "intel" || Value == "att") { CmdArgs.push_back("-mllvm"); CmdArgs.push_back(Args.MakeArgString("-x86-asm-syntax=" + Value)); + CmdArgs.push_back(Args.MakeArgString("-inline-asm=" + Value)); } else { D.Diag(diag::err_drv_unsupported_option_argument) << A->getOption().getName() << Value; Index: clang/lib/Frontend/CompilerInvocation.cpp =================================================================== --- clang/lib/Frontend/CompilerInvocation.cpp +++ clang/lib/Frontend/CompilerInvocation.cpp @@ -1614,6 +1614,18 @@ } } + if (Arg *A = Args.getLastArg(options::OPT_inline_asm_EQ)) { + StringRef Value = A->getValue(); + if (Value == "att") { + Opts.InlineAsmDialect = CodeGenOptions::IAD_ATT; + } else if (Value == "intel") { + Opts.InlineAsmDialect = CodeGenOptions::IAD_Intel; + } else { + Diags.Report(diag::err_drv_invalid_value) << A->getAsString(Args) + << A->getValue(); + } + } + // PIC defaults to -fno-direct-access-external-data while non-PIC defaults to // -fdirect-access-external-data. Opts.DirectAccessExternalData = Index: clang/lib/Headers/immintrin.h =================================================================== --- clang/lib/Headers/immintrin.h +++ clang/lib/Headers/immintrin.h @@ -543,13 +543,13 @@ #if defined(__i386__) || defined(__x86_64__) static __inline__ long __DEFAULT_FN_ATTRS _InterlockedExchange_HLEAcquire(long volatile *_Target, long _Value) { - __asm__ __volatile__(".byte 0xf2 ; lock ; xchg %0, %1" + __asm__ __volatile__(".byte 0xf2 ; lock ; xchg {%0, %1|%1, %0}" : "+r" (_Value), "+m" (*_Target) :: "memory"); return _Value; } static __inline__ long __DEFAULT_FN_ATTRS _InterlockedExchange_HLERelease(long volatile *_Target, long _Value) { - __asm__ __volatile__(".byte 0xf3 ; lock ; xchg %0, %1" + __asm__ __volatile__(".byte 0xf3 ; lock ; xchg {%0, %1|%1, %0}" : "+r" (_Value), "+m" (*_Target) :: "memory"); return _Value; } @@ -557,13 +557,13 @@ #if defined(__x86_64__) static __inline__ __int64 __DEFAULT_FN_ATTRS _InterlockedExchange64_HLEAcquire(__int64 volatile *_Target, __int64 _Value) { - __asm__ __volatile__(".byte 0xf2 ; lock ; xchg %0, %1" + __asm__ __volatile__(".byte 0xf2 ; lock ; xchg {%0, %1|%1, %0}" : "+r" (_Value), "+m" (*_Target) :: "memory"); return _Value; } static __inline__ __int64 __DEFAULT_FN_ATTRS _InterlockedExchange64_HLERelease(__int64 volatile *_Target, __int64 _Value) { - __asm__ __volatile__(".byte 0xf3 ; lock ; xchg %0, %1" + __asm__ __volatile__(".byte 0xf3 ; lock ; xchg {%0, %1|%1, %0}" : "+r" (_Value), "+m" (*_Target) :: "memory"); return _Value; } @@ -575,7 +575,7 @@ static __inline__ long __DEFAULT_FN_ATTRS _InterlockedCompareExchange_HLEAcquire(long volatile *_Destination, long _Exchange, long _Comparand) { - __asm__ __volatile__(".byte 0xf2 ; lock ; cmpxchg %2, %1" + __asm__ __volatile__(".byte 0xf2 ; lock ; cmpxchg {%2, %1|%1, %2}" : "+a" (_Comparand), "+m" (*_Destination) : "r" (_Exchange) : "memory"); return _Comparand; @@ -583,7 +583,7 @@ static __inline__ long __DEFAULT_FN_ATTRS _InterlockedCompareExchange_HLERelease(long volatile *_Destination, long _Exchange, long _Comparand) { - __asm__ __volatile__(".byte 0xf3 ; lock ; cmpxchg %2, %1" + __asm__ __volatile__(".byte 0xf3 ; lock ; cmpxchg {%2, %1|%1, %2}" : "+a" (_Comparand), "+m" (*_Destination) : "r" (_Exchange) : "memory"); return _Comparand; @@ -593,7 +593,7 @@ static __inline__ __int64 __DEFAULT_FN_ATTRS _InterlockedCompareExchange64_HLEAcquire(__int64 volatile *_Destination, __int64 _Exchange, __int64 _Comparand) { - __asm__ __volatile__(".byte 0xf2 ; lock ; cmpxchg %2, %1" + __asm__ __volatile__(".byte 0xf2 ; lock ; cmpxchg {%2, %1|%1, %2}" : "+a" (_Comparand), "+m" (*_Destination) : "r" (_Exchange) : "memory"); return _Comparand; @@ -601,7 +601,7 @@ static __inline__ __int64 __DEFAULT_FN_ATTRS _InterlockedCompareExchange64_HLERelease(__int64 volatile *_Destination, __int64 _Exchange, __int64 _Comparand) { - __asm__ __volatile__(".byte 0xf3 ; lock ; cmpxchg %2, %1" + __asm__ __volatile__(".byte 0xf3 ; lock ; cmpxchg {%2, %1|%1, %2}" : "+a" (_Comparand), "+m" (*_Destination) : "r" (_Exchange) : "memory"); return _Comparand; Index: clang/lib/Headers/intrin.h =================================================================== --- clang/lib/Headers/intrin.h +++ clang/lib/Headers/intrin.h @@ -455,7 +455,9 @@ : : "memory"); #else - __asm__ __volatile__("xchg %%esi, %1\nrep movsb\nxchg %%esi, %1" + __asm__ __volatile__("xchg {%%esi, %1|%1, esi}\n" + "rep movsb\n" + "xchg {%%esi, %1|%1, esi}" : "+D"(__dst), "+r"(__src), "+c"(__n) : : "memory"); @@ -465,12 +467,14 @@ unsigned long const *__src, size_t __n) { #if defined(__x86_64__) - __asm__ __volatile__("rep movsl" + __asm__ __volatile__("rep movs{l|d}" : "+D"(__dst), "+S"(__src), "+c"(__n) : : "memory"); #else - __asm__ __volatile__("xchg %%esi, %1\nrep movsl\nxchg %%esi, %1" + __asm__ __volatile__("xchg {%%esi, %1|%1, esi}\n" + "rep movs{l|d}\n" + "xchg {%%esi, %1|%1, esi}" : "+D"(__dst), "+r"(__src), "+c"(__n) : : "memory"); @@ -485,7 +489,9 @@ : : "memory"); #else - __asm__ __volatile__("xchg %%esi, %1\nrep movsw\nxchg %%esi, %1" + __asm__ __volatile__("xchg {%%esi, %1|%1, esi}\n" + "rep movsw\n" + "xchg {%%esi, %1|%1, esi}" : "+D"(__dst), "+r"(__src), "+c"(__n) : : "memory"); @@ -494,7 +500,7 @@ static __inline__ void __DEFAULT_FN_ATTRS __stosd(unsigned long *__dst, unsigned long __x, size_t __n) { - __asm__ __volatile__("rep stosl" + __asm__ __volatile__("rep stos{l|d}" : "+D"(__dst), "+c"(__n) : "a"(__x) : "memory"); @@ -536,9 +542,9 @@ #else /* x86-64 uses %rbx as the base register, so preserve it. */ #define __cpuid_count(__leaf, __count, __eax, __ebx, __ecx, __edx) \ - __asm("xchgq %%rbx,%q1\n" \ + __asm("xchg{q} {%%rbx, %q1|%q1, rbx}\n" \ "cpuid\n" \ - "xchgq %%rbx,%q1" \ + "xchg{q} {%%rbx, %q1|%q1, rbx}" \ : "=a"(__eax), "=r"(__ebx), "=c"(__ecx), "=d"(__edx) \ : "0"(__leaf), "2"(__count)) #endif @@ -598,13 +604,17 @@ static __inline__ unsigned __LPTRINT_TYPE__ __DEFAULT_FN_ATTRS __readcr3(void) { unsigned __LPTRINT_TYPE__ __cr3_val; - __asm__ __volatile__ ("mov %%cr3, %0" : "=r"(__cr3_val) : : "memory"); + __asm__ __volatile__( + "mov {%%cr3, %0|%0, cr3}" + : "=r"(__cr3_val) + : + : "memory"); return __cr3_val; } static __inline__ void __DEFAULT_FN_ATTRS __writecr3(unsigned __INTPTR_TYPE__ __cr3_val) { - __asm__ ("mov %0, %%cr3" : : "r"(__cr3_val) : "memory"); + __asm__ ("mov {%0, %%cr3|cr3, %0}" : : "r"(__cr3_val) : "memory"); } #ifdef __cplusplus Index: clang/lib/Headers/x86gprintrin.h =================================================================== --- clang/lib/Headers/x86gprintrin.h +++ clang/lib/Headers/x86gprintrin.h @@ -26,8 +26,10 @@ #endif #define __SSC_MARK(Tag) \ - __asm__ __volatile__("movl %%ebx, %%eax; movl %0, %%ebx; .byte 0x64, 0x67, " \ - "0x90; movl %%eax, %%ebx;" ::"i"(Tag) \ + __asm__ __volatile__("mov{l} {%%ebx, %%eax|eax, ebx}; " \ + "mov{l} {%0, %%ebx|ebx, %0}; " \ + ".byte 0x64, 0x67, 0x90; " \ + "mov{l} {%%eax, %%ebx|ebx, eax};" ::"i"(Tag) \ : "%eax"); #endif /* __X86GPRINTRIN_H */ Index: clang/test/CodeGen/inline-asm-intel.c =================================================================== --- /dev/null +++ clang/test/CodeGen/inline-asm-intel.c @@ -0,0 +1,82 @@ +// REQUIRES: x86-registered-target + +/// Accept intel inline asm but write it out as att: +// RUN: %clang_cc1 -Werror -target-feature +hreset -target-feature +pconfig -target-feature +sgx -ffreestanding -triple i386-unknown-unknown -mllvm -x86-asm-syntax=att -inline-asm=intel -O0 -S %s -o - | FileCheck --check-prefix=ATT %s +// RUN: %clang_cc1 -Werror -target-feature +hreset -target-feature +pconfig -target-feature +sgx -ffreestanding -triple x86_64-unknown-unknown -mllvm -x86-asm-syntax=att -inline-asm=intel -O0 -S %s -o - | FileCheck --check-prefix=ATT %s + +/// Accept intel inline asm and write it out as intel: +// RUN: %clang_cc1 -Werror -target-feature +hreset -target-feature +pconfig -target-feature +sgx -ffreestanding -triple i386-unknown-unknown -mllvm -x86-asm-syntax=intel -inline-asm=intel -O0 -S %s -o - | FileCheck --check-prefix=INTEL %s +// RUN: %clang_cc1 -Werror -target-feature +hreset -target-feature +pconfig -target-feature +sgx -ffreestanding -triple x86_64-unknown-unknown -mllvm -x86-asm-syntax=intel -inline-asm=intel -O0 -S %s -o - | FileCheck --check-prefix=INTEL %s + +// RUN: %clang_cc1 -Werror -target-feature +hreset -target-feature +pconfig -target-feature +sgx -ffreestanding -triple i386-pc-win32 -mllvm -x86-asm-syntax=intel -inline-asm=intel -O0 -S %s -o - -fms-extensions -fms-compatibility -fms-compatibility-version=17.00 | FileCheck --check-prefix=INTEL %s +// RUN: %clang_cc1 -Werror -target-feature +hreset -target-feature +pconfig -target-feature +sgx -ffreestanding -triple x86_64-pc-win32 -mllvm -x86-asm-syntax=intel -inline-asm=intel -O0 -S %s -o - -fms-extensions -fms-compatibility -fms-compatibility-version=17.00 | FileCheck --check-prefix=INTEL %s + +// Test that intrinsics headers still work with -masm=intel. +#ifdef _MSC_VER +#include +#else +#include +#endif + +void f() { + // Intrinsic headers contain macros and inline functions. + // Inline assembly in both are checked only when they are + // referenced, so reference a few intrinsics here. + __SSC_MARK(4); + int a; + _hreset(a); + _pconfig_u32(0, (void*)0); + + _encls_u32(0, (void*)0); + _enclu_u32(0, (void*)0); + _enclv_u32(0, (void*)0); +#ifdef _MSC_VER + __movsb((void*)0, (void*)0, 0); + __movsd((void*)0, (void*)0, 0); + __movsw((void*)0, (void*)0, 0); + __stosb((void*)0, 0, 0); + __stosd((void*)0, 0, 0); + __stosw((void*)0, 0, 0); +#ifdef __x86_64__ + __movsq((void*)0, (void*)0, 0); + __stosq((void*)0, 0, 0); +#endif + __cpuid((void*)0, 0); + __cpuidex((void*)0, 0, 0); + __halt(); + __nop(); + __readmsr(0); + __readcr3(); + __writecr3(0); + + _InterlockedExchange_HLEAcquire((void*)0, 0); + _InterlockedExchange_HLERelease((void*)0, 0); + _InterlockedCompareExchange_HLEAcquire((void*)0, 0, 0); + _InterlockedCompareExchange_HLERelease((void*)0, 0, 0); +#ifdef __x86_64__ + _InterlockedExchange64_HLEAcquire((void*)0, 0); + _InterlockedExchange64_HLERelease((void*)0, 0); + _InterlockedCompareExchange64_HLEAcquire((void*)0, 0, 0); + _InterlockedCompareExchange64_HLERelease((void*)0, 0, 0); +#endif +#endif + + + __asm__("mov eax, ebx"); + // ATT: movl %ebx, %eax + // INTEL: mov eax, ebx + + // Explicitly overriding asm style per block works: + __asm__(".att_syntax\nmovl %ebx, %eax"); + // ATT: movl %ebx, %eax + // INTEL: mov eax, ebx + + // The .att_syntax was only scoped to the previous statement. + // (This is different from gcc, where `.att_syntax` is in + // effect from that point on, so portable code would want an + // explicit `.intel_syntax noprefix\n` at the start of this string). + __asm__("mov eax, ebx"); + // ATT: movl %ebx, %eax + // INTEL: mov eax, ebx +} + Index: clang/test/CodeGen/inline-asm-mixed-style.c =================================================================== --- clang/test/CodeGen/inline-asm-mixed-style.c +++ clang/test/CodeGen/inline-asm-mixed-style.c @@ -1,6 +1,9 @@ // RUN: %clang_cc1 -triple i386-unknown-unknown -fasm-blocks -O0 -emit-llvm -S %s -o - | FileCheck %s +// RUN: %clang_cc1 -triple x86_64-unknown-unknown -fasm-blocks -O0 -emit-llvm -S %s -o - | FileCheck %s // REQUIRES: x86-registered-target +#include + void f() { __asm mov eax, ebx __asm mov ebx, ecx Index: clang/test/Driver/masm.c =================================================================== --- clang/test/Driver/masm.c +++ clang/test/Driver/masm.c @@ -6,9 +6,12 @@ int f() { // CHECK-INTEL: -x86-asm-syntax=intel +// CHECK-INTEL: -inline-asm=intel // CHECK-ATT: -x86-asm-syntax=att +// CHECK-ATT: -inline-asm=att // CHECK-SOMEREQUIRED: error: unsupported argument 'somerequired' to option 'masm=' // CHECK-ARM: warning: argument unused during compilation: '-masm=intel' // CHECK-CL: -x86-asm-syntax=intel +// CHECK-CL-NOT: -inline-asm=intel return 0; }