Index: llvm/lib/AsmParser/LLParser.cpp =================================================================== --- llvm/lib/AsmParser/LLParser.cpp +++ llvm/lib/AsmParser/LLParser.cpp @@ -998,10 +998,12 @@ // See if the alias was forward referenced, if so, prepare to replace the // forward reference. if (!Name.empty()) { - GVal = M->getNamedValue(Name); - if (GVal) { - if (!ForwardRefVals.erase(Name)) - return error(NameLoc, "redefinition of global '@" + Name + "'"); + auto I = ForwardRefVals.find(Name); + if (I != ForwardRefVals.end()) { + GVal = I->second.first; + ForwardRefVals.erase(Name); + } else if (M->getNamedValue(Name)) { + return error(NameLoc, "redefinition of global '@" + Name + "'"); } } else { auto I = ForwardRefValIDs.find(NumberedVals.size()); @@ -1123,10 +1125,12 @@ // See if the global was forward referenced, if so, use the global. if (!Name.empty()) { - GVal = M->getNamedValue(Name); - if (GVal) { - if (!ForwardRefVals.erase(Name)) - return error(NameLoc, "redefinition of global '@" + Name + "'"); + auto I = ForwardRefVals.find(Name); + if (I != ForwardRefVals.end()) { + GVal = I->second.first; + ForwardRefVals.erase(I); + } else if (M->getNamedValue(Name)) { + return error(NameLoc, "redefinition of global '@" + Name + "'"); } } else { auto I = ForwardRefValIDs.find(NumberedVals.size()); @@ -1136,22 +1140,9 @@ } } - GlobalVariable *GV; - if (!GVal) { - GV = new GlobalVariable(*M, Ty, false, GlobalValue::ExternalLinkage, nullptr, - Name, nullptr, GlobalVariable::NotThreadLocal, - AddrSpace); - } else { - if (GVal->getValueType() != Ty) - return error( - TyLoc, - "forward reference and definition of global have different types"); - - GV = cast(GVal); - - // Move the forward-reference to the correct spot in the module. - M->getGlobalList().splice(M->global_end(), M->getGlobalList(), GV); - } + GlobalVariable *GV = new GlobalVariable( + *M, Ty, false, GlobalValue::ExternalLinkage, nullptr, Name, nullptr, + GlobalVariable::NotThreadLocal, AddrSpace); if (Name.empty()) NumberedVals.push_back(GV); @@ -1168,6 +1159,16 @@ GV->setThreadLocalMode(TLM); GV->setUnnamedAddr(UnnamedAddr); + if (GVal) { + if (!GVal->getType()->isOpaque() && GVal->getValueType() != Ty) + return error( + TyLoc, + "forward reference and definition of global have different types"); + + GVal->replaceAllUsesWith(GV); + GVal->eraseFromParent(); + } + // parse attributes on the global. while (Lex.getKind() == lltok::comma) { Lex.Lex(); @@ -1456,14 +1457,17 @@ // GlobalValue Reference/Resolution Routines. //===----------------------------------------------------------------------===// -static inline GlobalValue *createGlobalFwdRef(Module *M, PointerType *PTy, - const std::string &Name) { - if (auto *FT = dyn_cast(PTy->getElementType())) +static inline GlobalValue *createGlobalFwdRef(Module *M, PointerType *PTy) { + // For opaque pointers, create a GlobalVariable with dummy type. We will + // RAUW it later with a global/function of the correct type. + Type *ElemTy = PTy->isOpaque() ? Type::getInt8Ty(M->getContext()) + : PTy->getElementType(); + if (auto *FT = dyn_cast(ElemTy)) return Function::Create(FT, GlobalValue::ExternalWeakLinkage, - PTy->getAddressSpace(), Name, M); + PTy->getAddressSpace(), "", M); else - return new GlobalVariable(*M, PTy->getElementType(), false, - GlobalValue::ExternalWeakLinkage, nullptr, Name, + return new GlobalVariable(*M, ElemTy, false, + GlobalValue::ExternalWeakLinkage, nullptr, "", nullptr, GlobalVariable::NotThreadLocal, PTy->getAddressSpace()); } @@ -1515,7 +1519,7 @@ checkValidVariableType(Loc, "@" + Name, Ty, Val, IsCall)); // Otherwise, create a new forward reference for this value and remember it. - GlobalValue *FwdVal = createGlobalFwdRef(M, PTy, Name); + GlobalValue *FwdVal = createGlobalFwdRef(M, PTy); ForwardRefVals[Name] = std::make_pair(FwdVal, Loc); return FwdVal; } @@ -1544,7 +1548,7 @@ checkValidVariableType(Loc, "@" + Twine(ID), Ty, Val, IsCall)); // Otherwise, create a new forward reference for this value and remember it. - GlobalValue *FwdVal = createGlobalFwdRef(M, PTy, ""); + GlobalValue *FwdVal = createGlobalFwdRef(M, PTy); ForwardRefValIDs[ID] = std::make_pair(FwdVal, Loc); return FwdVal; } @@ -5861,24 +5865,27 @@ PointerType *PFT = PointerType::get(FT, AddrSpace); Fn = nullptr; + GlobalValue *FwdFn = nullptr; if (!FunctionName.empty()) { // If this was a definition of a forward reference, remove the definition // from the forward reference table and fill in the forward ref. auto FRVI = ForwardRefVals.find(FunctionName); if (FRVI != ForwardRefVals.end()) { - Fn = M->getFunction(FunctionName); - if (!Fn) - return error(FRVI->second.second, "invalid forward reference to " - "function as global value!"); - if (Fn->getType() != PFT) - return error(FRVI->second.second, - "invalid forward reference to " - "function '" + - FunctionName + - "' with wrong type: " - "expected '" + - getTypeString(PFT) + "' but was '" + - getTypeString(Fn->getType()) + "'"); + FwdFn = FRVI->second.first; + if (!FwdFn->getType()->isOpaque()) { + if (!FwdFn->getType()->getPointerElementType()->isFunctionTy()) + return error(FRVI->second.second, "invalid forward reference to " + "function as global value!"); + if (FwdFn->getType() != PFT) + return error(FRVI->second.second, + "invalid forward reference to " + "function '" + + FunctionName + + "' with wrong type: " + "expected '" + + getTypeString(PFT) + "' but was '" + + getTypeString(FwdFn->getType()) + "'"); + } ForwardRefVals.erase(FRVI); } else if ((Fn = M->getFunction(FunctionName))) { // Reject redefinitions. @@ -5893,23 +5900,20 @@ // types agree. auto I = ForwardRefValIDs.find(NumberedVals.size()); if (I != ForwardRefValIDs.end()) { - Fn = cast(I->second.first); - if (Fn->getType() != PFT) + FwdFn = cast(I->second.first); + if (!FwdFn->getType()->isOpaque() && FwdFn->getType() != PFT) return error(NameLoc, "type of definition and forward reference of '@" + Twine(NumberedVals.size()) + "' disagree: " "expected '" + getTypeString(PFT) + "' but was '" + - getTypeString(Fn->getType()) + "'"); + getTypeString(FwdFn->getType()) + "'"); ForwardRefValIDs.erase(I); } } - if (!Fn) - Fn = Function::Create(FT, GlobalValue::ExternalLinkage, AddrSpace, - FunctionName, M); - else // Move the forward-reference to the correct spot in the module. - M->getFunctionList().splice(M->end(), M->getFunctionList(), Fn); + Fn = Function::Create(FT, GlobalValue::ExternalLinkage, AddrSpace, + FunctionName, M); assert(Fn->getAddressSpace() == AddrSpace && "Created function in wrong AS"); @@ -5947,6 +5951,11 @@ "redefinition of argument '%" + ArgList[i].Name + "'"); } + if (FwdFn) { + FwdFn->replaceAllUsesWith(Fn); + FwdFn->eraseFromParent(); + } + if (IsDefine) return false; Index: llvm/lib/IR/AsmWriter.cpp =================================================================== --- llvm/lib/IR/AsmWriter.cpp +++ llvm/lib/IR/AsmWriter.cpp @@ -202,8 +202,7 @@ // We may have lost some users. return; - bool GetsReversed = - !isa(V) && !isa(V) && !isa(V); + bool GetsReversed = !isa(V); if (auto *BA = dyn_cast(V)) ID = OM.lookup(BA->getBasicBlock()).first; llvm::sort(List, [&](const Entry &L, const Entry &R) { Index: llvm/test/CodeGen/WebAssembly/add-prototypes-conflict.ll =================================================================== --- llvm/test/CodeGen/WebAssembly/add-prototypes-conflict.ll +++ llvm/test/CodeGen/WebAssembly/add-prototypes-conflict.ll @@ -7,15 +7,15 @@ ; WARNING: warning: prototype-less function used with conflicting signatures: foo ; CHECK-LABEL: @call_with_conflicting_prototypes -; CHECK: %call1 = call i64 bitcast (i64 (i32, i32)* @foo to i64 (i32)*)(i32 42) -; CHECK: %call2 = call i64 @foo(i32 42, i32 43) +; CHECK: %call1 = call i64 @foo(i32 42) +; CHECK: %call2 = call i64 bitcast (i64 (i32)* @foo to i64 (i32, i32)*)(i32 42, i32 43) define void @call_with_conflicting_prototypes() { %call1 = call i64 bitcast (i64 (...)* @foo to i64 (i32)*)(i32 42) %call2 = call i64 bitcast (i64 (...)* @foo to i64 (i32, i32)*)(i32 42, i32 43) ret void } -; CHECK: declare extern_weak i64 @foo(i32, i32) +; CHECK: declare extern_weak i64 @foo(i32) declare extern_weak i64 @foo(...) #1 ; CHECK-NOT: attributes {{.*}} = { {{.*}}"no-prototype"{{.*}} } Index: llvm/test/Other/force-opaque-ptrs.ll =================================================================== --- llvm/test/Other/force-opaque-ptrs.ll +++ llvm/test/Other/force-opaque-ptrs.ll @@ -17,8 +17,15 @@ ; CHECK-LABEL: define {{[^@]+}}@f ; CHECK-SAME: (ptr [[P:%.*]]) { ; CHECK-NEXT: [[A:%.*]] = alloca i17, align 4 +; CHECK-NEXT: call void @fn.fwd(i32 0) +; CHECK-NEXT: store i32 0, ptr @g.fwd, align 4 ; CHECK-NEXT: ret void ; %a = alloca i17 + call void @fn.fwd(i32 0) + store i32 0, i32* @g.fwd ret void } + +@g.fwd = global i32 0 +declare void @fn.fwd(i32) Index: llvm/test/Transforms/Attributor/IPConstantProp/PR16052.ll =================================================================== --- llvm/test/Transforms/Attributor/IPConstantProp/PR16052.ll +++ llvm/test/Transforms/Attributor/IPConstantProp/PR16052.ll @@ -15,11 +15,23 @@ ; IS__TUNIT____-NEXT: [[CALL2:%.*]] = call i64 @fn1(i64 undef) #[[ATTR0]], !range [[RNG0:![0-9]+]] ; IS__TUNIT____-NEXT: ret i64 [[CALL2]] ; -; IS__CGSCC____: Function Attrs: nofree norecurse nosync nounwind readnone willreturn -; IS__CGSCC____-LABEL: define {{[^@]+}}@fn2 -; IS__CGSCC____-SAME: () #[[ATTR0:[0-9]+]] { -; IS__CGSCC____-NEXT: entry: -; IS__CGSCC____-NEXT: ret i64 undef +; IS__CGSCC_OPM: Function Attrs: nofree norecurse nosync nounwind readnone willreturn +; IS__CGSCC_OPM-LABEL: define {{[^@]+}}@fn2 +; IS__CGSCC_OPM-SAME: () #[[ATTR0:[0-9]+]] { +; IS__CGSCC_OPM-NEXT: entry: +; IS__CGSCC_OPM-NEXT: [[CONV:%.*]] = sext i32 undef to i64 +; IS__CGSCC_OPM-NEXT: [[DIV:%.*]] = sdiv i64 8, [[CONV]] +; IS__CGSCC_OPM-NEXT: [[CALL2:%.*]] = call i64 @fn1(i64 undef) #[[ATTR1:[0-9]+]] +; IS__CGSCC_OPM-NEXT: ret i64 [[CALL2]] +; +; IS__CGSCC_NPM: Function Attrs: nofree norecurse nosync nounwind readnone willreturn +; IS__CGSCC_NPM-LABEL: define {{[^@]+}}@fn2 +; IS__CGSCC_NPM-SAME: () #[[ATTR0:[0-9]+]] { +; IS__CGSCC_NPM-NEXT: entry: +; IS__CGSCC_NPM-NEXT: [[CONV:%.*]] = sext i32 undef to i64 +; IS__CGSCC_NPM-NEXT: [[DIV:%.*]] = sdiv i64 8, [[CONV]] +; IS__CGSCC_NPM-NEXT: [[CALL2:%.*]] = call i64 @fn1(i64 undef) #[[ATTR1:[0-9]+]], !range [[RNG0:![0-9]+]] +; IS__CGSCC_NPM-NEXT: ret i64 [[CALL2]] ; entry: %conv = sext i32 undef to i64 @@ -40,7 +52,7 @@ ; ; IS__CGSCC____: Function Attrs: nofree norecurse nosync nounwind readnone willreturn ; IS__CGSCC____-LABEL: define {{[^@]+}}@fn2b -; IS__CGSCC____-SAME: (i32 [[ARG:%.*]]) #[[ATTR0]] { +; IS__CGSCC____-SAME: (i32 [[ARG:%.*]]) #[[ATTR0:[0-9]+]] { ; IS__CGSCC____-NEXT: entry: ; IS__CGSCC____-NEXT: [[CONV:%.*]] = sext i32 [[ARG]] to i64 ; IS__CGSCC____-NEXT: [[DIV:%.*]] = sdiv i64 8, [[CONV]] Index: llvm/test/Transforms/Attributor/misc.ll =================================================================== --- llvm/test/Transforms/Attributor/misc.ll +++ llvm/test/Transforms/Attributor/misc.ll @@ -26,6 +26,7 @@ ; IS__CGSCC____-SAME: (void (i8*)* noundef nonnull [[FP:%.*]]) { ; IS__CGSCC____-NEXT: entry: ; IS__CGSCC____-NEXT: [[A:%.*]] = alloca i32, align 4 +; IS__CGSCC____-NEXT: [[TMP:%.*]] = bitcast i32* [[A]] to i8* ; IS__CGSCC____-NEXT: call void @foo(i32* noalias nocapture nofree noundef nonnull writeonly align 4 dereferenceable(4) [[A]]) #[[ATTR1:[0-9]+]] ; IS__CGSCC____-NEXT: call void [[FP]](i8* bitcast (void (i32*)* @foo to i8*)) ; IS__CGSCC____-NEXT: call void @callback1(void (i32*)* noundef nonnull @foo) Index: llvm/test/Transforms/FunctionSpecialization/function-specialization3.ll =================================================================== --- llvm/test/Transforms/FunctionSpecialization/function-specialization3.ll +++ llvm/test/Transforms/FunctionSpecialization/function-specialization3.ll @@ -14,8 +14,8 @@ define dso_local i32 @bar(i32 %x, i32 %y) { ; COMMON-LABEL: @bar -; FORCE: %call = call i32 @foo.2(i32 %x, i32* @A) -; FORCE: %call1 = call i32 @foo.1(i32 %y, i32* @B) +; FORCE: %call = call i32 @foo.1(i32 %x, i32* @A) +; FORCE: %call1 = call i32 @foo.2(i32 %y, i32* @B) ; DISABLED-NOT: %call1 = call i32 @foo.1( entry: %tobool = icmp ne i32 %x, 0 @@ -36,14 +36,14 @@ ; FORCE: define internal i32 @foo.1(i32 %x, i32* %b) { ; FORCE-NEXT: entry: -; FORCE-NEXT: %0 = load i32, i32* @B, align 4 +; FORCE-NEXT: %0 = load i32, i32* @A, align 4 ; FORCE-NEXT: %add = add nsw i32 %x, %0 ; FORCE-NEXT: ret i32 %add ; FORCE-NEXT: } ; FORCE: define internal i32 @foo.2(i32 %x, i32* %b) { ; FORCE-NEXT: entry: -; FORCE-NEXT: %0 = load i32, i32* @A, align 4 +; FORCE-NEXT: %0 = load i32, i32* @B, align 4 ; FORCE-NEXT: %add = add nsw i32 %x, %0 ; FORCE-NEXT: ret i32 %add ; FORCE-NEXT: } Index: llvm/test/Transforms/FunctionSpecialization/function-specialization4.ll =================================================================== --- llvm/test/Transforms/FunctionSpecialization/function-specialization4.ll +++ llvm/test/Transforms/FunctionSpecialization/function-specialization4.ll @@ -43,7 +43,7 @@ ; CHECK: define internal i32 @foo.1(i32 %x, i32* %b, i32* %c) { ; CHECK-NEXT: entry: -; CHECK-NEXT: %0 = load i32, i32* @B, align 4 +; CHECK-NEXT: %0 = load i32, i32* @A, align 4 ; CHECK-NEXT: %add = add nsw i32 %x, %0 ; CHECK-NEXT: %1 = load i32, i32* %c, align 4 ; CHECK-NEXT: %add1 = add nsw i32 %add, %1 @@ -52,7 +52,7 @@ ; CHECK: define internal i32 @foo.2(i32 %x, i32* %b, i32* %c) { ; CHECK-NEXT: entry: -; CHECK-NEXT: %0 = load i32, i32* @A, align 4 +; CHECK-NEXT: %0 = load i32, i32* @B, align 4 ; CHECK-NEXT: %add = add nsw i32 %x, %0 ; CHECK-NEXT: %1 = load i32, i32* %c, align 4 ; CHECK-NEXT: %add1 = add nsw i32 %add, %1 Index: llvm/test/Transforms/LowerTypeTests/function-weak.ll =================================================================== --- llvm/test/Transforms/LowerTypeTests/function-weak.ll +++ llvm/test/Transforms/LowerTypeTests/function-weak.ll @@ -55,11 +55,11 @@ ; CHECK: define internal void @__cfi_global_var_init() section ".text.startup" { ; CHECK-NEXT: entry: -; CHECK-NEXT: store { void ()*, void ()*, i32 } { void ()* select (i1 icmp ne (void ()* @f, void ()* null), void ()* @[[JT]], void ()* null), void ()* select (i1 icmp ne (void ()* @f, void ()* null), void ()* @[[JT]], void ()* null), i32 42 }, { void ()*, void ()*, i32 }* @s, align 8 -; CHECK-NEXT: store void ()* bitcast (i8* getelementptr (i8, i8* bitcast (void ()* select (i1 icmp ne (void ()* @f, void ()* null), void ()* @[[JT]], void ()* null) to i8*), i64 42) to void ()*), void ()** @x4, align 8 -; CHECK-NEXT: store void ()* select (i1 icmp ne (void ()* @f, void ()* null), void ()* @[[JT]], void ()* null), void ()** @x3, align 8 -; CHECK-NEXT: store void ()* select (i1 icmp ne (void ()* @f, void ()* null), void ()* @[[JT]], void ()* null), void ()** @x2, align 8 ; CHECK-NEXT: store void ()* select (i1 icmp ne (void ()* @f, void ()* null), void ()* @[[JT]], void ()* null), void ()** @x, align 8 +; CHECK-NEXT: store void ()* select (i1 icmp ne (void ()* @f, void ()* null), void ()* @[[JT]], void ()* null), void ()** @x2, align 8 +; CHECK-NEXT: store void ()* select (i1 icmp ne (void ()* @f, void ()* null), void ()* @[[JT]], void ()* null), void ()** @x3, align 8 +; CHECK-NEXT: store void ()* bitcast (i8* getelementptr (i8, i8* bitcast (void ()* select (i1 icmp ne (void ()* @f, void ()* null), void ()* @[[JT]], void ()* null) to i8*), i64 42) to void ()*), void ()** @x4, align 8 +; CHECK-NEXT: store { void ()*, void ()*, i32 } { void ()* select (i1 icmp ne (void ()* @f, void ()* null), void ()* @[[JT]], void ()* null), void ()* select (i1 icmp ne (void ()* @f, void ()* null), void ()* @[[JT]], void ()* null), i32 42 }, { void ()*, void ()*, i32 }* @s, align 8 ; CHECK-NEXT: ret void ; CHECK-NEXT: } Index: llvm/test/Transforms/LowerTypeTests/icall-branch-funnel.ll =================================================================== --- llvm/test/Transforms/LowerTypeTests/icall-branch-funnel.ll +++ llvm/test/Transforms/LowerTypeTests/icall-branch-funnel.ll @@ -4,10 +4,10 @@ target triple = "x86_64-unknown-linux" ; CHECK: @0 = private constant { i32, [0 x i8], i32 } { i32 1, [0 x i8] zeroinitializer, i32 2 } -; CHECK: @f1 = alias void (), void ()* @.cfi.jumptable -; CHECK: @f2 = alias void (), bitcast ([8 x i8]* getelementptr inbounds ([2 x [8 x i8]], [2 x [8 x i8]]* bitcast (void ()* @.cfi.jumptable to [2 x [8 x i8]]*), i64 0, i64 1) to void ()*) ; CHECK: @g1 = alias i32, getelementptr inbounds ({ i32, [0 x i8], i32 }, { i32, [0 x i8], i32 }* @0, i32 0, i32 0) ; CHECK: @g2 = alias i32, getelementptr inbounds ({ i32, [0 x i8], i32 }, { i32, [0 x i8], i32 }* @0, i32 0, i32 2) +; CHECK: @f1 = alias void (), void ()* @.cfi.jumptable +; CHECK: @f2 = alias void (), bitcast ([8 x i8]* getelementptr inbounds ([2 x [8 x i8]], [2 x [8 x i8]]* bitcast (void ()* @.cfi.jumptable to [2 x [8 x i8]]*), i64 0, i64 1) to void ()*) @g1 = constant i32 1 @g2 = constant i32 2 Index: llvm/test/Transforms/OpenMP/parallel_deletion_remarks.ll =================================================================== --- llvm/test/Transforms/OpenMP/parallel_deletion_remarks.ll +++ llvm/test/Transforms/OpenMP/parallel_deletion_remarks.ll @@ -23,9 +23,9 @@ ; ; This will delete all but the first parallel region -; CHECK: remark: parallel_deletion_remarks.c:14:1: Parallel region in delete_parallel deleted -; CHECK: remark: parallel_deletion_remarks.c:12:1: Parallel region in delete_parallel deleted ; CHECK: remark: parallel_deletion_remarks.c:10:1: Parallel region in delete_parallel deleted +; CHECK: remark: parallel_deletion_remarks.c:12:1: Parallel region in delete_parallel deleted +; CHECK: remark: parallel_deletion_remarks.c:14:1: Parallel region in delete_parallel deleted define dso_local void @delete_parallel() local_unnamed_addr !dbg !15 { call void (%struct.ident_t*, i32, void (i32*, i32*, ...)*, ...) @__kmpc_fork_call(%struct.ident_t* nonnull @0, i32 0, void (i32*, i32*, ...)* bitcast (void (i32*, i32*)* @.omp_outlined. to void (i32*, i32*, ...)*)), !dbg !18 call void (%struct.ident_t*, i32, void (i32*, i32*, ...)*, ...) @__kmpc_fork_call(%struct.ident_t* nonnull @0, i32 0, void (i32*, i32*, ...)* bitcast (void (i32*, i32*)* @.omp_outlined..2 to void (i32*, i32*, ...)*)), !dbg !19 Index: llvm/test/Transforms/WholeProgramDevirt/branch-funnel.ll =================================================================== --- llvm/test/Transforms/WholeProgramDevirt/branch-funnel.ll +++ llvm/test/Transforms/WholeProgramDevirt/branch-funnel.ll @@ -147,10 +147,11 @@ ret i32 %result } -; CHECK-LABEL: define internal void @branch_funnel(i8* -; CHECK: define hidden void @__typeid_typeid1_0_branch_funnel(i8* nest %0, ...) +; CHECK-LABEL: define hidden void @__typeid_typeid1_0_branch_funnel(i8* nest %0, ...) ; CHECK-NEXT: musttail call void (...) @llvm.icall.branch.funnel(i8* %0, i8* bitcast ([1 x i8*]* {{(nonnull )?}}@vt1_1 to i8*), i32 (i8*, i32)* {{(nonnull )?}}@vf1_1, i8* bitcast ([1 x i8*]* {{(nonnull )?}}@vt1_2 to i8*), i32 (i8*, i32)* {{(nonnull )?}}@vf1_2, ...) +; CHECK: define internal void @branch_funnel(i8* + declare i1 @llvm.type.test(i8*, metadata) declare void @llvm.assume(i1) Index: llvm/test/Transforms/WholeProgramDevirt/virtual-const-prop-begin.ll =================================================================== --- llvm/test/Transforms/WholeProgramDevirt/virtual-const-prop-begin.ll +++ llvm/test/Transforms/WholeProgramDevirt/virtual-const-prop-begin.ll @@ -3,28 +3,28 @@ target datalayout = "e-p:64:64" target triple = "x86_64-unknown-linux-gnu" -; CHECK: [[VT1DATA:@[^ ]*]] = private constant { [8 x i8], [3 x i8*], [0 x i8] } { [8 x i8] c"\00\00\00\01\01\00\00\00", [3 x i8*] [i8* bitcast (i1 (i8*)* @vf0i1 to i8*), i8* bitcast (i1 (i8*)* @vf1i1 to i8*), i8* bitcast (i32 (i8*)* @vf1i32 to i8*)], [0 x i8] zeroinitializer }, section "vt1sec", !type [[T8:![0-9]+]] +; CHECK: [[VT1DATA:@[^ ]*]] = private constant { [8 x i8], [3 x i8*], [0 x i8] } { [8 x i8] c"\00\00\00\01\00\00\00\02", [3 x i8*] [i8* bitcast (i1 (i8*)* @vf0i1 to i8*), i8* bitcast (i1 (i8*)* @vf1i1 to i8*), i8* bitcast (i32 (i8*)* @vf1i32 to i8*)], [0 x i8] zeroinitializer }, section "vt1sec", !type [[T8:![0-9]+]] @vt1 = constant [3 x i8*] [ i8* bitcast (i1 (i8*)* @vf0i1 to i8*), i8* bitcast (i1 (i8*)* @vf1i1 to i8*), i8* bitcast (i32 (i8*)* @vf1i32 to i8*) ], section "vt1sec", !type !0 -; CHECK: [[VT2DATA:@[^ ]*]] = private constant { [8 x i8], [3 x i8*], [0 x i8] } { [8 x i8] c"\00\00\00\02\02\00\00\00", [3 x i8*] [i8* bitcast (i1 (i8*)* @vf1i1 to i8*), i8* bitcast (i1 (i8*)* @vf0i1 to i8*), i8* bitcast (i32 (i8*)* @vf2i32 to i8*)], [0 x i8] zeroinitializer }, !type [[T8]] +; CHECK: [[VT2DATA:@[^ ]*]] = private constant { [8 x i8], [3 x i8*], [0 x i8] } { [8 x i8] c"\00\00\00\02\00\00\00\01", [3 x i8*] [i8* bitcast (i1 (i8*)* @vf1i1 to i8*), i8* bitcast (i1 (i8*)* @vf0i1 to i8*), i8* bitcast (i32 (i8*)* @vf2i32 to i8*)], [0 x i8] zeroinitializer }, !type [[T8]] @vt2 = constant [3 x i8*] [ i8* bitcast (i1 (i8*)* @vf1i1 to i8*), i8* bitcast (i1 (i8*)* @vf0i1 to i8*), i8* bitcast (i32 (i8*)* @vf2i32 to i8*) ], !type !0 -; CHECK: [[VT3DATA:@[^ ]*]] = private constant { [5 x i8], [3 x i8*], [0 x i8] } { [5 x i8] c"\01\03\00\00\00", [3 x i8*] [i8* bitcast (i1 (i8*)* @vf0i1 to i8*), i8* bitcast (i1 (i8*)* @vf1i1 to i8*), i8* bitcast (i32 (i8*)* @vf3i32 to i8*)], [0 x i8] zeroinitializer }, align 1, !type [[T5:![0-9]+]] +; CHECK: [[VT3DATA:@[^ ]*]] = private constant { [5 x i8], [3 x i8*], [0 x i8] } { [5 x i8] c"\03\00\00\00\02", [3 x i8*] [i8* bitcast (i1 (i8*)* @vf0i1 to i8*), i8* bitcast (i1 (i8*)* @vf1i1 to i8*), i8* bitcast (i32 (i8*)* @vf3i32 to i8*)], [0 x i8] zeroinitializer }, align 1, !type [[T5:![0-9]+]] @vt3 = constant [3 x i8*] [ i8* bitcast (i1 (i8*)* @vf0i1 to i8*), i8* bitcast (i1 (i8*)* @vf1i1 to i8*), i8* bitcast (i32 (i8*)* @vf3i32 to i8*) ], align 1, !type !0 -; CHECK: [[VT4DATA:@[^ ]*]] = private constant { [16 x i8], [3 x i8*], [0 x i8] } { [16 x i8] c"\00\00\00\00\00\00\00\00\00\00\00\02\04\00\00\00", [3 x i8*] [i8* bitcast (i1 (i8*)* @vf1i1 to i8*), i8* bitcast (i1 (i8*)* @vf0i1 to i8*), i8* bitcast (i32 (i8*)* @vf4i32 to i8*)], [0 x i8] zeroinitializer }, align 16, !type [[T16:![0-9]+]] +; CHECK: [[VT4DATA:@[^ ]*]] = private constant { [16 x i8], [3 x i8*], [0 x i8] } { [16 x i8] c"\00\00\00\00\00\00\00\00\00\00\00\04\00\00\00\01", [3 x i8*] [i8* bitcast (i1 (i8*)* @vf1i1 to i8*), i8* bitcast (i1 (i8*)* @vf0i1 to i8*), i8* bitcast (i32 (i8*)* @vf4i32 to i8*)], [0 x i8] zeroinitializer }, align 16, !type [[T16:![0-9]+]] @vt4 = constant [3 x i8*] [ i8* bitcast (i1 (i8*)* @vf1i1 to i8*), i8* bitcast (i1 (i8*)* @vf0i1 to i8*), @@ -79,9 +79,9 @@ %fptrptr = getelementptr [3 x i8*], [3 x i8*]* %vtable, i32 0, i32 0 %fptr = load i8*, i8** %fptrptr %fptr_casted = bitcast i8* %fptr to i1 (i8*)* - ; CHECK: [[VTGEP1:%[^ ]*]] = getelementptr i8, i8* [[VT1]], i32 -5 + ; CHECK: [[VTGEP1:%[^ ]*]] = getelementptr i8, i8* [[VT1]], i32 -1 ; CHECK: [[VTLOAD1:%[^ ]*]] = load i8, i8* [[VTGEP1]] - ; CHECK: [[VTAND1:%[^ ]*]] = and i8 [[VTLOAD1]], 2 + ; CHECK: [[VTAND1:%[^ ]*]] = and i8 [[VTLOAD1]], 1 ; CHECK: [[VTCMP1:%[^ ]*]] = icmp ne i8 [[VTAND1]], 0 %result = call i1 %fptr_casted(i8* %obj) ; CHECK: ret i1 [[VTCMP1]] @@ -100,9 +100,9 @@ %fptrptr = getelementptr [3 x i8*], [3 x i8*]* %vtable, i32 0, i32 1 %fptr = load i8*, i8** %fptrptr %fptr_casted = bitcast i8* %fptr to i1 (i8*)* - ; CHECK: [[VTGEP2:%[^ ]*]] = getelementptr i8, i8* [[VT2]], i32 -5 + ; CHECK: [[VTGEP2:%[^ ]*]] = getelementptr i8, i8* [[VT2]], i32 -1 ; CHECK: [[VTLOAD2:%[^ ]*]] = load i8, i8* [[VTGEP2]] - ; CHECK: [[VTAND2:%[^ ]*]] = and i8 [[VTLOAD2]], 1 + ; CHECK: [[VTAND2:%[^ ]*]] = and i8 [[VTLOAD2]], 2 ; CHECK: [[VTCMP2:%[^ ]*]] = icmp ne i8 [[VTAND2]], 0 %result = call i1 %fptr_casted(i8* %obj) ; CHECK: ret i1 [[VTCMP2]] @@ -121,7 +121,7 @@ %fptrptr = getelementptr [3 x i8*], [3 x i8*]* %vtable, i32 0, i32 2 %fptr = load i8*, i8** %fptrptr %fptr_casted = bitcast i8* %fptr to i32 (i8*)* - ; CHECK: [[VTGEP3:%[^ ]*]] = getelementptr i8, i8* [[VT3]], i32 -4 + ; CHECK: [[VTGEP3:%[^ ]*]] = getelementptr i8, i8* [[VT3]], i32 -5 ; CHECK: [[VTBC3:%[^ ]*]] = bitcast i8* [[VTGEP3]] to i32* ; CHECK: [[VTLOAD3:%[^ ]*]] = load i32, i32* [[VTBC3]] %result = call i32 %fptr_casted(i8* %obj) Index: llvm/test/Transforms/WholeProgramDevirt/virtual-const-prop-check.ll =================================================================== --- llvm/test/Transforms/WholeProgramDevirt/virtual-const-prop-check.ll +++ llvm/test/Transforms/WholeProgramDevirt/virtual-const-prop-check.ll @@ -11,9 +11,9 @@ target datalayout = "e-p:64:64" target triple = "x86_64-unknown-linux-gnu" -; CHECK: remark: :0:0: virtual-const-prop: devirtualized a call to vf1i32 -; CHECK: remark: :0:0: virtual-const-prop-1-bit: devirtualized a call to vf1i1 ; CHECK: remark: :0:0: virtual-const-prop-1-bit: devirtualized a call to vf0i1 +; CHECK: remark: :0:0: virtual-const-prop-1-bit: devirtualized a call to vf1i1 +; CHECK: remark: :0:0: virtual-const-prop: devirtualized a call to vf1i32 ; CHECK: remark: :0:0: devirtualized vf0i1 ; CHECK: remark: :0:0: devirtualized vf1i1 ; CHECK: remark: :0:0: devirtualized vf1i32 @@ -31,28 +31,28 @@ ; SKIP-ALL-NOT: devirtualized -; CHECK: [[VT1DATA:@[^ ]*]] = private constant { [8 x i8], [3 x i8*], [0 x i8] } { [8 x i8] c"\00\00\00\01\01\00\00\00", [3 x i8*] [i8* bitcast (i1 (i8*)* @vf0i1 to i8*), i8* bitcast (i1 (i8*)* @vf1i1 to i8*), i8* bitcast (i32 (i8*)* @vf1i32 to i8*)], [0 x i8] zeroinitializer }, section "vt1sec", !type [[T8:![0-9]+]] +; CHECK: [[VT1DATA:@[^ ]*]] = private constant { [8 x i8], [3 x i8*], [0 x i8] } { [8 x i8] c"\00\00\00\01\00\00\00\02", [3 x i8*] [i8* bitcast (i1 (i8*)* @vf0i1 to i8*), i8* bitcast (i1 (i8*)* @vf1i1 to i8*), i8* bitcast (i32 (i8*)* @vf1i32 to i8*)], [0 x i8] zeroinitializer }, section "vt1sec", !type [[T8:![0-9]+]] @vt1 = constant [3 x i8*] [ i8* bitcast (i1 (i8*)* @vf0i1 to i8*), i8* bitcast (i1 (i8*)* @vf1i1 to i8*), i8* bitcast (i32 (i8*)* @vf1i32 to i8*) ], section "vt1sec", !type !0 -; CHECK: [[VT2DATA:@[^ ]*]] = private constant { [8 x i8], [3 x i8*], [0 x i8] } { [8 x i8] c"\00\00\00\02\02\00\00\00", [3 x i8*] [i8* bitcast (i1 (i8*)* @vf1i1 to i8*), i8* bitcast (i1 (i8*)* @vf0i1 to i8*), i8* bitcast (i32 (i8*)* @vf2i32 to i8*)], [0 x i8] zeroinitializer }, !type [[T8]] +; CHECK: [[VT2DATA:@[^ ]*]] = private constant { [8 x i8], [3 x i8*], [0 x i8] } { [8 x i8] c"\00\00\00\02\00\00\00\01", [3 x i8*] [i8* bitcast (i1 (i8*)* @vf1i1 to i8*), i8* bitcast (i1 (i8*)* @vf0i1 to i8*), i8* bitcast (i32 (i8*)* @vf2i32 to i8*)], [0 x i8] zeroinitializer }, !type [[T8]] @vt2 = constant [3 x i8*] [ i8* bitcast (i1 (i8*)* @vf1i1 to i8*), i8* bitcast (i1 (i8*)* @vf0i1 to i8*), i8* bitcast (i32 (i8*)* @vf2i32 to i8*) ], !type !0 -; CHECK: [[VT3DATA:@[^ ]*]] = private constant { [8 x i8], [3 x i8*], [0 x i8] } { [8 x i8] c"\00\00\00\01\03\00\00\00", [3 x i8*] [i8* bitcast (i1 (i8*)* @vf0i1 to i8*), i8* bitcast (i1 (i8*)* @vf1i1 to i8*), i8* bitcast (i32 (i8*)* @vf3i32 to i8*)], [0 x i8] zeroinitializer }, !type [[T8]] +; CHECK: [[VT3DATA:@[^ ]*]] = private constant { [8 x i8], [3 x i8*], [0 x i8] } { [8 x i8] c"\00\00\00\03\00\00\00\02", [3 x i8*] [i8* bitcast (i1 (i8*)* @vf0i1 to i8*), i8* bitcast (i1 (i8*)* @vf1i1 to i8*), i8* bitcast (i32 (i8*)* @vf3i32 to i8*)], [0 x i8] zeroinitializer }, !type [[T8]] @vt3 = constant [3 x i8*] [ i8* bitcast (i1 (i8*)* @vf0i1 to i8*), i8* bitcast (i1 (i8*)* @vf1i1 to i8*), i8* bitcast (i32 (i8*)* @vf3i32 to i8*) ], !type !0 -; CHECK: [[VT4DATA:@[^ ]*]] = private constant { [8 x i8], [3 x i8*], [0 x i8] } { [8 x i8] c"\00\00\00\02\04\00\00\00", [3 x i8*] [i8* bitcast (i1 (i8*)* @vf1i1 to i8*), i8* bitcast (i1 (i8*)* @vf0i1 to i8*), i8* bitcast (i32 (i8*)* @vf4i32 to i8*)], [0 x i8] zeroinitializer }, !type [[T8]] +; CHECK: [[VT4DATA:@[^ ]*]] = private constant { [8 x i8], [3 x i8*], [0 x i8] } { [8 x i8] c"\00\00\00\04\00\00\00\01", [3 x i8*] [i8* bitcast (i1 (i8*)* @vf1i1 to i8*), i8* bitcast (i1 (i8*)* @vf0i1 to i8*), i8* bitcast (i32 (i8*)* @vf4i32 to i8*)], [0 x i8] zeroinitializer }, !type [[T8]] @vt4 = constant [3 x i8*] [ i8* bitcast (i1 (i8*)* @vf1i1 to i8*), i8* bitcast (i1 (i8*)* @vf0i1 to i8*), @@ -104,9 +104,9 @@ %pair = call {i8*, i1} @llvm.type.checked.load(i8* %vtablei8, i32 0, metadata !"typeid") %fptr = extractvalue {i8*, i1} %pair, 0 %fptr_casted = bitcast i8* %fptr to i1 (i8*)* - ; CHECK: [[VTGEP1:%[^ ]*]] = getelementptr i8, i8* [[VT1]], i32 -5 + ; CHECK: [[VTGEP1:%[^ ]*]] = getelementptr i8, i8* [[VT1]], i32 -1 ; CHECK: [[VTLOAD1:%[^ ]*]] = load i8, i8* [[VTGEP1]] - ; CHECK: [[VTAND1:%[^ ]*]] = and i8 [[VTLOAD1]], 2 + ; CHECK: [[VTAND1:%[^ ]*]] = and i8 [[VTLOAD1]], 1 ; CHECK: [[VTCMP1:%[^ ]*]] = icmp ne i8 [[VTAND1]], 0 %result = call i1 %fptr_casted(i8* %obj) ; CHECK: [[AND1:%[^ ]*]] = and i1 [[VTCMP1]], true @@ -125,9 +125,9 @@ %pair = call {i8*, i1} @llvm.type.checked.load(i8* %vtablei8, i32 8, metadata !"typeid") %fptr = extractvalue {i8*, i1} %pair, 0 %fptr_casted = bitcast i8* %fptr to i1 (i8*)* - ; CHECK: [[VTGEP2:%[^ ]*]] = getelementptr i8, i8* [[VT2]], i32 -5 + ; CHECK: [[VTGEP2:%[^ ]*]] = getelementptr i8, i8* [[VT2]], i32 -1 ; CHECK: [[VTLOAD2:%[^ ]*]] = load i8, i8* [[VTGEP2]] - ; CHECK: [[VTAND2:%[^ ]*]] = and i8 [[VTLOAD2]], 1 + ; CHECK: [[VTAND2:%[^ ]*]] = and i8 [[VTLOAD2]], 2 ; CHECK: [[VTCMP2:%[^ ]*]] = icmp ne i8 [[VTAND2]], 0 %result = call i1 %fptr_casted(i8* %obj) ; CHECK: [[AND2:%[^ ]*]] = and i1 [[VTCMP2]], true @@ -146,7 +146,7 @@ %pair = call {i8*, i1} @llvm.type.checked.load(i8* %vtablei8, i32 16, metadata !"typeid") %fptr = extractvalue {i8*, i1} %pair, 0 %fptr_casted = bitcast i8* %fptr to i32 (i8*)* - ; CHECK: [[VTGEP3:%[^ ]*]] = getelementptr i8, i8* [[VT3]], i32 -4 + ; CHECK: [[VTGEP3:%[^ ]*]] = getelementptr i8, i8* [[VT3]], i32 -5 ; CHECK: [[VTBC3:%[^ ]*]] = bitcast i8* [[VTGEP3]] to i32* ; CHECK: [[VTLOAD3:%[^ ]*]] = load i32, i32* [[VTBC3]] %result = call i32 %fptr_casted(i8* %obj) Index: llvm/test/Transforms/WholeProgramDevirt/virtual-const-prop-end.ll =================================================================== --- llvm/test/Transforms/WholeProgramDevirt/virtual-const-prop-end.ll +++ llvm/test/Transforms/WholeProgramDevirt/virtual-const-prop-end.ll @@ -3,7 +3,7 @@ target datalayout = "e-p:64:64" target triple = "x86_64-unknown-linux-gnu" -; CHECK: [[VT1DATA:@[^ ]*]] = private constant { [0 x i8], [4 x i8*], [5 x i8] } { [0 x i8] zeroinitializer, [4 x i8*] [i8* null, i8* bitcast (i1 (i8*)* @vf0i1 to i8*), i8* bitcast (i1 (i8*)* @vf1i1 to i8*), i8* bitcast (i32 (i8*)* @vf1i32 to i8*)], [5 x i8] c"\01\00\00\00\01" }, !type [[T8:![0-9]+]] +; CHECK: [[VT1DATA:@[^ ]*]] = private constant { [0 x i8], [4 x i8*], [5 x i8] } { [0 x i8] zeroinitializer, [4 x i8*] [i8* null, i8* bitcast (i1 (i8*)* @vf0i1 to i8*), i8* bitcast (i1 (i8*)* @vf1i1 to i8*), i8* bitcast (i32 (i8*)* @vf1i32 to i8*)], [5 x i8] c"\02\01\00\00\00" }, !type [[T8:![0-9]+]] @vt1 = constant [4 x i8*] [ i8* null, i8* bitcast (i1 (i8*)* @vf0i1 to i8*), @@ -11,14 +11,14 @@ i8* bitcast (i32 (i8*)* @vf1i32 to i8*) ], !type !1 -; CHECK: [[VT2DATA:@[^ ]*]] = private constant { [0 x i8], [3 x i8*], [5 x i8] } { [0 x i8] zeroinitializer, [3 x i8*] [i8* bitcast (i1 (i8*)* @vf1i1 to i8*), i8* bitcast (i1 (i8*)* @vf0i1 to i8*), i8* bitcast (i32 (i8*)* @vf2i32 to i8*)], [5 x i8] c"\02\00\00\00\02" }, !type [[T0:![0-9]+]] +; CHECK: [[VT2DATA:@[^ ]*]] = private constant { [0 x i8], [3 x i8*], [5 x i8] } { [0 x i8] zeroinitializer, [3 x i8*] [i8* bitcast (i1 (i8*)* @vf1i1 to i8*), i8* bitcast (i1 (i8*)* @vf0i1 to i8*), i8* bitcast (i32 (i8*)* @vf2i32 to i8*)], [5 x i8] c"\01\02\00\00\00" }, !type [[T0:![0-9]+]] @vt2 = constant [3 x i8*] [ i8* bitcast (i1 (i8*)* @vf1i1 to i8*), i8* bitcast (i1 (i8*)* @vf0i1 to i8*), i8* bitcast (i32 (i8*)* @vf2i32 to i8*) ], !type !0 -; CHECK: [[VT3DATA:@[^ ]*]] = private constant { [0 x i8], [4 x i8*], [5 x i8] } { [0 x i8] zeroinitializer, [4 x i8*] [i8* null, i8* bitcast (i1 (i8*)* @vf0i1 to i8*), i8* bitcast (i1 (i8*)* @vf1i1 to i8*), i8* bitcast (i32 (i8*)* @vf3i32 to i8*)], [5 x i8] c"\03\00\00\00\01" }, !type [[T8]] +; CHECK: [[VT3DATA:@[^ ]*]] = private constant { [0 x i8], [4 x i8*], [5 x i8] } { [0 x i8] zeroinitializer, [4 x i8*] [i8* null, i8* bitcast (i1 (i8*)* @vf0i1 to i8*), i8* bitcast (i1 (i8*)* @vf1i1 to i8*), i8* bitcast (i32 (i8*)* @vf3i32 to i8*)], [5 x i8] c"\02\03\00\00\00" }, !type [[T8]] @vt3 = constant [4 x i8*] [ i8* null, i8* bitcast (i1 (i8*)* @vf0i1 to i8*), @@ -26,7 +26,7 @@ i8* bitcast (i32 (i8*)* @vf3i32 to i8*) ], !type !1 -; CHECK: [[VT4DATA:@[^ ]*]] = private constant { [0 x i8], [3 x i8*], [5 x i8] } { [0 x i8] zeroinitializer, [3 x i8*] [i8* bitcast (i1 (i8*)* @vf1i1 to i8*), i8* bitcast (i1 (i8*)* @vf0i1 to i8*), i8* bitcast (i32 (i8*)* @vf4i32 to i8*)], [5 x i8] c"\04\00\00\00\02" }, !type [[T0]] +; CHECK: [[VT4DATA:@[^ ]*]] = private constant { [0 x i8], [3 x i8*], [5 x i8] } { [0 x i8] zeroinitializer, [3 x i8*] [i8* bitcast (i1 (i8*)* @vf1i1 to i8*), i8* bitcast (i1 (i8*)* @vf0i1 to i8*), i8* bitcast (i32 (i8*)* @vf4i32 to i8*)], [5 x i8] c"\01\04\00\00\00" }, !type [[T0]] @vt4 = constant [3 x i8*] [ i8* bitcast (i1 (i8*)* @vf1i1 to i8*), i8* bitcast (i1 (i8*)* @vf0i1 to i8*), @@ -74,9 +74,9 @@ %fptrptr = getelementptr [3 x i8*], [3 x i8*]* %vtable, i32 0, i32 0 %fptr = load i8*, i8** %fptrptr %fptr_casted = bitcast i8* %fptr to i1 (i8*)* - ; CHECK: [[VTGEP1:%[^ ]*]] = getelementptr i8, i8* [[VT1]], i32 28 + ; CHECK: [[VTGEP1:%[^ ]*]] = getelementptr i8, i8* [[VT1]], i32 24 ; CHECK: [[VTLOAD1:%[^ ]*]] = load i8, i8* [[VTGEP1]] - ; CHECK: [[VTAND1:%[^ ]*]] = and i8 [[VTLOAD1]], 2 + ; CHECK: [[VTAND1:%[^ ]*]] = and i8 [[VTLOAD1]], 1 ; CHECK: [[VTCMP1:%[^ ]*]] = icmp ne i8 [[VTAND1]], 0 %result = call i1 %fptr_casted(i8* %obj) ; CHECK: ret i1 [[VTCMP1]] @@ -95,9 +95,9 @@ %fptrptr = getelementptr [3 x i8*], [3 x i8*]* %vtable, i32 0, i32 1 %fptr = load i8*, i8** %fptrptr %fptr_casted = bitcast i8* %fptr to i1 (i8*)* - ; CHECK: [[VTGEP2:%[^ ]*]] = getelementptr i8, i8* [[VT2]], i32 28 + ; CHECK: [[VTGEP2:%[^ ]*]] = getelementptr i8, i8* [[VT2]], i32 24 ; CHECK: [[VTLOAD2:%[^ ]*]] = load i8, i8* [[VTGEP2]] - ; CHECK: [[VTAND2:%[^ ]*]] = and i8 [[VTLOAD2]], 1 + ; CHECK: [[VTAND2:%[^ ]*]] = and i8 [[VTLOAD2]], 2 ; CHECK: [[VTCMP2:%[^ ]*]] = icmp ne i8 [[VTAND2]], 0 %result = call i1 %fptr_casted(i8* %obj) ; CHECK: ret i1 [[VTCMP2]] @@ -116,7 +116,7 @@ %fptrptr = getelementptr [3 x i8*], [3 x i8*]* %vtable, i32 0, i32 2 %fptr = load i8*, i8** %fptrptr %fptr_casted = bitcast i8* %fptr to i32 (i8*)* - ; CHECK: [[VTGEP3:%[^ ]*]] = getelementptr i8, i8* [[VT3]], i32 24 + ; CHECK: [[VTGEP3:%[^ ]*]] = getelementptr i8, i8* [[VT3]], i32 25 ; CHECK: [[VTBC3:%[^ ]*]] = bitcast i8* [[VTGEP3]] to i32* ; CHECK: [[VTLOAD3:%[^ ]*]] = load i32, i32* [[VTBC3]] %result = call i32 %fptr_casted(i8* %obj)