/// WriteInstruction - Emit an instruction to the specified stream. /// Returns true if instruction actually emitted. static bool WriteInstruction(const Instruction &I, unsigned InstID, NaClValueEnumerator &VE, NaClBitstreamWriter &Stream, SmallVector<unsigned, 64> &Vals) { unsigned Code = 0; unsigned AbbrevToUse = 0; VE.setInstructionID(&I); switch (I.getOpcode()) { default: if (Instruction::isCast(I.getOpcode())) { // CAST: [opval, destty, castopc] if (VE.IsElidedCast(&I)) return false; Code = naclbitc::FUNC_CODE_INST_CAST; AbbrevToUse = FUNCTION_INST_CAST_ABBREV; pushValue(I.getOperand(0), InstID, Vals, VE, Stream); Vals.push_back(VE.getTypeID(I.getType())); unsigned Opcode = I.getOpcode(); Vals.push_back(GetEncodedCastOpcode(Opcode, I)); if (Opcode == Instruction::PtrToInt || Opcode == Instruction::IntToPtr || (Opcode == Instruction::BitCast && (I.getOperand(0)->getType()->isPointerTy() || I.getType()->isPointerTy()))) { ReportIllegalValue("(PNaCl ABI) pointer cast", I); } } else if (isa<BinaryOperator>(I)) { // BINOP: [opval, opval, opcode] Code = naclbitc::FUNC_CODE_INST_BINOP; AbbrevToUse = FUNCTION_INST_BINOP_ABBREV; pushValue(I.getOperand(0), InstID, Vals, VE, Stream); pushValue(I.getOperand(1), InstID, Vals, VE, Stream); Vals.push_back(GetEncodedBinaryOpcode(I.getOpcode(), I)); } else { ReportIllegalValue("instruction", I); } break; case Instruction::Select: Code = naclbitc::FUNC_CODE_INST_VSELECT; pushValue(I.getOperand(1), InstID, Vals, VE, Stream); pushValue(I.getOperand(2), InstID, Vals, VE, Stream); pushValue(I.getOperand(0), InstID, Vals, VE, Stream); break; case Instruction::ExtractElement: Code = naclbitc::FUNC_CODE_INST_EXTRACTELT; pushValue(I.getOperand(0), InstID, Vals, VE, Stream); pushValue(I.getOperand(1), InstID, Vals, VE, Stream); break; case Instruction::InsertElement: Code = naclbitc::FUNC_CODE_INST_INSERTELT; pushValue(I.getOperand(0), InstID, Vals, VE, Stream); pushValue(I.getOperand(1), InstID, Vals, VE, Stream); pushValue(I.getOperand(2), InstID, Vals, VE, Stream); break; case Instruction::ICmp: case Instruction::FCmp: // compare returning Int1Ty or vector of Int1Ty Code = naclbitc::FUNC_CODE_INST_CMP2; pushValue(I.getOperand(0), InstID, Vals, VE, Stream); pushValue(I.getOperand(1), InstID, Vals, VE, Stream); Vals.push_back(GetEncodedCmpPredicate(cast<CmpInst>(I))); break; case Instruction::Ret: { Code = naclbitc::FUNC_CODE_INST_RET; unsigned NumOperands = I.getNumOperands(); if (NumOperands == 0) AbbrevToUse = FUNCTION_INST_RET_VOID_ABBREV; else if (NumOperands == 1) { pushValue(I.getOperand(0), InstID, Vals, VE, Stream); AbbrevToUse = FUNCTION_INST_RET_VAL_ABBREV; } else { for (unsigned i = 0, e = NumOperands; i != e; ++i) pushValue(I.getOperand(i), InstID, Vals, VE, Stream); } } break; case Instruction::Br: { Code = naclbitc::FUNC_CODE_INST_BR; const BranchInst &II = cast<BranchInst>(I); Vals.push_back(VE.getValueID(II.getSuccessor(0))); if (II.isConditional()) { Vals.push_back(VE.getValueID(II.getSuccessor(1))); pushValue(II.getCondition(), InstID, Vals, VE, Stream); } } break; case Instruction::Switch: { // Redefine Vals, since here we need to use 64 bit values // explicitly to store large APInt numbers. SmallVector<uint64_t, 128> Vals64; Code = naclbitc::FUNC_CODE_INST_SWITCH; const SwitchInst &SI = cast<SwitchInst>(I); Vals64.push_back(VE.getTypeID(SI.getCondition()->getType())); pushValue64(SI.getCondition(), InstID, Vals64, VE, Stream); Vals64.push_back(VE.getValueID(SI.getDefaultDest())); Vals64.push_back(SI.getNumCases()); for (SwitchInst::ConstCaseIt i = SI.case_begin(), e = SI.case_end(); i != e; ++i) { // The PNaCl bitcode format has vestigial support for case // ranges, but we no longer support reading or writing them, // so the next two fields always have the same values. // See https://code.google.com/p/nativeclient/issues/detail?id=3758 Vals64.push_back(1/*NumItems = 1*/); Vals64.push_back(true/*IsSingleNumber = true*/); emitSignedInt64(Vals64, i.getCaseValue()->getSExtValue()); Vals64.push_back(VE.getValueID(i.getCaseSuccessor())); } Stream.EmitRecord(Code, Vals64, AbbrevToUse); // Also do expected action - clear external Vals collection: Vals.clear(); return true; } break; case Instruction::Unreachable: Code = naclbitc::FUNC_CODE_INST_UNREACHABLE; AbbrevToUse = FUNCTION_INST_UNREACHABLE_ABBREV; break; case Instruction::PHI: { const PHINode &PN = cast<PHINode>(I); Code = naclbitc::FUNC_CODE_INST_PHI; // With the newer instruction encoding, forward references could give // negative valued IDs. This is most common for PHIs, so we use // signed VBRs. SmallVector<uint64_t, 128> Vals64; Vals64.push_back(VE.getTypeID(PN.getType())); for (unsigned i = 0, e = PN.getNumIncomingValues(); i != e; ++i) { pushValueSigned(PN.getIncomingValue(i), InstID, Vals64, VE, Stream); Vals64.push_back(VE.getValueID(PN.getIncomingBlock(i))); } // Emit a Vals64 vector and exit. Stream.EmitRecord(Code, Vals64, AbbrevToUse); Vals64.clear(); return true; } case Instruction::Alloca: if (!cast<AllocaInst>(&I)->getAllocatedType()->isIntegerTy(8)) report_fatal_error("Type of alloca instruction is not i8"); Code = naclbitc::FUNC_CODE_INST_ALLOCA; pushValue(I.getOperand(0), InstID, Vals, VE, Stream); // size. Vals.push_back(Log2_32(cast<AllocaInst>(I).getAlignment())+1); break; case Instruction::Load: // LOAD: [op, align, ty] Code = naclbitc::FUNC_CODE_INST_LOAD; pushValue(I.getOperand(0), InstID, Vals, VE, Stream); AbbrevToUse = FUNCTION_INST_LOAD_ABBREV; Vals.push_back(Log2_32(cast<LoadInst>(I).getAlignment())+1); Vals.push_back(VE.getTypeID(I.getType())); break; case Instruction::Store: // STORE: [ptr, val, align] Code = naclbitc::FUNC_CODE_INST_STORE; AbbrevToUse = FUNCTION_INST_STORE_ABBREV; pushValue(I.getOperand(1), InstID, Vals, VE, Stream); pushValue(I.getOperand(0), InstID, Vals, VE, Stream); Vals.push_back(Log2_32(cast<StoreInst>(I).getAlignment())+1); break; case Instruction::Call: { // CALL: [cc, fnid, args...] // CALL_INDIRECT: [cc, fnid, fnty, args...] const CallInst &Call = cast<CallInst>(I); const Value* Callee = Call.getCalledValue(); Vals.push_back((GetEncodedCallingConv(Call.getCallingConv()) << 1) | unsigned(Call.isTailCall())); pushValue(Callee, InstID, Vals, VE, Stream); if (Callee == VE.ElideCasts(Callee)) { // Since the call pointer has not been elided, we know that // the call pointer has the type signature of the called // function. This implies that the reader can use the type // signature of the callee to figure out how to add casts to // the arguments. Code = naclbitc::FUNC_CODE_INST_CALL; } else { // If the cast was elided, a pointer conversion to a pointer // was applied, meaning that this is an indirect call. For the // reader, this implies that we can't use the type signature // of the callee to resolve elided call arguments, since it is // not known. Hence, we must send the type signature to the // reader. Code = naclbitc::FUNC_CODE_INST_CALL_INDIRECT; Vals.push_back(VE.getTypeID(I.getType())); } for (unsigned I = 0, E = Call.getNumArgOperands(); I < E; ++I) { pushValue(Call.getArgOperand(I), InstID, Vals, VE, Stream); } break; } } Stream.EmitRecord(Code, Vals, AbbrevToUse); Vals.clear(); return true; }
/// The specified block is found to be reachable, clone it and /// anything that it can reach. void PruningFunctionCloner::CloneBlock(const BasicBlock *BB, BasicBlock::const_iterator StartingInst, std::vector<const BasicBlock*> &ToClone){ WeakVH &BBEntry = VMap[BB]; // Have we already cloned this block? if (BBEntry) return; // Nope, clone it now. BasicBlock *NewBB; BBEntry = NewBB = BasicBlock::Create(BB->getContext()); if (BB->hasName()) NewBB->setName(BB->getName()+NameSuffix); // It is only legal to clone a function if a block address within that // function is never referenced outside of the function. Given that, we // want to map block addresses from the old function to block addresses in // the clone. (This is different from the generic ValueMapper // implementation, which generates an invalid blockaddress when // cloning a function.) // // Note that we don't need to fix the mapping for unreachable blocks; // the default mapping there is safe. if (BB->hasAddressTaken()) { Constant *OldBBAddr = BlockAddress::get(const_cast<Function*>(OldFunc), const_cast<BasicBlock*>(BB)); VMap[OldBBAddr] = BlockAddress::get(NewFunc, NewBB); } bool hasCalls = false, hasDynamicAllocas = false, hasStaticAllocas = false; // Loop over all instructions, and copy them over, DCE'ing as we go. This // loop doesn't include the terminator. for (BasicBlock::const_iterator II = StartingInst, IE = --BB->end(); II != IE; ++II) { Instruction *NewInst = II->clone(); // Eagerly remap operands to the newly cloned instruction, except for PHI // nodes for which we defer processing until we update the CFG. if (!isa<PHINode>(NewInst)) { RemapInstruction(NewInst, VMap, ModuleLevelChanges ? RF_None : RF_NoModuleLevelChanges); // If we can simplify this instruction to some other value, simply add // a mapping to that value rather than inserting a new instruction into // the basic block. if (Value *V = SimplifyInstruction(NewInst, BB->getModule()->getDataLayout())) { // On the off-chance that this simplifies to an instruction in the old // function, map it back into the new function. if (Value *MappedV = VMap.lookup(V)) V = MappedV; VMap[&*II] = V; delete NewInst; continue; } } if (II->hasName()) NewInst->setName(II->getName()+NameSuffix); VMap[&*II] = NewInst; // Add instruction map to value. NewBB->getInstList().push_back(NewInst); hasCalls |= (isa<CallInst>(II) && !isa<DbgInfoIntrinsic>(II)); if (CodeInfo) if (auto CS = ImmutableCallSite(&*II)) if (CS.hasOperandBundles()) CodeInfo->OperandBundleCallSites.push_back(NewInst); if (const AllocaInst *AI = dyn_cast<AllocaInst>(II)) { if (isa<ConstantInt>(AI->getArraySize())) hasStaticAllocas = true; else hasDynamicAllocas = true; } } // Finally, clone over the terminator. const TerminatorInst *OldTI = BB->getTerminator(); bool TerminatorDone = false; if (const BranchInst *BI = dyn_cast<BranchInst>(OldTI)) { if (BI->isConditional()) { // If the condition was a known constant in the callee... ConstantInt *Cond = dyn_cast<ConstantInt>(BI->getCondition()); // Or is a known constant in the caller... if (!Cond) { Value *V = VMap[BI->getCondition()]; Cond = dyn_cast_or_null<ConstantInt>(V); } // Constant fold to uncond branch! if (Cond) { BasicBlock *Dest = BI->getSuccessor(!Cond->getZExtValue()); VMap[OldTI] = BranchInst::Create(Dest, NewBB); ToClone.push_back(Dest); TerminatorDone = true; } } } else if (const SwitchInst *SI = dyn_cast<SwitchInst>(OldTI)) { // If switching on a value known constant in the caller. ConstantInt *Cond = dyn_cast<ConstantInt>(SI->getCondition()); if (!Cond) { // Or known constant after constant prop in the callee... Value *V = VMap[SI->getCondition()]; Cond = dyn_cast_or_null<ConstantInt>(V); } if (Cond) { // Constant fold to uncond branch! SwitchInst::ConstCaseIt Case = SI->findCaseValue(Cond); BasicBlock *Dest = const_cast<BasicBlock*>(Case.getCaseSuccessor()); VMap[OldTI] = BranchInst::Create(Dest, NewBB); ToClone.push_back(Dest); TerminatorDone = true; } } if (!TerminatorDone) { Instruction *NewInst = OldTI->clone(); if (OldTI->hasName()) NewInst->setName(OldTI->getName()+NameSuffix); NewBB->getInstList().push_back(NewInst); VMap[OldTI] = NewInst; // Add instruction map to value. if (CodeInfo) if (auto CS = ImmutableCallSite(OldTI)) if (CS.hasOperandBundles()) CodeInfo->OperandBundleCallSites.push_back(NewInst); // Recursively clone any reachable successor blocks. const TerminatorInst *TI = BB->getTerminator(); for (const BasicBlock *Succ : TI->successors()) ToClone.push_back(Succ); } if (CodeInfo) { CodeInfo->ContainsCalls |= hasCalls; CodeInfo->ContainsDynamicAllocas |= hasDynamicAllocas; CodeInfo->ContainsDynamicAllocas |= hasStaticAllocas && BB != &BB->getParent()->front(); } }
/// CloneBlock - The specified block is found to be reachable, clone it and /// anything that it can reach. void PruningFunctionCloner::CloneBlock(const BasicBlock *BB, std::vector<const BasicBlock*> &ToClone) { TrackingVH<Value> &BBEntry = VMap[BB]; // Have we already cloned this block? if (BBEntry) return; // Nope, clone it now. BasicBlock *NewBB; BBEntry = NewBB = BasicBlock::Create(BB->getContext()); if (BB->hasName()) NewBB->setName(BB->getName()+NameSuffix); // It is only legal to clone a function if a block address within that // function is never referenced outside of the function. Given that, we // want to map block addresses from the old function to block addresses in // the clone. (This is different from the generic ValueMapper // implementation, which generates an invalid blockaddress when // cloning a function.) // // Note that we don't need to fix the mapping for unreachable blocks; // the default mapping there is safe. if (BB->hasAddressTaken()) { Constant *OldBBAddr = BlockAddress::get(const_cast<Function*>(OldFunc), const_cast<BasicBlock*>(BB)); VMap[OldBBAddr] = BlockAddress::get(NewFunc, NewBB); } bool hasCalls = false, hasDynamicAllocas = false, hasStaticAllocas = false; // Loop over all instructions, and copy them over, DCE'ing as we go. This // loop doesn't include the terminator. for (BasicBlock::const_iterator II = BB->begin(), IE = --BB->end(); II != IE; ++II) { // If this instruction constant folds, don't bother cloning the instruction, // instead, just add the constant to the value map. if (Constant *C = ConstantFoldMappedInstruction(II)) { VMap[II] = C; continue; } Instruction *NewInst = II->clone(); if (II->hasName()) NewInst->setName(II->getName()+NameSuffix); NewBB->getInstList().push_back(NewInst); VMap[II] = NewInst; // Add instruction map to value. hasCalls |= (isa<CallInst>(II) && !isa<DbgInfoIntrinsic>(II)); if (const AllocaInst *AI = dyn_cast<AllocaInst>(II)) { if (isa<ConstantInt>(AI->getArraySize())) hasStaticAllocas = true; else hasDynamicAllocas = true; } } // Finally, clone over the terminator. const TerminatorInst *OldTI = BB->getTerminator(); bool TerminatorDone = false; if (const BranchInst *BI = dyn_cast<BranchInst>(OldTI)) { if (BI->isConditional()) { // If the condition was a known constant in the callee... ConstantInt *Cond = dyn_cast<ConstantInt>(BI->getCondition()); // Or is a known constant in the caller... if (Cond == 0) { Value *V = VMap[BI->getCondition()]; Cond = dyn_cast_or_null<ConstantInt>(V); } // Constant fold to uncond branch! if (Cond) { BasicBlock *Dest = BI->getSuccessor(!Cond->getZExtValue()); VMap[OldTI] = BranchInst::Create(Dest, NewBB); ToClone.push_back(Dest); TerminatorDone = true; } } } else if (const SwitchInst *SI = dyn_cast<SwitchInst>(OldTI)) { // If switching on a value known constant in the caller. ConstantInt *Cond = dyn_cast<ConstantInt>(SI->getCondition()); if (Cond == 0) { // Or known constant after constant prop in the callee... Value *V = VMap[SI->getCondition()]; Cond = dyn_cast_or_null<ConstantInt>(V); } if (Cond) { // Constant fold to uncond branch! SwitchInst::ConstCaseIt Case = SI->findCaseValue(Cond); BasicBlock *Dest = const_cast<BasicBlock*>(Case.getCaseSuccessor()); VMap[OldTI] = BranchInst::Create(Dest, NewBB); ToClone.push_back(Dest); TerminatorDone = true; } } if (!TerminatorDone) { Instruction *NewInst = OldTI->clone(); if (OldTI->hasName()) NewInst->setName(OldTI->getName()+NameSuffix); NewBB->getInstList().push_back(NewInst); VMap[OldTI] = NewInst; // Add instruction map to value. // Recursively clone any reachable successor blocks. const TerminatorInst *TI = BB->getTerminator(); for (unsigned i = 0, e = TI->getNumSuccessors(); i != e; ++i) ToClone.push_back(TI->getSuccessor(i)); } if (CodeInfo) { CodeInfo->ContainsCalls |= hasCalls; CodeInfo->ContainsDynamicAllocas |= hasDynamicAllocas; CodeInfo->ContainsDynamicAllocas |= hasStaticAllocas && BB != &BB->getParent()->front(); } if (ReturnInst *RI = dyn_cast<ReturnInst>(NewBB->getTerminator())) Returns.push_back(RI); }