Skip to content

Commit cf954ec

Browse files
alexmalyshevmeta-codesync[bot]
authored andcommitted
Always RefineType on the success branch of a CondBranchCheckType
Summary: The JIT currently has a strange setup where sometimes it'll emit `RefineType` instructions after a `CondBranchCheckType` in the HIR builder and other times it'll skip doing so but then it can materialize them in `removeUnreachableInstructions()`. The builder should always emit them, to be consistent. This gets rid of the register uses map and dominator tree usage in `removeUnreachableInstructions()` which is a nice cleanup. Technically this diff removes the failure branch `RefineType` that `removeUnreachableInstructions()` can add. That's an intentional sacrifice. The types in the failure branch are as precise as `TTop - TTuple` or `TTop - TType`; they're not useful for optimizations. If we really want this to work well, we'll want `reflowTypes()` to do a better job typing all codepaths through a CFG instead of doing this in unreachable code deletion. Reviewed By: DinoV Differential Revision: D115009155 fbshipit-source-id: f85d003e01bde3998d7a5d893ed250e7915ff0f2
1 parent f611695 commit cf954ec

7 files changed

Lines changed: 900 additions & 928 deletions

File tree

cinderx/Jit/hir/builder.cpp

Lines changed: 25 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -2226,7 +2226,7 @@ void HIRBuilder::emitLoadIterableArg(
22262226
tc.frame.stack.topPut(0, tuple);
22272227
tc.emitSnapshot();
22282228

2229-
tuple_path.emit<Assign>(tuple, iterable);
2229+
tuple_path.emit<RefineType>(tuple, TTuple, iterable);
22302230
tuple_path.emit<Branch>(tc.block);
22312231

22322232
non_tuple_path.emit<GetTuple>(tuple, iterable, non_tuple_path.frame);
@@ -3410,7 +3410,6 @@ void HIRBuilder::emitFastLen(
34103410
BasicBlock* fast_path = cfg.allocateBlock();
34113411
tc.emit<CondBranchCheckType>(collection, type, fast_path, deopt_path.block);
34123412
tc.block = fast_path;
3413-
// TASK(T105038867): Remove once we have RefineTypeInsertion
34143413
tc.emit<RefineType>(collection, type, collection);
34153414
} else {
34163415
collection = tc.frame.stack.pop();
@@ -4031,7 +4030,7 @@ void HIRBuilder::emitGetYieldFromIter(CFG& cfg, TranslationContext& tc) {
40314030
tc.emit<Branch>(done_block);
40324031

40334032
tc.block = nop_block;
4034-
tc.emit<Assign>(iter_out, iter_in);
4033+
tc.emit<RefineType>(iter_out, TGen, iter_in);
40354034
tc.emit<Branch>(done_block);
40364035

40374036
tc.block = done_block;
@@ -4142,23 +4141,29 @@ void HIRBuilder::emitUnpackSequence(
41424141
}
41434142

41444143
tc.block = tuple_fast_path;
4144+
Register* tuple_seq = allocateTemp();
41454145
Register* offset_reg = allocateTemp();
4146+
tc.emit<RefineType>(tuple_seq, TTupleExact, seq);
41464147
tc.emit<LoadConst>(
41474148
offset_reg, Type::fromCInt(offsetof(PyTupleObject, ob_item), TCInt64));
4148-
tc.emit<LoadFieldAddress>(list_mem, seq, offset_reg);
4149+
tc.emit<LoadFieldAddress>(list_mem, tuple_seq, offset_reg);
41494150
tc.emit<Branch>(fast_path);
41504151

41514152
tc.block = list_fast_path;
4153+
Register* list_seq = allocateTemp();
4154+
tc.emit<RefineType>(list_seq, TListExact, seq);
41524155
tc.emit<LoadField>(
4153-
list_mem, seq, "ob_item", offsetof(PyListObject, ob_item), TCPtr);
4156+
list_mem, list_seq, "ob_item", offsetof(PyListObject, ob_item), TCPtr);
41544157
tc.emit<Branch>(fast_path);
41554158

41564159
tc.block = fast_path;
41574160

4161+
Register* fast_seq = allocateTemp();
41584162
Register* seq_size = allocateTemp();
41594163
Register* target_size = allocateTemp();
41604164
Register* is_equal = allocateTemp();
4161-
tc.emit<LoadVarObjectSize>(seq_size, seq);
4165+
tc.emit<RefineType>(fast_seq, TListExact | TTupleExact, seq);
4166+
tc.emit<LoadVarObjectSize>(seq_size, fast_seq);
41624167
tc.emit<LoadConst>(target_size, Type::fromCInt(count, TCInt64));
41634168
tc.emit<PrimitiveCompare>(
41644169
is_equal, PrimitiveCompareOp::kEqual, seq_size, target_size);
@@ -4171,7 +4176,8 @@ void HIRBuilder::emitUnpackSequence(
41714176
// Write to pre-allocated items[] registers shared with the slow path.
41724177
for (int idx = count - 1; idx >= 0; --idx) {
41734178
tc.emit<LoadConst>(idx_reg, Type::fromCInt(idx, TCInt64));
4174-
tc.emit<LoadArrayItem>(items[idx], list_mem, idx_reg, seq, 0, TObject);
4179+
tc.emit<LoadArrayItem>(
4180+
items[idx], list_mem, idx_reg, fast_seq, 0, TObject);
41754181
}
41764182
tc.emit<Branch>(done_path);
41774183

@@ -4601,21 +4607,22 @@ void HIRBuilder::emitGetAwaitable(
46014607
BasicBlock* block_assert_not_awaited_coro = cfg.allocateBlock();
46024608
BasicBlock* block_done = cfg.allocateBlock();
46034609
BasicBlock* block_check_coro = cfg.allocateBlock();
4610+
4611+
auto our_coro_type =
4612+
Type::fromTypeExact(cinderx::getModuleState()->coro_type);
4613+
auto coro_type = Type::fromTypeExact(&PyCoro_Type);
4614+
46044615
tc.emit<CondBranchCheckType>(
4605-
iter,
4606-
Type::fromTypeExact(cinderx::getModuleState()->coro_type),
4607-
block_assert_not_awaited_coro,
4608-
block_check_coro);
4616+
iter, our_coro_type, block_assert_not_awaited_coro, block_check_coro);
46094617
tc.block = block_check_coro;
46104618
tc.emit<CondBranchCheckType>(
4611-
iter,
4612-
Type::fromTypeExact(&PyCoro_Type),
4613-
block_assert_not_awaited_coro,
4614-
block_done);
4619+
iter, coro_type, block_assert_not_awaited_coro, block_done);
46154620
Register* yf = allocateTemp();
46164621
tc.block = block_assert_not_awaited_coro;
4622+
Register* coro_iter = allocateTemp();
4623+
tc.emit<RefineType>(coro_iter, our_coro_type | coro_type, iter);
46174624
tc.emit<CallCFunc>(
4618-
1, yf, CallCFunc::Func::kJitGen_yf, std::vector<Register*>{iter});
4625+
1, yf, CallCFunc::Func::kJitGen_yf, std::vector<Register*>{coro_iter});
46194626
BasicBlock* block_coro_already_awaited = cfg.allocateBlock();
46204627
tc.emit<CondBranch>(yf, block_coro_already_awaited, block_done);
46214628
tc.block = block_coro_already_awaited;
@@ -4714,7 +4721,8 @@ void HIRBuilder::emitDispatchEagerCoroResult(
47144721
tc.emit<CondBranchCheckType>(
47154722
stack_top, TWaitHandle, has_wh_block.block, await_block);
47164723

4717-
Register* wait_handle = stack_top;
4724+
Register* wait_handle = allocateTemp();
4725+
has_wh_block.emit<RefineType>(wait_handle, TWaitHandle, stack_top);
47184726
Register* wh_coro_or_result = allocateTemp();
47194727
Register* wh_waiter = allocateTemp();
47204728
has_wh_block.emit<WaitHandleLoadCoroOrResult>(wh_coro_or_result, wait_handle);

cinderx/Jit/hir/pass.cpp

Lines changed: 0 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -834,15 +834,6 @@ bool removeUnreachableBlocks(Function& func) {
834834

835835
bool removeUnreachableInstructions(Function& func) {
836836
bool modified = false;
837-
RegUses reg_uses = collectDirectRegUses(func);
838-
auto remove_reg_uses = [&reg_uses](Instr* instr) {
839-
for (auto op : instr->getOperands()) {
840-
auto instrs = reg_uses.find(op);
841-
if (instrs != reg_uses.end()) {
842-
instrs->second.erase(instr);
843-
}
844-
}
845-
};
846837

847838
// Post-order traversal.
848839
const DominatorTree& dom = func.domTree();
@@ -891,13 +882,6 @@ bool removeUnreachableInstructions(Function& func) {
891882
// Clean up dangling phi references
892883
if (Instr* old_term = block->getTerminator()) {
893884
for (std::size_t i = 0, n = old_term->numEdges(); i < n; ++i) {
894-
auto bb = old_term->successor(i);
895-
for (auto& potential_phi : *bb) {
896-
if (potential_phi.isPhi()) {
897-
remove_reg_uses(&potential_phi);
898-
}
899-
}
900-
901885
old_term->successor(i)->removePhiPredecessor(block);
902886
}
903887
}
@@ -906,7 +890,6 @@ bool removeUnreachableInstructions(Function& func) {
906890
Instr& instrToDelete = *it;
907891
++it;
908892
instrToDelete.unlink();
909-
remove_reg_uses(&instrToDelete);
910893
delete &instrToDelete;
911894
}
912895
}
@@ -932,39 +915,10 @@ bool removeUnreachableInstructions(Function& func) {
932915
"true branch must be unreachable");
933916
target = cond_branch->false_bb();
934917
}
935-
936-
if (branch->isCondBranchCheckType()) {
937-
// Before replacing a CondBranchCheckType with a Branch to the
938-
// reachable block, insert a RefineType to preserve the type
939-
// information implied by following that path.
940-
auto check_type_branch = static_cast<CondBranchCheckType*>(branch);
941-
Register* refined_value = func.env.allocateRegister();
942-
Type check_type = check_type_branch->type();
943-
if (target == cond_branch->false_bb()) {
944-
check_type = TTop - check_type_branch->type();
945-
}
946-
947-
Register* operand = check_type_branch->getOperand(0);
948-
RefineType::create(refined_value, check_type, operand)
949-
->insertBefore(*cond_branch);
950-
auto uses = reg_uses.find(operand);
951-
if (uses == reg_uses.end()) {
952-
break;
953-
}
954-
std::unordered_set<Instr*>& instrs_using_reg = uses->second;
955-
const std::unordered_set<const BasicBlock*>& dom_set =
956-
dom.getBlocksDominatedBy(target);
957-
for (Instr* instr : instrs_using_reg) {
958-
if (dom_set.contains(instr->block())) {
959-
instr->replaceUsesOf(operand, refined_value);
960-
}
961-
}
962-
}
963918
cond_branch->replaceWith(*Branch::create(target));
964919
} else {
965920
JIT_ABORT("Unexpected branch instruction {}", *branch);
966921
}
967-
remove_reg_uses(branch);
968922
delete branch;
969923
}
970924
}

0 commit comments

Comments
 (0)