Index: include/llvm/Analysis/ConstantFolding.h =================================================================== --- include/llvm/Analysis/ConstantFolding.h +++ include/llvm/Analysis/ConstantFolding.h @@ -74,8 +74,10 @@ /// ConstantFoldLoadFromConstPtr - Return the value that a load from C would /// produce if it is constant and determinable. If this is not determinable, -/// return null. -Constant *ConstantFoldLoadFromConstPtr(Constant *C, const DataLayout &DL); +/// return null. If AssumeGVConst is true, assume that the base GlobalVariable +/// in C (if there is one) is constant even if the IR indicates otherwise. +Constant *ConstantFoldLoadFromConstPtr(Constant *C, const DataLayout &DL, + bool AssumeGVConst = false); /// ConstantFoldLoadThroughGEPConstantExpr - Given a constant and a /// getelementptr constantexpr, return the constant value being addressed by the Index: lib/Analysis/ConstantFolding.cpp =================================================================== --- lib/Analysis/ConstantFolding.cpp +++ lib/Analysis/ConstantFolding.cpp @@ -31,6 +31,7 @@ #include "llvm/IR/GlobalVariable.h" #include "llvm/IR/Instructions.h" #include "llvm/IR/Intrinsics.h" +#include "llvm/IR/LLVMContext.h" #include "llvm/IR/Operator.h" #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/MathExtras.h" @@ -479,14 +480,17 @@ return ConstantInt::get(IntType->getContext(), ResultVal); } +/// If AssumeGVConst is true, assume that the base GlobalVariable in C (if there +/// is one) is constant even if the IR indicates otherwise. static Constant *ConstantFoldLoadThroughBitcast(ConstantExpr *CE, - const DataLayout &DL) { + const DataLayout &DL, + bool AssumeGVConst) { auto *DestPtrTy = dyn_cast(CE->getType()); if (!DestPtrTy) return nullptr; Type *DestTy = DestPtrTy->getElementType(); - Constant *C = ConstantFoldLoadFromConstPtr(CE->getOperand(0), DL); + Constant *C = ConstantFoldLoadFromConstPtr(CE->getOperand(0), DL, AssumeGVConst); if (!C) return nullptr; @@ -524,12 +528,15 @@ } /// Return the value that a load from C would produce if it is constant and -/// determinable. If this is not determinable, return null. +/// determinable. If this is not determinable, return null. If AssumeGVConst is +/// true, assume that the base GlobalVariable in C (if there is one) is constant +/// even if the IR indicates otherwise. Constant *llvm::ConstantFoldLoadFromConstPtr(Constant *C, - const DataLayout &DL) { + const DataLayout &DL, + bool AssumeGVConst) { // First, try the easy cases: if (GlobalVariable *GV = dyn_cast(C)) - if (GV->isConstant() && GV->hasDefinitiveInitializer()) + if ((AssumeGVConst || GV->isConstant()) && GV->hasDefinitiveInitializer()) return GV->getInitializer(); // If the loaded value isn't a constant expr, we can't handle it. @@ -539,7 +546,7 @@ if (CE->getOpcode() == Instruction::GetElementPtr) { if (GlobalVariable *GV = dyn_cast(CE->getOperand(0))) { - if (GV->isConstant() && GV->hasDefinitiveInitializer()) { + if ((AssumeGVConst || GV->isConstant()) && GV->hasDefinitiveInitializer()) { if (Constant *V = ConstantFoldLoadThroughGEPConstantExpr(GV->getInitializer(), CE)) return V; @@ -548,7 +555,7 @@ } if (CE->getOpcode() == Instruction::BitCast) - if (Constant *LoadedC = ConstantFoldLoadThroughBitcast(CE, DL)) + if (Constant *LoadedC = ConstantFoldLoadThroughBitcast(CE, DL, AssumeGVConst)) return LoadedC; // Instead of loading constant c string, use corresponding integer value @@ -603,12 +610,26 @@ return FoldReinterpretLoadFromConstPtr(CE, DL); } +static bool isVtableLoad(const Instruction *I) { + if (MDNode *Tag = I->getMetadata(LLVMContext::MD_tbaa)) + return Tag->isTBAAVtableAccess(); + return false; +} + static Constant *ConstantFoldLoadInst(const LoadInst *LI, const DataLayout &DL) { if (LI->isVolatile()) return nullptr; - if (Constant *C = dyn_cast(LI->getOperand(0))) - return ConstantFoldLoadFromConstPtr(C, DL); + if (Constant *C = dyn_cast(LI->getOperand(0))) { + bool IsVTableLoad = isVtableLoad(LI); + Constant *FoldedC = ConstantFoldLoadFromConstPtr(C, DL, IsVTableLoad); + if (IsVTableLoad && FoldedC) { + if (!FoldedC->isZeroValue()) + return FoldedC; + return nullptr; + } + return FoldedC; + } return nullptr; } Index: test/Transforms/InstCombine/constant-fold-global-vtable-load.ll =================================================================== --- /dev/null +++ test/Transforms/InstCombine/constant-fold-global-vtable-load.ll @@ -0,0 +1,23 @@ +; RUN: opt -S -instcombine %s -o - | FileCheck %s +target datalayout = "e-m:e-i64:64-i128:128-n8:16:32:64-S128" + +%class.S = type { i32 (...)** } +@gS = global %class.S { i32 (...)** bitcast (i8** getelementptr inbounds ([3 x i8*], [3 x i8*]* @_ZTV1S, i64 0, i64 2) to i32 (...)**) } +@_ZTV1S = unnamed_addr constant [3 x i8*] [i8* null, i8* null, i8* bitcast (i32 (%class.S*, i32)* @memberfunc to i8*)] + +declare i32 @memberfunc(%class.S* nocapture readnone %this, i32 %x) + +define i32 @foo() { +; CHECK-LABEL: foo +entry: + %0 = bitcast %class.S* @gS to i32 (%class.S*, i32)*** + %vtable = load i32 (%class.S*, i32)**, i32 (%class.S*, i32)*** %0, !tbaa !1 + %1 = load i32 (%class.S*, i32)*, i32 (%class.S*, i32)** %vtable +; CHECK: call i32 @memberfunc + %call = tail call i32 %1(%class.S* @gS, i32 0) + ret i32 %call +} + +!1 = !{!2, !2, i64 0} +!2 = !{!"vtable pointer", !3, i64 0} +!3 = !{!"Simple C/C++ TBAA"}