bool RecurrenceDescriptor::getSourceExtensionKind( Instruction *Start, Instruction *Exit, Type *RT, bool &IsSigned, SmallPtrSetImpl<Instruction *> &Visited, SmallPtrSetImpl<Instruction *> &CI) { SmallVector<Instruction *, 8> Worklist; bool FoundOneOperand = false; unsigned DstSize = RT->getPrimitiveSizeInBits(); Worklist.push_back(Exit); // Traverse the instructions in the reduction expression, beginning with the // exit value. while (!Worklist.empty()) { Instruction *I = Worklist.pop_back_val(); for (Use &U : I->operands()) { // Terminate the traversal if the operand is not an instruction, or we // reach the starting value. Instruction *J = dyn_cast<Instruction>(U.get()); if (!J || J == Start) continue; // Otherwise, investigate the operation if it is also in the expression. if (Visited.count(J)) { Worklist.push_back(J); continue; } // If the operand is not in Visited, it is not a reduction operation, but // it does feed into one. Make sure it is either a single-use sign- or // zero-extend instruction. CastInst *Cast = dyn_cast<CastInst>(J); bool IsSExtInst = isa<SExtInst>(J); if (!Cast || !Cast->hasOneUse() || !(isa<ZExtInst>(J) || IsSExtInst)) return false; // Ensure the source type of the extend is no larger than the reduction // type. It is not necessary for the types to be identical. unsigned SrcSize = Cast->getSrcTy()->getPrimitiveSizeInBits(); if (SrcSize > DstSize) return false; // Furthermore, ensure that all such extends are of the same kind. if (FoundOneOperand) { if (IsSigned != IsSExtInst) return false; } else { FoundOneOperand = true; IsSigned = IsSExtInst; } // Lastly, if the source type of the extend matches the reduction type, // add the extend to CI so that we can avoid accounting for it in the // cost model. if (SrcSize == DstSize) CI.insert(Cast); } } return true; }
bool IRTranslator::translateCast(unsigned Opcode, const CastInst &CI) { unsigned Op = getOrCreateVReg(*CI.getOperand(0)); unsigned Res = getOrCreateVReg(CI); MIRBuilder.buildInstr(Opcode, {LLT{*CI.getDestTy()}, LLT{*CI.getSrcTy()}}) .addDef(Res) .addUse(Op); return true; }
bool IRTranslator::translateBitCast(const CastInst &CI) { if (LLT{*CI.getDestTy()} == LLT{*CI.getSrcTy()}) { MIRBuilder.buildCopy(getOrCreateVReg(CI), getOrCreateVReg(*CI.getOperand(0))); return true; } return translateCast(TargetOpcode::G_BITCAST, CI); }
void DSWP::insertProduce(Instruction *u, Instruction *v, DType dtype, int channel, int uthread, int vthread) { Function *fun = module->getFunction("sync_produce"); vector<Value *> args; Instruction *insPos = u->getNextNode(); if (insPos == NULL) { error("here cannot be null"); } //if (isa<BranchInst>(u)) { // error("I don't know how do deal with it"); // return; //} if (dtype == REG) { // register dep // cast the value to something that the communication guy likes CastInst *cast; if (u->getType()->isIntegerTy()) { cast = new ZExtInst(u, eleType, u->getName().str() + "_64"); } else if (u->getType()->isFloatingPointTy()) { if (u->getType()->isFloatTy()) { cout << "WARNING: float sucks?"; } cast = new BitCastInst(u, eleType, u->getName().str() + "_64"); } else if (u->getType()->isPointerTy()){ cast = new PtrToIntInst(u, eleType, u->getName().str() + "_64"); } else { error("what's the hell type"); } cast->insertBefore(insPos); args.push_back(cast); /* TODO: for true memory dependences, need to send anything or just sync? } else if (dtype == DTRUE) { // true dep error("check mem dep!!"); StoreInst *store = dyn_cast<StoreInst>(u); if (store == NULL) { error("not true dependency!"); } BitCastInst *cast = new BitCastInst(store->getOperand(0), Type::getInt8PtrTy(*context), u->getName().str() + "_ptr"); cast->insertBefore(insPos); args.push_back(cast); */ } else { // others // just send a dummy value for synchronization args.push_back(Constant::getNullValue(Type::getInt64Ty(*context))); } // channel ID args.push_back(ConstantInt::get(Type::getInt32Ty(*context), channel)); // make the actual call CallInst *call = CallInst::Create(fun, args, "", insPos); }
void Transformer4Trace::transformLoadInst(Module* module, LoadInst* inst, AliasAnalysis& AA) { Value * val = inst->getOperand(0); int svIdx = this->getValueIndex(module, val, AA); if (svIdx == -1) return; CastInst* c = CastInst::CreatePointerCast(val, Type::getIntNPtrTy(module->getContext(),POINTER_BIT_SIZE)); c->insertBefore(inst); Value* lnval = getOtInsertLineNumberValue(module, inst); this->insertCallInstBefore(inst, F_preload, c, lnval, getOrInsertSrcFileNameValue(module, inst), NULL); this->insertCallInstAfter(inst, F_load, c, lnval, getOrInsertSrcFileNameValue(module, inst), NULL); }
void Transformer4Trace::transformMemSet(Module* module, CallInst* call, AliasAnalysis& AA) { Value* lnval = getOtInsertLineNumberValue(module, call); Value * val = call->getArgOperand(0); int svIdx = this->getValueIndex(module, val, AA); if (svIdx == -1) return; CastInst* c = CastInst::CreatePointerCast(val, Type::getIntNPtrTy(module->getContext(),POINTER_BIT_SIZE)); c->insertBefore(call); insertCallInstBefore(call, F_prestore, c, lnval, getOrInsertSrcFileNameValue(module, call), NULL); insertCallInstAfter(call, F_store, c, lnval, getOrInsertSrcFileNameValue(module, call), NULL); }
/// If a value has only one user that is a CastInst, return it. Value *llvm::getUniqueCastUse(Value *Ptr, Loop *Lp, Type *Ty) { Value *UniqueCast = nullptr; for (User *U : Ptr->users()) { CastInst *CI = dyn_cast<CastInst>(U); if (CI && CI->getType() == Ty) { if (!UniqueCast) UniqueCast = CI; else return nullptr; } } return UniqueCast; }
bool CallAnalyzer::visitCastInst(CastInst &I) { // Propagate constants through ptrtoint. if (Constant *COp = dyn_cast<Constant>(I.getOperand(0))) if (Constant *C = ConstantExpr::getCast(I.getOpcode(), COp, I.getType())) { SimplifiedValues[&I] = C; return true; } // Disable SROA in the face of arbitrary casts we don't whitelist elsewhere. disableSROA(I.getOperand(0)); return isInstructionFree(&I, TD); }
/// Try to simplify cast instruction. bool UnrolledInstAnalyzer::visitCastInst(CastInst &I) { // Propagate constants through casts. Constant *COp = dyn_cast<Constant>(I.getOperand(0)); if (!COp) COp = SimplifiedValues.lookup(I.getOperand(0)); if (COp) if (Constant *C = ConstantExpr::getCast(I.getOpcode(), COp, I.getType())) { SimplifiedValues[&I] = C; return true; } return Base::visitCastInst(I); }
bool CallAnalyzer::visitCastInst(CastInst &I) { // Propagate constants through ptrtoint. Constant *COp = dyn_cast<Constant>(I.getOperand(0)); if (!COp) COp = SimplifiedValues.lookup(I.getOperand(0)); if (COp) if (Constant *C = ConstantExpr::getCast(I.getOpcode(), COp, I.getType())) { SimplifiedValues[&I] = C; return true; } // Disable SROA in the face of arbitrary casts we don't whitelist elsewhere. disableSROA(I.getOperand(0)); return TargetTransformInfo::TCC_Free == TTI.getUserCost(&I); }
bool Scalarizer::visitCastInst(CastInst &CI) { VectorType *VT = dyn_cast<VectorType>(CI.getDestTy()); if (!VT) return false; unsigned NumElems = VT->getNumElements(); IRBuilder<> Builder(CI.getParent(), &CI); Scatterer Op0 = scatter(&CI, CI.getOperand(0)); assert(Op0.size() == NumElems && "Mismatched cast"); ValueVector Res; Res.resize(NumElems); for (unsigned I = 0; I < NumElems; ++I) Res[I] = Builder.CreateCast(CI.getOpcode(), Op0[I], VT->getElementType(), CI.getName() + ".i" + Twine(I)); gather(&CI, Res); return true; }
bool CallAnalyzer::visitCastInst(CastInst &I) { // Propagate constants through ptrtoint. if (Constant *COp = dyn_cast<Constant>(I.getOperand(0))) if (Constant *C = ConstantExpr::getCast(I.getOpcode(), COp, I.getType())) { SimplifiedValues[&I] = C; return true; } // Disable SROA in the face of arbitrary casts we don't whitelist elsewhere. disableSROA(I.getOperand(0)); // No-op casts don't have any cost. if (I.isLosslessCast()) return true; // trunc to a native type is free (assuming the target has compare and // shift-right of the same width). if (TD && isa<TruncInst>(I) && TD->isLegalInteger(TD->getTypeSizeInBits(I.getType()))) return true; // Result of a cmp instruction is often extended (to be used by other // cmp instructions, logical or return instructions). These are usually // no-ops on most sane targets. if (isa<CmpInst>(I.getOperand(0))) return true; // Assume the rest of the casts require work. return false; }
void Transformer4Trace::transformPthreadCondSignal(Module* module, CallInst* call, AliasAnalysis& AA) { Value * val0 = call->getArgOperand(0); Value * val1 = call->getArgOperand(1); int svIdx0 = this->getValueIndex(module, val0, AA); int svIdx1 = this->getValueIndex(module, val1, AA); if (svIdx0 == -1 && svIdx1 == -1) return; CastInst* cond = CastInst::CreatePointerCast(val0, Type::getIntNPtrTy(module->getContext(),POINTER_BIT_SIZE)); cond->insertBefore(call); CastInst* mut = CastInst::CreatePointerCast(val1, Type::getIntNPtrTy(module->getContext(),POINTER_BIT_SIZE)); mut->insertBefore(call); Value* lnval = getOtInsertLineNumberValue(module, call); this->insertCallInstBefore(call, F_prenotify, cond, mut, lnval, getOrInsertSrcFileNameValue(module, call), NULL); this->insertCallInstAfter(call, F_notify, cond, mut, lnval, getOrInsertSrcFileNameValue(module, call), NULL); }
/// lowerIncomingArguments - To avoid having to handle incoming arguments /// specially, we lower each arg to a copy instruction in the entry block. This /// ensures that the argument value itself cannot be live out of the entry /// block. void SjLjEHPass::lowerIncomingArguments(Function &F) { BasicBlock::iterator AfterAllocaInsPt = F.begin()->begin(); while (isa<AllocaInst>(AfterAllocaInsPt) && isa<ConstantInt>(cast<AllocaInst>(AfterAllocaInsPt)->getArraySize())) ++AfterAllocaInsPt; for (Function::arg_iterator AI = F.arg_begin(), AE = F.arg_end(); AI != AE; ++AI) { Type *Ty = AI->getType(); // Aggregate types can't be cast, but are legal argument types, so we have // to handle them differently. We use an extract/insert pair as a // lightweight method to achieve the same goal. if (isa<StructType>(Ty) || isa<ArrayType>(Ty) || isa<VectorType>(Ty)) { Instruction *EI = ExtractValueInst::Create(AI, 0, "", AfterAllocaInsPt); Instruction *NI = InsertValueInst::Create(AI, EI, 0); NI->insertAfter(EI); AI->replaceAllUsesWith(NI); // Set the operand of the instructions back to the AllocaInst. EI->setOperand(0, AI); NI->setOperand(0, AI); } else { // This is always a no-op cast because we're casting AI to AI->getType() // so src and destination types are identical. BitCast is the only // possibility. CastInst *NC = new BitCastInst(AI, AI->getType(), AI->getName() + ".tmp", AfterAllocaInsPt); AI->replaceAllUsesWith(NC); // Set the operand of the cast instruction back to the AllocaInst. // Normally it's forbidden to replace a CastInst's operand because it // could cause the opcode to reflect an illegal conversion. However, we're // replacing it here with the same value it was constructed with. We do // this because the above replaceAllUsesWith() clobbered the operand, but // we want this one to remain. NC->setOperand(0, AI); } } }
void Transformer4Trace::transformOtherFunctionCalls(Module* module, CallInst* call, AliasAnalysis& AA) { Value* lnval = getOtInsertLineNumberValue(module, call); for (unsigned i = 0; i < call->getNumArgOperands(); i++) { Value * arg = call->getArgOperand(i); CastInst* c = NULL; if (arg->getType()->isPointerTy()) { c = CastInst::CreatePointerCast(arg, Type::getIntNPtrTy(module->getContext(),POINTER_BIT_SIZE)); c->insertBefore(call); } else { continue; } int svIdx = this->getValueIndex(module, arg, AA); if (svIdx != -1) { insertCallInstBefore(call, F_prestore, c, lnval, getOrInsertSrcFileNameValue(module, call), NULL); insertCallInstBefore(call, F_store, c, lnval, getOrInsertSrcFileNameValue(module, call), NULL); } } }
/// lowerIncomingArguments - To avoid having to handle incoming arguments /// specially, we lower each arg to a copy instruction in the entry block. This /// ensures that the argument value itself cannot be live out of the entry /// block. void SjLjEHPrepare::lowerIncomingArguments(Function &F) { BasicBlock::iterator AfterAllocaInsPt = F.begin()->begin(); while (isa<AllocaInst>(AfterAllocaInsPt) && isa<ConstantInt>(cast<AllocaInst>(AfterAllocaInsPt)->getArraySize())) ++AfterAllocaInsPt; for (Function::arg_iterator AI = F.arg_begin(), AE = F.arg_end(); AI != AE; ++AI) { Type *Ty = AI->getType(); if (isa<StructType>(Ty) || isa<ArrayType>(Ty)) { // Aggregate types can't be cast, but are legal argument types, // so we have to handle them differently. We use // select i8 true, %arg, undef to achieve the same goal Value *TrueValue = ConstantInt::getTrue(F.getContext()); Value *UndefValue = UndefValue::get(Ty); Instruction *SI = SelectInst::Create(TrueValue, AI, UndefValue, AI->getName() + ".tmp", AfterAllocaInsPt); AI->replaceAllUsesWith(SI); SI->setOperand(1, AI); } else { // This is always a no-op cast because we're casting AI to AI->getType() // so src and destination types are identical. BitCast is the only // possibility. CastInst *NC = new BitCastInst(AI, AI->getType(), AI->getName() + ".tmp", AfterAllocaInsPt); AI->replaceAllUsesWith(NC); // Set the operand of the cast instruction back to the AllocaInst. // Normally it's forbidden to replace a CastInst's operand because it // could cause the opcode to reflect an illegal conversion. However, we're // replacing it here with the same value it was constructed with. We do // this because the above replaceAllUsesWith() clobbered the operand, but // we want this one to remain. NC->setOperand(0, AI); } } }
/// store {atomic|volatile} T %val, T* %ptr memory_order, align sizeof(T) /// becomes: /// call void @llvm.nacl.atomic.store.i<size>(%val, %ptr, memory_order) void AtomicVisitor::visitStoreInst(StoreInst &I) { return; // XXX EMSCRIPTEN if (I.isSimple()) return; PointerHelper<StoreInst> PH(*this, I); const NaCl::AtomicIntrinsics::AtomicIntrinsic *Intrinsic = findAtomicIntrinsic(I, Intrinsic::nacl_atomic_store, PH.PET); checkAlignment(I, I.getAlignment(), PH.BitSize / CHAR_BIT); Value *V = I.getValueOperand(); if (!V->getType()->isIntegerTy()) { // The store isn't of an integer type. We define atomics in terms of // integers, so bitcast the value to store to an integer of the // proper width. CastInst *Cast = createCast(I, V, Type::getIntNTy(C, PH.BitSize), V->getName() + ".cast"); Cast->setDebugLoc(I.getDebugLoc()); V = Cast; } checkSizeMatchesType(I, PH.BitSize, V->getType()); Value *Args[] = {V, PH.P, freezeMemoryOrder(I, I.getOrdering())}; replaceInstructionWithIntrinsicCall(I, Intrinsic, PH.OriginalPET, PH.PET, Args); }
void Transformer4Trace::transformMemCpyMov(Module* module, CallInst* call, AliasAnalysis& AA) { Value* lnval = getOtInsertLineNumberValue(module, call); Value * dst = call->getArgOperand(0); Value * src = call->getArgOperand(1); int svIdx_dst = this->getValueIndex(module, dst, AA); int svIdx_src = this->getValueIndex(module, src, AA); if (svIdx_dst == -1 && svIdx_src == -1) { return; } else if (svIdx_dst != -1 && svIdx_src != -1) { CastInst* d = CastInst::CreatePointerCast(dst, Type::getIntNPtrTy(module->getContext(),POINTER_BIT_SIZE)); d->insertBefore(call); CastInst* s = CastInst::CreatePointerCast(src, Type::getIntNPtrTy(module->getContext(),POINTER_BIT_SIZE)); s->insertBefore(call); if (svIdx_dst != svIdx_src) { insertCallInstBefore(call, F_prestore, d, lnval, getOrInsertSrcFileNameValue(module, call), NULL); insertCallInstAfter(call, F_store, d, lnval, getOrInsertSrcFileNameValue(module, call), NULL); insertCallInstBefore(call, F_preload, s, lnval, getOrInsertSrcFileNameValue(module, call), NULL); insertCallInstAfter(call, F_load, s, lnval, getOrInsertSrcFileNameValue(module, call), NULL); } else { insertCallInstBefore(call, F_prestore, d, lnval, getOrInsertSrcFileNameValue(module, call), NULL); insertCallInstAfter(call, F_store, d, lnval, getOrInsertSrcFileNameValue(module, call), NULL); } } else if (svIdx_dst != -1) { CastInst* d = CastInst::CreatePointerCast(dst, Type::getIntNPtrTy(module->getContext(),POINTER_BIT_SIZE)); d->insertBefore(call); insertCallInstBefore(call, F_prestore, d, lnval, getOrInsertSrcFileNameValue(module, call), NULL); insertCallInstAfter(call, F_store, d, lnval, getOrInsertSrcFileNameValue(module, call), NULL); } else { CastInst* s = CastInst::CreatePointerCast(src, Type::getIntNPtrTy(module->getContext(),POINTER_BIT_SIZE)); s->insertBefore(call); insertCallInstBefore(call, F_preload, s, lnval, getOrInsertSrcFileNameValue(module, call), NULL); insertCallInstAfter(call, F_load, s, lnval, getOrInsertSrcFileNameValue(module, call), NULL); } }
/// Try to simplify cast instruction. bool UnrolledInstAnalyzer::visitCastInst(CastInst &I) { // Propagate constants through casts. Constant *COp = dyn_cast<Constant>(I.getOperand(0)); if (!COp) COp = SimplifiedValues.lookup(I.getOperand(0)); // If we know a simplified value for this operand and cast is valid, save the // result to SimplifiedValues. // The cast can be invalid, because SimplifiedValues contains results of SCEV // analysis, which operates on integers (and, e.g., might convert i8* null to // i32 0). if (COp && CastInst::castIsValid(I.getOpcode(), COp, I.getType())) { if (Constant *C = ConstantExpr::getCast(I.getOpcode(), COp, I.getType())) { SimplifiedValues[&I] = C; return true; } } return Base::visitCastInst(I); }
bool PPCCTRLoops::mightUseCTR(const Triple &TT, BasicBlock *BB) { for (BasicBlock::iterator J = BB->begin(), JE = BB->end(); J != JE; ++J) { if (CallInst *CI = dyn_cast<CallInst>(J)) { if (InlineAsm *IA = dyn_cast<InlineAsm>(CI->getCalledValue())) { // Inline ASM is okay, unless it clobbers the ctr register. InlineAsm::ConstraintInfoVector CIV = IA->ParseConstraints(); for (unsigned i = 0, ie = CIV.size(); i < ie; ++i) { InlineAsm::ConstraintInfo &C = CIV[i]; if (C.Type != InlineAsm::isInput) for (unsigned j = 0, je = C.Codes.size(); j < je; ++j) if (StringRef(C.Codes[j]).equals_lower("{ctr}")) return true; } continue; } if (!TM) return true; const TargetLowering *TLI = TM->getTargetLowering(); if (Function *F = CI->getCalledFunction()) { // Most intrinsics don't become function calls, but some might. // sin, cos, exp and log are always calls. unsigned Opcode; if (F->getIntrinsicID() != Intrinsic::not_intrinsic) { switch (F->getIntrinsicID()) { default: continue; // VisualStudio defines setjmp as _setjmp #if defined(_MSC_VER) && defined(setjmp) && \ !defined(setjmp_undefined_for_msvc) # pragma push_macro("setjmp") # undef setjmp # define setjmp_undefined_for_msvc #endif case Intrinsic::setjmp: #if defined(_MSC_VER) && defined(setjmp_undefined_for_msvc) // let's return it to _setjmp state # pragma pop_macro("setjmp") # undef setjmp_undefined_for_msvc #endif case Intrinsic::longjmp: // Exclude eh_sjlj_setjmp; we don't need to exclude eh_sjlj_longjmp // because, although it does clobber the counter register, the // control can't then return to inside the loop unless there is also // an eh_sjlj_setjmp. case Intrinsic::eh_sjlj_setjmp: case Intrinsic::memcpy: case Intrinsic::memmove: case Intrinsic::memset: case Intrinsic::powi: case Intrinsic::log: case Intrinsic::log2: case Intrinsic::log10: case Intrinsic::exp: case Intrinsic::exp2: case Intrinsic::pow: case Intrinsic::sin: case Intrinsic::cos: return true; case Intrinsic::copysign: if (CI->getArgOperand(0)->getType()->getScalarType()-> isPPC_FP128Ty()) return true; else continue; // ISD::FCOPYSIGN is never a library call. case Intrinsic::sqrt: Opcode = ISD::FSQRT; break; case Intrinsic::floor: Opcode = ISD::FFLOOR; break; case Intrinsic::ceil: Opcode = ISD::FCEIL; break; case Intrinsic::trunc: Opcode = ISD::FTRUNC; break; case Intrinsic::rint: Opcode = ISD::FRINT; break; case Intrinsic::nearbyint: Opcode = ISD::FNEARBYINT; break; case Intrinsic::round: Opcode = ISD::FROUND; break; } } // PowerPC does not use [US]DIVREM or other library calls for // operations on regular types which are not otherwise library calls // (i.e. soft float or atomics). If adapting for targets that do, // additional care is required here. LibFunc::Func Func; if (!F->hasLocalLinkage() && F->hasName() && LibInfo && LibInfo->getLibFunc(F->getName(), Func) && LibInfo->hasOptimizedCodeGen(Func)) { // Non-read-only functions are never treated as intrinsics. if (!CI->onlyReadsMemory()) return true; // Conversion happens only for FP calls. if (!CI->getArgOperand(0)->getType()->isFloatingPointTy()) return true; switch (Func) { default: return true; case LibFunc::copysign: case LibFunc::copysignf: continue; // ISD::FCOPYSIGN is never a library call. case LibFunc::copysignl: return true; case LibFunc::fabs: case LibFunc::fabsf: case LibFunc::fabsl: continue; // ISD::FABS is never a library call. case LibFunc::sqrt: case LibFunc::sqrtf: case LibFunc::sqrtl: Opcode = ISD::FSQRT; break; case LibFunc::floor: case LibFunc::floorf: case LibFunc::floorl: Opcode = ISD::FFLOOR; break; case LibFunc::nearbyint: case LibFunc::nearbyintf: case LibFunc::nearbyintl: Opcode = ISD::FNEARBYINT; break; case LibFunc::ceil: case LibFunc::ceilf: case LibFunc::ceill: Opcode = ISD::FCEIL; break; case LibFunc::rint: case LibFunc::rintf: case LibFunc::rintl: Opcode = ISD::FRINT; break; case LibFunc::round: case LibFunc::roundf: case LibFunc::roundl: Opcode = ISD::FROUND; break; case LibFunc::trunc: case LibFunc::truncf: case LibFunc::truncl: Opcode = ISD::FTRUNC; break; } MVT VTy = TLI->getSimpleValueType(CI->getArgOperand(0)->getType(), true); if (VTy == MVT::Other) return true; if (TLI->isOperationLegalOrCustom(Opcode, VTy)) continue; else if (VTy.isVector() && TLI->isOperationLegalOrCustom(Opcode, VTy.getScalarType())) continue; return true; } } return true; } else if (isa<BinaryOperator>(J) && J->getType()->getScalarType()->isPPC_FP128Ty()) { // Most operations on ppc_f128 values become calls. return true; } else if (isa<UIToFPInst>(J) || isa<SIToFPInst>(J) || isa<FPToUIInst>(J) || isa<FPToSIInst>(J)) { CastInst *CI = cast<CastInst>(J); if (CI->getSrcTy()->getScalarType()->isPPC_FP128Ty() || CI->getDestTy()->getScalarType()->isPPC_FP128Ty() || (TT.isArch32Bit() && (CI->getSrcTy()->getScalarType()->isIntegerTy(64) || CI->getDestTy()->getScalarType()->isIntegerTy(64)) )) return true; } else if (TT.isArch32Bit() && J->getType()->getScalarType()->isIntegerTy(64) && (J->getOpcode() == Instruction::UDiv || J->getOpcode() == Instruction::SDiv || J->getOpcode() == Instruction::URem || J->getOpcode() == Instruction::SRem)) { return true; } else if (isa<IndirectBrInst>(J) || isa<InvokeInst>(J)) { // On PowerPC, indirect jumps use the counter register. return true; } else if (SwitchInst *SI = dyn_cast<SwitchInst>(J)) { if (!TM) return true; const TargetLowering *TLI = TM->getTargetLowering(); if (TLI->supportJumpTables() && SI->getNumCases()+1 >= (unsigned) TLI->getMinimumJumpTableEntries()) return true; } } return false; }
/// splitLiveRangesAcrossInvokes - Each value that is live across an unwind edge /// we spill into a stack location, guaranteeing that there is nothing live /// across the unwind edge. This process also splits all critical edges /// coming out of invoke's. /// FIXME: Move this function to a common utility file (Local.cpp?) so /// both SjLj and LowerInvoke can use it. void SjLjEHPass:: splitLiveRangesAcrossInvokes(SmallVector<InvokeInst*,16> &Invokes) { // First step, split all critical edges from invoke instructions. for (unsigned i = 0, e = Invokes.size(); i != e; ++i) { InvokeInst *II = Invokes[i]; SplitCriticalEdge(II, 0, this); // FIXME: New EH - This if-condition will be always true in the new scheme. if (II->getUnwindDest()->isLandingPad()) { SmallVector<BasicBlock*, 2> NewBBs; SplitLandingPadPredecessors(II->getUnwindDest(), II->getParent(), ".1", ".2", this, NewBBs); LPadSuccMap[II] = *succ_begin(NewBBs[0]); } else { SplitCriticalEdge(II, 1, this); } assert(!isa<PHINode>(II->getNormalDest()) && !isa<PHINode>(II->getUnwindDest()) && "Critical edge splitting left single entry phi nodes?"); } Function *F = Invokes.back()->getParent()->getParent(); // To avoid having to handle incoming arguments specially, we lower each arg // to a copy instruction in the entry block. This ensures that the argument // value itself cannot be live across the entry block. BasicBlock::iterator AfterAllocaInsertPt = F->begin()->begin(); while (isa<AllocaInst>(AfterAllocaInsertPt) && isa<ConstantInt>(cast<AllocaInst>(AfterAllocaInsertPt)->getArraySize())) ++AfterAllocaInsertPt; for (Function::arg_iterator AI = F->arg_begin(), E = F->arg_end(); AI != E; ++AI) { Type *Ty = AI->getType(); // Aggregate types can't be cast, but are legal argument types, so we have // to handle them differently. We use an extract/insert pair as a // lightweight method to achieve the same goal. if (isa<StructType>(Ty) || isa<ArrayType>(Ty) || isa<VectorType>(Ty)) { Instruction *EI = ExtractValueInst::Create(AI, 0, "",AfterAllocaInsertPt); Instruction *NI = InsertValueInst::Create(AI, EI, 0); NI->insertAfter(EI); AI->replaceAllUsesWith(NI); // Set the operand of the instructions back to the AllocaInst. EI->setOperand(0, AI); NI->setOperand(0, AI); } else { // This is always a no-op cast because we're casting AI to AI->getType() // so src and destination types are identical. BitCast is the only // possibility. CastInst *NC = new BitCastInst( AI, AI->getType(), AI->getName()+".tmp", AfterAllocaInsertPt); AI->replaceAllUsesWith(NC); // Set the operand of the cast instruction back to the AllocaInst. // Normally it's forbidden to replace a CastInst's operand because it // could cause the opcode to reflect an illegal conversion. However, // we're replacing it here with the same value it was constructed with. // We do this because the above replaceAllUsesWith() clobbered the // operand, but we want this one to remain. NC->setOperand(0, AI); } } // Finally, scan the code looking for instructions with bad live ranges. for (Function::iterator BB = F->begin(), E = F->end(); BB != E; ++BB) for (BasicBlock::iterator II = BB->begin(), E = BB->end(); II != E; ++II) { // Ignore obvious cases we don't have to handle. In particular, most // instructions either have no uses or only have a single use inside the // current block. Ignore them quickly. Instruction *Inst = II; if (Inst->use_empty()) continue; if (Inst->hasOneUse() && cast<Instruction>(Inst->use_back())->getParent() == BB && !isa<PHINode>(Inst->use_back())) continue; // If this is an alloca in the entry block, it's not a real register // value. if (AllocaInst *AI = dyn_cast<AllocaInst>(Inst)) if (isa<ConstantInt>(AI->getArraySize()) && BB == F->begin()) continue; // Avoid iterator invalidation by copying users to a temporary vector. SmallVector<Instruction*,16> Users; for (Value::use_iterator UI = Inst->use_begin(), E = Inst->use_end(); UI != E; ++UI) { Instruction *User = cast<Instruction>(*UI); if (User->getParent() != BB || isa<PHINode>(User)) Users.push_back(User); } // Find all of the blocks that this value is live in. std::set<BasicBlock*> LiveBBs; LiveBBs.insert(Inst->getParent()); while (!Users.empty()) { Instruction *U = Users.back(); Users.pop_back(); if (!isa<PHINode>(U)) { MarkBlocksLiveIn(U->getParent(), LiveBBs); } else { // Uses for a PHI node occur in their predecessor block. PHINode *PN = cast<PHINode>(U); for (unsigned i = 0, e = PN->getNumIncomingValues(); i != e; ++i) if (PN->getIncomingValue(i) == Inst) MarkBlocksLiveIn(PN->getIncomingBlock(i), LiveBBs); } } // Now that we know all of the blocks that this thing is live in, see if // it includes any of the unwind locations. bool NeedsSpill = false; for (unsigned i = 0, e = Invokes.size(); i != e; ++i) { BasicBlock *UnwindBlock = Invokes[i]->getUnwindDest(); if (UnwindBlock != BB && LiveBBs.count(UnwindBlock)) { NeedsSpill = true; } } // If we decided we need a spill, do it. // FIXME: Spilling this way is overkill, as it forces all uses of // the value to be reloaded from the stack slot, even those that aren't // in the unwind blocks. We should be more selective. if (NeedsSpill) { ++NumSpilled; DemoteRegToStack(*Inst, true); } } }
bool PPCCTRLoops::mightUseCTR(BasicBlock *BB) { for (BasicBlock::iterator J = BB->begin(), JE = BB->end(); J != JE; ++J) { if (CallInst *CI = dyn_cast<CallInst>(J)) { // Inline ASM is okay, unless it clobbers the ctr register. if (InlineAsm *IA = dyn_cast<InlineAsm>(CI->getCalledValue())) { if (asmClobbersCTR(IA)) return true; continue; } if (Function *F = CI->getCalledFunction()) { // Most intrinsics don't become function calls, but some might. // sin, cos, exp and log are always calls. unsigned Opcode = 0; if (F->getIntrinsicID() != Intrinsic::not_intrinsic) { switch (F->getIntrinsicID()) { default: continue; // If we have a call to ppc_is_decremented_ctr_nonzero, or ppc_mtctr // we're definitely using CTR. case Intrinsic::ppc_is_decremented_ctr_nonzero: case Intrinsic::ppc_mtctr: return true; // VisualStudio defines setjmp as _setjmp #if defined(_MSC_VER) && defined(setjmp) && \ !defined(setjmp_undefined_for_msvc) # pragma push_macro("setjmp") # undef setjmp # define setjmp_undefined_for_msvc #endif case Intrinsic::setjmp: #if defined(_MSC_VER) && defined(setjmp_undefined_for_msvc) // let's return it to _setjmp state # pragma pop_macro("setjmp") # undef setjmp_undefined_for_msvc #endif case Intrinsic::longjmp: // Exclude eh_sjlj_setjmp; we don't need to exclude eh_sjlj_longjmp // because, although it does clobber the counter register, the // control can't then return to inside the loop unless there is also // an eh_sjlj_setjmp. case Intrinsic::eh_sjlj_setjmp: case Intrinsic::memcpy: case Intrinsic::memmove: case Intrinsic::memset: case Intrinsic::powi: case Intrinsic::log: case Intrinsic::log2: case Intrinsic::log10: case Intrinsic::exp: case Intrinsic::exp2: case Intrinsic::pow: case Intrinsic::sin: case Intrinsic::cos: return true; case Intrinsic::copysign: if (CI->getArgOperand(0)->getType()->getScalarType()-> isPPC_FP128Ty()) return true; else continue; // ISD::FCOPYSIGN is never a library call. case Intrinsic::sqrt: Opcode = ISD::FSQRT; break; case Intrinsic::floor: Opcode = ISD::FFLOOR; break; case Intrinsic::ceil: Opcode = ISD::FCEIL; break; case Intrinsic::trunc: Opcode = ISD::FTRUNC; break; case Intrinsic::rint: Opcode = ISD::FRINT; break; case Intrinsic::nearbyint: Opcode = ISD::FNEARBYINT; break; case Intrinsic::round: Opcode = ISD::FROUND; break; case Intrinsic::minnum: Opcode = ISD::FMINNUM; break; case Intrinsic::maxnum: Opcode = ISD::FMAXNUM; break; case Intrinsic::umul_with_overflow: Opcode = ISD::UMULO; break; case Intrinsic::smul_with_overflow: Opcode = ISD::SMULO; break; } } // PowerPC does not use [US]DIVREM or other library calls for // operations on regular types which are not otherwise library calls // (i.e. soft float or atomics). If adapting for targets that do, // additional care is required here. LibFunc Func; if (!F->hasLocalLinkage() && F->hasName() && LibInfo && LibInfo->getLibFunc(F->getName(), Func) && LibInfo->hasOptimizedCodeGen(Func)) { // Non-read-only functions are never treated as intrinsics. if (!CI->onlyReadsMemory()) return true; // Conversion happens only for FP calls. if (!CI->getArgOperand(0)->getType()->isFloatingPointTy()) return true; switch (Func) { default: return true; case LibFunc_copysign: case LibFunc_copysignf: continue; // ISD::FCOPYSIGN is never a library call. case LibFunc_copysignl: return true; case LibFunc_fabs: case LibFunc_fabsf: case LibFunc_fabsl: continue; // ISD::FABS is never a library call. case LibFunc_sqrt: case LibFunc_sqrtf: case LibFunc_sqrtl: Opcode = ISD::FSQRT; break; case LibFunc_floor: case LibFunc_floorf: case LibFunc_floorl: Opcode = ISD::FFLOOR; break; case LibFunc_nearbyint: case LibFunc_nearbyintf: case LibFunc_nearbyintl: Opcode = ISD::FNEARBYINT; break; case LibFunc_ceil: case LibFunc_ceilf: case LibFunc_ceill: Opcode = ISD::FCEIL; break; case LibFunc_rint: case LibFunc_rintf: case LibFunc_rintl: Opcode = ISD::FRINT; break; case LibFunc_round: case LibFunc_roundf: case LibFunc_roundl: Opcode = ISD::FROUND; break; case LibFunc_trunc: case LibFunc_truncf: case LibFunc_truncl: Opcode = ISD::FTRUNC; break; case LibFunc_fmin: case LibFunc_fminf: case LibFunc_fminl: Opcode = ISD::FMINNUM; break; case LibFunc_fmax: case LibFunc_fmaxf: case LibFunc_fmaxl: Opcode = ISD::FMAXNUM; break; } } if (Opcode) { EVT EVTy = TLI->getValueType(*DL, CI->getArgOperand(0)->getType(), true); if (EVTy == MVT::Other) return true; if (TLI->isOperationLegalOrCustom(Opcode, EVTy)) continue; else if (EVTy.isVector() && TLI->isOperationLegalOrCustom(Opcode, EVTy.getScalarType())) continue; return true; } } return true; } else if (isa<BinaryOperator>(J) && J->getType()->getScalarType()->isPPC_FP128Ty()) { // Most operations on ppc_f128 values become calls. return true; } else if (isa<UIToFPInst>(J) || isa<SIToFPInst>(J) || isa<FPToUIInst>(J) || isa<FPToSIInst>(J)) { CastInst *CI = cast<CastInst>(J); if (CI->getSrcTy()->getScalarType()->isPPC_FP128Ty() || CI->getDestTy()->getScalarType()->isPPC_FP128Ty() || isLargeIntegerTy(!TM->isPPC64(), CI->getSrcTy()->getScalarType()) || isLargeIntegerTy(!TM->isPPC64(), CI->getDestTy()->getScalarType())) return true; } else if (isLargeIntegerTy(!TM->isPPC64(), J->getType()->getScalarType()) && (J->getOpcode() == Instruction::UDiv || J->getOpcode() == Instruction::SDiv || J->getOpcode() == Instruction::URem || J->getOpcode() == Instruction::SRem)) { return true; } else if (!TM->isPPC64() && isLargeIntegerTy(false, J->getType()->getScalarType()) && (J->getOpcode() == Instruction::Shl || J->getOpcode() == Instruction::AShr || J->getOpcode() == Instruction::LShr)) { // Only on PPC32, for 128-bit integers (specifically not 64-bit // integers), these might be runtime calls. return true; } else if (isa<IndirectBrInst>(J) || isa<InvokeInst>(J)) { // On PowerPC, indirect jumps use the counter register. return true; } else if (SwitchInst *SI = dyn_cast<SwitchInst>(J)) { if (SI->getNumCases() + 1 >= (unsigned)TLI->getMinimumJumpTableEntries()) return true; } // FREM is always a call. if (J->getOpcode() == Instruction::FRem) return true; if (STI->useSoftFloat()) { switch(J->getOpcode()) { case Instruction::FAdd: case Instruction::FSub: case Instruction::FMul: case Instruction::FDiv: case Instruction::FPTrunc: case Instruction::FPExt: case Instruction::FPToUI: case Instruction::FPToSI: case Instruction::UIToFP: case Instruction::SIToFP: case Instruction::FCmp: return true; } } for (Value *Operand : J->operands()) if (memAddrUsesCTR(*TM, Operand)) return true; } return false; }
// First thing we need to do is scan the whole function for values that are // live across unwind edges. Each value that is live across an unwind edge // we spill into a stack location, guaranteeing that there is nothing live // across the unwind edge. This process also splits all critical edges // coming out of invoke's. void LowerInvoke:: splitLiveRangesLiveAcrossInvokes(std::vector<InvokeInst*> &Invokes) { // First step, split all critical edges from invoke instructions. for (unsigned i = 0, e = Invokes.size(); i != e; ++i) { InvokeInst *II = Invokes[i]; SplitCriticalEdge(II, 0, this); SplitCriticalEdge(II, 1, this); assert(!isa<PHINode>(II->getNormalDest()) && !isa<PHINode>(II->getUnwindDest()) && "critical edge splitting left single entry phi nodes?"); } Function *F = Invokes.back()->getParent()->getParent(); // To avoid having to handle incoming arguments specially, we lower each arg // to a copy instruction in the entry block. This ensures that the argument // value itself cannot be live across the entry block. BasicBlock::iterator AfterAllocaInsertPt = F->begin()->begin(); while (isa<AllocaInst>(AfterAllocaInsertPt) && isa<ConstantInt>(cast<AllocaInst>(AfterAllocaInsertPt)->getArraySize())) ++AfterAllocaInsertPt; for (Function::arg_iterator AI = F->arg_begin(), E = F->arg_end(); AI != E; ++AI) { // This is always a no-op cast because we're casting AI to AI->getType() so // src and destination types are identical. BitCast is the only possibility. CastInst *NC = new BitCastInst( AI, AI->getType(), AI->getName()+".tmp", AfterAllocaInsertPt); AI->replaceAllUsesWith(NC); // Normally its is forbidden to replace a CastInst's operand because it // could cause the opcode to reflect an illegal conversion. However, we're // replacing it here with the same value it was constructed with to simply // make NC its user. NC->setOperand(0, AI); } // Finally, scan the code looking for instructions with bad live ranges. for (Function::iterator BB = F->begin(), E = F->end(); BB != E; ++BB) for (BasicBlock::iterator II = BB->begin(), E = BB->end(); II != E; ++II) { // Ignore obvious cases we don't have to handle. In particular, most // instructions either have no uses or only have a single use inside the // current block. Ignore them quickly. Instruction *Inst = II; if (Inst->use_empty()) continue; if (Inst->hasOneUse() && cast<Instruction>(Inst->use_back())->getParent() == BB && !isa<PHINode>(Inst->use_back())) continue; // If this is an alloca in the entry block, it's not a real register // value. if (AllocaInst *AI = dyn_cast<AllocaInst>(Inst)) if (isa<ConstantInt>(AI->getArraySize()) && BB == F->begin()) continue; // Avoid iterator invalidation by copying users to a temporary vector. std::vector<Instruction*> Users; for (Value::use_iterator UI = Inst->use_begin(), E = Inst->use_end(); UI != E; ++UI) { Instruction *User = cast<Instruction>(*UI); if (User->getParent() != BB || isa<PHINode>(User)) Users.push_back(User); } // Scan all of the uses and see if the live range is live across an unwind // edge. If we find a use live across an invoke edge, create an alloca // and spill the value. std::set<InvokeInst*> InvokesWithStoreInserted; // Find all of the blocks that this value is live in. std::set<BasicBlock*> LiveBBs; LiveBBs.insert(Inst->getParent()); while (!Users.empty()) { Instruction *U = Users.back(); Users.pop_back(); if (!isa<PHINode>(U)) { MarkBlocksLiveIn(U->getParent(), LiveBBs); } else { // Uses for a PHI node occur in their predecessor block. PHINode *PN = cast<PHINode>(U); for (unsigned i = 0, e = PN->getNumIncomingValues(); i != e; ++i) if (PN->getIncomingValue(i) == Inst) MarkBlocksLiveIn(PN->getIncomingBlock(i), LiveBBs); } } // Now that we know all of the blocks that this thing is live in, see if // it includes any of the unwind locations. bool NeedsSpill = false; for (unsigned i = 0, e = Invokes.size(); i != e; ++i) { BasicBlock *UnwindBlock = Invokes[i]->getUnwindDest(); if (UnwindBlock != BB && LiveBBs.count(UnwindBlock)) { NeedsSpill = true; } } // If we decided we need a spill, do it. if (NeedsSpill) { ++NumSpilled; DemoteRegToStack(*Inst, true); } } }
void Interpreter::visitCastInst(CastInst &I) { ExecutionContext &SF = ECStack.back(); SetValue(&I, executeCastOperation(I.getOperand(0), I.getType(), SF), SF); }
void DSWP::insertConsume(Instruction *u, Instruction *v, DType dtype, int channel, int uthread, int vthread) { Instruction *oldu = dyn_cast<Instruction>(newToOld[u]); Instruction *insPos = placeEquivalents[vthread][oldu]; if (insPos == NULL) { insPos = dyn_cast<Instruction>(instMap[vthread][oldu]); if (insPos == NULL) { error("can't insert nowhere"); } } // call sync_consume(channel) Function *fun = module->getFunction("sync_consume"); vector<Value *> args; args.push_back(ConstantInt::get(Type::getInt32Ty(*context), channel)); CallInst *call = CallInst::Create(fun, args, "c" + itoa(channel), insPos); if (dtype == REG) { CastInst *cast; string name = call->getName().str() + "_val"; if (u->getType()->isIntegerTy()) { cast = new TruncInst(call, u->getType(), name); } else if (u->getType()->isFloatingPointTy()) { if (u->getType()->isFloatTy()) error("cannot deal with double"); cast = new BitCastInst(call, u->getType(), name); } else if (u->getType()->isPointerTy()){ cast = new IntToPtrInst(call, u->getType(), name); } else { error("what's the hell type"); } cast->insertBefore(insPos); // replace the uses for (Instruction::use_iterator ui = oldu->use_begin(), ue = oldu->use_end(); ui != ue; ++ui) { Instruction *user = dyn_cast<Instruction>(*ui); if (user == NULL) { error("used by a non-instruction?"); } // make sure it's in the same function... if (user->getParent()->getParent() != v->getParent()->getParent()) { continue; } // call replaceUses so that it handles phi nodes map<Value *, Value *> reps; reps[oldu] = cast; replaceUses(user, reps); } } /* TODO: need to handle true memory dependences more than just syncing? else if (dtype == DTRUE) { //READ after WRITE error("check mem dep!!"); if (!isa<LoadInst>(v)) { error("not true dependency"); } BitCastInst *cast = new BitCastInst(call, v->getType(), call->getName().str() + "_ptr"); cast->insertBefore(v); // replace the v with 'cast' in v's thread: // (other thread with be dealed using dependence) for (Instruction::use_iterator ui = v->use_begin(), ue = v->use_end(); ui != ue; ui++) { Instruction *user = dyn_cast<Instruction>(*ui); if (user == NULL) { error("how could it be NULL"); } // int userthread = this->getNewInstAssigned(user); if (user->getParent()->getParent() != v->getParent()->getParent()) { continue; } for (unsigned i = 0; i < user->getNumOperands(); i++) { Value * op = user->getOperand(i); if (op == v) { user->setOperand(i, cast); } } } } */ else { // nothing to do } }
/** * Inserts an argument. * @param rw_newInstr rewrite rule - new instruction * @param I instruction * @param CalleeF function to be called * @param variables map of found parameters from config * @param where position of the placement of the new instruction * @return a vector of arguments for the call that is to be inserted * and a pointer to the instruction after/before the new call * is going to be inserted (it is either I or some newly added * argument) */ tuple<vector<Value *>, Instruction*> InsertArgument(InstrumentInstruction rw_newInstr, Instruction *I, Function* CalleeF, const map <string, Value*>& variables, InstrumentPlacement where) { std::vector<Value *> args; unsigned i = 0; Instruction* nI = I; for (const string& arg : rw_newInstr.parameters) { if (i == rw_newInstr.parameters.size() - 1) { break; } auto var = variables.find(arg); if (var == variables.end()) { // NOTE: in future think also about other types than ConstantInt int argInt; try { argInt = stoi(arg); LLVMContext &Context = getGlobalContext(); Value *intValue = ConstantInt::get(Type::getInt32Ty(Context), argInt); args.push_back(intValue); } catch (invalid_argument) { logger.write_error("Problem with instruction arguments: invalid argument."); } catch (out_of_range) { logger.write_error("Problem with instruction arguments: out of range."); } } else { unsigned argIndex = 0; for (Function::ArgumentListType::iterator sit=CalleeF->getArgumentList().begin(); sit != CalleeF->getArgumentList().end(); ++sit) { Value *argV = &*sit; if (i == argIndex) { if (argV->getType() != var->second->getType()) { //TODO other types? if (!var->second->getType()->isPtrOrPtrVectorTy() && !var->second->getType()->isIntegerTy()) { args.push_back(var->second); } else { CastInst *CastI; if (var->second->getType()->isPtrOrPtrVectorTy()) { CastI = CastInst::CreatePointerCast(var->second, argV->getType()); } else { CastI = CastInst::CreateIntegerCast(var->second, argV->getType(), true); //TODO do something about signed argument } if (Instruction *Inst = dyn_cast<Instruction>(var->second)) CloneMetadata(Inst, CastI); if (where == InstrumentPlacement::BEFORE) { // we want to insert before I, that is: // %c = cast ... // newInstr // I // // NOTE that we do not set nI in this case, // so that the new instruction that we will insert // is inserted before I (and after all arguments // we added here) CastI->insertBefore(I); } else { // we want to insert after I, that is: // I // %c = cast ... // newInstr // // --> we must update the nI, so that the new // instruction is inserted after the arguments CastI->insertAfter(I); nI = CastI; } args.push_back(CastI); } } else{ args.push_back(var->second); } break; } argIndex++; } } i++; } return make_tuple(args,nI); }
void vSSA::createSigmasIfNeeded(BasicBlock *BB) { TerminatorInst *ti = BB->getTerminator(); // If the condition used in the terminator instruction is a Comparison instruction: //for each operand of the CmpInst, create sigmas, depending on some conditions /* if(isa<BranchInst>(ti)){ BranchInst * bc = cast<BranchInst>(ti); if(bc->isConditional()){ Value * cond = bc->getCondition(); CmpInst *comparison = dyn_cast<CmpInst>(cond); for (User::const_op_iterator it = comparison->op_begin(), e = comparison->op_end(); it != e; ++it) { Value *operand = *it; if (isa<Instruction>(operand) || isa<Argument>(operand)) { insertSigmas(ti, operand); } } } } */ // CASE 1: Branch Instruction BranchInst *bi = NULL; SwitchInst *si = NULL; if ((bi = dyn_cast<BranchInst>(ti))) { if (bi->isConditional()) { Value *condition = bi->getCondition(); ICmpInst *comparison = dyn_cast<ICmpInst>(condition); if (comparison) { // Create sigmas for ICmp operands for (User::const_op_iterator opit = comparison->op_begin(), opend = comparison->op_end(); opit != opend; ++opit) { Value *operand = *opit; if (isa<Instruction>(operand) || isa<Argument>(operand)) { insertSigmas(ti, operand); // If the operand is a result of a indirect instruction (e.g. ZExt, SExt, Trunc), // Create sigmas for the operands of the operands too CastInst *cinst = NULL; if ((cinst = dyn_cast<CastInst>(operand))) { insertSigmas(ti, cinst->getOperand(0)); } } } } } } // CASE 2: Switch Instruction else if ((si = dyn_cast<SwitchInst>(ti))) { Value *condition = si->getCondition(); if (isa<Instruction>(condition) || isa<Argument>(condition)) { insertSigmas(ti, condition); // If the operand is a result of a indirect instruction (e.g. ZExt, SExt, Trunc), // Create sigmas for the operands of the operands too CastInst *cinst = NULL; if ((cinst = dyn_cast<CastInst>(condition))) { insertSigmas(ti, cinst->getOperand(0)); } } } }
bool TypeChecksOpt::runOnModule(Module &M) { TS = &getAnalysis<dsa::TypeSafety<TDDataStructures> >(); // Create the necessary prototypes VoidTy = IntegerType::getVoidTy(M.getContext()); Int8Ty = IntegerType::getInt8Ty(M.getContext()); Int32Ty = IntegerType::getInt32Ty(M.getContext()); Int64Ty = IntegerType::getInt64Ty(M.getContext()); VoidPtrTy = PointerType::getUnqual(Int8Ty); TypeTagTy = Int8Ty; TypeTagPtrTy = PointerType::getUnqual(TypeTagTy); Constant *memsetF = M.getOrInsertFunction ("llvm.memset.i64", VoidTy, VoidPtrTy, Int8Ty, Int64Ty, Int32Ty, NULL); trackGlobal = M.getOrInsertFunction("trackGlobal", VoidTy, VoidPtrTy,/*ptr*/ TypeTagTy,/*type*/ Int64Ty,/*size*/ Int32Ty,/*tag*/ NULL); trackInitInst = M.getOrInsertFunction("trackInitInst", VoidTy, VoidPtrTy,/*ptr*/ Int64Ty,/*size*/ Int32Ty,/*tag*/ NULL); trackUnInitInst = M.getOrInsertFunction("trackUnInitInst", VoidTy, VoidPtrTy,/*ptr*/ Int64Ty,/*size*/ Int32Ty,/*tag*/ NULL); trackStoreInst = M.getOrInsertFunction("trackStoreInst", VoidTy, VoidPtrTy,/*ptr*/ TypeTagTy,/*type*/ Int64Ty,/*size*/ Int32Ty,/*tag*/ NULL); checkTypeInst = M.getOrInsertFunction("checkType", VoidTy, TypeTagTy,/*type*/ Int64Ty,/*size*/ TypeTagPtrTy, VoidPtrTy,/*ptr*/ Int32Ty,/*tag*/ NULL); copyTypeInfo = M.getOrInsertFunction("copyTypeInfo", VoidTy, VoidPtrTy,/*dest ptr*/ VoidPtrTy,/*src ptr*/ Int64Ty,/*size*/ Int32Ty,/*tag*/ NULL); setTypeInfo = M.getOrInsertFunction("setTypeInfo", VoidTy, VoidPtrTy,/*dest ptr*/ TypeTagPtrTy,/*metadata*/ Int64Ty,/*size*/ TypeTagTy, VoidPtrTy, Int32Ty,/*tag*/ NULL); trackStringInput = M.getOrInsertFunction("trackStringInput", VoidTy, VoidPtrTy, Int32Ty, NULL); getTypeTag = M.getOrInsertFunction("getTypeTag", VoidTy, VoidPtrTy, /*ptr*/ Int64Ty, /*size*/ TypeTagPtrTy, /*dest for type tag*/ Int32Ty, /*tag*/ NULL); MallocFunc = M.getFunction("malloc"); for(Value::use_iterator User = trackGlobal->use_begin(); User != trackGlobal->use_end(); ++User) { CallInst *CI = dyn_cast<CallInst>(*User); assert(CI); if(TS->isTypeSafe(CI->getOperand(1)->stripPointerCasts(), CI->getParent()->getParent())) { std::vector<Value*>Args; Args.push_back(CI->getOperand(1)); Args.push_back(CI->getOperand(3)); Args.push_back(CI->getOperand(4)); CallInst::Create(trackInitInst, Args, "", CI); toDelete.push_back(CI); } } for(Value::use_iterator User = checkTypeInst->use_begin(); User != checkTypeInst->use_end(); ++User) { CallInst *CI = dyn_cast<CallInst>(*User); assert(CI); if(TS->isTypeSafe(CI->getOperand(4)->stripPointerCasts(), CI->getParent()->getParent())) { toDelete.push_back(CI); } } for(Value::use_iterator User = trackStoreInst->use_begin(); User != trackStoreInst->use_end(); ++User) { CallInst *CI = dyn_cast<CallInst>(*User); assert(CI); if(TS->isTypeSafe(CI->getOperand(1)->stripPointerCasts(), CI->getParent()->getParent())) { toDelete.push_back(CI); } } // for alloca's if they are type known // assume initialized with TOP for(Value::use_iterator User = trackUnInitInst->use_begin(); User != trackUnInitInst->use_end(); ) { CallInst *CI = dyn_cast<CallInst>(*(User++)); assert(CI); // check if operand is an alloca inst. if(TS->isTypeSafe(CI->getOperand(1)->stripPointerCasts(), CI->getParent()->getParent())) { CI->setCalledFunction(trackInitInst); if(AllocaInst *AI = dyn_cast<AllocaInst>(CI->getOperand(1)->stripPointerCasts())) { // Initialize the allocation to NULL std::vector<Value *> Args2; Args2.push_back(CI->getOperand(1)); Args2.push_back(ConstantInt::get(Int8Ty, 0)); Args2.push_back(CI->getOperand(2)); Args2.push_back(ConstantInt::get(Int32Ty, AI->getAlignment())); CallInst::Create(memsetF, Args2, "", CI); } } } if(MallocFunc) { for(Value::use_iterator User = MallocFunc->use_begin(); User != MallocFunc->use_end(); User ++) { CallInst *CI = dyn_cast<CallInst>(*User); if(!CI) continue; if(TS->isTypeSafe(CI, CI->getParent()->getParent())){ CastInst *BCI = BitCastInst::CreatePointerCast(CI, VoidPtrTy); CastInst *Size = CastInst::CreateSExtOrBitCast(CI->getOperand(1), Int64Ty); Size->insertAfter(CI); BCI->insertAfter(Size); std::vector<Value *>Args; Args.push_back(BCI); Args.push_back(Size); Args.push_back(ConstantInt::get(Int32Ty, 0)); CallInst *CINew = CallInst::Create(trackInitInst, Args); CINew->insertAfter(BCI); } } } // also do for mallocs/calloc/other allocators??? // other allocators?? for(Value::use_iterator User = copyTypeInfo->use_begin(); User != copyTypeInfo->use_end(); ++User) { CallInst *CI = dyn_cast<CallInst>(*User); assert(CI); if(TS->isTypeSafe(CI->getOperand(1)->stripPointerCasts(), CI->getParent()->getParent())) { std::vector<Value*> Args; Args.push_back(CI->getOperand(1)); Args.push_back(CI->getOperand(3)); // size Args.push_back(CI->getOperand(4)); CallInst::Create(trackInitInst, Args, "", CI); toDelete.push_back(CI); } } for(Value::use_iterator User = setTypeInfo->use_begin(); User != setTypeInfo->use_end(); ++User) { CallInst *CI = dyn_cast<CallInst>(*User); assert(CI); if(TS->isTypeSafe(CI->getOperand(1)->stripPointerCasts(), CI->getParent()->getParent())) { std::vector<Value*> Args; Args.push_back(CI->getOperand(1)); Args.push_back(CI->getOperand(3)); // size Args.push_back(CI->getOperand(6)); CallInst::Create(trackInitInst, Args, "", CI); toDelete.push_back(CI); } } for(Value::use_iterator User = getTypeTag->use_begin(); User != getTypeTag->use_end(); ++User) { CallInst *CI = dyn_cast<CallInst>(*User); assert(CI); if(TS->isTypeSafe(CI->getOperand(1)->stripPointerCasts(), CI->getParent()->getParent())) { AllocaInst *AI = dyn_cast<AllocaInst>(CI->getOperand(3)->stripPointerCasts()); assert(AI); std::vector<Value*>Args; Args.push_back(CI->getOperand(3)); Args.push_back(ConstantInt::get(Int8Ty, 255)); Args.push_back(CI->getOperand(2)); Args.push_back(ConstantInt::get(Int32Ty, AI->getAlignment())); CallInst::Create(memsetF, Args, "", CI); toDelete.push_back(CI); } } numSafe += toDelete.size(); while(!toDelete.empty()) { Instruction *I = toDelete.back(); toDelete.pop_back(); I->eraseFromParent(); } return (numSafe > 0); }
/// InsertPHITranslatedPointer - Insert a computation of the PHI translated /// version of 'V' for the edge PredBB->CurBB into the end of the PredBB /// block. All newly created instructions are added to the NewInsts list. /// This returns null on failure. /// Value *PHITransAddr:: InsertPHITranslatedSubExpr(Value *InVal, BasicBlock *CurBB, BasicBlock *PredBB, const DominatorTree &DT, SmallVectorImpl<Instruction*> &NewInsts) { // See if we have a version of this value already available and dominating // PredBB. If so, there is no need to insert a new instance of it. PHITransAddr Tmp(InVal, DL, AC); if (!Tmp.PHITranslateValue(CurBB, PredBB, &DT, /*MustDominate=*/true)) return Tmp.getAddr(); // We don't need to PHI translate values which aren't instructions. auto *Inst = dyn_cast<Instruction>(InVal); if (!Inst) return nullptr; // Handle cast of PHI translatable value. if (CastInst *Cast = dyn_cast<CastInst>(Inst)) { if (!isSafeToSpeculativelyExecute(Cast)) return nullptr; Value *OpVal = InsertPHITranslatedSubExpr(Cast->getOperand(0), CurBB, PredBB, DT, NewInsts); if (!OpVal) return nullptr; // Otherwise insert a cast at the end of PredBB. CastInst *New = CastInst::Create(Cast->getOpcode(), OpVal, InVal->getType(), InVal->getName() + ".phi.trans.insert", PredBB->getTerminator()); New->setDebugLoc(Inst->getDebugLoc()); NewInsts.push_back(New); return New; } // Handle getelementptr with at least one PHI operand. if (GetElementPtrInst *GEP = dyn_cast<GetElementPtrInst>(Inst)) { SmallVector<Value*, 8> GEPOps; BasicBlock *CurBB = GEP->getParent(); for (unsigned i = 0, e = GEP->getNumOperands(); i != e; ++i) { Value *OpVal = InsertPHITranslatedSubExpr(GEP->getOperand(i), CurBB, PredBB, DT, NewInsts); if (!OpVal) return nullptr; GEPOps.push_back(OpVal); } GetElementPtrInst *Result = GetElementPtrInst::Create( GEP->getSourceElementType(), GEPOps[0], makeArrayRef(GEPOps).slice(1), InVal->getName() + ".phi.trans.insert", PredBB->getTerminator()); Result->setDebugLoc(Inst->getDebugLoc()); Result->setIsInBounds(GEP->isInBounds()); NewInsts.push_back(Result); return Result; } #if 0 // FIXME: This code works, but it is unclear that we actually want to insert // a big chain of computation in order to make a value available in a block. // This needs to be evaluated carefully to consider its cost trade offs. // Handle add with a constant RHS. if (Inst->getOpcode() == Instruction::Add && isa<ConstantInt>(Inst->getOperand(1))) { // PHI translate the LHS. Value *OpVal = InsertPHITranslatedSubExpr(Inst->getOperand(0), CurBB, PredBB, DT, NewInsts); if (OpVal == 0) return 0; BinaryOperator *Res = BinaryOperator::CreateAdd(OpVal, Inst->getOperand(1), InVal->getName()+".phi.trans.insert", PredBB->getTerminator()); Res->setHasNoSignedWrap(cast<BinaryOperator>(Inst)->hasNoSignedWrap()); Res->setHasNoUnsignedWrap(cast<BinaryOperator>(Inst)->hasNoUnsignedWrap()); NewInsts.push_back(Res); return Res; } #endif return nullptr; }
bool partition::runOnLoop(Loop* L, LPPassManager &LPM) { errs() << "*************************** Loop encountered: ************************" << '\n' << L->getHeader()->getName() << '\n'; if (function->getName() != "main") return false; IntegerType* int32Ty = Type::getInt32Ty(*context); IntegerType* int64Ty = Type::getInt64Ty(*context); PointerType* voidPtrTy = Type::getInt8PtrTy(*context); FunctionType* funcTy = FunctionType::get(int32Ty, false); Constant* func1_c; Function* func1; func1_c = module->getOrInsertFunction("func1", funcTy); func1 = cast<Function>(func1_c); Function* pro = module->getFunction("produce"); Function* con = module->getFunction("consume"); BasicBlock* func1EntryBlock = BasicBlock::Create(*context, "entry.func1", func1); AllocaInst* i_var = new AllocaInst(int32Ty, NULL, 4, "i", func1EntryBlock); Value* liveIn; BasicBlock *forCond, *forBody, *forInc; ValueToValueMapTy VMap; std::map<BasicBlock *, BasicBlock *> BlockMap; for (Loop::block_iterator BB = L->block_begin(), BBe = L->block_end(); BB != BBe; ++BB) { BasicBlock* func1Block = CloneBasicBlock(*BB, VMap, ".func1", func1); BlockMap[*BB] = func1Block; if ((*BB)->getName() == "for.cond") forCond = func1Block; if ((*BB)->getName() == "for.body") forBody = func1Block; if ((*BB)->getName() == "for.inc") forInc = func1Block; for (BasicBlock::iterator it = func1Block->begin(), ite = func1Block->end(); it != ite; ++it) { for (User::op_iterator oit = it->op_begin(), oite = it->op_end(); oit != oite; ++oit) { if (VMap[*oit] != NULL) { *oit = VMap[*oit]; } else { Constant* cons = dyn_cast<Constant>(*oit); BranchInst* br = dyn_cast<BranchInst>(it); if (cons == NULL && br == NULL) { liveIn = *oit; *oit = i_var; } } } } if ((*BB)->getName() == "for.body") { Instruction* term = (*BB)->getTerminator(); term->removeFromParent(); for (int i = 0; i < 7; i++) { (*BB)->back().eraseFromParent(); } term->insertAfter(&(*BB)->back()); (*BB)->front().eraseFromParent(); LoadInst* load = new LoadInst(liveIn, "", false, 4, term); std::vector<Value *> produce_args; CastInst* cast = CastInst::CreateIntegerCast(load, int64Ty, true); cast->insertAfter(load); produce_args.push_back(cast); ConstantInt* val = ConstantInt::get(int32Ty, (uint32_t) 3); produce_args.push_back(val); CallInst::Create(pro, ArrayRef<Value*>(produce_args), "", term); produce_args.pop_back(); val = ConstantInt::get(int32Ty, (uint32_t) 2); produce_args.push_back(val); CallInst::Create(pro, ArrayRef<Value*>(produce_args), "", term); } } // set branch instructions to restructure the CFG in created function BasicBlock* func1EndBlock = BasicBlock::Create(*context, "if.end.func1", func1); BasicBlock* garbageBB = BasicBlock::Create(*context, "garbage", func1); ConstantInt* retVal_g = ConstantInt::get(int32Ty, (uint32_t) 0); ReturnInst* ret_g = ReturnInst::Create(*context, retVal_g, garbageBB); for (Function::iterator fit = func1->begin(), fite = func1->end(); fit != fite; ++fit) { if (fit->getTerminator() == NULL || fit->getName() == "garbage") continue; BranchInst* br = dyn_cast<BranchInst>(fit->getTerminator()); int numSuccessors = br->getNumSuccessors(); for (int i = 0; i < numSuccessors; i++) { BasicBlock* successor = br->getSuccessor(i); if (BlockMap[successor] != NULL) { br->setSuccessor(i, BlockMap[successor]); } else { br->setSuccessor(i, func1EndBlock); } } /* if (fit->getName() == "for.body.func1") { for (int i = 0; i < 4; i++) { BasicBlock::iterator it = fit->begin(); it->moveBefore(ret_g); } } */ } garbageBB->eraseFromParent(); BranchInst* br = dyn_cast<BranchInst>(forBody->getTerminator()); br->setSuccessor(0, forCond); forInc->eraseFromParent(); // Create return instruction for func1EndBlock and set a branch from loop header to func1EndBlock ConstantInt* retVal = ConstantInt::get(int32Ty, (uint32_t) 0); ReturnInst* ret1 = ReturnInst::Create(*context, retVal, func1EndBlock); BasicBlock* loopHeader = BlockMap.at(L->getHeader()); BranchInst* brInst = BranchInst::Create(loopHeader, func1EntryBlock); // add produce function call std::vector<Value *> produce_args; ConstantInt* val = ConstantInt::get(int64Ty, (uint64_t) 0); produce_args.push_back(val); val = ConstantInt::get(int32Ty, (uint32_t) 5); produce_args.push_back(val); CallInst::Create(pro, ArrayRef<Value*>(produce_args), "", func1EndBlock->getTerminator()); // add consume function call int q_id = 2; for (Value::use_iterator uit = i_var->use_begin(), uite = i_var->use_end(); uit != uite; ++uit) { std::vector<Value *> consume_args; ConstantInt* val = ConstantInt::get(int32Ty, (uint32_t) q_id); consume_args.push_back(val); CallInst* call = CallInst::Create(con, ArrayRef<Value*>(consume_args)); Instruction* inst = dyn_cast<Instruction>(*uit); call->insertAfter(inst); CastInst* cast = CastInst::CreateIntegerCast(call, int32Ty, true); cast->insertAfter(call); (*uit)->replaceAllUsesWith(cast); inst->eraseFromParent(); q_id++; } i_var->eraseFromParent(); // add produce and consume function calls to main thread // transmit the function pointer to created function by a produce call BasicBlock* loopPreheader = L->getLoopPreheader(); produce_args.clear(); CastInst* cast = CastInst::CreatePointerCast(func1, int64Ty); cast->insertBefore(loopPreheader->getTerminator()); produce_args.push_back(cast); val = ConstantInt::get(int32Ty, (uint32_t) 0); produce_args.push_back(val); CallInst::Create(pro, ArrayRef<Value*>(produce_args), "", loopPreheader->getTerminator()); // transmit induction variable to created function by a produce call Instruction* load = &L->getHeader()->front(); produce_args.clear(); cast = CastInst::CreateIntegerCast(load, int64Ty, true); cast->insertAfter(load); produce_args.push_back(cast); val = ConstantInt::get(int32Ty, (uint32_t) 4); produce_args.push_back(val); CallInst::Create(pro, ArrayRef<Value*>(produce_args))->insertAfter(cast); return true; }