public bool JoinBasicBlocks(IList <ILNode> body, ILBasicBlock head, int pos) { ILLabel nextLabel; ILBasicBlock nextBB; if (!head.Body.ElementAtOrDefault(head.Body.Count - 2).IsConditionalControlFlow() && head.Body.Last().Match(GMCode.B, out nextLabel) && labelGlobalRefCount[nextLabel] == 1 && labelToBasicBlock.TryGetValue(nextLabel, out nextBB) && body.Contains(nextBB) && nextBB.Body.First() == nextLabel ) { head.Body.RemoveTail(GMCode.B); nextBB.Body.RemoveAt(0); // Remove label foreach (var a in nextBB.Body) { head.Body.Add(a); // head.Body.AddRange(nextBB.Body); } body.RemoveOrThrow(nextBB); return(true); } return(false); }
List <ILNode> FindConditions(HashSet <ControlFlowNode> scope, ControlFlowNode entryNode) { List <ILNode> result = new List <ILNode>(); // Do not modify entry data scope = new HashSet <ControlFlowNode>(scope); Stack <ControlFlowNode> agenda = new Stack <ControlFlowNode>(); agenda.Push(entryNode); while (agenda.Count > 0) { ControlFlowNode node = agenda.Pop(); // Find a block that represents a simple condition if (scope.Contains(node)) { ILBasicBlock block = (ILBasicBlock)node.UserData; { // Switch IList <ILExpression> cases; ILLabel[] caseLabels; ILExpression switchCondition; ILLabel fallLabel; // IList<ILExpression> cases; out IList<ILExpression> arg, out ILLabel fallLabel) // matches a switch statment, not sure how the hell I am going to do this if (block.MatchLastAndBr(GMCode.Switch, out caseLabels, out cases, out fallLabel)) { // Debug.Assert(fallLabel == endBlock); // this should be true switchCondition = cases[0]; // thats the switch arg cases.RemoveAt(0); // remove the switch condition // Replace the switch code with ILSwitch ILSwitch ilSwitch = new ILSwitch() { Condition = switchCondition }; block.Body.RemoveTail(GMCode.Switch, GMCode.B); block.Body.Add(ilSwitch); block.Body.Add(new ILExpression(GMCode.B, fallLabel)); result.Add(block); // Remove the item so that it is not picked up as content scope.RemoveOrThrow(node); // Pull in code of cases ControlFlowNode fallTarget = null; labelToCfNode.TryGetValue(fallLabel, out fallTarget); HashSet <ControlFlowNode> frontiers = new HashSet <ControlFlowNode>(); if (fallTarget != null) { frontiers.UnionWith(fallTarget.DominanceFrontier.Except(new[] { fallTarget })); } foreach (ILLabel condLabel in caseLabels) { ControlFlowNode condTarget = null; labelToCfNode.TryGetValue(condLabel, out condTarget); if (condTarget != null) { frontiers.UnionWith(condTarget.DominanceFrontier.Except(new[] { condTarget })); } } for (int i = 0; i < caseLabels.Length; i++) { ILLabel condLabel = caseLabels[i]; // Find or create new case block ILSwitch.CaseBlock caseBlock = ilSwitch.CaseBlocks.FirstOrDefault(b => b.EntryGoto.Operand == condLabel); if (caseBlock == null) { caseBlock = new ILSwitch.CaseBlock() { Values = new List <ILExpression>(), EntryGoto = new ILExpression(GMCode.B, condLabel) }; ilSwitch.CaseBlocks.Add(caseBlock); ControlFlowNode condTarget = null; labelToCfNode.TryGetValue(condLabel, out condTarget); if (condTarget != null && !frontiers.Contains(condTarget)) { HashSet <ControlFlowNode> content = FindDominatedNodes(scope, condTarget); scope.ExceptWith(content); foreach (var con in FindConditions(content, condTarget)) { caseBlock.Body.Add(con); } // caseBlock.Body.AddRange(FindConditions(content, condTarget)); // Add explicit break which should not be used by default, but the goto removal might decide to use it caseBlock.Body.Add(new ILBasicBlock() { Body = { new ILLabel() { Name = "SwitchBreak_" + (nextLabelIndex++) }, new ILExpression(GMCode.LoopOrSwitchBreak, null) } }); } } if (cases[i].Code != GMCode.DefaultCase) { caseBlock.Values.Add(cases[i].Arguments[0]); } else { caseBlock.Values.Add(new ILExpression(GMCode.DefaultCase, null)); } } // Heuristis to determine if we want to use fallthough as default case if (fallTarget != null && !frontiers.Contains(fallTarget)) { HashSet <ControlFlowNode> content = FindDominatedNodes(scope, fallTarget); if (content.Any()) { var caseBlock = new ILSwitch.CaseBlock() { EntryGoto = new ILExpression(GMCode.B, fallLabel) }; ilSwitch.CaseBlocks.Add(caseBlock); block.Body.RemoveTail(GMCode.B); scope.ExceptWith(content); foreach (var con in FindConditions(content, fallTarget)) { caseBlock.Body.Add(con); } // Add explicit break which should not be used by default, but the goto removal might decide to use it caseBlock.Body.Add(new ILBasicBlock() { Body = { new ILLabel() { Name = "SwitchBreak_" + (nextLabelIndex++) }, new ILExpression(GMCode.LoopOrSwitchBreak, null) } }); } } } // Debug.Assert((block.Body.First() as ILLabel).Name != "L1938"); // Two-way branch ILLabel trueLabel; ILLabel falseLabel; IList <ILExpression> condExprs; if (block.MatchLastAndBr(GMCode.Bf, out falseLabel, out condExprs, out trueLabel) && condExprs[0].Code != GMCode.Pop) // its resolved { ILExpression condExpr = condExprs[0]; IList <ILNode> body = block.Body; // this is a simple condition, skip anything short curiket for now // Match a condition patern // Convert the brtrue to ILCondition ILCondition ilCond = new ILCondition() { Condition = condExpr, TrueBlock = new ILBlock() { EntryGoto = new ILExpression(GMCode.B, trueLabel) }, FalseBlock = new ILBlock() { EntryGoto = new ILExpression(GMCode.B, falseLabel) } }; block.Body.RemoveTail(GMCode.Bf, GMCode.B); block.Body.Add(ilCond); result.Add(block); // Remove the item immediately so that it is not picked up as content scope.RemoveOrThrow(node); ControlFlowNode trueTarget = null; labelToCfNode.TryGetValue(trueLabel, out trueTarget); ControlFlowNode falseTarget = null; labelToCfNode.TryGetValue(falseLabel, out falseTarget); // Pull in the conditional code if (trueTarget != null && HasSingleEdgeEnteringBlock(trueTarget)) { HashSet <ControlFlowNode> content = FindDominatedNodes(scope, trueTarget); scope.ExceptWith(content); foreach (var con in FindConditions(content, trueTarget)) { ilCond.TrueBlock.Body.Add(con); } } if (falseTarget != null && HasSingleEdgeEnteringBlock(falseTarget)) { HashSet <ControlFlowNode> content = FindDominatedNodes(scope, falseTarget); scope.ExceptWith(content); foreach (var con in FindConditions(content, falseTarget)) { ilCond.FalseBlock.Body.Add(con); } } } } // Add the node now so that we have good ordering if (scope.Contains(node)) { result.Add((ILNode)node.UserData); scope.Remove(node); } } // depth-first traversal of dominator tree for (int i = node.DominatorTreeChildren.Count - 1; i >= 0; i--) { agenda.Push(node.DominatorTreeChildren[i]); } } // Add whatever is left foreach (var node in scope) { result.Add((ILNode)node.UserData); } return(result); }
List <ILNode> FindLoops(HashSet <ControlFlowNode> scope, ControlFlowNode entryPoint, bool excludeEntryPoint) { List <ILNode> result = new List <ILNode>(); // Do not modify entry data scope = new HashSet <ControlFlowNode>(scope); Queue <ControlFlowNode> agenda = new Queue <ControlFlowNode>(); agenda.Enqueue(entryPoint); while (agenda.Count > 0) { ControlFlowNode node = agenda.Dequeue(); // If the node is a loop header if (scope.Contains(node) && node.DominanceFrontier.Contains(node) && (node != entryPoint || !excludeEntryPoint)) { HashSet <ControlFlowNode> loopContents = FindLoopContent(scope, node); // If the first expression is a loop condition ILBasicBlock basicBlock = (ILBasicBlock)node.UserData; ILExpression condExpr; ILLabel trueLabel; ILLabel falseLabel; // It has to be just brtrue - any preceding code would introduce goto if (basicBlock.MatchSingleAndBr(GMCode.Bf, out falseLabel, out condExpr, out trueLabel) || // basicBlock.MatchSingleAndBr(GMCode.Bt, out trueLabel, out condExpr, out falseLabel) || basicBlock.MatchSingleAndBr(GMCode.Pushenv, out falseLabel, out condExpr, out trueLabel)) // built it the same way { bool ispushEnv = (basicBlock.Body.ElementAt(basicBlock.Body.Count - 2) as ILExpression).Code == GMCode.Pushenv; ControlFlowNode trueTarget; labelToCfNode.TryGetValue(trueLabel, out trueTarget); ControlFlowNode falseTarget; labelToCfNode.TryGetValue(falseLabel, out falseTarget); // If one point inside the loop and the other outside if ((!loopContents.Contains(trueTarget) && loopContents.Contains(falseTarget)) || (loopContents.Contains(trueTarget) && !loopContents.Contains(falseTarget))) { loopContents.RemoveOrThrow(node); scope.RemoveOrThrow(node); // If false means enter the loop if (loopContents.Contains(falseTarget) || falseTarget == node) { // Negate the condition condExpr = new ILExpression(GMCode.Not, null, condExpr); ILLabel tmp = trueLabel; trueLabel = falseLabel; falseLabel = tmp; } ControlFlowNode postLoopTarget; labelToCfNode.TryGetValue(falseLabel, out postLoopTarget); if (postLoopTarget != null) { // Pull more nodes into the loop HashSet <ControlFlowNode> postLoopContents = FindDominatedNodes(scope, postLoopTarget); var pullIn = scope.Except(postLoopContents).Where(n => node.Dominates(n)); loopContents.UnionWith(pullIn); } if (ispushEnv) { // Use loop to implement the brtrue basicBlock.Body.RemoveTail(GMCode.Pushenv, GMCode.B); basicBlock.Body.Add(new ILWithStatement() { Enviroment = condExpr, Body = new ILBlock() { EntryGoto = new ILExpression(GMCode.B, trueLabel), Body = FindLoops(loopContents, node, false) } }); } else { // Use loop to implement the brtrue basicBlock.Body.RemoveTail(GMCode.Bf, GMCode.B); basicBlock.Body.Add(new ILWhileLoop() { Condition = condExpr, BodyBlock = new ILBlock() { EntryGoto = new ILExpression(GMCode.B, trueLabel), Body = FindLoops(loopContents, node, false) } }); } basicBlock.Body.Add(new ILExpression(GMCode.B, falseLabel)); result.Add(basicBlock); scope.ExceptWith(loopContents); } } // Fallback method: while(true) if (scope.Contains(node)) { result.Add(new ILBasicBlock() { Body = new List <ILNode>() { new ILLabel() { Name = "Loop_" + (nextLabelIndex++) }, new ILWhileLoop() { BodyBlock = new ILBlock() { EntryGoto = new ILExpression(GMCode.B, (ILLabel)basicBlock.Body.First()), Body = FindLoops(loopContents, node, true) } }, }, }); scope.ExceptWith(loopContents); } } // Using the dominator tree should ensure we find the the widest loop first foreach (var child in node.DominatorTreeChildren) { agenda.Enqueue(child); } } // Add whatever is left foreach (var node in scope) { result.Add((ILNode)node.UserData); } scope.Clear(); return(result); }
/// <summary> /// Group input into a set of blocks that can be later arbitraliby schufled. /// The method adds necessary branches to make control flow between blocks /// explicit and thus order independent. /// </summary> public static void SplitToBasicBlocks(ILBlock block) { int nextLabelIndex = 0; List <ILNode> basicBlocks = new List <ILNode>(); ILLabel entryLabel = block.Body.FirstOrDefault() as ILLabel ?? new ILLabel() { Name = "Block_" + (nextLabelIndex++) }; ILBasicBlock basicBlock = new ILBasicBlock(); basicBlocks.Add(basicBlock); basicBlock.Body.Add(entryLabel); block.EntryGoto = new ILExpression(GMCode.B, entryLabel); if (block.Body.Count > 0) { if (block.Body[0] != entryLabel) { basicBlock.Body.Add(block.Body[0]); } for (int i = 1; i < block.Body.Count; i++) { ILNode lastNode = block.Body[i - 1]; ILNode currNode = block.Body[i]; // Start a new basic block if necessary if (currNode is ILLabel || lastNode.IsConditionalControlFlow() || lastNode.IsUnconditionalControlFlow()) { // Try to reuse the label ILLabel label = currNode as ILLabel ?? new ILLabel() { Name = "Block_" + (nextLabelIndex++).ToString() }; // Terminate the last block if (!lastNode.IsUnconditionalControlFlow()) { // Explicit branch from one block to other basicBlock.Body.Add(new ILExpression(GMCode.B, label)); } // Start the new block basicBlock = new ILBasicBlock(); basicBlocks.Add(basicBlock); basicBlock.Body.Add(label); // Add the node to the basic block if (currNode != label) { basicBlock.Body.Add(currNode); } } else { basicBlock.Body.Add(currNode); } } } block.Body = basicBlocks; return; }
// This is before the expression is processed, so ILValue's and constants havn't been assigned public bool SimplifyTernaryOperator(List <ILNode> body, ILBasicBlock head, int pos) { Debug.Assert(body.Contains(head)); // Debug.Assert((head.Body[0] as ILLabel).Name != "Block_54"); // Debug.Assert((head.Body[0] as ILLabel).Name != "L1257"); ILExpression condExpr; ILLabel trueLabel; ILLabel falseLabel; ILExpression trueExpr; ILLabel trueFall; ILExpression falseExpr; ILLabel falseFall; ILExpression finalFall; ILLabel finalFalseFall; ILLabel finalTrueFall; if ((head.MatchLastAndBr(GMCode.Bt, out trueLabel, out condExpr, out falseLabel) || head.MatchLastAndBr(GMCode.Bf, out falseLabel, out condExpr, out trueLabel)) && labelGlobalRefCount[trueLabel] == 1 && labelGlobalRefCount[falseLabel] == 1 && labelToBasicBlock[trueLabel].MatchSingleAndBr(GMCode.Push, out trueExpr, out trueFall) && labelToBasicBlock[falseLabel].MatchSingleAndBr(GMCode.Push, out falseExpr, out falseFall) && trueFall == falseFall && body.Contains(labelToBasicBlock[trueLabel]) && labelToBasicBlock[trueFall].MatchLastAndBr(GMCode.Bf, out finalFalseFall, out finalFall, out finalTrueFall) && finalFall.Code == GMCode.Pop ) // (finalFall == null || finalFall.Code == GMCode.Pop) { Debug.Assert(finalFall.Arguments.Count != 2); ILValue falseLocVar = falseExpr.Code == GMCode.Constant ? falseExpr.Operand as ILValue : null; ILValue trueLocVar = trueExpr.Code == GMCode.Constant ? trueExpr.Operand as ILValue : null; Debug.Assert(falseLocVar != null || trueLocVar != null); ILExpression newExpr = null; // a ? true : b is equivalent to a || b // a ? b : true is equivalent to !a || b // a ? b : false is equivalent to a && b // a ? false : b is equivalent to !a && b if (trueLocVar != null && trueLocVar.Type == GM_Type.Short && (trueLocVar == 0 || trueLocVar == 1)) { // It can be expressed as logical expression if (trueLocVar != 0) { newExpr = MakeLeftAssociativeShortCircuit(GMCode.LogicOr, condExpr, falseExpr); } else { newExpr = MakeLeftAssociativeShortCircuit(GMCode.LogicAnd, new ILExpression(GMCode.Not, null, condExpr), falseExpr); } } else if (falseLocVar != null && falseLocVar.Type == GM_Type.Short && (falseLocVar == 0 || falseLocVar == 1)) { // It can be expressed as logical expression if (falseLocVar != 0) { newExpr = MakeLeftAssociativeShortCircuit(GMCode.LogicOr, new ILExpression(GMCode.Not, null, condExpr), trueExpr); } else { newExpr = MakeLeftAssociativeShortCircuit(GMCode.LogicAnd, condExpr, trueExpr); } } Debug.Assert(newExpr != null); // head.Body.RemoveTail(ILCode.Brtrue, ILCode.Br); head.Body.RemoveRange(head.Body.Count - 2, 2); head.Body.Add(new ILExpression(GMCode.Bf, finalFalseFall, newExpr)); head.Body.Add(new ILExpression(GMCode.B, finalTrueFall)); // Remove the inlined branch from scope // body.RemoveOrThrow(nextBasicBlock); // Remove the old basic blocks body.RemoveOrThrow(labelToBasicBlock[trueLabel]); body.RemoveOrThrow(labelToBasicBlock[falseLabel]); body.RemoveOrThrow(labelToBasicBlock[trueFall]); return(true); } return(false); }
public bool SimplifyShortCircuit(IList <ILNode> body, ILBasicBlock head, int pos) { Debug.Assert(body.Contains(head)); // Debug.Assert((head.Body[0] as ILLabel).Name != "Block_54"); ILExpression condExpr; ILLabel trueLabel; ILLabel falseLabel; // Ok, since we have not changed out all the Bf's to Bt like in ILSpy, we have to do them seperately // as I am getting bugs in my wahhoo about it if ((head.MatchLastAndBr(GMCode.Bf, out falseLabel, out condExpr, out trueLabel) || head.MatchLastAndBr(GMCode.Bt, out trueLabel, out condExpr, out falseLabel)) && condExpr.Code != GMCode.Pop // its a terrtery so ignore it? ) // I saw this too { GMCode code = (head.Body[head.Body.Count - 2] as ILExpression).Code; for (int pass = 0; pass < 2; pass++) { // On the second pass, swap labels and negate expression of the first branch // It is slightly ugly, but much better then copy-pasting this whole block ILLabel nextLabel = (pass == 0) ? trueLabel : falseLabel; ILLabel otherLablel = (pass == 0) ? falseLabel : trueLabel; bool negate = (pass == 1); negate = GMCode.Bt == code ? !negate : negate; ILBasicBlock nextBasicBlock = labelToBasicBlock[nextLabel]; ILExpression nextCondExpr; ILLabel nextTrueLablel; ILLabel nextFalseLabel; if (body.Contains(nextBasicBlock) && nextBasicBlock != head && labelGlobalRefCount[(ILLabel)nextBasicBlock.Body.First()] == 1 && (nextBasicBlock.MatchSingleAndBr(GMCode.Bf, out nextFalseLabel, out nextCondExpr, out nextTrueLablel) || nextBasicBlock.MatchSingleAndBr(GMCode.Bt, out nextTrueLablel, out nextCondExpr, out nextFalseLabel)) && nextCondExpr.Code != GMCode.Pop && // ugh (otherLablel == nextFalseLabel || otherLablel == nextTrueLablel)) { // Debug.Assert(nextCondExpr.Arguments.Count != 2); // Create short cicuit branch ILExpression logicExpr; if (otherLablel == nextFalseLabel) { logicExpr = MakeLeftAssociativeShortCircuit(GMCode.LogicAnd, negate ? new ILExpression(GMCode.Not, null, condExpr) : condExpr, nextCondExpr); } else { logicExpr = MakeLeftAssociativeShortCircuit(GMCode.LogicOr, negate ? condExpr : new ILExpression(GMCode.Not, null, condExpr), nextCondExpr); } // head.Body.RemoveTail(GMCode.Bf, GMCode.B); head.Body.RemoveRange(head.Body.Count - 2, 2); head.Body.Add(new ILExpression(GMCode.Bf, nextFalseLabel, logicExpr)); head.Body.Add(new ILExpression(GMCode.B, nextTrueLablel)); // Remove the inlined branch from scope body.RemoveOrThrow(nextBasicBlock); return(true); } } } return(false); }
public static bool MatchSingleAndBr(this ILBasicBlock bb, GMCode code, out ILExpression arg, out ILLabel brLabel) { object filler; return(bb.MatchSingleAndBr <object>(code, out filler, out arg, out brLabel)); }
void TestAndFixWierdLoop(List <ILNode> body, ILBasicBlock head, int pos) { object uvalue1; ILValue value2; ILLabel endLoop; ILLabel startLoop; ILExpression filler; //Debug.Assert((head.Body[0] as ILLabel).Name != "L36"); // Wierd one here. I ran accross this a few times and I think this is generated code // for events. Basicly, it pushes a constant on the stack and uses a repeat loop // however since I am not doing ANY kind of real stack/temporary analysis. I would have // to rewrite and add a bunch of code to get that to work and right now its only a few functions // Its easyer to build a while loop out of it and let the decompiler handle it rather than // build a more robust stack anilizer // ugh have to make a new block for it too, meh int headLen = head.Body.Count; if (head.MatchAt(headLen - 6, GMCode.Push, out uvalue1) && head.MatchAt(headLen - 5, GMCode.Dup) && head.MatchAt(headLen - 4, GMCode.Push, out value2) && head.MatchAt(headLen - 3, GMCode.Sle) && head.MatchLastAndBr(GMCode.Bt, out endLoop, out filler, out startLoop)) { // ok, lets rewrite the head so it makes sence ILLabel newLoopStart = NewJunkLoop(); ILVariable genVar = NewGeneratedVar(); List <ILNode> newHead = new List <ILNode>(); for (int ii = 0; ii <= headLen - 7; ii++) { newHead.Add(head.Body[ii]); // add the front of it including the sub part } newHead.Add(new ILExpression(GMCode.Push, uvalue1)); newHead.Add(new ILExpression(GMCode.Pop, genVar)); newHead.Add(new ILExpression(GMCode.B, newLoopStart)); ILBasicBlock newLoopBlock = new ILBasicBlock(); newLoopBlock.Body.Add(newLoopStart); newLoopBlock.Body.Add(new ILExpression(GMCode.Push, genVar)); newLoopBlock.Body.Add(new ILExpression(GMCode.Push, new ILValue(0))); newLoopBlock.Body.Add(new ILExpression(GMCode.Sgt, null)); newLoopBlock.Body.Add(new ILExpression(GMCode.Bf, endLoop, new ILExpression(GMCode.Pop, null))); newLoopBlock.Body.Add(new ILExpression(GMCode.B, startLoop)); head.Body = newHead; body.Add(newLoopBlock); // Now the hard part, we have to find the end bit for (int j = pos; j < body.Count; j++) { ILBasicBlock bj = body[j] as ILBasicBlock; ILLabel testEnd, testStart; ILValue subPart; int len = bj.Body.Count; // Debug.Assert((bj.Body[0] as ILLabel).Name != "L114"); if (bj.MatchLastAndBr(GMCode.Bt, out testStart, out filler, out testEnd) && testEnd == endLoop && testStart == startLoop && bj.MatchAt(len - 3, GMCode.Dup) && bj.MatchAt(len - 4, GMCode.Sub) && bj.MatchAt(len - 5, GMCode.Push, out subPart) ) { List <ILNode> list2 = new List <ILNode>(); for (int ii = 0; ii <= len - 6; ii++) { list2.Add(bj.Body[ii]); // add the front of it including the sub part } list2.Add(new ILExpression(GMCode.Push, genVar)); list2.Add(bj.Body[len - 5]); // add the sub part list2.Add(bj.Body[len - 4]); // add the sub part list2.Add(new ILExpression(GMCode.Pop, genVar)); // assign it list2.Add(new ILExpression(GMCode.B, newLoopStart)); // branch back to the start bj.Body = list2; // replace break; // all done, let it continue } } // Debug.Assert(false); // coudln't find the end block } }
void CreateSwitchExpresion(ILNode condition, List <ILNode> list, List <ILNode> body, ILBasicBlock head, int pos) { // we are in a case block, check if its the first block List <ILBasicBlock> caseBlocks = new List <ILBasicBlock>(); List <ILLabel> caseLabels = new List <ILLabel>(); ILExpression switchExpression = new ILExpression(GMCode.Switch, null); switchExpression.Arguments.Add(NodeToExpresion(condition)); // pop the switch condition ILBasicBlock current = head; ILLabel nextCase; ILLabel caseTrue; ILExpression fakeArgument; while (current.MatchLastAndBr(GMCode.Bt, out caseTrue, out fakeArgument, out nextCase)) { ILNode operand; if (!current.MatchAt(current.Body.Count - 4, GMCode.Push, out operand)) { throw new Exception("fix"); } if (!(operand is ILValue)) { throw new Exception("Can only handle constants right now"); } switchExpression.Arguments.Add(new ILExpression(GMCode.Case, caseTrue, NodeToExpresion(operand))); caseLabels.Add(caseTrue); body.Remove(current); current = labelToBasicBlock[nextCase]; } body.Insert(pos, head); var lastBlock = current; ILLabel fallLabel; if (!lastBlock.MatchSingle(GMCode.B, out fallLabel)) { throw new Exception("fix"); } current = labelToBasicBlock[fallLabel]; if (!current.MatchAt(1, GMCode.Popz)) { // has a default case // Side note, the LoopAndConditions figures out if we have a default case by checking // if the ending branch is linked to all the other case branches // so we don't need to do anything here // All this code is JUST for finding that popz that pops the condition out of the switch // if you don't care about it, you could just search though all the expresions and remove any and all // popz's I am beggining to think this is the right way to do it as I don't see any other uses // of popz's // Debug.Assert(false); BuildNextBlockData(); // build block chain, we need this for default and mabye case lookups // ok, this is why we DON'T want to remove redundent code as there is this empty // useless goto RIGHt after this that has the link to the finale case ILLabel nextBlockLabel = lastBlock.Body.First() as ILLabel; var uselessBlock = this.labelToNextBlock[nextBlockLabel]; ILLabel newFallLabel; if (!uselessBlock.MatchSingle(GMCode.B, out newFallLabel)) { throw new Exception("fix"); } current = labelToBasicBlock[newFallLabel]; if (!current.MatchAt(1, GMCode.Popz)) { throw new Exception("I have no idea where the popz is for this switch"); } } current.Body.RemoveAt(1); ILLabel lastBlockLabel = lastBlock.Body.First() as ILLabel; if (this.labelGlobalRefCount[lastBlockLabel] == 1) { body.Remove(lastBlockLabel); } switchExpression.Operand = caseLabels.ToArray(); list.Add(switchExpression); list.Add(new ILExpression(GMCode.B, fallLabel)); }
Status ProcessExpression(List <ILNode> list, ILBasicBlock head, int pos, Stack <ILNode> stack) { ILExpression e = head.Body[pos] as ILExpression; if (e == null) { list.Add(head.Body[pos]); return(Status.NoChangeAdded); } ILValue tempValue; ILVariable tempVar; switch (e.Code) { case GMCode.Push: tempValue = e.Operand as ILValue; tempVar = e.Operand as ILVariable; if (tempValue != null) { stack.Push(tempValue); } else if (tempVar != null) { ProcessVar(tempVar, stack); stack.Push(tempVar); } else { // block comes back as a push expression Debug.Assert(e.Arguments.Count > 0); stack.Push(e.Arguments[0]); } return(Status.AddedToStack); case GMCode.Pop: // convert to an assign { tempVar = e.Operand as ILVariable; Debug.Assert(tempVar != null); ILExpression expr = null; if (Dup1Seen) { expr = NodeToExpresion(stack.Pop()); // have to swap the assignment if a dup 1 was done } ProcessVar(tempVar, stack); e.Code = GMCode.Assign; e.Operand = null; e.Arguments.Add(NodeToExpresion(tempVar)); if (!Dup1Seen) { expr = NodeToExpresion(stack.Pop()); } e.Arguments.Add(expr); list.Add(e); return(Status.ChangedAdded); } case GMCode.Call: { if (e.Extra == -1) { list.Add(e); return(Status.NoChangeAdded); } // its already resolved //ILExpression call = new ILExpression(GMCode.Call, ) //ILCall call = new ILCall() { Name = e.Operand as string }; //for (int j = 0; j < e.Extra; j++) call.Arguments.Add(stack.Pop()); if (e.Extra > 0) { for (int j = 0; j < e.Extra; j++) { e.Arguments.Add(NodeToExpresion(stack.Pop())); } } e.Extra = -1; stack.Push(e); } return(Status.AddedToStack); case GMCode.Popz: { if (stack.Count == 0) { list.Add(e); // Debug.Assert(false); return(Status.ChangedAdded); } else { ILExpression call = stack.Peek() as ILExpression; if (call != null && call.Code == GMCode.Call) { stack.Pop(); list.Add(call); return(Status.ChangedAdded); } else { throw new Exception("popz on a non call?"); // return e; // else, ignore for switch } } } case GMCode.Bf: case GMCode.Bt: case GMCode.Ret: if (stack.Count > 0) { // Debug.Assert(stack.Count == 1); e.Arguments[0] = NodeToExpresion(stack.Pop()); if (stack.Count > 0) { foreach (var n in stack) { list.Add(new ILExpression(GMCode.Push, null, NodeToExpresion(n))); } } list.Add(e); return(Status.ChangedAdded); } else { list.Add(e); return(Status.NoChangeAdded); } case GMCode.B: case GMCode.Exit: if (stack.Count > 0) { foreach (var n in stack) { list.Add(new ILExpression(GMCode.Push, null, NodeToExpresion(n))); } } list.Add(e); return(Status.ChangedAdded); case GMCode.Dup: if ((int)e.Operand == 0) { stack.Push(stack.Peek()); // simple case return(Status.DupStack0); } else { // this is usally on an expression that uses a var multipual times so the instance and index is copyed // HOWEVER the stack may need to be swaped foreach (var n in stack.Reverse().ToArray()) { stack.Push(n); // copy the entire stack } Dup1Seen = true; // usally this is on an assignment += -= of an array or such return(Status.DupStack1); } default: // ok we handle an expression if (e.Code.isExpression()) { for (int j = 0; j < e.Code.GetPopDelta(); j++) { if (stack.Count > 0) { e.Arguments.Add(NodeToExpresion(stack.Pop())); } else { e.Arguments.Add(new ILExpression(GMCode.Pop, null)); } } e.Arguments.Reverse(); // till I fix it latter, sigh stack.Push(e); // push expressions back return(Status.AddedToStack); } else { list.Add(e); return(Status.NoChangeAdded); } } throw new Exception("Shouldn't get here?"); }