aboutsummaryrefslogtreecommitdiff
path: root/llvm/lib/IR/Instructions.cpp
diff options
context:
space:
mode:
authorChandler Carruth <chandlerc@gmail.com>2018-11-22 10:31:35 +0000
committerChandler Carruth <chandlerc@gmail.com>2018-11-22 10:31:35 +0000
commite429c7941d466dcd7bad37c7e395c8295ef09fd9 (patch)
tree7e191aae252b3c96bf357543b584cdf8ab663f6c /llvm/lib/IR/Instructions.cpp
parent0a01f5d2447c7901c7c841a74d17a196218d3027 (diff)
downloadllvm-e429c7941d466dcd7bad37c7e395c8295ef09fd9.zip
llvm-e429c7941d466dcd7bad37c7e395c8295ef09fd9.tar.gz
llvm-e429c7941d466dcd7bad37c7e395c8295ef09fd9.tar.bz2
[TI removal] Leverage the fact that TerminatorInst is gone to create
a normal base class that provides all common "call" functionality. This merges two complex CRTP mixins for the common "call" logic and common operand bundle logic into a single, normal base class of `CallInst` and `InvokeInst`. Going forward, users can typically `dyn_cast<CallBase>` and use the resulting API. No more need for the `CallSite` wrapper. I'm planning to migrate current usage of the wrapper to directly use the base class and then it can be removed, but those are simpler and much more incremental steps. The big change is to introduce this abstraction into the type system. I've tried to do some basic simplifications of the APIs that I couldn't really help but touch as part of this: - I've tried to organize the attribute API and bundle API into groups to make understanding the API of `CallBase` easier. Without this, I wasn't able to navigate the API sanely for all of the ways I needed to modify it. - I've added what seem like more clear and consistent APIs for getting at the called operand. These ended up being especially useful to consolidate the *numerous* duplicated code paths trying to do this. - I've largely reworked the organization and implementation of the APIs for computing the argument operands as they needed to change to work with the new subclass approach. To minimize any cost associated with this abstraction, I've moved the operand layout in memory to store the called operand last. This makes its position relative to the end of the operand array the same, regardless of the subclass. It should make it much cheaper to reference from the `CallBase` abstraction, and this is likely one of the most frequent things to query. We do still pay one abstraction penalty here: we have to branch to determine whether there are 0 or 2 extra operands when computing the end of the argument operand sequence. However, that seems both rare and should optimize well. I've implemented this in a way specifically designed to allow it to optimize fairly well. If this shows up in profiles, we can add overrides of the relevant methods to the subclasses that bypass this penalty. It seems very unlikely that this will be an issue as the code was *already* dealing with an ever present abstraction of whether or not there are operand bundles, so this isn't the first branch to go into the computation. I've tried to remove as much of the obvious vestigial API surface of the old CRTP implementation as I could, but I suspect there is further cleanup that should now be possible, especially around the operand bundle APIs. I'm leaving all of that for future work in this patch as enough things are changing here as-is. One thing that made this harder for me to reason about and debug was the pervasive use of unsigned values in subtraction and other arithmetic computations. I had to debug more than one unintentional wrap. I've switched a few of these to use `int` which seems substantially simpler, but I've held back from doing this more broadly to avoid creating confusing divergence within a single class's API. I also worked to remove all of the magic numbers used to index into operands, putting them behind named constants or putting them into a single method with a comment and strictly using the method elsewhere. This was necessary to be able to re-layout the operands as discussed above. Thanks to Ben for reviewing this (somewhat large and awkward) patch! Differential Revision: https://reviews.llvm.org/D54788 llvm-svn: 347452
Diffstat (limited to 'llvm/lib/IR/Instructions.cpp')
-rw-r--r--llvm/lib/IR/Instructions.cpp131
1 files changed, 100 insertions, 31 deletions
diff --git a/llvm/lib/IR/Instructions.cpp b/llvm/lib/IR/Instructions.cpp
index 4ee91aa..8405bbd 100644
--- a/llvm/lib/IR/Instructions.cpp
+++ b/llvm/lib/IR/Instructions.cpp
@@ -65,10 +65,7 @@ AllocaInst::getAllocationSizeInBits(const DataLayout &DL) const {
//===----------------------------------------------------------------------===//
User::op_iterator CallSite::getCallee() const {
- Instruction *II(getInstruction());
- return isCall()
- ? cast<CallInst>(II)->op_end() - 1 // Skip Callee
- : cast<InvokeInst>(II)->op_end() - 3; // Skip BB, BB, Callee
+ return cast<CallBase>(getInstruction())->op_end() - 1;
}
//===----------------------------------------------------------------------===//
@@ -254,6 +251,82 @@ void LandingPadInst::addClause(Constant *Val) {
}
//===----------------------------------------------------------------------===//
+// CallBase Implementation
+//===----------------------------------------------------------------------===//
+
+Value *CallBase::getReturnedArgOperand() const {
+ unsigned Index;
+
+ if (Attrs.hasAttrSomewhere(Attribute::Returned, &Index) && Index)
+ return getArgOperand(Index - AttributeList::FirstArgIndex);
+ if (const Function *F = getCalledFunction())
+ if (F->getAttributes().hasAttrSomewhere(Attribute::Returned, &Index) &&
+ Index)
+ return getArgOperand(Index - AttributeList::FirstArgIndex);
+
+ return nullptr;
+}
+
+bool CallBase::hasRetAttr(Attribute::AttrKind Kind) const {
+ if (Attrs.hasAttribute(AttributeList::ReturnIndex, Kind))
+ return true;
+
+ // Look at the callee, if available.
+ if (const Function *F = getCalledFunction())
+ return F->getAttributes().hasAttribute(AttributeList::ReturnIndex, Kind);
+ return false;
+}
+
+/// Determine whether the argument or parameter has the given attribute.
+bool CallBase::paramHasAttr(unsigned ArgNo, Attribute::AttrKind Kind) const {
+ assert(ArgNo < getNumArgOperands() && "Param index out of bounds!");
+
+ if (Attrs.hasParamAttribute(ArgNo, Kind))
+ return true;
+ if (const Function *F = getCalledFunction())
+ return F->getAttributes().hasParamAttribute(ArgNo, Kind);
+ return false;
+}
+
+bool CallBase::hasFnAttrOnCalledFunction(Attribute::AttrKind Kind) const {
+ if (const Function *F = getCalledFunction())
+ return F->getAttributes().hasAttribute(AttributeList::FunctionIndex, Kind);
+ return false;
+}
+
+bool CallBase::hasFnAttrOnCalledFunction(StringRef Kind) const {
+ if (const Function *F = getCalledFunction())
+ return F->getAttributes().hasAttribute(AttributeList::FunctionIndex, Kind);
+ return false;
+}
+
+CallBase::op_iterator
+CallBase::populateBundleOperandInfos(ArrayRef<OperandBundleDef> Bundles,
+ const unsigned BeginIndex) {
+ auto It = op_begin() + BeginIndex;
+ for (auto &B : Bundles)
+ It = std::copy(B.input_begin(), B.input_end(), It);
+
+ auto *ContextImpl = getContext().pImpl;
+ auto BI = Bundles.begin();
+ unsigned CurrentIndex = BeginIndex;
+
+ for (auto &BOI : bundle_op_infos()) {
+ assert(BI != Bundles.end() && "Incorrect allocation?");
+
+ BOI.Tag = ContextImpl->getOrInsertBundleTag(BI->getTag());
+ BOI.Begin = CurrentIndex;
+ BOI.End = CurrentIndex + BI->input_size();
+ CurrentIndex = BOI.End;
+ BI++;
+ }
+
+ assert(BI == Bundles.end() && "Incorrect allocation?");
+
+ return It;
+}
+
+//===----------------------------------------------------------------------===//
// CallInst Implementation
//===----------------------------------------------------------------------===//
@@ -262,7 +335,7 @@ void CallInst::init(FunctionType *FTy, Value *Func, ArrayRef<Value *> Args,
this->FTy = FTy;
assert(getNumOperands() == Args.size() + CountBundleInputs(Bundles) + 1 &&
"NumOperands not set up?");
- Op<-1>() = Func;
+ setCalledOperand(Func);
#ifndef NDEBUG
assert((Args.size() == FTy->getNumParams() ||
@@ -288,7 +361,7 @@ void CallInst::init(Value *Func, const Twine &NameStr) {
FTy =
cast<FunctionType>(cast<PointerType>(Func->getType())->getElementType());
assert(getNumOperands() == 1 && "NumOperands not set up?");
- Op<-1>() = Func;
+ setCalledOperand(Func);
assert(FTy->getNumParams() == 0 && "Calling a function with bad signature");
@@ -296,31 +369,27 @@ void CallInst::init(Value *Func, const Twine &NameStr) {
}
CallInst::CallInst(Value *Func, const Twine &Name, Instruction *InsertBefore)
- : CallBase<CallInst>(
- cast<FunctionType>(
- cast<PointerType>(Func->getType())->getElementType())
- ->getReturnType(),
- Instruction::Call,
- OperandTraits<CallBase<CallInst>>::op_end(this) - 1, 1,
- InsertBefore) {
+ : CallBase(cast<FunctionType>(
+ cast<PointerType>(Func->getType())->getElementType())
+ ->getReturnType(),
+ Instruction::Call, OperandTraits<CallBase>::op_end(this) - 1, 1,
+ InsertBefore) {
init(Func, Name);
}
CallInst::CallInst(Value *Func, const Twine &Name, BasicBlock *InsertAtEnd)
- : CallBase<CallInst>(
- cast<FunctionType>(
- cast<PointerType>(Func->getType())->getElementType())
- ->getReturnType(),
- Instruction::Call,
- OperandTraits<CallBase<CallInst>>::op_end(this) - 1, 1, InsertAtEnd) {
+ : CallBase(cast<FunctionType>(
+ cast<PointerType>(Func->getType())->getElementType())
+ ->getReturnType(),
+ Instruction::Call, OperandTraits<CallBase>::op_end(this) - 1, 1,
+ InsertAtEnd) {
init(Func, Name);
}
CallInst::CallInst(const CallInst &CI)
- : CallBase<CallInst>(CI.Attrs, CI.FTy, CI.getType(), Instruction::Call,
- OperandTraits<CallBase<CallInst>>::op_end(this) -
- CI.getNumOperands(),
- CI.getNumOperands()) {
+ : CallBase(CI.Attrs, CI.FTy, CI.getType(), Instruction::Call,
+ OperandTraits<CallBase>::op_end(this) - CI.getNumOperands(),
+ CI.getNumOperands()) {
setTailCallKind(CI.getTailCallKind());
setCallingConv(CI.getCallingConv());
@@ -560,11 +629,12 @@ void InvokeInst::init(FunctionType *FTy, Value *Fn, BasicBlock *IfNormal,
const Twine &NameStr) {
this->FTy = FTy;
- assert(getNumOperands() == 3 + Args.size() + CountBundleInputs(Bundles) &&
+ assert((int)getNumOperands() ==
+ ComputeNumOperands(Args.size(), CountBundleInputs(Bundles)) &&
"NumOperands not set up?");
- Op<-3>() = Fn;
- Op<-2>() = IfNormal;
- Op<-1>() = IfException;
+ setNormalDest(IfNormal);
+ setUnwindDest(IfException);
+ setCalledOperand(Fn);
#ifndef NDEBUG
assert(((Args.size() == FTy->getNumParams()) ||
@@ -587,10 +657,9 @@ void InvokeInst::init(FunctionType *FTy, Value *Fn, BasicBlock *IfNormal,
}
InvokeInst::InvokeInst(const InvokeInst &II)
- : CallBase<InvokeInst>(II.Attrs, II.FTy, II.getType(), Instruction::Invoke,
- OperandTraits<CallBase<InvokeInst>>::op_end(this) -
- II.getNumOperands(),
- II.getNumOperands()) {
+ : CallBase(II.Attrs, II.FTy, II.getType(), Instruction::Invoke,
+ OperandTraits<CallBase>::op_end(this) - II.getNumOperands(),
+ II.getNumOperands()) {
setCallingConv(II.getCallingConv());
std::copy(II.op_begin(), II.op_end(), op_begin());
std::copy(II.bundle_op_info_begin(), II.bundle_op_info_end(),