Skip to content

Commit e9c14b0

Browse files
mengdilinfacebook-github-bot
authored andcommitted
Refine Type of CondBranchCheckType When Its Branch Leads to Unreachable
Summary: For example, in this program: ``` bb 0 { v0:Object = LoadArg<0> CondBranchCheckType<1, 2, TupleExact> v0 } bb 1 { ... } bb 2 { Unreachable } ``` We know that because `bb 2` is unreachable, `v0` must be a `TupleExact`. This diff inserts a `RefineType<TupleExact> v0` before the `Branch` that replaces the `CondBranchCheckType`. And if `bb 1` had been unreachable, the `RefineType `would be for `Object - TupleExact`. Reviewed By: swtaarrs Differential Revision: D41747741 fbshipit-source-id: 9714c75
1 parent 15df819 commit e9c14b0

File tree

2 files changed

+123
-6
lines changed

2 files changed

+123
-6
lines changed

Jit/hir/optimization.cpp

Lines changed: 27 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -530,6 +530,8 @@ static bool absorbDstBlock(BasicBlock* block) {
530530
bool CleanCFG::RemoveUnreachableInstructions(CFG* cfg) {
531531
bool modified = false;
532532
std::vector<BasicBlock*> blocks = cfg->GetPostOrderTraversal();
533+
DominatorAnalysis dom(*cfg->func);
534+
RegUses reg_uses = collectDirectRegUses(*cfg->func);
533535

534536
for (BasicBlock* block : blocks) {
535537
auto it = block->begin();
@@ -597,9 +599,31 @@ bool CleanCFG::RemoveUnreachableInstructions(CFG* cfg) {
597599
"true branch must be unreachable");
598600
target = cond_branch->false_bb();
599601
}
600-
// TODO(T138210636): When replacing CondBranchCheckType with Branch
601-
// due to an unreachable target, leave an appropriate AssertType in
602-
// its place
602+
603+
if (branch->IsCondBranchCheckType()) {
604+
auto check_type_branch = static_cast<CondBranchCheckType*>(branch);
605+
Register* refined_value = cfg->func->env.AllocateRegister();
606+
Type check_type = check_type_branch->type();
607+
if (target == cond_branch->false_bb()) {
608+
check_type = TTop - check_type_branch->type();
609+
}
610+
611+
Register* operand = check_type_branch->GetOperand(0);
612+
RefineType::create(refined_value, check_type, operand)
613+
->InsertBefore(*cond_branch);
614+
auto uses = reg_uses.find(operand);
615+
if (uses == reg_uses.end()) {
616+
break;
617+
}
618+
std::unordered_set<Instr*>& instrs_using_reg = uses->second;
619+
const std::unordered_set<const BasicBlock*>& dom_set =
620+
dom.getBlocksDominatedBy(target);
621+
for (Instr* instr : instrs_using_reg) {
622+
if (dom_set.count(instr->block())) {
623+
instr->ReplaceUsesOf(operand, refined_value);
624+
}
625+
}
626+
}
603627
cond_branch->ReplaceWith(*Branch::create(target));
604628
} else {
605629
JIT_CHECK(false, "Unexpected branch instruction %s", *branch);

RuntimeTests/hir_tests/clean_cfg_test.txt

Lines changed: 96 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -204,7 +204,7 @@ CleanUpCondBranchToTwoUnreachableEdges
204204
# HIR
205205
fun test {
206206
bb 0 {
207-
v0 = LoadArg<0; CInt32>
207+
v0 = LoadArg<0>
208208
v1 = GuardType<Tuple> v0
209209
CondBranch<1, 2> v0
210210
}
@@ -237,7 +237,7 @@ CleanUpExistingUnreachable
237237
# HIR
238238
fun test {
239239
bb 0 {
240-
v0 = LoadArg<0; CInt32>
240+
v0 = LoadArg<0>
241241
v1 = GuardType<Tuple> v0
242242
CondBranch<1, 2> v0
243243
}
@@ -274,7 +274,7 @@ CleanUpLoopWithUnreachable
274274
# HIR
275275
fun test {
276276
bb 0 {
277-
v0 = LoadArg<0; CInt32>
277+
v0 = LoadArg<0>
278278
v1 = GuardType<Tuple> v0
279279
Branch<1>
280280
}
@@ -329,3 +329,96 @@ fun test {
329329
}
330330
}
331331
---
332+
CleanUpTruthyBranchOfCondBranchCheckType
333+
---
334+
# HIR
335+
fun test {
336+
bb 0 {
337+
v0 = LoadArg<0>
338+
CondBranchCheckType<1, 2, Tuple> v0
339+
}
340+
341+
bb 1 (preds 0) {
342+
v1:Object = BinaryOp<Add> v0 v0
343+
CondBranch<3, 4> v1
344+
}
345+
346+
bb 2 (preds 0) {
347+
v2:Bottom = LoadConst<Bottom>
348+
Branch<3>
349+
}
350+
351+
bb 3 (preds 1, 2) {
352+
v4 = Phi<1, 2> v1 v2
353+
Return v4
354+
}
355+
356+
bb 4 (preds 1) {
357+
v5:Object = BinaryOp<Add> v1 v1
358+
CondBranch<1, 3> v5
359+
}
360+
}
361+
---
362+
fun test {
363+
bb 0 {
364+
v0:Object = LoadArg<0>
365+
v6:Tuple = RefineType<Tuple> v0
366+
Branch<1>
367+
}
368+
369+
bb 1 (preds 0, 4) {
370+
v1:Object = BinaryOp<Add> v6 v6 {
371+
FrameState {
372+
NextInstrOffset 0
373+
}
374+
}
375+
CondBranch<3, 4> v1
376+
}
377+
378+
bb 4 (preds 1) {
379+
v5:Object = BinaryOp<Add> v1 v1 {
380+
FrameState {
381+
NextInstrOffset 0
382+
}
383+
}
384+
CondBranch<1, 3> v5
385+
}
386+
387+
bb 3 (preds 1, 4) {
388+
Return v1
389+
}
390+
}
391+
---
392+
CleanUpFalseBranchOfCondBranchCheckType
393+
---
394+
# HIR
395+
fun test {
396+
bb 0 {
397+
v0 = LoadArg<0>
398+
CondBranchCheckType<2, 1, Tuple> v0
399+
}
400+
401+
bb 1 (preds 0) {
402+
v1:Object = BinaryOp<Add> v0 v0
403+
Return v1
404+
}
405+
406+
bb 2 (preds 0) {
407+
v2:Bottom = LoadConst<Bottom>
408+
Return v2
409+
}
410+
}
411+
---
412+
fun test {
413+
bb 0 {
414+
v0:Object = LoadArg<0>
415+
v3:{Array|BaseException|Bytes|Cell|Code|Dict|Float|Frame|Func|Gen|List|Long|NoneType|ObjectExact|ObjectUser|Set|Slice|Type|Unicode|WaitHandle} = RefineType<{Array|BaseException|Bytes|CBool|CDouble|CInt|CPtr|Cell|Code|Dict|Float|Frame|Func|Gen|List|Long|NoneType|Nullptr|ObjectExact|ObjectUser|Set|Slice|Type|Unicode|WaitHandle}> v0
416+
v1:Object = BinaryOp<Add> v3 v3 {
417+
FrameState {
418+
NextInstrOffset 0
419+
}
420+
}
421+
Return v1
422+
}
423+
}
424+
---

0 commit comments

Comments
 (0)