29#define DEBUG_TYPE "normalize"
37 const uint64_t kMul = 0x9ddfea08eb382d69ULL;
52 IRNormalizer(IRNormalizerOptions Options) : Options(Options) {}
55 const IRNormalizerOptions Options;
58 const uint64_t MagicHashConstant = 0x6acaa36bef8325c5ULL;
59 DenseSet<const Instruction *> NamedInstructions;
61 SmallVector<Instruction *, 16> Outputs;
65 void nameFunctionArguments(Function &
F)
const;
66 void nameBasicBlocks(Function &
F)
const;
67 void nameInstruction(Instruction *
I);
68 void nameAsInitialInstruction(Instruction *
I)
const;
69 void nameAsRegularInstruction(Instruction *
I);
70 void foldInstructionName(Instruction *
I)
const;
75 void reorderInstructions(Function &
F)
const;
76 void reorderDefinition(Instruction *Definition,
77 std::stack<Instruction *> &TopologicalSort,
78 SmallPtrSet<const Instruction *, 32> &Visited)
const;
79 void reorderInstructionOperandsByNames(Instruction *
I)
const;
80 void reorderPHIIncomingValues(PHINode *Phi)
const;
86 void sortCommutativeOperands(Instruction *
I,
T &Operands)
const;
87 SmallVector<Instruction *, 16> collectOutputInstructions(Function &
F)
const;
88 bool isOutput(
const Instruction *
I)
const;
89 bool isInitialInstruction(
const Instruction *
I)
const;
90 bool hasOnlyImmediateOperands(
const Instruction *
I)
const;
92 getOutputFootprint(Instruction *
I,
93 SmallPtrSet<const Instruction *, 32> &Visited)
const;
101bool IRNormalizer::runOnFunction(
Function &
F) {
102 nameFunctionArguments(
F);
105 Outputs = collectOutputInstructions(
F);
108 reorderInstructions(
F);
112 for (
auto &
I : Outputs)
118 reorderInstructionOperandsByNames(&
I);
121 reorderPHIIncomingValues(Phi);
123 foldInstructionName(&
I);
132void IRNormalizer::nameFunctionArguments(Function &
F)
const {
133 int ArgumentCounter = 0;
134 for (
auto &
A :
F.args()) {
135 if (
Options.RenameAll ||
A.getName().empty()) {
136 A.setName(
"a" + Twine(ArgumentCounter));
137 ArgumentCounter += 1;
146void IRNormalizer::nameBasicBlocks(Function &
F)
const {
149 uint64_t Hash = MagicHashConstant;
156 if (
Options.RenameAll ||
B.getName().empty()) {
158 B.setName(
"bb" + std::to_string(Hash).
substr(0, 5));
168void IRNormalizer::nameInstruction(Instruction *
I) {
172 if (NamedInstructions.contains(
I))
174 NamedInstructions.insert(
I);
175 if (isInitialInstruction(
I)) {
176 nameAsInitialInstruction(
I);
179 nameAsRegularInstruction(
I);
184void IRNormalizer::sortCommutativeOperands(Instruction *
I,
T &Operands)
const {
185 if (!(
I->isCommutative() && Operands.size() >= 2))
187 auto CommutativeEnd = Operands.begin();
188 std::advance(CommutativeEnd, 2);
205void IRNormalizer::nameAsInitialInstruction(Instruction *
I)
const {
206 if (
I->getType()->isVoidTy())
208 if (!(
I->getName().empty() ||
Options.RenameAll))
216 for (
auto &
Op :
I->operands()) {
218 std::string TextRepresentation;
219 raw_string_ostream Stream(TextRepresentation);
220 Op->printAsOperand(Stream,
false);
221 Operands.
push_back(StringRef(Stream.str()));
225 sortCommutativeOperands(
I, Operands);
228 uint64_t Hash = MagicHashConstant;
233 SmallPtrSet<const Instruction *, 32> Visited;
235 SetVector<int> OutputFootprint = getOutputFootprint(
I, Visited);
238 for (
const int &Output : OutputFootprint)
242 SmallString<256>
Name;
243 Name.append(
"vl" + std::to_string(Hash).
substr(0, 5));
250 Name.append(
F->getName());
254 for (
size_t i = 0; i < Operands.
size(); ++i) {
255 Name.append(Operands[i]);
257 if (i < Operands.
size() - 1)
282void IRNormalizer::nameAsRegularInstruction(Instruction *
I) {
294 for (
auto &
Op :
I->operands()) {
301 std::string TextRepresentation;
302 raw_string_ostream Stream(TextRepresentation);
303 Op->printAsOperand(Stream,
false);
304 Operands.
push_back(StringRef(Stream.str()));
308 sortCommutativeOperands(
I, Operands);
311 uint64_t Hash = MagicHashConstant;
317 SmallVector<int, 4> OperandsOpcodes;
320 for (
auto &
Op :
I->operands())
324 sortCommutativeOperands(
I, OperandsOpcodes);
327 for (
const int Code : OperandsOpcodes)
331 SmallString<512>
Name;
332 Name.append(
"op" + std::to_string(Hash).
substr(0, 5));
336 if (
const Function *
F = CI->getCalledFunction())
337 Name.append(
F->getName());
340 for (
size_t i = 0; i < Operands.
size(); ++i) {
341 Name.append(Operands[i]);
343 if (i < Operands.
size() - 1)
348 if ((
I->getName().empty() ||
Options.RenameAll) && !
I->getType()->isVoidTy())
365void IRNormalizer::foldInstructionName(Instruction *
I)
const {
370 for (
auto *U :
I->users())
377 if (isOutput(
I) || !
I->getName().starts_with(
"op"))
383 for (
auto &
Op :
I->operands()) {
386 I->getName().starts_with(
"op") ||
I->getName().starts_with(
"vl");
388 Operands.
push_back(HasNormalName ?
I->getName().substr(0, 7)
393 sortCommutativeOperands(
I, Operands);
395 SmallString<256>
Name;
396 Name.append(
I->getName().substr(0, 7));
399 for (
size_t i = 0; i < Operands.
size(); ++i) {
400 Name.append(Operands[i]);
402 if (i < Operands.
size() - 1)
417void IRNormalizer::reorderInstructions(Function &
F)
const {
420 << BB.getName() <<
"\n");
428 std::stack<Instruction *> TopologicalSort;
429 SmallPtrSet<const Instruction *, 32> Visited;
432 if (!(isOutput(&
I) ||
I.isTerminator()))
434 LLVM_DEBUG(
dbgs() <<
"\tReordering from source effecting instruction: ";
436 reorderDefinition(&
I, TopologicalSort, Visited);
448 LLVM_DEBUG(
dbgs() <<
"\tReordering from source instruction: ";
I.dump());
449 reorderDefinition(&
I, TopologicalSort, Visited);
452 LLVM_DEBUG(
dbgs() <<
"Inserting instructions into: " << BB.getName()
455 while (!TopologicalSort.empty()) {
457 auto FirstNonPHIOrDbgOrAlloca = BB.getFirstNonPHIOrDbgOrAlloca();
460 Intrinsic::experimental_convergence_entry ||
462 FirstNonPHIOrDbgOrAlloca++;
465 TopologicalSort.pop();
470void IRNormalizer::reorderDefinition(
471 Instruction *Definition, std::stack<Instruction *> &TopologicalSort,
472 SmallPtrSet<const Instruction *, 32> &Visited)
const {
475 Visited.
insert(Definition);
479 const auto FirstNonPHIOrDbgOrAlloca =
481 if (FirstNonPHIOrDbgOrAlloca ==
BasicBlock->end())
483 if (Definition->
comesBefore(&*FirstNonPHIOrDbgOrAlloca))
487 for (
auto &Operand : Definition->
operands()) {
491 reorderDefinition(
Op, TopologicalSort, Visited);
515 TopologicalSort.emplace(Definition);
523void IRNormalizer::reorderInstructionOperandsByNames(Instruction *
I)
const {
532 for (
auto &
Op :
I->operands()) {
536 Operands.
push_back(std::pair<std::string, Value *>(
V->getName(), V));
538 std::string TextRepresentation;
539 raw_string_ostream Stream(TextRepresentation);
540 Op->printAsOperand(Stream,
false);
541 Operands.
push_back(std::pair<std::string, Value *>(Stream.str(), V));
547 sortCommutativeOperands(
I, Operands);
550 unsigned Position = 0;
551 for (
auto &
Op :
I->operands()) {
552 Op.set(Operands[Position].second);
561void IRNormalizer::reorderPHIIncomingValues(PHINode *Phi)
const {
566 for (
auto &BB :
Phi->blocks()) {
567 Value *
V =
Phi->getIncomingValueForBlock(BB);
568 Values.
push_back(std::pair<Value *, BasicBlock *>(V, BB));
572 llvm::sort(Values, [](
const std::pair<Value *, BasicBlock *> &
LHS,
573 const std::pair<Value *, BasicBlock *> &
RHS) {
578 for (
unsigned i = 0; i < Values.
size(); ++i) {
579 Phi->setIncomingBlock(i, Values[i].second);
580 Phi->setIncomingValue(i, Values[i].first);
589SmallVector<Instruction *, 16>
590IRNormalizer::collectOutputInstructions(Function &
F)
const {
593 SmallVector<Instruction *, 16> Outputs;
604bool IRNormalizer::isOutput(
const Instruction *
I)
const {
613bool IRNormalizer::isInitialInstruction(
const Instruction *
I)
const {
616 return !
I->user_empty() && hasOnlyImmediateOperands(
I);
622bool IRNormalizer::hasOnlyImmediateOperands(
const Instruction *
I)
const {
623 for (
const auto &
Op :
I->operands())
635SetVector<int> IRNormalizer::getOutputFootprint(
636 Instruction *
I, SmallPtrSet<const Instruction *, 32> &Visited)
const {
640 SetVector<int> Outputs;
651 for (
const auto &
B : *Func) {
652 for (
const auto &
E :
B) {
663 for (
auto *U :
I->users()) {
666 SetVector<int> OutputsUsingUI = getOutputFootprint(UI, Visited);
679 IRNormalizer(Options).runOnFunction(
F);
Expand Atomic instructions
static GCRegistry::Add< ErlangGC > A("erlang", "erlang-compatible garbage collector")
static GCRegistry::Add< CoreCLRGC > E("coreclr", "CoreCLR-compatible GC")
static GCRegistry::Add< OcamlGC > B("ocaml", "ocaml 3.10-compatible GC")
static bool runOnFunction(Function &F, bool PostInlining)
static constexpr uint64_t hash_16_bytes(uint64_t low, uint64_t high)
static constexpr uint64_t hash_16_bytes(uint64_t low, uint64_t high)
This file implements a set that has insertion order iteration characteristics.
static StringRef substr(StringRef Str, uint64_t Len)
This file defines the SmallPtrSet class.
This file defines the SmallString class.
This file defines the SmallVector class.
Represents analyses that only rely on functions' control flow.
LLVM_ABI Intrinsic::ID getIntrinsicID() const
Returns the intrinsic ID of the intrinsic called or Intrinsic::not_intrinsic if the called function i...
bool isMustTailCall() const
bool isTerminator() const
LLVM_ABI bool comesBefore(const Instruction *Other) const
Given an instruction Other in the same basic block as this instruction, return true if this instructi...
A set of analyses that are preserved following a run of a transformation pass.
PreservedAnalyses & preserveSet()
Mark an analysis set as preserved.
void insert_range(Range &&R)
bool insert(const value_type &X)
Insert a new element into the SetVector.
size_type count(ConstPtrType Ptr) const
count - Return 1 if the specified pointer is in the set, 0 otherwise.
std::pair< iterator, bool > insert(PtrType Ptr)
Inserts Ptr if and only if there is no element in the container equal to Ptr.
bool contains(ConstPtrType Ptr) const
void push_back(const T &Elt)
LLVM_ABI StringRef getName() const
Return a constant reference to the value's name.
LLVM_ABI void dump() const
Support for debugging, callable in GDB: V->dump()
const ParentTy * getParent() const
@ BasicBlock
Various leaf nodes.
NodeAddr< PhiNode * > Phi
NodeAddr< FuncNode * > Func
friend class Instruction
Iterator for Instructions in a `BasicBlock.
This is an optimization pass for GlobalISel generic memory operations.
FunctionAddr VTableAddr Value
decltype(auto) dyn_cast(const From &Val)
dyn_cast<X> - Return the argument parameter cast to the specified type.
void sort(IteratorTy Start, IteratorTy End)
LLVM_ABI raw_ostream & dbgs()
dbgs() - This returns a reference to a raw_ostream for debugging messages.
FunctionAddr VTableAddr Count
class LLVM_GSL_OWNER SmallVector
Forward declaration of SmallVector so that calculateSmallVectorDefaultInlinedElements can reference s...
bool isa(const From &Val)
isa<X> - Return true if the parameter to the template is an instance of one of the template type argu...
DWARFExpression::Operation Op
AnalysisManager< Function > FunctionAnalysisManager
Convenience typedef for the Function analysis manager.
PreservedAnalyses run(Function &F, FunctionAnalysisManager &AM) const