1; RUN: llc < %s -asm-verbose=false -wasm-disable-explicit-locals -wasm-keep-registers | FileCheck %s --check-prefix=TYPEINFONAME 2; RUN: llc < %s -asm-verbose=false -wasm-disable-explicit-locals -wasm-keep-registers | FileCheck %s --check-prefix=VTABLE 3; RUN: llc < %s -asm-verbose=false -wasm-disable-explicit-locals -wasm-keep-registers | FileCheck %s --check-prefix=TYPEINFO 4 5; Test that simple vtables assemble as expected. 6; 7; The class hierarchy is: 8; struct A; 9; struct B : public A; 10; struct C : public A; 11; struct D : public B; 12; Each with a virtual dtor and method foo. 13 14target triple = "wasm32-unknown-unknown" 15 16%struct.A = type { ptr } 17%struct.B = type { %struct.A } 18%struct.C = type { %struct.A } 19%struct.D = type { %struct.B } 20 21@_ZTVN10__cxxabiv117__class_type_infoE = external global ptr 22@_ZTVN10__cxxabiv120__si_class_type_infoE = external global ptr 23 24; TYPEINFONAME-LABEL: _ZTS1A: 25; TYPEINFONAME-NEXT: .asciz "1A" 26@_ZTS1A = constant [3 x i8] c"1A\00" 27; TYPEINFONAME-LABEL: _ZTS1B: 28; TYPEINFONAME-NEXT: .asciz "1B" 29@_ZTS1B = constant [3 x i8] c"1B\00" 30; TYPEINFONAME-LABEL: _ZTS1C: 31; TYPEINFONAME-NEXT: .asciz "1C" 32@_ZTS1C = constant [3 x i8] c"1C\00" 33; TYPEINFONAME-LABEL: _ZTS1D: 34; TYPEINFONAME-NEXT: .asciz "1D" 35@_ZTS1D = constant [3 x i8] c"1D\00" 36 37; VTABLE: .type _ZTV1A,@object 38; VTABLE-NEXT: .section .rodata._ZTV1A, 39; VTABLE-NEXT: .globl _ZTV1A 40; VTABLE-LABEL: _ZTV1A: 41; VTABLE-NEXT: .int32 0 42; VTABLE-NEXT: .int32 _ZTI1A 43; VTABLE-NEXT: .int32 _ZN1AD2Ev 44; VTABLE-NEXT: .int32 _ZN1AD0Ev 45; VTABLE-NEXT: .int32 _ZN1A3fooEv 46; VTABLE-NEXT: .size _ZTV1A, 20 47@_ZTV1A = constant [5 x ptr] [ptr null, ptr @_ZTI1A, ptr @_ZN1AD2Ev, ptr @_ZN1AD0Ev, ptr @_ZN1A3fooEv], align 4 48; VTABLE: .type _ZTV1B,@object 49; VTABLE-NEXT: .section .rodata._ZTV1B, 50; VTABLE-NEXT: .globl _ZTV1B 51; VTABLE-LABEL: _ZTV1B: 52; VTABLE-NEXT: .int32 0 53; VTABLE-NEXT: .int32 _ZTI1B 54; VTABLE-NEXT: .int32 _ZN1AD2Ev 55; VTABLE-NEXT: .int32 _ZN1BD0Ev 56; VTABLE-NEXT: .int32 _ZN1B3fooEv 57; VTABLE-NEXT: .size _ZTV1B, 20 58@_ZTV1B = constant [5 x ptr] [ptr null, ptr @_ZTI1B, ptr @_ZN1AD2Ev, ptr @_ZN1BD0Ev, ptr @_ZN1B3fooEv], align 4 59; VTABLE: .type _ZTV1C,@object 60; VTABLE-NEXT: .section .rodata._ZTV1C, 61; VTABLE-NEXT: .globl _ZTV1C 62; VTABLE-LABEL: _ZTV1C: 63; VTABLE-NEXT: .int32 0 64; VTABLE-NEXT: .int32 _ZTI1C 65; VTABLE-NEXT: .int32 _ZN1AD2Ev 66; VTABLE-NEXT: .int32 _ZN1CD0Ev 67; VTABLE-NEXT: .int32 _ZN1C3fooEv 68; VTABLE-NEXT: .size _ZTV1C, 20 69@_ZTV1C = constant [5 x ptr] [ptr null, ptr @_ZTI1C, ptr @_ZN1AD2Ev, ptr @_ZN1CD0Ev, ptr @_ZN1C3fooEv], align 4 70; VTABLE: .type _ZTV1D,@object 71; VTABLE-NEXT: .section .rodata._ZTV1D, 72; VTABLE-NEXT: .globl _ZTV1D 73; VTABLE-LABEL: _ZTV1D: 74; VTABLE-NEXT: .int32 0 75; VTABLE-NEXT: .int32 _ZTI1D 76; VTABLE-NEXT: .int32 _ZN1AD2Ev 77; VTABLE-NEXT: .int32 _ZN1DD0Ev 78; VTABLE-NEXT: .int32 _ZN1D3fooEv 79; VTABLE-NEXT: .size _ZTV1D, 20 80@_ZTV1D = constant [5 x ptr] [ptr null, ptr @_ZTI1D, ptr @_ZN1AD2Ev, ptr @_ZN1DD0Ev, ptr @_ZN1D3fooEv], align 4 81 82; TYPEINFO: .type _ZTI1A,@object 83; TYPEINFO: .globl _ZTI1A 84; TYPEINFO-LABEL: _ZTI1A: 85; TYPEINFO-NEXT: .int32 _ZTVN10__cxxabiv117__class_type_infoE+8 86; TYPEINFO-NEXT: .int32 _ZTS1A 87; TYPEINFO-NEXT: .size _ZTI1A, 8 88@_ZTI1A = constant { ptr, ptr } { ptr getelementptr inbounds (ptr, ptr @_ZTVN10__cxxabiv117__class_type_infoE, i32 2), ptr @_ZTS1A } 89; TYPEINFO: .type _ZTI1B,@object 90; TYPEINFO: .globl _ZTI1B 91; TYPEINFO-LABEL: _ZTI1B: 92; TYPEINFO-NEXT: .int32 _ZTVN10__cxxabiv120__si_class_type_infoE+8 93; TYPEINFO-NEXT: .int32 _ZTS1B 94; TYPEINFO-NEXT: .int32 _ZTI1A 95; TYPEINFO-NEXT: .size _ZTI1B, 12 96@_ZTI1B = constant { ptr, ptr, ptr } { ptr getelementptr inbounds (ptr, ptr @_ZTVN10__cxxabiv120__si_class_type_infoE, i32 2), ptr @_ZTS1B, ptr @_ZTI1A } 97; TYPEINFO: .type _ZTI1C,@object 98; TYPEINFO: .globl _ZTI1C 99; TYPEINFO-LABEL: _ZTI1C: 100; TYPEINFO-NEXT: .int32 _ZTVN10__cxxabiv120__si_class_type_infoE+8 101; TYPEINFO-NEXT: .int32 _ZTS1C 102; TYPEINFO-NEXT: .int32 _ZTI1A 103; TYPEINFO-NEXT: .size _ZTI1C, 12 104@_ZTI1C = constant { ptr, ptr, ptr } { ptr getelementptr inbounds (ptr, ptr @_ZTVN10__cxxabiv120__si_class_type_infoE, i32 2), ptr @_ZTS1C, ptr @_ZTI1A } 105; TYPEINFO: .type _ZTI1D,@object 106; TYPEINFO: .globl _ZTI1D 107; TYPEINFO-LABEL: _ZTI1D: 108; TYPEINFO-NEXT: .int32 _ZTVN10__cxxabiv120__si_class_type_infoE+8 109; TYPEINFO-NEXT: .int32 _ZTS1D 110; TYPEINFO-NEXT: .int32 _ZTI1B 111; TYPEINFO-NEXT: .size _ZTI1D, 12 112@_ZTI1D = constant { ptr, ptr, ptr } { ptr getelementptr inbounds (ptr, ptr @_ZTVN10__cxxabiv120__si_class_type_infoE, i32 2), ptr @_ZTS1D, ptr @_ZTI1B } 113 114@g = global i32 0, align 4 115 116define void @_ZN1A3fooEv(ptr %this) { 117entry: 118 store i32 2, ptr @g, align 4 119 ret void 120} 121 122define void @_ZN1B3fooEv(ptr %this) { 123entry: 124 store i32 4, ptr @g, align 4 125 ret void 126} 127 128define void @_ZN1C3fooEv(ptr %this) { 129entry: 130 store i32 6, ptr @g, align 4 131 ret void 132} 133 134define void @_ZN1D3fooEv(ptr %this) { 135entry: 136 store i32 8, ptr @g, align 4 137 ret void 138} 139 140define linkonce_odr void @_ZN1AD0Ev(ptr %this) { 141entry: 142 tail call void @_ZdlPv(ptr %this) 143 ret void 144} 145 146define linkonce_odr void @_ZN1BD0Ev(ptr %this) { 147entry: 148 tail call void @_ZdlPv(ptr %this) 149 ret void 150} 151 152define linkonce_odr void @_ZN1CD0Ev(ptr %this) { 153entry: 154 tail call void @_ZdlPv(ptr %this) 155 ret void 156} 157 158define linkonce_odr ptr @_ZN1AD2Ev(ptr returned %this) { 159entry: 160 ret ptr %this 161} 162 163define linkonce_odr void @_ZN1DD0Ev(ptr %this) { 164entry: 165 tail call void @_ZdlPv(ptr %this) 166 ret void 167} 168 169declare void @_ZdlPv(ptr) 170