35#define DEBUG_TYPE "normalize"
59 const uint64_t MagicHashConstant = 0x6acaa36bef8325c5ULL;
66 void nameFunctionArguments(
Function &
F)
const;
76 void reorderInstructions(
Function &
F)
const;
78 std::stack<Instruction *> &TopologicalSort,
80 void reorderInstructionOperandsByNames(
Instruction *
I)
const;
81 void reorderPHIIncomingValues(
PHINode *Phi)
const;
91 bool hasOnlyImmediateOperands(
const Instruction *
I)
const;
101 cl::desc(
"Preserves original instruction order"));
104 cl::desc(
"Renames all instructions (including user-named)"));
107 cl::desc(
"Folds all regular instructions (including pre-outputs)"));
110 cl::desc(
"Sorts and reorders operands in commutative instructions"));
115bool IRNormalizer::runOnFunction(
Function &
F) {
116 nameFunctionArguments(
F);
119 Outputs = collectOutputInstructions(
F);
122 reorderInstructions(
F);
126 for (
auto &
I : Outputs)
130 if (!PreserveOrder) {
132 reorderInstructionOperandsByNames(&
I);
134 if (
auto *Phi = dyn_cast<PHINode>(&
I))
135 reorderPHIIncomingValues(Phi);
137 foldInstructionName(&
I);
146void IRNormalizer::nameFunctionArguments(
Function &
F)
const {
147 int ArgumentCounter = 0;
148 for (
auto &
A :
F.args()) {
149 if (RenameAll ||
A.getName().empty()) {
150 A.setName(
"a" +
Twine(ArgumentCounter));
151 ArgumentCounter += 1;
160void IRNormalizer::nameBasicBlocks(
Function &
F)
const {
170 if (RenameAll ||
B.getName().empty()) {
172 B.setName(
"bb" + std::to_string(Hash).
substr(0, 5));
186 if (NamedInstructions.contains(
I))
188 NamedInstructions.insert(
I);
189 if (isInitialInstruction(
I)) {
190 nameAsInitialInstruction(
I);
193 nameAsRegularInstruction(
I);
199 if (!(
I->isCommutative() &&
Operands.size() >= 2))
201 auto CommutativeEnd =
Operands.begin();
202 std::advance(CommutativeEnd, 2);
219void IRNormalizer::nameAsInitialInstruction(
Instruction *
I)
const {
220 if (
I->getType()->isVoidTy())
222 if (!(
I->getName().empty() || RenameAll))
230 for (
auto &
Op :
I->operands()) {
231 if (!isa<Function>(
Op)) {
232 std::string TextRepresentation;
234 Op->printAsOperand(Stream,
false);
252 for (
const int &Output : OutputFootprint)
257 Name.append(
"vl" + std::to_string(Hash).
substr(0, 5));
260 if (
const auto *CI = dyn_cast<CallInst>(
I)) {
264 Name.append(
F->getName());
268 for (
size_t i = 0; i <
Operands.size(); ++i) {
296void IRNormalizer::nameAsRegularInstruction(
Instruction *
I) {
308 for (
auto &
Op :
I->operands()) {
309 if (
auto *
I = dyn_cast<Instruction>(
Op)) {
313 }
else if (!isa<Function>(
Op)) {
315 std::string TextRepresentation;
317 Op->printAsOperand(Stream,
false);
334 for (
auto &
Op :
I->operands())
335 if (
auto *
I = dyn_cast<Instruction>(
Op))
338 sortCommutativeOperands(
I, OperandsOpcodes);
341 for (
const int Code : OperandsOpcodes)
346 Name.append(
"op" + std::to_string(Hash).
substr(0, 5));
349 if (
const auto *CI = dyn_cast<CallInst>(
I))
350 if (
const Function *
F = CI->getCalledFunction())
351 Name.append(
F->getName());
354 for (
size_t i = 0; i <
Operands.size(); ++i) {
362 if ((
I->getName().empty() || RenameAll) && !
I->getType()->isVoidTy())
379void IRNormalizer::foldInstructionName(
Instruction *
I)
const {
382 if (!FoldPreOutputs) {
384 for (
auto *U :
I->users())
385 if (
auto *IU = dyn_cast<Instruction>(U))
391 if (isOutput(
I) ||
I->getName().substr(0, 2) !=
"op")
397 for (
auto &
Op :
I->operands()) {
398 if (
const auto *
I = dyn_cast<Instruction>(
Op)) {
399 bool HasNormalName =
I->getName().substr(0, 2) ==
"op" ||
400 I->getName().substr(0, 2) ==
"vl";
402 Operands.push_back(HasNormalName ?
I->getName().substr(0, 7)
410 Name.append(
I->getName().substr(0, 7));
413 for (
size_t i = 0; i <
Operands.size(); ++i) {
431void IRNormalizer::reorderInstructions(
Function &
F)
const {
434 << BB.getName() <<
"\n");
442 std::stack<Instruction *> TopologicalSort;
446 if (!(isOutput(&
I) ||
I.isTerminator()))
448 LLVM_DEBUG(
dbgs() <<
"\tReordering from source effecting instruction: ";
450 reorderDefinition(&
I, TopologicalSort, Visited);
462 LLVM_DEBUG(
dbgs() <<
"\tReordering from source instruction: ";
I.dump());
463 reorderDefinition(&
I, TopologicalSort, Visited);
466 LLVM_DEBUG(
dbgs() <<
"Inserting instructions into: " << BB.getName()
469 while (!TopologicalSort.empty()) {
471 auto FirstNonPHIOrDbgOrAlloca = BB.getFirstNonPHIOrDbgOrAlloca();
472 if (
auto *Call = dyn_cast<CallInst>(&*FirstNonPHIOrDbgOrAlloca)) {
473 if (
Call->getIntrinsicID() ==
474 Intrinsic::experimental_convergence_entry ||
475 Call->getIntrinsicID() == Intrinsic::experimental_convergence_loop)
476 FirstNonPHIOrDbgOrAlloca++;
479 TopologicalSort.pop();
484void IRNormalizer::reorderDefinition(
485 Instruction *Definition, std::stack<Instruction *> &TopologicalSort,
489 Visited.
insert(Definition);
493 const auto FirstNonPHIOrDbgOrAlloca =
497 if (Definition->
comesBefore(&*FirstNonPHIOrDbgOrAlloca))
501 for (
auto &Operand : Definition->
operands()) {
502 if (
auto *
Op = dyn_cast<Instruction>(Operand)) {
505 reorderDefinition(
Op, TopologicalSort, Visited);
512 if (
auto *Call = dyn_cast<CallInst>(Definition)) {
513 if (
Call->isMustTailCall())
515 if (
Call->getIntrinsicID() == Intrinsic::experimental_deoptimize)
517 if (
Call->getIntrinsicID() == Intrinsic::experimental_convergence_entry)
519 if (
Call->getIntrinsicID() == Intrinsic::experimental_convergence_loop)
522 if (
auto *BitCast = dyn_cast<BitCastInst>(Definition)) {
523 if (
auto *Call = dyn_cast<CallInst>(BitCast->getOperand(0))) {
524 if (
Call->isMustTailCall())
529 TopologicalSort.emplace(Definition);
537void IRNormalizer::reorderInstructionOperandsByNames(
Instruction *
I)
const {
546 for (
auto &
Op :
I->operands()) {
547 if (
auto *V = dyn_cast<Value>(
Op)) {
548 if (isa<Instruction>(V)) {
550 Operands.push_back(std::pair<std::string, Value *>(
V->getName(), V));
552 std::string TextRepresentation;
554 Op->printAsOperand(Stream,
false);
555 Operands.push_back(std::pair<std::string, Value *>(Stream.str(), V));
564 unsigned Position = 0;
565 for (
auto &
Op :
I->operands()) {
575void IRNormalizer::reorderPHIIncomingValues(
PHINode *Phi)
const {
580 for (
auto &BB :
Phi->blocks()) {
581 Value *
V =
Phi->getIncomingValueForBlock(BB);
582 Values.
push_back(std::pair<Value *, BasicBlock *>(V, BB));
586 llvm::sort(Values, [](
const std::pair<Value *, BasicBlock *> &LHS,
587 const std::pair<Value *, BasicBlock *> &RHS) {
592 for (
unsigned i = 0; i < Values.
size(); ++i) {
593 Phi->setIncomingBlock(i, Values[i].second);
594 Phi->setIncomingValue(i, Values[i].first);
604IRNormalizer::collectOutputInstructions(
Function &
F)
const {
618bool IRNormalizer::isOutput(
const Instruction *
I)
const {
620 return I->mayHaveSideEffects() || isa<ReturnInst>(
I);
627bool IRNormalizer::isInitialInstruction(
const Instruction *
I)
const {
630 return !
I->user_empty() && hasOnlyImmediateOperands(
I);
636bool IRNormalizer::hasOnlyImmediateOperands(
const Instruction *
I)
const {
637 for (
const auto &
Op :
I->operands())
638 if (isa<Instruction>(
Op))
665 for (
const auto &
B : *Func) {
666 for (
const auto &E :
B) {
677 for (
auto *U :
I->users()) {
678 if (
auto *UI = dyn_cast<Instruction>(U)) {
693 IRNormalizer{}.runOnFunction(
F);
Expand Atomic instructions
static GCRegistry::Add< OcamlGC > B("ocaml", "ocaml 3.10-compatible GC")
static GCRegistry::Add< ErlangGC > A("erlang", "erlang-compatible garbage collector")
static bool runOnFunction(Function &F, bool PostInlining)
Module.h This file contains the declarations for the Module class.
mir Rename Register Operands
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.
A container for analyses that lazily runs them and caches their results.
LLVM Basic Block Representation.
const_iterator getFirstNonPHIOrDbgOrAlloca() const
Returns an iterator to the first instruction in this block that is not a PHINode, a debug intrinsic,...
Represents analyses that only rely on functions' control flow.
This class represents an Operation in the Expression.
Implements a dense probed hash-table based set.
bool isTerminator() const
bool comesBefore(const Instruction *Other) const
Given an instruction Other in the same basic block as this instruction, return true if this instructi...
void moveBefore(Instruction *MovePos)
Unlink this instruction from its current basic block and insert it into the basic block that MovePos ...
A set of analyses that are preserved following a run of a transformation pass.
void preserveSet()
Mark an analysis set as preserved.
A vector that has set insertion semantics.
iterator end()
Get an iterator to the end of the SetVector.
iterator begin()
Get an iterator to the beginning of the SetVector.
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
SmallPtrSet - This class implements a set which is optimized for holding SmallSize or less elements.
SmallString - A SmallString is just a SmallVector with methods and accessors that make it work better...
void push_back(const T &Elt)
This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small.
StringRef - Represent a constant reference to a string, i.e.
Twine - A lightweight data structure for efficiently representing the concatenation of temporary valu...
LLVM Value Representation.
StringRef getName() const
Return a constant reference to the value's name.
void dump() const
Support for debugging, callable in GDB: V->dump()
const ParentTy * getParent() const
A raw_ostream that writes to an std::string.
initializer< Ty > init(const Ty &Val)
uint64_t hash_16_bytes(uint64_t low, uint64_t high)
NodeAddr< PhiNode * > Phi
NodeAddr< FuncNode * > Func
This is an optimization pass for GlobalISel generic memory operations.
void sort(IteratorTy Start, IteratorTy End)
raw_ostream & dbgs()
dbgs() - This returns a reference to a raw_ostream for debugging messages.
PreservedAnalyses run(Function &F, FunctionAnalysisManager &AM) const