@@ -110,6 +110,150 @@ public void PushInstruction(in Instruction instruction, in SourcePosition positi
110110 instructionPositions . Add ( position ) ;
111111 }
112112
113+ /// <summary>
114+ /// Push or merge the new instruction.
115+ /// </summary>
116+ [ MethodImpl ( MethodImplOptions . AggressiveInlining ) ]
117+ public void PushOrMergeInstruction ( int lastLocal , in Instruction instruction , in SourcePosition position , ref bool incrementStackPosition )
118+ {
119+ if ( instructions . Length == 0 )
120+ {
121+ instructions . Add ( instruction ) ;
122+ instructionPositions . Add ( position ) ;
123+ return ;
124+ }
125+ ref var lastInstruction = ref instructions . AsSpan ( ) [ ^ 1 ] ;
126+ var opcode = instruction . OpCode ;
127+ switch ( opcode )
128+ {
129+ case OpCode . Move :
130+ // last A is not local variable
131+ if ( lastInstruction . A != lastLocal &&
132+ // available to merge
133+ lastInstruction . A == instruction . B &&
134+ // not already merged
135+ lastInstruction . A != lastInstruction . B )
136+ {
137+ switch ( lastInstruction . OpCode )
138+ {
139+ case OpCode . GetTable :
140+ case OpCode . Add :
141+ case OpCode . Sub :
142+ case OpCode . Mul :
143+ case OpCode . Div :
144+ case OpCode . Mod :
145+ case OpCode . Pow :
146+ case OpCode . Concat :
147+ {
148+ lastInstruction . A = instruction . A ;
149+ incrementStackPosition = false ;
150+ return ;
151+ }
152+ }
153+ }
154+ break ;
155+ case OpCode . GetTable :
156+ {
157+ // Merge MOVE GetTable
158+ if ( lastInstruction . OpCode == OpCode . Move && lastLocal != lastInstruction . A )
159+ {
160+ if ( lastInstruction . A == instruction . B )
161+ {
162+ lastInstruction = Instruction . GetTable ( instruction . A , lastInstruction . B , instruction . C ) ;
163+ instructionPositions [ ^ 1 ] = position ;
164+ incrementStackPosition = false ;
165+ return ;
166+ }
167+
168+ }
169+ break ;
170+ }
171+ case OpCode . SetTable :
172+ {
173+ // Merge MOVE SETTABLE
174+ if ( lastInstruction . OpCode == OpCode . Move && lastLocal != lastInstruction . A )
175+ {
176+ var lastB = lastInstruction . B ;
177+ var lastA = lastInstruction . A ;
178+ if ( lastB < 255 && lastA == instruction . A )
179+ {
180+ // Merge MOVE MOVE SETTABLE
181+ if ( instructions . Length > 2 )
182+ {
183+ ref var last2Instruction = ref instructions . AsSpan ( ) [ ^ 2 ] ;
184+ var last2A = last2Instruction . A ;
185+ if ( last2Instruction . OpCode == OpCode . Move && lastLocal != last2A && instruction . C == last2A )
186+ {
187+ last2Instruction = Instruction . SetTable ( ( byte ) ( lastB ) , instruction . B , last2Instruction . B ) ;
188+ instructions . RemoveAtSwapback ( instructions . Length - 1 ) ;
189+ instructionPositions . RemoveAtSwapback ( instructionPositions . Length - 1 ) ;
190+ instructionPositions [ ^ 1 ] = position ;
191+ incrementStackPosition = false ;
192+ return ;
193+ }
194+ }
195+ lastInstruction = Instruction . SetTable ( ( byte ) ( lastB ) , instruction . B , instruction . C ) ;
196+ instructionPositions [ ^ 1 ] = position ;
197+ incrementStackPosition = false ;
198+ return ;
199+ }
200+
201+ if ( lastA == instruction . C )
202+ {
203+ lastInstruction = Instruction . SetTable ( instruction . A , instruction . B , lastB ) ;
204+ instructionPositions [ ^ 1 ] = position ;
205+ incrementStackPosition = false ;
206+ return ;
207+ }
208+ }
209+ else if ( lastInstruction . OpCode == OpCode . GetTabUp && instructions . Length >= 2 )
210+ {
211+ ref var last2Instruction = ref instructions [ ^ 2 ] ;
212+ var last2OpCode = last2Instruction . OpCode ;
213+ if ( last2OpCode is OpCode . LoadK or OpCode . Move )
214+ {
215+
216+ var last2A = last2Instruction . A ;
217+ if ( last2A != lastLocal && instruction . C == last2A )
218+ {
219+ var c = last2OpCode == OpCode . LoadK ? last2Instruction . Bx + 256 : last2Instruction . B ;
220+ last2Instruction = lastInstruction ;
221+ lastInstruction = instruction with { C = ( ushort ) c } ;
222+ instructionPositions [ ^ 2 ] = instructionPositions [ ^ 1 ] ;
223+ instructionPositions [ ^ 1 ] = position ;
224+ incrementStackPosition = false ;
225+ return ;
226+ }
227+ }
228+ }
229+ break ;
230+ }
231+ case OpCode . Unm :
232+ case OpCode . Not :
233+ case OpCode . Len :
234+ if ( lastInstruction . OpCode == OpCode . Move && lastLocal != lastInstruction . A && lastInstruction . A == instruction . B )
235+ {
236+ lastInstruction = instruction with { B = lastInstruction . B } ; ;
237+ instructionPositions [ ^ 1 ] = position ;
238+ incrementStackPosition = false ;
239+ return ;
240+ }
241+ break ;
242+ case OpCode . Return :
243+ if ( lastInstruction . OpCode == OpCode . Move && instruction . B == 2 && lastInstruction . B < 256 )
244+ {
245+ lastInstruction = instruction with { A = ( byte ) lastInstruction . B } ;
246+ instructionPositions [ ^ 1 ] = position ;
247+ incrementStackPosition = false ;
248+ return ;
249+ }
250+ break ;
251+ }
252+
253+ instructions . Add ( instruction ) ;
254+ instructionPositions . Add ( position ) ;
255+ }
256+
113257 /// <summary>
114258 /// Gets the index of the constant from the value, or if the constant is not registered it is added and its index is returned.
115259 /// </summary>
0 commit comments