public void TestLoopInstruction() { var count1 = 0; var count2 = 0; var instructions = new List <Instruction> { new CustomInstruction(_ => ++ count1 % 10 != 0), new CustomInstruction(_ => ++ count2 % 15 != 0), }; var loop = new LoopInstruction(instructions, 10); var critterState = new CritterState(); var count = 0; for (; count < 1000; count++) { if (loop.Tick(critterState) == false) { break; } } if (count >= 1000) { Assert.Fail("Too many ticks"); } Assert.AreEqual(100, count1); Assert.AreEqual(150, count2); }
private IEnumerable <Instruction> Parse(IEnumerator <BrainfuckInstruction> cursor) { while (cursor.MoveNext()) { var currentBrainfuckInstruction = cursor.Current; if (!_loopInstructions.Contains(currentBrainfuckInstruction)) { yield return(CreateInstruction(currentBrainfuckInstruction)); } else if (currentBrainfuckInstruction == BrainfuckInstruction.StartLoop) { var loopInstruction = new LoopInstruction(); loopInstruction.AddRange(Parse(cursor)); yield return(loopInstruction); } } }
private Instruction ParseInstruction(List <Instruction> instructions, ref int i) { var instruction = instructions[i++]; if (instruction is LoopInstruction) { List <Instruction> loopedInstructions = new List <Instruction>(); //Instruction nextInstruction = ParseInstruction(instructions, ref i); //while(!nextInstruction.IsLoopBreaker) { // loopedInstructions.Add(nextInstruction); // nextInstruction = ParseInstruction(instructions, ref i); //} Instruction nextInstruction = instructions[i++]; while (!nextInstruction.IsLoopBreaker) { loopedInstructions.Add(nextInstruction); nextInstruction = instructions[i++]; } if (loopedInstructions.Count > 0) { var lastInstruction = loopedInstructions.Last(); lastInstruction.DecrementForLoopOnLine = instruction.CorrespondingUILineNumber; } instructions.Remove(instruction); i -= 2; LoopInstruction loopInstruction = instruction as LoopInstruction; for (int j = 1; j < loopInstruction.End; j++) { instructions.InsertRange(i, loopedInstructions); i += loopedInstructions.Count; } i--; } return(instruction); }
internal Instruction ReadInstruction() { OpCodes opcode = (OpCodes)this.ReadByte(); Instruction result = Instruction.FixedOpCodes[(int)opcode]; if (null != result) { return(result); } switch (opcode) { case OpCodes.Block: return(BlockInstruction.Create(this)); case OpCodes.Loop: return(LoopInstruction.Create(this)); case OpCodes.If: // block_type return(IfInstruction.Create(this)); case OpCodes.Br: case OpCodes.BrIf: // varuint32 return(BranchInstruction.Create(this, opcode)); case OpCodes.BrTable: // custom return(BranchTableInstruction.Create(this)); case OpCodes.Call: case OpCodes.CallIndirect: // varuint32 + varuint1 return(CallInstruction.Create(this, opcode)); case OpCodes.GetLocal: case OpCodes.SetLocal: case OpCodes.TeeLocal: // local_index return(LocalAccessorInstruction.Create(this, opcode)); case OpCodes.GetGlobal: case OpCodes.SetGlobal: // global_index return(GlobalAccessorInstruction.Create(this, (OpCodes.GetGlobal == opcode))); case OpCodes.I32Load: case OpCodes.I64Load: case OpCodes.F32Load: case OpCodes.F64Load: case OpCodes.I32Load8_s: case OpCodes.I32Load8_u: case OpCodes.I32Load16_s: case OpCodes.I32Load16_u: case OpCodes.I64Load8_s: case OpCodes.I64Load8_u: case OpCodes.I64Load16_s: case OpCodes.I64Load16_u: case OpCodes.I64Load32_s: case OpCodes.I64Load32_u: case OpCodes.I32Store: case OpCodes.I64Store: case OpCodes.F32Store: case OpCodes.F64Store: case OpCodes.I32Store8: case OpCodes.I32Store16: case OpCodes.I64Store8: case OpCodes.I64Store16: case OpCodes.I64Store32: // memory_immediate return(MemoryAccessInstruction.Create(this, opcode)); case OpCodes.CurrentMemory: case OpCodes.GrowMemory: // varuint1 return(MemoryControlInstruction.Create(this, opcode)); case OpCodes.I32Const: // varint32 return(ConstantValueInstruction <int> .Create(this, OpCodes.I32Const, this.ReadVarInt32())); case OpCodes.I64Const: // varint64 return(ConstantValueInstruction <long> .Create(this, OpCodes.I64Const, this.ReadVarInt64())); case OpCodes.F32Const: // uint32 return(ConstantValueInstruction <float> .Create(this, OpCodes.F32Const, this.ReadVarFloat32())); case OpCodes.F64Const: // uint64 return(ConstantValueInstruction <double> .Create(this, OpCodes.F64Const, this.ReadVarFloat64())); case OpCodes.F32eq: case OpCodes.F32ge: case OpCodes.F32gt: case OpCodes.F32le: case OpCodes.F32lt: case OpCodes.F32ne: case OpCodes.F64eq: case OpCodes.F64ge: case OpCodes.F64gt: case OpCodes.F64le: case OpCodes.F64lt: case OpCodes.F64ne: case OpCodes.I32eq: case OpCodes.I32ge_s: case OpCodes.I32ge_u: case OpCodes.I32gt_s: case OpCodes.I32gt_u: case OpCodes.I32le_s: case OpCodes.I32le_u: case OpCodes.I32lt_s: case OpCodes.I32lt_u: case OpCodes.I32ne: case OpCodes.I64eq: case OpCodes.I64ge_s: case OpCodes.I64ge_u: case OpCodes.I64gt_s: case OpCodes.I64gt_u: case OpCodes.I64le_s: case OpCodes.I64le_u: case OpCodes.I64lt_s: case OpCodes.I64lt_u: case OpCodes.I64ne: return(RelationalInstruction.GetInstruction(opcode)); case OpCodes.F32Convert_sI32: case OpCodes.F32Convert_uI32: case OpCodes.F32Convert_sI64: case OpCodes.F32Convert_uI64: case OpCodes.F32demoteF64: case OpCodes.F64Convert_sI32: case OpCodes.F64Convert_uI32: case OpCodes.F64Convert_sI64: case OpCodes.F64Convert_uI64: case OpCodes.F64PromoteF32: case OpCodes.I32Trunc_sF32: case OpCodes.I32Trunc_uF32: case OpCodes.I32Trunc_sF64: case OpCodes.I32Trunc_uF64: case OpCodes.I32wrapI64: case OpCodes.I64Extend_sI32: case OpCodes.I64Extend_uI32: case OpCodes.I64Trunc_sF32: case OpCodes.I64Trunc_uF32: case OpCodes.I64Trunc_sF64: case OpCodes.I64Trunc_uF64: return(ConversionInstruction.GetInstruction(opcode)); default: throw new NotSupportedException(); } }
private string TryReduceJump(BasicBlock root, JumpBasicBlock jumpbb) { // Try to find a linear chain of branches of length > 1 var group = new Set<BasicBlock> { jumpbb }; var chain = new Seq<BasicBlock> { jumpbb }; var start = jumpbb; while (start.Sources.Count == 1 && start.Sources[0] is JumpBasicBlock && !group.Contains(start.Sources[0])) { // Extend chain upwards start = (JumpBasicBlock)start.Sources[0]; group.Add(start); chain.Insert(0, start); } var endjump = jumpbb; while (endjump.Target.Sources.Count == 1 && endjump.Target is JumpBasicBlock && !group.Contains(endjump.Target)) { // Extend chain downwards endjump = (JumpBasicBlock)endjump.Target; group.Add(endjump); chain.Add(endjump); } var end = (BasicBlock)endjump; if (endjump.Target.Sources.Count == 1 && endjump.Target.AcceptsInstructions && !group.Contains(endjump.Target)) { // Extend chain downwards to include a final non jump basic block, provided we can put all // the accumulated instructions there end = endjump.Target; group.Add(end); chain.Add(end); } if (chain.Count > 1) { // Coalesce and peephole var instructions = new Seq<Instruction>(); foreach (var bb in chain) bb.Block.AccumInstructions(instructions); var newbb = end.CloneWithInstructions(nextBlockId++, Peephole(chain[0].Block.BeforeState, instructions)); root.Coalesce(start, group, newbb); return String.Format("collapsed chain of {0} jump blocks from B{1}", chain.Count, start.Id); } else if (start.Block.Count == 0 && !start.Target.Equals(start)) { // Short-circuit a trivial jump root.Delete(start); return String.Format("short-circuited trivial jump at B{0}", start.Id); } else if (start.Target.Equals(start)) { // loop var li = new LoopInstruction(NextInstructionId--, start.Block) { BeforeState = jumpbb.Block.BeforeState, AfterState = jumpbb.Block.AfterState }; var newbb = new NonReturningBasicBlock(nextBlockId++, new Instructions(li)); root.Coalesce(start, new Set<BasicBlock> { start }, newbb); return String.Format("trival loop at B{0}", start.Id); } else return null; }