-
Notifications
You must be signed in to change notification settings - Fork 0
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
feat: Phi nodes #58
Comments
For a region with more than 2 predecessors, it might be worthwhile to change the |
The output is a little bit wonky here: // RegionId(7)
if (<temp.ciphertype>#45 == "RC4")
{
}
// RegionId(6)
else
{
// RegionId(9)
if (<temp.ciphertype>#45 == "AES")
{
}
// RegionId(8)
else
{
}
}
phi<idx=0, regions=(RegionId(9), RegionId(8), RegionId(6))> = phi<idx=1, regions=(RegionId(9), RegionId(8), RegionId(6))>; Specifically, when we have "empty" if/else blocks (not actually empty, because
|
Sample output for function onCreated()
{
<temp.thingOne>#8 = true;
<temp.thingTwo>#9 = true;
<temp.thingThree>#10 = false;
// RegionId(1)
if (<temp.thingOne>#7)
{
}
phi<idx=1, regions=(RegionId(2))> = phi<idx=2, regions=(RegionId(2))>;
// RegionId(4)
if (<temp.thingOne>#7)
{
// RegionId(5)
if (<temp.thingTwo>#4)
{
}
}
phi<idx=3, regions=(RegionId(6))> = phi<idx=4, regions=(RegionId(6))>;
// RegionId(8)
if (<temp.thingOne>#7)
{
}
phi<idx=4, regions=(RegionId(9))> = phi<idx=5, regions=(RegionId(9))>;
// RegionId(11)
if (<temp.thingOne>#7)
{
// RegionId(12)
if (<temp.thingTwo>#4)
{
}
}
phi<idx=6, regions=(RegionId(13))> = phi<idx=7, regions=(RegionId(13))>;
// RegionId(15)
if (<temp.thingOne>#7)
{
}
// RegionId(17)
if (phi<idx=8, regions=(RegionId(15))>)
{
}
phi<idx=8, regions=(RegionId(18))> = phi<idx=9, regions=(RegionId(18))>;
// RegionId(20)
if (<temp.thingOne>#7)
{
}
// RegionId(22)
if (phi<idx=10, regions=(RegionId(20))>)
{
// RegionId(23)
if (<temp.thingThree>#2)
{
}
}
phi<idx=11, regions=(RegionId(24))> = phi<idx=12, regions=(RegionId(24))>;
// RegionId(26)
if (<temp.thingOne>#7)
{
}
// RegionId(28)
if (phi<idx=13, regions=(RegionId(26))>)
{
// RegionId(29)
if (<temp.thingThree>#2)
{
// RegionId(30)
if (<temp.thingOne>#7)
{
fn_call#32 = returnAndShortCircuit(true, false);
}
}
}
phi<idx=15, regions=(RegionId(31))> = phi<idx=16, regions=(RegionId(31))>;
fn_call#34 = echo("simpleAndTwo: " @ <temp.simpleAndTwo>#12);
fn_call#35 = echo("simpleAndThree: " @ <temp.simpleAndThree>#15);
fn_call#36 = echo("simpleOrTwo: " @ <temp.simpleOrTwo>#18);
fn_call#37 = echo("simpleOrThree: " @ <temp.simpleOrThree>#21);
fn_call#38 = echo("complex: " @ <temp.complex>#24);
fn_call#39 = echo("complexTwo: " @ <temp.complexTwo>#27);
return 0x0;
} Some thoughts:
|
When we iterate the predecessor blocks, we shouldn't rely on for (i, frame) in exec.iter().rev().enumerate() {
match frame {
ExecutionFrame::StandaloneNode(n) => {
// Ensure we have a slot in predecessor_regions for this index.
if predecessor_regions.len() <= i {
// If not, extend the vector so that index i is available.
predecessor_regions.resize(i + 1, Vec::new());
}
// Record the region info (e.g., pred.1 and pred.2) for this phi candidate.
predecessor_regions[i].push((pred.1, pred.2, n.clone()));
}
// TODO: Bug. BuildingArray is another possible frame type.
_ => {
return Err(FunctionDecompilerError::Other {
message: "Expected StandaloneNode".to_string(),
context: ctx.get_error_context(),
backtrace: Backtrace::capture(),
});
}
}
} Therefore, it may be wise to store the |
Consider the following enhanced for loop: function enhancedForLoop()
{
lit#8 = "baz";
lit#9 = "bar";
lit#10 = "foo";
<temp.arr>#11 = {lit#10, lit#9, lit#8};
lit#12 = 0x0;
<temp.i>#13 = lit#12;
lit#14 = 0x0;
// RegionId(2)
if (<temp.elem>#2 : <temp.arr>#5)
{
fn_call#15 = echo#3(<temp.elem>#2);
<temp.i>#16++;
lit#17 = lit#14 + 0x1;
goto RegionId(1);
}
// RegionId(3)
else
{
lit#18 = "done enhanced for";
fn_call#19 = echo#3(lit#18);
lit#20 = "num elems: ";
fn_call#21 = echo#3(lit#20 @ <temp.i>#7);
lit#22 = 0x0;
return lit#22;
}
} If we want to conform to SSA, we need to introduce a phi node within the for loop to merge Instead, it should look something like this: lit#14 = 0; // initial value outside the loop
loop_header:
lit#23 = φ(lit#14, lit#17) // lit#23 is the "current" value, merging the initial value and the back edge
// ... use lit#23 in the loop ...
lit#17 = lit#23 + 1; // new value computed in the loop body
goto loop_header; The above case is indicative that we should re-think our phi node resolution strategy. Here's a proposal for a new strategy:
|
Introduce phi nodes using the following algorithm:
DfsPostOrder
, so anyBasicBlock
that is a parent of a child block should already be traversed)AstNode
left on the stack, introducephi
nodes, with their arguments as the predecessorRegionId
as merge variabes.We may also have to consider weird edge cases like the following:
Sample algorithm:
The text was updated successfully, but these errors were encountered: