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