void SelectionDAGBuilder::LowerCallSiteWithDeoptBundleImpl( ImmutableCallSite CS, SDValue Callee, const BasicBlock *EHPadBB, bool VarArgDisallowed, bool ForceVoidReturnTy) { StatepointLoweringInfo SI(DAG); unsigned ArgBeginIndex = CS.arg_begin() - CS.getInstruction()->op_begin(); populateCallLoweringInfo( SI.CLI, CS, ArgBeginIndex, CS.getNumArgOperands(), Callee, ForceVoidReturnTy ? Type::getVoidTy(*DAG.getContext()) : CS.getType(), false); if (!VarArgDisallowed) SI.CLI.IsVarArg = CS.getFunctionType()->isVarArg(); auto DeoptBundle = *CS.getOperandBundle(LLVMContext::OB_deopt); unsigned DefaultID = StatepointDirectives::DeoptBundleStatepointID; auto SD = parseStatepointDirectivesFromAttrs(CS.getAttributes()); SI.ID = SD.StatepointID.getValueOr(DefaultID); SI.NumPatchBytes = SD.NumPatchBytes.getValueOr(0); SI.DeoptState = ArrayRef<const Use>(DeoptBundle.Inputs.begin(), DeoptBundle.Inputs.end()); SI.StatepointFlags = static_cast<uint64_t>(StatepointFlags::None); SI.EHPadBB = EHPadBB; // NB! The GC arguments are deliberately left empty. if (SDValue ReturnVal = LowerAsSTATEPOINT(SI)) { const Instruction *Inst = CS.getInstruction(); ReturnVal = lowerRangeToAssertZExt(DAG, *Inst, ReturnVal); setValue(Inst, ReturnVal); } }
bool CallLowering::lowerCall( MachineIRBuilder &MIRBuilder, ImmutableCallSite CS, unsigned ResReg, ArrayRef<unsigned> ArgRegs, std::function<unsigned()> GetCalleeReg) const { auto &DL = CS.getParent()->getParent()->getParent()->getDataLayout(); // First step is to marshall all the function's parameters into the correct // physregs and memory locations. Gather the sequence of argument types that // we'll pass to the assigner function. SmallVector<ArgInfo, 8> OrigArgs; unsigned i = 0; unsigned NumFixedArgs = CS.getFunctionType()->getNumParams(); for (auto &Arg : CS.args()) { ArgInfo OrigArg{ArgRegs[i], Arg->getType(), ISD::ArgFlagsTy{}, i < NumFixedArgs}; setArgFlags(OrigArg, i + AttributeList::FirstArgIndex, DL, CS); // We don't currently support swifterror or swiftself args. if (OrigArg.Flags.isSwiftError() || OrigArg.Flags.isSwiftSelf()) return false; OrigArgs.push_back(OrigArg); ++i; } MachineOperand Callee = MachineOperand::CreateImm(0); if (const Function *F = CS.getCalledFunction()) Callee = MachineOperand::CreateGA(F, 0); else Callee = MachineOperand::CreateReg(GetCalleeReg(), false); ArgInfo OrigRet{ResReg, CS.getType(), ISD::ArgFlagsTy{}}; if (!OrigRet.Ty->isVoidTy()) setArgFlags(OrigRet, AttributeList::ReturnIndex, DL, CS); return lowerCall(MIRBuilder, CS.getCallingConv(), Callee, OrigRet, OrigArgs); }
void SelectionDAGBuilder::LowerCallSiteWithDeoptBundle( ImmutableCallSite CS, SDValue Callee, const BasicBlock *EHPadBB) { StatepointLoweringInfo SI(DAG); unsigned ArgBeginIndex = CS.arg_begin() - CS.getInstruction()->op_begin(); populateCallLoweringInfo(SI.CLI, CS, ArgBeginIndex, CS.getNumArgOperands(), Callee, CS.getType(), false); auto DeoptBundle = *CS.getOperandBundle(LLVMContext::OB_deopt); unsigned DefaultID = StatepointDirectives::DeoptBundleStatepointID; auto SD = parseStatepointDirectivesFromAttrs(CS.getAttributes()); SI.ID = SD.StatepointID.getValueOr(DefaultID); SI.NumPatchBytes = SD.NumPatchBytes.getValueOr(0); SI.DeoptState = ArrayRef<const Use>(DeoptBundle.Inputs.begin(), DeoptBundle.Inputs.end()); SI.StatepointFlags = static_cast<uint64_t>(StatepointFlags::None); SI.EHPadBB = EHPadBB; if (SDValue ReturnVal = LowerAsSTATEPOINT(SI)) { const Instruction *Inst = CS.getInstruction(); ReturnVal = lowerRangeToAssertZExt(DAG, *Inst, ReturnVal); setValue(Inst, ReturnVal); } }
std::vector<FlowRecord> TaintReachable::process(const ContextID ctxt, const ImmutableCallSite cs) const { DEBUG(errs() << "Using taint reachable signature for: " << *cs.getInstruction() << "\n"); FlowRecord exp(false,ctxt,ctxt); FlowRecord imp(true,ctxt,ctxt); // implicit from the pc of the call site and the function pointer imp.addSourceValue(*cs->getParent()); imp.addSourceValue(*cs.getCalledValue()); // Sources and sinks of the args for (ImmutableCallSite::arg_iterator arg = cs.arg_begin(), end = cs.arg_end(); arg != end; ++arg) { // every argument's value is a source exp.addSourceValue(**arg); // if the argument is a pointer, everything it reaches is a source // and everything it reaches is a sink if ((*arg)->getType()->isPointerTy()) { exp.addSourceReachablePtr(**arg); imp.addSourceValue(**arg); exp.addSinkReachablePtr(**arg); imp.addSinkReachablePtr(**arg); } } // if the function has a return value it is a sink if (!cs->getType()->isVoidTy()) { imp.addSinkValue(*cs.getInstruction()); exp.addSinkValue(*cs.getInstruction()); } std::vector<FlowRecord> flows; flows.push_back(imp); flows.push_back(exp); return flows; }
std::vector<FlowRecord> ArgsToRet::process(const ContextID ctxt, const ImmutableCallSite cs) const { DEBUG(errs() << "Using ArgsToRet reachable signature for: " << *cs.getInstruction() << "\n"); std::vector<FlowRecord> flows; if (!cs->getType()->isVoidTy()) { FlowRecord exp(false,ctxt,ctxt); // Sources and sinks of the args for (ImmutableCallSite::arg_iterator arg = cs.arg_begin(), end = cs.arg_end(); arg != end; ++arg) { // every argument's value is a source exp.addSourceValue(**arg); } // if the function has a return value it is a sink exp.addSinkValue(*cs.getInstruction()); flows.push_back(exp); } return flows; }
std::vector<FlowRecord> OverflowChecks::process(const ContextID ctxt, const ImmutableCallSite cs) const { DEBUG(errs() << "Using OverflowChecks signature...\n"); FlowRecord exp(false,ctxt,ctxt); FlowRecord imp(true,ctxt,ctxt); imp.addSourceValue(*cs->getParent()); // Add all argument values as sources for (ImmutableCallSite::arg_iterator arg = cs.arg_begin(), end = cs.arg_end(); arg != end; ++arg) exp.addSourceValue(**arg); assert(!cs->getType()->isVoidTy() && "Found 'void' overflow check?"); // And the return value as a sink exp.addSinkValue(*cs.getInstruction()); imp.addSinkValue(*cs.getInstruction()); std::vector<FlowRecord> flows; flows.push_back(imp); flows.push_back(exp); return flows; }
// There are two types of constraints to add for a function call: // - ValueNode(callsite) = ReturnNode(call target) // - ValueNode(formal arg) = ValueNode(actual arg) void Andersen::addConstraintForCall(ImmutableCallSite cs) { if (const Function *f = cs.getCalledFunction()) // Direct call { if (f->isDeclaration() || f->isIntrinsic()) // External library call { // Handle libraries separately if (addConstraintForExternalLibrary(cs, f)) return; else // Unresolved library call: ruin everything! { errs() << "Unresolved ext function: " << f->getName() << "\n"; if (cs.getType()->isPointerTy()) { NodeIndex retIndex = nodeFactory.getValueNodeFor(cs.getInstruction()); assert(retIndex != AndersNodeFactory::InvalidIndex && "Failed to find ret node!"); constraints.emplace_back(AndersConstraint::COPY, retIndex, nodeFactory.getUniversalPtrNode()); } for (ImmutableCallSite::arg_iterator itr = cs.arg_begin(), ite = cs.arg_end(); itr != ite; ++itr) { Value *argVal = *itr; if (argVal->getType()->isPointerTy()) { NodeIndex argIndex = nodeFactory.getValueNodeFor(argVal); assert(argIndex != AndersNodeFactory::InvalidIndex && "Failed to find arg node!"); constraints.emplace_back(AndersConstraint::COPY, argIndex, nodeFactory.getUniversalPtrNode()); } } } } else // Non-external function call { if (cs.getType()->isPointerTy()) { NodeIndex retIndex = nodeFactory.getValueNodeFor(cs.getInstruction()); assert(retIndex != AndersNodeFactory::InvalidIndex && "Failed to find ret node!"); // errs() << f->getName() << "\n"; NodeIndex fRetIndex = nodeFactory.getReturnNodeFor(f); assert(fRetIndex != AndersNodeFactory::InvalidIndex && "Failed to find function ret node!"); constraints.emplace_back(AndersConstraint::COPY, retIndex, fRetIndex); } // The argument constraints addArgumentConstraintForCall(cs, f); } } else // Indirect call { // We do the simplest thing here: just assume the returned value can be // anything :) if (cs.getType()->isPointerTy()) { NodeIndex retIndex = nodeFactory.getValueNodeFor(cs.getInstruction()); assert(retIndex != AndersNodeFactory::InvalidIndex && "Failed to find ret node!"); constraints.emplace_back(AndersConstraint::COPY, retIndex, nodeFactory.getUniversalPtrNode()); } // For argument constraints, first search through all addr-taken functions: // any function that takes can take as many variables is a potential // candidate const Module *M = cs.getInstruction()->getParent()->getParent()->getParent(); for (auto const &f : *M) { NodeIndex funPtrIndex = nodeFactory.getValueNodeFor(&f); if (funPtrIndex == AndersNodeFactory::InvalidIndex) // Not an addr-taken function continue; if (!f.getFunctionType()->isVarArg() && f.arg_size() != cs.arg_size()) // #arg mismatch continue; if (f.isDeclaration() || f.isIntrinsic()) // External library call { if (addConstraintForExternalLibrary(cs, &f)) continue; else { // Pollute everything for (ImmutableCallSite::arg_iterator itr = cs.arg_begin(), ite = cs.arg_end(); itr != ite; ++itr) { Value *argVal = *itr; if (argVal->getType()->isPointerTy()) { NodeIndex argIndex = nodeFactory.getValueNodeFor(argVal); assert(argIndex != AndersNodeFactory::InvalidIndex && "Failed to find arg node!"); constraints.emplace_back(AndersConstraint::COPY, argIndex, nodeFactory.getUniversalPtrNode()); } } } } else addArgumentConstraintForCall(cs, &f); } } }