public static ILLabel GotoLabel(this ILBasicBlock bb) { if (bb.MatchLastAt(1, GMCode.Ret) || bb.MatchLastAt(1, GMCode.Exit)) { return(null); } ILLabel label = (bb.Body[bb.Body.Count - 1] as ILExpression).Operand as ILLabel; Debug.Assert(label != null); return(label); }
// Detect a switch block, combine them all, and either build a switch block or // just a bunch of if statements // the trick is to get rid of the popv at the end of all these case statements // might just have to be removed with the "remove redudent code" system bool MatchSwitchCase(ILBasicBlock head, out ILLabel trueLabel, out ILLabel falseLabel, out ILExpression condition) { if (head != null && head.MatchLastAndBr(GMCode.Bt, out trueLabel, out falseLabel) && head.MatchLastAt(3, GMCode.Seq) && head.MatchLastAt(4, GMCode.Push, out condition) && head.MatchLastAt(5, GMCode.Dup)) { return(true); } trueLabel = default(ILLabel); falseLabel = default(ILLabel); condition = default(ILExpression); return(false); }
public List <ILBasicBlock> GetAllCaseBlocks(IList <ILNode> body, ILBasicBlock head, int pos, out ILExpression condition, out ILLabel fallout) { ILExpression fswitch = new ILExpression(GMCode.Switch, null); List <ILBasicBlock> caseBlocks = new List <ILBasicBlock>(); int swtichStart = pos; ILLabel trueLabel; ILLabel falseLabel; while (MatchSwitchCase(head, out trueLabel, out falseLabel, out condition)) { caseBlocks.Add(head); head = body.ElementAtOrDefault(++swtichStart) as ILBasicBlock; } ILBasicBlock switchHead = caseBlocks.First(); if (!switchHead.ElementAtLastOrDefault(5).isNodeResolved()) { fallout = null; condition = null; return(null); } // caseBlocks.Reverse(); // reverse the order so its correct Debug.Assert(switchHead.MatchLastAt(6, GMCode.Push, out condition)); // return false; switchHead.RemoveAt(switchHead.Body.Count - 6); // ugh, might have to change the matchLastAt fallout = caseBlocks.Last().OperandLabelLastAt(0); return(caseBlocks); }
// 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 MatchRepeatStructure(IList <ILNode> body, ILBasicBlock head, int pos) { ILExpression rcount; ILExpression pushZero; int dupMode = 0; ILLabel fallthough; ILLabel repeatBlock; if (head.MatchLastAt(6, GMCode.Push, out rcount) && // header for a repeat, sets it up head.MatchLastAt(5, GMCode.Dup, out dupMode) && head.MatchLastAt(4, GMCode.Push, out pushZero) && pushZero.Code == GMCode.Constant && (pushZero.Operand as ILValue).IntValue == 0 && head.MatchLastAt(3, GMCode.Sle) && head.MatchLastAndBr(GMCode.Bt, out fallthough, out repeatBlock)) { // We have to seeperate the head from other bits of the block // humm, mabye have to put this in the general build routine like we did with push V:( head.Body.RemoveTail(GMCode.Push, GMCode.Dup, GMCode.Push, GMCode.Sle, GMCode.Bt, GMCode.B); ILBasicBlock header_block; ILLabel header_label; if (head.Body.Count == 1) {// The head only has the label, so its safe to use this as the header header_block = head; header_label = head.EntryLabel(); } else { header_label = ILLabel.Generate("R"); // We have to seperate the head. header_block = new ILBasicBlock(); head.Body.Add(new ILExpression(GMCode.B, header_label)); header_block.Body.Add(header_label); body.Insert(pos + 1, header_block); // insert before the block so it looks in order } header_block.Body.Add(new ILExpression(GMCode.Repeat, repeatBlock, rcount)); header_block.Body.Add(new ILExpression(GMCode.B, fallthough)); // NOW we got to find the block that matches ILExpression subOneConstant; ILLabel footerContinue, footerfallThough; /* * * * while (!(start.MatchLastAt(5, GMCode.Push, out subOneConstant) && * subOneConstant.Code == GMCode.Constant && (subOneConstant.Operand as ILValue).IntValue == 1 && * start.MatchLastAt(4, GMCode.Sub) && * start.MatchLastAt(3, GMCode.Dup, out dupMode) && dupMode == 0 && * start.MatchLastAndBr(GMCode.Bt, out footerContinue, out footerfallThough))) * { * ILLabel next = start.GotoLabel(); * start = labelToBasicBlock[next]; * } */// ok, on more complicated stuf like an internal loop, this f***s up, so we are going to do a hack // The popz fallthough comes RIGHT after the decrment for the repeate loop, so we are going to move up one from that // then check it ILBasicBlock popzBlock = labelToBasicBlock[fallthough]; // Debug.Assert((popzBlock.Body[1] as ILExpression).Code == GMCode.Popz); popzBlock.Body.RemoveAt(1); // remove the popz ILBasicBlock footer = body[body.IndexOf(popzBlock) - 1] as ILBasicBlock; if (footer.MatchLastAt(5, GMCode.Push, out subOneConstant) && subOneConstant.Code == GMCode.Constant && (subOneConstant.Operand as ILValue).IntValue == 1 && footer.MatchLastAt(4, GMCode.Sub) && footer.MatchLastAt(3, GMCode.Dup, out dupMode) && dupMode == 0 && footer.MatchLastAndBr(GMCode.Bt, out footerContinue, out footerfallThough)) { Debug.Assert(footerfallThough == fallthough && repeatBlock == footerContinue); // sanity check footer.Body.RemoveTail(GMCode.Push, GMCode.Sub, GMCode.Dup, GMCode.Bt, GMCode.B); footer.Body.Add(new ILExpression(GMCode.B, header_block.EntryLabel())); } else { throw new Exception("F**k me"); } // Found! Some sanity checks thogh /* MAJOR BUG UNFINSHED WORK ALERT! * Ok, so this isn't used in undertale, but at some point, somone might want to do a break or continue * Inside of a repeat statment. I have NO clue why though, use a while? * Anyway, if thats the case then you MUST change the target label of evetyhing going to start, to fallthough, otherwise * the goto cleaner will start screaming at you and do alot of weird stuff * fyi, like the with statments, I am converting this thing into a while loop so I don't have to have * custom loop graph code for these things * So, for now? convert start to loop back to head, head jumps to fallthough, and we remove the popz from the fall though */ // ILLabel.Generate("Block_", nextLabelIndex++); return(true); } return(false); }