// This is before the expression is processed, so ILValue's and constants havn't been assigned public bool SimplifyTernaryOperator(IList <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; ILLabel finalFalseFall; ILLabel finalTrueFall; if (head.MatchLastAndBr(GMCode.Bt, out trueLabel, out condExpr, out falseLabel) && 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[trueFall]) // finalFall.Code == GMCode.Pop ) // (finalFall == null || finalFall.Code == GMCode.Pop) { ILBasicBlock trueBlock = labelToBasicBlock[trueLabel]; ILBasicBlock falseBlock = labelToBasicBlock[falseLabel]; ILBasicBlock fallBlock = labelToBasicBlock[trueFall]; ILExpression newExpr = ResolveTernaryExpression(condExpr, trueExpr, falseExpr); head.Body.RemoveTail(GMCode.Bt, GMCode.B); body.RemoveOrThrow(trueBlock); body.RemoveOrThrow(falseBlock); IList <ILExpression> finalFall; // figure out if its a wierd short or not if (fallBlock.MatchSingleAndBr(GMCode.Bt, out finalTrueFall, out finalFall, out finalFalseFall) && finalFall.Count == 0) { head.Body.Add(new ILExpression(GMCode.Bt, finalTrueFall, newExpr)); if (labelGlobalRefCount[trueFall] == 2) { body.RemoveOrThrow(fallBlock); } } else if (fallBlock.Body.Count == 2) // wierd break, { finalFalseFall = fallBlock.GotoLabel(); head.Body.Add(new ILExpression(GMCode.Push, null, newExpr)); // we want to push it for next pass if (labelGlobalRefCount[trueFall] == 2) { body.RemoveOrThrow(fallBlock); } } else if (fallBlock.MatchAt(1, GMCode.Pop)) // generated? wierd instance? { finalFalseFall = fallBlock.EntryLabel(); error.Info("Wierd Generated Pop here", newExpr); head.Body.Add(new ILExpression(GMCode.Push, null, newExpr)); // It should be combined in JoinBasicBlocks function // so don't remove failblock } else if (fallBlock.MatchAt(1, GMCode.Assign, out finalFall)) // This is an assignment case and unsure what its for { finalFall.Add(newExpr); finalFalseFall = fallBlock.EntryLabel(); } if (finalFalseFall == null && fallBlock.MatchLastAt(1, GMCode.Ret)) { head.Body.Add(new ILExpression(GMCode.Ret, null)); } else { Debug.Assert(finalFalseFall != null); head.Body.Add(new ILExpression(GMCode.B, finalFalseFall)); } return(true); } return(false); }
public bool DetectSwitch_GenerateBranches(IList <ILNode> body, ILBasicBlock head, int pos) { bool modified = false; ILExpression condition; ILLabel trueLabel; ILLabel falseLabel; ILLabel fallThough; // Debug.Assert(head.EntryLabel().Name != "Block_473"); if (MatchSwitchCase(head, out trueLabel, out fallThough, out condition)) // we ignore this first match, but remember the position { List <ILExpression> cases = new List <ILExpression>(); List <ILNode> caseBlocks = new List <ILNode>(); ILLabel prev = head.EntryLabel(); ILBasicBlock startOfCases = head; cases.Add(PreSetUpCaseBlock(startOfCases, condition)); caseBlocks.Add(startOfCases); for (int i = pos - 1; i >= 0; i--) { ILBasicBlock bb = body[i] as ILBasicBlock; if (MatchSwitchCase(bb, out trueLabel, out falseLabel, out condition)) { caseBlocks.Add(bb); cases.Add(PreSetUpCaseBlock(bb, condition)); Debug.Assert(falseLabel == prev); prev = bb.EntryLabel(); startOfCases = bb; } else { break; } } // we have all the cases // head is at the "head" of the cases ILExpression left; if (startOfCases.Body[startOfCases.Body.Count - 3].Match(GMCode.Push, out left)) { startOfCases.Body.RemoveAt(startOfCases.Body.Count - 3); foreach (var e in cases) { e.Arguments.Insert(0, new ILExpression(left)); // add the expression to all the branches } } else { throw new Exception("switch failure"); } // It seems GM makes a default case that just jumps to the end of the switch but I cannot // rely on it always being there ILBasicBlock default_case = body[pos + 1] as ILBasicBlock; Debug.Assert(default_case.EntryLabel() == head.GotoLabel()); ILBasicBlock end_of_switch = labelToBasicBlock[default_case.GotoLabel()]; if ((end_of_switch.Body[1] as ILExpression).Code == GMCode.Popz) { end_of_switch.Body.RemoveAt(1); // yeaa! } else // booo { // We have a default case so now we have to find where the popz ends, // this could be bad if we had a wierd generated for loop, but we are just doing stupid search ILBasicBlock test1 = FindEndOfSwitch(end_of_switch); // we take a sample from one of the cases to make sure we do end up at the same place ILBasicBlock test2 = FindEndOfSwitch(head); if (test1 == test2) { // two matches are good enough for me test1.Body.RemoveAt(1); // yeaa! } else { error.Error("Cannot find end of switch", end_of_switch); // booo } } // tricky part, finding that damn popz // Ok, we have all the case blocks, they are all fixed, and its like a big chain of ifs now. // But for anything OTHER than lua that has switch statments, we want to mark this for latter modified |= true; } return(modified); }