Skip to content

Commit e100ef4

Browse files
alexmalyshevmeta-codesync[bot]
authored andcommitted
Have a cheaper Phi::create() that takes an ordered list
Summary: The current way to create a Phi requires building a hashmap of block -> value. Often times, we already know the order of the (block, value) pairs (or we can trivially sort and achieve it). Add a new ctor and setArgs() overload where we can pass in a `std::span<std::tuple<BasicBlock*, Register*>>` instead. Reviewed By: yoney Differential Revision: D114414426 fbshipit-source-id: 4bfa212417539c3e8a2fe93a7cd0d08adc2e8e76
1 parent 56b7586 commit e100ef4

3 files changed

Lines changed: 61 additions & 44 deletions

File tree

cinderx/Jit/hir/hir.cpp

Lines changed: 40 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
#include "cinderx/Jit/threaded_compile.h"
77

88
#include <algorithm>
9+
#include <ranges>
910

1011
namespace cinderx::jit::hir {
1112

@@ -161,7 +162,12 @@ std::string_view CallCFunc::funcName() const {
161162
}
162163

163164
void Phi::setArgs(const std::unordered_map<BasicBlock*, Register*>& args) {
164-
JIT_DCHECK(numOperands() == args.size(), "arg mismatch");
165+
// Can't resize a phi, the operands have already been allocated inline.
166+
JIT_THROW_IF(
167+
numOperands() != args.size(),
168+
"Trying to update phi with {} arguments to one with {} arguments",
169+
numOperands(),
170+
args.size());
165171

166172
basic_blocks_.clear();
167173
basic_blocks_.reserve(args.size());
@@ -184,6 +190,31 @@ void Phi::setArgs(const std::unordered_map<BasicBlock*, Register*>& args) {
184190
}
185191
}
186192

193+
void Phi::setArgs(std::span<std::tuple<BasicBlock*, Register*>> args) {
194+
// Can't resize a phi, the operands have already been allocated inline.
195+
JIT_THROW_IF(
196+
numOperands() != args.size(),
197+
"Trying to update phi with {} arguments to one with {} arguments",
198+
numOperands(),
199+
args.size());
200+
201+
JIT_DCHECK(
202+
std::ranges::is_sorted(
203+
args,
204+
[](const auto& a, const auto& b) {
205+
return std::get<0>(a)->id < std::get<0>(b)->id;
206+
}),
207+
"Phi must be created with a (block,value) list sorted by block ID");
208+
209+
basic_blocks_.clear();
210+
basic_blocks_.reserve(args.size());
211+
212+
for (size_t i = 0; i < args.size(); ++i) {
213+
basic_blocks_.push_back(std::get<0>(args[i]));
214+
operandAt(i) = std::get<1>(args[i]);
215+
}
216+
}
217+
187218
std::size_t Phi::blockIndex(const BasicBlock* block) const {
188219
auto it = std::lower_bound(
189220
basic_blocks_.begin(), basic_blocks_.end(), block, [](auto b1, auto b2) {
@@ -1180,32 +1211,6 @@ void BasicBlock::fixupPhis(BasicBlock* old_pred, BasicBlock* new_pred) {
11801211
forEachPhi([&](Phi& phi) { phi.replacePredecessor(old_pred, new_pred); });
11811212
}
11821213

1183-
void BasicBlock::addPhiPredecessor(BasicBlock* old_pred, BasicBlock* new_pred) {
1184-
std::vector<Phi*> replacements;
1185-
forEachPhi([&](Phi& phi) {
1186-
for (auto block : phi.basicBlocks()) {
1187-
if (block == old_pred) {
1188-
replacements.push_back(&phi);
1189-
break;
1190-
}
1191-
}
1192-
});
1193-
1194-
for (auto phi : replacements) {
1195-
std::unordered_map<BasicBlock*, Register*> args;
1196-
for (size_t i = 0, n = phi->numOperands(); i < n; ++i) {
1197-
auto block = phi->basicBlocks()[i];
1198-
if (block == old_pred) {
1199-
args[new_pred] = phi->getOperand(i);
1200-
}
1201-
args[block] = phi->getOperand(i);
1202-
}
1203-
1204-
phi->replaceWith(*Phi::create(phi->output(), args));
1205-
delete phi;
1206-
}
1207-
}
1208-
12091214
void BasicBlock::removePhiPredecessor(BasicBlock* old_pred) {
12101215
for (auto it = instrs_.begin(); it != instrs_.end();) {
12111216
auto& instr = *it;
@@ -1214,14 +1219,15 @@ void BasicBlock::removePhiPredecessor(BasicBlock* old_pred) {
12141219
break;
12151220
}
12161221

1217-
Phi* phi = static_cast<Phi*>(&instr);
1218-
std::unordered_map<BasicBlock*, Register*> args;
1219-
for (size_t i = 0, n = phi->numOperands(); i < n; ++i) {
1220-
auto block = phi->basicBlocks()[i];
1221-
if (block == old_pred) {
1222-
continue;
1222+
auto phi = static_cast<Phi*>(&instr);
1223+
auto num_operands = phi->numOperands();
1224+
std::vector<std::tuple<BasicBlock*, Register*>> args;
1225+
args.reserve(num_operands);
1226+
for (size_t i = 0; i < num_operands; ++i) {
1227+
BasicBlock* block = phi->basicBlocks()[i];
1228+
if (block != old_pred) {
1229+
args.emplace_back(block, phi->getOperand(i));
12231230
}
1224-
args[block] = phi->getOperand(i);
12251231
}
12261232
phi->replaceWith(*Phi::create(phi->output(), args));
12271233
delete phi;

cinderx/Jit/hir/hir.h

Lines changed: 14 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
#include <span>
1919
#include <string>
2020
#include <string_view>
21+
#include <tuple>
2122
#include <type_traits>
2223
#include <unordered_map>
2324
#include <unordered_set>
@@ -1144,12 +1145,11 @@ class INSTR_CLASS(Phi, (TTop), HasOutput, Operands<>) {
11441145
public:
11451146
explicit Phi(Register* dst) : InstrT(dst) {}
11461147

1147-
static Phi* create(
1148-
Register* dst,
1149-
const std::unordered_map<BasicBlock*, Register*>& args) {
1148+
template <typename PhiArgs>
1149+
static Phi* create(Register* dst, PhiArgs&& args) {
11501150
void* ptr = Instr::allocate(sizeof(Phi), args.size());
11511151
auto phi = new (ptr) Phi(dst);
1152-
phi->setArgs(args);
1152+
phi->setArgs(std::forward<PhiArgs>(args));
11531153
return phi;
11541154
}
11551155

@@ -1172,15 +1172,22 @@ class INSTR_CLASS(Phi, (TTop), HasOutput, Operands<>) {
11721172
// Return the index of the given predecessor in basic_blocks.
11731173
std::size_t blockIndex(const BasicBlock* block) const;
11741174

1175+
// Replace a predecessor block with a new block in the phi, keeping the same
1176+
// associated value.
11751177
void replacePredecessor(BasicBlock* old_pred, BasicBlock* new_pred);
11761178

11771179
const std::vector<BasicBlock*> basicBlocks() const {
11781180
return basic_blocks_;
11791181
}
11801182

1183+
private:
1184+
// Set a phi's arguments through a block -> value map.
11811185
void setArgs(const std::unordered_map<BasicBlock*, Register*>& args);
11821186

1183-
private:
1187+
// Set a phi's arguments through a (block, value) list. The list must already
1188+
// be sorted by the block's ID.
1189+
void setArgs(std::span<std::tuple<BasicBlock*, Register*>> args);
1190+
11841191
// List of incoming blocks, sorted by ascending block ID.
11851192
std::vector<BasicBlock*> basic_blocks_;
11861193
};
@@ -4116,9 +4123,8 @@ class BasicBlock : public IntrusiveListNode<BasicBlock> {
41164123

41174124
// Replace any references to old_pred in this block's Phis with new_pred.
41184125
void fixupPhis(BasicBlock* old_pred, BasicBlock* new_pred);
4119-
// Adds a new predecessor to the phi that follows from the old predecessor
4120-
void addPhiPredecessor(BasicBlock* old_pred, BasicBlock* new_pred);
4121-
// Removes any references to old_pred in this block's Phis
4126+
4127+
// Removes any references to old_pred in this block's Phis.
41224128
void removePhiPredecessor(BasicBlock* old_pred);
41234129

41244130
// Call f with each Phi instruction at the beginning of this block.

cinderx/Jit/hir/parser.cpp

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -805,6 +805,10 @@ HIRParser::parseInstr(std::string_view opcode, Register* dst, int bb_index) {
805805
for (auto& input : info.inputs) {
806806
input.value = parseRegister();
807807
}
808+
std::sort(
809+
info.inputs.begin(),
810+
info.inputs.end(),
811+
[](const PhiInput& a, const PhiInput& b) { return a.bb < b.bb; });
808812
phis_[bb_index].emplace_back(std::move(info));
809813
break;
810814
}
@@ -1316,9 +1320,10 @@ void HIRParser::realizePhis() {
13161320
auto& front = block->front();
13171321

13181322
for (auto& phi : pair.second) {
1319-
std::unordered_map<BasicBlock*, Register*> inputs;
1323+
std::vector<std::tuple<BasicBlock*, Register*>> inputs;
1324+
inputs.reserve(phi.inputs.size());
13201325
for (auto& info : phi.inputs) {
1321-
inputs.emplace(index_to_bb_[info.bb], info.value);
1326+
inputs.emplace_back(index_to_bb_[info.bb], info.value);
13221327
}
13231328
(Phi::create(phi.dst, inputs))->insertBefore(front);
13241329
}

0 commit comments

Comments
 (0)