Files
clang-p2996/clang/test/CodeGen/ms-inline-asm.cpp
Reid Kleckner 6d2ea6ec80 [ms-inline-asm] Use the frontend size only for ambiguous instructions
This avoids problems on code like this:
  char buf[16];
  __asm {
    movups xmm0, [buf]
    mov [buf], eax
  }

The frontend size in this case (1) is wrong, and the register makes the
instruction matching unambiguous. There are also enough bytes available
that we shouldn't complain to the user that they are potentially using
an incorrectly sized instruction to access the variable.

Supersedes D32636 and D26586 and fixes PR28266

llvm-svn: 302179
2017-05-04 18:19:52 +00:00

183 lines
4.8 KiB
C++

// REQUIRES: x86-registered-target
// RUN: %clang_cc1 -x c++ %s -triple i386-apple-darwin10 -fasm-blocks -emit-llvm -o - -std=c++11 | FileCheck %s
// rdar://13645930
struct Foo {
static int *ptr;
static int a, b;
int arr[4];
struct Bar {
static int *ptr;
char arr[2];
};
};
void t1() {
// CHECK-LABEL: define void @_Z2t1v()
Foo::ptr = (int *)0xDEADBEEF;
Foo::Bar::ptr = (int *)0xDEADBEEF;
// CHECK: call void asm sideeffect inteldialect
// CHECK-SAME: mov eax, $0
// CHECK-SAME: mov eax, $1
// CHECK-SAME: mov eax, $2
// CHECK-SAME: mov eax, dword ptr $3
// CHECK-SAME: mov eax, dword ptr $4
// CHECK-SAME: "*m,*m,*m,*m,*m,~{eax},~{dirflag},~{fpsr},~{flags}"(i32** @_ZN3Foo3ptrE, i32** @_ZN3Foo3Bar3ptrE, i32** @_ZN3Foo3ptrE, i32** @_ZN3Foo3ptrE, i32** @_ZN3Foo3ptrE)
__asm mov eax, Foo ::ptr
__asm mov eax, Foo :: Bar :: ptr
__asm mov eax, [Foo:: ptr]
__asm mov eax, dword ptr [Foo :: ptr]
__asm mov eax, dword ptr [Foo :: ptr]
}
int gvar = 10;
void t2() {
int lvar = 10;
__asm mov eax, offset Foo::ptr
__asm mov eax, offset Foo::Bar::ptr
// CHECK-LABEL: define void @_Z2t2v()
// CHECK: call void asm sideeffect inteldialect
// CHECK-SAME: mov eax, $0
// CHECK-SAME: mov eax, $1
// CHECK-SAME: "r,r,~{eax},~{dirflag},~{fpsr},~{flags}"(i32** @_ZN3Foo3ptrE, i32** @_ZN3Foo3Bar3ptrE)
}
// CHECK-LABEL: define void @_Z2t3v()
void t3() {
__asm mov eax, LENGTH Foo::ptr
__asm mov eax, LENGTH Foo::Bar::ptr
__asm mov eax, LENGTH Foo::arr
__asm mov eax, LENGTH Foo::Bar::arr
__asm mov eax, TYPE Foo::ptr
__asm mov eax, TYPE Foo::Bar::ptr
__asm mov eax, TYPE Foo::arr
__asm mov eax, TYPE Foo::Bar::arr
__asm mov eax, SIZE Foo::ptr
__asm mov eax, SIZE Foo::Bar::ptr
__asm mov eax, SIZE Foo::arr
__asm mov eax, SIZE Foo::Bar::arr
// CHECK: call void asm sideeffect inteldialect
// CHECK-SAME: mov eax, $$1
// CHECK-SAME: mov eax, $$1
// CHECK-SAME: mov eax, $$4
// CHECK-SAME: mov eax, $$2
// CHECK-SAME: mov eax, $$4
// CHECK-SAME: mov eax, $$4
// CHECK-SAME: mov eax, $$4
// CHECK-SAME: mov eax, $$1
// CHECK-SAME: mov eax, $$4
// CHECK-SAME: mov eax, $$4
// CHECK-SAME: mov eax, $$16
// CHECK-SAME: mov eax, $$2
// CHECK-SAME: "~{eax},~{dirflag},~{fpsr},~{flags}"()
}
struct T4 {
int x;
static int y;
void test();
};
// CHECK-LABEL: define void @_ZN2T44testEv(
void T4::test() {
// CHECK: [[T0:%.*]] = alloca [[T4:%.*]]*,
// CHECK: [[THIS:%.*]] = load [[T4]]*, [[T4]]** [[T0]]
// CHECK: [[X:%.*]] = getelementptr inbounds [[T4]], [[T4]]* [[THIS]], i32 0, i32 0
__asm mov eax, x;
__asm mov y, eax;
// CHECK: call void asm sideeffect inteldialect
// CHECK-SAME: mov eax, $1
// CHECK-SAME: mov $0, eax
// CHECK-SAME: "=*m,*m,~{eax},~{dirflag},~{fpsr},~{flags}"(i32* @_ZN2T41yE, i32* {{.*}})
}
template <class T> struct T5 {
template <class U> static T create(U);
void run();
};
// CHECK-LABEL: define void @_Z5test5v()
void test5() {
// CHECK: [[X:%.*]] = alloca i32
// CHECK: [[Y:%.*]] = alloca i32
int x, y;
__asm push y
__asm call T5<int>::create<float>
__asm mov x, eax
// CHECK: call void asm sideeffect inteldialect
// CHECK-SAME: push $0
// CHECK-SAME: call dword ptr $2
// CHECK-SAME: mov $1, eax
// CHECK-SAME: "=*m,=*m,*m,~{esp},~{dirflag},~{fpsr},~{flags}"(i32* %y, i32* %x, i32 (float)* @_ZN2T5IiE6createIfEEiT_)
}
// Just verify this doesn't emit an error.
void test6() {
__asm {
a:
jmp a
}
}
void t7_struct() {
struct A {
int a;
int b;
};
__asm mov eax, [eax].A.b
// CHECK-LABEL: define void @_Z9t7_structv
// CHECK: call void asm sideeffect inteldialect
// CHECK-SAME: mov eax, [eax].4
// CHECK-SAME: "~{eax},~{dirflag},~{fpsr},~{flags}"()
}
void t7_typedef() {
typedef struct {
int a;
int b;
} A;
__asm mov eax, [eax].A.b
// CHECK-LABEL: define void @_Z10t7_typedefv
// CHECK: call void asm sideeffect inteldialect
// CHECK-SAME: mov eax, [eax].4
// CHECK-SAME: "~{eax},~{dirflag},~{fpsr},~{flags}"()
}
void t7_using() {
using A = struct {
int a;
int b;
};
__asm mov eax, [eax].A.b
// CHECK-LABEL: define void @_Z8t7_usingv
// CHECK: call void asm sideeffect inteldialect
// CHECK-SAME: mov eax, [eax].4
// CHECK-SAME: "~{eax},~{dirflag},~{fpsr},~{flags}"()
}
void t8() {
__asm some_label:
// CHECK-LABEL: define void @_Z2t8v()
// CHECK: call void asm sideeffect inteldialect
// CHECK-SAME: L__MSASMLABEL_.${:uid}__some_label:
// CHECK-SAME: "~{dirflag},~{fpsr},~{flags}"()
struct A {
static void g() {
__asm jmp some_label ; This should jump forwards
__asm some_label:
__asm nop
// CHECK-LABEL: define internal void @_ZZ2t8vEN1A1gEv()
// CHECK: call void asm sideeffect inteldialect
// CHECK-SAME: jmp L__MSASMLABEL_.${:uid}__some_label
// CHECK-SAME: L__MSASMLABEL_.${:uid}__some_label:
// CHECK-SAME: nop
// CHECK-SAME: "~{dirflag},~{fpsr},~{flags}"()
}
};
A::g();
}