File: microsoft-abi-multiple-nonvirtual-inheritance.cpp

package info (click to toggle)
llvm-toolchain-17 1%3A17.0.6-22
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid, trixie
  • size: 1,799,624 kB
  • sloc: cpp: 6,428,607; ansic: 1,383,196; asm: 793,408; python: 223,504; objc: 75,364; f90: 60,502; lisp: 33,869; pascal: 15,282; sh: 9,684; perl: 7,453; ml: 4,937; awk: 3,523; makefile: 2,889; javascript: 2,149; xml: 888; fortran: 619; cs: 573
file content (181 lines) | stat: -rw-r--r-- 6,008 bytes parent folder | download | duplicates (10)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
// RUN: %clang_cc1 -fno-rtti -emit-llvm %s -o - -mconstructor-aliases -triple=i386-pc-win32 | FileCheck %s

struct Left {
  virtual void left();
};

struct Right {
  virtual void right();
};

struct ChildNoOverride : Left, Right {
};

struct ChildOverride : Left, Right {
  virtual void left();
  virtual void right();
};

extern "C" void foo(void *);

void call_left_no_override(ChildNoOverride *child) {
// CHECK-LABEL: define dso_local void @"?call_left_no_override
// CHECK: %[[CHILD:.*]] = load ptr

  child->left();
// Only need to cast 'this' to Left*.
// CHECK: %[[VFTABLE:.*]] = load ptr, ptr %[[CHILD]]
// CHECK: %[[VFUN:.*]] = getelementptr inbounds ptr, ptr %[[VFTABLE]], i64 0
// CHECK: %[[VFUN_VALUE:.*]] = load ptr, ptr %[[VFUN]]
// CHECK: call x86_thiscallcc void %[[VFUN_VALUE]](ptr {{[^,]*}} %[[CHILD]])
// CHECK: ret
}

void ChildOverride::left() {
// CHECK-LABEL: define dso_local x86_thiscallcc void @"?left@ChildOverride@@UAEXXZ"
// CHECK-SAME: (ptr {{[^,]*}} %[[THIS:.*]])
//
// No need to adjust 'this' as the ChildOverride's layout begins with Left.
// CHECK: %[[THIS_ADDR:.*]] = alloca ptr, align 4
// CHECK: store ptr %[[THIS]], ptr %[[THIS_ADDR]], align 4

  foo(this);
// CHECK: %[[THIS:.*]] = load ptr, ptr %[[THIS_ADDR]]
// CHECK: call void @foo(ptr noundef %[[THIS]])
// CHECK: ret
}

void call_left_override(ChildOverride *child) {
// CHECK-LABEL: define dso_local void @"?call_left_override
// CHECK: %[[CHILD:.*]] = load ptr

  child->left();
// CHECK: %[[VFTABLE:.*]] = load ptr, ptr %[[CHILD]]
// CHECK: %[[VFUN:.*]] = getelementptr inbounds ptr, ptr %[[VFTABLE]], i64 0
// CHECK: %[[VFUN_VALUE:.*]] = load ptr, ptr %[[VFUN]]
//
// CHECK: call x86_thiscallcc void %[[VFUN_VALUE]](ptr {{[^,]*}} %[[CHILD]])
// CHECK: ret
}

void call_right_no_override(ChildNoOverride *child) {
// CHECK-LABEL: define dso_local void @"?call_right_no_override
// CHECK: %[[CHILD:.*]] = load ptr

  child->right();
// When calling a right base's virtual method, one needs to adjust 'this' at
// the caller site.
//
// CHECK: %[[RIGHT_i8:.*]] = getelementptr inbounds i8, ptr %[[CHILD]], i32 4
//
// CHECK: %[[VFTABLE:.*]] = load ptr, ptr %[[RIGHT_i8]]
// CHECK: %[[VFUN:.*]] = getelementptr inbounds ptr, ptr %[[VFTABLE]], i64 0
// CHECK: %[[VFUN_VALUE:.*]] = load ptr, ptr %[[VFUN]]
// CHECK: call x86_thiscallcc void %[[VFUN_VALUE]](ptr {{[^,]*}} %[[RIGHT_i8]])
// CHECK: ret
}

void ChildOverride::right() {
// CHECK-LABEL: define dso_local x86_thiscallcc void @"?right@ChildOverride@@UAEXXZ"(ptr
//
// ChildOverride::right gets 'this' cast to Right* in ECX (i.e. this+4) so we
// need to adjust 'this' before use.
//
// CHECK: %[[THIS_ADDR:.*]] = alloca ptr, align 4
// CHECK: store ptr %[[ECX:.*]], ptr %[[THIS_ADDR]], align 4
// CHECK: %[[THIS_RELOAD:.*]] = load ptr, ptr %[[THIS_ADDR]]
// CHECK: %[[THIS_ADJUSTED:.*]] = getelementptr inbounds i8, ptr %[[THIS_RELOAD]], i32 -4

  foo(this);
// CHECK: call void @foo(ptr noundef %[[THIS_ADJUSTED]])
// CHECK: ret
}

void call_right_override(ChildOverride *child) {
// CHECK-LABEL: define dso_local void @"?call_right_override
// CHECK: %[[CHILD:.*]] = load ptr

  child->right();
// When calling a right child's virtual method, one needs to adjust 'this' at
// the caller site.
//
// CHECK: %[[RIGHT:.*]] = getelementptr inbounds i8, ptr %[[CHILD]], i32 4
//
// CHECK: %[[VFPTR_i8:.*]] = getelementptr inbounds i8, ptr %[[CHILD]], i32 4
// CHECK: %[[VFTABLE:.*]] = load ptr, ptr %[[VFPTR_i8]]
// CHECK: %[[VFUN:.*]] = getelementptr inbounds ptr, ptr %[[VFTABLE]], i64 0
// CHECK: %[[VFUN_VALUE:.*]] = load ptr, ptr %[[VFUN]]
//
// CHECK: call x86_thiscallcc void %[[VFUN_VALUE]](ptr noundef %[[RIGHT]])
// CHECK: ret
}

struct GrandchildOverride : ChildOverride {
  virtual void right();
};

void GrandchildOverride::right() {
// CHECK-LABEL: define dso_local x86_thiscallcc void @"?right@GrandchildOverride@@UAEXXZ"(ptr
//
// CHECK: %[[THIS_ADDR:.*]] = alloca ptr, align 4
// CHECK: store ptr %[[ECX:.*]], ptr %[[THIS_ADDR]], align 4
// CHECK: %[[THIS_RELOAD:.*]] = load ptr, ptr %[[THIS_ADDR]]
// CHECK: %[[THIS_ADJUSTED:.*]] = getelementptr inbounds i8, ptr %[[THIS_RELOAD]], i32 -4

  foo(this);
// CHECK: call void @foo(ptr noundef %[[THIS_ADJUSTED]])
// CHECK: ret
}

void call_grandchild_right(GrandchildOverride *obj) {
  // Just make sure we don't crash.
  obj->right();
}

void emit_ctors() {
  Left l;
  // CHECK-LABEL: define {{.*}} @"??0Left@@QAE@XZ"
  // CHECK-NOT: getelementptr
  // CHECK:   store ptr @"??_7Left@@6B@"
  // CHECK: ret

  Right r;
  // CHECK-LABEL: define {{.*}} @"??0Right@@QAE@XZ"
  // CHECK-NOT: getelementptr
  // CHECK:   store ptr @"??_7Right@@6B@"
  // CHECK: ret

  ChildOverride co;
  // CHECK-LABEL: define {{.*}} @"??0ChildOverride@@QAE@XZ"
  // CHECK:   %[[THIS:.*]] = load ptr, ptr
  // CHECK:   store ptr @"??_7ChildOverride@@6BLeft@@@", ptr %[[THIS]]
  // CHECK:   %[[VFPTR_i8:.*]] = getelementptr inbounds i8, ptr %[[THIS]], i32 4
  // CHECK:   store ptr @"??_7ChildOverride@@6BRight@@@", ptr %[[VFPTR_i8]]
  // CHECK: ret

  GrandchildOverride gc;
  // CHECK-LABEL: define {{.*}} @"??0GrandchildOverride@@QAE@XZ"
  // CHECK:   %[[THIS:.*]] = load ptr, ptr
  // CHECK:   store ptr @"??_7GrandchildOverride@@6BLeft@@@", ptr %[[THIS]]
  // CHECK:   %[[VFPTR_i8:.*]] = getelementptr inbounds i8, ptr %[[THIS]], i32 4
  // CHECK:   store ptr @"??_7GrandchildOverride@@6BRight@@@", ptr %[[VFPTR_i8]]
  // CHECK: ret
}

struct LeftWithNonVirtualDtor {
  virtual void left();
  ~LeftWithNonVirtualDtor();
};

struct AsymmetricChild : LeftWithNonVirtualDtor, Right {
  virtual ~AsymmetricChild();
};

void call_asymmetric_child_complete_dtor() {
  // CHECK-LABEL: define dso_local void @"?call_asymmetric_child_complete_dtor@@YAXXZ"
  AsymmetricChild obj;
  // CHECK: call x86_thiscallcc noundef ptr @"??0AsymmetricChild@@QAE@XZ"(ptr {{[^,]*}} %[[OBJ:.*]])
  // CHECK-NOT: getelementptr
  // CHECK: call x86_thiscallcc void @"??1AsymmetricChild@@UAE@XZ"(ptr {{[^,]*}} %[[OBJ]])
  // CHECK: ret
}