1
0
mirror of https://github.com/RPCS3/llvm-mirror.git synced 2024-11-22 18:54:02 +01:00

[AssumeBundles] Add API to query a bundles from a use

Summary: Finding what information is know about a value from a use is generally useful and can be done quickly.

Reviewers: jdoerfert

Reviewed By: jdoerfert

Subscribers: hiraditya, llvm-commits

Tags: #llvm

Differential Revision: https://reviews.llvm.org/D75616
This commit is contained in:
Tyker 2020-03-07 18:00:05 +01:00
parent c5b36c0e65
commit 1f48436556
5 changed files with 190 additions and 5 deletions

View File

@ -2097,16 +2097,14 @@ public:
op_iterator populateBundleOperandInfos(ArrayRef<OperandBundleDef> Bundles,
const unsigned BeginIndex);
public:
/// Return the BundleOpInfo for the operand at index OpIdx.
///
/// It is an error to call this with an OpIdx that does not correspond to an
/// bundle operand.
BundleOpInfo &getBundleOpInfoForOperand(unsigned OpIdx);
const BundleOpInfo &getBundleOpInfoForOperand(unsigned OpIdx) const {
for (auto &BOI : bundle_op_infos())
if (BOI.Begin <= OpIdx && OpIdx < BOI.End)
return BOI;
llvm_unreachable("Did not find operand bundle for operand!");
return const_cast<CallBase *>(this)->getBundleOpInfoForOperand(OpIdx);
}
protected:

View File

@ -93,6 +93,28 @@ using RetainedKnowledgeMap = DenseMap<RetainedKnowledgeKey, MinMax>;
/// If the IR changes the map will be outdated.
void fillMapFromAssume(CallInst &AssumeCI, RetainedKnowledgeMap &Result);
/// Represent one information held inside an operand bundle of an llvm.assume.
/// AttrKind is the property that hold.
/// WasOn if not null is that Value for which AttrKind holds.
/// ArgValue is optionally an argument.
struct RetainedKnowledge {
Attribute::AttrKind AttrKind = Attribute::None;
Value *WasOn = nullptr;
unsigned ArgValue = 0;
};
/// Retreive the information help by Assume on the operand at index Idx.
/// Assume should be an llvm.assume and Idx should be in the operand bundle.
RetainedKnowledge getKnowledgeFromOperandInAssume(CallInst &Assume,
unsigned Idx);
/// Retreive the information help by the Use U of an llvm.assume. the use should
/// be in the operand bundle.
inline RetainedKnowledge getKnowledgeFromUseInAssume(const Use *U) {
return getKnowledgeFromOperandInAssume(*cast<CallInst>(U->getUser()),
U->getOperandNo());
}
//===----------------------------------------------------------------------===//
// Utilities for testing
//===----------------------------------------------------------------------===//

View File

@ -384,6 +384,53 @@ CallBase::populateBundleOperandInfos(ArrayRef<OperandBundleDef> Bundles,
return It;
}
CallBase::BundleOpInfo &CallBase::getBundleOpInfoForOperand(unsigned OpIdx) {
/// When there isn't many bundles, we do a simple linear search.
/// Else fallback to a binary-search that use the fact that bundles usually
/// have similar number of argument to get faster convergence.
if (bundle_op_info_end() - bundle_op_info_begin() < 8) {
for (auto &BOI : bundle_op_infos())
if (BOI.Begin <= OpIdx && OpIdx < BOI.End)
return BOI;
llvm_unreachable("Did not find operand bundle for operand!");
}
assert(OpIdx >= arg_size() && "the Idx is not in the operand bundles");
assert(bundle_op_info_end() - bundle_op_info_begin() > 0 &&
OpIdx < std::prev(bundle_op_info_end())->End &&
"The Idx isn't in the operand bundle");
/// We need a decimal number below and to prevent using floating point numbers
/// we use an intergal value multiplied by this constant.
constexpr unsigned NumberScaling = 1024;
bundle_op_iterator Begin = bundle_op_info_begin();
bundle_op_iterator End = bundle_op_info_end();
bundle_op_iterator Current;
while (Begin != End) {
unsigned ScaledOperandPerBundle =
NumberScaling * (std::prev(End)->End - Begin->Begin) / (End - Begin);
Current = Begin + (((OpIdx - Begin->Begin) * NumberScaling) /
ScaledOperandPerBundle);
if (Current >= End)
Current = std::prev(End);
assert(Current < End && Current >= Begin &&
"the operand bundle doesn't cover every value in the range");
if (OpIdx >= Current->Begin && OpIdx < Current->End)
break;
if (OpIdx >= Current->End)
Begin = Current + 1;
else
End = Current;
}
assert(OpIdx >= Current->Begin && OpIdx < Current->End &&
"the operand bundle doesn't cover every value in the range");
return *Current;
}
//===----------------------------------------------------------------------===//
// CallInst Implementation
//===----------------------------------------------------------------------===//

View File

@ -288,6 +288,23 @@ void llvm::fillMapFromAssume(CallInst &AssumeCI, RetainedKnowledgeMap &Result) {
}
}
RetainedKnowledge llvm::getKnowledgeFromOperandInAssume(CallInst &AssumeCI,
unsigned Idx) {
IntrinsicInst &Assume = cast<IntrinsicInst>(AssumeCI);
assert(Assume.getIntrinsicID() == Intrinsic::assume &&
"this function is intended to be used on llvm.assume");
CallBase::BundleOpInfo BOI = Assume.getBundleOpInfoForOperand(Idx);
RetainedKnowledge Result;
Result.AttrKind = Attribute::getAttrKindFromName(BOI.Tag->getKey());
Result.WasOn = getValueFromBundleOpInfo(Assume, BOI, BOIE_WasOn);
if (BOI.End - BOI.Begin > BOIE_Argument)
Result.ArgValue =
cast<ConstantInt>(getValueFromBundleOpInfo(Assume, BOI, BOIE_Argument))
->getZExtValue();
return Result;
}
PreservedAnalyses AssumeBuilderPass::run(Function &F,
FunctionAnalysisManager &AM) {
for (Instruction &I : instructions(F))

View File

@ -10,10 +10,12 @@
#include "llvm/AsmParser/Parser.h"
#include "llvm/IR/CallSite.h"
#include "llvm/IR/LLVMContext.h"
#include "llvm/IR/IntrinsicInst.h"
#include "llvm/Support/Regex.h"
#include "llvm/Support/SourceMgr.h"
#include "llvm/Support/CommandLine.h"
#include "gtest/gtest.h"
#include <random>
using namespace llvm;
@ -387,3 +389,102 @@ TEST(AssumeQueryAPI, fillMapFromAssume) {
}));
RunTest(Head, Tail, Tests);
}
static void RunRandTest(uint64_t Seed, int Size, int MinCount, int MaxCount,
unsigned MaxValue) {
LLVMContext C;
SMDiagnostic Err;
std::random_device dev;
std::mt19937 Rng(Seed);
std::uniform_int_distribution<int> DistCount(MinCount, MaxCount);
std::uniform_int_distribution<unsigned> DistValue(0, MaxValue);
std::uniform_int_distribution<unsigned> DistAttr(0,
Attribute::EndAttrKinds - 1);
std::unique_ptr<Module> Mod = std::make_unique<Module>("AssumeQueryAPI", C);
if (!Mod)
Err.print("AssumeQueryAPI", errs());
std::vector<Type *> TypeArgs;
for (int i = 0; i < (Size * 2); i++)
TypeArgs.push_back(Type::getInt32PtrTy(C));
FunctionType *FuncType =
FunctionType::get(Type::getVoidTy(C), TypeArgs, false);
Function *F =
Function::Create(FuncType, GlobalValue::ExternalLinkage, "test", &*Mod);
BasicBlock *BB = BasicBlock::Create(C);
BB->insertInto(F);
Instruction *Ret = ReturnInst::Create(C);
BB->getInstList().insert(BB->begin(), Ret);
Function *FnAssume = Intrinsic::getDeclaration(Mod.get(), Intrinsic::assume);
std::vector<Argument *> ShuffledArgs;
std::vector<bool> HasArg;
for (auto &Arg : F->args()) {
ShuffledArgs.push_back(&Arg);
HasArg.push_back(false);
}
std::shuffle(ShuffledArgs.begin(), ShuffledArgs.end(), Rng);
std::vector<OperandBundleDef> OpBundle;
OpBundle.reserve(Size);
std::vector<Value *> Args;
Args.reserve(2);
for (int i = 0; i < Size; i++) {
int count = DistCount(Rng);
int value = DistValue(Rng);
int attr = DistAttr(Rng);
std::string str;
raw_string_ostream ss(str);
ss << Attribute::getNameFromAttrKind(
static_cast<Attribute::AttrKind>(attr));
Args.clear();
if (count > 0) {
Args.push_back(ShuffledArgs[i]);
HasArg[i] = true;
}
if (count > 1)
Args.push_back(ConstantInt::get(Type::getInt32Ty(C), value));
OpBundle.push_back(OperandBundleDef{ss.str().c_str(), std::move(Args)});
}
Instruction *Assume =
CallInst::Create(FnAssume, ArrayRef<Value *>({ConstantInt::getTrue(C)}),
std::move(OpBundle));
Assume->insertBefore(&F->begin()->front());
RetainedKnowledgeMap Map;
fillMapFromAssume(*cast<CallInst>(Assume), Map);
for (int i = 0; i < (Size * 2); i++) {
if (!HasArg[i])
continue;
RetainedKnowledge K =
getKnowledgeFromUseInAssume(&*ShuffledArgs[i]->use_begin());
auto LookupIt = Map.find(RetainedKnowledgeKey{K.WasOn, K.AttrKind});
ASSERT_TRUE(LookupIt != Map.end());
MinMax MM = LookupIt->second;
ASSERT_TRUE(MM.Min == MM.Max);
ASSERT_TRUE(MM.Min == K.ArgValue);
}
}
TEST(AssumeQueryAPI, getKnowledgeFromUseInAssume) {
// // For Fuzzing
// std::random_device dev;
// std::mt19937 Rng(dev());
// while (true) {
// unsigned Seed = Rng();
// dbgs() << Seed << "\n";
// RunRandTest(Seed, 100000, 0, 2, 100);
// }
RunRandTest(23456, 4, 0, 2, 100);
RunRandTest(560987, 25, -3, 2, 100);
// Large bundles can lead to special cases. this is why this test is soo
// large.
RunRandTest(9876789, 100000, -0, 7, 100);
}