diff options
author | Chris Lattner <sabre@nondot.org> | 2004-07-13 01:49:43 +0000 |
---|---|---|
committer | Chris Lattner <sabre@nondot.org> | 2004-07-13 01:49:43 +0000 |
commit | b89e071aea07022c0240491b380a23958692890c (patch) | |
tree | b6a44009f0f3b16cbfa0e2212eed1580b9db29d5 /lib/Transforms | |
parent | d9aa7836e23e518388ed7426ce3d19111074e0bc (diff) |
Factor some code to handle "load (constantexpr cast foo)" just like
"load (cast foo)". This allows us to compile C++ code like this:
class Bclass {
public: virtual int operator()() { return 666; }
};
class Dclass: public Bclass {
public: virtual int operator()() { return 667; }
} ;
int main(int argc, char** argv) {
Dclass x;
return x();
}
Into this:
int %main(int %argc, sbyte** %argv) {
entry:
call void %__main( )
ret int 667
}
Instead of this:
int %main(int %argc, sbyte** %argv) {
entry:
%x = alloca "struct.std::bad_typeid" ; <"struct.std::bad_typeid"*> [#uses=3]
call void %__main( )
%tmp.1.i.i = getelementptr "struct.std::bad_typeid"* %x, uint 0, uint 0, uint 0 ; <int (...)***> [#uses=1]
store int (...)** getelementptr ([3 x int (...)*]* %vtable for Bclass, int 0, long 2), int (...)*** %tmp.1.i.i
%tmp.3.i = getelementptr "struct.std::bad_typeid"* %x, int 0, uint 0, uint 0 ; <int (...)***> [#uses=1]
store int (...)** getelementptr ([3 x int (...)*]* %vtable for Dclass, int 0, long 2), int (...)*** %tmp.3.i
%tmp.5 = load int ("struct.std::bad_typeid"*)** cast (int (...)** getelementptr ([3 x int (...)*]* %vtable for Dclass, int 0, long 2) to int
("struct.std::bad_typeid"*)**) ; <int ("struct.std::bad_typeid"*)*> [#uses=1]
%tmp.6 = call int %tmp.5( "struct.std::bad_typeid"* %x ) ; <int> [#uses=1]
ret int %tmp.6
ret int 0
}
In order words, we now resolve the virtual function call.
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@14783 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'lib/Transforms')
-rw-r--r-- | lib/Transforms/Scalar/InstructionCombining.cpp | 52 |
1 files changed, 32 insertions, 20 deletions
diff --git a/lib/Transforms/Scalar/InstructionCombining.cpp b/lib/Transforms/Scalar/InstructionCombining.cpp index d43011da5b..8d353c8063 100644 --- a/lib/Transforms/Scalar/InstructionCombining.cpp +++ b/lib/Transforms/Scalar/InstructionCombining.cpp @@ -2947,6 +2947,30 @@ static Constant *GetGEPGlobalInitializer(Constant *C, ConstantExpr *CE) { return C; } +static Instruction *InstCombineLoadCast(InstCombiner &IC, LoadInst &LI) { + User *CI = cast<User>(LI.getOperand(0)); + + const Type *DestPTy = cast<PointerType>(CI->getType())->getElementType(); + if (const PointerType *SrcTy = + dyn_cast<PointerType>(CI->getOperand(0)->getType())) { + const Type *SrcPTy = SrcTy->getElementType(); + if (SrcPTy->isSized() && DestPTy->isSized() && + IC.getTargetData().getTypeSize(SrcPTy) == + IC.getTargetData().getTypeSize(DestPTy) && + (SrcPTy->isInteger() || isa<PointerType>(SrcPTy)) && + (DestPTy->isInteger() || isa<PointerType>(DestPTy))) { + // Okay, we are casting from one integer or pointer type to another of + // the same size. Instead of casting the pointer before the load, cast + // the result of the loaded value. + Value *NewLoad = IC.InsertNewInstBefore(new LoadInst(CI->getOperand(0), + CI->getName()), LI); + // Now cast the result of the load. + return new CastInst(NewLoad, LI.getType()); + } + } + return 0; +} + Instruction *InstCombiner::visitLoadInst(LoadInst &LI) { Value *Op = LI.getOperand(0); if (LI.isVolatile()) return 0; @@ -2964,33 +2988,21 @@ Instruction *InstCombiner::visitLoadInst(LoadInst &LI) { // Instcombine load (constantexpr_GEP global, 0, ...) into the value loaded... if (ConstantExpr *CE = dyn_cast<ConstantExpr>(Op)) - if (CE->getOpcode() == Instruction::GetElementPtr) + if (CE->getOpcode() == Instruction::GetElementPtr) { if (ConstantPointerRef *G=dyn_cast<ConstantPointerRef>(CE->getOperand(0))) if (GlobalVariable *GV = dyn_cast<GlobalVariable>(G->getValue())) if (GV->isConstant() && !GV->isExternal()) if (Constant *V = GetGEPGlobalInitializer(GV->getInitializer(), CE)) return ReplaceInstUsesWith(LI, V); + } else if (CE->getOpcode() == Instruction::Cast) { + if (Instruction *Res = InstCombineLoadCast(*this, LI)) + return Res; + } // load (cast X) --> cast (load X) iff safe - if (CastInst *CI = dyn_cast<CastInst>(Op)) { - const Type *DestPTy = cast<PointerType>(CI->getType())->getElementType(); - if (const PointerType *SrcTy = - dyn_cast<PointerType>(CI->getOperand(0)->getType())) { - const Type *SrcPTy = SrcTy->getElementType(); - if (SrcPTy->isSized() && DestPTy->isSized() && - TD->getTypeSize(SrcPTy) == TD->getTypeSize(DestPTy) && - (SrcPTy->isInteger() || isa<PointerType>(SrcPTy)) && - (DestPTy->isInteger() || isa<PointerType>(DestPTy))) { - // Okay, we are casting from one integer or pointer type to another of - // the same size. Instead of casting the pointer before the load, cast - // the result of the loaded value. - Value *NewLoad = InsertNewInstBefore(new LoadInst(CI->getOperand(0), - CI->getName()), LI); - // Now cast the result of the load. - return new CastInst(NewLoad, LI.getType()); - } - } - } + if (CastInst *CI = dyn_cast<CastInst>(Op)) + if (Instruction *Res = InstCombineLoadCast(*this, LI)) + return Res; return 0; } |