| //===----- LowerConstantCalls.cpp - Changes arrayLength calls --------------===// |
| // |
| // The VMKit project |
| // |
| // This file is distributed under the University of Illinois Open Source |
| // License. See LICENSE.TXT for details. |
| // |
| //===----------------------------------------------------------------------===// |
| |
| #include "llvm/IR/Constants.h" |
| #include "llvm/IR/GlobalVariable.h" |
| #include "llvm/Pass.h" |
| #include "llvm/IR/Function.h" |
| #include "llvm/IR/Instructions.h" |
| #include "llvm/Support/CallSite.h" |
| #include "llvm/Support/Compiler.h" |
| #include "llvm/Support/Debug.h" |
| |
| #include "JavaClass.h" |
| #include "j3/JavaLLVMCompiler.h" |
| #include "j3/J3Intrinsics.h" |
| |
| using namespace llvm; |
| |
| namespace j3 { |
| |
| class LowerConstantCalls : public FunctionPass { |
| public: |
| static char ID; |
| JavaLLVMCompiler* TheCompiler; |
| LowerConstantCalls(JavaLLVMCompiler* Compiler) : FunctionPass(ID), |
| TheCompiler(Compiler) { } |
| |
| const char* getPassName() const { return "Lower Java calls"; } |
| |
| virtual bool runOnFunction(Function &F); |
| private: |
| }; |
| char LowerConstantCalls::ID = 0; |
| |
| static Value* getTCM(J3Intrinsics* intrinsics, Value* Arg, Instruction* CI) { |
| Value* GEP[2] = { intrinsics->constantZero, |
| intrinsics->OffsetTaskClassMirrorInClassConstant }; |
| Value* TCMArray = GetElementPtrInst::Create(Arg, GEP, "", CI); |
| |
| Value* GEP2[2] = { intrinsics->constantZero, intrinsics->constantZero }; |
| |
| Value* TCM = GetElementPtrInst::Create(TCMArray, GEP2, "", CI); |
| return TCM; |
| |
| } |
| |
| static Value* getDelegatee(J3Intrinsics* intrinsics, Value* Arg, Instruction* CI) { |
| Value* GEP[2] = { intrinsics->constantZero, |
| intrinsics->constantZero }; |
| Value* TCMArray = GetElementPtrInst::Create(Arg, GEP, "", CI); |
| |
| Value* GEP2[2] = { intrinsics->constantZero, intrinsics->constantZero }; |
| |
| Value* TCM = GetElementPtrInst::Create(TCMArray, GEP2, "", CI); |
| return new LoadInst(TCM, "", CI); |
| |
| } |
| |
| bool LowerConstantCalls::runOnFunction(Function& F) { |
| LLVMContext* Context = &F.getContext(); |
| bool Changed = false; |
| J3Intrinsics* intrinsics = TheCompiler->getIntrinsics(); |
| JavaMethod* meth = TheCompiler->getJavaMethod(F); |
| assert(meth && "Method not registered"); |
| for (Function::iterator BI = F.begin(), BE = F.end(); BI != BE; BI++) { |
| BasicBlock *Cur = BI; |
| for (BasicBlock::iterator II = Cur->begin(), IE = Cur->end(); II != IE;) { |
| Instruction *I = II; |
| II++; |
| |
| if (ICmpInst* Cmp = dyn_cast<ICmpInst>(I)) { |
| if (Cmp->getOperand(1) == intrinsics->JavaObjectNullConstant) { |
| Value* Arg = Cmp->getOperand(0); |
| if (isVirtual(meth->access) && Arg == F.arg_begin()) { |
| Changed = true; |
| Cmp->replaceAllUsesWith(ConstantInt::getFalse(*Context)); |
| Cmp->eraseFromParent(); |
| break; |
| } |
| |
| Instruction* InsArg = dyn_cast<Instruction>(Arg); |
| if (InsArg != NULL && |
| (InsArg->getOpcode() == Instruction::Call || |
| InsArg->getOpcode() == Instruction::Invoke)) { |
| CallSite Ca(Arg); |
| if (Ca.getCalledValue() == intrinsics->VTAllocateFunction) { |
| Changed = true; |
| Cmp->replaceAllUsesWith(ConstantInt::getFalse(*Context)); |
| Cmp->eraseFromParent(); |
| break; |
| } |
| } |
| } |
| } |
| |
| // Remove useless Alloca's, usually used for stacks or temporary values. |
| // The optimizers may have rendered them useless. |
| if (AllocaInst* AI = dyn_cast<AllocaInst>(I)) { |
| bool ToDelete = true; |
| for (Value::use_iterator UI = AI->use_begin(), UE = AI->use_end(); |
| UI != UE; ++UI) { |
| if (dyn_cast<StoreInst>(*UI)) continue; |
| if (BitCastInst* BI = dyn_cast<BitCastInst>(*UI)) { |
| if (BI->hasOneUse()) { |
| Instruction* use = dyn_cast<Instruction>(*(BI->use_begin())); |
| if (use != NULL && |
| (use->getOpcode() == Instruction::Call || |
| use->getOpcode() == Instruction::Invoke)) { |
| CallSite Call(use); |
| if (Call.getCalledFunction() == intrinsics->llvm_gc_gcroot) { |
| continue; |
| } |
| } |
| } |
| } |
| |
| ToDelete = false; |
| break; |
| } |
| |
| if (ToDelete) { |
| Changed = true; |
| for (Value::use_iterator UI = AI->use_begin(), UE = AI->use_end(); |
| UI != UE;) { |
| Value* Temp = *UI; |
| ++UI; |
| if (StoreInst* SI = dyn_cast<StoreInst>(Temp)) { |
| if (dyn_cast<Instruction>(II) == SI) ++II; |
| SI->eraseFromParent(); |
| } else if (BitCastInst* BI = dyn_cast<BitCastInst>(Temp)) { |
| CallSite Call(*(BI->use_begin())); |
| Instruction* CI = Call.getInstruction(); |
| if (dyn_cast<Instruction>(II) == CI) ++II; |
| CI->eraseFromParent(); |
| if (dyn_cast<Instruction>(II) == BI) ++II; |
| BI->eraseFromParent(); |
| } |
| } |
| AI->eraseFromParent(); |
| } |
| continue; |
| } |
| |
| if ((I->getOpcode() == Instruction::Call || |
| I->getOpcode() == Instruction::Invoke)) { |
| Instruction* CI = I; |
| CallSite Call(I); |
| Value* V = Call.getCalledValue(); |
| if (V == intrinsics->ArrayLengthFunction) { |
| Changed = true; |
| Value* val = Call.getArgument(0); // get the array |
| Value* array = new BitCastInst(val, intrinsics->JavaArrayType, |
| "", CI); |
| Value* args[2] = { intrinsics->constantZero, |
| intrinsics->JavaArraySizeOffsetConstant }; |
| Value* ptr = GetElementPtrInst::Create(array, args, "", CI); |
| Value* load = new LoadInst(ptr, "", CI); |
| load = new PtrToIntInst(load, Type::getInt32Ty(*Context), "", CI); |
| CI->replaceAllUsesWith(load); |
| CI->eraseFromParent(); |
| } else if (V == intrinsics->GetVTFunction) { |
| Changed = true; |
| Value* val = Call.getArgument(0); // get the object |
| Value* indexes[2] = { intrinsics->constantZero, intrinsics->JavaObjectVTOffsetConstant }; |
| Value* VTPtr = GetElementPtrInst::Create(val, indexes, "", CI); |
| Value* VT = new LoadInst(VTPtr, "", CI); |
| CI->replaceAllUsesWith(VT); |
| CI->eraseFromParent(); |
| } else if (V == intrinsics->GetIMTFunction) { |
| Changed = true; |
| Value* val = Call.getArgument(0); // get the VT |
| Value* indexes[2] = { intrinsics->constantZero, |
| intrinsics->OffsetIMTInVTConstant }; |
| Value* IMTPtr = GetElementPtrInst::Create(val, indexes, "", CI); |
| Value* IMT = new LoadInst(IMTPtr, "", CI); |
| IMT = new BitCastInst(IMT, CI->getType(), "", CI); |
| CI->replaceAllUsesWith(IMT); |
| CI->eraseFromParent(); |
| } else if (V == intrinsics->GetClassFunction) { |
| Changed = true; |
| Value* val = Call.getArgument(0); // get the object |
| Value* args2[2] = { intrinsics->constantZero, |
| intrinsics->JavaObjectVTOffsetConstant }; |
| Value* VTPtr = GetElementPtrInst::Create(val, args2, "", CI); |
| Value* VT = new LoadInst(VTPtr, "", CI); |
| Value* args3[2] = { intrinsics->constantZero, |
| intrinsics->OffsetClassInVTConstant }; |
| |
| Value* clPtr = GetElementPtrInst::Create(VT, args3, "", CI); |
| Value* cl = new LoadInst(clPtr, "", CI); |
| cl = new BitCastInst(cl, intrinsics->JavaCommonClassType, "", CI); |
| |
| CI->replaceAllUsesWith(cl); |
| CI->eraseFromParent(); |
| } else if (V == intrinsics->GetVTFromClassFunction) { |
| Changed = true; |
| |
| Value* val = Call.getArgument(0); |
| Value* indexes[3] = { intrinsics->constantZero, |
| intrinsics->constantZero, |
| intrinsics->OffsetVTInClassConstant }; |
| Value* VTPtr = GetElementPtrInst::Create(val, indexes, "", CI); |
| Value* VT = new LoadInst(VTPtr, "", CI); |
| CI->replaceAllUsesWith(VT); |
| CI->eraseFromParent(); |
| } else if (V == intrinsics->GetVTFromCommonClassFunction) { |
| Changed = true; |
| |
| Value* val = Call.getArgument(0); |
| Value* indexes[2] = { intrinsics->constantZero, |
| intrinsics->OffsetVTInClassConstant }; |
| Value* VTPtr = GetElementPtrInst::Create(val, indexes, "", CI); |
| Value* VT = new LoadInst(VTPtr, "", CI); |
| CI->replaceAllUsesWith(VT); |
| CI->eraseFromParent(); |
| } else if (V == intrinsics->GetVTFromClassArrayFunction) { |
| Changed = true; |
| |
| Value* val = Call.getArgument(0); |
| Value* indexes[3] = { intrinsics->constantZero, |
| intrinsics->constantZero, |
| intrinsics->OffsetVTInClassConstant }; |
| Value* VTPtr = GetElementPtrInst::Create(val, indexes, "", CI); |
| Value* VT = new LoadInst(VTPtr, "", CI); |
| CI->replaceAllUsesWith(VT); |
| CI->eraseFromParent(); |
| } else if (V == intrinsics->GetBaseClassVTFromVTFunction) { |
| Changed = true; |
| |
| Value* val = Call.getArgument(0); |
| Value* indexes[2] = { intrinsics->constantZero, |
| intrinsics->OffsetBaseClassVTInVTConstant }; |
| Value* VTPtr = GetElementPtrInst::Create(val, indexes, "", CI); |
| Value* VT = new LoadInst(VTPtr, "", CI); |
| VT = new BitCastInst(VT, intrinsics->VTType, "", CI); |
| CI->replaceAllUsesWith(VT); |
| CI->eraseFromParent(); |
| } else if (V == intrinsics->GetObjectSizeFromClassFunction) { |
| Changed = true; |
| |
| Value* val = Call.getArgument(0); |
| Value* indexes[2] = { intrinsics->constantZero, |
| intrinsics->OffsetObjectSizeInClassConstant }; |
| Value* SizePtr = GetElementPtrInst::Create(val, indexes, "", CI); |
| Value* Size = new LoadInst(SizePtr, "", CI); |
| CI->replaceAllUsesWith(Size); |
| CI->eraseFromParent(); |
| } else if (V == intrinsics->GetDepthFunction) { |
| Changed = true; |
| Value* val = Call.getArgument(0); |
| Value* indexes[2] = { intrinsics->constantZero, |
| intrinsics->OffsetDepthInVTConstant }; |
| Value* DepthPtr = GetElementPtrInst::Create(val, indexes, "", CI); |
| Value* Depth = new LoadInst(DepthPtr, "", CI); |
| Depth = new PtrToIntInst(Depth, Type::getInt32Ty(*Context), "", CI); |
| CI->replaceAllUsesWith(Depth); |
| CI->eraseFromParent(); |
| } else if (V == intrinsics->GetDisplayFunction) { |
| Changed = true; |
| Value* val = Call.getArgument(0); |
| Value* indexes[2] = { intrinsics->constantZero, |
| intrinsics->OffsetDisplayInVTConstant }; |
| Value* DisplayPtr = GetElementPtrInst::Create(val, indexes, "", CI); |
| Type* Ty = PointerType::getUnqual(intrinsics->VTType); |
| DisplayPtr = new BitCastInst(DisplayPtr, Ty, "", CI); |
| CI->replaceAllUsesWith(DisplayPtr); |
| CI->eraseFromParent(); |
| } else if (V == intrinsics->GetVTInDisplayFunction) { |
| Changed = true; |
| Value* val = Call.getArgument(0); |
| Value* depth = Call.getArgument(1); |
| Value* ClassPtr = GetElementPtrInst::Create(val, depth, "", CI); |
| Value* Class = new LoadInst(ClassPtr, "", CI); |
| CI->replaceAllUsesWith(Class); |
| CI->eraseFromParent(); |
| } else if (V == intrinsics->GetClassDelegateeFunction) { |
| Changed = true; |
| BasicBlock* NBB = II->getParent()->splitBasicBlock(II); |
| I->getParent()->getTerminator()->eraseFromParent(); |
| Value* Del = getDelegatee(intrinsics, Call.getArgument(0), CI); |
| Value* cmp = new ICmpInst(CI, ICmpInst::ICMP_EQ, Del, |
| intrinsics->JavaObjectNullConstant, ""); |
| |
| BasicBlock* NoDelegatee = BasicBlock::Create(*Context, "No delegatee", &F); |
| BasicBlock* DelegateeOK = BasicBlock::Create(*Context, "Delegatee OK", &F); |
| BranchInst::Create(NoDelegatee, DelegateeOK, cmp, CI); |
| PHINode* phi = PHINode::Create(intrinsics->JavaObjectType, 2, "", DelegateeOK); |
| phi->addIncoming(Del, CI->getParent()); |
| |
| Instruction* Res = CallInst::Create(intrinsics->RuntimeDelegateeFunction, |
| Call.getArgument(0), "", NoDelegatee); |
| Res->setDebugLoc(CI->getDebugLoc()); |
| BranchInst::Create(DelegateeOK, NoDelegatee); |
| phi->addIncoming(Res, NoDelegatee); |
| |
| CI->replaceAllUsesWith(phi); |
| CI->eraseFromParent(); |
| BranchInst::Create(NBB, DelegateeOK); |
| break; |
| |
| } else if (V == intrinsics->InitialisationCheckFunction) { |
| Changed = true; |
| |
| BasicBlock* NBB = 0; |
| if (CI->getParent()->getTerminator() != CI) { |
| NBB = II->getParent()->splitBasicBlock(II); |
| CI->getParent()->getTerminator()->eraseFromParent(); |
| } else { |
| InvokeInst* Invoke = dyn_cast<InvokeInst>(CI); |
| assert(Invoke && "Last instruction is not an invoke"); |
| NBB = Invoke->getNormalDest(); |
| } |
| |
| Value* Cl = Call.getArgument(0); |
| Value* TCM = getTCM(intrinsics, Call.getArgument(0), CI); |
| Value* GEP[2] = |
| { intrinsics->constantZero, |
| intrinsics->OffsetInitializedInTaskClassMirrorConstant }; |
| Value* StatusPtr = GetElementPtrInst::Create(TCM, GEP, "", CI); |
| |
| Value* test = new LoadInst(StatusPtr, "", CI); |
| |
| BasicBlock* trueCl = BasicBlock::Create(*Context, "Initialized", &F); |
| BasicBlock* falseCl = BasicBlock::Create(*Context, "Uninitialized", &F); |
| PHINode* node = llvm::PHINode::Create(intrinsics->JavaClassType, 2, "", trueCl); |
| node->addIncoming(Cl, CI->getParent()); |
| BranchInst::Create(trueCl, falseCl, test, CI); |
| |
| |
| Instruction* res = 0; |
| if (InvokeInst* Invoke = dyn_cast<InvokeInst>(CI)) { |
| Value* Args[1] = { Cl }; |
| BasicBlock* UI = Invoke->getUnwindDest(); |
| |
| res = InvokeInst::Create(intrinsics->InitialiseClassFunction, |
| trueCl, UI, Args, "", falseCl); |
| |
| // For some reason, an LLVM pass may add PHI nodes to the |
| // exception destination. |
| BasicBlock::iterator Temp = UI->getInstList().begin(); |
| while (PHINode* PHI = dyn_cast<PHINode>(Temp)) { |
| Value* Val = PHI->getIncomingValueForBlock(CI->getParent()); |
| PHI->removeIncomingValue(CI->getParent(), false); |
| PHI->addIncoming(Val, falseCl); |
| Temp++; |
| } |
| |
| // And here we set the phi nodes of the normal dest of the Invoke |
| // instruction. The phi nodes have now the trueCl as basic block. |
| Temp = NBB->getInstList().begin(); |
| while (PHINode* PHI = dyn_cast<PHINode>(Temp)) { |
| Value* Val = PHI->getIncomingValueForBlock(CI->getParent()); |
| PHI->removeIncomingValue(CI->getParent(), false); |
| PHI->addIncoming(Val, trueCl); |
| Temp++; |
| } |
| |
| } else { |
| res = CallInst::Create(intrinsics->InitialiseClassFunction, |
| Cl, "", falseCl); |
| BranchInst::Create(trueCl, falseCl); |
| } |
| res->setDebugLoc(CI->getDebugLoc()); |
| |
| node->addIncoming(res, falseCl); |
| |
| |
| CI->replaceAllUsesWith(node); |
| CI->eraseFromParent(); |
| BranchInst::Create(NBB, trueCl); |
| break; |
| } else if (V == intrinsics->GetConstantPoolAtFunction) { |
| Function* resolver = dyn_cast<Function>(Call.getArgument(0)); |
| assert(resolver && "Wrong use of GetConstantPoolAt"); |
| Type* returnType = resolver->getReturnType(); |
| Value* CTP = Call.getArgument(1); |
| Value* Index = Call.getArgument(3); |
| Changed = true; |
| BasicBlock* NBB = 0; |
| if (CI->getParent()->getTerminator() != CI) { |
| NBB = II->getParent()->splitBasicBlock(II); |
| CI->getParent()->getTerminator()->eraseFromParent(); |
| } else { |
| InvokeInst* Invoke = dyn_cast<InvokeInst>(CI); |
| assert(Invoke && "Last instruction is not an invoke"); |
| NBB = Invoke->getNormalDest(); |
| } |
| |
| Value* indexes = Index; |
| Value* arg1 = GetElementPtrInst::Create(CTP, indexes, "", CI); |
| arg1 = new LoadInst(arg1, "", false, CI); |
| Value* test = new ICmpInst(CI, ICmpInst::ICMP_EQ, arg1, |
| intrinsics->constantPtrNull, ""); |
| |
| BasicBlock* trueCl = BasicBlock::Create(*Context, "Ctp OK", &F); |
| BasicBlock* falseCl = BasicBlock::Create(*Context, "Ctp Not OK", &F); |
| PHINode* node = llvm::PHINode::Create(returnType, 2, "", trueCl); |
| node->addIncoming(arg1, CI->getParent()); |
| BranchInst::Create(falseCl, trueCl, test, CI); |
| |
| std::vector<Value*> Args; |
| unsigned ArgSize = Call.arg_size(), i = 1; |
| while (++i < ArgSize) { |
| Args.push_back(Call.getArgument(i)); |
| } |
| |
| Instruction* res = 0; |
| if (InvokeInst* Invoke = dyn_cast<InvokeInst>(CI)) { |
| BasicBlock* UI = Invoke->getUnwindDest(); |
| res = InvokeInst::Create(resolver, trueCl, UI, Args, "", falseCl); |
| |
| // For some reason, an LLVM pass may add PHI nodes to the |
| // exception destination. |
| BasicBlock::iterator Temp = UI->getInstList().begin(); |
| while (PHINode* PHI = dyn_cast<PHINode>(Temp)) { |
| Value* Val = PHI->getIncomingValueForBlock(CI->getParent()); |
| PHI->removeIncomingValue(CI->getParent(), false); |
| PHI->addIncoming(Val, falseCl); |
| Temp++; |
| } |
| |
| // And here we set the phi nodes of the normal dest of the Invoke |
| // instruction. The phi nodes have now the trueCl as basic block. |
| Temp = NBB->getInstList().begin(); |
| while (PHINode* PHI = dyn_cast<PHINode>(Temp)) { |
| Value* Val = PHI->getIncomingValueForBlock(CI->getParent()); |
| PHI->removeIncomingValue(CI->getParent(), false); |
| PHI->addIncoming(Val, trueCl); |
| Temp++; |
| } |
| |
| } else { |
| res = CallInst::Create(resolver, Args, "", falseCl); |
| BranchInst::Create(trueCl, falseCl); |
| } |
| |
| res->setDebugLoc(CI->getDebugLoc()); |
| node->addIncoming(res, falseCl); |
| |
| CI->replaceAllUsesWith(node); |
| CI->eraseFromParent(); |
| BranchInst::Create(NBB, trueCl); |
| break; |
| } else if (V == intrinsics->GetArrayClassFunction) { |
| Type* Ty = PointerType::getUnqual(intrinsics->VTType); |
| Constant* nullValue = Constant::getNullValue(Ty); |
| // Check if we have already proceed this call. |
| if (Call.getArgument(2) == nullValue) { |
| BasicBlock* NBB = II->getParent()->splitBasicBlock(II); |
| I->getParent()->getTerminator()->eraseFromParent(); |
| |
| Constant* init = Constant::getNullValue(intrinsics->VTType); |
| GlobalVariable* GV = |
| new GlobalVariable(*(F.getParent()), intrinsics->VTType, |
| false, GlobalValue::ExternalLinkage, |
| init, ""); |
| |
| Value* LoadedGV = new LoadInst(GV, "", CI); |
| Value* cmp = new ICmpInst(CI, ICmpInst::ICMP_EQ, LoadedGV, init, |
| ""); |
| |
| BasicBlock* OKBlock = BasicBlock::Create(*Context, "", &F); |
| BasicBlock* NotOKBlock = BasicBlock::Create(*Context, "", &F); |
| PHINode* node = PHINode::Create(intrinsics->VTType, 2, "", |
| OKBlock); |
| node->addIncoming(LoadedGV, CI->getParent()); |
| |
| BranchInst::Create(NotOKBlock, OKBlock, cmp, CI); |
| |
| Value* args[3] = { Call.getArgument(0), Call.getArgument(1), GV }; |
| Instruction* res = CallInst::Create(intrinsics->GetArrayClassFunction, args, |
| "", NotOKBlock); |
| res->setDebugLoc(CI->getDebugLoc()); |
| BranchInst::Create(OKBlock, NotOKBlock); |
| node->addIncoming(res, NotOKBlock); |
| |
| CI->replaceAllUsesWith(node); |
| CI->eraseFromParent(); |
| BranchInst::Create(NBB, OKBlock); |
| Changed = true; |
| break; |
| } |
| } else if (V == intrinsics->ForceInitialisationCheckFunction || |
| V == intrinsics->ForceLoadedCheckFunction ) { |
| Changed = true; |
| CI->eraseFromParent(); |
| } else if (V == intrinsics->GetFinalInt8FieldFunction || |
| V == intrinsics->GetFinalInt16FieldFunction || |
| V == intrinsics->GetFinalInt32FieldFunction || |
| V == intrinsics->GetFinalLongFieldFunction || |
| V == intrinsics->GetFinalFloatFieldFunction || |
| V == intrinsics->GetFinalDoubleFieldFunction) { |
| Changed = true; |
| Value* val = Call.getArgument(0); |
| Value* res = new LoadInst(val, "", CI); |
| CI->replaceAllUsesWith(res); |
| CI->eraseFromParent(); |
| } else if (V == intrinsics->IsSubclassOfFunction) { |
| Changed = true; |
| Value* VT1 = Call.getArgument(0); |
| Value* VT2 = Call.getArgument(1); |
| |
| BasicBlock* EndBlock = II->getParent()->splitBasicBlock(II); |
| I->getParent()->getTerminator()->eraseFromParent(); |
| |
| BasicBlock* CurEndBlock = BasicBlock::Create(*Context, "", &F); |
| BasicBlock* FailedBlock = BasicBlock::Create(*Context, "", &F); |
| PHINode* node = PHINode::Create(Type::getInt1Ty(*Context), 2, "", CurEndBlock); |
| |
| ConstantInt* CC = ConstantInt::get(Type::getInt32Ty(*Context), |
| JavaVirtualTable::getOffsetIndex()); |
| Value* indices[2] = { intrinsics->constantZero, CC }; |
| Value* Offset = GetElementPtrInst::Create(VT2, indices, "", CI); |
| Offset = new LoadInst(Offset, "", false, CI); |
| Offset = new PtrToIntInst(Offset, Type::getInt32Ty(*Context), "", CI); |
| indices[1] = Offset; |
| Value* CurVT = GetElementPtrInst::Create(VT1, indices, "", CI); |
| CurVT = new LoadInst(CurVT, "", false, CI); |
| CurVT = new BitCastInst(CurVT, intrinsics->VTType, "", CI); |
| |
| Instruction* res = |
| new ICmpInst(CI, ICmpInst::ICMP_EQ, CurVT, VT2, ""); |
| |
| node->addIncoming(ConstantInt::getTrue(*Context), CI->getParent()); |
| BranchInst::Create(CurEndBlock, FailedBlock, res, CI); |
| |
| Value* Args[2] = { VT1, VT2 }; |
| res = CallInst::Create(intrinsics->IsSecondaryClassFunction, Args, |
| "", FailedBlock); |
| res->setDebugLoc(CI->getDebugLoc()); |
| |
| node->addIncoming(res, FailedBlock); |
| BranchInst::Create(CurEndBlock, FailedBlock); |
| |
| // Branch to the next block. |
| BranchInst::Create(EndBlock, CurEndBlock); |
| |
| // We can now replace the previous instruction. |
| CI->replaceAllUsesWith(node); |
| CI->eraseFromParent(); |
| |
| // Reanalyse the current block. |
| break; |
| |
| } else if (V == intrinsics->IsSecondaryClassFunction) { |
| Changed = true; |
| Value* VT1 = Call.getArgument(0); |
| Value* VT2 = Call.getArgument(1); |
| |
| BasicBlock* EndBlock = II->getParent()->splitBasicBlock(II); |
| I->getParent()->getTerminator()->eraseFromParent(); |
| |
| |
| BasicBlock* Preheader = BasicBlock::Create(*Context, "preheader", &F); |
| BasicBlock* BB4 = BasicBlock::Create(*Context, "BB4", &F); |
| BasicBlock* BB5 = BasicBlock::Create(*Context, "BB5", &F); |
| BasicBlock* BB6 = BasicBlock::Create(*Context, "BB6", &F); |
| BasicBlock* BB7 = BasicBlock::Create(*Context, "BB7", &F); |
| BasicBlock* BB9 = BasicBlock::Create(*Context, "BB9", &F); |
| Type* Ty = PointerType::getUnqual(intrinsics->VTType); |
| |
| PHINode* resFwd = PHINode::Create(Type::getInt32Ty(*Context), 2, "", BB7); |
| |
| // This corresponds to: |
| // if (VT1.cache == VT2 || VT1 == VT2) goto end with true; |
| // else goto headerLoop; |
| ConstantInt* cacheIndex = |
| ConstantInt::get(Type::getInt32Ty(*Context), JavaVirtualTable::getCacheIndex()); |
| Value* indices[2] = { intrinsics->constantZero, cacheIndex }; |
| Instruction* CachePtr = GetElementPtrInst::Create(VT1, indices, "", CI); |
| CachePtr = new BitCastInst(CachePtr, Ty, "", CI); |
| Value* Cache = new LoadInst(CachePtr, "", false, CI); |
| ICmpInst* cmp1 = new ICmpInst(CI, ICmpInst::ICMP_EQ, Cache, VT2, ""); |
| ICmpInst* cmp2 = new ICmpInst(CI, ICmpInst::ICMP_EQ, VT1, VT2, ""); |
| BinaryOperator* Or = BinaryOperator::Create(Instruction::Or, cmp1, |
| cmp2, "", CI); |
| BranchInst::Create(BB9, Preheader, Or, CI); |
| |
| // First test failed. Go into the loop. The Preheader looks like this: |
| // headerLoop: |
| // types = VT1->secondaryTypes; |
| // size = VT1->nbSecondaryTypes; |
| // i = 0; |
| // goto test; |
| ConstantInt* sizeIndex = ConstantInt::get(Type::getInt32Ty(*Context), |
| JavaVirtualTable::getNumSecondaryTypesIndex()); |
| indices[1] = sizeIndex; |
| Instruction* Size = GetElementPtrInst::Create(VT1, indices, "", Preheader); |
| Size = new LoadInst(Size, "", false, Preheader); |
| Size = new PtrToIntInst(Size, Type::getInt32Ty(*Context), "", Preheader); |
| |
| ConstantInt* secondaryTypesIndex = ConstantInt::get(Type::getInt32Ty(*Context), |
| JavaVirtualTable::getSecondaryTypesIndex()); |
| indices[1] = secondaryTypesIndex; |
| Instruction* secondaryTypes = |
| GetElementPtrInst::Create(VT1, indices, "", Preheader); |
| secondaryTypes = new LoadInst(secondaryTypes, "", false, Preheader); |
| secondaryTypes = new BitCastInst(secondaryTypes, Ty, "", Preheader); |
| BranchInst::Create(BB7, Preheader); |
| |
| // Here is the test if the current secondary type is VT2. |
| // test: |
| // CurVT = types[i]; |
| // if (CurVT == VT2) goto update cache; |
| // est goto inc; |
| Instruction* CurVT = GetElementPtrInst::Create(secondaryTypes, resFwd, |
| "", BB4); |
| CurVT = new LoadInst(CurVT, "", false, BB4); |
| cmp1 = new ICmpInst(*BB4, ICmpInst::ICMP_EQ, CurVT, VT2, ""); |
| BranchInst::Create(BB5, BB6, cmp1, BB4); |
| |
| // Increment i if the previous test failed |
| // inc: |
| // ++i; |
| // goto endLoopTest; |
| BinaryOperator* IndVar = |
| BinaryOperator::CreateAdd(resFwd, intrinsics->constantOne, "", BB6); |
| BranchInst::Create(BB7, BB6); |
| |
| // Verify that we haven't reached the end of the loop: |
| // endLoopTest: |
| // if (i < size) goto test |
| // else goto end with false |
| resFwd->addIncoming(intrinsics->constantZero, Preheader); |
| resFwd->addIncoming(IndVar, BB6); |
| |
| cmp1 = new ICmpInst(*BB7, ICmpInst::ICMP_SGT, Size, resFwd, ""); |
| BranchInst::Create(BB4, BB9, cmp1, BB7); |
| |
| // Update the cache if the result is found. |
| // updateCache: |
| // VT1->cache = result |
| // goto end with true |
| new StoreInst(VT2, CachePtr, false, BB5); |
| BranchInst::Create(BB9, BB5); |
| |
| // Final block, that gets the result. |
| PHINode* node = PHINode::Create(Type::getInt1Ty(*Context), 3, "", BB9); |
| node->addIncoming(ConstantInt::getTrue(*Context), CI->getParent()); |
| node->addIncoming(ConstantInt::getFalse(*Context), BB7); |
| node->addIncoming(ConstantInt::getTrue(*Context), BB5); |
| |
| // Don't forget to jump to the next block. |
| BranchInst::Create(EndBlock, BB9); |
| |
| // We can now replace the previous instruction |
| CI->replaceAllUsesWith(node); |
| CI->eraseFromParent(); |
| |
| // And reanalyse the current block. |
| break; |
| } |
| } |
| } |
| } |
| return Changed; |
| } |
| |
| |
| FunctionPass* createLowerConstantCallsPass(JavaLLVMCompiler* Compiler) { |
| return new LowerConstantCalls(Compiler); |
| } |
| |
| } |