1 // RUN: %clang_cc1 -triple x86_64-linux-gnu -emit-llvm -o - %s | FileCheck %s
2
3 // CHECK-LABEL: define{{.*}} void @foo_no_mempcy() #0
foo_no_mempcy()4 extern "C" void foo_no_mempcy() __attribute__((no_builtin("memcpy"))) {}
5
6 // CHECK-LABEL: define{{.*}} void @foo_no_mempcy_twice() #0
foo_no_mempcy_twice()7 extern "C" void foo_no_mempcy_twice() __attribute__((no_builtin("memcpy"))) __attribute__((no_builtin("memcpy"))) {}
8
9 // CHECK-LABEL: define{{.*}} void @foo_no_builtins() #1
foo_no_builtins()10 extern "C" void foo_no_builtins() __attribute__((no_builtin)) {}
11
12 // CHECK-LABEL: define{{.*}} void @foo_no_mempcy_memset() #2
foo_no_mempcy_memset()13 extern "C" void foo_no_mempcy_memset() __attribute__((no_builtin("memset", "memcpy"))) {}
14
15 // CHECK-LABEL: define{{.*}} void @separate_attrs() #2
separate_attrs()16 extern "C" void separate_attrs() __attribute__((no_builtin("memset"))) __attribute__((no_builtin("memcpy"))) {}
17
18 // CHECK-LABEL: define{{.*}} void @separate_attrs_ordering() #2
separate_attrs_ordering()19 extern "C" void separate_attrs_ordering() __attribute__((no_builtin("memcpy"))) __attribute__((no_builtin("memset"))) {}
20
21 struct A {
fooA22 virtual int foo() const __attribute__((no_builtin("memcpy"))) { return 1; }
23 virtual ~A();
24 };
25
26 struct B : public A {
fooB27 int foo() const override __attribute__((no_builtin("memmove"))) { return 2; }
28 virtual ~B();
29 };
30
31 // CHECK-LABEL: define{{.*}} void @call_a_foo(ptr noundef %a) #3
call_a_foo(A * a)32 extern "C" void call_a_foo(A *a) {
33 // CHECK: %call = call noundef i32 %1(ptr {{[^,]*}} %0)
34 a->foo(); // virtual call is not annotated
35 }
36
37 // CHECK-LABEL: define{{.*}} void @call_b_foo(ptr noundef %b) #3
call_b_foo(B * b)38 extern "C" void call_b_foo(B *b) {
39 // CHECK: %call = call noundef i32 %1(ptr {{[^,]*}} %0)
40 b->foo(); // virtual call is not annotated
41 }
42
43 // CHECK-LABEL: define{{.*}} void @call_foo_no_mempcy() #3
call_foo_no_mempcy()44 extern "C" void call_foo_no_mempcy() {
45 // CHECK: call void @foo_no_mempcy() #6
46 foo_no_mempcy(); // call gets annotated with "no-builtin-memcpy"
47 }
48
~A()49 A::~A() {} // Anchoring A so A::foo() gets generated
~B()50 B::~B() {} // Anchoring B so B::foo() gets generated
51
52 // CHECK-LABEL: define linkonce_odr noundef i32 @_ZNK1A3fooEv(ptr noundef{{[^,]*}} %this) unnamed_addr #0 comdat align 2
53 // CHECK-LABEL: define linkonce_odr noundef i32 @_ZNK1B3fooEv(ptr noundef{{[^,]*}} %this) unnamed_addr #5 comdat align 2
54
55 // CHECK: attributes #0 = {{{.*}}"no-builtin-memcpy"{{.*}}}
56 // CHECK-NOT: attributes #0 = {{{.*}}"no-builtin-memmove"{{.*}}}
57 // CHECK-NOT: attributes #0 = {{{.*}}"no-builtin-memset"{{.*}}}
58 // CHECK: attributes #1 = {{{.*}}"no-builtins"{{.*}}}
59 // CHECK: attributes #2 = {{{.*}}"no-builtin-memcpy"{{.*}}"no-builtin-memset"{{.*}}}
60 // CHECK-NOT: attributes #2 = {{{.*}}"no-builtin-memmove"{{.*}}}
61 // CHECK: attributes #6 = {{{.*}}"no-builtin-memcpy"{{.*}}}
62 // CHECK-NOT: attributes #5 = {{{.*}}"no-builtin-memcpy"{{.*}}}
63 // CHECK-NOT: attributes #5 = {{{.*}}"no-builtin-memset"{{.*}}}
64 // CHECK: attributes #8 = { builtin nounwind }
65