diff options
| -rw-r--r-- | src/compiler/CompilerIR.h | 3 | ||||
| -rw-r--r-- | src/compiler/Dataflow.cc | 64 | ||||
| -rw-r--r-- | src/compiler/Dataflow.h | 2 | ||||
| -rw-r--r-- | src/compiler/Frontend.cc | 6 | ||||
| -rw-r--r-- | src/compiler/codegen/MethodBitcode.cc | 920 |
5 files changed, 537 insertions, 458 deletions
diff --git a/src/compiler/CompilerIR.h b/src/compiler/CompilerIR.h index 1cbf2b5f19..87dbd096c0 100644 --- a/src/compiler/CompilerIR.h +++ b/src/compiler/CompilerIR.h @@ -280,6 +280,8 @@ struct BasicBlock { bool visited; bool hidden; bool catchEntry; + bool explicitThrow; + bool conditionalBranch; #if defined(ART_USE_QUICK_COMPILER) bool hasReturn; #endif @@ -611,6 +613,7 @@ struct CompilationUnit { bool requireShadowFrame; int numShadowFrameEntries; int* shadowMap; + std::set<llvm::BasicBlock*> llvmBlocks; #endif #ifndef NDEBUG /* diff --git a/src/compiler/Dataflow.cc b/src/compiler/Dataflow.cc index a5cdbdeaaa..6fe0659eb6 100644 --- a/src/compiler/Dataflow.cc +++ b/src/compiler/Dataflow.cc @@ -1970,6 +1970,54 @@ bool countChecks( struct CompilationUnit* cUnit, struct BasicBlock* bb) return false; } +/* Try to make common case the fallthrough path */ +bool layoutBlocks(struct CompilationUnit* cUnit, struct BasicBlock* bb) +{ + // TODO: For now, just looking for direct throws. Consider generalizing for profile feedback + if (!bb->explicitThrow) { + return false; + } + BasicBlock* walker = bb; + while (true) { + // Check termination conditions + if ((walker->blockType == kEntryBlock) || (walker->predecessors->numUsed != 1)) { + break; + } + BasicBlock* prev = GET_ELEM_N(walker->predecessors, BasicBlock*, 0); + if (prev->conditionalBranch) { + if (prev->fallThrough == walker) { + // Already done - return + break; + } + DCHECK_EQ(walker, prev->taken); + // Got one. Flip it and exit + Instruction::Code opcode = prev->lastMIRInsn->dalvikInsn.opcode; + switch (opcode) { + case Instruction::IF_EQ: opcode = Instruction::IF_NE; break; + case Instruction::IF_NE: opcode = Instruction::IF_EQ; break; + case Instruction::IF_LT: opcode = Instruction::IF_GE; break; + case Instruction::IF_GE: opcode = Instruction::IF_LT; break; + case Instruction::IF_GT: opcode = Instruction::IF_LE; break; + case Instruction::IF_LE: opcode = Instruction::IF_GT; break; + case Instruction::IF_EQZ: opcode = Instruction::IF_NEZ; break; + case Instruction::IF_NEZ: opcode = Instruction::IF_EQZ; break; + case Instruction::IF_LTZ: opcode = Instruction::IF_GEZ; break; + case Instruction::IF_GEZ: opcode = Instruction::IF_LTZ; break; + case Instruction::IF_GTZ: opcode = Instruction::IF_LEZ; break; + case Instruction::IF_LEZ: opcode = Instruction::IF_GTZ; break; + default: LOG(FATAL) << "Unexpected opcode 0x" << std::hex << (int)opcode; + } + prev->lastMIRInsn->dalvikInsn.opcode = opcode; + BasicBlock* tBB = prev->taken; + prev->taken = prev->fallThrough; + prev->fallThrough = tBB; + break; + } + walker = prev; + } + return false; +} + /* Combine any basic blocks terminated by instructions that we now know can't throw */ bool combineBlocks(struct CompilationUnit* cUnit, struct BasicBlock* bb) { @@ -1992,9 +2040,14 @@ bool combineBlocks(struct CompilationUnit* cUnit, struct BasicBlock* bb) // Grab the attributes from the paired opcode MIR* throwInsn = mir->meta.throwInsn; int dfAttributes = oatDataFlowAttributes[throwInsn->dalvikInsn.opcode]; - // Only null checks, and null checks eliminated? - if (((dfAttributes & DF_HAS_NULL_CHKS) == 0) || ((dfAttributes & DF_HAS_RANGE_CHKS) != 0) - || !(throwInsn->optimizationFlags & MIR_IGNORE_NULL_CHECK)) { + bool canCombine = true; + if (dfAttributes & DF_HAS_NULL_CHKS) { + canCombine &= ((throwInsn->optimizationFlags & MIR_IGNORE_NULL_CHECK) != 0); + } + if (dfAttributes & DF_HAS_RANGE_CHKS) { + canCombine &= ((throwInsn->optimizationFlags & MIR_IGNORE_RANGE_CHECK) != 0); + } + if (!canCombine) { break; } // OK - got one. Combine @@ -2180,6 +2233,11 @@ void oatMethodBasicBlockCombine(CompilationUnit* cUnit) oatDataFlowAnalysisDispatcher(cUnit, combineBlocks, kPreOrderDFSTraversal, false); } +void oatMethodCodeLayout(CompilationUnit* cUnit) +{ + oatDataFlowAnalysisDispatcher(cUnit, layoutBlocks, kAllNodes, false); +} + void oatDumpCheckStats(CompilationUnit *cUnit) { Checkstats* stats = (Checkstats*)oatNew(cUnit, sizeof(Checkstats), true, kAllocDFInfo); diff --git a/src/compiler/Dataflow.h b/src/compiler/Dataflow.h index e2d5a4c50a..8e99e4dffe 100644 --- a/src/compiler/Dataflow.h +++ b/src/compiler/Dataflow.h @@ -168,6 +168,8 @@ void oatDumpCheckStats(CompilationUnit*); void oatMethodBasicBlockCombine(CompilationUnit*); +void oatMethodCodeLayout(CompilationUnit*); + void oatMethodBasicBlockOptimization(CompilationUnit*); } // namespace art diff --git a/src/compiler/Frontend.cc b/src/compiler/Frontend.cc index 4aa0ac89e9..50630aea06 100644 --- a/src/compiler/Frontend.cc +++ b/src/compiler/Frontend.cc @@ -519,6 +519,7 @@ BasicBlock* processCanBranch(CompilationUnit* cUnit, BasicBlock* curBlock, case Instruction::IF_GE: case Instruction::IF_GT: case Instruction::IF_LE: + curBlock->conditionalBranch = true; target += (int) insn->dalvikInsn.vC; break; case Instruction::IF_EQZ: @@ -527,6 +528,7 @@ BasicBlock* processCanBranch(CompilationUnit* cUnit, BasicBlock* curBlock, case Instruction::IF_GEZ: case Instruction::IF_GTZ: case Instruction::IF_LEZ: + curBlock->conditionalBranch = true; target += (int) insn->dalvikInsn.vB; break; default: @@ -720,6 +722,7 @@ BasicBlock* processCanThrow(CompilationUnit* cUnit, BasicBlock* curBlock, } if (insn->dalvikInsn.opcode == Instruction::THROW){ + curBlock->explicitThrow = true; if ((codePtr < codeEnd) && contentIsInsn(codePtr)) { // Force creation of new block following THROW via side-effect findBlock(cUnit, curOffset + width, /* split */ false, @@ -1074,6 +1077,9 @@ CompiledMethod* oatCompileMethod(Compiler& compiler, oatDumpCompilationUnit(cUnit.get()); } + /* Do a code layout pass */ + oatMethodCodeLayout(cUnit.get()); + if (cUnit->enableDebug & (1 << kDebugVerifyDataflow)) { /* Verify if all blocks are connected as claimed */ oatDataFlowAnalysisDispatcher(cUnit.get(), verifyPredInfo, kAllNodes, diff --git a/src/compiler/codegen/MethodBitcode.cc b/src/compiler/codegen/MethodBitcode.cc index c4e1b9ddf3..25aae113a8 100644 --- a/src/compiler/codegen/MethodBitcode.cc +++ b/src/compiler/codegen/MethodBitcode.cc @@ -160,10 +160,10 @@ void createLocFromValue(CompilationUnit* cUnit, llvm::Value* val) if (cUnit->printMe && loc.home) { if (loc.wide) { - LOG(INFO) << "Promoted wide " << s << " to regs " << loc.lowReg + LOG(INFO) << "Promoted wide " << s << " to regs " << static_cast<int>(loc.lowReg) << "/" << loc.highReg; } else { - LOG(INFO) << "Promoted " << s << " to reg " << loc.lowReg; + LOG(INFO) << "Promoted " << s << " to reg " << static_cast<int>(loc.lowReg); } } cUnit->locMap.Put(val, loc); @@ -2856,475 +2856,485 @@ RegLocation valToLoc(CompilationUnit* cUnit, llvm::Value* val) bool methodBitcodeBlockCodeGen(CompilationUnit* cUnit, llvm::BasicBlock* bb) { - bool isEntry = (bb == &cUnit->func->getEntryBlock()); - // Define the starting label - LIR* blockLabel = cUnit->blockToLabelMap.Get(bb); - // Extract the type and starting offset from the block's name - char blockType = kNormalBlock; - if (!isEntry) { - const char* blockName = bb->getName().str().c_str(); - int dummy; - sscanf(blockName, kLabelFormat, &blockType, &blockLabel->operands[0], &dummy); - cUnit->currentDalvikOffset = blockLabel->operands[0]; - } else { - cUnit->currentDalvikOffset = 0; - } - // Set the label kind - blockLabel->opcode = kPseudoNormalBlockLabel; - // Insert the label - oatAppendLIR(cUnit, blockLabel); - - LIR* headLIR = NULL; - - if (blockType == kCatchBlock) { - headLIR = newLIR0(cUnit, kPseudoSafepointPC); - } - - // Free temp registers and reset redundant store tracking */ - oatResetRegPool(cUnit); - oatResetDefTracking(cUnit); + while (cUnit->llvmBlocks.find(bb) == cUnit->llvmBlocks.end()) { + llvm::BasicBlock* nextBB = NULL; + cUnit->llvmBlocks.insert(bb); + bool isEntry = (bb == &cUnit->func->getEntryBlock()); + // Define the starting label + LIR* blockLabel = cUnit->blockToLabelMap.Get(bb); + // Extract the type and starting offset from the block's name + char blockType = kNormalBlock; + if (!isEntry) { + const char* blockName = bb->getName().str().c_str(); + int dummy; + sscanf(blockName, kLabelFormat, &blockType, &blockLabel->operands[0], &dummy); + cUnit->currentDalvikOffset = blockLabel->operands[0]; + } else { + cUnit->currentDalvikOffset = 0; + } + // Set the label kind + blockLabel->opcode = kPseudoNormalBlockLabel; + // Insert the label + oatAppendLIR(cUnit, blockLabel); - //TODO: restore oat incoming liveness optimization - oatClobberAllRegs(cUnit); + LIR* headLIR = NULL; - if (isEntry) { - RegLocation* argLocs = (RegLocation*) - oatNew(cUnit, sizeof(RegLocation) * cUnit->numIns, true, kAllocMisc); - llvm::Function::arg_iterator it(cUnit->func->arg_begin()); - llvm::Function::arg_iterator it_end(cUnit->func->arg_end()); - // Skip past Method* - it++; - for (unsigned i = 0; it != it_end; ++it) { - llvm::Value* val = it; - argLocs[i++] = valToLoc(cUnit, val); - llvm::Type* ty = val->getType(); - if ((ty == cUnit->irb->getInt64Ty()) || (ty == cUnit->irb->getDoubleTy())) { - argLocs[i] = argLocs[i-1]; - argLocs[i].lowReg = argLocs[i].highReg; - argLocs[i].origSReg++; - argLocs[i].sRegLow = INVALID_SREG; - argLocs[i].highWord = true; - i++; - } - } - genEntrySequence(cUnit, argLocs, cUnit->methodLoc); - } - - // Visit all of the instructions in the block - for (llvm::BasicBlock::iterator it = bb->begin(), e = bb->end(); it != e;) { - llvm::Instruction* inst = it; - llvm::BasicBlock::iterator nextIt = ++it; - // Extract the Dalvik offset from the instruction - uint32_t opcode = inst->getOpcode(); - llvm::MDNode* dexOffsetNode = inst->getMetadata("DexOff"); - if (dexOffsetNode != NULL) { - llvm::ConstantInt* dexOffsetValue = - static_cast<llvm::ConstantInt*>(dexOffsetNode->getOperand(0)); - cUnit->currentDalvikOffset = dexOffsetValue->getZExtValue(); + if (blockType == kCatchBlock) { + headLIR = newLIR0(cUnit, kPseudoSafepointPC); } + // Free temp registers and reset redundant store tracking */ oatResetRegPool(cUnit); - if (cUnit->disableOpt & (1 << kTrackLiveTemps)) { - oatClobberAllRegs(cUnit); - } - - if (cUnit->disableOpt & (1 << kSuppressLoads)) { - oatResetDefTracking(cUnit); + oatResetDefTracking(cUnit); + + //TODO: restore oat incoming liveness optimization + oatClobberAllRegs(cUnit); + + if (isEntry) { + RegLocation* argLocs = (RegLocation*) + oatNew(cUnit, sizeof(RegLocation) * cUnit->numIns, true, kAllocMisc); + llvm::Function::arg_iterator it(cUnit->func->arg_begin()); + llvm::Function::arg_iterator it_end(cUnit->func->arg_end()); + // Skip past Method* + it++; + for (unsigned i = 0; it != it_end; ++it) { + llvm::Value* val = it; + argLocs[i++] = valToLoc(cUnit, val); + llvm::Type* ty = val->getType(); + if ((ty == cUnit->irb->getInt64Ty()) || (ty == cUnit->irb->getDoubleTy())) { + argLocs[i] = argLocs[i-1]; + argLocs[i].lowReg = argLocs[i].highReg; + argLocs[i].origSReg++; + argLocs[i].sRegLow = INVALID_SREG; + argLocs[i].highWord = true; + i++; + } + } + genEntrySequence(cUnit, argLocs, cUnit->methodLoc); } -#ifndef NDEBUG - /* Reset temp tracking sanity check */ - cUnit->liveSReg = INVALID_SREG; -#endif + // Visit all of the instructions in the block + for (llvm::BasicBlock::iterator it = bb->begin(), e = bb->end(); it != e;) { + llvm::Instruction* inst = it; + llvm::BasicBlock::iterator nextIt = ++it; + // Extract the Dalvik offset from the instruction + uint32_t opcode = inst->getOpcode(); + llvm::MDNode* dexOffsetNode = inst->getMetadata("DexOff"); + if (dexOffsetNode != NULL) { + llvm::ConstantInt* dexOffsetValue = + static_cast<llvm::ConstantInt*>(dexOffsetNode->getOperand(0)); + cUnit->currentDalvikOffset = dexOffsetValue->getZExtValue(); + } - // TODO: use llvm opcode name here instead of "boundary" if verbose - LIR* boundaryLIR = markBoundary(cUnit, cUnit->currentDalvikOffset, "boundary"); + oatResetRegPool(cUnit); + if (cUnit->disableOpt & (1 << kTrackLiveTemps)) { + oatClobberAllRegs(cUnit); + } - /* Remember the first LIR for thisl block*/ - if (headLIR == NULL) { - headLIR = boundaryLIR; - headLIR->defMask = ENCODE_ALL; - } + if (cUnit->disableOpt & (1 << kSuppressLoads)) { + oatResetDefTracking(cUnit); + } - switch(opcode) { + #ifndef NDEBUG + /* Reset temp tracking sanity check */ + cUnit->liveSReg = INVALID_SREG; + #endif - case llvm::Instruction::ICmp: { - llvm::Instruction* nextInst = nextIt; - llvm::BranchInst* brInst = llvm::dyn_cast<llvm::BranchInst>(nextInst); - if (brInst != NULL /* and... */) { - cvtICmpBr(cUnit, inst, brInst); - ++it; - } else { - cvtICmp(cUnit, inst); - } - } - break; + // TODO: use llvm opcode name here instead of "boundary" if verbose + LIR* boundaryLIR = markBoundary(cUnit, cUnit->currentDalvikOffset, "boundary"); - case llvm::Instruction::Call: { - llvm::CallInst* callInst = llvm::dyn_cast<llvm::CallInst>(inst); - llvm::Function* callee = callInst->getCalledFunction(); - greenland::IntrinsicHelper::IntrinsicId id = - cUnit->intrinsic_helper->GetIntrinsicId(callee); - switch (id) { - case greenland::IntrinsicHelper::AllocaShadowFrame: - case greenland::IntrinsicHelper::SetShadowFrameEntry: - case greenland::IntrinsicHelper::PopShadowFrame: - // Ignore shadow frame stuff for quick compiler - break; - case greenland::IntrinsicHelper::CopyInt: - case greenland::IntrinsicHelper::CopyObj: - case greenland::IntrinsicHelper::CopyFloat: - case greenland::IntrinsicHelper::CopyLong: - case greenland::IntrinsicHelper::CopyDouble: - cvtCopy(cUnit, callInst); - break; - case greenland::IntrinsicHelper::ConstInt: - case greenland::IntrinsicHelper::ConstObj: - case greenland::IntrinsicHelper::ConstLong: - case greenland::IntrinsicHelper::ConstFloat: - case greenland::IntrinsicHelper::ConstDouble: - cvtConst(cUnit, callInst); - break; - case greenland::IntrinsicHelper::DivInt: - case greenland::IntrinsicHelper::DivLong: - cvtBinOp(cUnit, kOpDiv, inst); - break; - case greenland::IntrinsicHelper::RemInt: - case greenland::IntrinsicHelper::RemLong: - cvtBinOp(cUnit, kOpRem, inst); - break; - case greenland::IntrinsicHelper::MethodInfo: - // Already dealt with - just ignore it here. - break; - case greenland::IntrinsicHelper::CheckSuspend: - genSuspendTest(cUnit, 0 /* optFlags already applied */); - break; - case greenland::IntrinsicHelper::HLInvokeObj: - case greenland::IntrinsicHelper::HLInvokeFloat: - case greenland::IntrinsicHelper::HLInvokeDouble: - case greenland::IntrinsicHelper::HLInvokeLong: - case greenland::IntrinsicHelper::HLInvokeInt: - cvtInvoke(cUnit, callInst, false /* isVoid */, false /* newArray */); - break; - case greenland::IntrinsicHelper::HLInvokeVoid: - cvtInvoke(cUnit, callInst, true /* isVoid */, false /* newArray */); - break; - case greenland::IntrinsicHelper::FilledNewArray: - cvtInvoke(cUnit, callInst, false /* isVoid */, true /* newArray */); - break; - case greenland::IntrinsicHelper::FillArrayData: - cvtFillArrayData(cUnit, callInst); - break; - case greenland::IntrinsicHelper::ConstString: - cvtConstObject(cUnit, callInst, true /* isString */); - break; - case greenland::IntrinsicHelper::ConstClass: - cvtConstObject(cUnit, callInst, false /* isString */); - break; - case greenland::IntrinsicHelper::CheckCast: - cvtCheckCast(cUnit, callInst); - break; - case greenland::IntrinsicHelper::NewInstance: - cvtNewInstance(cUnit, callInst); - break; - case greenland::IntrinsicHelper::HLSgetObject: - cvtSget(cUnit, callInst, false /* wide */, true /* Object */); - break; - case greenland::IntrinsicHelper::HLSget: - case greenland::IntrinsicHelper::HLSgetFloat: - case greenland::IntrinsicHelper::HLSgetBoolean: - case greenland::IntrinsicHelper::HLSgetByte: - case greenland::IntrinsicHelper::HLSgetChar: - case greenland::IntrinsicHelper::HLSgetShort: - cvtSget(cUnit, callInst, false /* wide */, false /* Object */); - break; - case greenland::IntrinsicHelper::HLSgetWide: - case greenland::IntrinsicHelper::HLSgetDouble: - cvtSget(cUnit, callInst, true /* wide */, false /* Object */); - break; - case greenland::IntrinsicHelper::HLSput: - case greenland::IntrinsicHelper::HLSputFloat: - case greenland::IntrinsicHelper::HLSputBoolean: - case greenland::IntrinsicHelper::HLSputByte: - case greenland::IntrinsicHelper::HLSputChar: - case greenland::IntrinsicHelper::HLSputShort: - cvtSput(cUnit, callInst, false /* wide */, false /* Object */); - break; - case greenland::IntrinsicHelper::HLSputWide: - case greenland::IntrinsicHelper::HLSputDouble: - cvtSput(cUnit, callInst, true /* wide */, false /* Object */); - break; - case greenland::IntrinsicHelper::HLSputObject: - cvtSput(cUnit, callInst, false /* wide */, true /* Object */); - break; - case greenland::IntrinsicHelper::GetException: - cvtMoveException(cUnit, callInst); - break; - case greenland::IntrinsicHelper::Throw: - cvtThrow(cUnit, callInst); - break; - case greenland::IntrinsicHelper::MonitorEnter: - cvtMonitorEnterExit(cUnit, true /* isEnter */, callInst); - break; - case greenland::IntrinsicHelper::MonitorExit: - cvtMonitorEnterExit(cUnit, false /* isEnter */, callInst); - break; - case greenland::IntrinsicHelper::ArrayLength: - cvtArrayLength(cUnit, callInst); - break; - case greenland::IntrinsicHelper::NewArray: - cvtNewArray(cUnit, callInst); - break; - case greenland::IntrinsicHelper::InstanceOf: - cvtInstanceOf(cUnit, callInst); - break; - - case greenland::IntrinsicHelper::HLArrayGet: - case greenland::IntrinsicHelper::HLArrayGetObject: - case greenland::IntrinsicHelper::HLArrayGetFloat: - cvtAget(cUnit, callInst, kWord, 2); - break; - case greenland::IntrinsicHelper::HLArrayGetWide: - case greenland::IntrinsicHelper::HLArrayGetDouble: - cvtAget(cUnit, callInst, kLong, 3); - break; - case greenland::IntrinsicHelper::HLArrayGetBoolean: - cvtAget(cUnit, callInst, kUnsignedByte, 0); - break; - case greenland::IntrinsicHelper::HLArrayGetByte: - cvtAget(cUnit, callInst, kSignedByte, 0); - break; - case greenland::IntrinsicHelper::HLArrayGetChar: - cvtAget(cUnit, callInst, kUnsignedHalf, 1); - break; - case greenland::IntrinsicHelper::HLArrayGetShort: - cvtAget(cUnit, callInst, kSignedHalf, 1); - break; - - case greenland::IntrinsicHelper::HLArrayPut: - case greenland::IntrinsicHelper::HLArrayPutFloat: - cvtAputPrimitive(cUnit, callInst, kWord, 2); - break; - case greenland::IntrinsicHelper::HLArrayPutObject: - cvtAputObj(cUnit, callInst); - break; - case greenland::IntrinsicHelper::HLArrayPutWide: - case greenland::IntrinsicHelper::HLArrayPutDouble: - cvtAputPrimitive(cUnit, callInst, kLong, 3); - break; - case greenland::IntrinsicHelper::HLArrayPutBoolean: - cvtAputPrimitive(cUnit, callInst, kUnsignedByte, 0); - break; - case greenland::IntrinsicHelper::HLArrayPutByte: - cvtAputPrimitive(cUnit, callInst, kSignedByte, 0); - break; - case greenland::IntrinsicHelper::HLArrayPutChar: - cvtAputPrimitive(cUnit, callInst, kUnsignedHalf, 1); - break; - case greenland::IntrinsicHelper::HLArrayPutShort: - cvtAputPrimitive(cUnit, callInst, kSignedHalf, 1); - break; - - case greenland::IntrinsicHelper::HLIGet: - case greenland::IntrinsicHelper::HLIGetFloat: - cvtIget(cUnit, callInst, kWord, false /* isWide */, false /* obj */); - break; - case greenland::IntrinsicHelper::HLIGetObject: - cvtIget(cUnit, callInst, kWord, false /* isWide */, true /* obj */); - break; - case greenland::IntrinsicHelper::HLIGetWide: - case greenland::IntrinsicHelper::HLIGetDouble: - cvtIget(cUnit, callInst, kLong, true /* isWide */, false /* obj */); - break; - case greenland::IntrinsicHelper::HLIGetBoolean: - cvtIget(cUnit, callInst, kUnsignedByte, false /* isWide */, - false /* obj */); - break; - case greenland::IntrinsicHelper::HLIGetByte: - cvtIget(cUnit, callInst, kSignedByte, false /* isWide */, - false /* obj */); - break; - case greenland::IntrinsicHelper::HLIGetChar: - cvtIget(cUnit, callInst, kUnsignedHalf, false /* isWide */, - false /* obj */); - break; - case greenland::IntrinsicHelper::HLIGetShort: - cvtIget(cUnit, callInst, kSignedHalf, false /* isWide */, - false /* obj */); - break; - - case greenland::IntrinsicHelper::HLIPut: - case greenland::IntrinsicHelper::HLIPutFloat: - cvtIput(cUnit, callInst, kWord, false /* isWide */, false /* obj */); - break; - case greenland::IntrinsicHelper::HLIPutObject: - cvtIput(cUnit, callInst, kWord, false /* isWide */, true /* obj */); - break; - case greenland::IntrinsicHelper::HLIPutWide: - case greenland::IntrinsicHelper::HLIPutDouble: - cvtIput(cUnit, callInst, kLong, true /* isWide */, false /* obj */); - break; - case greenland::IntrinsicHelper::HLIPutBoolean: - cvtIput(cUnit, callInst, kUnsignedByte, false /* isWide */, - false /* obj */); - break; - case greenland::IntrinsicHelper::HLIPutByte: - cvtIput(cUnit, callInst, kSignedByte, false /* isWide */, - false /* obj */); - break; - case greenland::IntrinsicHelper::HLIPutChar: - cvtIput(cUnit, callInst, kUnsignedHalf, false /* isWide */, - false /* obj */); - break; - case greenland::IntrinsicHelper::HLIPutShort: - cvtIput(cUnit, callInst, kSignedHalf, false /* isWide */, - false /* obj */); - break; - - case greenland::IntrinsicHelper::IntToChar: - cvtIntNarrowing(cUnit, callInst, Instruction::INT_TO_CHAR); - break; - case greenland::IntrinsicHelper::IntToShort: - cvtIntNarrowing(cUnit, callInst, Instruction::INT_TO_SHORT); - break; - case greenland::IntrinsicHelper::IntToByte: - cvtIntNarrowing(cUnit, callInst, Instruction::INT_TO_BYTE); - break; - - case greenland::IntrinsicHelper::CmplFloat: - cvtFPCompare(cUnit, callInst, Instruction::CMPL_FLOAT); - break; - case greenland::IntrinsicHelper::CmpgFloat: - cvtFPCompare(cUnit, callInst, Instruction::CMPG_FLOAT); - break; - case greenland::IntrinsicHelper::CmplDouble: - cvtFPCompare(cUnit, callInst, Instruction::CMPL_DOUBLE); - break; - case greenland::IntrinsicHelper::CmpgDouble: - cvtFPCompare(cUnit, callInst, Instruction::CMPG_DOUBLE); - break; - - case greenland::IntrinsicHelper::CmpLong: - cvtLongCompare(cUnit, callInst); - break; - - case greenland::IntrinsicHelper::SHLLong: - cvtShiftOp(cUnit, Instruction::SHL_LONG, callInst); - break; - case greenland::IntrinsicHelper::SHRLong: - cvtShiftOp(cUnit, Instruction::SHR_LONG, callInst); - break; - case greenland::IntrinsicHelper::USHRLong: - cvtShiftOp(cUnit, Instruction::USHR_LONG, callInst); - break; - case greenland::IntrinsicHelper::SHLInt: - cvtShiftOp(cUnit, Instruction::SHL_INT, callInst); - break; - case greenland::IntrinsicHelper::SHRInt: - cvtShiftOp(cUnit, Instruction::SHR_INT, callInst); - break; - case greenland::IntrinsicHelper::USHRInt: - cvtShiftOp(cUnit, Instruction::USHR_INT, callInst); - break; - - case greenland::IntrinsicHelper::CatchTargets: { - llvm::SwitchInst* swInst = - llvm::dyn_cast<llvm::SwitchInst>(nextIt); - DCHECK(swInst != NULL); - /* - * Discard the edges and the following conditional branch. - * Do a direct branch to the default target (which is the - * "work" portion of the pair. - * TODO: awful code layout - rework - */ - llvm::BasicBlock* targetBB = swInst->getDefaultDest(); - DCHECK(targetBB != NULL); - opUnconditionalBranch(cUnit, - cUnit->blockToLabelMap.Get(targetBB)); - ++it; - } - break; - - default: - LOG(FATAL) << "Unexpected intrinsic " << (int)id << ", " - << cUnit->intrinsic_helper->GetName(id); - } - } - break; + /* Remember the first LIR for thisl block*/ + if (headLIR == NULL) { + headLIR = boundaryLIR; + headLIR->defMask = ENCODE_ALL; + } - case llvm::Instruction::Br: cvtBr(cUnit, inst); break; - case llvm::Instruction::Add: cvtBinOp(cUnit, kOpAdd, inst); break; - case llvm::Instruction::Sub: cvtBinOp(cUnit, kOpSub, inst); break; - case llvm::Instruction::Mul: cvtBinOp(cUnit, kOpMul, inst); break; - case llvm::Instruction::SDiv: cvtBinOp(cUnit, kOpDiv, inst); break; - case llvm::Instruction::SRem: cvtBinOp(cUnit, kOpRem, inst); break; - case llvm::Instruction::And: cvtBinOp(cUnit, kOpAnd, inst); break; - case llvm::Instruction::Or: cvtBinOp(cUnit, kOpOr, inst); break; - case llvm::Instruction::Xor: cvtBinOp(cUnit, kOpXor, inst); break; - case llvm::Instruction::PHI: cvtPhi(cUnit, inst); break; - case llvm::Instruction::Ret: cvtRet(cUnit, inst); break; - case llvm::Instruction::FAdd: cvtBinFPOp(cUnit, kOpAdd, inst); break; - case llvm::Instruction::FSub: cvtBinFPOp(cUnit, kOpSub, inst); break; - case llvm::Instruction::FMul: cvtBinFPOp(cUnit, kOpMul, inst); break; - case llvm::Instruction::FDiv: cvtBinFPOp(cUnit, kOpDiv, inst); break; - case llvm::Instruction::FRem: cvtBinFPOp(cUnit, kOpRem, inst); break; - case llvm::Instruction::SIToFP: cvtIntToFP(cUnit, inst); break; - case llvm::Instruction::FPToSI: cvtFPToInt(cUnit, inst); break; - case llvm::Instruction::FPTrunc: cvtDoubleToFloat(cUnit, inst); break; - case llvm::Instruction::FPExt: cvtFloatToDouble(cUnit, inst); break; - case llvm::Instruction::Trunc: cvtTrunc(cUnit, inst); break; - - case llvm::Instruction::ZExt: cvtIntExt(cUnit, inst, false /* signed */); - break; - case llvm::Instruction::SExt: cvtIntExt(cUnit, inst, true /* signed */); - break; + switch(opcode) { - case llvm::Instruction::Switch: cvtSwitch(cUnit, inst); break; - - case llvm::Instruction::Unreachable: - break; // FIXME: can we really ignore these? - - case llvm::Instruction::Shl: - case llvm::Instruction::LShr: - case llvm::Instruction::AShr: - case llvm::Instruction::Invoke: - case llvm::Instruction::FPToUI: - case llvm::Instruction::UIToFP: - case llvm::Instruction::PtrToInt: - case llvm::Instruction::IntToPtr: - case llvm::Instruction::FCmp: - case llvm::Instruction::URem: - case llvm::Instruction::UDiv: - case llvm::Instruction::Resume: - case llvm::Instruction::Alloca: - case llvm::Instruction::GetElementPtr: - case llvm::Instruction::Fence: - case llvm::Instruction::AtomicCmpXchg: - case llvm::Instruction::AtomicRMW: - case llvm::Instruction::BitCast: - case llvm::Instruction::VAArg: - case llvm::Instruction::Select: - case llvm::Instruction::UserOp1: - case llvm::Instruction::UserOp2: - case llvm::Instruction::ExtractElement: - case llvm::Instruction::InsertElement: - case llvm::Instruction::ShuffleVector: - case llvm::Instruction::ExtractValue: - case llvm::Instruction::InsertValue: - case llvm::Instruction::LandingPad: - case llvm::Instruction::IndirectBr: - case llvm::Instruction::Load: - case llvm::Instruction::Store: - LOG(FATAL) << "Unexpected llvm opcode: " << opcode; break; - - default: - LOG(FATAL) << "Unknown llvm opcode: " << inst->getOpcodeName(); - break; + case llvm::Instruction::ICmp: { + llvm::Instruction* nextInst = nextIt; + llvm::BranchInst* brInst = llvm::dyn_cast<llvm::BranchInst>(nextInst); + if (brInst != NULL /* and... */) { + cvtICmpBr(cUnit, inst, brInst); + ++it; + } else { + cvtICmp(cUnit, inst); + } + } + break; + + case llvm::Instruction::Call: { + llvm::CallInst* callInst = llvm::dyn_cast<llvm::CallInst>(inst); + llvm::Function* callee = callInst->getCalledFunction(); + greenland::IntrinsicHelper::IntrinsicId id = + cUnit->intrinsic_helper->GetIntrinsicId(callee); + switch (id) { + case greenland::IntrinsicHelper::AllocaShadowFrame: + case greenland::IntrinsicHelper::SetShadowFrameEntry: + case greenland::IntrinsicHelper::PopShadowFrame: + // Ignore shadow frame stuff for quick compiler + break; + case greenland::IntrinsicHelper::CopyInt: + case greenland::IntrinsicHelper::CopyObj: + case greenland::IntrinsicHelper::CopyFloat: + case greenland::IntrinsicHelper::CopyLong: + case greenland::IntrinsicHelper::CopyDouble: + cvtCopy(cUnit, callInst); + break; + case greenland::IntrinsicHelper::ConstInt: + case greenland::IntrinsicHelper::ConstObj: + case greenland::IntrinsicHelper::ConstLong: + case greenland::IntrinsicHelper::ConstFloat: + case greenland::IntrinsicHelper::ConstDouble: + cvtConst(cUnit, callInst); + break; + case greenland::IntrinsicHelper::DivInt: + case greenland::IntrinsicHelper::DivLong: + cvtBinOp(cUnit, kOpDiv, inst); + break; + case greenland::IntrinsicHelper::RemInt: + case greenland::IntrinsicHelper::RemLong: + cvtBinOp(cUnit, kOpRem, inst); + break; + case greenland::IntrinsicHelper::MethodInfo: + // Already dealt with - just ignore it here. + break; + case greenland::IntrinsicHelper::CheckSuspend: + genSuspendTest(cUnit, 0 /* optFlags already applied */); + break; + case greenland::IntrinsicHelper::HLInvokeObj: + case greenland::IntrinsicHelper::HLInvokeFloat: + case greenland::IntrinsicHelper::HLInvokeDouble: + case greenland::IntrinsicHelper::HLInvokeLong: + case greenland::IntrinsicHelper::HLInvokeInt: + cvtInvoke(cUnit, callInst, false /* isVoid */, false /* newArray */); + break; + case greenland::IntrinsicHelper::HLInvokeVoid: + cvtInvoke(cUnit, callInst, true /* isVoid */, false /* newArray */); + break; + case greenland::IntrinsicHelper::FilledNewArray: + cvtInvoke(cUnit, callInst, false /* isVoid */, true /* newArray */); + break; + case greenland::IntrinsicHelper::FillArrayData: + cvtFillArrayData(cUnit, callInst); + break; + case greenland::IntrinsicHelper::ConstString: + cvtConstObject(cUnit, callInst, true /* isString */); + break; + case greenland::IntrinsicHelper::ConstClass: + cvtConstObject(cUnit, callInst, false /* isString */); + break; + case greenland::IntrinsicHelper::CheckCast: + cvtCheckCast(cUnit, callInst); + break; + case greenland::IntrinsicHelper::NewInstance: + cvtNewInstance(cUnit, callInst); + break; + case greenland::IntrinsicHelper::HLSgetObject: + cvtSget(cUnit, callInst, false /* wide */, true /* Object */); + break; + case greenland::IntrinsicHelper::HLSget: + case greenland::IntrinsicHelper::HLSgetFloat: + case greenland::IntrinsicHelper::HLSgetBoolean: + case greenland::IntrinsicHelper::HLSgetByte: + case greenland::IntrinsicHelper::HLSgetChar: + case greenland::IntrinsicHelper::HLSgetShort: + cvtSget(cUnit, callInst, false /* wide */, false /* Object */); + break; + case greenland::IntrinsicHelper::HLSgetWide: + case greenland::IntrinsicHelper::HLSgetDouble: + cvtSget(cUnit, callInst, true /* wide */, false /* Object */); + break; + case greenland::IntrinsicHelper::HLSput: + case greenland::IntrinsicHelper::HLSputFloat: + case greenland::IntrinsicHelper::HLSputBoolean: + case greenland::IntrinsicHelper::HLSputByte: + case greenland::IntrinsicHelper::HLSputChar: + case greenland::IntrinsicHelper::HLSputShort: + cvtSput(cUnit, callInst, false /* wide */, false /* Object */); + break; + case greenland::IntrinsicHelper::HLSputWide: + case greenland::IntrinsicHelper::HLSputDouble: + cvtSput(cUnit, callInst, true /* wide */, false /* Object */); + break; + case greenland::IntrinsicHelper::HLSputObject: + cvtSput(cUnit, callInst, false /* wide */, true /* Object */); + break; + case greenland::IntrinsicHelper::GetException: + cvtMoveException(cUnit, callInst); + break; + case greenland::IntrinsicHelper::Throw: + cvtThrow(cUnit, callInst); + break; + case greenland::IntrinsicHelper::MonitorEnter: + cvtMonitorEnterExit(cUnit, true /* isEnter */, callInst); + break; + case greenland::IntrinsicHelper::MonitorExit: + cvtMonitorEnterExit(cUnit, false /* isEnter */, callInst); + break; + case greenland::IntrinsicHelper::ArrayLength: + cvtArrayLength(cUnit, callInst); + break; + case greenland::IntrinsicHelper::NewArray: + cvtNewArray(cUnit, callInst); + break; + case greenland::IntrinsicHelper::InstanceOf: + cvtInstanceOf(cUnit, callInst); + break; + + case greenland::IntrinsicHelper::HLArrayGet: + case greenland::IntrinsicHelper::HLArrayGetObject: + case greenland::IntrinsicHelper::HLArrayGetFloat: + cvtAget(cUnit, callInst, kWord, 2); + break; + case greenland::IntrinsicHelper::HLArrayGetWide: + case greenland::IntrinsicHelper::HLArrayGetDouble: + cvtAget(cUnit, callInst, kLong, 3); + break; + case greenland::IntrinsicHelper::HLArrayGetBoolean: + cvtAget(cUnit, callInst, kUnsignedByte, 0); + break; + case greenland::IntrinsicHelper::HLArrayGetByte: + cvtAget(cUnit, callInst, kSignedByte, 0); + break; + case greenland::IntrinsicHelper::HLArrayGetChar: + cvtAget(cUnit, callInst, kUnsignedHalf, 1); + break; + case greenland::IntrinsicHelper::HLArrayGetShort: + cvtAget(cUnit, callInst, kSignedHalf, 1); + break; + + case greenland::IntrinsicHelper::HLArrayPut: + case greenland::IntrinsicHelper::HLArrayPutFloat: + cvtAputPrimitive(cUnit, callInst, kWord, 2); + break; + case greenland::IntrinsicHelper::HLArrayPutObject: + cvtAputObj(cUnit, callInst); + break; + case greenland::IntrinsicHelper::HLArrayPutWide: + case greenland::IntrinsicHelper::HLArrayPutDouble: + cvtAputPrimitive(cUnit, callInst, kLong, 3); + break; + case greenland::IntrinsicHelper::HLArrayPutBoolean: + cvtAputPrimitive(cUnit, callInst, kUnsignedByte, 0); + break; + case greenland::IntrinsicHelper::HLArrayPutByte: + cvtAputPrimitive(cUnit, callInst, kSignedByte, 0); + break; + case greenland::IntrinsicHelper::HLArrayPutChar: + cvtAputPrimitive(cUnit, callInst, kUnsignedHalf, 1); + break; + case greenland::IntrinsicHelper::HLArrayPutShort: + cvtAputPrimitive(cUnit, callInst, kSignedHalf, 1); + break; + + case greenland::IntrinsicHelper::HLIGet: + case greenland::IntrinsicHelper::HLIGetFloat: + cvtIget(cUnit, callInst, kWord, false /* isWide */, false /* obj */); + break; + case greenland::IntrinsicHelper::HLIGetObject: + cvtIget(cUnit, callInst, kWord, false /* isWide */, true /* obj */); + break; + case greenland::IntrinsicHelper::HLIGetWide: + case greenland::IntrinsicHelper::HLIGetDouble: + cvtIget(cUnit, callInst, kLong, true /* isWide */, false /* obj */); + break; + case greenland::IntrinsicHelper::HLIGetBoolean: + cvtIget(cUnit, callInst, kUnsignedByte, false /* isWide */, + false /* obj */); + break; + case greenland::IntrinsicHelper::HLIGetByte: + cvtIget(cUnit, callInst, kSignedByte, false /* isWide */, + false /* obj */); + break; + case greenland::IntrinsicHelper::HLIGetChar: + cvtIget(cUnit, callInst, kUnsignedHalf, false /* isWide */, + false /* obj */); + break; + case greenland::IntrinsicHelper::HLIGetShort: + cvtIget(cUnit, callInst, kSignedHalf, false /* isWide */, + false /* obj */); + break; + + case greenland::IntrinsicHelper::HLIPut: + case greenland::IntrinsicHelper::HLIPutFloat: + cvtIput(cUnit, callInst, kWord, false /* isWide */, false /* obj */); + break; + case greenland::IntrinsicHelper::HLIPutObject: + cvtIput(cUnit, callInst, kWord, false /* isWide */, true /* obj */); + break; + case greenland::IntrinsicHelper::HLIPutWide: + case greenland::IntrinsicHelper::HLIPutDouble: + cvtIput(cUnit, callInst, kLong, true /* isWide */, false /* obj */); + break; + case greenland::IntrinsicHelper::HLIPutBoolean: + cvtIput(cUnit, callInst, kUnsignedByte, false /* isWide */, + false /* obj */); + break; + case greenland::IntrinsicHelper::HLIPutByte: + cvtIput(cUnit, callInst, kSignedByte, false /* isWide */, + false /* obj */); + break; + case greenland::IntrinsicHelper::HLIPutChar: + cvtIput(cUnit, callInst, kUnsignedHalf, false /* isWide */, + false /* obj */); + break; + case greenland::IntrinsicHelper::HLIPutShort: + cvtIput(cUnit, callInst, kSignedHalf, false /* isWide */, + false /* obj */); + break; + + case greenland::IntrinsicHelper::IntToChar: + cvtIntNarrowing(cUnit, callInst, Instruction::INT_TO_CHAR); + break; + case greenland::IntrinsicHelper::IntToShort: + cvtIntNarrowing(cUnit, callInst, Instruction::INT_TO_SHORT); + break; + case greenland::IntrinsicHelper::IntToByte: + cvtIntNarrowing(cUnit, callInst, Instruction::INT_TO_BYTE); + break; + + case greenland::IntrinsicHelper::CmplFloat: + cvtFPCompare(cUnit, callInst, Instruction::CMPL_FLOAT); + break; + case greenland::IntrinsicHelper::CmpgFloat: + cvtFPCompare(cUnit, callInst, Instruction::CMPG_FLOAT); + break; + case greenland::IntrinsicHelper::CmplDouble: + cvtFPCompare(cUnit, callInst, Instruction::CMPL_DOUBLE); + break; + case greenland::IntrinsicHelper::CmpgDouble: + cvtFPCompare(cUnit, callInst, Instruction::CMPG_DOUBLE); + break; + + case greenland::IntrinsicHelper::CmpLong: + cvtLongCompare(cUnit, callInst); + break; + + case greenland::IntrinsicHelper::SHLLong: + cvtShiftOp(cUnit, Instruction::SHL_LONG, callInst); + break; + case greenland::IntrinsicHelper::SHRLong: + cvtShiftOp(cUnit, Instruction::SHR_LONG, callInst); + break; + case greenland::IntrinsicHelper::USHRLong: + cvtShiftOp(cUnit, Instruction::USHR_LONG, callInst); + break; + case greenland::IntrinsicHelper::SHLInt: + cvtShiftOp(cUnit, Instruction::SHL_INT, callInst); + break; + case greenland::IntrinsicHelper::SHRInt: + cvtShiftOp(cUnit, Instruction::SHR_INT, callInst); + break; + case greenland::IntrinsicHelper::USHRInt: + cvtShiftOp(cUnit, Instruction::USHR_INT, callInst); + break; + + case greenland::IntrinsicHelper::CatchTargets: { + llvm::SwitchInst* swInst = + llvm::dyn_cast<llvm::SwitchInst>(nextIt); + DCHECK(swInst != NULL); + /* + * Discard the edges and the following conditional branch. + * Do a direct branch to the default target (which is the + * "work" portion of the pair. + * TODO: awful code layout - rework + */ + llvm::BasicBlock* targetBB = swInst->getDefaultDest(); + DCHECK(targetBB != NULL); + opUnconditionalBranch(cUnit, + cUnit->blockToLabelMap.Get(targetBB)); + ++it; + // Set next bb to default target - improves code layout + nextBB = targetBB; + } + break; + + default: + LOG(FATAL) << "Unexpected intrinsic " << (int)id << ", " + << cUnit->intrinsic_helper->GetName(id); + } + } + break; + + case llvm::Instruction::Br: cvtBr(cUnit, inst); break; + case llvm::Instruction::Add: cvtBinOp(cUnit, kOpAdd, inst); break; + case llvm::Instruction::Sub: cvtBinOp(cUnit, kOpSub, inst); break; + case llvm::Instruction::Mul: cvtBinOp(cUnit, kOpMul, inst); break; + case llvm::Instruction::SDiv: cvtBinOp(cUnit, kOpDiv, inst); break; + case llvm::Instruction::SRem: cvtBinOp(cUnit, kOpRem, inst); break; + case llvm::Instruction::And: cvtBinOp(cUnit, kOpAnd, inst); break; + case llvm::Instruction::Or: cvtBinOp(cUnit, kOpOr, inst); break; + case llvm::Instruction::Xor: cvtBinOp(cUnit, kOpXor, inst); break; + case llvm::Instruction::PHI: cvtPhi(cUnit, inst); break; + case llvm::Instruction::Ret: cvtRet(cUnit, inst); break; + case llvm::Instruction::FAdd: cvtBinFPOp(cUnit, kOpAdd, inst); break; + case llvm::Instruction::FSub: cvtBinFPOp(cUnit, kOpSub, inst); break; + case llvm::Instruction::FMul: cvtBinFPOp(cUnit, kOpMul, inst); break; + case llvm::Instruction::FDiv: cvtBinFPOp(cUnit, kOpDiv, inst); break; + case llvm::Instruction::FRem: cvtBinFPOp(cUnit, kOpRem, inst); break; + case llvm::Instruction::SIToFP: cvtIntToFP(cUnit, inst); break; + case llvm::Instruction::FPToSI: cvtFPToInt(cUnit, inst); break; + case llvm::Instruction::FPTrunc: cvtDoubleToFloat(cUnit, inst); break; + case llvm::Instruction::FPExt: cvtFloatToDouble(cUnit, inst); break; + case llvm::Instruction::Trunc: cvtTrunc(cUnit, inst); break; + + case llvm::Instruction::ZExt: cvtIntExt(cUnit, inst, false /* signed */); + break; + case llvm::Instruction::SExt: cvtIntExt(cUnit, inst, true /* signed */); + break; + + case llvm::Instruction::Switch: cvtSwitch(cUnit, inst); break; + + case llvm::Instruction::Unreachable: + break; // FIXME: can we really ignore these? + + case llvm::Instruction::Shl: + case llvm::Instruction::LShr: + case llvm::Instruction::AShr: + case llvm::Instruction::Invoke: + case llvm::Instruction::FPToUI: + case llvm::Instruction::UIToFP: + case llvm::Instruction::PtrToInt: + case llvm::Instruction::IntToPtr: + case llvm::Instruction::FCmp: + case llvm::Instruction::URem: + case llvm::Instruction::UDiv: + case llvm::Instruction::Resume: + case llvm::Instruction::Alloca: + case llvm::Instruction::GetElementPtr: + case llvm::Instruction::Fence: + case llvm::Instruction::AtomicCmpXchg: + case llvm::Instruction::AtomicRMW: + case llvm::Instruction::BitCast: + case llvm::Instruction::VAArg: + case llvm::Instruction::Select: + case llvm::Instruction::UserOp1: + case llvm::Instruction::UserOp2: + case llvm::Instruction::ExtractElement: + case llvm::Instruction::InsertElement: + case llvm::Instruction::ShuffleVector: + case llvm::Instruction::ExtractValue: + case llvm::Instruction::InsertValue: + case llvm::Instruction::LandingPad: + case llvm::Instruction::IndirectBr: + case llvm::Instruction::Load: + case llvm::Instruction::Store: + LOG(FATAL) << "Unexpected llvm opcode: " << opcode; break; + + default: + LOG(FATAL) << "Unknown llvm opcode: " << inst->getOpcodeName(); + break; + } } - } - if (headLIR != NULL) { - oatApplyLocalOptimizations(cUnit, headLIR, cUnit->lastLIRInsn); + if (headLIR != NULL) { + oatApplyLocalOptimizations(cUnit, headLIR, cUnit->lastLIRInsn); + } + if (nextBB != NULL) { + bb = nextBB; + nextBB = NULL; + } } return false; } |