66
77#include "avs.h"
88
9+ static int emit_assign (
10+ AvsILAssemblerContext * ctx ,
11+ AvsRunnable * obj ,
12+ AvsCompilerInstruction insn ,
13+ AvsCompilerArgument * retval ,
14+ AvsCompilerArgument * args ,
15+ int count )
16+ {
17+ ILRegister * reg [3 ];
18+ ILInstruction * is ;
19+
20+ reg [1 ] = avs_il_register_load_from_argument (ctx , obj , & args [0 ]);
21+ reg [2 ] = avs_il_register_load_from_argument (ctx , obj , & args [1 ]);
22+ reg [0 ] = avs_il_register_load_worker (ctx , obj , retval );
23+
24+ if (reg [1 ]-> flags & ILRegisterPointer )
25+ is = avs_il_instruction_emit_triplet (ctx , obj , ILInstructionStoreReference , reg [0 ], reg [1 ], reg [2 ]);
26+ else
27+ is = avs_il_instruction_emit_triplet (ctx , obj , ILInstructionAssign , reg [0 ], reg [1 ], reg [2 ]);
28+
29+ avs_il_tree_add (& ctx -> tree , is );
30+ return VISUAL_OK ;
31+ }
32+
33+ static int emit_loop (
34+ AvsILAssemblerContext * ctx ,
35+ AvsRunnable * obj ,
36+ AvsCompilerInstruction insn ,
37+ AvsCompilerArgument * retval ,
38+ AvsCompilerArgument * args ,
39+ int count )
40+ {
41+ AvsILTreeNodeIterator iter ;
42+ AvsILTreeNode * base ;
43+ ILRegister * pds , * lhs , * rhs ;
44+ ILInstruction * is , * iloop , * mm ;
45+ int argc ;
46+
47+
48+ argc = avs_il_tree_node_level_count (& ctx -> tree );
49+ avs_debug (print ("il: Loop function, dumping argument context (count: %d)" , argc ));
50+
51+ if (argc < 2 ) {
52+ avs_debug (print ("il: Need more parameters for 'loop' function" ));
53+ exit (1 );
54+ }
55+
56+ /* Level down */
57+ avs_il_tree_node_level_down (& ctx -> tree , & iter );
58+
59+ /* Retrieve stack variables, order IS important */
60+ lhs = avs_il_register_load_from_argument (ctx , obj , & args [1 ]);
61+ rhs = avs_il_register_load_from_argument (ctx , obj , & args [2 ]);
62+ pds = avs_il_register_load_worker (ctx , obj , retval );
63+
64+ /* Load counter */
65+ avs_il_tree_merge (& ctx -> tree , avs_il_tree_node_iterator_next (& iter ));
66+ iloop = avs_il_instruction_emit_twin (ctx , obj , ILInstructionLoopInit , pds , lhs );
67+ avs_il_tree_add (& ctx -> tree , iloop );
68+
69+ /* Merge loop statement */
70+ base = avs_il_tree_node_iterator_next (& iter );
71+ if (!base ) {
72+ fprintf (stderr , "No loop statement to execute!\n" );
73+ exit (1 );
74+ }
75+ avs_il_tree_merge (& ctx -> tree , base );
76+
77+ /* Emit loop instruction */
78+ is = avs_il_instruction_emit (ctx , obj , ILInstructionLoop );
79+ is -> ex .jmp .pointer = base -> insn .base ;
80+ avs_il_tree_add (& ctx -> tree , is );
81+
82+ /* Emit merge marker */
83+ mm = avs_il_instruction_emit (ctx , obj , ILInstructionMergeMarker );
84+ mm -> ex .merge .type = AvsILInstructionMergeTypeLoop ;
85+ mm -> ex .merge .from [0 ] = iloop ;
86+ mm -> ex .merge .from [1 ] = base -> insn .base ;
87+ mm -> ex .merge .from [2 ] = is ;
88+ avs_il_tree_add (& ctx -> tree , mm );
89+
90+ return VISUAL_OK ;
91+ }
92+
93+ static int emit_if (
94+ AvsILAssemblerContext * ctx ,
95+ AvsRunnable * obj ,
96+ AvsCompilerInstruction insn ,
97+ AvsCompilerArgument * retval ,
98+ AvsCompilerArgument * args ,
99+ int count )
100+ {
101+ AvsILTreeNodeIterator iter ;
102+ AvsILTreeNode * base [3 ];
103+ ILRegister * reg [4 ];
104+ ILInstruction * jpt0 , * jpt1 , * mm ;
105+ int argc ;
106+
107+ argc = avs_il_tree_node_level_count (& ctx -> tree );
108+ avs_debug (print ("il: If function, dumpring argument context (count: %d)" , argc ));
109+
110+ if (argc < 3 ) {
111+ avs_debug (print ("il: Need more parameters for 'if' function" ));
112+ exit (1 );
113+ }
114+
115+ /* Level down */
116+ avs_il_tree_node_level_down (& ctx -> tree , & iter );
117+
118+ /* Retrieve stack variables, order IS important */
119+ reg [1 ] = avs_il_register_load_from_argument (ctx , obj , & args [1 ]);
120+ reg [2 ] = avs_il_register_load_from_argument (ctx , obj , & args [2 ]);
121+ reg [3 ] = avs_il_register_load_from_argument (ctx , obj , & args [3 ]);
122+ reg [0 ] = avs_il_register_load_worker (ctx , obj , retval );
123+
124+ /* Load instruction contexts */
125+ base [0 ] = avs_il_tree_node_iterator_next (& iter );
126+ base [1 ] = avs_il_tree_node_iterator_next (& iter );
127+ base [2 ] = avs_il_tree_node_iterator_next (& iter );
128+
129+ /* Merge condition statement */
130+ avs_il_tree_merge (& ctx -> tree , base [0 ]);
131+
132+ /* Jump to valtrue or valfalse statement */
133+ jpt0 = avs_il_instruction_emit_single (ctx , obj , ILInstructionJumpTrue , reg [1 ]);
134+ avs_il_tree_add (& ctx -> tree , jpt0 );
135+
136+ /* Handle special case of assign(if(..., x, y), ...) */
137+ if (!base [1 ]-> insn .base && !base [2 ]-> insn .base ) {
138+ reg [0 ]-> flags |= ILRegisterPointer ;
139+
140+ /* Emit valfalse statement */
141+ avs_il_tree_add (& ctx -> tree , avs_il_instruction_emit_twin (ctx , obj , ILInstructionLoadReference , reg [0 ], reg [3 ]));
142+ jpt1 = avs_il_instruction_emit (ctx , obj , ILInstructionJump );
143+ avs_il_tree_add (& ctx -> tree , jpt1 );
144+
145+ /* Emit valtrue statement */
146+ avs_il_tree_add (& ctx -> tree , avs_il_instruction_emit_twin (ctx , obj , ILInstructionLoadReference , reg [0 ], reg [2 ]));
147+ jpt0 -> ex .jmp .pointer = ctx -> tree .current -> insn .end ;
148+
149+ /* Emit merge marker */
150+ mm = avs_il_instruction_emit (ctx , obj , ILInstructionMergeMarker );
151+ avs_il_tree_add (& ctx -> tree , mm );
152+ jpt1 -> ex .jmp .pointer = mm ;
153+ mm -> ex .merge .type = AvsILInstructionMergeTypeJumpConditional ;
154+ mm -> ex .merge .from [0 ] = jpt1 ;
155+ return VISUAL_OK ;
156+ }
157+
158+ /* Emit valfalse statement */
159+ avs_il_tree_merge (& ctx -> tree , base [2 ]);
160+ avs_il_tree_add (& ctx -> tree , avs_il_instruction_emit_triplet (ctx , obj , ILInstructionAssign , reg [0 ], reg [3 ], reg [3 ]));
161+ jpt1 = avs_il_instruction_emit (ctx , obj , ILInstructionJump );
162+ avs_il_tree_add (& ctx -> tree , jpt1 );
163+
164+ /* Emit valtrue statement */
165+ avs_il_tree_merge (& ctx -> tree , base [1 ]);
166+ avs_il_tree_add (& ctx -> tree , avs_il_instruction_emit_triplet (ctx , obj , ILInstructionAssign , reg [0 ], reg [2 ], reg [2 ]));
167+ jpt0 -> ex .jmp .pointer = base [1 ]-> insn .base ;
168+
169+ /* Emit merge marker */
170+ mm = avs_il_instruction_emit (ctx , obj , ILInstructionMergeMarker );
171+ avs_il_tree_add (& ctx -> tree , mm );
172+ jpt1 -> ex .jmp .pointer = mm ;
173+ mm -> ex .merge .type = AvsILInstructionMergeTypeJumpConditional ;
174+ mm -> ex .merge .from [0 ] = jpt1 ;
175+
176+ return VISUAL_OK ;
177+ }
178+
179+ static void emit_trampoline (
180+ AvsILAssemblerContext * ctx ,
181+ AvsRunnable * obj ,
182+ AvsCompilerArgument * retval ,
183+ AvsCompilerArgument * args ,
184+ int count ,
185+ AvsRunnableFunction * fn )
186+ {
187+ ILInstruction * insn ;
188+ ILRegister * reg ;
189+ int i ;
190+
191+ /* Note: retrieving the result value before retrieving the function arguments
192+ * is normally dangerous, because it'll overwrite the first argument.
193+ * but since the first stack value is equal to the function name
194+ * it isn't a problem in this instance. */
195+ reg = avs_il_register_load_worker (ctx , obj , retval );
196+ insn = avs_il_instruction_emit_single (ctx , obj , ILInstructionCall , reg );
197+
198+ insn -> ex .call .call = fn ;
199+ insn -> ex .call .argc = count - 1 ;
200+ insn -> ex .call .argv = malloc (sizeof (ILRegister * * ) * insn -> ex .call .argc );
201+
202+ /* Load function arguments */
203+ for (i = 1 ; i < count ; i ++ )
204+ insn -> ex .call .argv [i - 1 ] = avs_il_register_load_from_argument (ctx , obj , & args [i ]);
205+
206+ avs_il_tree_add (& ctx -> tree , insn );
207+ return ;
208+ }
209+
210+ static int emit_call (
211+ AvsILAssemblerContext * ctx ,
212+ AvsRunnable * obj ,
213+ AvsCompilerInstruction insn ,
214+ AvsCompilerArgument * retval ,
215+ AvsCompilerArgument * args ,
216+ int count )
217+ {
218+ AvsBuiltinFunctionType type ;
219+ char * name ;
220+
221+ /* Retrieve function name from compiler argument stack */
222+ name = args [0 ].value .identifier ;
223+ type = avs_builtin_function_type (name );
224+
225+ switch (type ) {
226+ case AVS_BUILTIN_FUNCTION_ASSIGN :
227+ emit_assign (ctx , obj , insn , retval , args + 1 , count - 1 );
228+ break ;
229+
230+ case AVS_BUILTIN_FUNCTION_EXEC2 :
231+ * retval = args [2 ];
232+ break ;
233+
234+ case AVS_BUILTIN_FUNCTION_EXEC3 :
235+ * retval = args [3 ];
236+ break ;
237+
238+ case AVS_BUILTIN_FUNCTION_LOOP :
239+ emit_loop (ctx , obj , insn , retval , args , count );
240+ break ;
241+
242+ case AVS_BUILTIN_FUNCTION_IF :
243+ emit_if (ctx , obj , insn , retval , args , count );
244+ break ;
245+
246+ default : {
247+ AvsRunnableFunction * fn = avs_builtin_function_lookup (type );
248+ if (!fn )
249+ avs_debug (print ("il: Unable to find builtin function: %s" , name ));
250+
251+ if (fn -> param_count && fn -> param_count != count - 1 ) {
252+ avs_debug (print ("il: Incorrect parameter count for function: %s, needed: %d parameters, received: %d parameters" ,
253+ fn -> name , fn -> param_count , count - 1 ));
254+ exit (1 );
255+ }
256+
257+ avs_debug (print ("il: Call to function: %s" , fn -> name ));
258+ emit_trampoline (ctx , obj , retval , args , count , fn );
259+ }
260+ }
261+
262+ /* Descrese nesting level */
263+ ctx -> nestlevel -- ;
264+
265+ return VISUAL_OK ;
266+ }
267+
9268/**
10269 * Emit a single compiler instruction to IL Assembler.
11270 *
@@ -31,12 +290,25 @@ int avs_il_emit_instruction(
31290 break ;
32291
33292 case AvsCompilerInstructionCall :
293+ emit_call (ctx , obj , insn , retval , args , count );
34294 break ;
35295
36- case AvsCompilerInstructionNegate :
296+ case AvsCompilerInstructionNegate : {
297+ ILRegister * pds , * rhs ;
298+
299+ rhs = avs_il_register_load_from_argument (ctx , obj , & args [0 ]);
300+ pds = avs_il_register_load_worker (ctx , obj , retval );
301+
302+ avs_il_tree_add (& ctx -> tree ,
303+ avs_il_instruction_emit_twin (ctx , obj , ILInstructionNegate ,
304+ pds , rhs ));
37305 break ;
38-
306+ }
307+
39308 case AvsCompilerInstructionAssign :
309+ emit_assign (ctx , obj , insn , retval , args , count );
310+ break ;
311+
40312 case AvsCompilerInstructionAdd :
41313 case AvsCompilerInstructionSub :
42314 case AvsCompilerInstructionMul :
@@ -92,9 +364,32 @@ int avs_il_emit_marker(
92364{
93365 switch (marker ) {
94366 case AvsCompilerMarkerFunction :
367+ /* Function marker: notifies start of function (and thus function argumentation) */
368+ avs_debug (print ("il: Function marker for function: %s" , name ));
369+ ctx -> nestlevel ++ ;
370+
371+ switch (avs_builtin_function_type (name )) {
372+ case AVS_BUILTIN_FUNCTION_IF :
373+ case AVS_BUILTIN_FUNCTION_LOOP :
374+ avs_debug (print ("il: Function marker: leveling-up!" ));
375+ avs_il_tree_node_level_up (& ctx -> tree , AvsILTreeNodeTypeFunction );
376+ avs_il_tree_node_level_mark (& ctx -> tree , ctx -> nestlevel );
377+ break ;
378+
379+ default :
380+ break ;
381+ }
95382 break ;
96383
97384 case AvsCompilerMarkerArgument :
385+ avs_debug (print ("il: Argument marker: nestlevel = %d, level depth = %d, mark = %d" ,
386+ ctx -> nestlevel , avs_il_tree_node_level_depth (& ctx -> tree ),
387+ avs_il_tree_node_level_get_mark (& ctx -> tree )));
388+ if (!ctx -> nestlevel || ctx -> nestlevel != avs_il_tree_node_level_get_mark (& ctx -> tree ))
389+ break ;
390+
391+ avs_debug (print ("il: Argument marker!" ));
392+ avs_il_tree_node_up (& ctx -> tree , AvsILTreeNodeTypeFunctionArgument );
98393 break ;
99394
100395 case AvsCompilerMarkerSequencePoint :
@@ -136,13 +431,15 @@ int avs_il_runnable_finish(AvsILAssemblerContext *ctx, AvsRunnable *obj)
136431{
137432 ILInstruction * insn ;
138433 static char * insnname [] = {
139- "nop" , "load" , "loadconstant" , "negate" , "assign" ,
140- "add" , "sub" , "mul" , "div" , "mod" , "and" , "or" , "count"
434+ "nop" , "call" , "negate" , "assign" ,
435+ "add" , "sub" , "mul" , "div" , "mod" , "and" , "or" ,
436+ "loopinit" , "loop" , "jump" , "jumptrue" , "mergemarker" ,
437+ "loadreference" , "storereference" , "count"
141438 };
142439
143440 avs_print ("il: finished! (count: %d)" , (ILInstruction * )avs_stack_end (ctx -> tree .ixstack ) - (ILInstruction * )avs_stack_begin (ctx -> tree .ixstack ));
144441
145- for (insn = ctx -> tree . base ; insn != NULL ; insn = insn -> next ) {
442+ for (insn = avs_il_tree_base ( & ctx -> tree ) ; insn != NULL ; insn = insn -> next ) {
146443 avs_print ("il: instruction %p %s %p, %p, %p" , insn , insnname [insn -> type ], insn -> reg [0 ], insn -> reg [1 ], insn -> reg [2 ]);
147444
148445 }
0 commit comments