forked from facebook/hermes
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathBCOpt.cpp
More file actions
113 lines (95 loc) · 3.67 KB
/
BCOpt.cpp
File metadata and controls
113 lines (95 loc) · 3.67 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
/*
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
#include "hermes/BCGen/BCOpt.h"
#include "hermes/BCGen/RegAlloc.h"
#include "hermes/IR/Analysis.h"
#include "hermes/IR/CFG.h"
#include "hermes/IR/IR.h"
#include "hermes/IR/IRBuilder.h"
#include "hermes/IR/Instrs.h"
#include "hermes/Utils/Dumper.h"
#include "llvh/ADT/PostOrderIterator.h"
#include "llvh/ADT/SmallPtrSet.h"
#include "llvh/Support/Debug.h"
#include "llvh/Support/raw_ostream.h"
#define DEBUG_TYPE "bcopt"
using namespace hermes;
using llvh::cast;
using llvh::dbgs;
using llvh::dyn_cast;
using llvh::dyn_cast_or_null;
using llvh::isa;
bool MovElimination::runOnFunction(Function *F) {
bool changed = false;
// Keeps track of last assignment point of each register.
llvh::DenseMap<Register, unsigned> lastAssignment;
// Keeps track of last use point of each register.
llvh::DenseMap<Register, unsigned> lastUse;
IRBuilder::InstructionDestroyer destroyer;
// For each basic block, do a forward scan and remember when each variable was
// last assigned. Use this information to remove MOVs.
PostOrderAnalysis PO(F);
llvh::SmallVector<BasicBlock *, 16> order(PO.rbegin(), PO.rend());
for (auto *BB : order) {
unsigned index = 0;
lastAssignment.clear();
lastUse.clear();
for (auto &it : *BB) {
// Skip basic blocks with unallocated instructions.
if (!RA_.isAllocated(&it))
continue;
// Set to true if the current instruction is a mov which we eliminated.
bool movRemoved = false;
index++;
Register dest = RA_.getRegister(&it);
if (auto *mov = llvh::dyn_cast<MovInst>(&it)) {
Value *op = mov->getSingleOperand();
// If the operand is an instruction in the current basic block and it
// has one user then maybe we can write it directly into the target
// register.
auto *IOp = llvh::dyn_cast<Instruction>(op);
// Skip basic blocks with unallocated instructions.
if (!RA_.isAllocated(op))
continue;
if (IOp && op->hasOneUser() && IOp->getParent() == BB) {
Register src = RA_.getRegister(IOp);
// Get the index of the instructions that last wrote to the source and
// dest registers. Note lookup() returns 0 if not found.
unsigned srcIdx = lastAssignment.lookup(src);
unsigned destIdx = lastAssignment.lookup(dest);
unsigned destUseIdx = lastUse.lookup(dest);
// If the dest register was last written *after* the src register was
// written into then we know that it is *live* in the range src..dest
// so we can't remove the MOV. Only if the dest was live before the
// src can we remove it.
// Additionally, dest must not have uses in the range (src..dest).
if (destIdx < srcIdx && !llvh::isa<PhiInst>(IOp) &&
destUseIdx <= srcIdx) {
RA_.updateRegister(op, dest);
destroyer.add(mov);
mov->replaceAllUsesWith(op);
changed = true;
movRemoved = true;
}
}
}
// Save the current instruction and report the last index where the
// register was modified.
lastAssignment[dest] = index;
// Save the last use point of every register, but skip mov-s which we just
// eliminated.
if (!movRemoved) {
for (unsigned i = 0, e = it.getNumOperands(); i != e; ++i) {
auto *op = it.getOperand(i);
if (RA_.isAllocated(op))
lastUse[RA_.getRegister(op)] = index;
}
}
}
}
return changed;
}