Skip to content
Merged
Show file tree
Hide file tree
Changes from 6 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
55 changes: 48 additions & 7 deletions lib/SPIRV/SPIRVReader.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2138,11 +2138,34 @@ Value *SPIRVToLLVM::transValueWithoutDecoration(SPIRVValue *BV, Function *F,
Index.insert(Index.begin(), getInt32(M, 0));
auto IsInbound = AC->isInBounds();
Value *V = nullptr;

if (GEPOrUseMap.count(Base)) {
auto IdxToInstMap = GEPOrUseMap[Base];
auto Idx = AC->getIndices();

// In transIntelFPGADecorations we generated GEPs only for the fields of
// structure, meaning that GEP to `0` accesses the Structure itself, and
// the second `Id` is a Key in the map.
if (Idx.size() == 2) {
Comment thread
MrSidims marked this conversation as resolved.
unsigned Idx1 = static_cast<ConstantInt *>(getTranslatedValue(Idx[0]))
->getZExtValue();
if (Idx1 == 0) {
unsigned Idx2 = static_cast<ConstantInt *>(getTranslatedValue(Idx[1]))
->getZExtValue();

// If we already have the instruction in a map, use it.
if (IdxToInstMap.count(Idx2))
return mapValue(BV, IdxToInstMap[Idx2]);
}
}
}

if (BB) {
auto GEP =
GetElementPtrInst::Create(BaseTy, Base, Index, BV->getName(), BB);
GEP->setIsInBounds(IsInbound);
V = GEP;

Comment thread
vmaksimo marked this conversation as resolved.
Outdated
} else {
V = ConstantExpr::getGetElementPtr(BaseTy, dyn_cast<Constant>(Base),
Index, IsInbound);
Expand Down Expand Up @@ -3520,21 +3543,39 @@ void SPIRVToLLVM::transIntelFPGADecorations(SPIRVValue *BV, Value *V) {
for (auto AnnotStr : AnnotStrVec) {
auto *GS = Builder.CreateGlobalStringPtr(AnnotStr);

auto *GEP = cast<GetElementPtrInst>(
Builder.CreateConstInBoundsGEP2_32(AllocatedTy, AL, 0, I));
Instruction *PtrAnnFirstArg = nullptr;

Type *IntTy = GEP->getResultElementType()->isIntegerTy()
? GEP->getType()
: Int8PtrTyPrivate;
if (GEPOrUseMap.count(AL)) {
auto IdxToInstMap = GEPOrUseMap[AL];
if (IdxToInstMap.count(I)) {
PtrAnnFirstArg = IdxToInstMap[I];
}
}

Type *IntTy = nullptr;

if (!PtrAnnFirstArg) {
GetElementPtrInst *GEP = cast<GetElementPtrInst>(
Builder.CreateConstInBoundsGEP2_32(AllocatedTy, AL, 0, I));

IntTy = GEP->getResultElementType()->isIntegerTy()
? GEP->getType()
: Int8PtrTyPrivate;
PtrAnnFirstArg = GEP;
} else {
IntTy = PtrAnnFirstArg->getType();
}

auto AnnotationFn = llvm::Intrinsic::getDeclaration(
M, Intrinsic::ptr_annotation, IntTy);

llvm::Value *Args[] = {
Builder.CreateBitCast(GEP, IntTy, GEP->getName()),
Builder.CreateBitCast(PtrAnnFirstArg, IntTy,
PtrAnnFirstArg->getName()),
Builder.CreateBitCast(GS, Int8PtrTyPrivate), UndefInt8Ptr,
UndefInt32, UndefInt8Ptr};
Builder.CreateCall(AnnotationFn, Args);
auto *PtrAnnotationCall = Builder.CreateCall(AnnotationFn, Args);
GEPOrUseMap[AL][I] = PtrAnnotationCall;
}
}
}
Expand Down
10 changes: 10 additions & 0 deletions lib/SPIRV/SPIRVReader.h
Original file line number Diff line number Diff line change
Expand Up @@ -155,6 +155,14 @@ class SPIRVToLLVM : private BuiltinCallHelper {
typedef std::map<const BasicBlock *, const SPIRVValue *>
SPIRVToLLVMLoopMetadataMap;

// Store all the allocations to Struct Types that are further
// accessed inside GetElementPtr instruction or in ptr.annotation intrinsics.
// For every structure we save the accessed structure field index and the
// last corresponding translated LLVM instruction.
typedef std::unordered_map<Value *,
std::unordered_map<SPIRVWord, Instruction *>>
TypeToGEPOrUseMap;

private:
Module *M;
LLVMContext *Context;
Expand Down Expand Up @@ -186,6 +194,8 @@ class SPIRVToLLVM : private BuiltinCallHelper {
SPIRVToLLVMMDAliasInstMap MDAliasScopeMap;
SPIRVToLLVMMDAliasInstMap MDAliasListMap;

TypeToGEPOrUseMap GEPOrUseMap;

Type *mapType(SPIRVType *BT, Type *T);

// If a value is mapped twice, the existing mapped value is a placeholder,
Expand Down
11 changes: 8 additions & 3 deletions test/transcoding/multiple_user_semantic.ll
Original file line number Diff line number Diff line change
Expand Up @@ -23,14 +23,19 @@
; CHECK-LLVM: @[[StrB:[0-9_.]+]] = {{.*}}"var_annotation_b\00"
Comment thread
vmaksimo marked this conversation as resolved.
Outdated
; CHECK-LLVM: %[[#StructMember:]] = alloca %class.Sample, align 4
; CHECK-LLVM: %[[#GEP1:]] = getelementptr inbounds %class.Sample, %class.Sample* %[[#StructMember]], i32 0, i32 0
; CHECK-LLVM: call i32* @llvm.ptr.annotation.p0i32(i32* %[[#GEP1:]], i8* getelementptr inbounds ([19 x i8], [19 x i8]* @[[StrStructA]], i32 0, i32 0), i8* undef, i32 undef, i8* undef)
; CHECK-LLVM: %[[#GEP2:]] = getelementptr inbounds %class.Sample, %class.Sample* %[[#StructMember]], i32 0, i32 0
; CHECK-LLVM: call i32* @llvm.ptr.annotation.p0i32(i32* %[[#GEP2]], i8* getelementptr inbounds ([19 x i8], [19 x i8]* @[[StrStructB]], i32 0, i32 0), i8* undef, i32 undef, i8* undef)
; CHECK-LLVM: %[[#PtrAnn1:]] = call i32* @llvm.ptr.annotation.p0i32(i32* %[[#GEP1:]], i8* getelementptr inbounds ([19 x i8], [19 x i8]* @[[StrStructA]], i32 0, i32 0), i8* undef, i32 undef, i8* undef)
; CHECK-LLVM: %[[#PtrAnn2:]] = call i32* @llvm.ptr.annotation.p0i32(i32* %[[#PtrAnn1]], i8* getelementptr inbounds ([19 x i8], [19 x i8]* @[[StrStructB]], i32 0, i32 0), i8* undef, i32 undef, i8* undef)
; CHECK-LLVM: [[#Var:]] = alloca i32, align 4
; CHECK-LLVM: [[#Bitcast1:]] = bitcast i32* %[[#Var]] to i8*
; CHECK-LLVM: call void @llvm.var.annotation(i8* %[[#Bitcast1]], i8* getelementptr inbounds ([17 x i8], [17 x i8]* @[[StrA]], i32 0, i32 0), i8* undef, i32 undef, i8* undef)
; CHECK-LLVM: [[#Bitcast2:]] = bitcast i32* %[[#Var]] to i8*
; CHECK-LLVM: call void @llvm.var.annotation(i8* %[[#Bitcast2]], i8* getelementptr inbounds ([17 x i8], [17 x i8]* @[[StrB]], i32 0, i32 0), i8* undef, i32 undef, i8* undef)
; CHECK-LLVM: [[#Bitcast3:]] = bitcast i32* %[[#PtrAnn2]] to i8*
; CHECK-LLVM: [[#Bitcast4:]] = bitcast i8* %[[#Bitcast3]] to i32*
; CHECK-LLVM: [[#Load1:]] = load i32, i32* %[[#Bitcast4]], align 4
; CHECK-LLVM: call spir_func void @_Z3fooi(i32 %[[#Load1]])
; CHECK-LLVM: [[#Load2:]] = load i32, i32* %[[#Var]], align 4
; CHECK-LLVM: call spir_func void @_Z3fooi(i32 %[[#Load2]])


source_filename = "llvm-link"
Expand Down
5 changes: 2 additions & 3 deletions test/transcoding/multiple_user_semantic_nonopaque.ll
Original file line number Diff line number Diff line change
Expand Up @@ -28,9 +28,8 @@
; CHECK-LLVM: call void @llvm.var.annotation(i8* %[[#Bitcast2]], i8* getelementptr inbounds ([17 x i8], [17 x i8]* @[[StrB]], i32 0, i32 0), i8* undef, i32 undef, i8* undef)
; CHECK-LLVM: %[[#StructMember:]] = alloca %class.Sample, align 4
; CHECK-LLVM: %[[#GEP1:]] = getelementptr inbounds %class.Sample, %class.Sample* %[[#StructMember]], i32 0, i32 0
; CHECK-LLVM: call i32* @llvm.ptr.annotation.p0i32(i32* %[[#GEP1:]], i8* getelementptr inbounds ([19 x i8], [19 x i8]* @[[StrStructA]], i32 0, i32 0), i8* undef, i32 undef, i8* undef)
; CHECK-LLVM: %[[#GEP2:]] = getelementptr inbounds %class.Sample, %class.Sample* %[[#StructMember]], i32 0, i32 0
; CHECK-LLVM: call i32* @llvm.ptr.annotation.p0i32(i32* %[[#GEP2]], i8* getelementptr inbounds ([19 x i8], [19 x i8]* @[[StrStructB]], i32 0, i32 0), i8* undef, i32 undef, i8* undef)
; CHECK-LLVM: %[[#PtrAnn:]] = call i32* @llvm.ptr.annotation.p0i32(i32* %[[#GEP1:]], i8* getelementptr inbounds ([19 x i8], [19 x i8]* @[[StrStructA]], i32 0, i32 0), i8* undef, i32 undef, i8* undef)
; CHECK-LLVM: call i32* @llvm.ptr.annotation.p0i32(i32* %[[#PtrAnn]], i8* getelementptr inbounds ([19 x i8], [19 x i8]* @[[StrStructB]], i32 0, i32 0), i8* undef, i32 undef, i8* undef)


source_filename = "llvm-link"
Expand Down
190 changes: 190 additions & 0 deletions test/transcoding/multiple_user_semantic_on_struct.ll
Original file line number Diff line number Diff line change
@@ -0,0 +1,190 @@
; This test is intended to check that we are actually using the
; ptr.annotation intrinsic call results during the reverse translation.

; Source (https://godbolt.org/z/qzhsKfPeq):
; class B {
; public:
; int Val [[clang::annotate("ClassB")]];
; };
; class A {
; public:
; int Val [[clang::annotate("ClassA")]];
; int MultiDec [[clang::annotate("Dec1"), clang::annotate("Dec2"), clang::annotate("Dec3")]];
; [[clang::annotate("ClassAfieldB")]]class B b;
; };
; void foo(int);
; int main() {
; A a;
; B b;
; A c;
; foo(a.Val); // ClassA
; foo(c.Val); // Obj2ClassA
; foo(a.MultiDec); // ClassAMultiDec
; foo(a.b.Val); // ClassAFieldB
; foo(b.Val); // ClassB
; return 0;
; }


; RUN: llvm-as %s -o %t.bc
; RUN: llvm-spirv %t.bc -spirv-text -o - | FileCheck %s --check-prefix=CHECK-SPIRV

; RUN: llvm-spirv %t.bc -o %t.spv
; RUN: llvm-spirv -r %t.spv -o %t.rev.bc
; RUN: llvm-dis < %t.rev.bc | FileCheck %s --check-prefix=CHECK-LLVM

; Check that even when FPGA memory extensions are enabled - yet we have
; UserSemantic decoration be generated
; RUN: llvm-as %s -o %t.bc
; RUN: llvm-spirv %t.bc --spirv-ext=+SPV_INTEL_fpga_memory_accesses,+SPV_INTEL_fpga_memory_attributes -spirv-text -o - | FileCheck %s --check-prefix=CHECK-SPIRV

; CHECK-SPIRV: Name [[#ClassA:]] "class.A"
; CHECK-SPIRV: Name [[#ClassB:]] "class.B"
; CHECK-SPIRV: MemberDecorate [[#ClassA]] 0 UserSemantic "ClassA"
; CHECK-SPIRV: MemberDecorate [[#ClassA]] 0 UserSemantic "ClassA"
; CHECK-SPIRV: MemberDecorate [[#ClassA]] 1 UserSemantic "Dec1"
; CHECK-SPIRV: MemberDecorate [[#ClassA]] 1 UserSemantic "Dec2"
; CHECK-SPIRV: MemberDecorate [[#ClassA]] 1 UserSemantic "Dec3"
; CHECK-SPIRV: MemberDecorate [[#ClassA]] 2 UserSemantic "ClassAfieldB"
; CHECK-SPIRV: MemberDecorate [[#ClassB]] 0 UserSemantic "ClassB"
; CHECK-SPIRV: MemberDecorate [[#ClassB]] 0 UserSemantic "ClassB"

; CHECK-LLVM: @[[#StrStructA:]] = {{.*}}"ClassA\00"
; CHECK-LLVM: @[[#StrStructA2:]] = {{.*}}"ClassA\00"
; CHECK-LLVM: @[[#Dec1:]] = {{.*}}"Dec1\00"
; CHECK-LLVM: @[[#Dec2:]] = {{.*}}"Dec2\00"
; CHECK-LLVM: @[[#Dec3:]] = {{.*}}"Dec3\00"
; CHECK-LLVM: @[[#StrAfieldB:]] = {{.*}}"ClassAfieldB\00"
; CHECK-LLVM: @[[#StrStructB:]] = {{.*}}"ClassB\00"
; CHECK-LLVM: @[[#StrStructB2:]] = {{.*}}"ClassB\00"
; CHECK-LLVM: @[[#StrObj2StructA:]] = {{.*}}"ClassA\00"
; CHECK-LLVM: @[[#StrObj2StructA2:]] = {{.*}}"ClassA\00"

; CHECK-LLVM: %[[#ObjClassA:]] = alloca %class.A, align 4
; CHECK-LLVM: %[[#GepClassAVal:]] = getelementptr inbounds %class.A, %class.A* %[[#ObjClassA]], i32 0, i32 0
; CHECK-LLVM: %[[#PtrAnnClassAVal:]] = call i32* @llvm.ptr.annotation.p0i32(i32* %[[#GepClassAVal]], i8* getelementptr inbounds ([7 x i8], [7 x i8]* @[[#StrStructA]], i32 0, i32 0), i8* undef, i32 undef, i8* undef)
; CHECK-LLVM: %[[#PtrAnn2ClassAVal:]] = call i32* @llvm.ptr.annotation.p0i32(i32* %[[#PtrAnnClassAVal]], i8* getelementptr inbounds ([7 x i8], [7 x i8]* @[[#StrStructA2]], i32 0, i32 0), i8* undef, i32 undef, i8* undef)

; CHECK-LLVM: %[[#GepMultiDec:]] = getelementptr inbounds %class.A, %class.A* %[[#ObjClassA]], i32 0, i32 1
; CHECK-LLVM: %[[#PtrAnnMultiDec:]] = call i32* @llvm.ptr.annotation.p0i32(i32* %[[#GepMultiDec]], i8* getelementptr inbounds ([5 x i8], [5 x i8]* @[[#Dec1]], i32 0, i32 0), i8* undef, i32 undef, i8* undef)
; CHECK-LLVM: %[[#PtrAnn2MultiDec:]] = call i32* @llvm.ptr.annotation.p0i32(i32* %[[#PtrAnnMultiDec]], i8* getelementptr inbounds ([5 x i8], [5 x i8]* @[[#Dec2]], i32 0, i32 0), i8* undef, i32 undef, i8* undef)
; CHECK-LLVM: %[[#PtrAnn3MultiDec:]] = call i32* @llvm.ptr.annotation.p0i32(i32* %[[#PtrAnn2MultiDec]], i8* getelementptr inbounds ([5 x i8], [5 x i8]* @[[#Dec3]], i32 0, i32 0), i8* undef, i32 undef, i8* undef)

; CHECK-LLVM: %[[#GepClassAFieldB:]] = getelementptr inbounds %class.A, %class.A* %[[#ObjClassA]], i32 0, i32 2
; CHECK-LLVM: %[[#CastClassAFieldB:]] = bitcast %class.B* %[[#GepClassAFieldB]] to i8*
; CHECK-LLVM: %[[#PtrAnnClassAFieldB:]] = call i8* @llvm.ptr.annotation.p0i8(i8* %[[#CastClassAFieldB]], i8* getelementptr inbounds ([13 x i8], [13 x i8]* @[[#StrAfieldB]], i32 0, i32 0), i8* undef, i32 undef, i8* undef)

; CHECK-LLVM: %[[#ObjClassB:]] = alloca %class.B, align 4
; CHECK-LLVM: %[[#GEPClassB:]] = getelementptr inbounds %class.B, %class.B* %[[#ObjClassB]], i32 0, i32 0
; CHECK-LLVM: %[[#PtrAnnClassB:]] = call i32* @llvm.ptr.annotation.p0i32(i32* %[[#GEPClassB]], i8* getelementptr inbounds ([7 x i8], [7 x i8]* @[[#StrStructB]], i32 0, i32 0), i8* undef, i32 undef, i8* undef)
; CHECK-LLVM: %[[#PtrAnn2ClassB:]] = call i32* @llvm.ptr.annotation.p0i32(i32* %[[#PtrAnnClassB]], i8* getelementptr inbounds ([7 x i8], [7 x i8]* @[[#StrStructB2]], i32 0, i32 0), i8* undef, i32 undef, i8* undef)

; CHECK-LLVM: %[[#Obj2ClassA:]] = alloca %class.A, align 4
; CHECK-LLVM: %[[#GepObj2ClassA:]] = getelementptr inbounds %class.A, %class.A* %[[#Obj2ClassA]], i32 0, i32 0
; CHECK-LLVM: %[[#PtrAnnObj2ClassA:]] = call i32* @llvm.ptr.annotation.p0i32(i32* %[[#GepObj2ClassA]], i8* getelementptr inbounds ([7 x i8], [7 x i8]* @[[#StrObj2StructA]], i32 0, i32 0), i8* undef, i32 undef, i8* undef)
; CHECK-LLVM: %[[#PtrAnn2Obj2ClassA:]] = call i32* @llvm.ptr.annotation.p0i32(i32* %[[#PtrAnnObj2ClassA]], i8* getelementptr inbounds ([7 x i8], [7 x i8]* @[[#StrObj2StructA2]], i32 0, i32 0), i8* undef, i32 undef, i8* undef)


; CHECK-LLVM: %[[#CastClassAVal:]] = bitcast i32* %[[#PtrAnn2ClassAVal]] to i8*
; CHECK-LLVM: %[[#LoadClassAVal:]] = bitcast i8* %[[#CastClassAVal]] to i32*
; CHECK-LLVM: %[[#CallClassA:]] = load i32, i32* %[[#LoadClassAVal]], align 4
; CHECK-LLVM: call spir_func void @_Z3fooi(i32 %[[#CallClassA]])

; CHECK-LLVM: %[[#CastObj2ClassA:]] = bitcast i32* %[[#PtrAnn2Obj2ClassA]] to i8*
; CHECK-LLVM: %[[#LoadObj2ClassA:]] = bitcast i8* %[[#CastObj2ClassA]] to i32*
; CHECK-LLVM: %[[#CallObj2ClassA:]] = load i32, i32* %[[#LoadObj2ClassA]], align 4
; CHECK-LLVM: call spir_func void @_Z3fooi(i32 %[[#CallObj2ClassA]])

; CHECK-LLVM: %[[#CastMultiDec:]] = bitcast i32* %[[#PtrAnn3MultiDec]] to i8*
; CHECK-LLVM: %[[#CastMultiDec1:]] = bitcast i8* %[[#CastMultiDec]] to i32*
; CHECK-LLVM: %[[#CastMultiDec2:]] = bitcast i32* %[[#CastMultiDec1]] to i8*
; CHECK-LLVM: %[[#CastMultiDec3:]] = bitcast i8* %[[#CastMultiDec2]] to i32*
; CHECK-LLVM: %[[#CastMultiDec4:]] = bitcast i32* %[[#CastMultiDec3]] to i8*
; CHECK-LLVM: %[[#LoadMultiDec:]] = bitcast i8* %[[#CastMultiDec4]] to i32*
; CHECK-LLVM: %[[#CallClassAMultiDec:]] = load i32, i32* %[[#LoadMultiDec]], align 4
; CHECK-LLVM: call spir_func void @_Z3fooi(i32 %[[#CallClassAMultiDec]])

; CHECK-LLVM: %[[#CastClassAFieldB:]] = bitcast i8* %[[#PtrAnnClassAFieldB]] to i8*
; CHECK-LLVM: %[[#Cast2ClassAFieldB:]] = bitcast i8* %[[#CastClassAFieldB]] to %class.B*
; CHECK-LLVM: %[[#GEPClassB:]] = getelementptr inbounds %class.B, %class.B* %[[#Cast2ClassAFieldB]], i32 0, i32 0
; CHECK-LLVM: %[[#CastClassB:]] = bitcast i32* %[[#GEPClassB]] to i8*
; CHECK-LLVM: %[[#Cast2ClassB:]] = bitcast i8* %[[#CastClassB]] to i32*
; CHECK-LLVM: %[[#CallClassAFieldB:]] = load i32, i32* %[[#Cast2ClassB]], align 4
; CHECK-LLVM: call spir_func void @_Z3fooi(i32 %[[#CallClassAFieldB]])

; CHECK-LLVM: %[[#CastClassB:]] = bitcast i32* %[[#PtrAnn2ClassB]] to i8*
; CHECK-LLVM: %[[#Cast2ClassB:]] = bitcast i8* %[[#CastClassB]] to i32*
; CHECK-LLVM: %[[#CallClassB:]] = load i32, i32* %[[#Cast2ClassB]], align 4
; CHECK-LLVM: call spir_func void @_Z3fooi(i32 %[[#CallClassB]])

target datalayout = "e-i64:64-v16:16-v24:32-v32:32-v48:64-v96:128-v192:256-v256:256-v512:512-v1024:1024-n8:16:32:64"
target triple = "spir64"

%class.A = type { i32, i32, %class.B }
%class.B = type { i32 }

@.str = private unnamed_addr constant [7 x i8] c"ClassA\00", section "llvm.metadata"
@.str.1 = private unnamed_addr constant [17 x i8] c"/app/example.cpp\00", section "llvm.metadata"
@.str.2 = private unnamed_addr constant [5 x i8] c"Dec1\00", section "llvm.metadata"
@.str.3 = private unnamed_addr constant [5 x i8] c"Dec2\00", section "llvm.metadata"
@.str.4 = private unnamed_addr constant [5 x i8] c"Dec3\00", section "llvm.metadata"
@.str.5 = private unnamed_addr constant [13 x i8] c"ClassAfieldB\00", section "llvm.metadata"
@.str.6 = private unnamed_addr constant [7 x i8] c"ClassB\00", section "llvm.metadata"

define dso_local noundef i32 @main() #0 {
%1 = alloca i32, align 4
%2 = alloca %class.A, align 4
%3 = alloca %class.B, align 4
%4 = alloca %class.A, align 4
store i32 0, i32* %1, align 4
%5 = getelementptr inbounds %class.A, %class.A* %2, i32 0, i32 0
%6 = bitcast i32* %5 to i8*
%7 = call i8* @llvm.ptr.annotation.p0i8(i8* %6, i8* getelementptr inbounds ([7 x i8], [7 x i8]* @.str, i32 0, i32 0), i8* getelementptr inbounds ([17 x i8], [17 x i8]* @.str.1, i32 0, i32 0), i32 12, i8* null)
%8 = bitcast i8* %7 to i32*
%9 = load i32, i32* %8, align 4
call void @_Z3fooi(i32 noundef %9)
%10 = getelementptr inbounds %class.A, %class.A* %4, i32 0, i32 0
%11 = bitcast i32* %10 to i8*
%12 = call i8* @llvm.ptr.annotation.p0i8(i8* %11, i8* getelementptr inbounds ([7 x i8], [7 x i8]* @.str, i32 0, i32 0), i8* getelementptr inbounds ([17 x i8], [17 x i8]* @.str.1, i32 0, i32 0), i32 12, i8* null)
%13 = bitcast i8* %12 to i32*
%14 = load i32, i32* %13, align 4
call void @_Z3fooi(i32 noundef %14)
%15 = getelementptr inbounds %class.A, %class.A* %2, i32 0, i32 1
%16 = bitcast i32* %15 to i8*
%17 = call i8* @llvm.ptr.annotation.p0i8(i8* %16, i8* getelementptr inbounds ([5 x i8], [5 x i8]* @.str.2, i32 0, i32 0), i8* getelementptr inbounds ([17 x i8], [17 x i8]* @.str.1, i32 0, i32 0), i32 13, i8* null)
%18 = bitcast i8* %17 to i32*
%19 = bitcast i32* %18 to i8*
%20 = call i8* @llvm.ptr.annotation.p0i8(i8* %19, i8* getelementptr inbounds ([5 x i8], [5 x i8]* @.str.3, i32 0, i32 0), i8* getelementptr inbounds ([17 x i8], [17 x i8]* @.str.1, i32 0, i32 0), i32 13, i8* null)
%21 = bitcast i8* %20 to i32*
%22 = bitcast i32* %21 to i8*
%23 = call i8* @llvm.ptr.annotation.p0i8(i8* %22, i8* getelementptr inbounds ([5 x i8], [5 x i8]* @.str.4, i32 0, i32 0), i8* getelementptr inbounds ([17 x i8], [17 x i8]* @.str.1, i32 0, i32 0), i32 13, i8* null)
%24 = bitcast i8* %23 to i32*
%25 = load i32, i32* %24, align 4
call void @_Z3fooi(i32 noundef %25)
%26 = getelementptr inbounds %class.A, %class.A* %2, i32 0, i32 2
%27 = bitcast %class.B* %26 to i8*
%28 = call i8* @llvm.ptr.annotation.p0i8(i8* %27, i8* getelementptr inbounds ([13 x i8], [13 x i8]* @.str.5, i32 0, i32 0), i8* getelementptr inbounds ([17 x i8], [17 x i8]* @.str.1, i32 0, i32 0), i32 14, i8* null)
%29 = bitcast i8* %28 to %class.B*
%30 = getelementptr inbounds %class.B, %class.B* %29, i32 0, i32 0
%31 = bitcast i32* %30 to i8*
%32 = call i8* @llvm.ptr.annotation.p0i8(i8* %31, i8* getelementptr inbounds ([7 x i8], [7 x i8]* @.str.6, i32 0, i32 0), i8* getelementptr inbounds ([17 x i8], [17 x i8]* @.str.1, i32 0, i32 0), i32 6, i8* null)
%33 = bitcast i8* %32 to i32*
%34 = load i32, i32* %33, align 4
call void @_Z3fooi(i32 noundef %34)
%35 = getelementptr inbounds %class.B, %class.B* %3, i32 0, i32 0
%36 = bitcast i32* %35 to i8*
%37 = call i8* @llvm.ptr.annotation.p0i8(i8* %36, i8* getelementptr inbounds ([7 x i8], [7 x i8]* @.str.6, i32 0, i32 0), i8* getelementptr inbounds ([17 x i8], [17 x i8]* @.str.1, i32 0, i32 0), i32 6, i8* null)
%38 = bitcast i8* %37 to i32*
%39 = load i32, i32* %38, align 4
call void @_Z3fooi(i32 noundef %39)
ret i32 0
}

declare void @_Z3fooi(i32 noundef) #2

declare i8* @llvm.ptr.annotation.p0i8(i8*, i8*, i8*, i32, i8*) #3

attributes #0 = { mustprogress noinline norecurse optnone uwtable "frame-pointer"="all" "min-legal-vector-width"="0" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-cpu"="x86-64" "target-features"="+cx8,+fxsr,+mmx,+sse,+sse2,+x87" "tune-cpu"="generic" }
attributes #1 = { nocallback nofree nosync nounwind speculatable willreturn memory(none) }
attributes #2 = { "frame-pointer"="all" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-cpu"="x86-64" "target-features"="+cx8,+fxsr,+mmx,+sse,+sse2,+x87" "tune-cpu"="generic" }
attributes #3 = { nocallback nofree nosync nounwind willreturn memory(inaccessiblemem: readwrite) }