1 /**
2 * MojoShader; generate shader programs from bytecode of compiled
3 * Direct3D shaders.
4 *
5 * Please see the file LICENSE.txt in the source's root directory.
6 *
7 * This file written by Ryan C. Gordon.
8 */
9
10 // !!! FIXME: this needs to be split into separate source files:
11 // !!! FIXME: parse, AST, IR, etc. The problem is we need to deal with the
12 // !!! FIXME: "Context" struct being passed around everywhere.
13
14 #define __MOJOSHADER_INTERNAL__ 1
15 #include "mojoshader_internal.h"
16
17 #if DEBUG_COMPILER_PARSER
18 #define LEMON_SUPPORT_TRACING 1
19 #endif
20
21 // !!! FIXME: I'd like to lose this. It's really inefficient. Just keep a
22 // !!! FIXME: (tail) on these list structures instead?
23 #define REVERSE_LINKED_LIST(typ, head) { \
24 if ((head) && (head->next)) { \
25 typ *tmp = NULL; \
26 typ *tmp1 = NULL; \
27 while (head != NULL) { \
28 tmp = head; \
29 head = head->next; \
30 tmp->next = tmp1; \
31 tmp1 = tmp; \
32 } \
33 head = tmp; \
34 } \
35 }
36
operator_is_unary(const MOJOSHADER_astNodeType op)37 static inline int operator_is_unary(const MOJOSHADER_astNodeType op)
38 {
39 return ( (op > MOJOSHADER_AST_OP_START_RANGE_UNARY) &&
40 (op < MOJOSHADER_AST_OP_END_RANGE_UNARY) );
41 } // operator_is_unary
42
operator_is_binary(const MOJOSHADER_astNodeType op)43 static inline int operator_is_binary(const MOJOSHADER_astNodeType op)
44 {
45 return ( (op > MOJOSHADER_AST_OP_START_RANGE_BINARY) &&
46 (op < MOJOSHADER_AST_OP_END_RANGE_BINARY) );
47 } // operator_is_binary
48
operator_is_ternary(const MOJOSHADER_astNodeType op)49 static inline int operator_is_ternary(const MOJOSHADER_astNodeType op)
50 {
51 return ( (op > MOJOSHADER_AST_OP_START_RANGE_TERNARY) &&
52 (op < MOJOSHADER_AST_OP_END_RANGE_TERNARY) );
53 } // operator_is_ternary
54
55
56 typedef union TokenData
57 {
58 int64 i64;
59 double dbl;
60 const char *string;
61 const MOJOSHADER_astDataType *datatype;
62 } TokenData;
63
64
65 // This tracks data types and variables, and notes when they enter/leave scope.
66
67 typedef struct SymbolScope
68 {
69 const char *symbol;
70 const MOJOSHADER_astDataType *datatype;
71 int index; // unique positive value within a function, negative if global.
72 int referenced; // non-zero if something looked for this symbol (so we know it's used).
73 struct SymbolScope *next;
74 } SymbolScope;
75
76 typedef struct SymbolMap
77 {
78 HashTable *hash;
79 SymbolScope *scope;
80 } SymbolMap;
81
82 typedef struct LoopLabels
83 {
84 int start; // loop's start label during IR build.
85 int end; // loop's end label during IR build.
86 struct LoopLabels *prev;
87 } LoopLabels;
88
89 // Compile state, passed around all over the place.
90
91 typedef struct Context
92 {
93 int isfail;
94 int out_of_memory;
95 MOJOSHADER_malloc malloc;
96 MOJOSHADER_free free;
97 void *malloc_data;
98 ErrorList *errors;
99 ErrorList *warnings;
100 StringCache *strcache;
101 const char *sourcefile; // current source file that we're parsing.
102 unsigned int sourceline; // current line in sourcefile that we're parsing.
103 SymbolMap usertypes;
104 SymbolMap variables;
105 MOJOSHADER_astNode *ast; // Abstract Syntax Tree
106 const char *source_profile;
107 int is_func_scope; // non-zero if semantic analysis is in function scope.
108 int loop_count;
109 int switch_count;
110 int var_index; // next variable index for current function.
111 int global_var_index; // next variable index for global scope.
112 int user_func_index; // next function index for user-defined functions.
113 int intrinsic_func_index; // next function index for intrinsic functions.
114
115 MOJOSHADER_irStatement **ir; // intermediate representation.
116 int ir_label_count; // next unused IR label index.
117 int ir_temp_count; // next unused IR temporary value index.
118 int ir_end; // current function's end label during IR build.
119 int ir_ret; // temp that holds current function's retval during IR build.
120 LoopLabels *ir_loop; // nested loop boundary labels during IR build.
121
122 // Cache intrinsic types for fast lookup and consistent pointer values.
123 MOJOSHADER_astDataType dt_none;
124 MOJOSHADER_astDataType dt_bool;
125 MOJOSHADER_astDataType dt_int;
126 MOJOSHADER_astDataType dt_uint;
127 MOJOSHADER_astDataType dt_float;
128 MOJOSHADER_astDataType dt_float_snorm;
129 MOJOSHADER_astDataType dt_float_unorm;
130 MOJOSHADER_astDataType dt_half;
131 MOJOSHADER_astDataType dt_double;
132 MOJOSHADER_astDataType dt_string;
133 MOJOSHADER_astDataType dt_sampler1d;
134 MOJOSHADER_astDataType dt_sampler2d;
135 MOJOSHADER_astDataType dt_sampler3d;
136 MOJOSHADER_astDataType dt_samplercube;
137 MOJOSHADER_astDataType dt_samplerstate;
138 MOJOSHADER_astDataType dt_samplercompstate;
139 MOJOSHADER_astDataType dt_buf_bool;
140 MOJOSHADER_astDataType dt_buf_int;
141 MOJOSHADER_astDataType dt_buf_uint;
142 MOJOSHADER_astDataType dt_buf_half;
143 MOJOSHADER_astDataType dt_buf_float;
144 MOJOSHADER_astDataType dt_buf_double;
145 MOJOSHADER_astDataType dt_buf_float_snorm;
146 MOJOSHADER_astDataType dt_buf_float_unorm;
147
148 Buffer *garbage; // this is sort of hacky.
149 } Context;
150
151
152 // !!! FIXME: cut and paste between every damned source file follows...
153 // !!! FIXME: We need to make some sort of ContextBase that applies to all
154 // !!! FIXME: files and move this stuff to mojoshader_common.c ...
155
156 // Convenience functions for allocators...
157
out_of_memory(Context * ctx)158 static inline void out_of_memory(Context *ctx)
159 {
160 ctx->isfail = ctx->out_of_memory = 1;
161 } // out_of_memory
162
Malloc(Context * ctx,const size_t len)163 static inline void *Malloc(Context *ctx, const size_t len)
164 {
165 void *retval = ctx->malloc((int) len, ctx->malloc_data);
166 if (retval == NULL)
167 out_of_memory(ctx);
168 return retval;
169 } // Malloc
170
StrDup(Context * ctx,const char * str)171 static inline char *StrDup(Context *ctx, const char *str)
172 {
173 char *retval = (char *) Malloc(ctx, strlen(str) + 1);
174 if (retval != NULL)
175 strcpy(retval, str);
176 return retval;
177 } // StrDup
178
Free(Context * ctx,void * ptr)179 static inline void Free(Context *ctx, void *ptr)
180 {
181 ctx->free(ptr, ctx->malloc_data);
182 } // Free
183
MallocBridge(int bytes,void * data)184 static void *MallocBridge(int bytes, void *data)
185 {
186 return Malloc((Context *) data, (size_t) bytes);
187 } // MallocBridge
188
FreeBridge(void * ptr,void * data)189 static void FreeBridge(void *ptr, void *data)
190 {
191 Free((Context *) data, ptr);
192 } // FreeBridge
193
194 static void failf(Context *ctx, const char *fmt, ...) ISPRINTF(2,3);
failf(Context * ctx,const char * fmt,...)195 static void failf(Context *ctx, const char *fmt, ...)
196 {
197 ctx->isfail = 1;
198 if (ctx->out_of_memory)
199 return;
200
201 va_list ap;
202 va_start(ap, fmt);
203 errorlist_add_va(ctx->errors, ctx->sourcefile, ctx->sourceline, fmt, ap);
204 va_end(ap);
205 } // failf
206
fail(Context * ctx,const char * reason)207 static inline void fail(Context *ctx, const char *reason)
208 {
209 failf(ctx, "%s", reason);
210 } // fail
211
212 static void warnf(Context *ctx, const char *fmt, ...) ISPRINTF(2,3);
warnf(Context * ctx,const char * fmt,...)213 static void warnf(Context *ctx, const char *fmt, ...)
214 {
215 if (ctx->out_of_memory)
216 return;
217
218 va_list ap;
219 va_start(ap, fmt);
220 errorlist_add_va(ctx->warnings, ctx->sourcefile, ctx->sourceline, fmt, ap);
221 va_end(ap);
222 } // warnf
223
warn(Context * ctx,const char * reason)224 static inline void warn(Context *ctx, const char *reason)
225 {
226 warnf(ctx, "%s", reason);
227 } // warn
228
isfail(const Context * ctx)229 static inline int isfail(const Context *ctx)
230 {
231 return ctx->isfail;
232 } // isfail
233
234
symbolmap_nuke(const void * k,const void * v,void * d)235 static void symbolmap_nuke(const void *k, const void *v, void *d) {/*no-op*/}
236
create_symbolmap(Context * ctx,SymbolMap * map)237 static int create_symbolmap(Context *ctx, SymbolMap *map)
238 {
239 // !!! FIXME: should compare string pointer, with string in cache.
240 map->scope = NULL;
241 map->hash = hash_create(ctx, hash_hash_string, hash_keymatch_string,
242 symbolmap_nuke, 1, MallocBridge, FreeBridge, ctx);
243 return (map->hash != NULL);
244 } // create_symbolmap
245
datatypes_match(const MOJOSHADER_astDataType * a,const MOJOSHADER_astDataType * b)246 static int datatypes_match(const MOJOSHADER_astDataType *a,
247 const MOJOSHADER_astDataType *b)
248 {
249 int i;
250
251 if (a == b)
252 return 1;
253 else if (a->type != b->type)
254 return 0;
255
256 switch (a->type)
257 {
258 case MOJOSHADER_AST_DATATYPE_STRUCT:
259 if (a->structure.member_count != b->structure.member_count)
260 return 0;
261 for (i = 0; i < a->structure.member_count; i++)
262 {
263 if (!datatypes_match(a->structure.members[i].datatype,
264 b->structure.members[i].datatype))
265 return 0;
266 // stringcache'd, pointer compare is safe.
267 else if (a->structure.members[i].identifier !=
268 b->structure.members[i].identifier)
269 return 0;
270 } // for
271 return 1;
272
273 case MOJOSHADER_AST_DATATYPE_ARRAY:
274 if (a->array.elements != b->array.elements)
275 return 0;
276 else if (!datatypes_match(a->array.base, b->array.base))
277 return 0;
278 return 1;
279
280 case MOJOSHADER_AST_DATATYPE_VECTOR:
281 if (a->vector.elements != b->vector.elements)
282 return 0;
283 else if (!datatypes_match(a->vector.base, b->vector.base))
284 return 0;
285 return 1;
286
287 case MOJOSHADER_AST_DATATYPE_MATRIX:
288 if (a->matrix.rows != b->matrix.rows)
289 return 0;
290 else if (a->matrix.columns != b->matrix.columns)
291 return 0;
292 else if (!datatypes_match(a->matrix.base, b->matrix.base))
293 return 0;
294 return 1;
295
296 case MOJOSHADER_AST_DATATYPE_BUFFER:
297 return datatypes_match(a->buffer.base, b->buffer.base);
298
299 case MOJOSHADER_AST_DATATYPE_FUNCTION:
300 if (a->function.num_params != b->function.num_params)
301 return 0;
302 else if (a->function.intrinsic != b->function.intrinsic)
303 return 0;
304 else if (!datatypes_match(a->function.retval, b->function.retval))
305 return 0;
306 for (i = 0; i < a->function.num_params; i++)
307 {
308 if (!datatypes_match(a->function.params[i], b->function.params[i]))
309 return 0;
310 } // for
311 return 1;
312
313 case MOJOSHADER_AST_DATATYPE_USER:
314 return 0; // pointers must match, this clearly didn't.
315
316 default:
317 assert(0 && "unexpected case");
318 return 0;
319 } // switch
320
321 return 0;
322 } // datatypes_match
323
push_symbol(Context * ctx,SymbolMap * map,const char * sym,const MOJOSHADER_astDataType * dt,const int index,const int check_dupes)324 static void push_symbol(Context *ctx, SymbolMap *map, const char *sym,
325 const MOJOSHADER_astDataType *dt, const int index,
326 const int check_dupes)
327 {
328 if (ctx->out_of_memory)
329 return;
330
331 // Decide if this symbol is defined, and if it's in the current scope.
332 SymbolScope *item = NULL;
333 const void *value = NULL;
334 if ((check_dupes) && (sym != NULL) && (hash_find(map->hash, sym, &value)))
335 {
336 // check the current scope for a dupe.
337 // !!! FIXME: note current scope's starting index, see if found
338 // !!! FIXME: item is < index (and thus, a previous scope).
339 item = map->scope;
340 while ((item) && (item->symbol))
341 {
342 if ( ((const void *) item) == value )
343 {
344 failf(ctx, "Symbol '%s' already defined", sym);
345 return;
346 } // if
347 item = item->next;
348 } // while
349 } // if
350
351 // Add the symbol to our map and scope stack.
352 item = (SymbolScope *) Malloc(ctx, sizeof (SymbolScope));
353 if (item == NULL)
354 return;
355
356 if (sym != NULL) // sym can be NULL if we're pushing a new scope.
357 {
358 if (hash_insert(map->hash, sym, item) == -1)
359 {
360 Free(ctx, item);
361 return;
362 } // if
363 } // if
364
365 item->symbol = sym; // cached strings, don't copy.
366 item->index = index;
367 item->datatype = dt;
368 item->referenced = 0;
369 item->next = map->scope;
370 map->scope = item;
371 } // push_symbol
372
push_usertype(Context * ctx,const char * sym,const MOJOSHADER_astDataType * dt)373 static void push_usertype(Context *ctx, const char *sym, const MOJOSHADER_astDataType *dt)
374 {
375 if (sym != NULL)
376 {
377 MOJOSHADER_astDataType *userdt;
378 userdt = (MOJOSHADER_astDataType *) Malloc(ctx, sizeof (*userdt));
379 if (userdt != NULL)
380 {
381 // !!! FIXME: this is hacky.
382 if (!buffer_append(ctx->garbage, &userdt, sizeof (userdt)))
383 {
384 Free(ctx, userdt);
385 return;
386 } // if
387
388 userdt->type = MOJOSHADER_AST_DATATYPE_USER;
389 userdt->user.details = dt;
390 userdt->user.name = sym;
391
392 dt = userdt;
393 } // if
394 } // if
395
396 push_symbol(ctx, &ctx->usertypes, sym, dt, 0, 1);
397 } // push_usertype
398
push_variable(Context * ctx,const char * sym,const MOJOSHADER_astDataType * dt)399 static inline void push_variable(Context *ctx, const char *sym, const MOJOSHADER_astDataType *dt)
400 {
401 int idx = 0;
402 if (sym != NULL)
403 {
404 // leave space for individual member indexes. The IR will need this.
405 int additional = 0;
406 if (dt->type == MOJOSHADER_AST_DATATYPE_STRUCT)
407 additional = dt->structure.member_count;
408 if (ctx->is_func_scope)
409 {
410 idx = ++ctx->var_index; // these are positive.
411 ctx->var_index += additional;
412 } // if
413 else
414 {
415 idx = --ctx->global_var_index; // these are negative.
416 ctx->global_var_index -= additional;
417 } // else
418 } // if
419
420 push_symbol(ctx, &ctx->variables, sym, dt, idx, 1);
421 } // push_variable
422
push_function(Context * ctx,const char * sym,const MOJOSHADER_astDataType * dt,const int just_declare)423 static int push_function(Context *ctx, const char *sym,
424 const MOJOSHADER_astDataType *dt,
425 const int just_declare)
426 {
427 // we don't have any reason to support nested functions at the moment,
428 // so this would be a bug.
429 assert(!ctx->is_func_scope);
430 assert(dt->type == MOJOSHADER_AST_DATATYPE_FUNCTION);
431
432 // Functions are always global, so no need to search scopes.
433 // Functions overload, though, so we have to continue iterating to
434 // see if it matches anything.
435 const void *value = NULL;
436 void *iter = NULL;
437 while (hash_iter(ctx->variables.hash, sym, &value, &iter))
438 {
439 // !!! FIXME: this breaks if you predeclare a function.
440 // !!! FIXME: (a declare AFTER defining works, though.)
441 // there's already something called this.
442 SymbolScope *item = (SymbolScope *) value;
443 if (datatypes_match(dt, item->datatype))
444 {
445 if (!just_declare)
446 failf(ctx, "Function '%s' already defined.", sym);
447 return item->index;
448 } // if
449 } // while
450
451 int idx = 0;
452 if ((sym != NULL) && (dt != NULL))
453 {
454 if (!dt->function.intrinsic)
455 idx = ++ctx->user_func_index; // these are positive.
456 else
457 idx = --ctx->intrinsic_func_index; // these are negative.
458 } // if
459
460 // push_symbol() doesn't check dupes, because we just did.
461 push_symbol(ctx, &ctx->variables, sym, dt, idx, 0);
462
463 return idx;
464 } // push_function
465
push_scope(Context * ctx)466 static inline void push_scope(Context *ctx)
467 {
468 push_usertype(ctx, NULL, NULL);
469 push_variable(ctx, NULL, NULL);
470 } // push_scope
471
pop_symbol(Context * ctx,SymbolMap * map)472 static void pop_symbol(Context *ctx, SymbolMap *map)
473 {
474 SymbolScope *item = map->scope;
475 if (!item)
476 return;
477 if (item->symbol)
478 hash_remove(map->hash, item->symbol);
479 map->scope = item->next;
480 Free(ctx, item);
481 } // pop_symbol
482
pop_symbol_scope(Context * ctx,SymbolMap * map)483 static void pop_symbol_scope(Context *ctx, SymbolMap *map)
484 {
485 while ((map->scope) && (map->scope->symbol))
486 pop_symbol(ctx, map);
487
488 assert(map->scope != NULL);
489 assert(map->scope->symbol == NULL);
490 pop_symbol(ctx, map);
491 } // pop_symbol_scope
492
pop_scope(Context * ctx)493 static inline void pop_scope(Context *ctx)
494 {
495 pop_symbol_scope(ctx, &ctx->usertypes);
496 pop_symbol_scope(ctx, &ctx->variables);
497 } // push_scope
498
find_symbol(Context * ctx,SymbolMap * map,const char * sym,int * _index)499 static const MOJOSHADER_astDataType *find_symbol(Context *ctx, SymbolMap *map, const char *sym, int *_index)
500 {
501 const void *_item = NULL;
502 hash_find(map->hash, sym, &_item);
503 SymbolScope *item = (SymbolScope *) _item;
504 if (item != NULL)
505 {
506 item->referenced++;
507 if (_index != NULL)
508 *_index = item->index;
509 } // if
510 return item ? item->datatype : NULL;
511 } // find_symbol
512
find_usertype(Context * ctx,const char * sym)513 static inline const MOJOSHADER_astDataType *find_usertype(Context *ctx, const char *sym)
514 {
515 return find_symbol(ctx, &ctx->usertypes, sym, NULL);
516 } // find_usertype
517
find_variable(Context * ctx,const char * sym,int * _index)518 static inline const MOJOSHADER_astDataType *find_variable(Context *ctx, const char *sym, int *_index)
519 {
520 return find_symbol(ctx, &ctx->variables, sym, _index);
521 } // find_variable
522
destroy_symbolmap(Context * ctx,SymbolMap * map)523 static void destroy_symbolmap(Context *ctx, SymbolMap *map)
524 {
525 while (map->scope)
526 pop_symbol(ctx, map);
527 hash_destroy(map->hash);
528 } // destroy_symbolmap
529
530
new_datatype_vector(Context * ctx,const MOJOSHADER_astDataType * dt,const int columns)531 static const MOJOSHADER_astDataType *new_datatype_vector(Context *ctx,
532 const MOJOSHADER_astDataType *dt,
533 const int columns)
534 {
535 MOJOSHADER_astDataType *retval;
536 retval = (MOJOSHADER_astDataType *) Malloc(ctx, sizeof (*retval));
537 if (retval == NULL)
538 return NULL;
539
540 // !!! FIXME: this is hacky.
541 // !!! FIXME: I'd like to cache these anyhow and reuse types.
542 if (!buffer_append(ctx->garbage, &retval, sizeof (retval)))
543 {
544 Free(ctx, retval);
545 return NULL;
546 } // if
547
548 if ((columns < 1) || (columns > 4))
549 fail(ctx, "Vector must have between 1 and 4 elements");
550
551 retval->type = MOJOSHADER_AST_DATATYPE_VECTOR;
552 retval->vector.base = dt;
553 retval->vector.elements = columns;
554 return retval;
555 } // new_datatype_vector
556
new_datatype_matrix(Context * ctx,const MOJOSHADER_astDataType * dt,const int rows,const int columns)557 static const MOJOSHADER_astDataType *new_datatype_matrix(Context *ctx,
558 const MOJOSHADER_astDataType *dt,
559 const int rows, const int columns)
560 {
561 MOJOSHADER_astDataType *retval;
562 // !!! FIXME: allocate enough for a matrix, but we need to cleanup things that copy without checking for subsize.
563 retval = (MOJOSHADER_astDataType *) Malloc(ctx, sizeof (*retval));
564 if (retval == NULL)
565 return NULL;
566
567 // !!! FIXME: this is hacky.
568 // !!! FIXME: I'd like to cache these anyhow and reuse types.
569 if (!buffer_append(ctx->garbage, &retval, sizeof (retval)))
570 {
571 Free(ctx, retval);
572 return NULL;
573 } // if
574
575 if ((rows < 1) || (rows > 4))
576 fail(ctx, "Matrix must have between 1 and 4 rows");
577 if ((columns < 1) || (columns > 4))
578 fail(ctx, "Matrix must have between 1 and 4 columns");
579
580 retval->type = MOJOSHADER_AST_DATATYPE_MATRIX;
581 retval->matrix.base = dt;
582 retval->matrix.rows = rows;
583 retval->matrix.columns = columns;
584 return retval;
585 } // new_datatype_matrix
586
587
588 // !!! FIXME: move this to mojoshader_ast.c
589 // !!! FIXME: new_* and delete_* should take an allocator, not a context.
590
591 // These functions are mostly for construction and cleanup of nodes in the
592 // parse tree. Mostly this is simple allocation and initialization, so we
593 // can do as little in the lemon code as possible, and then sort it all out
594 // afterwards.
595
596 #define NEW_AST_NODE(retval, cls, typ) \
597 cls *retval = (cls *) Malloc(ctx, sizeof (cls)); \
598 do { \
599 if (retval == NULL) { return NULL; } \
600 retval->ast.type = typ; \
601 retval->ast.filename = ctx->sourcefile; \
602 retval->ast.line = ctx->sourceline; \
603 } while (0)
604
605 #define DELETE_AST_NODE(cls) do { \
606 if (!cls) return; \
607 } while (0)
608
609
610 static void delete_compilation_unit(Context*, MOJOSHADER_astCompilationUnit*);
611 static void delete_statement(Context *ctx, MOJOSHADER_astStatement *stmt);
612
new_identifier_expr(Context * ctx,const char * string)613 static MOJOSHADER_astExpression *new_identifier_expr(Context *ctx,
614 const char *string)
615 {
616 NEW_AST_NODE(retval, MOJOSHADER_astExpressionIdentifier,
617 MOJOSHADER_AST_OP_IDENTIFIER);
618 retval->datatype = NULL;
619 retval->identifier = string; // cached; don't copy string.
620 retval->index = 0;
621 return (MOJOSHADER_astExpression *) retval;
622 } // new_identifier_expr
623
new_callfunc_expr(Context * ctx,const char * identifier,MOJOSHADER_astArguments * args)624 static MOJOSHADER_astExpression *new_callfunc_expr(Context *ctx,
625 const char *identifier,
626 MOJOSHADER_astArguments *args)
627 {
628 NEW_AST_NODE(retval, MOJOSHADER_astExpressionCallFunction,
629 MOJOSHADER_AST_OP_CALLFUNC);
630 MOJOSHADER_astExpression *expr = new_identifier_expr(ctx, identifier);
631 retval->datatype = NULL;
632 retval->identifier = (MOJOSHADER_astExpressionIdentifier *) expr;
633 retval->args = args;
634 return (MOJOSHADER_astExpression *) retval;
635 } // new_callfunc_expr
636
new_constructor_expr(Context * ctx,const MOJOSHADER_astDataType * dt,MOJOSHADER_astArguments * args)637 static MOJOSHADER_astExpression *new_constructor_expr(Context *ctx,
638 const MOJOSHADER_astDataType *dt,
639 MOJOSHADER_astArguments *args)
640 {
641 NEW_AST_NODE(retval, MOJOSHADER_astExpressionConstructor,
642 MOJOSHADER_AST_OP_CONSTRUCTOR);
643 retval->datatype = dt;
644 retval->args = args;
645 return (MOJOSHADER_astExpression *) retval;
646 } // new_constructor_expr
647
new_cast_expr(Context * ctx,const MOJOSHADER_astDataType * dt,MOJOSHADER_astExpression * operand)648 static MOJOSHADER_astExpression *new_cast_expr(Context *ctx,
649 const MOJOSHADER_astDataType *dt,
650 MOJOSHADER_astExpression *operand)
651 {
652 NEW_AST_NODE(retval, MOJOSHADER_astExpressionCast, MOJOSHADER_AST_OP_CAST);
653 retval->datatype = dt;
654 retval->operand = operand;
655 return (MOJOSHADER_astExpression *) retval;
656 } // new_cast_expr
657
new_unary_expr(Context * ctx,const MOJOSHADER_astNodeType op,MOJOSHADER_astExpression * operand)658 static MOJOSHADER_astExpression *new_unary_expr(Context *ctx,
659 const MOJOSHADER_astNodeType op,
660 MOJOSHADER_astExpression *operand)
661 {
662 NEW_AST_NODE(retval, MOJOSHADER_astExpressionUnary, op);
663 assert(operator_is_unary(op));
664 retval->datatype = NULL;
665 retval->operand = operand;
666 return (MOJOSHADER_astExpression *) retval;
667 } // new_unary_expr
668
new_binary_expr(Context * ctx,const MOJOSHADER_astNodeType op,MOJOSHADER_astExpression * left,MOJOSHADER_astExpression * right)669 static MOJOSHADER_astExpression *new_binary_expr(Context *ctx,
670 const MOJOSHADER_astNodeType op,
671 MOJOSHADER_astExpression *left,
672 MOJOSHADER_astExpression *right)
673 {
674 NEW_AST_NODE(retval, MOJOSHADER_astExpressionBinary, op);
675 assert(operator_is_binary(op));
676 retval->datatype = NULL;
677 retval->left = left;
678 retval->right = right;
679 return (MOJOSHADER_astExpression *) retval;
680 } // new_binary_expr
681
new_ternary_expr(Context * ctx,const MOJOSHADER_astNodeType op,MOJOSHADER_astExpression * left,MOJOSHADER_astExpression * center,MOJOSHADER_astExpression * right)682 static MOJOSHADER_astExpression *new_ternary_expr(Context *ctx,
683 const MOJOSHADER_astNodeType op,
684 MOJOSHADER_astExpression *left,
685 MOJOSHADER_astExpression *center,
686 MOJOSHADER_astExpression *right)
687 {
688 NEW_AST_NODE(retval, MOJOSHADER_astExpressionTernary, op);
689 assert(operator_is_ternary(op));
690 assert(op == MOJOSHADER_AST_OP_CONDITIONAL);
691 retval->datatype = &ctx->dt_bool;
692 retval->left = left;
693 retval->center = center;
694 retval->right = right;
695 return (MOJOSHADER_astExpression *) retval;
696 } // new_ternary_expr
697
new_deref_struct_expr(Context * ctx,MOJOSHADER_astExpression * identifier,const char * member)698 static MOJOSHADER_astExpression *new_deref_struct_expr(Context *ctx,
699 MOJOSHADER_astExpression *identifier,
700 const char *member)
701 {
702 NEW_AST_NODE(retval, MOJOSHADER_astExpressionDerefStruct,
703 MOJOSHADER_AST_OP_DEREF_STRUCT);
704 retval->datatype = NULL;
705 retval->identifier = identifier;
706 retval->member = member; // cached; don't copy string.
707 retval->isswizzle = 0; // may change during semantic analysis.
708 retval->member_index = 0; // set during semantic analysis.
709 return (MOJOSHADER_astExpression *) retval;
710 } // new_deref_struct_expr
711
new_literal_int_expr(Context * ctx,const int value)712 static MOJOSHADER_astExpression *new_literal_int_expr(Context *ctx,
713 const int value)
714 {
715 NEW_AST_NODE(retval, MOJOSHADER_astExpressionIntLiteral,
716 MOJOSHADER_AST_OP_INT_LITERAL);
717 retval->datatype = &ctx->dt_int;
718 retval->value = value;
719 return (MOJOSHADER_astExpression *) retval;
720 } // new_literal_int_expr
721
new_literal_float_expr(Context * ctx,const double dbl)722 static MOJOSHADER_astExpression *new_literal_float_expr(Context *ctx,
723 const double dbl)
724 {
725 NEW_AST_NODE(retval, MOJOSHADER_astExpressionFloatLiteral,
726 MOJOSHADER_AST_OP_FLOAT_LITERAL);
727 retval->datatype = &ctx->dt_float;
728 retval->value = dbl;
729 return (MOJOSHADER_astExpression *) retval;
730 } // new_literal_float_expr
731
new_literal_string_expr(Context * ctx,const char * string)732 static MOJOSHADER_astExpression *new_literal_string_expr(Context *ctx,
733 const char *string)
734 {
735 NEW_AST_NODE(retval, MOJOSHADER_astExpressionStringLiteral,
736 MOJOSHADER_AST_OP_STRING_LITERAL);
737 retval->datatype = &ctx->dt_string;
738 retval->string = string; // cached; don't copy string.
739 return (MOJOSHADER_astExpression *) retval;
740 } // new_literal_string_expr
741
new_literal_boolean_expr(Context * ctx,const int value)742 static MOJOSHADER_astExpression *new_literal_boolean_expr(Context *ctx,
743 const int value)
744 {
745 NEW_AST_NODE(retval, MOJOSHADER_astExpressionBooleanLiteral,
746 MOJOSHADER_AST_OP_BOOLEAN_LITERAL);
747 retval->datatype = &ctx->dt_bool;
748 retval->value = value;
749 return (MOJOSHADER_astExpression *) retval;
750 } // new_literal_boolean_expr
751
752 static void delete_arguments(Context *ctx, MOJOSHADER_astArguments *args);
753
delete_expr(Context * ctx,MOJOSHADER_astExpression * _expr)754 static void delete_expr(Context *ctx, MOJOSHADER_astExpression *_expr)
755 {
756 MOJOSHADER_astNode *expr = (MOJOSHADER_astNode *) _expr;
757
758 DELETE_AST_NODE(expr);
759
760 if (expr->ast.type == MOJOSHADER_AST_OP_CAST)
761 delete_expr(ctx, expr->cast.operand);
762
763 else if (expr->ast.type == MOJOSHADER_AST_OP_CONSTRUCTOR)
764 delete_arguments(ctx, expr->constructor.args);
765
766 else if (expr->ast.type == MOJOSHADER_AST_OP_DEREF_STRUCT)
767 delete_expr(ctx, expr->derefstruct.identifier);
768
769 else if (operator_is_unary(expr->ast.type))
770 delete_expr(ctx, expr->unary.operand);
771
772 else if (operator_is_binary(expr->ast.type))
773 {
774 delete_expr(ctx, expr->binary.left);
775 delete_expr(ctx, expr->binary.right);
776 } // else if
777
778 else if (operator_is_ternary(expr->ast.type))
779 {
780 delete_expr(ctx, expr->ternary.left);
781 delete_expr(ctx, expr->ternary.center);
782 delete_expr(ctx, expr->ternary.right);
783 } // else if
784
785 else if (expr->ast.type == MOJOSHADER_AST_OP_CALLFUNC)
786 {
787 delete_expr(ctx, (MOJOSHADER_astExpression*)expr->callfunc.identifier);
788 delete_arguments(ctx, expr->callfunc.args);
789 } // else if
790
791 // rest of operators don't have extra data to free.
792
793 Free(ctx, expr);
794 } // delete_expr
795
new_argument(Context * ctx,MOJOSHADER_astExpression * arg)796 static MOJOSHADER_astArguments *new_argument(Context *ctx,
797 MOJOSHADER_astExpression *arg)
798 {
799 NEW_AST_NODE(retval, MOJOSHADER_astArguments, MOJOSHADER_AST_ARGUMENTS);
800 retval->argument = arg;
801 retval->next = NULL;
802 return retval;
803 } // new_argument
804
delete_arguments(Context * ctx,MOJOSHADER_astArguments * args)805 static void delete_arguments(Context *ctx, MOJOSHADER_astArguments *args)
806 {
807 DELETE_AST_NODE(args);
808 delete_arguments(ctx, args->next);
809 delete_expr(ctx, args->argument);
810 Free(ctx, args);
811 } // delete_arguments
812
new_function_param(Context * ctx,const MOJOSHADER_astInputModifier inputmod,const MOJOSHADER_astDataType * dt,const char * identifier,const char * semantic,const MOJOSHADER_astInterpolationModifier interpmod,MOJOSHADER_astExpression * initializer)813 static MOJOSHADER_astFunctionParameters *new_function_param(Context *ctx,
814 const MOJOSHADER_astInputModifier inputmod,
815 const MOJOSHADER_astDataType *dt,
816 const char *identifier, const char *semantic,
817 const MOJOSHADER_astInterpolationModifier interpmod,
818 MOJOSHADER_astExpression *initializer)
819 {
820 NEW_AST_NODE(retval, MOJOSHADER_astFunctionParameters,
821 MOJOSHADER_AST_FUNCTION_PARAMS);
822 retval->datatype = dt;
823 retval->input_modifier = inputmod;
824 retval->identifier = identifier;
825 retval->semantic = semantic;
826 retval->interpolation_modifier = interpmod;
827 retval->initializer = initializer;
828 retval->next = NULL;
829 return retval;
830 } // new_function_param
831
delete_function_params(Context * ctx,MOJOSHADER_astFunctionParameters * params)832 static void delete_function_params(Context *ctx,
833 MOJOSHADER_astFunctionParameters *params)
834 {
835 DELETE_AST_NODE(params);
836 delete_function_params(ctx, params->next);
837 delete_expr(ctx, params->initializer);
838 Free(ctx, params);
839 } // delete_function_params
840
new_function_signature(Context * ctx,const MOJOSHADER_astDataType * dt,const char * identifier,MOJOSHADER_astFunctionParameters * params)841 static MOJOSHADER_astFunctionSignature *new_function_signature(Context *ctx,
842 const MOJOSHADER_astDataType *dt,
843 const char *identifier,
844 MOJOSHADER_astFunctionParameters *params)
845 {
846 NEW_AST_NODE(retval, MOJOSHADER_astFunctionSignature,
847 MOJOSHADER_AST_FUNCTION_SIGNATURE);
848 retval->datatype = dt;
849 retval->identifier = identifier;
850 retval->params = params;
851 retval->storage_class = MOJOSHADER_AST_FNSTORECLS_NONE;
852 retval->semantic = NULL;
853 return retval;
854 } // new_function_signature
855
delete_function_signature(Context * ctx,MOJOSHADER_astFunctionSignature * sig)856 static void delete_function_signature(Context *ctx,
857 MOJOSHADER_astFunctionSignature *sig)
858 {
859 DELETE_AST_NODE(sig);
860 delete_function_params(ctx, sig->params);
861 Free(ctx, sig);
862 } // delete_function_signature
863
new_function(Context * ctx,MOJOSHADER_astFunctionSignature * declaration,MOJOSHADER_astStatement * definition)864 static MOJOSHADER_astCompilationUnit *new_function(Context *ctx,
865 MOJOSHADER_astFunctionSignature *declaration,
866 MOJOSHADER_astStatement *definition)
867 {
868 NEW_AST_NODE(retval, MOJOSHADER_astCompilationUnitFunction,
869 MOJOSHADER_AST_COMPUNIT_FUNCTION);
870 retval->next = NULL;
871 retval->declaration = declaration;
872 retval->definition = definition;
873 retval->index = 0;
874 return (MOJOSHADER_astCompilationUnit *) retval;
875 } // new_function
876
delete_function(Context * ctx,MOJOSHADER_astCompilationUnitFunction * unitfn)877 static void delete_function(Context *ctx,
878 MOJOSHADER_astCompilationUnitFunction *unitfn)
879 {
880 DELETE_AST_NODE(unitfn);
881 delete_compilation_unit(ctx, unitfn->next);
882 delete_function_signature(ctx, unitfn->declaration);
883 delete_statement(ctx, unitfn->definition);
884 Free(ctx, unitfn);
885 } // delete_function
886
new_scalar_or_array(Context * ctx,const char * ident,const int isvec,MOJOSHADER_astExpression * dim)887 static MOJOSHADER_astScalarOrArray *new_scalar_or_array(Context *ctx,
888 const char *ident, const int isvec,
889 MOJOSHADER_astExpression *dim)
890 {
891 NEW_AST_NODE(retval, MOJOSHADER_astScalarOrArray,
892 MOJOSHADER_AST_SCALAR_OR_ARRAY);
893 retval->identifier = ident;
894 retval->isarray = isvec;
895 retval->dimension = dim;
896 return retval;
897 } // new_scalar_or_array
898
delete_scalar_or_array(Context * ctx,MOJOSHADER_astScalarOrArray * s)899 static void delete_scalar_or_array(Context *ctx,MOJOSHADER_astScalarOrArray *s)
900 {
901 DELETE_AST_NODE(s);
902 delete_expr(ctx, s->dimension);
903 Free(ctx, s);
904 } // delete_scalar_or_array
905
new_typedef(Context * ctx,const int isconst,const MOJOSHADER_astDataType * dt,MOJOSHADER_astScalarOrArray * soa)906 static MOJOSHADER_astTypedef *new_typedef(Context *ctx, const int isconst,
907 const MOJOSHADER_astDataType *dt,
908 MOJOSHADER_astScalarOrArray *soa)
909 {
910 // we correct this datatype to the final version during semantic analysis.
911 NEW_AST_NODE(retval, MOJOSHADER_astTypedef, MOJOSHADER_AST_TYPEDEF);
912 retval->datatype = dt;
913 retval->isconst = isconst;
914 retval->details = soa;
915 return retval;
916 } // new_typedef
917
delete_typedef(Context * ctx,MOJOSHADER_astTypedef * td)918 static void delete_typedef(Context *ctx, MOJOSHADER_astTypedef *td)
919 {
920 DELETE_AST_NODE(td);
921 delete_scalar_or_array(ctx, td->details);
922 Free(ctx, td);
923 } // delete_typedef
924
new_pack_offset(Context * ctx,const char * a,const char * b)925 static MOJOSHADER_astPackOffset *new_pack_offset(Context *ctx,
926 const char *a, const char *b)
927 {
928 NEW_AST_NODE(retval, MOJOSHADER_astPackOffset, MOJOSHADER_AST_PACK_OFFSET);
929 retval->ident1 = a;
930 retval->ident2 = b;
931 return retval;
932 } // new_pack_offset
933
delete_pack_offset(Context * ctx,MOJOSHADER_astPackOffset * o)934 static void delete_pack_offset(Context *ctx, MOJOSHADER_astPackOffset *o)
935 {
936 DELETE_AST_NODE(o);
937 Free(ctx, o);
938 } // delete_pack_offset
939
new_variable_lowlevel(Context * ctx,MOJOSHADER_astPackOffset * po,const char * reg)940 static MOJOSHADER_astVariableLowLevel *new_variable_lowlevel(Context *ctx,
941 MOJOSHADER_astPackOffset *po,
942 const char *reg)
943 {
944 NEW_AST_NODE(retval, MOJOSHADER_astVariableLowLevel,
945 MOJOSHADER_AST_VARIABLE_LOWLEVEL);
946 retval->packoffset = po;
947 retval->register_name = reg;
948 return retval;
949 } // new_variable_lowlevel
950
delete_variable_lowlevel(Context * ctx,MOJOSHADER_astVariableLowLevel * vll)951 static void delete_variable_lowlevel(Context *ctx,
952 MOJOSHADER_astVariableLowLevel *vll)
953 {
954 DELETE_AST_NODE(vll);
955 delete_pack_offset(ctx, vll->packoffset);
956 Free(ctx, vll);
957 } // delete_variable_lowlevel
958
new_annotation(Context * ctx,const MOJOSHADER_astDataType * dt,MOJOSHADER_astExpression * initializer)959 static MOJOSHADER_astAnnotations *new_annotation(Context *ctx,
960 const MOJOSHADER_astDataType *dt,
961 MOJOSHADER_astExpression *initializer)
962 {
963 NEW_AST_NODE(retval, MOJOSHADER_astAnnotations, MOJOSHADER_AST_ANNOTATION);
964 retval->datatype = dt;
965 retval->initializer = initializer;
966 retval->next = NULL;
967 return retval;
968 } // new_annotation
969
delete_annotation(Context * ctx,MOJOSHADER_astAnnotations * annos)970 static void delete_annotation(Context *ctx, MOJOSHADER_astAnnotations *annos)
971 {
972 DELETE_AST_NODE(annos);
973 delete_annotation(ctx, annos->next);
974 delete_expr(ctx, annos->initializer);
975 Free(ctx, annos);
976 } // delete_annotation
977
new_variable_declaration(Context * ctx,MOJOSHADER_astScalarOrArray * soa,const char * semantic,MOJOSHADER_astAnnotations * annotations,MOJOSHADER_astExpression * init,MOJOSHADER_astVariableLowLevel * vll)978 static MOJOSHADER_astVariableDeclaration *new_variable_declaration(
979 Context *ctx, MOJOSHADER_astScalarOrArray *soa,
980 const char *semantic,
981 MOJOSHADER_astAnnotations *annotations,
982 MOJOSHADER_astExpression *init,
983 MOJOSHADER_astVariableLowLevel *vll)
984 {
985 NEW_AST_NODE(retval, MOJOSHADER_astVariableDeclaration,
986 MOJOSHADER_AST_VARIABLE_DECLARATION);
987 retval->datatype = NULL;
988 retval->attributes = 0;
989 retval->anonymous_datatype = NULL;
990 retval->details = soa;
991 retval->semantic = semantic;
992 retval->annotations = annotations;
993 retval->initializer = init;
994 retval->lowlevel = vll;
995 retval->next = NULL;
996 return retval;
997 } // new_variable_declaration
998
delete_variable_declaration(Context * ctx,MOJOSHADER_astVariableDeclaration * dcl)999 static void delete_variable_declaration(Context *ctx,
1000 MOJOSHADER_astVariableDeclaration *dcl)
1001 {
1002 DELETE_AST_NODE(dcl);
1003 delete_variable_declaration(ctx, dcl->next);
1004 delete_scalar_or_array(ctx, dcl->details);
1005 delete_annotation(ctx, dcl->annotations);
1006 delete_expr(ctx, dcl->initializer);
1007 delete_variable_lowlevel(ctx, dcl->lowlevel);
1008 Free(ctx, dcl);
1009 } // delete_variable_declaration
1010
new_global_variable(Context * ctx,MOJOSHADER_astVariableDeclaration * decl)1011 static MOJOSHADER_astCompilationUnit *new_global_variable(Context *ctx,
1012 MOJOSHADER_astVariableDeclaration *decl)
1013 {
1014 NEW_AST_NODE(retval, MOJOSHADER_astCompilationUnitVariable,
1015 MOJOSHADER_AST_COMPUNIT_VARIABLE);
1016 retval->next = NULL;
1017 retval->declaration = decl;
1018 return (MOJOSHADER_astCompilationUnit *) retval;
1019 } // new_global_variable
1020
delete_global_variable(Context * ctx,MOJOSHADER_astCompilationUnitVariable * var)1021 static void delete_global_variable(Context *ctx,
1022 MOJOSHADER_astCompilationUnitVariable *var)
1023 {
1024 DELETE_AST_NODE(var);
1025 delete_compilation_unit(ctx, var->next);
1026 delete_variable_declaration(ctx, var->declaration);
1027 Free(ctx, var);
1028 } // delete_global_variable
1029
new_global_typedef(Context * ctx,MOJOSHADER_astTypedef * td)1030 static MOJOSHADER_astCompilationUnit *new_global_typedef(Context *ctx,
1031 MOJOSHADER_astTypedef *td)
1032 {
1033 NEW_AST_NODE(retval, MOJOSHADER_astCompilationUnitTypedef,
1034 MOJOSHADER_AST_COMPUNIT_TYPEDEF);
1035 retval->next = NULL;
1036 retval->type_info = td;
1037 return (MOJOSHADER_astCompilationUnit *) retval;
1038 } // new_global_typedef
1039
delete_global_typedef(Context * ctx,MOJOSHADER_astCompilationUnitTypedef * unit)1040 static void delete_global_typedef(Context *ctx,
1041 MOJOSHADER_astCompilationUnitTypedef *unit)
1042 {
1043 DELETE_AST_NODE(unit);
1044 delete_compilation_unit(ctx, unit->next);
1045 delete_typedef(ctx, unit->type_info);
1046 Free(ctx, unit);
1047 } // delete_global_typedef
1048
new_struct_member(Context * ctx,MOJOSHADER_astScalarOrArray * soa,const char * semantic)1049 static MOJOSHADER_astStructMembers *new_struct_member(Context *ctx,
1050 MOJOSHADER_astScalarOrArray *soa,
1051 const char *semantic)
1052 {
1053 NEW_AST_NODE(retval, MOJOSHADER_astStructMembers,
1054 MOJOSHADER_AST_STRUCT_MEMBER);
1055 retval->datatype = NULL;
1056 retval->semantic = semantic;
1057 retval->details = soa;
1058 retval->interpolation_mod = MOJOSHADER_AST_INTERPMOD_NONE;
1059 retval->next = NULL;
1060 return retval;
1061 } // new_struct_member
1062
delete_struct_member(Context * ctx,MOJOSHADER_astStructMembers * member)1063 static void delete_struct_member(Context *ctx,
1064 MOJOSHADER_astStructMembers *member)
1065 {
1066 DELETE_AST_NODE(member);
1067 delete_struct_member(ctx, member->next);
1068 delete_scalar_or_array(ctx, member->details);
1069 Free(ctx, member);
1070 } // delete_struct_member
1071
new_struct_declaration(Context * ctx,const char * name,MOJOSHADER_astStructMembers * members)1072 static MOJOSHADER_astStructDeclaration *new_struct_declaration(Context *ctx,
1073 const char *name,
1074 MOJOSHADER_astStructMembers *members)
1075 {
1076 NEW_AST_NODE(retval, MOJOSHADER_astStructDeclaration,
1077 MOJOSHADER_AST_STRUCT_DECLARATION);
1078 retval->datatype = NULL;
1079 retval->name = name;
1080 retval->members = members;
1081 return retval;
1082 } // new_struct_declaration
1083
delete_struct_declaration(Context * ctx,MOJOSHADER_astStructDeclaration * decl)1084 static void delete_struct_declaration(Context *ctx,
1085 MOJOSHADER_astStructDeclaration *decl)
1086 {
1087 DELETE_AST_NODE(decl);
1088 delete_struct_member(ctx, decl->members);
1089 Free(ctx, decl);
1090 } // delete_struct_declaration
1091
new_global_struct(Context * ctx,MOJOSHADER_astStructDeclaration * sd)1092 static MOJOSHADER_astCompilationUnit *new_global_struct(Context *ctx,
1093 MOJOSHADER_astStructDeclaration *sd)
1094 {
1095 NEW_AST_NODE(retval, MOJOSHADER_astCompilationUnitStruct,
1096 MOJOSHADER_AST_COMPUNIT_STRUCT);
1097 retval->next = NULL;
1098 retval->struct_info = sd;
1099 return (MOJOSHADER_astCompilationUnit *) retval;
1100 } // new_global_struct
1101
delete_global_struct(Context * ctx,MOJOSHADER_astCompilationUnitStruct * unit)1102 static void delete_global_struct(Context *ctx,
1103 MOJOSHADER_astCompilationUnitStruct *unit)
1104 {
1105 DELETE_AST_NODE(unit);
1106 delete_compilation_unit(ctx, unit->next);
1107 delete_struct_declaration(ctx, unit->struct_info);
1108 Free(ctx, unit);
1109 } // delete_global_struct
1110
delete_compilation_unit(Context * ctx,MOJOSHADER_astCompilationUnit * unit)1111 static void delete_compilation_unit(Context *ctx,
1112 MOJOSHADER_astCompilationUnit *unit)
1113 {
1114 if (!unit) return;
1115
1116 // it's important to not recurse too deeply here, since you may have
1117 // thousands of items in this linked list (each line of a massive
1118 // function, for example). To avoid this, we iterate the list here,
1119 // deleting all children and making them think they have no reason
1120 // to recurse in their own delete methods.
1121 // Please note that everyone should _try_ to delete their "next" member,
1122 // just in case, but hopefully this cleaned it out.
1123
1124 MOJOSHADER_astCompilationUnit *i = unit->next;
1125 unit->next = NULL;
1126 while (i)
1127 {
1128 MOJOSHADER_astCompilationUnit *next = i->next;
1129 i->next = NULL;
1130 delete_compilation_unit(ctx, i);
1131 i = next;
1132 } // while
1133
1134 switch (unit->ast.type)
1135 {
1136 #define DELETE_UNIT(typ, cls, fn) \
1137 case MOJOSHADER_AST_COMPUNIT_##typ: delete_##fn(ctx, (cls *) unit); break;
1138 DELETE_UNIT(FUNCTION, MOJOSHADER_astCompilationUnitFunction, function);
1139 DELETE_UNIT(TYPEDEF, MOJOSHADER_astCompilationUnitTypedef, global_typedef);
1140 DELETE_UNIT(VARIABLE, MOJOSHADER_astCompilationUnitVariable, global_variable);
1141 DELETE_UNIT(STRUCT, MOJOSHADER_astCompilationUnitStruct, global_struct);
1142 #undef DELETE_UNIT
1143 default: assert(0 && "missing cleanup code"); break;
1144 } // switch
1145
1146 // don't free (unit) here, the class-specific functions do it.
1147 } // delete_compilation_unit
1148
new_typedef_statement(Context * ctx,MOJOSHADER_astTypedef * td)1149 static MOJOSHADER_astStatement *new_typedef_statement(Context *ctx,
1150 MOJOSHADER_astTypedef *td)
1151 {
1152 NEW_AST_NODE(retval, MOJOSHADER_astTypedefStatement,
1153 MOJOSHADER_AST_STATEMENT_TYPEDEF);
1154 retval->next = NULL;
1155 retval->type_info = td;
1156 return (MOJOSHADER_astStatement *) retval;
1157 } // new_typedef_statement
1158
delete_typedef_statement(Context * ctx,MOJOSHADER_astTypedefStatement * stmt)1159 static void delete_typedef_statement(Context *ctx,
1160 MOJOSHADER_astTypedefStatement *stmt)
1161 {
1162 DELETE_AST_NODE(stmt);
1163 delete_statement(ctx, stmt->next);
1164 delete_typedef(ctx, stmt->type_info);
1165 Free(ctx, stmt);
1166 } // delete_typedef_statement
1167
new_return_statement(Context * ctx,MOJOSHADER_astExpression * expr)1168 static MOJOSHADER_astStatement *new_return_statement(Context *ctx,
1169 MOJOSHADER_astExpression *expr)
1170 {
1171 NEW_AST_NODE(retval, MOJOSHADER_astReturnStatement,
1172 MOJOSHADER_AST_STATEMENT_RETURN);
1173 retval->next = NULL;
1174 retval->expr = expr;
1175 return (MOJOSHADER_astStatement *) retval;
1176 } // new_return_statement
1177
delete_return_statement(Context * ctx,MOJOSHADER_astReturnStatement * stmt)1178 static void delete_return_statement(Context *ctx,
1179 MOJOSHADER_astReturnStatement *stmt)
1180 {
1181 DELETE_AST_NODE(stmt);
1182 delete_statement(ctx, stmt->next);
1183 delete_expr(ctx, stmt->expr);
1184 Free(ctx, stmt);
1185 } // delete_return_statement
1186
new_block_statement(Context * ctx,MOJOSHADER_astStatement * stmts)1187 static MOJOSHADER_astStatement *new_block_statement(Context *ctx,
1188 MOJOSHADER_astStatement *stmts)
1189 {
1190 NEW_AST_NODE(retval, MOJOSHADER_astBlockStatement,
1191 MOJOSHADER_AST_STATEMENT_BLOCK);
1192 retval->next = NULL;
1193 retval->statements = stmts;
1194 return (MOJOSHADER_astStatement *) retval;
1195 } // new_block_statement
1196
delete_block_statement(Context * ctx,MOJOSHADER_astBlockStatement * stmt)1197 static void delete_block_statement(Context *ctx,
1198 MOJOSHADER_astBlockStatement *stmt)
1199 {
1200 DELETE_AST_NODE(stmt);
1201 delete_statement(ctx, stmt->statements);
1202 delete_statement(ctx, stmt->next);
1203 Free(ctx, stmt);
1204 } // delete_statement_block
1205
new_for_statement(Context * ctx,MOJOSHADER_astVariableDeclaration * decl,MOJOSHADER_astExpression * initializer,MOJOSHADER_astExpression * looptest,MOJOSHADER_astExpression * counter,MOJOSHADER_astStatement * statement)1206 static MOJOSHADER_astStatement *new_for_statement(Context *ctx,
1207 MOJOSHADER_astVariableDeclaration *decl,
1208 MOJOSHADER_astExpression *initializer,
1209 MOJOSHADER_astExpression *looptest,
1210 MOJOSHADER_astExpression *counter,
1211 MOJOSHADER_astStatement *statement)
1212 {
1213 NEW_AST_NODE(retval, MOJOSHADER_astForStatement,
1214 MOJOSHADER_AST_STATEMENT_FOR);
1215 retval->next = NULL;
1216 retval->unroll = -1;
1217 retval->var_decl = decl;
1218 retval->initializer = initializer;
1219 retval->looptest = looptest;
1220 retval->counter = counter;
1221 retval->statement = statement;
1222 return (MOJOSHADER_astStatement *) retval;
1223 } // new_for_statement
1224
delete_for_statement(Context * ctx,MOJOSHADER_astForStatement * stmt)1225 static void delete_for_statement(Context *ctx,MOJOSHADER_astForStatement *stmt)
1226 {
1227 DELETE_AST_NODE(stmt);
1228 delete_statement(ctx, stmt->next);
1229 delete_variable_declaration(ctx, stmt->var_decl);
1230 delete_expr(ctx, stmt->initializer);
1231 delete_expr(ctx, stmt->looptest);
1232 delete_expr(ctx, stmt->counter);
1233 delete_statement(ctx, stmt->statement);
1234 Free(ctx, stmt);
1235 } // delete_for_statement
1236
new_do_statement(Context * ctx,const int unroll,MOJOSHADER_astStatement * stmt,MOJOSHADER_astExpression * expr)1237 static MOJOSHADER_astStatement *new_do_statement(Context *ctx,
1238 const int unroll,
1239 MOJOSHADER_astStatement *stmt,
1240 MOJOSHADER_astExpression *expr)
1241 {
1242 NEW_AST_NODE(retval,MOJOSHADER_astDoStatement,MOJOSHADER_AST_STATEMENT_DO);
1243 retval->next = NULL;
1244 retval->unroll = unroll;
1245 retval->expr = expr;
1246 retval->statement = stmt;
1247 return (MOJOSHADER_astStatement *) retval;
1248 } // new_do_statement
1249
delete_do_statement(Context * ctx,MOJOSHADER_astDoStatement * stmt)1250 static void delete_do_statement(Context *ctx, MOJOSHADER_astDoStatement *stmt)
1251 {
1252 DELETE_AST_NODE(stmt);
1253 delete_statement(ctx, stmt->next);
1254 delete_statement(ctx, stmt->statement);
1255 delete_expr(ctx, stmt->expr);
1256 Free(ctx, stmt);
1257 } // delete_do_statement
1258
new_while_statement(Context * ctx,const int unroll,MOJOSHADER_astExpression * expr,MOJOSHADER_astStatement * stmt)1259 static MOJOSHADER_astStatement *new_while_statement(Context *ctx,
1260 const int unroll,
1261 MOJOSHADER_astExpression *expr,
1262 MOJOSHADER_astStatement *stmt)
1263 {
1264 NEW_AST_NODE(retval, MOJOSHADER_astWhileStatement,
1265 MOJOSHADER_AST_STATEMENT_WHILE);
1266 retval->next = NULL;
1267 retval->unroll = unroll;
1268 retval->expr = expr;
1269 retval->statement = stmt;
1270 return (MOJOSHADER_astStatement *) retval;
1271 } // new_while_statement
1272
delete_while_statement(Context * ctx,MOJOSHADER_astWhileStatement * stmt)1273 static void delete_while_statement(Context *ctx,
1274 MOJOSHADER_astWhileStatement *stmt)
1275 {
1276 DELETE_AST_NODE(stmt);
1277 delete_statement(ctx, stmt->next);
1278 delete_statement(ctx, stmt->statement);
1279 delete_expr(ctx, stmt->expr);
1280 Free(ctx, stmt);
1281 } // delete_while_statement
1282
new_if_statement(Context * ctx,const int attr,MOJOSHADER_astExpression * expr,MOJOSHADER_astStatement * stmt,MOJOSHADER_astStatement * elsestmt)1283 static MOJOSHADER_astStatement *new_if_statement(Context *ctx,
1284 const int attr,
1285 MOJOSHADER_astExpression *expr,
1286 MOJOSHADER_astStatement *stmt,
1287 MOJOSHADER_astStatement *elsestmt)
1288 {
1289 NEW_AST_NODE(retval,MOJOSHADER_astIfStatement,MOJOSHADER_AST_STATEMENT_IF);
1290 retval->next = NULL;
1291 retval->attributes = attr;
1292 retval->expr = expr;
1293 retval->statement = stmt;
1294 retval->else_statement = elsestmt;
1295 return (MOJOSHADER_astStatement *) retval;
1296 } // new_if_statement
1297
delete_if_statement(Context * ctx,MOJOSHADER_astIfStatement * stmt)1298 static void delete_if_statement(Context *ctx, MOJOSHADER_astIfStatement *stmt)
1299 {
1300 DELETE_AST_NODE(stmt);
1301 delete_statement(ctx, stmt->next);
1302 delete_expr(ctx, stmt->expr);
1303 delete_statement(ctx, stmt->statement);
1304 delete_statement(ctx, stmt->else_statement);
1305 Free(ctx, stmt);
1306 } // delete_if_statement
1307
new_switch_case(Context * ctx,MOJOSHADER_astExpression * expr,MOJOSHADER_astStatement * stmt)1308 static MOJOSHADER_astSwitchCases *new_switch_case(Context *ctx,
1309 MOJOSHADER_astExpression *expr,
1310 MOJOSHADER_astStatement *stmt)
1311 {
1312 NEW_AST_NODE(retval, MOJOSHADER_astSwitchCases, MOJOSHADER_AST_SWITCH_CASE);
1313 retval->expr = expr;
1314 retval->statement = stmt;
1315 retval->next = NULL;
1316 return retval;
1317 } // new_switch_case
1318
delete_switch_case(Context * ctx,MOJOSHADER_astSwitchCases * sc)1319 static void delete_switch_case(Context *ctx, MOJOSHADER_astSwitchCases *sc)
1320 {
1321 DELETE_AST_NODE(sc);
1322 delete_switch_case(ctx, sc->next);
1323 delete_expr(ctx, sc->expr);
1324 delete_statement(ctx, sc->statement);
1325 Free(ctx, sc);
1326 } // delete_switch_case
1327
new_empty_statement(Context * ctx)1328 static MOJOSHADER_astStatement *new_empty_statement(Context *ctx)
1329 {
1330 NEW_AST_NODE(retval, MOJOSHADER_astEmptyStatement,
1331 MOJOSHADER_AST_STATEMENT_EMPTY);
1332 retval->next = NULL;
1333 return (MOJOSHADER_astStatement *) retval;
1334 } // new_empty_statement
1335
delete_empty_statement(Context * ctx,MOJOSHADER_astEmptyStatement * stmt)1336 static void delete_empty_statement(Context *ctx,
1337 MOJOSHADER_astEmptyStatement *stmt)
1338 {
1339 DELETE_AST_NODE(stmt);
1340 delete_statement(ctx, stmt->next);
1341 Free(ctx, stmt);
1342 } // delete_empty_statement
1343
new_break_statement(Context * ctx)1344 static MOJOSHADER_astStatement *new_break_statement(Context *ctx)
1345 {
1346 NEW_AST_NODE(retval, MOJOSHADER_astBreakStatement,
1347 MOJOSHADER_AST_STATEMENT_BREAK);
1348 retval->next = NULL;
1349 return (MOJOSHADER_astStatement *) retval;
1350 } // new_break_statement
1351
delete_break_statement(Context * ctx,MOJOSHADER_astBreakStatement * stmt)1352 static void delete_break_statement(Context *ctx,
1353 MOJOSHADER_astBreakStatement *stmt)
1354 {
1355 DELETE_AST_NODE(stmt);
1356 delete_statement(ctx, stmt->next);
1357 Free(ctx, stmt);
1358 } // delete_break_statement
1359
new_continue_statement(Context * ctx)1360 static MOJOSHADER_astStatement *new_continue_statement(Context *ctx)
1361 {
1362 NEW_AST_NODE(retval, MOJOSHADER_astContinueStatement,
1363 MOJOSHADER_AST_STATEMENT_CONTINUE);
1364 retval->next = NULL;
1365 return (MOJOSHADER_astStatement *) retval;
1366 } // new_continue_statement
1367
delete_continue_statement(Context * ctx,MOJOSHADER_astContinueStatement * stmt)1368 static void delete_continue_statement(Context *ctx,
1369 MOJOSHADER_astContinueStatement *stmt)
1370 {
1371 DELETE_AST_NODE(stmt);
1372 delete_statement(ctx, stmt->next);
1373 Free(ctx, stmt);
1374 } // delete_continue_statement
1375
new_discard_statement(Context * ctx)1376 static MOJOSHADER_astStatement *new_discard_statement(Context *ctx)
1377 {
1378 NEW_AST_NODE(retval, MOJOSHADER_astDiscardStatement,
1379 MOJOSHADER_AST_STATEMENT_DISCARD);
1380 retval->next = NULL;
1381 return (MOJOSHADER_astStatement *) retval;
1382 } // new_discard_statement
1383
delete_discard_statement(Context * ctx,MOJOSHADER_astDiscardStatement * stmt)1384 static void delete_discard_statement(Context *ctx,
1385 MOJOSHADER_astDiscardStatement *stmt)
1386 {
1387 DELETE_AST_NODE(stmt);
1388 delete_statement(ctx, stmt->next);
1389 Free(ctx, stmt);
1390 } // delete_discard_statement
1391
new_expr_statement(Context * ctx,MOJOSHADER_astExpression * expr)1392 static MOJOSHADER_astStatement *new_expr_statement(Context *ctx,
1393 MOJOSHADER_astExpression *expr)
1394 {
1395 NEW_AST_NODE(retval, MOJOSHADER_astExpressionStatement,
1396 MOJOSHADER_AST_STATEMENT_EXPRESSION);
1397 retval->next = NULL;
1398 retval->expr = expr;
1399 return (MOJOSHADER_astStatement *) retval;
1400 } // new_expr_statement
1401
delete_expr_statement(Context * ctx,MOJOSHADER_astExpressionStatement * stmt)1402 static void delete_expr_statement(Context *ctx,
1403 MOJOSHADER_astExpressionStatement *stmt)
1404 {
1405 DELETE_AST_NODE(stmt);
1406 delete_statement(ctx, stmt->next);
1407 delete_expr(ctx, stmt->expr);
1408 Free(ctx, stmt);
1409 } // delete_expr_statement
1410
new_switch_statement(Context * ctx,const int attr,MOJOSHADER_astExpression * expr,MOJOSHADER_astSwitchCases * cases)1411 static MOJOSHADER_astStatement *new_switch_statement(Context *ctx,
1412 const int attr,
1413 MOJOSHADER_astExpression *expr,
1414 MOJOSHADER_astSwitchCases *cases)
1415 {
1416 NEW_AST_NODE(retval, MOJOSHADER_astSwitchStatement,
1417 MOJOSHADER_AST_STATEMENT_SWITCH);
1418 retval->next = NULL;
1419 retval->attributes = attr;
1420 retval->expr = expr;
1421 retval->cases = cases;
1422 return (MOJOSHADER_astStatement *) retval;
1423 } // new_switch_statement
1424
delete_switch_statement(Context * ctx,MOJOSHADER_astSwitchStatement * stmt)1425 static void delete_switch_statement(Context *ctx,
1426 MOJOSHADER_astSwitchStatement *stmt)
1427 {
1428 DELETE_AST_NODE(stmt);
1429 delete_expr(ctx, stmt->expr);
1430 delete_switch_case(ctx, stmt->cases);
1431 Free(ctx, stmt);
1432 } // delete_switch_statement
1433
new_struct_statement(Context * ctx,MOJOSHADER_astStructDeclaration * sd)1434 static MOJOSHADER_astStatement *new_struct_statement(Context *ctx,
1435 MOJOSHADER_astStructDeclaration *sd)
1436 {
1437 NEW_AST_NODE(retval, MOJOSHADER_astStructStatement,
1438 MOJOSHADER_AST_STATEMENT_STRUCT);
1439 retval->next = NULL;
1440 retval->struct_info = sd;
1441 return (MOJOSHADER_astStatement *) retval;
1442 } // new_struct_statement
1443
delete_struct_statement(Context * ctx,MOJOSHADER_astStructStatement * stmt)1444 static void delete_struct_statement(Context *ctx,
1445 MOJOSHADER_astStructStatement *stmt)
1446 {
1447 DELETE_AST_NODE(stmt);
1448 delete_statement(ctx, stmt->next);
1449 delete_struct_declaration(ctx, stmt->struct_info);
1450 Free(ctx, stmt);
1451 } // delete_struct_statement
1452
new_vardecl_statement(Context * ctx,MOJOSHADER_astVariableDeclaration * vd)1453 static MOJOSHADER_astStatement *new_vardecl_statement(Context *ctx,
1454 MOJOSHADER_astVariableDeclaration *vd)
1455 {
1456 NEW_AST_NODE(retval, MOJOSHADER_astVarDeclStatement,
1457 MOJOSHADER_AST_STATEMENT_VARDECL);
1458 retval->next = NULL;
1459 retval->declaration = vd;
1460 return (MOJOSHADER_astStatement *) retval;
1461 } // new_vardecl_statement
1462
delete_vardecl_statement(Context * ctx,MOJOSHADER_astVarDeclStatement * stmt)1463 static void delete_vardecl_statement(Context *ctx,
1464 MOJOSHADER_astVarDeclStatement *stmt)
1465 {
1466 DELETE_AST_NODE(stmt);
1467 delete_statement(ctx, stmt->next);
1468 delete_variable_declaration(ctx, stmt->declaration);
1469 Free(ctx, stmt);
1470 } // delete_vardecl_statement
1471
delete_statement(Context * ctx,MOJOSHADER_astStatement * stmt)1472 static void delete_statement(Context *ctx, MOJOSHADER_astStatement *stmt)
1473 {
1474 if (!stmt) return;
1475
1476 // it's important to not recurse too deeply here, since you may have
1477 // thousands of items in this linked list (each line of a massive
1478 // function, for example). To avoid this, we iterate the list here,
1479 // deleting all children and making them think they have no reason
1480 // to recurse in their own delete methods.
1481 // Please note that everyone should _try_ to delete their "next" member,
1482 // just in case, but hopefully this cleaned it out.
1483
1484 MOJOSHADER_astStatement *i = stmt->next;
1485 stmt->next = NULL;
1486 while (i)
1487 {
1488 MOJOSHADER_astStatement *next = i->next;
1489 i->next = NULL;
1490 delete_statement(ctx, i);
1491 i = next;
1492 } // while
1493
1494 switch (stmt->ast.type)
1495 {
1496 #define DELETE_STATEMENT(typ, cls, fn) \
1497 case MOJOSHADER_AST_STATEMENT_##typ: \
1498 delete_##fn##_statement(ctx, (cls *) stmt); break;
1499 DELETE_STATEMENT(BLOCK, MOJOSHADER_astBlockStatement, block);
1500 DELETE_STATEMENT(EMPTY, MOJOSHADER_astEmptyStatement, empty);
1501 DELETE_STATEMENT(IF, MOJOSHADER_astIfStatement, if);
1502 DELETE_STATEMENT(SWITCH, MOJOSHADER_astSwitchStatement, switch);
1503 DELETE_STATEMENT(EXPRESSION, MOJOSHADER_astExpressionStatement, expr);
1504 DELETE_STATEMENT(FOR, MOJOSHADER_astForStatement, for);
1505 DELETE_STATEMENT(DO, MOJOSHADER_astDoStatement, do);
1506 DELETE_STATEMENT(WHILE, MOJOSHADER_astWhileStatement, while);
1507 DELETE_STATEMENT(RETURN, MOJOSHADER_astReturnStatement, return);
1508 DELETE_STATEMENT(BREAK, MOJOSHADER_astBreakStatement, break);
1509 DELETE_STATEMENT(CONTINUE, MOJOSHADER_astContinueStatement, continue);
1510 DELETE_STATEMENT(DISCARD, MOJOSHADER_astDiscardStatement, discard);
1511 DELETE_STATEMENT(TYPEDEF, MOJOSHADER_astTypedefStatement, typedef);
1512 DELETE_STATEMENT(STRUCT, MOJOSHADER_astStructStatement, struct);
1513 DELETE_STATEMENT(VARDECL, MOJOSHADER_astVarDeclStatement, vardecl);
1514 #undef DELETE_STATEMENT
1515 default: assert(0 && "missing cleanup code"); break;
1516 } // switch
1517 // don't free (stmt) here, the class-specific functions do it.
1518 } // delete_statement
1519
1520
get_usertype(const Context * ctx,const char * token)1521 static const MOJOSHADER_astDataType *get_usertype(const Context *ctx,
1522 const char *token)
1523 {
1524 const void *value; // search all scopes.
1525 if (!hash_find(ctx->usertypes.hash, token, &value))
1526 return NULL;
1527 return value ? ((SymbolScope *) value)->datatype : NULL;
1528 } // get_usertype
1529
1530
1531 // This is where the actual parsing happens. It's Lemon-generated!
1532 #define __MOJOSHADER_HLSL_COMPILER__ 1
1533 #include "mojoshader_parser_hlsl.h"
1534
1535
1536 #if 0
1537 static int expr_is_constant(MOJOSHADER_astExpression *expr)
1538 {
1539 const MOJOSHADER_astNodeType op = expr->ast.type;
1540 if (operator_is_unary(op))
1541 return expr_is_constant(expr->unary.operand);
1542 else if (operator_is_binary(op))
1543 {
1544 return ( expr_is_constant(expr->binary.left) &&
1545 expr_is_constant(expr->binary.right) );
1546 } // else if
1547 else if (operator_is_ternary(op))
1548 {
1549 return ( expr_is_constant(expr->ternary.left) &&
1550 expr_is_constant(expr->ternary.center) &&
1551 expr_is_constant(expr->ternary.right) );
1552 } // else if
1553
1554 return ( (op == MOJOSHADER_AST_OP_INT_LITERAL) ||
1555 (op == MOJOSHADER_AST_OP_FLOAT_LITERAL) ||
1556 (op == MOJOSHADER_AST_OP_STRING_LITERAL) ||
1557 (op == MOJOSHADER_AST_OP_BOOLEAN_LITERAL) );
1558 } // expr_is_constant
1559 #endif
1560
1561 typedef struct AstCalcData
1562 {
1563 int isflt;
1564 union
1565 {
1566 double f;
1567 int64 i;
1568 } value;
1569 } AstCalcData;
1570
1571 // returns 0 if this expression is non-constant, 1 if it is.
1572 // calculation results land in (data).
calc_ast_const_expr(Context * ctx,void * _expr,AstCalcData * data)1573 static int calc_ast_const_expr(Context *ctx, void *_expr, AstCalcData *data)
1574 {
1575 const MOJOSHADER_astNode *expr = (MOJOSHADER_astNode *) _expr;
1576 const MOJOSHADER_astNodeType op = expr->ast.type;
1577
1578 ctx->sourcefile = expr->ast.filename;
1579 ctx->sourceline = expr->ast.line;
1580
1581 if (operator_is_unary(op))
1582 {
1583 if (!calc_ast_const_expr(ctx, expr->unary.operand, data))
1584 return 0;
1585
1586 if (data->isflt)
1587 {
1588 switch (op)
1589 {
1590 case MOJOSHADER_AST_OP_NEGATE:
1591 data->value.f = -data->value.f;
1592 return 1;
1593 case MOJOSHADER_AST_OP_NOT:
1594 data->value.f = !data->value.f;
1595 return 1;
1596 case MOJOSHADER_AST_OP_COMPLEMENT:
1597 fail(ctx, "integer operation on floating point value");
1598 return 0;
1599 case MOJOSHADER_AST_OP_CAST:
1600 // !!! FIXME: this should work, but it's complicated.
1601 assert(0 && "write me");
1602 return 0;
1603 default: break;
1604 } // switch
1605 } // if
1606
1607 else // integer version
1608 {
1609 switch (op)
1610 {
1611 case MOJOSHADER_AST_OP_NEGATE:
1612 data->value.i = -data->value.i;
1613 return 1;
1614 case MOJOSHADER_AST_OP_NOT:
1615 data->value.i = !data->value.i;
1616 return 1;
1617 case MOJOSHADER_AST_OP_COMPLEMENT:
1618 data->value.i = ~data->value.i;
1619 return 1;
1620 case MOJOSHADER_AST_OP_CAST:
1621 // !!! FIXME: this should work, but it's complicated.
1622 assert(0 && "write me");
1623 return 0;
1624 default: break;
1625 } // switch
1626 } // else
1627 assert(0 && "unhandled operation?");
1628 return 0;
1629 } // if
1630
1631 else if (operator_is_binary(op))
1632 {
1633 AstCalcData subdata2;
1634 if ( (!calc_ast_const_expr(ctx, expr->binary.left, data)) ||
1635 (!calc_ast_const_expr(ctx, expr->binary.right, &subdata2)) )
1636 return 0;
1637
1638 // upgrade to float if either operand is float.
1639 if ((data->isflt) || (subdata2.isflt))
1640 {
1641 if (!data->isflt) data->value.f = (double) data->value.i;
1642 if (!subdata2.isflt) subdata2.value.f = (double) subdata2.value.i;
1643 data->isflt = subdata2.isflt = 1;
1644 } // if
1645
1646 switch (op)
1647 {
1648 // gcc doesn't handle commas here, either (fails to parse!).
1649 case MOJOSHADER_AST_OP_COMMA:
1650 case MOJOSHADER_AST_OP_ASSIGN:
1651 case MOJOSHADER_AST_OP_MULASSIGN:
1652 case MOJOSHADER_AST_OP_DIVASSIGN:
1653 case MOJOSHADER_AST_OP_MODASSIGN:
1654 case MOJOSHADER_AST_OP_ADDASSIGN:
1655 case MOJOSHADER_AST_OP_SUBASSIGN:
1656 case MOJOSHADER_AST_OP_LSHIFTASSIGN:
1657 case MOJOSHADER_AST_OP_RSHIFTASSIGN:
1658 case MOJOSHADER_AST_OP_ANDASSIGN:
1659 case MOJOSHADER_AST_OP_XORASSIGN:
1660 case MOJOSHADER_AST_OP_ORASSIGN:
1661 return 0; // assignment is non-constant.
1662 default: break;
1663 } // switch
1664
1665 if (data->isflt)
1666 {
1667 switch (op)
1668 {
1669 case MOJOSHADER_AST_OP_MULTIPLY:
1670 data->value.f *= subdata2.value.f;
1671 return 1;
1672 case MOJOSHADER_AST_OP_DIVIDE:
1673 data->value.f /= subdata2.value.f;
1674 return 1;
1675 case MOJOSHADER_AST_OP_ADD:
1676 data->value.f += subdata2.value.f;
1677 return 1;
1678 case MOJOSHADER_AST_OP_SUBTRACT:
1679 data->value.f -= subdata2.value.f;
1680 return 1;
1681 case MOJOSHADER_AST_OP_LESSTHAN:
1682 data->isflt = 0;
1683 data->value.i = data->value.f < subdata2.value.f;
1684 return 1;
1685 case MOJOSHADER_AST_OP_GREATERTHAN:
1686 data->isflt = 0;
1687 data->value.i = data->value.f > subdata2.value.f;
1688 return 1;
1689 case MOJOSHADER_AST_OP_LESSTHANOREQUAL:
1690 data->isflt = 0;
1691 data->value.i = data->value.f <= subdata2.value.f;
1692 return 1;
1693 case MOJOSHADER_AST_OP_GREATERTHANOREQUAL:
1694 data->isflt = 0;
1695 data->value.i = data->value.f >= subdata2.value.f;
1696 return 1;
1697 case MOJOSHADER_AST_OP_EQUAL:
1698 data->isflt = 0;
1699 data->value.i = data->value.f == subdata2.value.f;
1700 return 1;
1701 case MOJOSHADER_AST_OP_NOTEQUAL:
1702 data->isflt = 0;
1703 data->value.i = data->value.f != subdata2.value.f;
1704 return 1;
1705 case MOJOSHADER_AST_OP_LOGICALAND:
1706 data->isflt = 0;
1707 data->value.i = data->value.f && subdata2.value.f;
1708 return 1;
1709 case MOJOSHADER_AST_OP_LOGICALOR:
1710 data->isflt = 0;
1711 data->value.i = data->value.f || subdata2.value.f;
1712 return 1;
1713
1714 case MOJOSHADER_AST_OP_LSHIFT:
1715 case MOJOSHADER_AST_OP_RSHIFT:
1716 case MOJOSHADER_AST_OP_MODULO:
1717 case MOJOSHADER_AST_OP_BINARYAND:
1718 case MOJOSHADER_AST_OP_BINARYXOR:
1719 case MOJOSHADER_AST_OP_BINARYOR:
1720 fail(ctx, "integer operation on floating point value");
1721 return 0;
1722 default: break;
1723 } // switch
1724 } // if
1725
1726 else // integer version.
1727 {
1728 switch (op)
1729 {
1730 case MOJOSHADER_AST_OP_MULTIPLY:
1731 data->value.i *= subdata2.value.i;
1732 return 1;
1733 case MOJOSHADER_AST_OP_DIVIDE:
1734 data->value.i /= subdata2.value.i;
1735 return 1;
1736 case MOJOSHADER_AST_OP_ADD:
1737 data->value.i += subdata2.value.i;
1738 return 1;
1739 case MOJOSHADER_AST_OP_SUBTRACT:
1740 data->value.i -= subdata2.value.i;
1741 return 1;
1742 case MOJOSHADER_AST_OP_LESSTHAN:
1743 data->value.i = data->value.i < subdata2.value.i;
1744 return 1;
1745 case MOJOSHADER_AST_OP_GREATERTHAN:
1746 data->value.i = data->value.i > subdata2.value.i;
1747 return 1;
1748 case MOJOSHADER_AST_OP_LESSTHANOREQUAL:
1749 data->value.i = data->value.i <= subdata2.value.i;
1750 return 1;
1751 case MOJOSHADER_AST_OP_GREATERTHANOREQUAL:
1752 data->value.i = data->value.i >= subdata2.value.i;
1753 return 1;
1754 case MOJOSHADER_AST_OP_EQUAL:
1755 data->value.i = data->value.i == subdata2.value.i;
1756 return 1;
1757 case MOJOSHADER_AST_OP_NOTEQUAL:
1758 data->value.i = data->value.i != subdata2.value.i;
1759 return 1;
1760 case MOJOSHADER_AST_OP_LOGICALAND:
1761 data->value.i = data->value.i && subdata2.value.i;
1762 return 1;
1763 case MOJOSHADER_AST_OP_LOGICALOR:
1764 data->value.i = data->value.i || subdata2.value.i;
1765 return 1;
1766 case MOJOSHADER_AST_OP_LSHIFT:
1767 data->value.i = data->value.i << subdata2.value.i;
1768 return 1;
1769 case MOJOSHADER_AST_OP_RSHIFT:
1770 data->value.i = data->value.i >> subdata2.value.i;
1771 return 1;
1772 case MOJOSHADER_AST_OP_MODULO:
1773 data->value.i = data->value.i % subdata2.value.i;
1774 return 1;
1775 case MOJOSHADER_AST_OP_BINARYAND:
1776 data->value.i = data->value.i & subdata2.value.i;
1777 return 1;
1778 case MOJOSHADER_AST_OP_BINARYXOR:
1779 data->value.i = data->value.i ^ subdata2.value.i;
1780 return 1;
1781 case MOJOSHADER_AST_OP_BINARYOR:
1782 data->value.i = data->value.i | subdata2.value.i;
1783 return 1;
1784 default: break;
1785 } // switch
1786 } // else
1787
1788 assert(0 && "unhandled operation?");
1789 return 0;
1790 } // else if
1791
1792 else if (operator_is_ternary(op))
1793 {
1794 AstCalcData subdata2;
1795 AstCalcData subdata3;
1796
1797 assert(op == MOJOSHADER_AST_OP_CONDITIONAL); // only one we have.
1798
1799 if ( (!calc_ast_const_expr(ctx, expr->ternary.left, data)) ||
1800 (!calc_ast_const_expr(ctx, expr->ternary.center, &subdata2)) ||
1801 (!calc_ast_const_expr(ctx, expr->ternary.right, &subdata3)) )
1802 return 0;
1803
1804 // first operand should be bool (for the one ternary operator we have).
1805 if (data->isflt)
1806 {
1807 data->isflt = 0;
1808 data->value.i = (int64) subdata3.value.f;
1809 } // if
1810
1811 // upgrade to float if either operand is float.
1812 if ((subdata2.isflt) || (subdata3.isflt))
1813 {
1814 if (!subdata2.isflt) subdata2.value.f = (double) subdata2.value.i;
1815 if (!subdata3.isflt) subdata3.value.f = (double) subdata3.value.i;
1816 subdata2.isflt = subdata3.isflt = 1;
1817 } // if
1818
1819 data->isflt = subdata2.isflt;
1820 if (data->isflt)
1821 data->value.f = data->value.i ? subdata2.value.f : subdata3.value.f;
1822 else
1823 data->value.i = data->value.i ? subdata2.value.i : subdata3.value.i;
1824 return 1;
1825 } // else if
1826
1827 else // not an operator? See if this is a literal value.
1828 {
1829 switch (op)
1830 {
1831 case MOJOSHADER_AST_OP_INT_LITERAL:
1832 data->isflt = 0;
1833 data->value.i = expr->intliteral.value;
1834 return 1;
1835
1836 case MOJOSHADER_AST_OP_FLOAT_LITERAL:
1837 data->isflt = 1;
1838 data->value.f = expr->floatliteral.value;
1839 return 1;
1840
1841 case MOJOSHADER_AST_OP_BOOLEAN_LITERAL:
1842 data->isflt = 0;
1843 data->value.i = expr->boolliteral.value ? 1 : 0;
1844 return 1;
1845
1846 default: break;
1847 } // switch
1848 } // switch
1849
1850 return 0; // not constant, or unhandled.
1851 } // calc_ast_const_expr
1852
1853
reduce_datatype(Context * ctx,const MOJOSHADER_astDataType * dt)1854 static const MOJOSHADER_astDataType *reduce_datatype(Context *ctx, const MOJOSHADER_astDataType *dt)
1855 {
1856 const MOJOSHADER_astDataType *retval = dt;
1857 while (retval && retval->type == MOJOSHADER_AST_DATATYPE_USER)
1858 {
1859 // !!! FIXME: Ugh, const removal.
1860 MOJOSHADER_astDataTypeUser *user = (MOJOSHADER_astDataTypeUser *) &retval->user;
1861 if (user->details->type == MOJOSHADER_AST_DATATYPE_NONE)
1862 {
1863 // Take this opportunity to fix up some usertype stubs that were
1864 // left over from the parse phase. You HAVE to catch these in the
1865 // right scope, so be aggressive about calling reduce_datatype()
1866 // as soon as things come into view!
1867 user->details = get_usertype(ctx, user->name);
1868 assert(user->details != NULL);
1869 } // if
1870
1871 retval = user->details;
1872 } // while
1873
1874 return retval;
1875 } // reduce_datatype
1876
1877
sanitize_datatype(Context * ctx,const MOJOSHADER_astDataType * dt)1878 static inline const MOJOSHADER_astDataType *sanitize_datatype(Context *ctx, const MOJOSHADER_astDataType *dt)
1879 {
1880 reduce_datatype(ctx, dt);
1881 return dt;
1882 } // sanitize_datatype
1883
1884
build_function_datatype(Context * ctx,const MOJOSHADER_astDataType * rettype,const int paramcount,const MOJOSHADER_astDataType ** params,const int intrinsic)1885 static const MOJOSHADER_astDataType *build_function_datatype(Context *ctx,
1886 const MOJOSHADER_astDataType *rettype,
1887 const int paramcount,
1888 const MOJOSHADER_astDataType **params,
1889 const int intrinsic)
1890 {
1891 if ( ((paramcount > 0) && (params == NULL)) ||
1892 ((paramcount == 0) && (params != NULL)) )
1893 return NULL;
1894
1895 // !!! FIXME: this is hacky.
1896 const MOJOSHADER_astDataType **dtparams;
1897 void *ptr = Malloc(ctx, sizeof (*params) * paramcount);
1898 if (ptr == NULL)
1899 return NULL;
1900 if (!buffer_append(ctx->garbage, &ptr, sizeof (ptr)))
1901 {
1902 Free(ctx, ptr);
1903 return NULL;
1904 } // if
1905 dtparams = (const MOJOSHADER_astDataType **) ptr;
1906 memcpy(dtparams, params, sizeof (*params) * paramcount);
1907
1908 ptr = Malloc(ctx, sizeof (MOJOSHADER_astDataType));
1909 if (ptr == NULL)
1910 return NULL;
1911 if (!buffer_append(ctx->garbage, &ptr, sizeof (ptr)))
1912 {
1913 Free(ctx, ptr);
1914 return NULL;
1915 } // if
1916
1917 MOJOSHADER_astDataType *dt = (MOJOSHADER_astDataType *) ptr;
1918 dt->type = MOJOSHADER_AST_DATATYPE_FUNCTION;
1919 dt->function.retval = rettype;
1920 dt->function.params = dtparams;
1921 dt->function.num_params = paramcount;
1922 dt->function.intrinsic = intrinsic;
1923 return dt;
1924 } // build_function_datatype
1925
1926
build_datatype(Context * ctx,const int isconst,const MOJOSHADER_astDataType * dt,MOJOSHADER_astScalarOrArray * soa)1927 static const MOJOSHADER_astDataType *build_datatype(Context *ctx,
1928 const int isconst,
1929 const MOJOSHADER_astDataType *dt,
1930 MOJOSHADER_astScalarOrArray *soa)
1931 {
1932 MOJOSHADER_astDataType *retval = NULL;
1933
1934 assert( (soa->isarray && soa->dimension) ||
1935 (!soa->isarray && !soa->dimension) );
1936
1937 sanitize_datatype(ctx, dt);
1938
1939 // see if we can just reuse the exist datatype.
1940 if (!soa->isarray)
1941 {
1942 const int c1 = (dt->type & MOJOSHADER_AST_DATATYPE_CONST) != 0;
1943 const int c2 = (isconst != 0);
1944 if (c1 == c2)
1945 return dt; // reuse existing datatype!
1946 } // if
1947
1948 retval = (MOJOSHADER_astDataType *) Malloc(ctx, sizeof (*retval));
1949 if (retval == NULL)
1950 return NULL;
1951
1952 // !!! FIXME: this is hacky.
1953 if (!buffer_append(ctx->garbage, &retval, sizeof (retval)))
1954 {
1955 Free(ctx, retval);
1956 return NULL;
1957 } // if
1958
1959 if (!soa->isarray)
1960 {
1961 assert(soa->dimension == NULL);
1962 memcpy(retval, dt, sizeof (MOJOSHADER_astDataType));
1963 if (isconst)
1964 retval->type = (MOJOSHADER_astDataTypeType)((unsigned)retval->type | MOJOSHADER_AST_DATATYPE_CONST);
1965 else
1966 retval->type = (MOJOSHADER_astDataTypeType)((unsigned)retval->type & ~MOJOSHADER_AST_DATATYPE_CONST);
1967 return retval;
1968 } // if
1969
1970 retval->type = MOJOSHADER_AST_DATATYPE_ARRAY;
1971 retval->array.base = dt;
1972 if (soa->dimension == NULL)
1973 {
1974 retval->array.elements = -1;
1975 return retval;
1976 } // if
1977
1978 // Run the expression to verify it's constant and produces a positive int.
1979 AstCalcData data;
1980 data.isflt = 0;
1981 data.value.i = 0;
1982 retval->array.elements = 16; // sane default for failure.
1983 const int ok = calc_ast_const_expr(ctx, soa->dimension, &data);
1984
1985 // reset error position.
1986 ctx->sourcefile = soa->ast.filename;
1987 ctx->sourceline = soa->ast.line;
1988
1989 if (!ok)
1990 fail(ctx, "array dimensions not constant");
1991 else if (data.isflt)
1992 fail(ctx, "array dimensions not integer");
1993 else if (data.value.i < 0)
1994 fail(ctx, "array dimensions negative");
1995 else
1996 retval->array.elements = data.value.i;
1997
1998 return retval;
1999 } // build_datatype
2000
2001
require_numeric_datatype(Context * ctx,const MOJOSHADER_astDataType * datatype)2002 static void require_numeric_datatype(Context *ctx,
2003 const MOJOSHADER_astDataType *datatype)
2004 {
2005 datatype = reduce_datatype(ctx, datatype);
2006 if (datatype->type == MOJOSHADER_AST_DATATYPE_VECTOR)
2007 datatype = reduce_datatype(ctx, datatype->vector.base);
2008 else if (datatype->type == MOJOSHADER_AST_DATATYPE_MATRIX)
2009 datatype = reduce_datatype(ctx, datatype->matrix.base);
2010
2011 switch (datatype->type)
2012 {
2013 case MOJOSHADER_AST_DATATYPE_BOOL:
2014 case MOJOSHADER_AST_DATATYPE_INT:
2015 case MOJOSHADER_AST_DATATYPE_UINT:
2016 case MOJOSHADER_AST_DATATYPE_HALF:
2017 case MOJOSHADER_AST_DATATYPE_FLOAT:
2018 case MOJOSHADER_AST_DATATYPE_DOUBLE:
2019 return;
2020 default: break;
2021 } // switch
2022
2023 fail(ctx, "Expected numeric type"); // !!! FIXME: fmt.
2024 // !!! FIXME: replace AST node with an AST_OP_INT_LITERAL zero, keep going.
2025 } // require_numeric_datatype
2026
require_integer_datatype(Context * ctx,const MOJOSHADER_astDataType * datatype)2027 static void require_integer_datatype(Context *ctx,
2028 const MOJOSHADER_astDataType *datatype)
2029 {
2030 datatype = reduce_datatype(ctx, datatype);
2031 switch (datatype->type)
2032 {
2033 case MOJOSHADER_AST_DATATYPE_INT:
2034 case MOJOSHADER_AST_DATATYPE_UINT:
2035 return;
2036 default: break;
2037 } // switch
2038
2039 fail(ctx, "Expected integer type"); // !!! FIXME: fmt.
2040 // !!! FIXME: replace AST node with an AST_OP_INT_LITERAL zero, keep going.
2041 } // require_integer_datatype
2042
require_boolean_datatype(Context * ctx,const MOJOSHADER_astDataType * datatype)2043 static void require_boolean_datatype(Context *ctx,
2044 const MOJOSHADER_astDataType *datatype)
2045 {
2046 datatype = reduce_datatype(ctx, datatype);
2047 switch (datatype->type)
2048 {
2049 case MOJOSHADER_AST_DATATYPE_BOOL:
2050 case MOJOSHADER_AST_DATATYPE_INT:
2051 case MOJOSHADER_AST_DATATYPE_UINT:
2052 return;
2053 default: break;
2054 } // switch
2055
2056 fail(ctx, "Expected boolean type"); // !!! FIXME: fmt.
2057 // !!! FIXME: replace AST node with an AST_OP_BOOLEAN_LITERAL false, keep going.
2058 } // require_numeric_datatype
2059
2060
require_array_datatype(Context * ctx,const MOJOSHADER_astDataType * datatype)2061 static void require_array_datatype(Context *ctx,
2062 const MOJOSHADER_astDataType *datatype)
2063 {
2064 datatype = reduce_datatype(ctx, datatype);
2065 if (datatype->type == MOJOSHADER_AST_DATATYPE_ARRAY)
2066 return;
2067
2068 fail(ctx, "expected array");
2069 // !!! FIXME: delete array dereference for further processing.
2070 } // require_array_datatype
2071
2072
require_struct_datatype(Context * ctx,const MOJOSHADER_astDataType * datatype)2073 static void require_struct_datatype(Context *ctx,
2074 const MOJOSHADER_astDataType *datatype)
2075 {
2076 datatype = reduce_datatype(ctx, datatype);
2077 if (datatype->type == MOJOSHADER_AST_DATATYPE_STRUCT)
2078 return;
2079
2080 fail(ctx, "expected struct");
2081 // !!! FIXME: delete struct dereference for further processing.
2082 } // require_struct_datatype
2083
2084
require_function_datatype(Context * ctx,const MOJOSHADER_astDataType * datatype)2085 static int require_function_datatype(Context *ctx,
2086 const MOJOSHADER_astDataType *datatype)
2087 {
2088 datatype = reduce_datatype(ctx, datatype);
2089 if ((!datatype) || (datatype->type != MOJOSHADER_AST_DATATYPE_FUNCTION))
2090 {
2091 fail(ctx, "expected function");
2092 return 0;
2093 } // if
2094
2095 return 1;
2096 } // require_function_datatype
2097
2098
2099 // Extract the individual element type from an array datatype.
array_element_datatype(Context * ctx,const MOJOSHADER_astDataType * datatype)2100 static const MOJOSHADER_astDataType *array_element_datatype(Context *ctx,
2101 const MOJOSHADER_astDataType *datatype)
2102 {
2103 datatype = reduce_datatype(ctx, datatype);
2104 assert(datatype->type == MOJOSHADER_AST_DATATYPE_ARRAY);
2105 return datatype->array.base;
2106 } // array_element_datatype
2107
2108
2109 // This tests two datatypes to see if they are compatible, and adds cast
2110 // operator nodes to the AST if the program was relying on implicit
2111 // casts between then. Will fail() if the datatypes can't be coerced
2112 // with a cast at all. (left) can be NULL to say that its datatype is
2113 // set in stone (an lvalue, for example). No other NULLs are allowed.
2114 // Returns final datatype used once implicit casting is complete.
2115 // The datatypes must be pointers from the string cache.
add_type_coercion(Context * ctx,MOJOSHADER_astExpression ** left,const MOJOSHADER_astDataType * _ldatatype,MOJOSHADER_astExpression ** right,const MOJOSHADER_astDataType * _rdatatype)2116 static const MOJOSHADER_astDataType *add_type_coercion(Context *ctx,
2117 MOJOSHADER_astExpression **left,
2118 const MOJOSHADER_astDataType *_ldatatype,
2119 MOJOSHADER_astExpression **right,
2120 const MOJOSHADER_astDataType *_rdatatype)
2121 {
2122 // !!! FIXME: this whole function is probably naive at best.
2123 const MOJOSHADER_astDataType *ldatatype = reduce_datatype(ctx, _ldatatype);
2124 const MOJOSHADER_astDataType *rdatatype = reduce_datatype(ctx, _rdatatype);
2125
2126 if (ldatatype == rdatatype)
2127 return ldatatype; // they already match, so we're done.
2128
2129 struct {
2130 const MOJOSHADER_astDataTypeType type;
2131 const int bits;
2132 const int is_unsigned;
2133 const int floating;
2134 } typeinf[] = {
2135 { MOJOSHADER_AST_DATATYPE_BOOL, 1, 1, 0 },
2136 { MOJOSHADER_AST_DATATYPE_HALF, 16, 0, 1 },
2137 { MOJOSHADER_AST_DATATYPE_INT, 32, 0, 0 },
2138 { MOJOSHADER_AST_DATATYPE_UINT, 32, 1, 0 },
2139 { MOJOSHADER_AST_DATATYPE_FLOAT, 32, 0, 1 },
2140 { MOJOSHADER_AST_DATATYPE_DOUBLE, 64, 0, 1 },
2141 };
2142
2143 int lvector = 0;
2144 int lmatrix = 0;
2145 int l = STATICARRAYLEN(typeinf);
2146 if (ldatatype != NULL)
2147 {
2148 MOJOSHADER_astDataTypeType type = ldatatype->type;
2149 if (type == MOJOSHADER_AST_DATATYPE_VECTOR)
2150 {
2151 lvector = 1;
2152 type = ldatatype->vector.base->type;
2153 } // if
2154 else if (type == MOJOSHADER_AST_DATATYPE_MATRIX)
2155 {
2156 lmatrix = 1;
2157 type = ldatatype->matrix.base->type;
2158 } // if
2159
2160 for (l = 0; l < STATICARRAYLEN(typeinf); l++)
2161 {
2162 if (typeinf[l].type == type)
2163 break;
2164 } // for
2165 } // if
2166
2167 int rvector = 0;
2168 int rmatrix = 0;
2169 int r = STATICARRAYLEN(typeinf);
2170 if (rdatatype != NULL)
2171 {
2172 MOJOSHADER_astDataTypeType type = rdatatype->type;
2173 if (type == MOJOSHADER_AST_DATATYPE_VECTOR)
2174 {
2175 rvector = 1;
2176 type = rdatatype->vector.base->type;
2177 } // if
2178 else if (type == MOJOSHADER_AST_DATATYPE_MATRIX)
2179 {
2180 rmatrix = 1;
2181 type = rdatatype->matrix.base->type;
2182 } // if
2183
2184 for (r = 0; r < STATICARRAYLEN(typeinf); r++)
2185 {
2186 if (typeinf[r].type == type)
2187 break;
2188 } // for
2189 } // if
2190
2191 enum { CHOOSE_NEITHER, CHOOSE_LEFT, CHOOSE_RIGHT } choice = CHOOSE_NEITHER;
2192 if ((l < STATICARRAYLEN(typeinf)) && (r < STATICARRAYLEN(typeinf)))
2193 {
2194 if (left == NULL)
2195 choice = CHOOSE_LEFT; // we need to force to the lvalue.
2196 else if (lmatrix && !rmatrix)
2197 choice = CHOOSE_LEFT;
2198 else if (!lmatrix && rmatrix)
2199 choice = CHOOSE_RIGHT;
2200 else if (lvector && !rvector)
2201 choice = CHOOSE_LEFT;
2202 else if (!lvector && rvector)
2203 choice = CHOOSE_RIGHT;
2204 else if (typeinf[l].bits > typeinf[r].bits)
2205 choice = CHOOSE_LEFT;
2206 else if (typeinf[l].bits < typeinf[r].bits)
2207 choice = CHOOSE_RIGHT;
2208 else if (typeinf[l].floating && !typeinf[r].floating)
2209 choice = CHOOSE_LEFT;
2210 else if (!typeinf[l].floating && typeinf[r].floating)
2211 choice = CHOOSE_RIGHT;
2212 else if (typeinf[l].is_unsigned && !typeinf[r].is_unsigned)
2213 choice = CHOOSE_LEFT;
2214 else if (!typeinf[l].is_unsigned && typeinf[r].is_unsigned)
2215 choice = CHOOSE_RIGHT;
2216 } // if
2217
2218 if (choice == CHOOSE_LEFT)
2219 {
2220 *right = new_cast_expr(ctx, _ldatatype, *right);
2221 return _ldatatype;
2222 } // if
2223 else if (choice == CHOOSE_RIGHT)
2224 {
2225 *left = new_cast_expr(ctx, _rdatatype, *left);
2226 return _rdatatype;
2227 } // else if
2228
2229 assert(choice == CHOOSE_NEITHER);
2230 fail(ctx, "incompatible data types");
2231 // Ditch original (*right), force a literal value that matches
2232 // ldatatype, so further processing is normalized.
2233 // !!! FIXME: force (right) to match (left).
2234 delete_expr(ctx, *right);
2235 *right = new_cast_expr(ctx, _ldatatype, new_literal_int_expr(ctx, 0));
2236 return ldatatype;
2237 } // add_type_coercion
2238
is_swizzle_str(const char * str,const int veclen)2239 static int is_swizzle_str(const char *str, const int veclen)
2240 {
2241 int i;
2242 int is_xyzw = 0;
2243 int is_rgba = 0;
2244
2245 assert(*str != '\0'); // can this actually happen?
2246
2247 for (i = 0; i < veclen; i++, str++)
2248 {
2249 const char ch = *str;
2250 if (ch == '\0')
2251 break;
2252 else if ((ch == 'x') || (ch == 'y') || (ch == 'z') || (ch == 'w'))
2253 is_xyzw = 1;
2254 else if ((ch == 'r') || (ch == 'g') || (ch == 'b') || (ch == 'a'))
2255 is_rgba = 1;
2256 } // for
2257
2258 if (*str != '\0') // must be end of string here.
2259 return 0; // not a swizzle.
2260 return ((is_rgba + is_xyzw) == 1); // can only be one or the other.
2261 } // is_swizzle_str
2262
datatype_size(const MOJOSHADER_astDataType * dt)2263 static int datatype_size(const MOJOSHADER_astDataType *dt)
2264 {
2265 switch (dt->type)
2266 {
2267 case MOJOSHADER_AST_DATATYPE_BOOL: return 1;
2268 case MOJOSHADER_AST_DATATYPE_INT: return 4;
2269 case MOJOSHADER_AST_DATATYPE_UINT: return 4;
2270 case MOJOSHADER_AST_DATATYPE_FLOAT: return 4;
2271 case MOJOSHADER_AST_DATATYPE_FLOAT_SNORM: return 4;
2272 case MOJOSHADER_AST_DATATYPE_FLOAT_UNORM: return 4;
2273 case MOJOSHADER_AST_DATATYPE_HALF: return 2;
2274 case MOJOSHADER_AST_DATATYPE_DOUBLE: return 8;
2275 return 1;
2276 default:
2277 assert(0 && "Maybe should have used reduce_datatype()?");
2278 return 0;
2279 } // switch
2280 } // datatype_size
2281
is_scalar_datatype(const MOJOSHADER_astDataType * dt)2282 static inline int is_scalar_datatype(const MOJOSHADER_astDataType *dt)
2283 {
2284 switch (dt->type)
2285 {
2286 case MOJOSHADER_AST_DATATYPE_BOOL:
2287 case MOJOSHADER_AST_DATATYPE_INT:
2288 case MOJOSHADER_AST_DATATYPE_UINT:
2289 case MOJOSHADER_AST_DATATYPE_FLOAT:
2290 case MOJOSHADER_AST_DATATYPE_FLOAT_SNORM:
2291 case MOJOSHADER_AST_DATATYPE_FLOAT_UNORM:
2292 case MOJOSHADER_AST_DATATYPE_HALF:
2293 case MOJOSHADER_AST_DATATYPE_DOUBLE:
2294 return 1;
2295 default:
2296 return 0;
2297 } // switch
2298 } // is_scalar_datatype
2299
is_float_datatype(const MOJOSHADER_astDataType * dt)2300 static inline int is_float_datatype(const MOJOSHADER_astDataType *dt)
2301 {
2302 switch (dt->type)
2303 {
2304 case MOJOSHADER_AST_DATATYPE_FLOAT: return 1;
2305 case MOJOSHADER_AST_DATATYPE_FLOAT_SNORM: return 1;
2306 case MOJOSHADER_AST_DATATYPE_FLOAT_UNORM: return 1;
2307 default: return 0;
2308 } // switch
2309 } // is_float_datatype
2310
datatype_elems(Context * ctx,const MOJOSHADER_astDataType * dt)2311 static int datatype_elems(Context *ctx, const MOJOSHADER_astDataType *dt)
2312 {
2313 dt = reduce_datatype(ctx, dt);
2314 switch (dt->type)
2315 {
2316 case MOJOSHADER_AST_DATATYPE_VECTOR:
2317 return dt->vector.elements;
2318 case MOJOSHADER_AST_DATATYPE_MATRIX:
2319 return dt->matrix.rows * dt->matrix.columns;
2320 default:
2321 return 1;
2322 } // switch
2323 } // datatype_elems
2324
datatype_base(Context * ctx,const MOJOSHADER_astDataType * dt)2325 static const MOJOSHADER_astDataType *datatype_base(Context *ctx, const MOJOSHADER_astDataType *dt)
2326 {
2327 dt = reduce_datatype(ctx, dt);
2328 if (dt == NULL)
2329 return dt;
2330
2331 switch (dt->type)
2332 {
2333 case MOJOSHADER_AST_DATATYPE_VECTOR:
2334 dt = dt->vector.base;
2335 break;
2336 case MOJOSHADER_AST_DATATYPE_MATRIX:
2337 dt = dt->matrix.base;
2338 break;
2339 case MOJOSHADER_AST_DATATYPE_BUFFER:
2340 dt = dt->buffer.base;
2341 break;
2342 case MOJOSHADER_AST_DATATYPE_ARRAY:
2343 dt = dt->array.base;
2344 break;
2345 default: break;
2346 } // switch
2347
2348 return dt;
2349 } // datatype_base
2350
2351 typedef enum
2352 {
2353 DT_MATCH_INCOMPATIBLE, // flatly incompatible
2354 DT_MATCH_COMPATIBLE_DOWNCAST, // would have to lose precision
2355 DT_MATCH_COMPATIBLE_UPCAST, // would have to gain precision
2356 DT_MATCH_COMPATIBLE, // can cast to without serious change.
2357 DT_MATCH_PERFECT // identical datatype.
2358 } DatatypeMatch;
2359
compatible_arg_datatype(Context * ctx,const MOJOSHADER_astDataType * arg,const MOJOSHADER_astDataType * param)2360 static DatatypeMatch compatible_arg_datatype(Context *ctx,
2361 const MOJOSHADER_astDataType *arg,
2362 const MOJOSHADER_astDataType *param)
2363 {
2364 // The matching rules for HLSL function overloading, as far as I can
2365 // tell from experimenting with Microsoft's compiler, seem to be this:
2366 //
2367 // - All parameters of a function must match what the caller specified
2368 // after possible type promotion via the following rules.
2369 // - If the number of arguments and the number of parameters don't match,
2370 // that overload is immediately rejected.
2371 // - Each overloaded function is given a score that is the sum of the
2372 // "worth" of each parameter vs the caller's arguments
2373 // (see DatatypeMatch). The higher the score, the more favorable this
2374 // function overload would be.
2375 // - If there is a tie for highest score between two or more function
2376 // overloads, we declare that function call to be ambiguous and fail().
2377 // - Scalars can be promoted to vectors to make a parameter match.
2378 // - Scalars can promote to other scalars (short to int, etc).
2379 // - Datatypes can downcast, but should generate a warning.
2380 // (calling void fn(float x); as fn((double)1.0) should warn).
2381 // - Vectors may NOT be extend (a float2 can't implicity extend to a
2382 // float4).
2383 // - Vectors with the same elements can promote (a half2 can become
2384 // a float2). Downcasting between vectors with the same number of
2385 // elements is allowed.
2386 // - A perfect match of all params will be favored over any functions
2387 // that only match if type promotion is applied (given a perfect match
2388 // of all parameters, we'll stop looking for other matches).
2389
2390 if (datatypes_match(arg, param))
2391 return DT_MATCH_PERFECT; // that was easy.
2392
2393 arg = reduce_datatype(ctx, arg);
2394 param = reduce_datatype(ctx, param);
2395
2396 int do_base_test = 0;
2397
2398 if (is_scalar_datatype(arg))
2399 do_base_test = 1; // we let these all go through for now.
2400
2401 else if (arg->type == param->type)
2402 {
2403 if (arg->type == MOJOSHADER_AST_DATATYPE_VECTOR)
2404 do_base_test = (arg->vector.elements == param->vector.elements);
2405 else if (arg->type == MOJOSHADER_AST_DATATYPE_MATRIX)
2406 {
2407 do_base_test =
2408 ((arg->matrix.rows == param->matrix.rows) &&
2409 (arg->matrix.columns == param->matrix.columns));
2410 } // if
2411 } // if
2412
2413 if (do_base_test)
2414 {
2415 arg = datatype_base(ctx, arg);
2416 param = datatype_base(ctx, param);
2417
2418 const int argsize = datatype_size(arg);
2419 const int paramsize = datatype_size(param);
2420 const int argfloat = is_float_datatype(arg);
2421 const int paramfloat = is_float_datatype(param);
2422
2423 if (argfloat && !paramfloat)
2424 return DT_MATCH_COMPATIBLE_DOWNCAST; // always loss of precision.
2425 else if (argfloat && !paramfloat)
2426 {
2427 if (argsize < paramsize)
2428 return DT_MATCH_COMPATIBLE_UPCAST;
2429 else
2430 return DT_MATCH_COMPATIBLE_DOWNCAST; // loss of precision.
2431 } // else if
2432 else if (argsize == paramsize)
2433 return DT_MATCH_COMPATIBLE;
2434 else if (argsize < paramsize)
2435 return DT_MATCH_COMPATIBLE_UPCAST;
2436 else /* if (argsize > paramsize) */
2437 return DT_MATCH_COMPATIBLE_DOWNCAST;
2438 } // if
2439
2440 return DT_MATCH_INCOMPATIBLE;
2441 } // compatible_arg_datatype
2442
2443
2444 static const MOJOSHADER_astDataType *type_check_ast(Context *ctx, void *_ast);
2445
2446 // !!! FIXME: this function sucks.
match_func_to_call(Context * ctx,MOJOSHADER_astExpressionCallFunction * ast)2447 static const MOJOSHADER_astDataType *match_func_to_call(Context *ctx,
2448 MOJOSHADER_astExpressionCallFunction *ast)
2449 {
2450 SymbolScope *best = NULL; // best choice we find.
2451 int best_score = 0;
2452 MOJOSHADER_astExpressionIdentifier *ident = ast->identifier;
2453 const char *sym = ident->identifier;
2454 const void *value = NULL;
2455 void *iter = NULL;
2456
2457 int argcount = 0;
2458 MOJOSHADER_astArguments *args = ast->args;
2459 while (args != NULL)
2460 {
2461 argcount++;
2462 type_check_ast(ctx, args->argument);
2463 args = args->next;
2464 } // while;
2465
2466 // we do some tapdancing to handle function overloading here.
2467 int match = 0;
2468 while (hash_iter(ctx->variables.hash, sym, &value, &iter))
2469 {
2470 SymbolScope *item = (SymbolScope *) value;
2471 const MOJOSHADER_astDataType *dt = item->datatype;
2472 dt = reduce_datatype(ctx, dt);
2473 // there's a locally-scoped symbol with this name? It takes precedence.
2474 if (dt->type != MOJOSHADER_AST_DATATYPE_FUNCTION)
2475 return dt;
2476
2477 const MOJOSHADER_astDataTypeFunction *dtfn = (MOJOSHADER_astDataTypeFunction *) dt;
2478 const int perfect = argcount * ((int) DT_MATCH_PERFECT);
2479 int score = 0;
2480
2481 if (argcount == dtfn->num_params) // !!! FIXME: default args.
2482 {
2483 args = ast->args;
2484 int i;
2485 for (i = 0; i < argcount; i++)
2486 {
2487 assert(args != NULL);
2488 dt = args->argument->datatype;
2489 args = args->next;
2490 const DatatypeMatch compatible = compatible_arg_datatype(ctx, dt, dtfn->params[i]);
2491 if (compatible == DT_MATCH_INCOMPATIBLE)
2492 {
2493 args = NULL;
2494 score = 0;
2495 break;
2496 } // if
2497
2498 score += (int) compatible;
2499 } // for
2500
2501 if (args != NULL)
2502 score = 0; // too many arguments supplied. No match.
2503 } // else
2504
2505 if (score == 0) // incompatible.
2506 continue;
2507
2508 else if (score == perfect) // perfection! stop looking!
2509 {
2510 match = 1; // ignore all other compatible matches.
2511 best = item;
2512 break;
2513 } // if
2514
2515 else if (score >= best_score) // compatible, but not perfect, match.
2516 {
2517 if (score == best_score)
2518 {
2519 match++;
2520 // !!! FIXME: list each possible function in a fail(),
2521 // !!! FIXME: but you can't actually fail() here, since
2522 // !!! FIXME: this may cease to be ambiguous if we get
2523 // !!! FIXME: a better match on a later overload.
2524 } // if
2525
2526 else if (score > best_score)
2527 {
2528 match = 1; // reset the ambiguousness count.
2529 best = item;
2530 best_score = score;
2531 } // if
2532 } // else if
2533 } // while
2534
2535 if (match > 1)
2536 {
2537 assert(best != NULL);
2538 failf(ctx, "Ambiguous function call to '%s'", sym);
2539 } // if
2540
2541 if (best == NULL)
2542 {
2543 assert(match == 0);
2544 assert(best_score == 0);
2545 // !!! FIXME: ident->datatype = ?
2546 failf(ctx, "No matching function named '%s'", sym);
2547 } // if
2548 else
2549 {
2550 ident->datatype = reduce_datatype(ctx, best->datatype);
2551 ident->index = best->index;
2552 } // else
2553
2554 return ident->datatype;
2555 } // match_func_to_call
2556
2557
vectype_from_base(Context * ctx,const MOJOSHADER_astDataType * base,const int len)2558 static const MOJOSHADER_astDataType *vectype_from_base(Context *ctx,
2559 const MOJOSHADER_astDataType *base,
2560 const int len)
2561 {
2562 assert(len > 0);
2563 assert(len <= 4);
2564
2565 if (len == 1) // return "float" and not "float1"
2566 return base;
2567
2568 const char *typestr = NULL;
2569 switch (base->type)
2570 {
2571 case MOJOSHADER_AST_DATATYPE_BOOL: typestr = "bool"; break;
2572 case MOJOSHADER_AST_DATATYPE_INT: typestr = "int"; break;
2573 case MOJOSHADER_AST_DATATYPE_UINT: typestr = "uint"; break;
2574 case MOJOSHADER_AST_DATATYPE_HALF: typestr = "half"; break;
2575 case MOJOSHADER_AST_DATATYPE_FLOAT: typestr = "float"; break;
2576 case MOJOSHADER_AST_DATATYPE_DOUBLE: typestr = "double"; break;
2577 default: assert(0 && "This shouldn't happen"); break;
2578 } // switch
2579
2580 char buf[32];
2581 snprintf(buf, sizeof (buf), "%s%d", typestr, len);
2582 const MOJOSHADER_astDataType *datatype = get_usertype(ctx, buf);
2583 assert(datatype != NULL);
2584 return datatype;
2585 } // vectype_from_base
2586
2587
2588 // Go through the AST and make sure all datatypes check out okay. For datatypes
2589 // that are compatible but are relying on an implicit cast, we add explicit
2590 // casts to the AST here, so further processing doesn't have to worry about
2591 // type coercion.
2592 // For things that are incompatible, we generate errors and
2593 // then replace them with reasonable defaults so further processing can
2594 // continue (but code generation will be skipped due to errors).
2595 // This means further processing can assume the AST is sane and not have to
2596 // spend effort verifying it again.
2597 // This stage will also set every AST node's datatype field, if it is
2598 // meaningful to do so. This will allow conversion to IR to know what
2599 // type/size a given node is.
type_check_ast(Context * ctx,void * _ast)2600 static const MOJOSHADER_astDataType *type_check_ast(Context *ctx, void *_ast)
2601 {
2602 MOJOSHADER_astNode *ast = (MOJOSHADER_astNode *) _ast;
2603 const MOJOSHADER_astDataType *datatype = NULL;
2604 const MOJOSHADER_astDataType *datatype2 = NULL;
2605 const MOJOSHADER_astDataType *datatype3 = NULL;
2606
2607 if ((!ast) || (ctx->out_of_memory))
2608 return NULL;
2609
2610 // upkeep so we report correct error locations...
2611 ctx->sourcefile = ast->ast.filename;
2612 ctx->sourceline = ast->ast.line;
2613
2614 switch (ast->ast.type)
2615 {
2616 case MOJOSHADER_AST_OP_POSTINCREMENT:
2617 case MOJOSHADER_AST_OP_POSTDECREMENT:
2618 case MOJOSHADER_AST_OP_PREINCREMENT:
2619 case MOJOSHADER_AST_OP_PREDECREMENT:
2620 case MOJOSHADER_AST_OP_COMPLEMENT:
2621 case MOJOSHADER_AST_OP_NEGATE:
2622 // !!! FIXME: must be lvalue.
2623 // !!! FIXME: bools must type-promote to ...int?
2624 // !!! FIXME: complement must not be float (...right?)
2625 datatype = type_check_ast(ctx, ast->unary.operand);
2626 require_numeric_datatype(ctx, datatype);
2627 ast->unary.datatype = datatype;
2628 return datatype;
2629
2630 case MOJOSHADER_AST_OP_NOT:
2631 datatype = type_check_ast(ctx, ast->unary.operand);
2632 require_boolean_datatype(ctx, datatype);
2633 // !!! FIXME: coerce to bool here.
2634 ast->unary.datatype = &ctx->dt_bool;
2635 return datatype;
2636
2637 case MOJOSHADER_AST_OP_DEREF_ARRAY:
2638 datatype = type_check_ast(ctx, ast->binary.left);
2639 datatype2 = type_check_ast(ctx, ast->binary.right);
2640 require_integer_datatype(ctx, datatype2);
2641 add_type_coercion(ctx, NULL, &ctx->dt_int, &ast->binary.right, datatype2);
2642
2643 datatype = reduce_datatype(ctx, datatype);
2644 if (datatype->type == MOJOSHADER_AST_DATATYPE_VECTOR)
2645 {
2646 // !!! FIXME: if constant int, fail if not 0 >= value <= vecsize.
2647 ast->binary.datatype = datatype->vector.base;
2648 } // if
2649 else if (datatype->type == MOJOSHADER_AST_DATATYPE_MATRIX)
2650 {
2651 // !!! FIXME: if constant int, fail if not 0 >= value <= rowsize (colsize?).
2652 ast->binary.datatype = vectype_from_base(ctx, datatype->matrix.base, datatype->matrix.columns); // !!! FIXME: rows?
2653 }
2654 else
2655 {
2656 require_array_datatype(ctx, datatype);
2657 ast->binary.datatype = array_element_datatype(ctx, datatype);
2658 } // else
2659
2660 return ast->binary.datatype;
2661
2662 case MOJOSHADER_AST_OP_DEREF_STRUCT:
2663 {
2664 const char *member = ast->derefstruct.member;
2665 datatype = type_check_ast(ctx, ast->derefstruct.identifier);
2666 const MOJOSHADER_astDataType *reduced = reduce_datatype(ctx, datatype);
2667
2668 // Is this a swizzle and not a struct deref?
2669 if (reduced->type == MOJOSHADER_AST_DATATYPE_VECTOR)
2670 {
2671 const int veclen = reduced->vector.elements;
2672 ast->derefstruct.isswizzle = 1;
2673 if (!is_swizzle_str(member, veclen))
2674 {
2675 fail(ctx, "invalid swizzle on vector");
2676 // force this to be sane for further processing.
2677 const char *sane_swiz = stringcache(ctx->strcache, "xyzw");
2678 member = ast->derefstruct.member = sane_swiz;
2679 } // if
2680
2681 const int swizlen = (int) strlen(member);
2682 if (swizlen != veclen)
2683 datatype = vectype_from_base(ctx, reduced->vector.base, swizlen);
2684
2685 ast->derefstruct.datatype = datatype;
2686 return ast->derefstruct.datatype;
2687 } // if
2688
2689 // maybe this is an actual struct?
2690 // !!! FIXME: replace with an int or something if not.
2691 require_struct_datatype(ctx, reduced);
2692
2693 // map member to datatype
2694 assert(ast->derefstruct.datatype == NULL);
2695 const MOJOSHADER_astDataTypeStructMember *mbrs = reduced->structure.members;
2696 int i;
2697 for (i = 0; i < reduced->structure.member_count; i++)
2698 {
2699 if (strcmp(mbrs[i].identifier, member) == 0)
2700 {
2701 ast->derefstruct.datatype = mbrs[i].datatype;
2702 ast->derefstruct.member_index = i;
2703 break;
2704 } // if
2705 } // for
2706
2707 if (ast->derefstruct.datatype == NULL)
2708 {
2709 // !!! FIXME: replace with an int or something.
2710 failf(ctx, "Struct has no member named '%s'", member);
2711 } // if
2712
2713 return ast->derefstruct.datatype;
2714 } // case
2715
2716 case MOJOSHADER_AST_OP_COMMA:
2717 // evaluate and throw away left, return right.
2718 type_check_ast(ctx, ast->binary.left);
2719 ast->binary.datatype = type_check_ast(ctx, ast->binary.right);
2720 return ast->binary.datatype;
2721
2722 case MOJOSHADER_AST_OP_MULTIPLY:
2723 case MOJOSHADER_AST_OP_DIVIDE:
2724 case MOJOSHADER_AST_OP_ADD:
2725 case MOJOSHADER_AST_OP_SUBTRACT:
2726 datatype = type_check_ast(ctx, ast->binary.left);
2727 datatype2 = type_check_ast(ctx, ast->binary.right);
2728 require_numeric_datatype(ctx, datatype);
2729 require_numeric_datatype(ctx, datatype2);
2730 ast->binary.datatype = add_type_coercion(ctx, &ast->binary.left,
2731 datatype, &ast->binary.right, datatype2);
2732 return ast->binary.datatype;
2733
2734 case MOJOSHADER_AST_OP_LSHIFT:
2735 case MOJOSHADER_AST_OP_RSHIFT:
2736 case MOJOSHADER_AST_OP_MODULO:
2737 datatype = type_check_ast(ctx, ast->binary.left);
2738 datatype2 = type_check_ast(ctx, ast->binary.right);
2739 require_integer_datatype(ctx, datatype);
2740 require_integer_datatype(ctx, datatype2);
2741 ast->binary.datatype = add_type_coercion(ctx, &ast->binary.left,
2742 datatype, &ast->binary.right, datatype2);
2743 return ast->binary.datatype;
2744
2745 case MOJOSHADER_AST_OP_LESSTHAN:
2746 case MOJOSHADER_AST_OP_GREATERTHAN:
2747 case MOJOSHADER_AST_OP_LESSTHANOREQUAL:
2748 case MOJOSHADER_AST_OP_GREATERTHANOREQUAL:
2749 case MOJOSHADER_AST_OP_NOTEQUAL:
2750 case MOJOSHADER_AST_OP_EQUAL:
2751 datatype = type_check_ast(ctx, ast->binary.left);
2752 datatype2 = type_check_ast(ctx, ast->binary.right);
2753 add_type_coercion(ctx, &ast->binary.left, datatype,
2754 &ast->binary.right, datatype2);
2755 ast->binary.datatype = &ctx->dt_bool;
2756 return ast->binary.datatype;
2757
2758 case MOJOSHADER_AST_OP_BINARYAND:
2759 case MOJOSHADER_AST_OP_BINARYXOR:
2760 case MOJOSHADER_AST_OP_BINARYOR:
2761 datatype = type_check_ast(ctx, ast->binary.left);
2762 datatype2 = type_check_ast(ctx, ast->binary.right);
2763 require_integer_datatype(ctx, datatype);
2764 require_integer_datatype(ctx, datatype2);
2765 ast->binary.datatype = add_type_coercion(ctx, &ast->binary.left,
2766 datatype, &ast->binary.right, datatype2);
2767 return ast->binary.datatype;
2768
2769 case MOJOSHADER_AST_OP_LOGICALAND:
2770 case MOJOSHADER_AST_OP_LOGICALOR:
2771 datatype = type_check_ast(ctx, ast->binary.left);
2772 datatype2 = type_check_ast(ctx, ast->binary.right);
2773 require_boolean_datatype(ctx, datatype);
2774 require_boolean_datatype(ctx, datatype2);
2775 // !!! FIXME: coerce each to bool here, separately.
2776 add_type_coercion(ctx, &ast->binary.left, datatype,
2777 &ast->binary.right, datatype2);
2778 ast->binary.datatype = &ctx->dt_bool;
2779
2780 case MOJOSHADER_AST_OP_ASSIGN:
2781 case MOJOSHADER_AST_OP_MULASSIGN:
2782 case MOJOSHADER_AST_OP_DIVASSIGN:
2783 case MOJOSHADER_AST_OP_MODASSIGN:
2784 case MOJOSHADER_AST_OP_ADDASSIGN:
2785 case MOJOSHADER_AST_OP_SUBASSIGN:
2786 case MOJOSHADER_AST_OP_LSHIFTASSIGN:
2787 case MOJOSHADER_AST_OP_RSHIFTASSIGN:
2788 case MOJOSHADER_AST_OP_ANDASSIGN:
2789 case MOJOSHADER_AST_OP_XORASSIGN:
2790 case MOJOSHADER_AST_OP_ORASSIGN:
2791 // !!! FIXME: verify binary.left is an lvalue, or fail()!
2792 datatype = type_check_ast(ctx, ast->binary.left);
2793 datatype2 = type_check_ast(ctx, ast->binary.right);
2794 ast->binary.datatype = add_type_coercion(ctx, NULL, datatype,
2795 &ast->binary.right, datatype2);
2796 return ast->binary.datatype;
2797
2798 case MOJOSHADER_AST_OP_CONDITIONAL:
2799 datatype = type_check_ast(ctx, ast->ternary.left);
2800 datatype2 = type_check_ast(ctx, ast->ternary.center);
2801 datatype3 = type_check_ast(ctx, ast->ternary.right);
2802 require_numeric_datatype(ctx, datatype);
2803 ast->ternary.datatype = add_type_coercion(ctx, &ast->ternary.center,
2804 datatype2, &ast->ternary.right, datatype3);
2805 return ast->ternary.datatype;
2806
2807 case MOJOSHADER_AST_OP_IDENTIFIER:
2808 datatype = find_variable(ctx, ast->identifier.identifier, &ast->identifier.index);
2809 if (datatype == NULL)
2810 {
2811 fail(ctx, "Unknown identifier");
2812 // !!! FIXME: replace with a sane default, move on.
2813 datatype = &ctx->dt_int;
2814 } // if
2815 ast->identifier.datatype = datatype;
2816 return ast->identifier.datatype;
2817
2818 case MOJOSHADER_AST_OP_INT_LITERAL:
2819 case MOJOSHADER_AST_OP_FLOAT_LITERAL:
2820 case MOJOSHADER_AST_OP_STRING_LITERAL:
2821 case MOJOSHADER_AST_OP_BOOLEAN_LITERAL:
2822 assert(ast->expression.datatype != NULL);
2823 return ast->expression.datatype; // already set up during parsing.
2824
2825 case MOJOSHADER_AST_ARGUMENTS:
2826 assert(0 && "Should be done by MOJOSHADER_AST_OP_CALLFUNC/CONSTRUCTOR");
2827 return NULL;
2828
2829 case MOJOSHADER_AST_OP_CALLFUNC:
2830 {
2831 datatype = match_func_to_call(ctx, &ast->callfunc);
2832 const MOJOSHADER_astDataType *reduced = reduce_datatype(ctx, datatype);
2833 // !!! FIXME: replace AST node with an int if this isn't a func.
2834 if (!require_function_datatype(ctx, reduced))
2835 {
2836 ast->callfunc.datatype = &ctx->dt_int;
2837 return ast->callfunc.datatype;
2838 } // if
2839
2840 MOJOSHADER_astArguments *arg = ast->callfunc.args;
2841 int i;
2842 for (i = 0; i < reduced->function.num_params; i++)
2843 {
2844 if (arg == NULL) // !!! FIXME: check for default parameters, fill them in.
2845 {
2846 fail(ctx, "Too few arguments");
2847 // !!! FIXME: replace AST here.
2848 break;
2849 } // if
2850 datatype2 = arg->argument->datatype; // already type-checked.
2851 add_type_coercion(ctx, NULL, reduced->function.params[i],
2852 &arg->argument, datatype2);
2853 arg = arg->next;
2854 } // for
2855
2856 assert(arg == NULL); // shouldn't have chosen func if too many args.
2857
2858 ast->callfunc.datatype = reduced->function.retval;
2859 return ast->callfunc.datatype;
2860 } // case
2861
2862 case MOJOSHADER_AST_OP_CONSTRUCTOR:
2863 {
2864 const MOJOSHADER_astDataType *reduced = reduce_datatype(ctx, ast->constructor.datatype);
2865 const MOJOSHADER_astDataType *base_dt = reduced;
2866 int num_params = 1;
2867
2868 assert(reduced != NULL);
2869 switch (reduced->type)
2870 {
2871 case MOJOSHADER_AST_DATATYPE_VECTOR:
2872 num_params = reduced->vector.elements;
2873 base_dt = reduced->vector.base;
2874 break;
2875 case MOJOSHADER_AST_DATATYPE_MATRIX:
2876 num_params = reduced->matrix.rows * reduced->matrix.columns;
2877 base_dt = reduced->matrix.base;
2878 break;
2879
2880 case MOJOSHADER_AST_DATATYPE_BOOL:
2881 case MOJOSHADER_AST_DATATYPE_INT:
2882 case MOJOSHADER_AST_DATATYPE_UINT:
2883 case MOJOSHADER_AST_DATATYPE_FLOAT:
2884 case MOJOSHADER_AST_DATATYPE_FLOAT_SNORM:
2885 case MOJOSHADER_AST_DATATYPE_FLOAT_UNORM:
2886 case MOJOSHADER_AST_DATATYPE_HALF:
2887 case MOJOSHADER_AST_DATATYPE_DOUBLE:
2888 case MOJOSHADER_AST_DATATYPE_STRING:
2889 num_params = 1;
2890 break;
2891
2892 // !!! FIXME: can you construct a MOJOSHADER_AST_DATATYPE_STRUCT?
2893 // !!! FIXME: can you construct a MOJOSHADER_AST_DATATYPE_ARRAY?
2894 // !!! FIXME: can you construct a MOJOSHADER_AST_DATATYPE_BUFFER?
2895
2896 default:
2897 fail(ctx, "Invalid type for constructor");
2898 delete_arguments(ctx, ast->constructor.args);
2899 ast->constructor.args = new_argument(ctx, new_literal_int_expr(ctx, 0));
2900 ast->constructor.datatype = &ctx->dt_int;
2901 return ast->constructor.datatype;
2902 } // switch
2903
2904 assert(num_params > 0);
2905
2906 MOJOSHADER_astArguments *arg = ast->constructor.args;
2907 MOJOSHADER_astArguments *prev = NULL;
2908 int i;
2909 for (i = 0; i < num_params; i++)
2910 {
2911 if (arg == NULL) // !!! FIXME: check for default parameters.
2912 {
2913 fail(ctx, "Too few arguments");
2914 // !!! FIXME: replace AST here.
2915 break;
2916 } // if
2917 datatype2 = type_check_ast(ctx, arg->argument);
2918
2919 // "float4(float3(1,2,3),4)" is legal, so we need to see if
2920 // we're a vector, and jump that number of parameters instead
2921 // of doing type coercion.
2922 reduced = reduce_datatype(ctx, datatype2);
2923 if (reduced->type == MOJOSHADER_AST_DATATYPE_VECTOR)
2924 {
2925 // make sure things like float4(half3(1,2,3),1) convert that half3 to float3.
2926 const int count = reduced->vector.elements;
2927 datatype3 = vectype_from_base(ctx, base_dt, count);
2928 add_type_coercion(ctx, NULL, datatype3, &arg->argument, datatype2);
2929 i += count - 1;
2930 } // else
2931 else
2932 {
2933 add_type_coercion(ctx, NULL, base_dt, &arg->argument, datatype2);
2934 } // else
2935 prev = arg;
2936 arg = arg->next;
2937 } // for
2938
2939 if (arg != NULL)
2940 {
2941 fail(ctx, "Too many arguments");
2942 // Process extra arguments then chop them out.
2943 MOJOSHADER_astArguments *argi;
2944 for (argi = arg; argi != NULL; argi = argi->next)
2945 type_check_ast(ctx, argi->argument);
2946 if (prev != NULL)
2947 prev->next = NULL;
2948 delete_arguments(ctx, arg);
2949 } // if
2950
2951 return ast->constructor.datatype;
2952 } // case
2953
2954 case MOJOSHADER_AST_OP_CAST:
2955 datatype = sanitize_datatype(ctx, ast->cast.datatype);
2956 datatype2 = type_check_ast(ctx, ast->cast.operand);
2957 // you still need type coercion, since you could do a wrong cast,
2958 // like "int x = (short) mychar;"
2959 add_type_coercion(ctx, NULL, datatype, &ast->cast.operand, datatype2);
2960 return datatype;
2961
2962 case MOJOSHADER_AST_STATEMENT_BREAK:
2963 if ((ctx->loop_count == 0) && (ctx->switch_count == 0))
2964 fail(ctx, "Break outside loop or switch");
2965 // !!! FIXME: warn if unreachable statements follow?
2966 type_check_ast(ctx, ast->stmt.next);
2967 return NULL;
2968
2969 case MOJOSHADER_AST_STATEMENT_CONTINUE:
2970 if (ctx->loop_count == 0)
2971 fail(ctx, "Continue outside loop");
2972 // !!! FIXME: warn if unreachable statements follow?
2973 type_check_ast(ctx, ast->stmt.next);
2974 return NULL;
2975
2976 case MOJOSHADER_AST_STATEMENT_DISCARD:
2977 // !!! FIXME: warn if unreachable statements follow?
2978 type_check_ast(ctx, ast->stmt.next);
2979 return NULL;
2980
2981 case MOJOSHADER_AST_STATEMENT_EMPTY:
2982 type_check_ast(ctx, ast->stmt.next);
2983 return NULL;
2984
2985 case MOJOSHADER_AST_STATEMENT_EXPRESSION:
2986 // !!! FIXME: warn about expressions without a side-effect here?
2987 type_check_ast(ctx, ast->exprstmt.expr); // !!! FIXME: This is named badly...
2988 type_check_ast(ctx, ast->exprstmt.next);
2989 return NULL;
2990
2991 case MOJOSHADER_AST_STATEMENT_IF:
2992 push_scope(ctx); // new scope for "if ((int x = blah()) != 0)"
2993 type_check_ast(ctx, ast->ifstmt.expr);
2994 type_check_ast(ctx, ast->ifstmt.statement);
2995 pop_scope(ctx);
2996 type_check_ast(ctx, ast->ifstmt.next);
2997 return NULL;
2998
2999 case MOJOSHADER_AST_STATEMENT_TYPEDEF:
3000 type_check_ast(ctx, ast->typedefstmt.type_info);
3001 type_check_ast(ctx, ast->typedefstmt.next);
3002 return NULL;
3003
3004 case MOJOSHADER_AST_STATEMENT_SWITCH:
3005 {
3006 ctx->switch_count++;
3007 MOJOSHADER_astSwitchCases *cases = ast->switchstmt.cases;
3008 // !!! FIXME: expr must be POD (no structs, arrays, etc!).
3009 datatype = type_check_ast(ctx, ast->switchstmt.expr);
3010 while (cases)
3011 {
3012 // !!! FIXME: case must be POD (no structs, arrays, etc!).
3013 datatype2 = type_check_ast(ctx, cases->expr);
3014 add_type_coercion(ctx, NULL, datatype,
3015 &cases->expr, datatype2);
3016 type_check_ast(ctx, cases->statement);
3017 cases = cases->next;
3018 } // while
3019 ctx->switch_count--;
3020 type_check_ast(ctx, ast->switchstmt.next);
3021 return NULL;
3022 } // case
3023
3024 case MOJOSHADER_AST_SWITCH_CASE:
3025 assert(0 && "Should be done by MOJOSHADER_AST_STATEMENT_SWITCH.");
3026 return NULL;
3027
3028 case MOJOSHADER_AST_STATEMENT_STRUCT:
3029 type_check_ast(ctx, ast->structstmt.struct_info);
3030 type_check_ast(ctx, ast->structstmt.next);
3031 return NULL;
3032
3033 case MOJOSHADER_AST_STATEMENT_VARDECL:
3034 type_check_ast(ctx, ast->vardeclstmt.declaration);
3035 type_check_ast(ctx, ast->vardeclstmt.next);
3036 return NULL;
3037
3038 case MOJOSHADER_AST_STATEMENT_BLOCK:
3039 push_scope(ctx); // new vars declared here live until '}'.
3040 type_check_ast(ctx, ast->blockstmt.statements);
3041 pop_scope(ctx);
3042 type_check_ast(ctx, ast->blockstmt.next);
3043 return NULL;
3044
3045 case MOJOSHADER_AST_STATEMENT_FOR:
3046 ctx->loop_count++;
3047 push_scope(ctx); // new scope for "for (int x = 0; ...)"
3048 type_check_ast(ctx, ast->forstmt.var_decl);
3049 type_check_ast(ctx, ast->forstmt.initializer);
3050 type_check_ast(ctx, ast->forstmt.looptest);
3051 type_check_ast(ctx, ast->forstmt.counter);
3052 type_check_ast(ctx, ast->forstmt.statement);
3053 pop_scope(ctx);
3054 ctx->loop_count--;
3055 type_check_ast(ctx, ast->forstmt.next);
3056 return NULL;
3057
3058 case MOJOSHADER_AST_STATEMENT_DO:
3059 ctx->loop_count++;
3060 // !!! FIXME: should there be a push_scope() here?
3061 type_check_ast(ctx, ast->dostmt.statement);
3062 push_scope(ctx); // new scope for "while ((int x = blah()) != 0)"
3063 type_check_ast(ctx, ast->dostmt.expr);
3064 pop_scope(ctx);
3065 ctx->loop_count--;
3066 type_check_ast(ctx, ast->dostmt.next);
3067 return NULL;
3068
3069 case MOJOSHADER_AST_STATEMENT_WHILE:
3070 ctx->loop_count++;
3071 push_scope(ctx); // new scope for "while ((int x = blah()) != 0)"
3072 type_check_ast(ctx, ast->whilestmt.expr);
3073 type_check_ast(ctx, ast->whilestmt.statement);
3074 pop_scope(ctx);
3075 ctx->loop_count--;
3076 type_check_ast(ctx, ast->whilestmt.next);
3077 return NULL;
3078
3079 case MOJOSHADER_AST_STATEMENT_RETURN:
3080 // !!! FIXME: type coercion to outer function's return type.
3081 // !!! FIXME: warn if unreachable statements follow?
3082 type_check_ast(ctx, ast->returnstmt.expr);
3083 type_check_ast(ctx, ast->returnstmt.next);
3084 return NULL;
3085
3086 case MOJOSHADER_AST_COMPUNIT_FUNCTION:
3087 assert(!ctx->is_func_scope);
3088
3089 // We have to tapdance here to make sure the function is in
3090 // the global scope, but it's parameters are pushed as variables
3091 // in the function's scope.
3092 datatype = type_check_ast(ctx, ast->funcunit.declaration);
3093 ast->funcunit.index = push_function(ctx,
3094 ast->funcunit.declaration->identifier,
3095 datatype, ast->funcunit.definition == NULL);
3096
3097 // not just a declaration, but a full function definition?
3098 if (ast->funcunit.definition != NULL)
3099 {
3100 assert(ctx->loop_count == 0);
3101 assert(ctx->switch_count == 0);
3102 ctx->is_func_scope = 1;
3103 ctx->var_index = 0; // reset this every function.
3104 push_scope(ctx); // so function params are in function scope.
3105 // repush the parameters before checking the actual function.
3106 MOJOSHADER_astFunctionParameters *param;
3107 for (param = ast->funcunit.declaration->params; param; param = param->next)
3108 push_variable(ctx, param->identifier, param->datatype);
3109 type_check_ast(ctx, ast->funcunit.definition);
3110 pop_scope(ctx);
3111 ctx->is_func_scope = 0;
3112 assert(ctx->loop_count == 0);
3113 assert(ctx->switch_count == 0);
3114 } // else
3115
3116 type_check_ast(ctx, ast->funcunit.next);
3117 return NULL;
3118
3119 case MOJOSHADER_AST_COMPUNIT_TYPEDEF:
3120 type_check_ast(ctx, ast->typedefunit.type_info);
3121 type_check_ast(ctx, ast->typedefunit.next);
3122 return NULL;
3123
3124 case MOJOSHADER_AST_COMPUNIT_STRUCT:
3125 type_check_ast(ctx, ast->structunit.struct_info);
3126 type_check_ast(ctx, ast->structunit.next);
3127 return NULL;
3128
3129 case MOJOSHADER_AST_COMPUNIT_VARIABLE:
3130 type_check_ast(ctx, ast->varunit.declaration);
3131 type_check_ast(ctx, ast->varunit.next);
3132 return NULL;
3133
3134 case MOJOSHADER_AST_SCALAR_OR_ARRAY:
3135 assert(0 && "Should be done by other AST nodes.");
3136 return NULL;
3137
3138 case MOJOSHADER_AST_TYPEDEF:
3139 {
3140 MOJOSHADER_astScalarOrArray *soa = ast->typdef.details;
3141 datatype = get_usertype(ctx, soa->identifier);
3142 if (datatype != NULL)
3143 {
3144 fail(ctx, "typedef already defined");
3145 ast->typdef.datatype = datatype;
3146 return datatype;
3147 } // if
3148
3149 datatype = build_datatype(ctx, ast->typdef.isconst,
3150 ast->typdef.datatype, soa);
3151 if (datatype == NULL)
3152 return NULL; // out of memory?
3153
3154 push_usertype(ctx, soa->identifier, datatype);
3155 ast->typdef.datatype = datatype;
3156 return ast->typdef.datatype;
3157 } // case
3158
3159 case MOJOSHADER_AST_FUNCTION_PARAMS:
3160 assert(0 && "Should be done by MOJOSHADER_AST_FUNCTION_SIGNATURE");
3161
3162 case MOJOSHADER_AST_FUNCTION_SIGNATURE:
3163 {
3164 MOJOSHADER_astFunctionParameters *param;
3165 const MOJOSHADER_astDataType *dtparams[64];
3166
3167 int i = 0;
3168 for (param = ast->funcsig.params; param; param = param->next)
3169 {
3170 assert(i <= STATICARRAYLEN(dtparams)); // laziness.
3171 sanitize_datatype(ctx, param->datatype);
3172 if (param->initializer != NULL)
3173 {
3174 datatype2 = type_check_ast(ctx, param->initializer);
3175 add_type_coercion(ctx, NULL, param->datatype,
3176 ¶m->initializer, datatype2);
3177 } // if
3178 dtparams[i] = param->datatype;
3179 i++;
3180 } // for
3181
3182 ast->funcsig.datatype = build_function_datatype(ctx,
3183 ast->funcsig.datatype,
3184 i, dtparams, 0);
3185 return ast->funcsig.datatype;
3186 } // case
3187
3188 case MOJOSHADER_AST_STRUCT_DECLARATION:
3189 {
3190 // !!! FIXME: We don't handle struct predeclaration at all right now
3191 // !!! FIXME: (neither does the grammar)...not only does that mean
3192 // !!! FIXME: you need to know the struct definition up front, but
3193 // !!! FIXME: you can't do "struct XXX *next;" for a self-referencing
3194 // !!! FIXME: linked list struct thing. This probably isn't a big
3195 // !!! FIXME: deal, as there aren't (CURRENTLY!) pointers in HLSL,
3196 // !!! FIXME: but you never know.
3197
3198 const MOJOSHADER_astStructMembers *mbrs;
3199
3200 // !!! FIXME: count this during parsing?
3201 int count = 0;
3202 mbrs = ast->structdecl.members;
3203 while (mbrs != NULL)
3204 {
3205 count++;
3206 mbrs = mbrs->next;
3207 } // while
3208
3209 // !!! FIXME: this is hacky.
3210 MOJOSHADER_astDataTypeStructMember *dtmbrs;
3211 void *ptr = Malloc(ctx, sizeof (*dtmbrs) * count);
3212 if (ptr == NULL)
3213 return NULL;
3214 if (!buffer_append(ctx->garbage, &ptr, sizeof (ptr)))
3215 {
3216 Free(ctx, ptr);
3217 return NULL;
3218 } // if
3219 dtmbrs = (MOJOSHADER_astDataTypeStructMember *) ptr;
3220
3221 ptr = Malloc(ctx, sizeof (MOJOSHADER_astDataType));
3222 if (ptr == NULL)
3223 return NULL;
3224 if (!buffer_append(ctx->garbage, &ptr, sizeof (ptr)))
3225 {
3226 Free(ctx, ptr);
3227 return NULL;
3228 } // if
3229 MOJOSHADER_astDataType *dt = (MOJOSHADER_astDataType *) ptr;
3230
3231 mbrs = ast->structdecl.members;
3232 int i;
3233 for (i = 0; i < count; i++)
3234 {
3235 // !!! FIXME: current grammar forbids const keyword on struct members!
3236 dtmbrs[i].datatype = build_datatype(ctx, 0, mbrs->datatype, mbrs->details);
3237 dtmbrs[i].identifier = mbrs->details->identifier; // cached!
3238 mbrs = mbrs->next;
3239 } // for
3240
3241 dt->structure.type = MOJOSHADER_AST_DATATYPE_STRUCT;
3242 dt->structure.members = dtmbrs;
3243 dt->structure.member_count = count;
3244 ast->structdecl.datatype = dt;
3245
3246 // !!! FIXME: this shouldn't push for anonymous structs: "struct { int x; } myvar;"
3247 // !!! FIXME: but right now, the grammar is wrong and requires a name for the struct.
3248 push_usertype(ctx, ast->structdecl.name, ast->structdecl.datatype);
3249 return ast->structdecl.datatype;
3250 } // case
3251
3252 case MOJOSHADER_AST_STRUCT_MEMBER:
3253 assert(0 && "Should be done by MOJOSHADER_AST_STRUCT_DECLARATION.");
3254 return NULL;
3255
3256 case MOJOSHADER_AST_VARIABLE_DECLARATION:
3257 {
3258 MOJOSHADER_astVariableDeclaration *decl = &ast->vardecl;
3259
3260 // this is true now, but we'll fill in ->datatype no matter what.
3261 assert((decl->datatype && !decl->anonymous_datatype) ||
3262 (!decl->datatype && decl->anonymous_datatype));
3263
3264 // An anonymous struct? That AST node does the heavy lifting.
3265 if (decl->anonymous_datatype != NULL)
3266 datatype = type_check_ast(ctx, decl->anonymous_datatype);
3267 else
3268 {
3269 datatype = build_datatype(ctx, (decl->attributes & MOJOSHADER_AST_VARATTR_CONST) != 0,
3270 decl->datatype, decl->details);
3271 } // else
3272
3273 while (decl != NULL)
3274 {
3275 decl->datatype = datatype;
3276 push_variable(ctx, decl->details->identifier, datatype);
3277 if (decl->initializer != NULL)
3278 {
3279 datatype2 = type_check_ast(ctx, decl->initializer);
3280 add_type_coercion(ctx, NULL, datatype, &decl->initializer, datatype2);
3281 } // if
3282
3283 type_check_ast(ctx, decl->annotations);
3284 type_check_ast(ctx, decl->lowlevel);
3285 decl = decl->next;
3286 } // while
3287
3288 return datatype;
3289 } // case
3290
3291 case MOJOSHADER_AST_ANNOTATION:
3292 {
3293 MOJOSHADER_astAnnotations *anno = &ast->annotations;
3294 while (anno)
3295 {
3296 type_check_ast(ctx, anno->initializer);
3297 anno = anno->next;
3298 } // while
3299 return NULL;
3300 } // case
3301
3302 case MOJOSHADER_AST_PACK_OFFSET:
3303 case MOJOSHADER_AST_VARIABLE_LOWLEVEL:
3304 return NULL; // no-op (for now, at least).
3305
3306 default:
3307 assert(0 && "unexpected type");
3308 } // switch
3309
3310 return NULL;
3311 } // type_check_ast
3312
3313
semantic_analysis(Context * ctx)3314 static inline void semantic_analysis(Context *ctx)
3315 {
3316 type_check_ast(ctx, ctx->ast);
3317 } // semantic_analysis
3318
3319 // !!! FIXME: isn't this a cut-and-paste of somewhere else?
strtoi64(const char * str,unsigned int len)3320 static inline int64 strtoi64(const char *str, unsigned int len)
3321 {
3322 int64 retval = 0;
3323 int64 mult = 1;
3324 int i = 0;
3325
3326 while ((len) && (*str == ' '))
3327 {
3328 str++;
3329 len--;
3330 } // while
3331
3332 if ((len) && (*str == '-'))
3333 {
3334 mult = -1;
3335 str++;
3336 len--;
3337 } // if
3338
3339 while (i < len)
3340 {
3341 const char ch = str[i];
3342 if ((ch < '0') || (ch > '9'))
3343 break;
3344 i++;
3345 } // while
3346
3347 while (--i >= 0)
3348 {
3349 const char ch = str[i];
3350 retval += ((int64) (ch - '0')) * mult;
3351 mult *= 10;
3352 } // while
3353
3354 return retval;
3355 } // strtoi64
3356
3357 // !!! FIXME: isn't this a cut-and-paste of somewhere else?
strtodouble(const char * _str,unsigned int len)3358 static inline double strtodouble(const char *_str, unsigned int len)
3359 {
3360 // !!! FIXME: laziness prevails.
3361 char *str = (char *) alloca(len+1);
3362 memcpy(str, _str, len);
3363 str[len] = '\0';
3364 return strtod(str, NULL);
3365 } // strtodouble
3366
3367 #if 0
3368 // This does not check correctness (POSITIONT993842 passes, etc).
3369 static int is_semantic(const Context *ctx, const char *token,
3370 const unsigned int tokenlen)
3371 {
3372 static const char *names[] = {
3373 "BINORMAL", "BLENDINDICES", "BLENDWEIGHT",
3374 "COLOR", "NORMAL", "POSITION", "POSITIONT", "PSIZE", "TANGENT",
3375 "TEXCOORD", "FOG", "TESSFACTOR", "TEXCOORD", "VFACE", "VPOS",
3376 "DEPTH", NULL
3377 };
3378
3379 // !!! FIXME: DX10 has SV_* ("System Value Semantics").
3380 const char **i;
3381 for (i = names; *i; i++)
3382 {
3383 const char *name = *i;
3384 const size_t namelen = strlen(name);
3385 if (tokenlen < namelen)
3386 continue;
3387 else if (memcmp(token, name, namelen) != 0)
3388 continue;
3389
3390 for (name += namelen; *name; name++)
3391 {
3392 if ((*name < '0') || (*name > '9'))
3393 break;
3394 } // for
3395
3396 if (*name == '\0')
3397 return 1;
3398 } // for
3399
3400 return 0;
3401 } // is_semantic
3402 #endif
3403
convert_to_lemon_token(Context * ctx,const char * token,unsigned int tokenlen,const Token tokenval)3404 static int convert_to_lemon_token(Context *ctx, const char *token,
3405 unsigned int tokenlen, const Token tokenval)
3406 {
3407 switch (tokenval)
3408 {
3409 case ((Token) ','): return TOKEN_HLSL_COMMA;
3410 case ((Token) '='): return TOKEN_HLSL_ASSIGN;
3411 case ((Token) TOKEN_ADDASSIGN): return TOKEN_HLSL_ADDASSIGN;
3412 case ((Token) TOKEN_SUBASSIGN): return TOKEN_HLSL_SUBASSIGN;
3413 case ((Token) TOKEN_MULTASSIGN): return TOKEN_HLSL_MULASSIGN;
3414 case ((Token) TOKEN_DIVASSIGN): return TOKEN_HLSL_DIVASSIGN;
3415 case ((Token) TOKEN_MODASSIGN): return TOKEN_HLSL_MODASSIGN;
3416 case ((Token) TOKEN_LSHIFTASSIGN): return TOKEN_HLSL_LSHIFTASSIGN;
3417 case ((Token) TOKEN_RSHIFTASSIGN): return TOKEN_HLSL_RSHIFTASSIGN;
3418 case ((Token) TOKEN_ANDASSIGN): return TOKEN_HLSL_ANDASSIGN;
3419 case ((Token) TOKEN_ORASSIGN): return TOKEN_HLSL_ORASSIGN;
3420 case ((Token) TOKEN_XORASSIGN): return TOKEN_HLSL_XORASSIGN;
3421 case ((Token) '?'): return TOKEN_HLSL_QUESTION;
3422 case ((Token) TOKEN_OROR): return TOKEN_HLSL_OROR;
3423 case ((Token) TOKEN_ANDAND): return TOKEN_HLSL_ANDAND;
3424 case ((Token) '|'): return TOKEN_HLSL_OR;
3425 case ((Token) '^'): return TOKEN_HLSL_XOR;
3426 case ((Token) '&'): return TOKEN_HLSL_AND;
3427 case ((Token) TOKEN_EQL): return TOKEN_HLSL_EQL;
3428 case ((Token) TOKEN_NEQ): return TOKEN_HLSL_NEQ;
3429 case ((Token) '<'): return TOKEN_HLSL_LT;
3430 case ((Token) TOKEN_LEQ): return TOKEN_HLSL_LEQ;
3431 case ((Token) '>'): return TOKEN_HLSL_GT;
3432 case ((Token) TOKEN_GEQ): return TOKEN_HLSL_GEQ;
3433 case ((Token) TOKEN_LSHIFT): return TOKEN_HLSL_LSHIFT;
3434 case ((Token) TOKEN_RSHIFT): return TOKEN_HLSL_RSHIFT;
3435 case ((Token) '+'): return TOKEN_HLSL_PLUS;
3436 case ((Token) '-'): return TOKEN_HLSL_MINUS;
3437 case ((Token) '*'): return TOKEN_HLSL_STAR;
3438 case ((Token) '/'): return TOKEN_HLSL_SLASH;
3439 case ((Token) '%'): return TOKEN_HLSL_PERCENT;
3440 case ((Token) '!'): return TOKEN_HLSL_EXCLAMATION;
3441 case ((Token) '~'): return TOKEN_HLSL_COMPLEMENT;
3442 case ((Token) TOKEN_DECREMENT): return TOKEN_HLSL_MINUSMINUS;
3443 case ((Token) TOKEN_INCREMENT): return TOKEN_HLSL_PLUSPLUS;
3444 case ((Token) '.'): return TOKEN_HLSL_DOT;
3445 case ((Token) '['): return TOKEN_HLSL_LBRACKET;
3446 case ((Token) ']'): return TOKEN_HLSL_RBRACKET;
3447 case ((Token) '('): return TOKEN_HLSL_LPAREN;
3448 case ((Token) ')'): return TOKEN_HLSL_RPAREN;
3449 case ((Token) TOKEN_INT_LITERAL): return TOKEN_HLSL_INT_CONSTANT;
3450 case ((Token) TOKEN_FLOAT_LITERAL): return TOKEN_HLSL_FLOAT_CONSTANT;
3451 case ((Token) TOKEN_STRING_LITERAL): return TOKEN_HLSL_STRING_LITERAL;
3452 case ((Token) ':'): return TOKEN_HLSL_COLON;
3453 case ((Token) ';'): return TOKEN_HLSL_SEMICOLON;
3454 case ((Token) '{'): return TOKEN_HLSL_LBRACE;
3455 case ((Token) '}'): return TOKEN_HLSL_RBRACE;
3456 //case ((Token) TOKEN_PP_PRAGMA): return TOKEN_HLSL_PRAGMA;
3457 //case ((Token) '\n'): return TOKEN_HLSL_NEWLINE;
3458
3459 case ((Token) TOKEN_IDENTIFIER):
3460 #define tokencmp(t) ((tokenlen == strlen(t)) && (memcmp(token, t, tokenlen) == 0))
3461 //case ((Token) ''): return TOKEN_HLSL_TYPECAST
3462 //if (tokencmp("")) return TOKEN_HLSL_TYPE_NAME
3463 //if (tokencmp("...")) return TOKEN_HLSL_ELIPSIS
3464 if (tokencmp("else")) return TOKEN_HLSL_ELSE;
3465 if (tokencmp("inline")) return TOKEN_HLSL_INLINE;
3466 if (tokencmp("void")) return TOKEN_HLSL_VOID;
3467 if (tokencmp("in")) return TOKEN_HLSL_IN;
3468 if (tokencmp("inout")) return TOKEN_HLSL_INOUT;
3469 if (tokencmp("out")) return TOKEN_HLSL_OUT;
3470 if (tokencmp("uniform")) return TOKEN_HLSL_UNIFORM;
3471 if (tokencmp("linear")) return TOKEN_HLSL_LINEAR;
3472 if (tokencmp("centroid")) return TOKEN_HLSL_CENTROID;
3473 if (tokencmp("nointerpolation")) return TOKEN_HLSL_NOINTERPOLATION;
3474 if (tokencmp("noperspective")) return TOKEN_HLSL_NOPERSPECTIVE;
3475 if (tokencmp("sample")) return TOKEN_HLSL_SAMPLE;
3476 if (tokencmp("struct")) return TOKEN_HLSL_STRUCT;
3477 if (tokencmp("typedef")) return TOKEN_HLSL_TYPEDEF;
3478 if (tokencmp("const")) return TOKEN_HLSL_CONST;
3479 if (tokencmp("packoffset")) return TOKEN_HLSL_PACKOFFSET;
3480 if (tokencmp("register")) return TOKEN_HLSL_REGISTER;
3481 if (tokencmp("extern")) return TOKEN_HLSL_EXTERN;
3482 if (tokencmp("shared")) return TOKEN_HLSL_SHARED;
3483 if (tokencmp("static")) return TOKEN_HLSL_STATIC;
3484 if (tokencmp("volatile")) return TOKEN_HLSL_VOLATILE;
3485 if (tokencmp("row_major")) return TOKEN_HLSL_ROWMAJOR;
3486 if (tokencmp("column_major")) return TOKEN_HLSL_COLUMNMAJOR;
3487 if (tokencmp("bool")) return TOKEN_HLSL_BOOL;
3488 if (tokencmp("int")) return TOKEN_HLSL_INT;
3489 if (tokencmp("uint")) return TOKEN_HLSL_UINT;
3490 if (tokencmp("half")) return TOKEN_HLSL_HALF;
3491 if (tokencmp("float")) return TOKEN_HLSL_FLOAT;
3492 if (tokencmp("double")) return TOKEN_HLSL_DOUBLE;
3493 if (tokencmp("string")) return TOKEN_HLSL_STRING;
3494 if (tokencmp("snorm")) return TOKEN_HLSL_SNORM;
3495 if (tokencmp("unorm")) return TOKEN_HLSL_UNORM;
3496 if (tokencmp("buffer")) return TOKEN_HLSL_BUFFER;
3497 if (tokencmp("vector")) return TOKEN_HLSL_VECTOR;
3498 if (tokencmp("matrix")) return TOKEN_HLSL_MATRIX;
3499 if (tokencmp("break")) return TOKEN_HLSL_BREAK;
3500 if (tokencmp("continue")) return TOKEN_HLSL_CONTINUE;
3501 if (tokencmp("discard")) return TOKEN_HLSL_DISCARD;
3502 if (tokencmp("return")) return TOKEN_HLSL_RETURN;
3503 if (tokencmp("while")) return TOKEN_HLSL_WHILE;
3504 if (tokencmp("for")) return TOKEN_HLSL_FOR;
3505 if (tokencmp("unroll")) return TOKEN_HLSL_UNROLL;
3506 if (tokencmp("loop")) return TOKEN_HLSL_LOOP;
3507 if (tokencmp("do")) return TOKEN_HLSL_DO;
3508 if (tokencmp("if")) return TOKEN_HLSL_IF;
3509 if (tokencmp("branch")) return TOKEN_HLSL_BRANCH;
3510 if (tokencmp("flatten")) return TOKEN_HLSL_FLATTEN;
3511 if (tokencmp("switch")) return TOKEN_HLSL_SWITCH;
3512 if (tokencmp("forcecase")) return TOKEN_HLSL_FORCECASE;
3513 if (tokencmp("call")) return TOKEN_HLSL_CALL;
3514 if (tokencmp("case")) return TOKEN_HLSL_CASE;
3515 if (tokencmp("default")) return TOKEN_HLSL_DEFAULT;
3516 if (tokencmp("sampler")) return TOKEN_HLSL_SAMPLER;
3517 if (tokencmp("sampler1D")) return TOKEN_HLSL_SAMPLER1D;
3518 if (tokencmp("sampler2D")) return TOKEN_HLSL_SAMPLER2D;
3519 if (tokencmp("sampler3D")) return TOKEN_HLSL_SAMPLER3D;
3520 if (tokencmp("samplerCUBE")) return TOKEN_HLSL_SAMPLERCUBE;
3521 if (tokencmp("sampler_state")) return TOKEN_HLSL_SAMPLER_STATE;
3522 if (tokencmp("SamplerState")) return TOKEN_HLSL_SAMPLERSTATE;
3523 if (tokencmp("true")) return TOKEN_HLSL_TRUE;
3524 if (tokencmp("false")) return TOKEN_HLSL_FALSE;
3525 if (tokencmp("SamplerComparisonState")) return TOKEN_HLSL_SAMPLERCOMPARISONSTATE;
3526 if (tokencmp("isolate")) return TOKEN_HLSL_ISOLATE;
3527 if (tokencmp("maxInstructionCount")) return TOKEN_HLSL_MAXINSTRUCTIONCOUNT;
3528 if (tokencmp("noExpressionOptimizations")) return TOKEN_HLSL_NOEXPRESSIONOPTIMIZATIONS;
3529 if (tokencmp("unused")) return TOKEN_HLSL_UNUSED;
3530 if (tokencmp("xps")) return TOKEN_HLSL_XPS;
3531 #undef tokencmp
3532
3533 // get a canonical copy of the string now, as we'll need it.
3534 token = stringcache_len(ctx->strcache, token, tokenlen);
3535 if (get_usertype(ctx, token) != NULL)
3536 return TOKEN_HLSL_USERTYPE;
3537 return TOKEN_HLSL_IDENTIFIER;
3538
3539 case TOKEN_EOI: return 0;
3540 default: assert(0 && "unexpected token from lexer\n"); return 0;
3541 } // switch
3542
3543 return 0;
3544 } // convert_to_lemon_token
3545
3546
3547 static void delete_ir(Context *ctx, void *_ir); // !!! FIXME: move this code around.
3548
destroy_context(Context * ctx)3549 static void destroy_context(Context *ctx)
3550 {
3551 if (ctx != NULL)
3552 {
3553 MOJOSHADER_free f = ((ctx->free != NULL) ? ctx->free : MOJOSHADER_internal_free);
3554 void *d = ctx->malloc_data;
3555 size_t i = 0;
3556
3557 // !!! FIXME: this is kinda hacky.
3558 const size_t count = buffer_size(ctx->garbage) / sizeof (void *);
3559 if (count > 0)
3560 {
3561 void **garbage = (void **) buffer_flatten(ctx->garbage);
3562 if (garbage != NULL)
3563 {
3564 for (i = 0; i < count; i++)
3565 f(garbage[i], d);
3566 f(garbage, d);
3567 } // if
3568 } // if
3569 buffer_destroy(ctx->garbage);
3570
3571 delete_compilation_unit(ctx, (MOJOSHADER_astCompilationUnit*)ctx->ast);
3572 destroy_symbolmap(ctx, &ctx->usertypes);
3573 destroy_symbolmap(ctx, &ctx->variables);
3574 stringcache_destroy(ctx->strcache);
3575 errorlist_destroy(ctx->errors);
3576 errorlist_destroy(ctx->warnings);
3577
3578 if (ctx->ir != NULL)
3579 {
3580 for (i = 0; i <= ctx->user_func_index; i++)
3581 delete_ir(ctx, ctx->ir[i]);
3582 f(ctx->ir, d);
3583 } // if
3584
3585 // !!! FIXME: more to clean up here, now.
3586
3587 f(ctx, d);
3588 } // if
3589 } // destroy_context
3590
build_context(MOJOSHADER_malloc m,MOJOSHADER_free f,void * d)3591 static Context *build_context(MOJOSHADER_malloc m, MOJOSHADER_free f, void *d)
3592 {
3593 if (!m) m = MOJOSHADER_internal_malloc;
3594 if (!f) f = MOJOSHADER_internal_free;
3595
3596 Context *ctx = (Context *) m(sizeof (Context), d);
3597 if (ctx == NULL)
3598 return NULL;
3599
3600 memset(ctx, '\0', sizeof (Context));
3601 ctx->malloc = m;
3602 ctx->free = f;
3603 ctx->malloc_data = d;
3604 //ctx->parse_phase = MOJOSHADER_PARSEPHASE_NOTSTARTED;
3605 create_symbolmap(ctx, &ctx->usertypes); // !!! FIXME: check for failure.
3606 create_symbolmap(ctx, &ctx->variables); // !!! FIXME: check for failure.
3607 ctx->strcache = stringcache_create(MallocBridge, FreeBridge, ctx); // !!! FIXME: check for failure.
3608 ctx->errors = errorlist_create(MallocBridge, FreeBridge, ctx); // !!! FIXME: check for failure.
3609 ctx->warnings = errorlist_create(MallocBridge, FreeBridge, ctx); // !!! FIXME: check for failure.
3610
3611 // !!! FIXME: this feels hacky.
3612 ctx->garbage = buffer_create(256*sizeof(void*),MallocBridge,FreeBridge,ctx); // !!! FIXME: check for failure.
3613
3614 ctx->dt_none.type = MOJOSHADER_AST_DATATYPE_NONE;
3615 ctx->dt_bool.type = MOJOSHADER_AST_DATATYPE_BOOL;
3616 ctx->dt_int.type = MOJOSHADER_AST_DATATYPE_INT;
3617 ctx->dt_uint.type = MOJOSHADER_AST_DATATYPE_UINT;
3618 ctx->dt_float.type = MOJOSHADER_AST_DATATYPE_FLOAT;
3619 ctx->dt_float_snorm.type = MOJOSHADER_AST_DATATYPE_FLOAT_SNORM;
3620 ctx->dt_float_unorm.type = MOJOSHADER_AST_DATATYPE_FLOAT_UNORM;
3621 ctx->dt_half.type = MOJOSHADER_AST_DATATYPE_HALF;
3622 ctx->dt_double.type = MOJOSHADER_AST_DATATYPE_DOUBLE;
3623 ctx->dt_string.type = MOJOSHADER_AST_DATATYPE_STRING;
3624 ctx->dt_sampler1d.type = MOJOSHADER_AST_DATATYPE_SAMPLER_1D;
3625 ctx->dt_sampler2d.type = MOJOSHADER_AST_DATATYPE_SAMPLER_2D;
3626 ctx->dt_sampler3d.type = MOJOSHADER_AST_DATATYPE_SAMPLER_3D;
3627 ctx->dt_samplercube.type = MOJOSHADER_AST_DATATYPE_SAMPLER_CUBE;
3628 ctx->dt_samplerstate.type = MOJOSHADER_AST_DATATYPE_SAMPLER_STATE;
3629 ctx->dt_samplercompstate.type = MOJOSHADER_AST_DATATYPE_SAMPLER_COMPARISON_STATE;
3630
3631 #define INIT_DT_BUFFER(t) \
3632 ctx->dt_buf_##t.type = MOJOSHADER_AST_DATATYPE_BUFFER; \
3633 ctx->dt_buf_##t.buffer.base = &ctx->dt_##t;
3634 INIT_DT_BUFFER(bool);
3635 INIT_DT_BUFFER(int);
3636 INIT_DT_BUFFER(uint);
3637 INIT_DT_BUFFER(half);
3638 INIT_DT_BUFFER(float);
3639 INIT_DT_BUFFER(double);
3640 INIT_DT_BUFFER(float_snorm);
3641 INIT_DT_BUFFER(float_unorm);
3642 #undef INIT_DT_BUFFER
3643
3644 return ctx;
3645 } // build_context
3646
3647
3648 // This macro salsa is kinda nasty, but it's the smallest, least error-prone
3649 // way I can find to do this well in C. :/
3650
3651 #define ADD_INTRINSIC(fn, ret, params) do { \
3652 push_function(ctx, fn, \
3653 build_function_datatype(ctx, ret, STATICARRAYLEN(params), params, 1), \
3654 0); \
3655 } while (0)
3656
3657 #define ADD_INTRINSIC_VECTOR(typestr, code) do { \
3658 const MOJOSHADER_astDataType *dt; \
3659 dt = get_usertype(ctx, typestr "1"); code; \
3660 dt = get_usertype(ctx, typestr "2"); code; \
3661 dt = get_usertype(ctx, typestr "3"); code; \
3662 dt = get_usertype(ctx, typestr "4"); code; \
3663 } while (0)
3664
3665 #define ADD_INTRINSIC_VECTOR_FLOAT(code) { \
3666 ADD_INTRINSIC_VECTOR("float", code); \
3667 ADD_INTRINSIC_VECTOR("half", code); \
3668 ADD_INTRINSIC_VECTOR("double", code); \
3669 }
3670 #define ADD_INTRINSIC_VECTOR_INT(code) { \
3671 ADD_INTRINSIC_VECTOR("int", code); \
3672 ADD_INTRINSIC_VECTOR("uint", code); \
3673 }
3674 #define ADD_INTRINSIC_VECTOR_BOOL(code) { \
3675 ADD_INTRINSIC_VECTOR("bool", code); \
3676 }
3677
3678 #define ADD_INTRINSIC_MATRIX(typestr, code) do { \
3679 const MOJOSHADER_astDataType *dt; \
3680 dt = get_usertype(ctx, typestr "1x1"); code; \
3681 dt = get_usertype(ctx, typestr "1x2"); code; \
3682 dt = get_usertype(ctx, typestr "1x3"); code; \
3683 dt = get_usertype(ctx, typestr "1x4"); code; \
3684 dt = get_usertype(ctx, typestr "2x1"); code; \
3685 dt = get_usertype(ctx, typestr "2x2"); code; \
3686 dt = get_usertype(ctx, typestr "2x3"); code; \
3687 dt = get_usertype(ctx, typestr "2x4"); code; \
3688 dt = get_usertype(ctx, typestr "3x1"); code; \
3689 dt = get_usertype(ctx, typestr "3x2"); code; \
3690 dt = get_usertype(ctx, typestr "3x3"); code; \
3691 dt = get_usertype(ctx, typestr "3x4"); code; \
3692 dt = get_usertype(ctx, typestr "4x1"); code; \
3693 dt = get_usertype(ctx, typestr "4x2"); code; \
3694 dt = get_usertype(ctx, typestr "4x3"); code; \
3695 dt = get_usertype(ctx, typestr "4x4"); code; \
3696 } while (0)
3697
3698 #define ADD_INTRINSIC_MATRIX_FLOAT(code) { \
3699 ADD_INTRINSIC_MATRIX("float", code); \
3700 ADD_INTRINSIC_MATRIX("half", code); \
3701 ADD_INTRINSIC_MATRIX("double", code); \
3702 }
3703 #define ADD_INTRINSIC_MATRIX_INT(code) { \
3704 ADD_INTRINSIC_MATRIX("int", code); \
3705 ADD_INTRINSIC_MATRIX("uint", code); \
3706 }
3707 #define ADD_INTRINSIC_MATRIX_BOOL(code) { \
3708 ADD_INTRINSIC_MATRIX("bool", code); \
3709 }
3710
3711 #define ADD_INTRINSIC_ANY(scalar, typestr, code) do { \
3712 { const MOJOSHADER_astDataType *dt = scalar; code; } \
3713 ADD_INTRINSIC_VECTOR(typestr, code); \
3714 ADD_INTRINSIC_MATRIX(typestr, code); \
3715 } while (0)
3716
3717 #define ADD_INTRINSIC_ANY_FLOAT(code) do { \
3718 ADD_INTRINSIC_ANY(&ctx->dt_double, "double", code); \
3719 ADD_INTRINSIC_ANY(&ctx->dt_half, "half", code); \
3720 ADD_INTRINSIC_ANY(&ctx->dt_float, "float", code); \
3721 } while (0)
3722 #define ADD_INTRINSIC_ANY_INT(code) do { \
3723 ADD_INTRINSIC_ANY(&ctx->dt_uint, "uint", code); \
3724 ADD_INTRINSIC_ANY(&ctx->dt_int, "int", code); \
3725 } while (0)
3726
3727 #define ADD_INTRINSIC_ANY_BOOL(code) ADD_INTRINSIC_ANY(&ctx->dt_bool, "bool", code)
3728
add_intrinsic1(Context * ctx,const char * fn,const MOJOSHADER_astDataType * ret,const MOJOSHADER_astDataType * dt1)3729 static void add_intrinsic1(Context *ctx, const char *fn,
3730 const MOJOSHADER_astDataType *ret,
3731 const MOJOSHADER_astDataType *dt1)
3732 {
3733 const MOJOSHADER_astDataType *params[] = { dt1 };
3734 ADD_INTRINSIC(fn, ret, params);
3735 } // add_intrinsic1
3736
add_intrinsic2(Context * ctx,const char * fn,const MOJOSHADER_astDataType * ret,const MOJOSHADER_astDataType * dt1,const MOJOSHADER_astDataType * dt2)3737 static void add_intrinsic2(Context *ctx, const char *fn,
3738 const MOJOSHADER_astDataType *ret,
3739 const MOJOSHADER_astDataType *dt1,
3740 const MOJOSHADER_astDataType *dt2)
3741 {
3742 const MOJOSHADER_astDataType *params[] = { dt1, dt2 };
3743 ADD_INTRINSIC(fn, ret, params);
3744 } // add_intrinsic2
3745
add_intrinsic3(Context * ctx,const char * fn,const MOJOSHADER_astDataType * ret,const MOJOSHADER_astDataType * dt1,const MOJOSHADER_astDataType * dt2,const MOJOSHADER_astDataType * dt3)3746 static void add_intrinsic3(Context *ctx, const char *fn,
3747 const MOJOSHADER_astDataType *ret,
3748 const MOJOSHADER_astDataType *dt1,
3749 const MOJOSHADER_astDataType *dt2,
3750 const MOJOSHADER_astDataType *dt3)
3751 {
3752 const MOJOSHADER_astDataType *params[] = { dt1, dt2, dt3 };
3753 ADD_INTRINSIC(fn, ret, params);
3754 } // add_intrinsic3
3755
add_intrinsic4(Context * ctx,const char * fn,const MOJOSHADER_astDataType * ret,const MOJOSHADER_astDataType * dt1,const MOJOSHADER_astDataType * dt2,const MOJOSHADER_astDataType * dt3,const MOJOSHADER_astDataType * dt4)3756 static void add_intrinsic4(Context *ctx, const char *fn,
3757 const MOJOSHADER_astDataType *ret,
3758 const MOJOSHADER_astDataType *dt1,
3759 const MOJOSHADER_astDataType *dt2,
3760 const MOJOSHADER_astDataType *dt3,
3761 const MOJOSHADER_astDataType *dt4)
3762 {
3763 const MOJOSHADER_astDataType *params[] = { dt1, dt2, dt3, dt4 };
3764 ADD_INTRINSIC(fn, ret, params);
3765 } // add_intrinsic4
3766
3767 // PLEASE NOTE that add_intrinsic*() is called AFTER the various
3768 // ADD_INTRINSIC_* macros, even though these look like functions that
3769 // should be called first. They might be called multiple times by the macro.
3770 // The variable "dt" is defined by the macro for use by your code.
add_intrinsic_SAME1_ANYf(Context * ctx,const char * fn)3771 static void add_intrinsic_SAME1_ANYf(Context *ctx, const char *fn)
3772 {
3773 ADD_INTRINSIC_ANY_FLOAT(add_intrinsic1(ctx, fn, dt, dt));
3774 } // add_intrinsic_SAME1_ANYf
3775
add_intrinsic_SAME1_ANYfi(Context * ctx,const char * fn)3776 static void add_intrinsic_SAME1_ANYfi(Context *ctx, const char *fn)
3777 {
3778 ADD_INTRINSIC_ANY_INT(add_intrinsic1(ctx, fn, dt, dt));
3779 add_intrinsic_SAME1_ANYf(ctx, fn);
3780 } // add_intrinsic_SAME1_ANYfi
3781
add_intrinsic_BOOL_ANYf(Context * ctx,const char * fn)3782 static void add_intrinsic_BOOL_ANYf(Context *ctx, const char *fn)
3783 {
3784 ADD_INTRINSIC_ANY_FLOAT(add_intrinsic1(ctx, fn, &ctx->dt_bool, dt));
3785 } // add_intrinsic_BOOL_ANYf
3786
add_intrinsic_BOOL_ANYfib(Context * ctx,const char * fn)3787 static void add_intrinsic_BOOL_ANYfib(Context *ctx, const char *fn)
3788 {
3789 ADD_INTRINSIC_ANY_BOOL(add_intrinsic1(ctx, fn, &ctx->dt_bool, dt));
3790 ADD_INTRINSIC_ANY_INT(add_intrinsic1(ctx, fn, &ctx->dt_bool, dt));
3791 add_intrinsic_BOOL_ANYf(ctx, fn);
3792 } // add_intrinsic_BOOL_ANYfib
3793
add_intrinsic_SAME1_ANYf_SAME1(Context * ctx,const char * fn)3794 static void add_intrinsic_SAME1_ANYf_SAME1(Context *ctx, const char *fn)
3795 {
3796 ADD_INTRINSIC_ANY_FLOAT(add_intrinsic2(ctx, fn, dt, dt, dt));
3797 } // add_intrinsic_SAME1_ANYf_SAME1
3798
add_intrinsic_SAME1_ANYfi_SAME1(Context * ctx,const char * fn)3799 static void add_intrinsic_SAME1_ANYfi_SAME1(Context *ctx, const char *fn)
3800 {
3801 ADD_INTRINSIC_ANY_INT(add_intrinsic2(ctx, fn, dt, dt, dt));
3802 add_intrinsic_SAME1_ANYf_SAME1(ctx, fn);
3803 } // add_intrinsic_SAME1_ANYfi_SAME1
3804
add_intrinsic_SAME1_ANYf_SAME1_SAME1(Context * ctx,const char * fn)3805 static void add_intrinsic_SAME1_ANYf_SAME1_SAME1(Context *ctx, const char *fn)
3806 {
3807 ADD_INTRINSIC_ANY_FLOAT(add_intrinsic3(ctx, fn, dt, dt, dt, dt));
3808 } // add_intrinsic_SAME1_ANYf_SAME1_SAME1
3809
add_intrinsic_SAME1_ANYfi_SAME1_SAME1(Context * ctx,const char * fn)3810 static void add_intrinsic_SAME1_ANYfi_SAME1_SAME1(Context *ctx, const char *fn)
3811 {
3812 ADD_INTRINSIC_ANY_INT(add_intrinsic3(ctx, fn, dt, dt, dt, dt));
3813 add_intrinsic_SAME1_ANYf_SAME1_SAME1(ctx, fn);
3814 } // add_intrinsic_SAME1_ANYfi_SAME1_SAME1
3815
add_intrinsic_SAME1_Mfib(Context * ctx,const char * fn)3816 static void add_intrinsic_SAME1_Mfib(Context *ctx, const char *fn)
3817 {
3818 ADD_INTRINSIC_MATRIX_BOOL(add_intrinsic1(ctx, fn, dt, dt));
3819 ADD_INTRINSIC_MATRIX_INT(add_intrinsic1(ctx, fn, dt, dt));
3820 ADD_INTRINSIC_MATRIX_FLOAT(add_intrinsic1(ctx, fn, dt, dt));
3821 } // add_intrinsic_SAME1_Mfib
3822
add_intrinsic_SAME1_Vf(Context * ctx,const char * fn)3823 static void add_intrinsic_SAME1_Vf(Context *ctx, const char *fn)
3824 {
3825 ADD_INTRINSIC_VECTOR_FLOAT(add_intrinsic1(ctx, fn, dt, dt));
3826 } // add_intrinsic_SAME1_Vf
3827
add_intrinsic_SAME1_Vf_SAME1_SAME1(Context * ctx,const char * fn)3828 static void add_intrinsic_SAME1_Vf_SAME1_SAME1(Context *ctx, const char *fn)
3829 {
3830 ADD_INTRINSIC_VECTOR_FLOAT(add_intrinsic3(ctx, fn, dt, dt, dt, dt));
3831 } // add_intrinsic_SAME1_Vf_SAME1_SAME1
3832
add_intrinsic_SAME1_Vf_SAME1_f(Context * ctx,const char * fn)3833 static void add_intrinsic_SAME1_Vf_SAME1_f(Context *ctx, const char *fn)
3834 {
3835 ADD_INTRINSIC_VECTOR_FLOAT(add_intrinsic3(ctx, fn, dt, dt, dt, dt->user.details->vector.base));
3836 } // add_intrinsic_SAME1_Vf_SAME1_f
3837
add_intrinsic_VOID_ANYf(Context * ctx,const char * fn)3838 static void add_intrinsic_VOID_ANYf(Context *ctx, const char *fn)
3839 {
3840 ADD_INTRINSIC_ANY_FLOAT(add_intrinsic1(ctx, fn, NULL, dt));
3841 } // add_intrinsic_VOID_ANYf
3842
add_intrinsic_VOID_ANYf_SAME1_SAME1(Context * ctx,const char * fn)3843 static void add_intrinsic_VOID_ANYf_SAME1_SAME1(Context *ctx, const char *fn)
3844 {
3845 ADD_INTRINSIC_ANY_FLOAT(add_intrinsic3(ctx, fn, NULL, dt, dt, dt));
3846 } // add_intrinsic_VOID_ANYf_SAME1_SAME1
3847
add_intrinsic_f_SQUAREMATRIXf(Context * ctx,const char * fn)3848 static void add_intrinsic_f_SQUAREMATRIXf(Context *ctx, const char *fn)
3849 {
3850 add_intrinsic1(ctx, fn, &ctx->dt_float, get_usertype(ctx, "float1x1"));
3851 add_intrinsic1(ctx, fn, &ctx->dt_float, get_usertype(ctx, "float2x2"));
3852 add_intrinsic1(ctx, fn, &ctx->dt_float, get_usertype(ctx, "float3x3"));
3853 add_intrinsic1(ctx, fn, &ctx->dt_float, get_usertype(ctx, "float4x4"));
3854 } // add_intrinsic_f_SQUAREMATRIXf
3855
add_intrinsic_f_Vf(Context * ctx,const char * fn)3856 static void add_intrinsic_f_Vf(Context *ctx, const char *fn)
3857 {
3858 ADD_INTRINSIC_VECTOR_FLOAT(add_intrinsic1(ctx, fn, dt->user.details->vector.base, dt));
3859 } // add_intrinsic_f_Vf
3860
add_intrinsic_fi_Vfi_SAME1(Context * ctx,const char * fn)3861 static void add_intrinsic_fi_Vfi_SAME1(Context *ctx, const char *fn)
3862 {
3863 ADD_INTRINSIC_VECTOR_INT(add_intrinsic2(ctx, fn, dt->user.details->vector.base, dt, dt));
3864 ADD_INTRINSIC_VECTOR_FLOAT(add_intrinsic2(ctx, fn, dt->user.details->vector.base, dt, dt));
3865 } // add_intrinsic_fi_Vfi_SAME1
3866
add_intrinsic_f_Vf_SAME1(Context * ctx,const char * fn)3867 static void add_intrinsic_f_Vf_SAME1(Context *ctx, const char *fn)
3868 {
3869 ADD_INTRINSIC_VECTOR_FLOAT(add_intrinsic2(ctx, fn, dt->user.details->vector.base, dt, dt));
3870 } // add_intrinsic_f_Vf_SAME1
3871
add_intrinsic_3f_3f_3f(Context * ctx,const char * fn)3872 static void add_intrinsic_3f_3f_3f(Context *ctx, const char *fn)
3873 {
3874 const MOJOSHADER_astDataType *dt = get_usertype(ctx, "float3");
3875 add_intrinsic2(ctx, fn, dt, dt, dt);
3876 } // add_intrinsic_3f_3f_3f
3877
add_intrinsic_4f_f_f_f(Context * ctx,const char * fn)3878 static void add_intrinsic_4f_f_f_f(Context *ctx, const char *fn)
3879 {
3880 const MOJOSHADER_astDataType *f4 = get_usertype(ctx, "float4");
3881 const MOJOSHADER_astDataType *f = &ctx->dt_float;
3882 add_intrinsic3(ctx, fn, f4, f, f, f);
3883 } // add_intrinsic_4f_f_f_f
3884
add_intrinsic_4f_s1_4f(Context * ctx,const char * fn)3885 static void add_intrinsic_4f_s1_4f(Context *ctx, const char *fn)
3886 {
3887 const MOJOSHADER_astDataType *dt = get_usertype(ctx, "float4");
3888 add_intrinsic2(ctx, fn, dt, &ctx->dt_sampler1d, dt);
3889 } // add_intrinsic_4f_s1_4f
3890
add_intrinsic_4f_s1_f(Context * ctx,const char * fn)3891 static void add_intrinsic_4f_s1_f(Context *ctx, const char *fn)
3892 {
3893 const MOJOSHADER_astDataType *dt = get_usertype(ctx, "float4");
3894 add_intrinsic2(ctx, fn, dt, &ctx->dt_sampler1d, &ctx->dt_float);
3895 } // add_intrinsic_4f_s1_f
3896
add_intrinsic_4f_s1_f_f_f(Context * ctx,const char * fn)3897 static void add_intrinsic_4f_s1_f_f_f(Context *ctx, const char *fn)
3898 {
3899 const MOJOSHADER_astDataType *dt = get_usertype(ctx, "float4");
3900 const MOJOSHADER_astDataType *f = &ctx->dt_float;
3901 add_intrinsic4(ctx, fn, dt, &ctx->dt_sampler1d, f, f, f);
3902 } // add_intrinsic_4f_s1_f_f_f
3903
add_intrinsic_4f_s2_2f(Context * ctx,const char * fn)3904 static void add_intrinsic_4f_s2_2f(Context *ctx, const char *fn)
3905 {
3906 const MOJOSHADER_astDataType *f4 = get_usertype(ctx, "float4");
3907 const MOJOSHADER_astDataType *f2 = get_usertype(ctx, "float2");
3908 add_intrinsic2(ctx, fn, f4, &ctx->dt_sampler2d, f2);
3909 } // add_intrinsic_4f_s2_2f
3910
add_intrinsic_4f_s2_2f_2f_2f(Context * ctx,const char * fn)3911 static void add_intrinsic_4f_s2_2f_2f_2f(Context *ctx, const char *fn)
3912 {
3913 const MOJOSHADER_astDataType *f4 = get_usertype(ctx, "float4");
3914 const MOJOSHADER_astDataType *f2 = get_usertype(ctx, "float2");
3915 add_intrinsic4(ctx, fn, f4, &ctx->dt_sampler2d, f2, f2, f2);
3916 } // add_intrinsic_4f_s2_2f_2f_2f
3917
add_intrinsic_4f_s2_4f(Context * ctx,const char * fn)3918 static void add_intrinsic_4f_s2_4f(Context *ctx, const char *fn)
3919 {
3920 const MOJOSHADER_astDataType *f4 = get_usertype(ctx, "float4");
3921 add_intrinsic2(ctx, fn, f4, &ctx->dt_sampler2d, f4);
3922 } // add_intrinsic_4f_s2_4f
3923
add_intrinsic_4f_s3_3f(Context * ctx,const char * fn)3924 static void add_intrinsic_4f_s3_3f(Context *ctx, const char *fn)
3925 {
3926 const MOJOSHADER_astDataType *f4 = get_usertype(ctx, "float4");
3927 const MOJOSHADER_astDataType *f3 = get_usertype(ctx, "float3");
3928 add_intrinsic2(ctx, fn, f4, &ctx->dt_sampler3d, f3);
3929 } // add_intrinsic_4f_s3_3f
3930
add_intrinsic_4f_s3_3f_3f_3f(Context * ctx,const char * fn)3931 static void add_intrinsic_4f_s3_3f_3f_3f(Context *ctx, const char *fn)
3932 {
3933 const MOJOSHADER_astDataType *f4 = get_usertype(ctx, "float4");
3934 const MOJOSHADER_astDataType *f3 = get_usertype(ctx, "float3");
3935 add_intrinsic4(ctx, fn, f4, &ctx->dt_sampler3d, f3, f3, f3);
3936 } // add_intrinsic_4f_s3_3f_3f_3f
3937
add_intrinsic_4f_s3_4f(Context * ctx,const char * fn)3938 static void add_intrinsic_4f_s3_4f(Context *ctx, const char *fn)
3939 {
3940 const MOJOSHADER_astDataType *f4 = get_usertype(ctx, "float4");
3941 add_intrinsic2(ctx, fn, f4, &ctx->dt_sampler3d, f4);
3942 } // add_intrinsic_4f_s3_4f
3943
add_intrinsic_4f_sc_3f(Context * ctx,const char * fn)3944 static void add_intrinsic_4f_sc_3f(Context *ctx, const char *fn)
3945 {
3946 const MOJOSHADER_astDataType *f4 = get_usertype(ctx, "float4");
3947 const MOJOSHADER_astDataType *f3 = get_usertype(ctx, "float3");
3948 add_intrinsic2(ctx, fn, f4, &ctx->dt_samplercube, f3);
3949 } // add_intrinsic_4f_sc_3f
3950
add_intrinsic_4f_sc_3f_3f_3f(Context * ctx,const char * fn)3951 static void add_intrinsic_4f_sc_3f_3f_3f(Context *ctx, const char *fn)
3952 {
3953 const MOJOSHADER_astDataType *f4 = get_usertype(ctx, "float4");
3954 const MOJOSHADER_astDataType *f3 = get_usertype(ctx, "float3");
3955 add_intrinsic4(ctx, fn, f4, &ctx->dt_samplercube, f3, f3, f3);
3956 } // add_intrinsic_4f_sc_3f_3f_3f
3957
add_intrinsic_4f_sc_4f(Context * ctx,const char * fn)3958 static void add_intrinsic_4f_sc_4f(Context *ctx, const char *fn)
3959 {
3960 const MOJOSHADER_astDataType *f4 = get_usertype(ctx, "float4");
3961 add_intrinsic2(ctx, fn, f4, &ctx->dt_samplercube, f4);
3962 } // add_intrinsic_4f_sc_4f
3963
add_intrinsic_4i_4f(Context * ctx,const char * fn)3964 static void add_intrinsic_4i_4f(Context *ctx, const char *fn)
3965 {
3966 const MOJOSHADER_astDataType *i4 = get_usertype(ctx, "int4");
3967 const MOJOSHADER_astDataType *f4 = get_usertype(ctx, "float4");
3968 add_intrinsic1(ctx, fn, i4, f4);
3969 } // add_intrinsic_4i_4f
3970
add_intrinsic_mul(Context * ctx,const char * fn)3971 static void add_intrinsic_mul(Context *ctx, const char *fn)
3972 {
3973 // mul() is nasty, since there's a bunch of overloads that aren't just
3974 // related to vector size.
3975 // !!! FIXME: needs half, double, uint...
3976 const MOJOSHADER_astDataType *dtf = &ctx->dt_float;
3977 const MOJOSHADER_astDataType *dti = &ctx->dt_int;
3978 const MOJOSHADER_astDataType *f1 = get_usertype(ctx, "float1");
3979 const MOJOSHADER_astDataType *f2 = get_usertype(ctx, "float2");
3980 const MOJOSHADER_astDataType *f3 = get_usertype(ctx, "float3");
3981 const MOJOSHADER_astDataType *f4 = get_usertype(ctx, "float4");
3982 const MOJOSHADER_astDataType *i1 = get_usertype(ctx, "int1");
3983 const MOJOSHADER_astDataType *i2 = get_usertype(ctx, "int2");
3984 const MOJOSHADER_astDataType *i3 = get_usertype(ctx, "int3");
3985 const MOJOSHADER_astDataType *i4 = get_usertype(ctx, "int4");
3986 const MOJOSHADER_astDataType *f1x1 = get_usertype(ctx, "float1x1");
3987 const MOJOSHADER_astDataType *f1x2 = get_usertype(ctx, "float1x2");
3988 const MOJOSHADER_astDataType *f1x3 = get_usertype(ctx, "float1x3");
3989 const MOJOSHADER_astDataType *f1x4 = get_usertype(ctx, "float1x4");
3990 const MOJOSHADER_astDataType *f2x1 = get_usertype(ctx, "float2x1");
3991 const MOJOSHADER_astDataType *f2x2 = get_usertype(ctx, "float2x2");
3992 const MOJOSHADER_astDataType *f2x3 = get_usertype(ctx, "float2x3");
3993 const MOJOSHADER_astDataType *f2x4 = get_usertype(ctx, "float2x4");
3994 const MOJOSHADER_astDataType *f3x1 = get_usertype(ctx, "float3x1");
3995 const MOJOSHADER_astDataType *f3x2 = get_usertype(ctx, "float3x2");
3996 const MOJOSHADER_astDataType *f3x3 = get_usertype(ctx, "float3x3");
3997 const MOJOSHADER_astDataType *f3x4 = get_usertype(ctx, "float3x4");
3998 const MOJOSHADER_astDataType *f4x1 = get_usertype(ctx, "float4x1");
3999 const MOJOSHADER_astDataType *f4x2 = get_usertype(ctx, "float4x2");
4000 const MOJOSHADER_astDataType *f4x3 = get_usertype(ctx, "float4x3");
4001 const MOJOSHADER_astDataType *f4x4 = get_usertype(ctx, "float4x4");
4002 const MOJOSHADER_astDataType *i1x1 = get_usertype(ctx, "int1x1");
4003 const MOJOSHADER_astDataType *i1x2 = get_usertype(ctx, "int1x2");
4004 const MOJOSHADER_astDataType *i1x3 = get_usertype(ctx, "int1x3");
4005 const MOJOSHADER_astDataType *i1x4 = get_usertype(ctx, "int1x4");
4006 const MOJOSHADER_astDataType *i2x1 = get_usertype(ctx, "int2x1");
4007 const MOJOSHADER_astDataType *i2x2 = get_usertype(ctx, "int2x2");
4008 const MOJOSHADER_astDataType *i2x3 = get_usertype(ctx, "int2x3");
4009 const MOJOSHADER_astDataType *i2x4 = get_usertype(ctx, "int2x4");
4010 const MOJOSHADER_astDataType *i3x1 = get_usertype(ctx, "int3x1");
4011 const MOJOSHADER_astDataType *i3x2 = get_usertype(ctx, "int3x2");
4012 const MOJOSHADER_astDataType *i3x3 = get_usertype(ctx, "int3x3");
4013 const MOJOSHADER_astDataType *i3x4 = get_usertype(ctx, "int3x4");
4014 const MOJOSHADER_astDataType *i4x1 = get_usertype(ctx, "int4x1");
4015 const MOJOSHADER_astDataType *i4x2 = get_usertype(ctx, "int4x2");
4016 const MOJOSHADER_astDataType *i4x3 = get_usertype(ctx, "int4x3");
4017 const MOJOSHADER_astDataType *i4x4 = get_usertype(ctx, "int4x4");
4018
4019 // scalar * scalar
4020 add_intrinsic2(ctx, fn, dti, dti, dti);
4021 add_intrinsic2(ctx, fn, dtf, dtf, dtf);
4022
4023 // scalar * vector
4024 ADD_INTRINSIC_VECTOR_INT(add_intrinsic2(ctx, fn, dt, dti, dt));
4025 ADD_INTRINSIC_VECTOR_FLOAT(add_intrinsic2(ctx, fn, dt, dtf, dt));
4026
4027 // scalar * matrix
4028 ADD_INTRINSIC_MATRIX_INT(add_intrinsic2(ctx, fn, dt, dti, dt));
4029 ADD_INTRINSIC_MATRIX_FLOAT(add_intrinsic2(ctx, fn, dt, dtf, dt));
4030
4031 // vector * scalar
4032 ADD_INTRINSIC_VECTOR_INT(add_intrinsic2(ctx, fn, dt, dt, dti));
4033 ADD_INTRINSIC_VECTOR_FLOAT(add_intrinsic2(ctx, fn, dt, dt, dtf));
4034
4035 // vector * vector
4036 ADD_INTRINSIC_VECTOR_INT(add_intrinsic2(ctx, fn, dti, dt, dt));
4037 ADD_INTRINSIC_VECTOR_FLOAT(add_intrinsic2(ctx, fn, dtf, dt, dt));
4038
4039 // vector * matrix
4040 add_intrinsic2(ctx, fn, i1, i1, i1x1);
4041 add_intrinsic2(ctx, fn, i2, i1, i1x2);
4042 add_intrinsic2(ctx, fn, i3, i1, i1x3);
4043 add_intrinsic2(ctx, fn, i4, i1, i1x4);
4044 add_intrinsic2(ctx, fn, i1, i2, i2x1);
4045 add_intrinsic2(ctx, fn, i2, i2, i2x2);
4046 add_intrinsic2(ctx, fn, i3, i2, i2x3);
4047 add_intrinsic2(ctx, fn, i4, i2, i2x4);
4048 add_intrinsic2(ctx, fn, i1, i3, i3x1);
4049 add_intrinsic2(ctx, fn, i2, i3, i3x2);
4050 add_intrinsic2(ctx, fn, i3, i3, i3x3);
4051 add_intrinsic2(ctx, fn, i4, i3, i3x4);
4052 add_intrinsic2(ctx, fn, i1, i4, i4x1);
4053 add_intrinsic2(ctx, fn, i2, i4, i4x2);
4054 add_intrinsic2(ctx, fn, i3, i4, i4x3);
4055 add_intrinsic2(ctx, fn, i4, i4, i4x4);
4056 add_intrinsic2(ctx, fn, f1, f1, f1x1);
4057 add_intrinsic2(ctx, fn, f2, f1, f1x2);
4058 add_intrinsic2(ctx, fn, f3, f1, f1x3);
4059 add_intrinsic2(ctx, fn, f4, f1, f1x4);
4060 add_intrinsic2(ctx, fn, f1, f2, f2x1);
4061 add_intrinsic2(ctx, fn, f2, f2, f2x2);
4062 add_intrinsic2(ctx, fn, f3, f2, f2x3);
4063 add_intrinsic2(ctx, fn, f4, f2, f2x4);
4064 add_intrinsic2(ctx, fn, f1, f3, f3x1);
4065 add_intrinsic2(ctx, fn, f2, f3, f3x2);
4066 add_intrinsic2(ctx, fn, f3, f3, f3x3);
4067 add_intrinsic2(ctx, fn, f4, f3, f3x4);
4068 add_intrinsic2(ctx, fn, f1, f4, f4x1);
4069 add_intrinsic2(ctx, fn, f2, f4, f4x2);
4070 add_intrinsic2(ctx, fn, f3, f4, f4x3);
4071 add_intrinsic2(ctx, fn, f4, f4, f4x4);
4072
4073 // matrix * scalar
4074 ADD_INTRINSIC_MATRIX_INT(add_intrinsic2(ctx, fn, dt, dt, dti));
4075 ADD_INTRINSIC_MATRIX_FLOAT(add_intrinsic2(ctx, fn, dt, dt, dtf));
4076
4077 // matrix * vector
4078 add_intrinsic2(ctx, fn, i1, i1x1, i1);
4079 add_intrinsic2(ctx, fn, i1, i1x2, i2);
4080 add_intrinsic2(ctx, fn, i1, i1x3, i3);
4081 add_intrinsic2(ctx, fn, i1, i1x4, i4);
4082 add_intrinsic2(ctx, fn, i2, i2x1, i1);
4083 add_intrinsic2(ctx, fn, i2, i2x2, i2);
4084 add_intrinsic2(ctx, fn, i2, i2x3, i3);
4085 add_intrinsic2(ctx, fn, i2, i2x4, i4);
4086 add_intrinsic2(ctx, fn, i3, i3x1, i1);
4087 add_intrinsic2(ctx, fn, i3, i3x2, i2);
4088 add_intrinsic2(ctx, fn, i3, i3x3, i3);
4089 add_intrinsic2(ctx, fn, i3, i3x4, i4);
4090 add_intrinsic2(ctx, fn, i4, i4x1, i1);
4091 add_intrinsic2(ctx, fn, i4, i4x2, i2);
4092 add_intrinsic2(ctx, fn, i4, i4x3, i3);
4093 add_intrinsic2(ctx, fn, i4, i4x4, i4);
4094 add_intrinsic2(ctx, fn, f1, f1x1, f1);
4095 add_intrinsic2(ctx, fn, f1, f1x2, f2);
4096 add_intrinsic2(ctx, fn, f1, f1x3, f3);
4097 add_intrinsic2(ctx, fn, f1, f1x4, f4);
4098 add_intrinsic2(ctx, fn, f2, f2x1, f1);
4099 add_intrinsic2(ctx, fn, f2, f2x2, f2);
4100 add_intrinsic2(ctx, fn, f2, f2x3, f3);
4101 add_intrinsic2(ctx, fn, f2, f2x4, f4);
4102 add_intrinsic2(ctx, fn, f3, f3x1, f1);
4103 add_intrinsic2(ctx, fn, f3, f3x2, f2);
4104 add_intrinsic2(ctx, fn, f3, f3x3, f3);
4105 add_intrinsic2(ctx, fn, f3, f3x4, f4);
4106 add_intrinsic2(ctx, fn, f4, f4x1, f1);
4107 add_intrinsic2(ctx, fn, f4, f4x2, f2);
4108 add_intrinsic2(ctx, fn, f4, f4x3, f3);
4109 add_intrinsic2(ctx, fn, f4, f4x4, f4);
4110
4111 // matrix * matrix
4112 add_intrinsic2(ctx, fn, i1x1, i1x1, i1x1);
4113 add_intrinsic2(ctx, fn, i1x2, i1x1, i1x2);
4114 add_intrinsic2(ctx, fn, i1x3, i1x1, i1x3);
4115 add_intrinsic2(ctx, fn, i1x4, i1x1, i1x4);
4116 add_intrinsic2(ctx, fn, i1x1, i1x2, i2x1);
4117 add_intrinsic2(ctx, fn, i1x2, i1x2, i2x2);
4118 add_intrinsic2(ctx, fn, i1x3, i1x2, i2x3);
4119 add_intrinsic2(ctx, fn, i1x4, i1x2, i2x4);
4120 add_intrinsic2(ctx, fn, i1x1, i1x3, i3x1);
4121 add_intrinsic2(ctx, fn, i1x2, i1x3, i3x2);
4122 add_intrinsic2(ctx, fn, i1x3, i1x3, i3x3);
4123 add_intrinsic2(ctx, fn, i1x4, i1x3, i3x4);
4124 add_intrinsic2(ctx, fn, i1x1, i1x4, i4x1);
4125 add_intrinsic2(ctx, fn, i1x2, i1x4, i4x2);
4126 add_intrinsic2(ctx, fn, i1x3, i1x4, i4x3);
4127 add_intrinsic2(ctx, fn, i1x4, i1x4, i4x4);
4128 add_intrinsic2(ctx, fn, i2x1, i2x1, i1x1);
4129 add_intrinsic2(ctx, fn, i2x2, i2x1, i1x2);
4130 add_intrinsic2(ctx, fn, i2x3, i2x1, i1x3);
4131 add_intrinsic2(ctx, fn, i2x4, i2x1, i1x4);
4132 add_intrinsic2(ctx, fn, i2x1, i2x2, i2x1);
4133 add_intrinsic2(ctx, fn, i2x2, i2x2, i2x2);
4134 add_intrinsic2(ctx, fn, i2x3, i2x2, i2x3);
4135 add_intrinsic2(ctx, fn, i2x4, i2x2, i2x4);
4136 add_intrinsic2(ctx, fn, i2x1, i2x3, i3x1);
4137 add_intrinsic2(ctx, fn, i2x2, i2x3, i3x2);
4138 add_intrinsic2(ctx, fn, i2x3, i2x3, i3x3);
4139 add_intrinsic2(ctx, fn, i2x4, i2x3, i3x4);
4140 add_intrinsic2(ctx, fn, i2x1, i2x4, i4x1);
4141 add_intrinsic2(ctx, fn, i2x2, i2x4, i4x2);
4142 add_intrinsic2(ctx, fn, i2x3, i2x4, i4x3);
4143 add_intrinsic2(ctx, fn, i2x4, i2x4, i4x4);
4144 add_intrinsic2(ctx, fn, i3x1, i3x1, i1x1);
4145 add_intrinsic2(ctx, fn, i3x2, i3x1, i1x2);
4146 add_intrinsic2(ctx, fn, i3x3, i3x1, i1x3);
4147 add_intrinsic2(ctx, fn, i3x4, i3x1, i1x4);
4148 add_intrinsic2(ctx, fn, i3x1, i3x2, i2x1);
4149 add_intrinsic2(ctx, fn, i3x2, i3x2, i2x2);
4150 add_intrinsic2(ctx, fn, i3x3, i3x2, i2x3);
4151 add_intrinsic2(ctx, fn, i3x4, i3x2, i2x4);
4152 add_intrinsic2(ctx, fn, i3x1, i3x3, i3x1);
4153 add_intrinsic2(ctx, fn, i3x2, i3x3, i3x2);
4154 add_intrinsic2(ctx, fn, i3x3, i3x3, i3x3);
4155 add_intrinsic2(ctx, fn, i3x4, i3x3, i3x4);
4156 add_intrinsic2(ctx, fn, i3x1, i3x4, i4x1);
4157 add_intrinsic2(ctx, fn, i3x2, i3x4, i4x2);
4158 add_intrinsic2(ctx, fn, i3x3, i3x4, i4x3);
4159 add_intrinsic2(ctx, fn, i3x4, i3x4, i4x4);
4160 add_intrinsic2(ctx, fn, i4x1, i4x1, i1x1);
4161 add_intrinsic2(ctx, fn, i4x2, i4x1, i1x2);
4162 add_intrinsic2(ctx, fn, i4x3, i4x1, i1x3);
4163 add_intrinsic2(ctx, fn, i4x4, i4x1, i1x4);
4164 add_intrinsic2(ctx, fn, i4x1, i4x2, i2x1);
4165 add_intrinsic2(ctx, fn, i4x2, i4x2, i2x2);
4166 add_intrinsic2(ctx, fn, i4x3, i4x2, i2x3);
4167 add_intrinsic2(ctx, fn, i4x4, i4x2, i2x4);
4168 add_intrinsic2(ctx, fn, i4x1, i4x3, i3x1);
4169 add_intrinsic2(ctx, fn, i4x2, i4x3, i3x2);
4170 add_intrinsic2(ctx, fn, i4x3, i4x3, i3x3);
4171 add_intrinsic2(ctx, fn, i4x4, i4x3, i3x4);
4172 add_intrinsic2(ctx, fn, i4x1, i4x4, i4x1);
4173 add_intrinsic2(ctx, fn, i4x2, i4x4, i4x2);
4174 add_intrinsic2(ctx, fn, i4x3, i4x4, i4x3);
4175 add_intrinsic2(ctx, fn, i4x4, i4x4, i4x4);
4176 add_intrinsic2(ctx, fn, f1x1, f1x1, f1x1);
4177 add_intrinsic2(ctx, fn, f1x2, f1x1, f1x2);
4178 add_intrinsic2(ctx, fn, f1x3, f1x1, f1x3);
4179 add_intrinsic2(ctx, fn, f1x4, f1x1, f1x4);
4180 add_intrinsic2(ctx, fn, f1x1, f1x2, f2x1);
4181 add_intrinsic2(ctx, fn, f1x2, f1x2, f2x2);
4182 add_intrinsic2(ctx, fn, f1x3, f1x2, f2x3);
4183 add_intrinsic2(ctx, fn, f1x4, f1x2, f2x4);
4184 add_intrinsic2(ctx, fn, f1x1, f1x3, f3x1);
4185 add_intrinsic2(ctx, fn, f1x2, f1x3, f3x2);
4186 add_intrinsic2(ctx, fn, f1x3, f1x3, f3x3);
4187 add_intrinsic2(ctx, fn, f1x4, f1x3, f3x4);
4188 add_intrinsic2(ctx, fn, f1x1, f1x4, f4x1);
4189 add_intrinsic2(ctx, fn, f1x2, f1x4, f4x2);
4190 add_intrinsic2(ctx, fn, f1x3, f1x4, f4x3);
4191 add_intrinsic2(ctx, fn, f1x4, f1x4, f4x4);
4192 add_intrinsic2(ctx, fn, f2x1, f2x1, f1x1);
4193 add_intrinsic2(ctx, fn, f2x2, f2x1, f1x2);
4194 add_intrinsic2(ctx, fn, f2x3, f2x1, f1x3);
4195 add_intrinsic2(ctx, fn, f2x4, f2x1, f1x4);
4196 add_intrinsic2(ctx, fn, f2x1, f2x2, f2x1);
4197 add_intrinsic2(ctx, fn, f2x2, f2x2, f2x2);
4198 add_intrinsic2(ctx, fn, f2x3, f2x2, f2x3);
4199 add_intrinsic2(ctx, fn, f2x4, f2x2, f2x4);
4200 add_intrinsic2(ctx, fn, f2x1, f2x3, f3x1);
4201 add_intrinsic2(ctx, fn, f2x2, f2x3, f3x2);
4202 add_intrinsic2(ctx, fn, f2x3, f2x3, f3x3);
4203 add_intrinsic2(ctx, fn, f2x4, f2x3, f3x4);
4204 add_intrinsic2(ctx, fn, f2x1, f2x4, f4x1);
4205 add_intrinsic2(ctx, fn, f2x2, f2x4, f4x2);
4206 add_intrinsic2(ctx, fn, f2x3, f2x4, f4x3);
4207 add_intrinsic2(ctx, fn, f2x4, f2x4, f4x4);
4208 add_intrinsic2(ctx, fn, f3x1, f3x1, f1x1);
4209 add_intrinsic2(ctx, fn, f3x2, f3x1, f1x2);
4210 add_intrinsic2(ctx, fn, f3x3, f3x1, f1x3);
4211 add_intrinsic2(ctx, fn, f3x4, f3x1, f1x4);
4212 add_intrinsic2(ctx, fn, f3x1, f3x2, f2x1);
4213 add_intrinsic2(ctx, fn, f3x2, f3x2, f2x2);
4214 add_intrinsic2(ctx, fn, f3x3, f3x2, f2x3);
4215 add_intrinsic2(ctx, fn, f3x4, f3x2, f2x4);
4216 add_intrinsic2(ctx, fn, f3x1, f3x3, f3x1);
4217 add_intrinsic2(ctx, fn, f3x2, f3x3, f3x2);
4218 add_intrinsic2(ctx, fn, f3x3, f3x3, f3x3);
4219 add_intrinsic2(ctx, fn, f3x4, f3x3, f3x4);
4220 add_intrinsic2(ctx, fn, f3x1, f3x4, f4x1);
4221 add_intrinsic2(ctx, fn, f3x2, f3x4, f4x2);
4222 add_intrinsic2(ctx, fn, f3x3, f3x4, f4x3);
4223 add_intrinsic2(ctx, fn, f3x4, f3x4, f4x4);
4224 add_intrinsic2(ctx, fn, f4x1, f4x1, f1x1);
4225 add_intrinsic2(ctx, fn, f4x2, f4x1, f1x2);
4226 add_intrinsic2(ctx, fn, f4x3, f4x1, f1x3);
4227 add_intrinsic2(ctx, fn, f4x4, f4x1, f1x4);
4228 add_intrinsic2(ctx, fn, f4x1, f4x2, f2x1);
4229 add_intrinsic2(ctx, fn, f4x2, f4x2, f2x2);
4230 add_intrinsic2(ctx, fn, f4x3, f4x2, f2x3);
4231 add_intrinsic2(ctx, fn, f4x4, f4x2, f2x4);
4232 add_intrinsic2(ctx, fn, f4x1, f4x3, f3x1);
4233 add_intrinsic2(ctx, fn, f4x2, f4x3, f3x2);
4234 add_intrinsic2(ctx, fn, f4x3, f4x3, f3x3);
4235 add_intrinsic2(ctx, fn, f4x4, f4x3, f3x4);
4236 add_intrinsic2(ctx, fn, f4x1, f4x4, f4x1);
4237 add_intrinsic2(ctx, fn, f4x2, f4x4, f4x2);
4238 add_intrinsic2(ctx, fn, f4x3, f4x4, f4x3);
4239 add_intrinsic2(ctx, fn, f4x4, f4x4, f4x4);
4240 } // add_intrinsic_mul
4241
init_builtins(Context * ctx)4242 static void init_builtins(Context *ctx)
4243 {
4244 // add in standard typedefs...
4245 const struct
4246 {
4247 const char *str;
4248 const MOJOSHADER_astDataType *datatype;
4249 } types[] = {
4250 { "bool", &ctx->dt_bool },
4251 { "int", &ctx->dt_int },
4252 { "uint", &ctx->dt_uint },
4253 { "half", &ctx->dt_half },
4254 { "float", &ctx->dt_float },
4255 { "double", &ctx->dt_double },
4256 };
4257
4258 int i, j, k;
4259 for (i = 0; i < STATICARRAYLEN(types); i++)
4260 {
4261 char buf[32];
4262 int len;
4263 const MOJOSHADER_astDataType *dt;
4264
4265 for (j = 1; j <= 4; j++)
4266 {
4267 // "float2"
4268 dt = new_datatype_vector(ctx, types[i].datatype, j);
4269 len = snprintf(buf, sizeof (buf), "%s%d", types[i].str, j);
4270 push_usertype(ctx, stringcache_len(ctx->strcache, buf, len), dt);
4271 for (k = 1; k <= 4; k++)
4272 {
4273 // "float2x2"
4274 dt = new_datatype_matrix(ctx, types[i].datatype, j, k);
4275 len = snprintf(buf, sizeof (buf), "%s%dx%d", types[i].str,j,k);
4276 push_usertype(ctx, stringcache_len(ctx->strcache,buf,len), dt);
4277 } // for
4278 } // for
4279 } // for
4280
4281 // !!! FIXME: block these out by pixel/vertex/etc shader.
4282 // !!! FIXME: calculate actual shader model (or maybe just let bytecode verifier throw up?).
4283 const int shader_model = 3;
4284 if (shader_model >= 1)
4285 {
4286 add_intrinsic_SAME1_ANYfi(ctx, stringcache(ctx->strcache, "abs"));
4287 add_intrinsic_SAME1_ANYf(ctx, stringcache(ctx->strcache, "acos"));
4288 add_intrinsic_BOOL_ANYfib(ctx, stringcache(ctx->strcache, "all"));
4289 add_intrinsic_BOOL_ANYfib(ctx, stringcache(ctx->strcache, "any"));
4290 add_intrinsic_SAME1_ANYf(ctx, stringcache(ctx->strcache, "asin"));
4291 add_intrinsic_SAME1_ANYf(ctx, stringcache(ctx->strcache, "atan"));
4292 add_intrinsic_SAME1_ANYf_SAME1(ctx, stringcache(ctx->strcache, "atan2"));
4293 add_intrinsic_SAME1_ANYf(ctx, stringcache(ctx->strcache, "ceil"));
4294 add_intrinsic_SAME1_ANYfi_SAME1_SAME1(ctx, stringcache(ctx->strcache, "clamp"));
4295 add_intrinsic_VOID_ANYf(ctx, stringcache(ctx->strcache, "clip"));
4296 add_intrinsic_SAME1_ANYf(ctx, stringcache(ctx->strcache, "cos"));
4297 add_intrinsic_SAME1_ANYf(ctx, stringcache(ctx->strcache, "cosh"));
4298 add_intrinsic_3f_3f_3f(ctx, stringcache(ctx->strcache, "cross"));
4299 add_intrinsic_4i_4f(ctx, stringcache(ctx->strcache, "D3DCOLORtoUBYTE4"));
4300 add_intrinsic_f_Vf_SAME1(ctx, stringcache(ctx->strcache, "distance"));
4301 add_intrinsic_SAME1_ANYf(ctx, stringcache(ctx->strcache, "degrees"));
4302 add_intrinsic_f_SQUAREMATRIXf(ctx, stringcache(ctx->strcache, "determinant"));
4303 add_intrinsic_fi_Vfi_SAME1(ctx, stringcache(ctx->strcache, "dot"));
4304 add_intrinsic_SAME1_ANYf(ctx, stringcache(ctx->strcache, "exp"));
4305 add_intrinsic_SAME1_ANYf(ctx, stringcache(ctx->strcache, "exp2"));
4306 add_intrinsic_SAME1_Vf_SAME1_SAME1(ctx, stringcache(ctx->strcache, "faceforward"));
4307 add_intrinsic_SAME1_ANYf(ctx, stringcache(ctx->strcache, "floor"));
4308 add_intrinsic_SAME1_ANYf_SAME1(ctx, stringcache(ctx->strcache, "fmod"));
4309 add_intrinsic_SAME1_ANYf(ctx, stringcache(ctx->strcache, "frac"));
4310 add_intrinsic_BOOL_ANYf(ctx, stringcache(ctx->strcache, "isfinite"));
4311 add_intrinsic_BOOL_ANYf(ctx, stringcache(ctx->strcache, "isinf"));
4312 add_intrinsic_BOOL_ANYf(ctx, stringcache(ctx->strcache, "isnan"));
4313 add_intrinsic_SAME1_ANYf_SAME1(ctx, stringcache(ctx->strcache, "ldexp"));
4314 add_intrinsic_f_Vf(ctx, stringcache(ctx->strcache, "length"));
4315 add_intrinsic_SAME1_ANYf_SAME1_SAME1(ctx, stringcache(ctx->strcache, "lerp"));
4316 add_intrinsic_4f_f_f_f(ctx, stringcache(ctx->strcache, "lit"));
4317 add_intrinsic_SAME1_ANYf(ctx, stringcache(ctx->strcache, "log"));
4318 add_intrinsic_SAME1_ANYf(ctx, stringcache(ctx->strcache, "log10"));
4319 add_intrinsic_SAME1_ANYf(ctx, stringcache(ctx->strcache, "log2"));
4320 add_intrinsic_SAME1_ANYfi_SAME1(ctx, stringcache(ctx->strcache, "max"));
4321 add_intrinsic_SAME1_ANYfi_SAME1(ctx, stringcache(ctx->strcache, "min"));
4322 add_intrinsic_SAME1_ANYfi_SAME1(ctx, stringcache(ctx->strcache, "modf")); // !!! FIXME: out var?
4323 add_intrinsic_mul(ctx, stringcache(ctx->strcache, "mul"));
4324 add_intrinsic_f_Vf(ctx, stringcache(ctx->strcache, "noise"));
4325 add_intrinsic_SAME1_Vf(ctx, stringcache(ctx->strcache, "normalize"));
4326 add_intrinsic_SAME1_ANYf_SAME1(ctx, stringcache(ctx->strcache, "pow"));
4327 add_intrinsic_SAME1_ANYf(ctx, stringcache(ctx->strcache, "radians"));
4328 add_intrinsic_SAME1_ANYfi_SAME1(ctx, stringcache(ctx->strcache, "reflect"));
4329 add_intrinsic_SAME1_Vf_SAME1_f(ctx, stringcache(ctx->strcache, "refract"));
4330 add_intrinsic_SAME1_ANYf(ctx, stringcache(ctx->strcache, "round"));
4331 add_intrinsic_SAME1_ANYf(ctx, stringcache(ctx->strcache, "rsqrt"));
4332 add_intrinsic_SAME1_ANYf(ctx, stringcache(ctx->strcache, "saturate"));
4333 add_intrinsic_SAME1_ANYf(ctx, stringcache(ctx->strcache, "sign"));
4334 add_intrinsic_SAME1_ANYf(ctx, stringcache(ctx->strcache, "sin"));
4335 add_intrinsic_VOID_ANYf_SAME1_SAME1(ctx, stringcache(ctx->strcache, "sincos")); // !!! FIXME: out var?
4336 add_intrinsic_SAME1_ANYf(ctx, stringcache(ctx->strcache, "sinh"));
4337 add_intrinsic_SAME1_ANYf_SAME1_SAME1(ctx, stringcache(ctx->strcache, "smoothstep"));
4338 add_intrinsic_SAME1_ANYf(ctx, stringcache(ctx->strcache, "sqrt"));
4339 add_intrinsic_SAME1_ANYf_SAME1(ctx, stringcache(ctx->strcache, "step"));
4340 add_intrinsic_SAME1_ANYf(ctx, stringcache(ctx->strcache, "tan"));
4341 add_intrinsic_SAME1_ANYf(ctx, stringcache(ctx->strcache, "tanh"));
4342 add_intrinsic_4f_s1_f(ctx, stringcache(ctx->strcache, "tex1D"));
4343 add_intrinsic_4f_s2_2f(ctx, stringcache(ctx->strcache, "tex2D"));
4344 add_intrinsic_4f_s3_3f(ctx, stringcache(ctx->strcache, "tex3D"));
4345 add_intrinsic_4f_sc_3f(ctx, stringcache(ctx->strcache, "texCUBE"));
4346 add_intrinsic_SAME1_Mfib(ctx, stringcache(ctx->strcache, "transpose"));
4347 add_intrinsic_SAME1_ANYf(ctx, stringcache(ctx->strcache, "trunc"));
4348 } // if
4349
4350 if (shader_model >= 2)
4351 {
4352 add_intrinsic_SAME1_ANYf(ctx, stringcache(ctx->strcache, "ddx"));
4353 add_intrinsic_SAME1_ANYf(ctx, stringcache(ctx->strcache, "ddy"));
4354 add_intrinsic_SAME1_ANYf_SAME1(ctx, stringcache(ctx->strcache, "frexp"));
4355 add_intrinsic_SAME1_ANYf(ctx, stringcache(ctx->strcache, "fwidth"));
4356 add_intrinsic_4f_s1_f_f_f(ctx, stringcache(ctx->strcache, "tex1D"));
4357 add_intrinsic_4f_s1_4f(ctx, stringcache(ctx->strcache, "tex1Dbias"));
4358 add_intrinsic_4f_s1_f_f_f(ctx, stringcache(ctx->strcache, "tex1Dgrad"));
4359 add_intrinsic_4f_s1_4f(ctx, stringcache(ctx->strcache, "tex1Dproj"));
4360 add_intrinsic_4f_s2_2f_2f_2f(ctx, stringcache(ctx->strcache, "tex2D"));
4361 add_intrinsic_4f_s2_4f(ctx, stringcache(ctx->strcache, "tex2Dbias"));
4362 add_intrinsic_4f_s2_2f_2f_2f(ctx, stringcache(ctx->strcache, "tex2Dgrad"));
4363 add_intrinsic_4f_s2_4f(ctx, stringcache(ctx->strcache, "tex2Dproj"));
4364 add_intrinsic_4f_s3_3f_3f_3f(ctx, stringcache(ctx->strcache, "tex3D"));
4365 add_intrinsic_4f_s3_4f(ctx, stringcache(ctx->strcache, "tex3Dbias"));
4366 add_intrinsic_4f_s3_3f_3f_3f(ctx, stringcache(ctx->strcache, "tex3Dgrad"));
4367 add_intrinsic_4f_s3_4f(ctx, stringcache(ctx->strcache, "tex3Dproj"));
4368 add_intrinsic_4f_sc_3f_3f_3f(ctx, stringcache(ctx->strcache, "texCUBE"));
4369 add_intrinsic_4f_sc_4f(ctx, stringcache(ctx->strcache, "texCUBEbias"));
4370 add_intrinsic_4f_sc_3f_3f_3f(ctx, stringcache(ctx->strcache, "texCUBEgrad"));
4371 add_intrinsic_4f_sc_4f(ctx, stringcache(ctx->strcache, "texCUBEproj"));
4372 } // if
4373
4374 if (shader_model >= 3)
4375 {
4376 add_intrinsic_4f_s1_4f(ctx, stringcache(ctx->strcache, "tex1Dlod"));
4377 add_intrinsic_4f_s2_4f(ctx, stringcache(ctx->strcache, "tex2Dlod"));
4378 add_intrinsic_4f_s3_4f(ctx, stringcache(ctx->strcache, "tex3Dlod"));
4379 add_intrinsic_4f_sc_4f(ctx, stringcache(ctx->strcache, "texCUBElod"));
4380 } // if
4381 } // init_builtins
4382
4383
4384 // parse the source code into an AST.
parse_source(Context * ctx,const char * filename,const char * source,unsigned int sourcelen,const MOJOSHADER_preprocessorDefine * defines,unsigned int define_count,MOJOSHADER_includeOpen include_open,MOJOSHADER_includeClose include_close)4385 static void parse_source(Context *ctx, const char *filename,
4386 const char *source, unsigned int sourcelen,
4387 const MOJOSHADER_preprocessorDefine *defines,
4388 unsigned int define_count,
4389 MOJOSHADER_includeOpen include_open,
4390 MOJOSHADER_includeClose include_close)
4391 {
4392 TokenData data;
4393 unsigned int tokenlen;
4394 Token tokenval;
4395 const char *token;
4396 int lemon_token;
4397 const char *fname;
4398 Preprocessor *pp;
4399 void *parser;
4400
4401 if (!include_open) include_open = MOJOSHADER_internal_include_open;
4402 if (!include_close) include_close = MOJOSHADER_internal_include_close;
4403
4404 pp = preprocessor_start(filename, source, sourcelen, include_open,
4405 include_close, defines, define_count, 0,
4406 MallocBridge, FreeBridge, ctx);
4407 if (pp == NULL)
4408 {
4409 assert(ctx->out_of_memory); // shouldn't fail for any other reason.
4410 return;
4411 } // if
4412
4413 parser = ParseHLSLAlloc(ctx->malloc, ctx->malloc_data);
4414 if (parser == NULL)
4415 {
4416 assert(ctx->out_of_memory); // shouldn't fail for any other reason.
4417 preprocessor_end(pp);
4418 return;
4419 } // if
4420
4421 // !!! FIXME: check if (parser == NULL)...
4422
4423 init_builtins(ctx);
4424
4425 SymbolScope *start_scope = ctx->usertypes.scope;
4426
4427 #if DEBUG_COMPILER_PARSER
4428 ParseHLSLTrace(stdout, "COMPILER: ");
4429 #endif
4430
4431 // Run the preprocessor/lexer/parser...
4432 int is_pragma = 0; // !!! FIXME: remove this later when we can parse #pragma.
4433 int skipping = 0; // !!! FIXME: remove this later when we can parse #pragma.
4434 do {
4435 token = preprocessor_nexttoken(pp, &tokenlen, &tokenval);
4436
4437 if (ctx->out_of_memory)
4438 break;
4439
4440 fname = preprocessor_sourcepos(pp, &ctx->sourceline);
4441 ctx->sourcefile = fname ? stringcache(ctx->strcache, fname) : 0;
4442
4443 if ((tokenval == TOKEN_HASH) || (tokenval == TOKEN_HASHHASH))
4444 tokenval = TOKEN_BAD_CHARS;
4445
4446 if (tokenval == TOKEN_BAD_CHARS)
4447 {
4448 fail(ctx, "Bad characters in source file");
4449 continue;
4450 } // else if
4451
4452 else if (tokenval == TOKEN_PREPROCESSING_ERROR)
4453 {
4454 fail(ctx, token); // this happens to be null-terminated.
4455 continue;
4456 } // else if
4457
4458 else if (tokenval == TOKEN_PP_PRAGMA)
4459 {
4460 assert(!is_pragma);
4461 is_pragma = 1;
4462 skipping = 1;
4463 continue;
4464 }
4465
4466 else if (tokenval == ((Token) '\n'))
4467 {
4468 assert(is_pragma);
4469 is_pragma = 0;
4470 skipping = 0;
4471 continue;
4472 }
4473
4474 else if (skipping)
4475 {
4476 continue;
4477 }
4478
4479 // !!! FIXME: this is a mess, decide who should be doing this stuff, and only do it once.
4480 lemon_token = convert_to_lemon_token(ctx, token, tokenlen, tokenval);
4481 switch (lemon_token)
4482 {
4483 case TOKEN_HLSL_INT_CONSTANT:
4484 data.i64 = strtoi64(token, tokenlen);
4485 break;
4486
4487 case TOKEN_HLSL_FLOAT_CONSTANT:
4488 data.dbl = strtodouble(token, tokenlen);
4489 break;
4490
4491 case TOKEN_HLSL_USERTYPE:
4492 data.string = stringcache_len(ctx->strcache, token, tokenlen);
4493 data.datatype = get_usertype(ctx, data.string); // !!! FIXME: do we need this? It's kind of useless during parsing.
4494 assert(data.datatype != NULL);
4495 break;
4496
4497 case TOKEN_HLSL_STRING_LITERAL:
4498 case TOKEN_HLSL_IDENTIFIER:
4499 data.string = stringcache_len(ctx->strcache, token, tokenlen);
4500 break;
4501
4502 default:
4503 data.i64 = 0;
4504 break;
4505 } // switch
4506
4507 ParseHLSL(parser, lemon_token, data, ctx);
4508
4509 // this probably isn't perfect, but it's good enough for surviving
4510 // the parse. We'll sort out correctness once we have a tree.
4511 if (lemon_token == TOKEN_HLSL_LBRACE)
4512 push_scope(ctx);
4513 else if (lemon_token == TOKEN_HLSL_RBRACE)
4514 pop_scope(ctx);
4515 } while (tokenval != TOKEN_EOI);
4516
4517 // Clean out extra usertypes; they are dummies until semantic analysis.
4518 while (ctx->usertypes.scope != start_scope)
4519 pop_symbol(ctx, &ctx->usertypes);
4520
4521 ParseHLSLFree(parser, ctx->free, ctx->malloc_data);
4522 preprocessor_end(pp);
4523 } // parse_source
4524
4525
4526 /* Intermediate representation... */
4527
generate_ir_label(Context * ctx)4528 static inline int generate_ir_label(Context *ctx)
4529 {
4530 return ctx->ir_label_count++;
4531 } // generate_ir_label
4532
generate_ir_temp(Context * ctx)4533 static inline int generate_ir_temp(Context *ctx)
4534 {
4535 return ctx->ir_temp_count++;
4536 } // generate_ir_temp
4537
push_ir_loop(Context * ctx,const int isswitch)4538 static const LoopLabels *push_ir_loop(Context *ctx, const int isswitch)
4539 {
4540 // !!! FIXME: cache these allocations?
4541 LoopLabels *retval = (LoopLabels *)Malloc(ctx, sizeof (LoopLabels));
4542 if (retval)
4543 {
4544 retval->start = (isswitch) ? -1 : generate_ir_label(ctx);
4545 retval->end = generate_ir_label(ctx);
4546 retval->prev = ctx->ir_loop;
4547 ctx->ir_loop = retval;
4548 } // if
4549
4550 return retval;
4551 } // push_ir_loop
4552
pop_ir_loop(Context * ctx)4553 static void pop_ir_loop(Context *ctx)
4554 {
4555 assert(ctx->ir_loop != NULL);
4556 LoopLabels *labels = ctx->ir_loop;
4557 ctx->ir_loop = ctx->ir_loop->prev;
4558 Free(ctx, labels);
4559 } // pop_ir_loop
4560
4561
4562 #define NEW_IR_NODE(retval, cls, typ) \
4563 cls *retval = (cls *) Malloc(ctx, sizeof (cls)); \
4564 do { \
4565 if (retval == NULL) { return NULL; } \
4566 retval->ir.type = typ; \
4567 retval->ir.filename = ctx->sourcefile; \
4568 retval->ir.line = ctx->sourceline; \
4569 } while (0)
4570
4571 #define NEW_IR_EXPR(retval, cls, typ, dt, numelems) \
4572 cls *retval = (cls *) Malloc(ctx, sizeof (cls)); \
4573 do { \
4574 if (retval == NULL) { return NULL; } \
4575 retval->info.ir.type = typ; \
4576 retval->info.ir.filename = ctx->sourcefile; \
4577 retval->info.ir.line = ctx->sourceline; \
4578 retval->info.type = dt; \
4579 retval->info.elements = numelems; \
4580 } while (0)
4581
4582 // syntactic sugar.
4583 static inline MOJOSHADER_irNode *build_ir(Context *ctx, void *_ast);
build_ir_expr(Context * ctx,void * _ast)4584 static inline MOJOSHADER_irExpression *build_ir_expr(Context *ctx, void *_ast)
4585 {
4586 MOJOSHADER_irNode *retval = build_ir(ctx, _ast);
4587 assert(!retval || (retval->ir.type > MOJOSHADER_IR_START_RANGE_EXPR));
4588 assert(!retval || (retval->ir.type < MOJOSHADER_IR_END_RANGE_EXPR));
4589 return (MOJOSHADER_irExpression *) retval;
4590 } // build_ir_expr
4591
build_ir_stmt(Context * ctx,void * _ast)4592 static inline MOJOSHADER_irStatement *build_ir_stmt(Context *ctx, void *_ast)
4593 {
4594 MOJOSHADER_irNode *retval = build_ir(ctx, _ast);
4595 assert(!retval || (retval->ir.type > MOJOSHADER_IR_START_RANGE_STMT));
4596 assert(!retval || (retval->ir.type < MOJOSHADER_IR_END_RANGE_STMT));
4597 return (MOJOSHADER_irStatement *) retval;
4598 } // build_ir_stmt
4599
4600
new_ir_binop(Context * ctx,const MOJOSHADER_irBinOpType op,MOJOSHADER_irExpression * left,MOJOSHADER_irExpression * right)4601 static MOJOSHADER_irExpression *new_ir_binop(Context *ctx,
4602 const MOJOSHADER_irBinOpType op,
4603 MOJOSHADER_irExpression *left,
4604 MOJOSHADER_irExpression *right)
4605 {
4606 if ((!left) || (!right)) return NULL;
4607 NEW_IR_EXPR(retval, MOJOSHADER_irBinOp, MOJOSHADER_IR_BINOP, left->info.type, left->info.elements);
4608 assert(left->info.type == right->info.type);
4609 assert(left->info.elements == right->info.elements);
4610 retval->op = op;
4611 retval->left = left;
4612 retval->right = right;
4613 return (MOJOSHADER_irExpression *) retval;
4614 } // new_ir_binop
4615
new_ir_eseq(Context * ctx,MOJOSHADER_irStatement * stmt,MOJOSHADER_irExpression * expr)4616 static MOJOSHADER_irExpression *new_ir_eseq(Context *ctx,
4617 MOJOSHADER_irStatement *stmt,
4618 MOJOSHADER_irExpression *expr)
4619 {
4620 if (!expr) return NULL;
4621 NEW_IR_EXPR(retval, MOJOSHADER_irESeq, MOJOSHADER_IR_ESEQ, expr->info.type, expr->info.elements);
4622 retval->stmt = stmt;
4623 retval->expr = expr;
4624 return (MOJOSHADER_irExpression *) retval;
4625 } // new_ir_eseq
4626
new_ir_temp(Context * ctx,const int index,const MOJOSHADER_astDataTypeType type,const int elements)4627 static MOJOSHADER_irExpression *new_ir_temp(Context *ctx, const int index,
4628 const MOJOSHADER_astDataTypeType type,
4629 const int elements)
4630 {
4631 NEW_IR_EXPR(retval, MOJOSHADER_irTemp, MOJOSHADER_IR_TEMP, type, elements);
4632 retval->index = index;
4633 return (MOJOSHADER_irExpression *) retval;
4634 } // new_ir_temp
4635
4636
4637
4638 #define NEW_IR_BINOP(op,l,r) new_ir_binop(ctx, MOJOSHADER_IR_BINOP_##op, l, r)
4639 #define EASY_IR_BINOP(op) \
4640 NEW_IR_BINOP(op, build_ir_expr(ctx, ast->binary.left), \
4641 build_ir_expr(ctx, ast->binary.right))
4642
4643 // You have to fill in ->value yourself!
new_ir_constant(Context * ctx,const MOJOSHADER_astDataTypeType type,const int elements)4644 static MOJOSHADER_irExpression *new_ir_constant(Context *ctx,
4645 const MOJOSHADER_astDataTypeType type,
4646 const int elements)
4647 {
4648 NEW_IR_EXPR(retval, MOJOSHADER_irConstant, MOJOSHADER_IR_CONSTANT, type, elements);
4649 return (MOJOSHADER_irExpression *) retval;
4650 } // new_ir_constant
4651
new_ir_constint(Context * ctx,const int val)4652 static MOJOSHADER_irExpression *new_ir_constint(Context *ctx, const int val)
4653 {
4654 NEW_IR_EXPR(retval, MOJOSHADER_irConstant, MOJOSHADER_IR_CONSTANT, MOJOSHADER_AST_DATATYPE_INT, 1);
4655 retval->value.ival[0] = val;
4656 return (MOJOSHADER_irExpression *) retval;
4657 } // new_ir_constint
4658
new_ir_constfloat(Context * ctx,const float val)4659 static MOJOSHADER_irExpression *new_ir_constfloat(Context *ctx, const float val)
4660 {
4661 NEW_IR_EXPR(retval, MOJOSHADER_irConstant, MOJOSHADER_IR_CONSTANT, MOJOSHADER_AST_DATATYPE_FLOAT, 1);
4662 retval->value.fval[0] = val;
4663 return (MOJOSHADER_irExpression *) retval;
4664 } // new_ir_constfloat
4665
new_ir_constbool(Context * ctx,const int val)4666 static MOJOSHADER_irExpression *new_ir_constbool(Context *ctx, const int val)
4667 {
4668 // !!! FIXME: cache true and false in (ctx), ignore in delete_ir().
4669 NEW_IR_EXPR(retval, MOJOSHADER_irConstant, MOJOSHADER_IR_CONSTANT, MOJOSHADER_AST_DATATYPE_BOOL, 1);
4670 retval->value.ival[0] = val;
4671 return (MOJOSHADER_irExpression *) retval;
4672 } // new_ir_constbool
4673
new_ir_convert(Context * ctx,MOJOSHADER_irExpression * expr,const MOJOSHADER_astDataTypeType type,const int elements)4674 static MOJOSHADER_irExpression *new_ir_convert(Context *ctx, MOJOSHADER_irExpression *expr,
4675 const MOJOSHADER_astDataTypeType type,
4676 const int elements)
4677 {
4678 NEW_IR_EXPR(retval, MOJOSHADER_irConvert, MOJOSHADER_IR_CONVERT, type, elements);
4679 retval->expr = expr;
4680 return (MOJOSHADER_irExpression *) retval;
4681 } // new_ir_convert
4682
new_ir_construct(Context * ctx,MOJOSHADER_irExprList * args,const MOJOSHADER_astDataTypeType type,const int elements)4683 static MOJOSHADER_irExpression *new_ir_construct(Context *ctx, MOJOSHADER_irExprList *args,
4684 const MOJOSHADER_astDataTypeType type,
4685 const int elements)
4686 {
4687 NEW_IR_EXPR(retval, MOJOSHADER_irConstruct, MOJOSHADER_IR_CONSTRUCT, type, elements);
4688 retval->args = args;
4689 return (MOJOSHADER_irExpression *) retval;
4690 } // new_ir_construct
4691
new_ir_call(Context * ctx,const int index,MOJOSHADER_irExprList * args,const MOJOSHADER_astDataTypeType type,const int elements)4692 static MOJOSHADER_irExpression *new_ir_call(Context *ctx, const int index,
4693 MOJOSHADER_irExprList *args,
4694 const MOJOSHADER_astDataTypeType type,
4695 const int elements)
4696 {
4697 NEW_IR_EXPR(retval, MOJOSHADER_irCall, MOJOSHADER_IR_CALL, type, elements);
4698 retval->args = args;
4699 retval->index = index;
4700 return (MOJOSHADER_irExpression *) retval;
4701 } // new_ir_call
4702
new_ir_swizzle(Context * ctx,MOJOSHADER_irExpression * expr,const char * channels,const MOJOSHADER_astDataTypeType type,const int elements)4703 static MOJOSHADER_irExpression *new_ir_swizzle(Context *ctx,
4704 MOJOSHADER_irExpression *expr,
4705 const char *channels,
4706 const MOJOSHADER_astDataTypeType type,
4707 const int elements)
4708 {
4709 NEW_IR_EXPR(retval, MOJOSHADER_irSwizzle, MOJOSHADER_IR_SWIZZLE, type, elements);
4710 retval->expr = expr;
4711 memcpy(retval->channels, channels, sizeof (retval->channels));
4712 return (MOJOSHADER_irExpression *) retval;
4713 } // new_ir_swizzle
4714
new_ir_memory(Context * ctx,const int index,const MOJOSHADER_astDataTypeType type,const int elements)4715 static MOJOSHADER_irExpression *new_ir_memory(Context *ctx, const int index,
4716 const MOJOSHADER_astDataTypeType type,
4717 const int elements)
4718 {
4719 NEW_IR_EXPR(retval, MOJOSHADER_irMemory, MOJOSHADER_IR_MEMORY, type, elements);
4720 retval->index = index;
4721 return (MOJOSHADER_irExpression *) retval;
4722 } // new_ir_memory
4723
new_ir_array(Context * ctx,MOJOSHADER_irExpression * array,MOJOSHADER_irExpression * element,const MOJOSHADER_astDataTypeType type,const int elements)4724 static MOJOSHADER_irExpression *new_ir_array(Context *ctx,
4725 MOJOSHADER_irExpression *array,
4726 MOJOSHADER_irExpression *element,
4727 const MOJOSHADER_astDataTypeType type,
4728 const int elements)
4729 {
4730 NEW_IR_EXPR(retval, MOJOSHADER_irArray, MOJOSHADER_IR_ARRAY, type, elements);
4731 retval->array = array;
4732 retval->element = element;
4733 return (MOJOSHADER_irExpression *) retval;
4734 } // new_ir_array
4735
new_ir_seq(Context * ctx,MOJOSHADER_irStatement * first,MOJOSHADER_irStatement * next)4736 static MOJOSHADER_irStatement *new_ir_seq(Context *ctx,
4737 MOJOSHADER_irStatement *first,
4738 MOJOSHADER_irStatement *next)
4739 {
4740 assert((first != NULL) || (next != NULL));
4741 if (first == NULL) // don't generate a SEQ if unnecessary.
4742 return next;
4743 else if (next == NULL)
4744 return first;
4745
4746 NEW_IR_NODE(retval, MOJOSHADER_irSeq, MOJOSHADER_IR_SEQ);
4747 retval->first = first;
4748 retval->next = next;
4749 return (MOJOSHADER_irStatement *) retval;
4750 } // new_ir_seq
4751
new_ir_jump(Context * ctx,const int label)4752 static MOJOSHADER_irStatement *new_ir_jump(Context *ctx, const int label)
4753 {
4754 NEW_IR_NODE(retval, MOJOSHADER_irJump, MOJOSHADER_IR_JUMP);
4755 retval->label = label;
4756 return (MOJOSHADER_irStatement *) retval;
4757 } // new_ir_jump
4758
new_ir_cjump(Context * ctx,const MOJOSHADER_irConditionType cond,MOJOSHADER_irExpression * left,MOJOSHADER_irExpression * right,const int iftrue,const int iffalse)4759 static MOJOSHADER_irStatement *new_ir_cjump(Context *ctx,
4760 const MOJOSHADER_irConditionType cond,
4761 MOJOSHADER_irExpression *left,
4762 MOJOSHADER_irExpression *right,
4763 const int iftrue, const int iffalse)
4764 {
4765 NEW_IR_NODE(retval, MOJOSHADER_irCJump, MOJOSHADER_IR_CJUMP);
4766 retval->cond = cond;
4767 retval->left = left;
4768 retval->right = right;
4769 retval->iftrue = iftrue;
4770 retval->iffalse = iffalse;
4771 return (MOJOSHADER_irStatement *) retval;
4772 } // new_ir_cjump
4773
new_ir_label(Context * ctx,const int index)4774 static MOJOSHADER_irStatement *new_ir_label(Context *ctx, const int index)
4775 {
4776 NEW_IR_NODE(retval, MOJOSHADER_irLabel, MOJOSHADER_IR_LABEL);
4777 retval->index = index;
4778 return (MOJOSHADER_irStatement *) retval;
4779 } // new_ir_label
4780
new_ir_move(Context * ctx,MOJOSHADER_irExpression * dst,MOJOSHADER_irExpression * src,const int writemask)4781 static MOJOSHADER_irStatement *new_ir_move(Context *ctx,
4782 MOJOSHADER_irExpression *dst,
4783 MOJOSHADER_irExpression *src,
4784 const int writemask)
4785 {
4786 NEW_IR_NODE(retval, MOJOSHADER_irMove, MOJOSHADER_IR_MOVE);
4787 assert(dst && src && (dst->info.type == src->info.type));
4788 assert(dst && src && (dst->info.elements == src->info.elements));
4789 retval->dst = dst;
4790 retval->src = src;
4791 retval->writemask = writemask;
4792 return (MOJOSHADER_irStatement *) retval;
4793 } // new_ir_move
4794
new_ir_expr_stmt(Context * ctx,MOJOSHADER_irExpression * expr)4795 static MOJOSHADER_irStatement *new_ir_expr_stmt(Context *ctx, MOJOSHADER_irExpression *expr)
4796 {
4797 NEW_IR_NODE(retval, MOJOSHADER_irExprStmt, MOJOSHADER_IR_EXPR_STMT);
4798 retval->expr = expr;
4799 return (MOJOSHADER_irStatement *) retval;
4800 } // new_ir_expr_stmt
4801
new_ir_discard(Context * ctx)4802 static MOJOSHADER_irStatement *new_ir_discard(Context *ctx)
4803 {
4804 NEW_IR_NODE(retval, MOJOSHADER_irDiscard, MOJOSHADER_IR_DISCARD);
4805 return (MOJOSHADER_irStatement *) retval;
4806 } // new_ir_discard
4807
new_ir_exprlist(Context * ctx,MOJOSHADER_irExpression * expr)4808 static MOJOSHADER_irExprList *new_ir_exprlist(Context *ctx, MOJOSHADER_irExpression *expr)
4809 {
4810 NEW_IR_NODE(retval, MOJOSHADER_irExprList, MOJOSHADER_IR_EXPRLIST);
4811 retval->expr = expr;
4812 retval->next = NULL;
4813 return (MOJOSHADER_irExprList *) retval;
4814 } // new_ir_exprlist
4815
4816
4817 // This handles most comparison operators (less-than, equals, etc...)
build_ir_compare(Context * ctx,const MOJOSHADER_irConditionType operation,MOJOSHADER_irExpression * left,MOJOSHADER_irExpression * right,MOJOSHADER_irExpression * tval,MOJOSHADER_irExpression * fval)4818 static MOJOSHADER_irExpression *build_ir_compare(Context *ctx,
4819 const MOJOSHADER_irConditionType operation,
4820 MOJOSHADER_irExpression *left,
4821 MOJOSHADER_irExpression *right,
4822 MOJOSHADER_irExpression *tval,
4823 MOJOSHADER_irExpression *fval)
4824 {
4825 /* The gist...
4826 cjump x < y, t, f // '<' is whatever operation
4827 t:
4828 move tmp, tval
4829 jump join
4830 f:
4831 move tmp, fval
4832 join:
4833 */
4834
4835 const int t = generate_ir_label(ctx);
4836 const int f = generate_ir_label(ctx);
4837 const int join = generate_ir_label(ctx);
4838 const int tmp = generate_ir_temp(ctx);
4839
4840 assert(tval && fval && (tval->info.type == fval->info.type));
4841 assert(tval && fval && (tval->info.elements == fval->info.elements));
4842
4843 const MOJOSHADER_astDataTypeType dt = tval->info.type;
4844 const int elements = tval->info.elements;
4845
4846 return new_ir_eseq(ctx,
4847 new_ir_seq(ctx, new_ir_cjump(ctx, operation, left, right, t, f),
4848 new_ir_seq(ctx, new_ir_label(ctx, t),
4849 new_ir_seq(ctx, new_ir_move(ctx, new_ir_temp(ctx, tmp, dt, elements), tval, -1),
4850 new_ir_seq(ctx, new_ir_jump(ctx, join),
4851 new_ir_seq(ctx, new_ir_label(ctx, f),
4852 new_ir_seq(ctx, new_ir_move(ctx, new_ir_temp(ctx, tmp, dt, elements), fval, -1),
4853 new_ir_label(ctx, join))))))),
4854 new_ir_temp(ctx, tmp, dt, elements));
4855 } // build_ir_compare
4856
4857 #define EASY_IR_COMPARE(op) \
4858 build_ir_compare(ctx, MOJOSHADER_IR_COND_##op, \
4859 build_ir_expr(ctx, ast->binary.left), \
4860 build_ir_expr(ctx, ast->binary.right), \
4861 new_ir_constbool(ctx, 1), \
4862 new_ir_constbool(ctx, 0))
4863
4864
4865 // This handles && and || operators.
build_ir_logical_and_or(Context * ctx,const MOJOSHADER_astExpressionBinary * ast,const int left_testval)4866 static MOJOSHADER_irExpression *build_ir_logical_and_or(Context *ctx,
4867 const MOJOSHADER_astExpressionBinary *ast,
4868 const int left_testval)
4869 {
4870 /* The gist...
4871 cjump left == left_testval, maybe, f
4872 maybe:
4873 cjump right == true, t, f
4874 t:
4875 move tmp, 1
4876 jump join
4877 f:
4878 move tmp, 0
4879 join:
4880 */
4881
4882 assert(ast->left->datatype->type == MOJOSHADER_AST_DATATYPE_BOOL);
4883 assert(ast->right->datatype->type == MOJOSHADER_AST_DATATYPE_BOOL);
4884
4885 const int t = generate_ir_label(ctx);
4886 const int f = generate_ir_label(ctx);
4887 const int maybe = generate_ir_label(ctx);
4888 const int join = generate_ir_label(ctx);
4889 const int tmp = generate_ir_temp(ctx);
4890
4891 return new_ir_eseq(ctx,
4892 new_ir_seq(ctx, new_ir_cjump(ctx, MOJOSHADER_IR_COND_EQL, build_ir_expr(ctx, ast->left), new_ir_constbool(ctx, left_testval), maybe, f),
4893 new_ir_seq(ctx, new_ir_label(ctx, maybe),
4894 new_ir_seq(ctx, new_ir_cjump(ctx, MOJOSHADER_IR_COND_EQL, build_ir_expr(ctx, ast->right), new_ir_constbool(ctx, 1), t, f),
4895 new_ir_seq(ctx, new_ir_label(ctx, t),
4896 new_ir_seq(ctx, new_ir_move(ctx, new_ir_temp(ctx, tmp, MOJOSHADER_AST_DATATYPE_BOOL, 1), new_ir_constbool(ctx, 1), -1),
4897 new_ir_seq(ctx, new_ir_jump(ctx, join),
4898 new_ir_seq(ctx, new_ir_label(ctx, f),
4899 new_ir_seq(ctx, new_ir_move(ctx, new_ir_temp(ctx, tmp, MOJOSHADER_AST_DATATYPE_BOOL, 1), new_ir_constbool(ctx, 0), -1),
4900 new_ir_label(ctx, join))))))))),
4901 new_ir_temp(ctx, tmp, MOJOSHADER_AST_DATATYPE_BOOL, 1));
4902 } // build_ir_logical_and_or
4903
build_ir_logical_and(Context * ctx,const MOJOSHADER_astExpressionBinary * ast)4904 static inline MOJOSHADER_irExpression *build_ir_logical_and(Context *ctx,
4905 const MOJOSHADER_astExpressionBinary *ast)
4906 {
4907 // this needs to not evaluate (right) if (left) is false!
4908 return build_ir_logical_and_or(ctx, ast, 1);
4909 } // build_ir_logical_and
4910
build_ir_logical_or(Context * ctx,const MOJOSHADER_astExpressionBinary * ast)4911 static inline MOJOSHADER_irExpression *build_ir_logical_or(Context *ctx,
4912 const MOJOSHADER_astExpressionBinary *ast)
4913 {
4914 // this needs to not evaluate (right) if (left) is true!
4915 return build_ir_logical_and_or(ctx, ast, 0);
4916 } // build_ir_logical_or
4917
build_ir_no_op(Context * ctx)4918 static inline MOJOSHADER_irStatement *build_ir_no_op(Context *ctx)
4919 {
4920 return new_ir_label(ctx, generate_ir_label(ctx));
4921 } // build_ir_no_op
4922
build_ir_ifstmt(Context * ctx,const MOJOSHADER_astIfStatement * ast)4923 static MOJOSHADER_irStatement *build_ir_ifstmt(Context *ctx,
4924 const MOJOSHADER_astIfStatement *ast)
4925 {
4926 assert(ast->expr->datatype->type == MOJOSHADER_AST_DATATYPE_BOOL);
4927
4928 // !!! FIXME: ast->attributes?
4929
4930 // IF statement without an ELSE.
4931 if (ast->else_statement == NULL)
4932 {
4933 /* The gist...
4934 cjump expr, t, join
4935 t:
4936 statement
4937 join:
4938 */
4939
4940 const int t = generate_ir_label(ctx);
4941 const int join = generate_ir_label(ctx);
4942
4943 return new_ir_seq(ctx, new_ir_cjump(ctx, MOJOSHADER_IR_COND_EQL, build_ir_expr(ctx, ast->expr), new_ir_constbool(ctx, 1), t, join),
4944 new_ir_seq(ctx, new_ir_label(ctx, t),
4945 new_ir_seq(ctx, build_ir_stmt(ctx, ast->statement),
4946 new_ir_seq(ctx, new_ir_label(ctx, join),
4947 build_ir_stmt(ctx, ast->next)))));
4948 } // if
4949
4950 // IF statement _with_ an ELSE.
4951 /* The gist...
4952 cjump expr, t, f
4953 t:
4954 statement
4955 jump join
4956 f:
4957 elsestatement
4958 join:
4959 */
4960
4961 const int t = generate_ir_label(ctx);
4962 const int f = generate_ir_label(ctx);
4963 const int join = generate_ir_label(ctx);
4964
4965 return new_ir_seq(ctx, new_ir_cjump(ctx, MOJOSHADER_IR_COND_EQL, build_ir_expr(ctx, ast->expr), new_ir_constbool(ctx, 1), t, f),
4966 new_ir_seq(ctx, new_ir_label(ctx, t),
4967 new_ir_seq(ctx, build_ir_stmt(ctx, ast->statement),
4968 new_ir_seq(ctx, new_ir_jump(ctx, join),
4969 new_ir_seq(ctx, new_ir_label(ctx, f),
4970 new_ir_seq(ctx, build_ir_stmt(ctx, ast->else_statement),
4971 new_ir_seq(ctx, new_ir_label(ctx, join),
4972 build_ir_stmt(ctx, ast->next))))))));
4973 } // build_ir_ifstmt
4974
4975
build_ir_forstmt(Context * ctx,const MOJOSHADER_astForStatement * ast)4976 static MOJOSHADER_irStatement *build_ir_forstmt(Context *ctx,
4977 const MOJOSHADER_astForStatement *ast)
4978 {
4979 // !!! FIXME: ast->unroll
4980
4981 assert(ast->looptest->datatype->type == MOJOSHADER_AST_DATATYPE_BOOL);
4982
4983 /* The gist...
4984 initializer // (or var_decl->initializer!)
4985 test:
4986 cjump looptest == true, loop, join
4987 loop:
4988 statement
4989 increment: // needs to be here; this is where "continue" jumps!
4990 counter
4991 jump test
4992 join:
4993 */
4994
4995 const int test = generate_ir_label(ctx);
4996 const int loop = generate_ir_label(ctx);
4997
4998 const LoopLabels *labels = push_ir_loop(ctx, 0);
4999 if (labels == NULL)
5000 return NULL; // out of memory...
5001
5002 const int increment = labels->start;
5003 const int join = labels->end;
5004
5005 assert( (ast->var_decl && !ast->initializer) ||
5006 (!ast->var_decl && ast->initializer) );
5007
5008 MOJOSHADER_irStatement *init = NULL;
5009 if (ast->var_decl != NULL)
5010 {
5011 //sdfsdf
5012 // !!! FIXME: map the initializer to the variable? Need fix to var_decl parsing.
5013 // new_ir_move(ctx, FIXME MAP TO REGISTER ast->var_decl->index, build_ir_expr(ctx, ast->fsdf));
5014 // FIXME
5015 // init = build_ir_vardecl(ctx, ast->var_decl);
5016 } // if
5017 else
5018 {
5019 // init = build_ir_expr(ctx, ast->initializer);
5020 } // else
5021
5022 MOJOSHADER_irStatement *retval =
5023 new_ir_seq(ctx, init,
5024 new_ir_seq(ctx, new_ir_label(ctx, test),
5025 new_ir_seq(ctx, new_ir_cjump(ctx, MOJOSHADER_IR_COND_EQL, build_ir_expr(ctx, ast->looptest), new_ir_constbool(ctx, 1), loop, join),
5026 new_ir_seq(ctx, new_ir_label(ctx, loop),
5027 new_ir_seq(ctx, build_ir_stmt(ctx, ast->statement),
5028 new_ir_seq(ctx, new_ir_label(ctx, increment),
5029 new_ir_seq(ctx, new_ir_expr_stmt(ctx, build_ir_expr(ctx, ast->counter)),
5030 new_ir_seq(ctx, new_ir_jump(ctx, test),
5031 new_ir_label(ctx, join)))))))));
5032
5033 pop_ir_loop(ctx);
5034
5035 return new_ir_seq(ctx, retval, build_ir_stmt(ctx, ast->next));
5036 } // build_ir_forstmt
5037
build_ir_whilestmt(Context * ctx,const MOJOSHADER_astWhileStatement * ast)5038 static MOJOSHADER_irStatement *build_ir_whilestmt(Context *ctx,
5039 const MOJOSHADER_astWhileStatement *ast)
5040 {
5041 // !!! FIXME: ast->unroll
5042
5043 assert(ast->expr->datatype->type == MOJOSHADER_AST_DATATYPE_BOOL);
5044
5045 /* The gist...
5046 loop:
5047 cjump expr == true, t, join
5048 t:
5049 statement
5050 jump loop
5051 join:
5052 */
5053
5054 const LoopLabels *labels = push_ir_loop(ctx, 0);
5055 if (labels == NULL)
5056 return NULL; // out of memory...
5057
5058 const int loop = labels->start;
5059 const int t = generate_ir_label(ctx);
5060 const int join = labels->end;
5061
5062 MOJOSHADER_irStatement *retval =
5063 new_ir_seq(ctx, new_ir_label(ctx, loop),
5064 new_ir_seq(ctx, new_ir_cjump(ctx, MOJOSHADER_IR_COND_EQL, build_ir_expr(ctx, ast->expr), new_ir_constbool(ctx, 1), t, join),
5065 new_ir_seq(ctx, new_ir_label(ctx, t),
5066 new_ir_seq(ctx, build_ir_stmt(ctx, ast->statement),
5067 new_ir_seq(ctx, new_ir_jump(ctx, loop),
5068 new_ir_label(ctx, join))))));
5069
5070 pop_ir_loop(ctx);
5071
5072 return new_ir_seq(ctx, retval, build_ir_stmt(ctx, ast->next));
5073 } // build_ir_whilestmt
5074
build_ir_dostmt(Context * ctx,const MOJOSHADER_astDoStatement * ast)5075 static MOJOSHADER_irStatement *build_ir_dostmt(Context *ctx,
5076 const MOJOSHADER_astDoStatement *ast)
5077 {
5078 // !!! FIXME: ast->unroll
5079
5080 assert(ast->expr->datatype->type == MOJOSHADER_AST_DATATYPE_BOOL);
5081
5082 /* The gist...
5083 loop:
5084 statement
5085 cjump expr == true, loop, join
5086 join:
5087 */
5088
5089 const LoopLabels *labels = push_ir_loop(ctx, 0);
5090 if (labels == NULL)
5091 return NULL; // out of memory...
5092
5093 const int loop = labels->start;
5094 const int join = labels->end;
5095
5096 MOJOSHADER_irStatement *retval =
5097 new_ir_seq(ctx, new_ir_label(ctx, loop),
5098 new_ir_seq(ctx, build_ir_stmt(ctx, ast->statement),
5099 new_ir_seq(ctx, new_ir_cjump(ctx, MOJOSHADER_IR_COND_EQL, build_ir_expr(ctx, ast->expr), new_ir_constbool(ctx, 1), loop, join),
5100 new_ir_label(ctx, join))));
5101
5102 pop_ir_loop(ctx);
5103
5104 return new_ir_seq(ctx, retval, build_ir_stmt(ctx, ast->next));
5105 } // build_ir_dostmt
5106
build_ir_switch(Context * ctx,const MOJOSHADER_astSwitchStatement * ast)5107 static MOJOSHADER_irStatement *build_ir_switch(Context *ctx, const MOJOSHADER_astSwitchStatement *ast)
5108 {
5109 // Dithering down to a list of if-statements in all cases
5110 // isn't ideal, but we can't do jumptables in D3D bytecode.
5111
5112 // !!! FIXME: attributes?
5113
5114 /* The gist...
5115 move tmp, expr
5116 cjump tmp == case1expr, case1, testcase2
5117 testcase2: // etc
5118 cjump tmp == case2expr, case2, join
5119 case1:
5120 case1stmt // might have a break in it somewhere.
5121 case2:
5122 case2stmt
5123 join:
5124 */
5125
5126 const LoopLabels *labels = push_ir_loop(ctx, 1);
5127 if (labels == NULL)
5128 return NULL; // out of memory...
5129
5130 const int join = labels->end;
5131 const int elems = datatype_elems(ctx, ast->expr->datatype);
5132 const MOJOSHADER_astDataTypeType dt = datatype_base(ctx, ast->expr->datatype)->type;
5133
5134 const MOJOSHADER_astSwitchCases *cases = ast->cases;
5135 const int tmp = generate_ir_temp(ctx);
5136 MOJOSHADER_irStatement *startseqs = new_ir_move(ctx, new_ir_temp(ctx, tmp, dt, elems), build_ir_expr(ctx, ast->expr), -1);
5137 MOJOSHADER_irStatement *testseqs = startseqs;
5138 MOJOSHADER_irStatement *startcaseseqs = NULL;
5139 MOJOSHADER_irStatement *caseseqs = NULL;
5140 while (cases)
5141 {
5142 const int t = generate_ir_label(ctx);
5143 const int f = (cases->next == NULL) ? join : generate_ir_label(ctx);
5144 MOJOSHADER_irStatement *cjump = new_ir_cjump(ctx, MOJOSHADER_IR_COND_EQL, build_ir_expr(ctx, cases->expr), new_ir_temp(ctx, tmp, dt, elems), t, f);
5145
5146 if (cases->next == NULL) // last one, do the join label.
5147 {
5148 testseqs = new_ir_seq(ctx, testseqs, cjump);
5149 caseseqs = new_ir_seq(ctx, caseseqs, new_ir_seq(ctx, new_ir_label(ctx, t), build_ir_stmt(ctx, cases->statement)));
5150 caseseqs = new_ir_seq(ctx, caseseqs, new_ir_label(ctx, f));
5151 } // if
5152 else
5153 {
5154 testseqs = new_ir_seq(ctx, testseqs, new_ir_seq(ctx, cjump, new_ir_label(ctx, f)));
5155 caseseqs = new_ir_seq(ctx, caseseqs, new_ir_seq(ctx, new_ir_label(ctx, t), build_ir_stmt(ctx, cases->statement)));
5156 } // else
5157
5158 if (startcaseseqs == NULL)
5159 startcaseseqs = caseseqs;
5160
5161 cases = cases->next;
5162 } // while
5163
5164 pop_ir_loop(ctx);
5165
5166 return new_ir_seq(ctx, startseqs, new_ir_seq(ctx, startcaseseqs, build_ir_stmt(ctx, ast->next)));
5167 } // build_ir_switch
5168
build_ir_increxpr(Context * ctx,const MOJOSHADER_astDataType * _dt,const int val)5169 static MOJOSHADER_irExpression *build_ir_increxpr(Context *ctx, const MOJOSHADER_astDataType *_dt,
5170 const int val)
5171 {
5172 const MOJOSHADER_astDataType *dt = reduce_datatype(ctx, _dt);
5173 const MOJOSHADER_astDataTypeType type = datatype_base(ctx, dt)->type;
5174 const int elems = datatype_elems(ctx, dt);
5175 MOJOSHADER_irConstant *retval = (MOJOSHADER_irConstant *) new_ir_constant(ctx, type, elems);
5176 int i;
5177
5178 switch (type)
5179 {
5180 case MOJOSHADER_AST_DATATYPE_BOOL:
5181 case MOJOSHADER_AST_DATATYPE_INT:
5182 case MOJOSHADER_AST_DATATYPE_UINT:
5183 for (i = 0; i < elems; i++)
5184 retval->value.ival[i] = (int) val;
5185 break;
5186
5187 case MOJOSHADER_AST_DATATYPE_FLOAT:
5188 case MOJOSHADER_AST_DATATYPE_FLOAT_SNORM:
5189 case MOJOSHADER_AST_DATATYPE_FLOAT_UNORM:
5190 case MOJOSHADER_AST_DATATYPE_HALF:
5191 case MOJOSHADER_AST_DATATYPE_DOUBLE:
5192 for (i = 0; i < elems; i++)
5193 retval->value.fval[i] = (float) val;
5194 break;
5195
5196 default:
5197 assert(0 && "Semantic analysis should have caught this!");
5198 } // switch
5199
5200 return (MOJOSHADER_irExpression *) retval;
5201 } // build_ir_increxpr
5202
build_ir_preincdec(Context * ctx,MOJOSHADER_astExpressionUnary * ast,const MOJOSHADER_irBinOpType binop)5203 static MOJOSHADER_irExpression *build_ir_preincdec(Context *ctx, MOJOSHADER_astExpressionUnary *ast, const MOJOSHADER_irBinOpType binop)
5204 {
5205 /* The gist...
5206 move expr, expr + 1
5207 return expr
5208 */
5209 // !!! FIXME: can you writemask an increment operator?
5210 MOJOSHADER_irExpression *constant = build_ir_increxpr(ctx, ast->datatype, 1);
5211 return new_ir_eseq(ctx,
5212 new_ir_move(ctx,
5213 build_ir_expr(ctx, ast->operand),
5214 new_ir_binop(ctx, binop, build_ir_expr(ctx, ast->operand), constant), -1),
5215 build_ir_expr(ctx, ast->operand));
5216 } // build_ir_preincdec
5217
build_ir_postincdec(Context * ctx,MOJOSHADER_astExpressionUnary * ast,const MOJOSHADER_irBinOpType binop)5218 static MOJOSHADER_irExpression *build_ir_postincdec(Context *ctx, MOJOSHADER_astExpressionUnary *ast, const MOJOSHADER_irBinOpType binop)
5219 {
5220 /* The gist...
5221 move tmp, expr
5222 move expr, expr + 1
5223 return tmp
5224 */
5225
5226 // !!! FIXME: can you writemask an increment operator?
5227 MOJOSHADER_irExpression *constant = build_ir_increxpr(ctx, ast->datatype, 1);
5228 const int tmp = generate_ir_temp(ctx);
5229 return new_ir_eseq(ctx,
5230 new_ir_seq(ctx,
5231 new_ir_move(ctx, new_ir_temp(ctx, tmp, constant->info.type, constant->info.elements), build_ir_expr(ctx, ast->operand), -1),
5232 new_ir_move(ctx, build_ir_expr(ctx, ast->operand),
5233 new_ir_binop(ctx, binop, build_ir_expr(ctx, ast->operand), constant), -1)),
5234 new_ir_temp(ctx, tmp, constant->info.type, constant->info.elements));
5235 } // build_ir_postincdec
5236
build_ir_convert(Context * ctx,const MOJOSHADER_astExpressionCast * ast)5237 static MOJOSHADER_irExpression *build_ir_convert(Context *ctx, const MOJOSHADER_astExpressionCast *ast)
5238 {
5239 const MOJOSHADER_astDataType *dt = reduce_datatype(ctx, ast->datatype);
5240 const MOJOSHADER_astDataTypeType type = datatype_base(ctx, dt)->type;
5241 const int elems = datatype_elems(ctx, dt);
5242 return new_ir_convert(ctx, build_ir_expr(ctx, ast->operand), type, elems);
5243 } // build_ir_convert
5244
build_ir_exprlist(Context * ctx,MOJOSHADER_astArguments * args)5245 static MOJOSHADER_irExprList *build_ir_exprlist(Context *ctx, MOJOSHADER_astArguments *args)
5246 {
5247 MOJOSHADER_irExprList *retval = NULL;
5248 MOJOSHADER_irExprList *prev = NULL;
5249
5250 while (args != NULL)
5251 {
5252 assert((retval && prev) || ((!retval) && (!prev)));
5253
5254 MOJOSHADER_irExprList *item = new_ir_exprlist(ctx, build_ir_expr(ctx, args->argument));
5255 if (prev == NULL)
5256 prev = retval = item;
5257 else
5258 prev->next = item;
5259
5260 args = args->next;
5261 } // while
5262
5263 return retval;
5264 } // build_ir_exprlist
5265
build_ir_constructor(Context * ctx,const MOJOSHADER_astExpressionConstructor * ast)5266 static MOJOSHADER_irExpression *build_ir_constructor(Context *ctx, const MOJOSHADER_astExpressionConstructor *ast)
5267 {
5268 const MOJOSHADER_astDataType *dt = reduce_datatype(ctx, ast->datatype);
5269 const MOJOSHADER_astDataTypeType type = datatype_base(ctx, dt)->type;
5270 const int elems = datatype_elems(ctx, dt);
5271 assert(elems <= 16); // just in case (matrix4x4 constructor is largest).
5272 return new_ir_construct(ctx, build_ir_exprlist(ctx, ast->args), type, elems);
5273 } // build_ir_constructor
5274
build_ir_call(Context * ctx,const MOJOSHADER_astExpressionCallFunction * ast)5275 static MOJOSHADER_irExpression *build_ir_call(Context *ctx, const MOJOSHADER_astExpressionCallFunction *ast)
5276 {
5277 const MOJOSHADER_astDataType *dt = reduce_datatype(ctx, ast->datatype);
5278 const MOJOSHADER_astDataTypeType type = datatype_base(ctx, dt)->type;
5279 const int elems = datatype_elems(ctx, dt);
5280 return new_ir_call(ctx, ast->identifier->index, build_ir_exprlist(ctx, ast->args), type, elems);
5281 } // build_ir_call
5282
swiz_to_channel(const char swiz)5283 static char swiz_to_channel(const char swiz)
5284 {
5285 if ((swiz == 'r') || (swiz == 'x')) return 0;
5286 if ((swiz == 'g') || (swiz == 'y')) return 1;
5287 if ((swiz == 'b') || (swiz == 'z')) return 2;
5288 if ((swiz == 'a') || (swiz == 'w')) return 3;
5289 assert(0 && "Should have been caught by semantic analysis.");
5290 return 0;
5291 } // swiz_to_channel
5292
build_ir_swizzle(Context * ctx,const MOJOSHADER_astExpressionDerefStruct * ast)5293 static MOJOSHADER_irExpression *build_ir_swizzle(Context *ctx, const MOJOSHADER_astExpressionDerefStruct *ast)
5294 {
5295 const MOJOSHADER_astDataType *dt = reduce_datatype(ctx, ast->datatype);
5296 const MOJOSHADER_astDataTypeType type = datatype_base(ctx, dt)->type;
5297 const int elems = datatype_elems(ctx, dt);
5298 char chans[4] = { 0, 0, 0, 0 };
5299 const char *swizstr = ast->member;
5300 int i;
5301
5302 for (i = 0; swizstr[i]; i++)
5303 chans[i] = swiz_to_channel(swizstr[i]);
5304
5305 return new_ir_swizzle(ctx, build_ir_expr(ctx, ast->identifier), chans, type, elems);
5306 } // build_ir_swizzle
5307
build_ir_identifier(Context * ctx,const MOJOSHADER_astExpressionIdentifier * ast)5308 static MOJOSHADER_irExpression *build_ir_identifier(Context *ctx, const MOJOSHADER_astExpressionIdentifier *ast)
5309 {
5310 const MOJOSHADER_astDataType *dt = reduce_datatype(ctx, ast->datatype);
5311 const MOJOSHADER_astDataTypeType type = datatype_base(ctx, dt)->type;
5312 const int elems = datatype_elems(ctx, dt);
5313 return new_ir_memory(ctx, ast->index, type, elems);
5314 } // build_ir_identifier
5315
build_ir_derefstruct(Context * ctx,const MOJOSHADER_astExpressionDerefStruct * ast)5316 static MOJOSHADER_irExpression *build_ir_derefstruct(Context *ctx, const MOJOSHADER_astExpressionDerefStruct *ast)
5317 {
5318 // There are only three possible IR nodes that contain a struct:
5319 // an irTemp, an irMemory, or an irESeq that results in a temp or memory.
5320 // As such, we figure out which it is, and offset appropriately for the
5321 // member.
5322 const MOJOSHADER_astDataType *dt = reduce_datatype(ctx, ast->datatype);
5323 const MOJOSHADER_astDataTypeType type = datatype_base(ctx, dt)->type;
5324 const int elems = datatype_elems(ctx, dt);
5325 MOJOSHADER_irExpression *expr = build_ir_expr(ctx, ast->identifier);
5326 MOJOSHADER_irExpression *finalexpr = expr;
5327
5328 if (expr == NULL)
5329 return NULL;
5330
5331 assert(!ast->isswizzle);
5332
5333 while (finalexpr->ir.type == MOJOSHADER_IR_ESEQ)
5334 finalexpr = finalexpr->eseq.expr;
5335
5336 if (finalexpr->ir.type == MOJOSHADER_IR_TEMP)
5337 finalexpr->temp.index += ast->member_index;
5338 else if (finalexpr->ir.type == MOJOSHADER_IR_MEMORY)
5339 finalexpr->memory.index += ast->member_index;
5340 else
5341 assert(0 && "Unexpected condition");
5342
5343 // Replace the struct type with the type of the member.
5344 expr->info.type = type;
5345 expr->info.elements = elems;
5346
5347 return expr;
5348 } // build_ir_derefstruct
5349
build_ir_derefarray(Context * ctx,const MOJOSHADER_astExpressionBinary * ast)5350 static MOJOSHADER_irExpression *build_ir_derefarray(Context *ctx, const MOJOSHADER_astExpressionBinary *ast)
5351 {
5352 // In most compilers, arrays dither down to offsets into memory, but
5353 // they're somewhat special in D3D, since they might have to deal with
5354 // vectors, etc...so we keep them as first-class citizens of the IR,
5355 // and let the optimizer/codegen sort it out.
5356 // !!! FIXME: this might be the wrong move. Maybe remove this IR node type?
5357 const MOJOSHADER_astDataType *dt = reduce_datatype(ctx, ast->datatype);
5358 const MOJOSHADER_astDataTypeType type = datatype_base(ctx, dt)->type;
5359 const int elems = datatype_elems(ctx, dt);
5360
5361 // !!! FIXME: Array dereference of a vector can become a simple swizzle operation, if we have a constant index.
5362 // !!! FIXME: Matrix dereference of a vector can become a simple reference to a temp/memory, if we have a constant index.
5363 return new_ir_array(ctx, build_ir_expr(ctx, ast->left), build_ir_expr(ctx, ast->right), type, elems);
5364 } // build_ir_derefarray
5365
build_ir_assign_binop(Context * ctx,const MOJOSHADER_irBinOpType op,const MOJOSHADER_astExpressionBinary * ast)5366 static MOJOSHADER_irExpression *build_ir_assign_binop(Context *ctx,
5367 const MOJOSHADER_irBinOpType op,
5368 const MOJOSHADER_astExpressionBinary *ast)
5369 {
5370 MOJOSHADER_irExpression *lvalue = build_ir_expr(ctx, ast->left);
5371 MOJOSHADER_irExpression *rvalue = build_ir_expr(ctx, ast->right);
5372 const MOJOSHADER_astDataTypeType type = lvalue->info.type;
5373 const int elems = lvalue->info.elements;
5374 const int tmp = generate_ir_temp(ctx);
5375
5376 // Semantic analysis should have inserted casts if necessary.
5377 assert(type == rvalue->info.type);
5378 assert(elems == rvalue->info.elements);
5379
5380 // The destination must eventually be lvalue, which means memory or temp.
5381 MOJOSHADER_irExpression *dst = lvalue;
5382 while (dst->ir.type == MOJOSHADER_IR_ESEQ)
5383 dst = dst->eseq.expr;
5384
5385 if (dst->ir.type == MOJOSHADER_IR_TEMP)
5386 dst = new_ir_temp(ctx, dst->temp.index, dst->info.type, dst->info.elements);
5387 else if (dst->ir.type == MOJOSHADER_IR_MEMORY)
5388 dst = new_ir_memory(ctx, dst->memory.index, dst->info.type, dst->info.elements);
5389 else
5390 assert(0 && "Unexpected condition");
5391
5392 // !!! FIXME: write masking!
5393 return new_ir_eseq(ctx,
5394 new_ir_seq(ctx,
5395 new_ir_move(ctx, new_ir_temp(ctx, tmp, type, elems), new_ir_binop(ctx, op, lvalue, rvalue), -1),
5396 new_ir_move(ctx, dst, new_ir_temp(ctx, tmp, type, elems), -1)),
5397 new_ir_temp(ctx, tmp, type, elems));
5398 } // build_ir_assign_binop
5399
build_ir_assign(Context * ctx,const MOJOSHADER_astExpressionBinary * ast)5400 static MOJOSHADER_irExpression *build_ir_assign(Context *ctx,
5401 const MOJOSHADER_astExpressionBinary *ast)
5402 {
5403 MOJOSHADER_irExpression *lvalue = build_ir_expr(ctx, ast->left);
5404 MOJOSHADER_irExpression *rvalue = build_ir_expr(ctx, ast->right);
5405 const MOJOSHADER_astDataTypeType type = lvalue->info.type;
5406 const int elems = lvalue->info.elements;
5407 const int tmp = generate_ir_temp(ctx);
5408
5409 // Semantic analysis should have inserted casts if necessary.
5410 assert(type == rvalue->info.type);
5411 assert(elems == rvalue->info.elements);
5412
5413 // !!! FIXME: write masking!
5414 // !!! FIXME: whole array/struct assignments need to become a sequence of moves.
5415 return new_ir_eseq(ctx,
5416 new_ir_seq(ctx,
5417 new_ir_move(ctx, new_ir_temp(ctx, tmp, type, elems), rvalue, -1),
5418 new_ir_move(ctx, lvalue, new_ir_temp(ctx, tmp, type, elems), -1)),
5419 new_ir_temp(ctx, tmp, type, elems));
5420 } // build_ir_assign
5421
5422
5423 // The AST must be perfect and normalized and sane here. If there are any
5424 // strange corner cases, you should strive to handle them in semantic
5425 // analysis, so conversion to IR can proceed with a minimum of drama.
5426 static void *build_ir_internal(Context *ctx, void *_ast);
build_ir(Context * ctx,void * _ast)5427 static inline MOJOSHADER_irNode *build_ir(Context *ctx, void *_ast)
5428 {
5429 return (MOJOSHADER_irNode *) build_ir_internal(ctx, _ast);
5430 } // build_ir
5431
build_ir_internal(Context * ctx,void * _ast)5432 static void *build_ir_internal(Context *ctx, void *_ast)
5433 {
5434 if ((_ast == NULL) || (ctx->out_of_memory))
5435 return NULL;
5436
5437 MOJOSHADER_astNode *ast = (MOJOSHADER_astNode *) _ast;
5438
5439 // upkeep so we report correct error locations...
5440 ctx->sourcefile = ast->ast.filename;
5441 ctx->sourceline = ast->ast.line;
5442
5443 switch (ast->ast.type)
5444 {
5445 case MOJOSHADER_AST_OP_PREINCREMENT: // !!! FIXME: sequence points?
5446 return build_ir_preincdec(ctx, &ast->unary, MOJOSHADER_IR_BINOP_ADD);
5447
5448 case MOJOSHADER_AST_OP_POSTINCREMENT: // !!! FIXME: sequence points?
5449 return build_ir_postincdec(ctx, &ast->unary, MOJOSHADER_IR_BINOP_ADD);
5450
5451 case MOJOSHADER_AST_OP_PREDECREMENT: // !!! FIXME: sequence points?
5452 return build_ir_preincdec(ctx, &ast->unary, MOJOSHADER_IR_BINOP_SUBTRACT);
5453
5454 case MOJOSHADER_AST_OP_POSTDECREMENT: // !!! FIXME: sequence points?
5455 return build_ir_postincdec(ctx, &ast->unary, MOJOSHADER_IR_BINOP_SUBTRACT);
5456
5457 case MOJOSHADER_AST_OP_COMPLEMENT:
5458 return NEW_IR_BINOP(XOR, build_ir_expr(ctx, ast->unary.operand),
5459 new_ir_constint(ctx, 0xFFFFFFFF));
5460
5461 case MOJOSHADER_AST_OP_NEGATE: // !!! FIXME: -0.0f != +0.0f
5462 return NEW_IR_BINOP(SUBTRACT, build_ir_increxpr(ctx, ast->unary.datatype, -1),
5463 build_ir_expr(ctx, ast->unary.operand));
5464
5465 case MOJOSHADER_AST_OP_NOT: // operand must be bool here!
5466 assert(ast->unary.operand->datatype->type == MOJOSHADER_AST_DATATYPE_BOOL);
5467 return NEW_IR_BINOP(XOR, build_ir_expr(ctx, ast->unary.operand),
5468 new_ir_constint(ctx, 1));
5469
5470 case MOJOSHADER_AST_OP_DEREF_ARRAY:
5471 return build_ir_derefarray(ctx, &ast->binary);
5472
5473 case MOJOSHADER_AST_OP_DEREF_STRUCT:
5474 if (ast->derefstruct.isswizzle)
5475 return build_ir_swizzle(ctx, &ast->derefstruct);
5476 return build_ir_derefstruct(ctx, &ast->derefstruct);
5477
5478 case MOJOSHADER_AST_OP_COMMA:
5479 // evaluate and throw away left, return right.
5480 return new_ir_eseq(ctx, new_ir_expr_stmt(ctx, build_ir_expr(ctx, ast->binary.left)),
5481 build_ir_expr(ctx, ast->binary.right));
5482
5483 case MOJOSHADER_AST_OP_LESSTHAN: return EASY_IR_COMPARE(LT);
5484 case MOJOSHADER_AST_OP_GREATERTHAN: return EASY_IR_COMPARE(GT);
5485 case MOJOSHADER_AST_OP_LESSTHANOREQUAL: return EASY_IR_COMPARE(LEQ);
5486 case MOJOSHADER_AST_OP_GREATERTHANOREQUAL: return EASY_IR_COMPARE(GEQ);
5487 case MOJOSHADER_AST_OP_NOTEQUAL: return EASY_IR_COMPARE(NEQ);
5488 case MOJOSHADER_AST_OP_EQUAL: return EASY_IR_COMPARE(EQL);
5489
5490 case MOJOSHADER_AST_OP_MULTIPLY: return EASY_IR_BINOP(MULTIPLY);
5491 case MOJOSHADER_AST_OP_DIVIDE: return EASY_IR_BINOP(DIVIDE);
5492 case MOJOSHADER_AST_OP_MODULO: return EASY_IR_BINOP(MODULO);
5493 case MOJOSHADER_AST_OP_ADD: return EASY_IR_BINOP(ADD);
5494 case MOJOSHADER_AST_OP_SUBTRACT: return EASY_IR_BINOP(SUBTRACT);
5495 case MOJOSHADER_AST_OP_LSHIFT: return EASY_IR_BINOP(LSHIFT);
5496 case MOJOSHADER_AST_OP_RSHIFT: return EASY_IR_BINOP(RSHIFT);
5497 case MOJOSHADER_AST_OP_BINARYAND: return EASY_IR_BINOP(AND);
5498 case MOJOSHADER_AST_OP_BINARYXOR: return EASY_IR_BINOP(XOR);
5499 case MOJOSHADER_AST_OP_BINARYOR: return EASY_IR_BINOP(OR);
5500
5501 case MOJOSHADER_AST_OP_LOGICALAND:
5502 return build_ir_logical_and(ctx, &ast->binary);
5503
5504 case MOJOSHADER_AST_OP_LOGICALOR:
5505 return build_ir_logical_or(ctx, &ast->binary);
5506
5507 case MOJOSHADER_AST_OP_ASSIGN:
5508 return build_ir_assign(ctx, &ast->binary);
5509
5510 case MOJOSHADER_AST_OP_MULASSIGN: return build_ir_assign_binop(ctx, MOJOSHADER_IR_BINOP_MULTIPLY, &ast->binary);
5511 case MOJOSHADER_AST_OP_DIVASSIGN: return build_ir_assign_binop(ctx, MOJOSHADER_IR_BINOP_DIVIDE, &ast->binary);
5512 case MOJOSHADER_AST_OP_MODASSIGN: return build_ir_assign_binop(ctx, MOJOSHADER_IR_BINOP_MODULO, &ast->binary);
5513 case MOJOSHADER_AST_OP_ADDASSIGN: return build_ir_assign_binop(ctx, MOJOSHADER_IR_BINOP_ADD, &ast->binary);
5514 case MOJOSHADER_AST_OP_SUBASSIGN: return build_ir_assign_binop(ctx, MOJOSHADER_IR_BINOP_SUBTRACT, &ast->binary);
5515 case MOJOSHADER_AST_OP_LSHIFTASSIGN: return build_ir_assign_binop(ctx, MOJOSHADER_IR_BINOP_LSHIFT, &ast->binary);
5516 case MOJOSHADER_AST_OP_RSHIFTASSIGN: return build_ir_assign_binop(ctx, MOJOSHADER_IR_BINOP_RSHIFT, &ast->binary);
5517 case MOJOSHADER_AST_OP_ANDASSIGN: return build_ir_assign_binop(ctx, MOJOSHADER_IR_BINOP_AND, &ast->binary);
5518 case MOJOSHADER_AST_OP_XORASSIGN: return build_ir_assign_binop(ctx, MOJOSHADER_IR_BINOP_XOR, &ast->binary);
5519 case MOJOSHADER_AST_OP_ORASSIGN: return build_ir_assign_binop(ctx, MOJOSHADER_IR_BINOP_OR, &ast->binary);
5520
5521 case MOJOSHADER_AST_OP_CONDITIONAL:
5522 assert(ast->binary.left->datatype->type == MOJOSHADER_AST_DATATYPE_BOOL);
5523 return build_ir_compare(ctx, MOJOSHADER_IR_COND_EQL,
5524 build_ir_expr(ctx, ast->ternary.left),
5525 new_ir_constbool(ctx, 1),
5526 build_ir_expr(ctx, ast->ternary.center),
5527 build_ir_expr(ctx, ast->ternary.right));
5528
5529 case MOJOSHADER_AST_OP_IDENTIFIER:
5530 return build_ir_identifier(ctx, &ast->identifier);
5531
5532 case MOJOSHADER_AST_OP_INT_LITERAL:
5533 return new_ir_constint(ctx, ast->intliteral.value);
5534
5535 case MOJOSHADER_AST_OP_FLOAT_LITERAL:
5536 return new_ir_constfloat(ctx, ast->floatliteral.value);
5537
5538 case MOJOSHADER_AST_OP_BOOLEAN_LITERAL:
5539 return new_ir_constbool(ctx, ast->boolliteral.value);
5540
5541 case MOJOSHADER_AST_OP_CALLFUNC:
5542 return build_ir_call(ctx, &ast->callfunc);
5543
5544 case MOJOSHADER_AST_OP_CONSTRUCTOR:
5545 return build_ir_constructor(ctx, &ast->constructor);
5546
5547 case MOJOSHADER_AST_OP_CAST:
5548 return build_ir_convert(ctx, &ast->cast);
5549
5550 case MOJOSHADER_AST_STATEMENT_BREAK:
5551 {
5552 const LoopLabels *labels = ctx->ir_loop;
5553 assert(labels != NULL); // semantic analysis should catch this.
5554 return new_ir_jump(ctx, labels->end);
5555 } // case
5556
5557 case MOJOSHADER_AST_STATEMENT_CONTINUE:
5558 {
5559 const LoopLabels *labels = ctx->ir_loop;
5560 assert(labels != NULL); // semantic analysis should catch this.
5561 return new_ir_jump(ctx, labels->start);
5562 } // case
5563
5564 case MOJOSHADER_AST_STATEMENT_DISCARD:
5565 return new_ir_seq(ctx, new_ir_discard(ctx), build_ir_stmt(ctx, ast->discardstmt.next));
5566
5567 case MOJOSHADER_AST_STATEMENT_EMPTY:
5568 return build_ir(ctx, ast->stmt.next); // skip it, do next thing.
5569
5570 case MOJOSHADER_AST_STATEMENT_EXPRESSION:
5571 return new_ir_seq(ctx, new_ir_expr_stmt(ctx, build_ir_expr(ctx, ast->exprstmt.expr)), build_ir_stmt(ctx, ast->exprstmt.next));
5572
5573 case MOJOSHADER_AST_STATEMENT_IF:
5574 return build_ir_ifstmt(ctx, &ast->ifstmt);
5575
5576 case MOJOSHADER_AST_STATEMENT_TYPEDEF: // ignore this, move on.
5577 return build_ir(ctx, ast->typedefstmt.next);
5578
5579 case MOJOSHADER_AST_STATEMENT_SWITCH:
5580 return build_ir_switch(ctx, &ast->switchstmt);
5581
5582 case MOJOSHADER_AST_STATEMENT_STRUCT: // ignore this, move on.
5583 return build_ir(ctx, ast->structstmt.next);
5584
5585 case MOJOSHADER_AST_STATEMENT_VARDECL: // ignore this, move on.
5586 return build_ir(ctx, ast->vardeclstmt.next);
5587
5588 case MOJOSHADER_AST_STATEMENT_BLOCK:
5589 return new_ir_seq(ctx, build_ir_stmt(ctx, ast->blockstmt.statements), build_ir_stmt(ctx, ast->blockstmt.next));
5590
5591 case MOJOSHADER_AST_STATEMENT_FOR:
5592 return build_ir_forstmt(ctx, &ast->forstmt);
5593
5594 case MOJOSHADER_AST_STATEMENT_DO:
5595 return build_ir_dostmt(ctx, &ast->dostmt);
5596
5597 case MOJOSHADER_AST_STATEMENT_WHILE:
5598 return build_ir_whilestmt(ctx, &ast->whilestmt);
5599
5600 case MOJOSHADER_AST_STATEMENT_RETURN:
5601 {
5602 const int label = ctx->ir_end;
5603 assert(label >= 0); // parser should have caught this!
5604 MOJOSHADER_irStatement *retval = NULL;
5605 if (ast->returnstmt.expr != NULL)
5606 {
5607 // !!! FIXME: whole array/struct returns need to move more into the temp.
5608 const MOJOSHADER_astDataType *dt = reduce_datatype(ctx, ast->returnstmt.expr->datatype);
5609 const MOJOSHADER_astDataTypeType type = datatype_base(ctx, dt)->type;
5610 const int elems = datatype_elems(ctx, dt);
5611 assert(ctx->ir_ret >= 0);
5612 retval = new_ir_move(ctx, new_ir_temp(ctx, ctx->ir_ret, type, elems), build_ir_expr(ctx, ast->returnstmt.expr), -1);
5613 } // if
5614 return new_ir_seq(ctx, retval, new_ir_jump(ctx, label));
5615 } // case
5616
5617 case MOJOSHADER_AST_COMPUNIT_TYPEDEF:
5618 case MOJOSHADER_AST_COMPUNIT_STRUCT:
5619 case MOJOSHADER_AST_COMPUNIT_VARIABLE:
5620 case MOJOSHADER_AST_COMPUNIT_FUNCTION:
5621 case MOJOSHADER_AST_ARGUMENTS:
5622 case MOJOSHADER_AST_OP_STRING_LITERAL:
5623 case MOJOSHADER_AST_SWITCH_CASE:
5624 case MOJOSHADER_AST_SCALAR_OR_ARRAY:
5625 case MOJOSHADER_AST_TYPEDEF:
5626 case MOJOSHADER_AST_FUNCTION_PARAMS:
5627 case MOJOSHADER_AST_FUNCTION_SIGNATURE:
5628 case MOJOSHADER_AST_STRUCT_DECLARATION:
5629 case MOJOSHADER_AST_STRUCT_MEMBER:
5630 case MOJOSHADER_AST_VARIABLE_DECLARATION:
5631 case MOJOSHADER_AST_ANNOTATION:
5632 case MOJOSHADER_AST_PACK_OFFSET:
5633 case MOJOSHADER_AST_VARIABLE_LOWLEVEL:
5634 assert(0 && "Shouldn't hit this in build_ir.");
5635 return NULL;
5636
5637 default:
5638 assert(0 && "unexpected type");
5639 return NULL;
5640 } // switch
5641 } // build_ir
5642
print_ir(FILE * io,unsigned int depth,void * _ir)5643 static void print_ir(FILE *io, unsigned int depth, void *_ir)
5644 {
5645 MOJOSHADER_irNode *ir = (MOJOSHADER_irNode *) _ir;
5646 if (ir == NULL)
5647 return;
5648
5649 const char *fname = strrchr(ir->ir.filename, '/');
5650 if (fname != NULL)
5651 fname++;
5652 else
5653 {
5654 fname = strrchr(ir->ir.filename, '\\');
5655 if (fname != NULL)
5656 fname++;
5657 else
5658 fname = ir->ir.filename;
5659 } // else
5660
5661 int i;
5662 for (i = 0; i < depth; i++)
5663 fprintf(io, " ");
5664 depth++;
5665
5666 fprintf(io, "[ %s:%d ", fname, ir->ir.line);
5667
5668 switch (ir->ir.type)
5669 {
5670 case MOJOSHADER_IR_LABEL:
5671 fprintf(io, "LABEL %d ]\n", ir->stmt.label.index);
5672 break;
5673
5674 case MOJOSHADER_IR_CONSTANT:
5675 fprintf(io, "CONSTANT ");
5676 switch (ir->expr.constant.info.type)
5677 {
5678 case MOJOSHADER_AST_DATATYPE_BOOL:
5679 case MOJOSHADER_AST_DATATYPE_INT:
5680 case MOJOSHADER_AST_DATATYPE_UINT:
5681 for (i = 0; i < ir->expr.constant.info.elements-1; i++)
5682 fprintf(io, "%d, ", ir->expr.constant.value.ival[i]);
5683 if (ir->expr.constant.info.elements > 0)
5684 fprintf(io, "%d", ir->expr.constant.value.ival[i]);
5685 break;
5686
5687 case MOJOSHADER_AST_DATATYPE_FLOAT:
5688 case MOJOSHADER_AST_DATATYPE_FLOAT_SNORM:
5689 case MOJOSHADER_AST_DATATYPE_FLOAT_UNORM:
5690 case MOJOSHADER_AST_DATATYPE_HALF:
5691 case MOJOSHADER_AST_DATATYPE_DOUBLE:
5692 for (i = 0; i < ir->expr.constant.info.elements-1; i++)
5693 fprintf(io, "%ff, ", ir->expr.constant.value.fval[i]);
5694 if (ir->expr.constant.info.elements > 0)
5695 fprintf(io, "%ff", ir->expr.constant.value.fval[i]);
5696 break;
5697
5698 default: assert(0 && "shouldn't happen");
5699 } // switch
5700 fprintf(io, " ]\n");
5701 break;
5702
5703 case MOJOSHADER_IR_TEMP:
5704 fprintf(io, "TEMP %d ]\n", ir->expr.temp.index);
5705 break;
5706
5707 case MOJOSHADER_IR_DISCARD:
5708 fprintf(io, "DISCARD ]\n");
5709 break;
5710
5711 case MOJOSHADER_IR_SWIZZLE:
5712 fprintf(io, "SWIZZLE");
5713 for (i = 0; i < ir->expr.swizzle.info.elements-1; i++)
5714 fprintf(io, " %d", (int) ir->expr.swizzle.channels[i]);
5715 fprintf(io, " ]\n");
5716 print_ir(io, depth, ir->expr.swizzle.expr);
5717 break;
5718
5719 case MOJOSHADER_IR_CONSTRUCT:
5720 fprintf(io, "CONSTRUCT ]\n");
5721 print_ir(io, depth, ir->expr.construct.args);
5722 break;
5723
5724 case MOJOSHADER_IR_CONVERT:
5725 fprintf(io, "CONVERT ]\n");
5726 print_ir(io, depth, ir->expr.convert.expr);
5727 break;
5728
5729 case MOJOSHADER_IR_BINOP:
5730 fprintf(io, "BINOP ");
5731 switch (ir->expr.binop.op)
5732 {
5733 #define PRINT_IR_BINOP(x) \
5734 case MOJOSHADER_IR_BINOP_##x: fprintf(io, #x); break;
5735 PRINT_IR_BINOP(ADD)
5736 PRINT_IR_BINOP(SUBTRACT)
5737 PRINT_IR_BINOP(MULTIPLY)
5738 PRINT_IR_BINOP(DIVIDE)
5739 PRINT_IR_BINOP(MODULO)
5740 PRINT_IR_BINOP(AND)
5741 PRINT_IR_BINOP(OR)
5742 PRINT_IR_BINOP(XOR)
5743 PRINT_IR_BINOP(LSHIFT)
5744 PRINT_IR_BINOP(RSHIFT)
5745 PRINT_IR_BINOP(UNKNOWN)
5746 #undef PRINT_IR_BINOP
5747 default: assert(0 && "unexpected case"); break;
5748 } // switch
5749 fprintf(io, " ]\n");
5750 print_ir(io, depth, ir->expr.binop.left);
5751 print_ir(io, depth, ir->expr.binop.right);
5752 break;
5753
5754 case MOJOSHADER_IR_MEMORY:
5755 fprintf(io, "MEMORY %d ]\n", ir->expr.memory.index);
5756 break;
5757
5758 case MOJOSHADER_IR_CALL:
5759 fprintf(io, "CALL %d ]\n", ir->expr.call.index);
5760 print_ir(io, depth, ir->expr.call.args);
5761 break;
5762
5763 case MOJOSHADER_IR_ESEQ:
5764 fprintf(io, "ESEQ ]\n");
5765 print_ir(io, depth, ir->expr.eseq.stmt);
5766 break;
5767
5768 case MOJOSHADER_IR_ARRAY:
5769 fprintf(io, "ARRAY ]\n");
5770 print_ir(io, depth, ir->expr.array.array);
5771 print_ir(io, depth, ir->expr.array.element);
5772 break;
5773
5774 case MOJOSHADER_IR_MOVE:
5775 fprintf(io, "MOVE ]\n");
5776 print_ir(io, depth, ir->stmt.move.dst);
5777 print_ir(io, depth, ir->stmt.move.src);
5778 break;
5779
5780 case MOJOSHADER_IR_EXPR_STMT:
5781 fprintf(io, "EXPRSTMT ]\n");
5782 print_ir(io, depth, ir->stmt.expr.expr);
5783 break;
5784
5785 case MOJOSHADER_IR_JUMP:
5786 fprintf(io, "JUMP %d ]\n", ir->stmt.jump.label);
5787 break;
5788
5789 case MOJOSHADER_IR_CJUMP:
5790 fprintf(io, "CJUMP ");
5791 switch (ir->stmt.cjump.cond)
5792 {
5793 #define PRINT_IR_COND(x) \
5794 case MOJOSHADER_IR_COND_##x: fprintf(io, #x); break;
5795 PRINT_IR_COND(EQL)
5796 PRINT_IR_COND(NEQ)
5797 PRINT_IR_COND(LT)
5798 PRINT_IR_COND(GT)
5799 PRINT_IR_COND(LEQ)
5800 PRINT_IR_COND(GEQ)
5801 PRINT_IR_COND(UNKNOWN)
5802 #undef PRINT_IR_COND
5803 default: assert(0 && "unexpected case"); break;
5804 } // switch
5805 fprintf(io, " %d %d ]\n", ir->stmt.cjump.iftrue, ir->stmt.cjump.iffalse);
5806 print_ir(io, depth, ir->stmt.cjump.left);
5807 print_ir(io, depth, ir->stmt.cjump.right);
5808 break;
5809
5810 case MOJOSHADER_IR_SEQ:
5811 fprintf(io, "SEQ ]\n");
5812 print_ir(io, depth, ir->stmt.seq.first);
5813 print_ir(io, depth, ir->stmt.seq.next); // !!! FIXME: don't recurse?
5814 break;
5815
5816 case MOJOSHADER_IR_EXPRLIST:
5817 fprintf(io, "EXPRLIST ]\n");
5818 print_ir(io, depth, ir->misc.exprlist.expr);
5819 print_ir(io, depth, ir->misc.exprlist.next); // !!! FIXME: don't recurse?
5820 break;
5821
5822 default: assert(0 && "unexpected IR node"); break;
5823 } // switch
5824 } // print_ir
5825
print_whole_ir(Context * ctx,FILE * io)5826 static void print_whole_ir(Context *ctx, FILE *io)
5827 {
5828 if (ctx->ir != NULL)
5829 {
5830 int i;
5831 for (i = 0; i <= ctx->user_func_index; i++)
5832 {
5833 printf("[FUNCTION %d ]\n", i);
5834 print_ir(io, 1, ctx->ir[i]);
5835 } // for
5836 } // if
5837 } // print_whole_ir
5838
delete_ir(Context * ctx,void * _ir)5839 static void delete_ir(Context *ctx, void *_ir)
5840 {
5841 MOJOSHADER_irNode *ir = (MOJOSHADER_irNode *) _ir;
5842 if (ir == NULL)
5843 return;
5844
5845 switch (ir->ir.type)
5846 {
5847 case MOJOSHADER_IR_JUMP:
5848 case MOJOSHADER_IR_LABEL:
5849 case MOJOSHADER_IR_CONSTANT:
5850 case MOJOSHADER_IR_TEMP:
5851 case MOJOSHADER_IR_DISCARD:
5852 case MOJOSHADER_IR_MEMORY:
5853 break; // nothing extra to free here.
5854
5855 case MOJOSHADER_IR_BINOP:
5856 delete_ir(ctx, ir->expr.binop.left);
5857 delete_ir(ctx, ir->expr.binop.right);
5858 break;
5859
5860 case MOJOSHADER_IR_CALL:
5861 delete_ir(ctx, ir->expr.call.args);
5862 break;
5863
5864 case MOJOSHADER_IR_ESEQ:
5865 delete_ir(ctx, ir->expr.eseq.stmt);
5866 delete_ir(ctx, ir->expr.eseq.expr);
5867 break;
5868
5869 case MOJOSHADER_IR_ARRAY:
5870 delete_ir(ctx, ir->expr.array.array);
5871 delete_ir(ctx, ir->expr.array.element);
5872 break;
5873
5874 case MOJOSHADER_IR_MOVE:
5875 delete_ir(ctx, ir->stmt.move.dst);
5876 delete_ir(ctx, ir->stmt.move.src);
5877 break;
5878
5879 case MOJOSHADER_IR_EXPR_STMT:
5880 delete_ir(ctx, ir->stmt.expr.expr);
5881 break;
5882
5883 case MOJOSHADER_IR_CJUMP:
5884 delete_ir(ctx, ir->stmt.cjump.left);
5885 delete_ir(ctx, ir->stmt.cjump.right);
5886 break;
5887
5888 case MOJOSHADER_IR_SEQ:
5889 delete_ir(ctx, ir->stmt.seq.first);
5890 delete_ir(ctx, ir->stmt.seq.next); // !!! FIXME: don't recurse?
5891 break;
5892
5893 case MOJOSHADER_IR_EXPRLIST:
5894 delete_ir(ctx, ir->misc.exprlist.expr);
5895 delete_ir(ctx, ir->misc.exprlist.next); // !!! FIXME: don't recurse?
5896 break;
5897
5898 case MOJOSHADER_IR_SWIZZLE:
5899 delete_ir(ctx, ir->expr.swizzle.expr);
5900 break;
5901
5902 case MOJOSHADER_IR_CONSTRUCT:
5903 delete_ir(ctx, ir->expr.construct.args);
5904 break;
5905
5906 case MOJOSHADER_IR_CONVERT:
5907 delete_ir(ctx, ir->expr.convert.expr);
5908 break;
5909
5910 default: assert(0 && "unexpected IR node"); break;
5911 } // switch
5912
5913 Free(ctx, ir);
5914 } // delete_ir
5915
intermediate_representation(Context * ctx)5916 static void intermediate_representation(Context *ctx)
5917 {
5918 const MOJOSHADER_astCompilationUnit *ast = NULL;
5919 const MOJOSHADER_astCompilationUnitFunction *astfn = NULL;
5920 const size_t arraylen = (ctx->user_func_index+1) * sizeof (MOJOSHADER_irStatement *);
5921
5922 ctx->ir = (MOJOSHADER_irStatement **)Malloc(ctx, arraylen);
5923 if (ctx->ir == NULL)
5924 return;
5925 memset(ctx->ir, '\0', arraylen);
5926
5927 ctx->ir_end = -1;
5928 ctx->ir_ret = -1;
5929
5930 for (ast = &ctx->ast->compunit; ast != NULL; ast = ast->next)
5931 {
5932 assert(ast->ast.type > MOJOSHADER_AST_COMPUNIT_START_RANGE);
5933 assert(ast->ast.type < MOJOSHADER_AST_COMPUNIT_END_RANGE);
5934 if (ast->ast.type != MOJOSHADER_AST_COMPUNIT_FUNCTION)
5935 continue; // only care about functions right now.
5936
5937 astfn = (MOJOSHADER_astCompilationUnitFunction *) ast;
5938 if (astfn->definition == NULL) // just a predeclare; skip.
5939 continue;
5940
5941 assert(ctx->ir_loop == NULL); // parser should have caught this!
5942 assert(ctx->ir_end < 0); // parser should have caught this!
5943 assert(ctx->ir_ret < 0); // parser should have caught this!
5944 const int start = generate_ir_label(ctx); // !!! FIXME: store somewhere.
5945 const int end = generate_ir_label(ctx);
5946 ctx->ir_end = end;
5947
5948 if (astfn->declaration->datatype != NULL)
5949 ctx->ir_ret = generate_ir_temp(ctx);
5950
5951 MOJOSHADER_irStatement *funcseq = new_ir_seq(ctx, new_ir_label(ctx, start), build_ir_stmt(ctx, astfn->definition));
5952 funcseq = new_ir_seq(ctx, funcseq, new_ir_label(ctx, end));
5953 assert(ctx->ir_loop == NULL); // parser should have caught this!
5954 ctx->ir_end = -1;
5955 ctx->ir_ret = -1;
5956
5957 assert(astfn->index <= ctx->user_func_index);
5958 assert(ctx->ir[astfn->index] == NULL);
5959 ctx->ir[astfn->index] = funcseq;
5960 } // for
5961
5962 print_whole_ir(ctx, stdout);
5963
5964 // done with the AST, nuke it.
5965 // !!! FIXME: we're going to need CTAB data from this at some point.
5966 delete_compilation_unit(ctx, (MOJOSHADER_astCompilationUnit *) ctx->ast);
5967 ctx->ast = NULL;
5968 } // intermediate_representation
5969
5970
5971
5972 static MOJOSHADER_astData MOJOSHADER_out_of_mem_ast_data = {
5973 1, &MOJOSHADER_out_of_mem_error, 0, 0, 0, 0, 0, 0
5974 };
5975
5976
5977 // !!! FIXME: cut and paste from assembler.
build_failed_ast(Context * ctx)5978 static const MOJOSHADER_astData *build_failed_ast(Context *ctx)
5979 {
5980 assert(isfail(ctx));
5981
5982 if (ctx->out_of_memory)
5983 return &MOJOSHADER_out_of_mem_ast_data;
5984
5985 MOJOSHADER_astData *retval = NULL;
5986 retval = (MOJOSHADER_astData *) Malloc(ctx, sizeof (MOJOSHADER_astData));
5987 if (retval == NULL)
5988 return &MOJOSHADER_out_of_mem_ast_data;
5989
5990 memset(retval, '\0', sizeof (MOJOSHADER_astData));
5991 retval->source_profile = ctx->source_profile;
5992 retval->malloc = (ctx->malloc == MOJOSHADER_internal_malloc) ? NULL : ctx->malloc;
5993 retval->free = (ctx->free == MOJOSHADER_internal_free) ? NULL : ctx->free;
5994 retval->malloc_data = ctx->malloc_data;
5995 retval->error_count = errorlist_count(ctx->errors);
5996 retval->errors = errorlist_flatten(ctx->errors);
5997
5998 if (ctx->out_of_memory)
5999 {
6000 Free(ctx, retval);
6001 return &MOJOSHADER_out_of_mem_ast_data;
6002 } // if
6003
6004 return retval;
6005 } // build_failed_ast
6006
6007
build_astdata(Context * ctx)6008 static const MOJOSHADER_astData *build_astdata(Context *ctx)
6009 {
6010 MOJOSHADER_astData *retval = NULL;
6011
6012 if (ctx->out_of_memory)
6013 return &MOJOSHADER_out_of_mem_ast_data;
6014
6015 retval = (MOJOSHADER_astData *) Malloc(ctx, sizeof (MOJOSHADER_astData));
6016 if (retval == NULL)
6017 return &MOJOSHADER_out_of_mem_ast_data;
6018
6019 memset(retval, '\0', sizeof (MOJOSHADER_astData));
6020 retval->malloc = (ctx->malloc == MOJOSHADER_internal_malloc) ? NULL : ctx->malloc;
6021 retval->free = (ctx->free == MOJOSHADER_internal_free) ? NULL : ctx->free;
6022 retval->malloc_data = ctx->malloc_data;
6023
6024 if (!isfail(ctx))
6025 {
6026 retval->source_profile = ctx->source_profile;
6027 retval->ast = ctx->ast;
6028 } // if
6029
6030 retval->error_count = errorlist_count(ctx->errors);
6031 retval->errors = errorlist_flatten(ctx->errors);
6032 if (ctx->out_of_memory)
6033 {
6034 Free(ctx, retval);
6035 return &MOJOSHADER_out_of_mem_ast_data;
6036 } // if
6037
6038 retval->opaque = ctx;
6039
6040 return retval;
6041 } // build_astdata
6042
6043
choose_src_profile(Context * ctx,const char * srcprofile)6044 static void choose_src_profile(Context *ctx, const char *srcprofile)
6045 {
6046 ctx->source_profile = srcprofile;
6047
6048 #define TEST_PROFILE(x) if (strcmp(srcprofile, x) == 0) { return; }
6049
6050 TEST_PROFILE(MOJOSHADER_SRC_PROFILE_HLSL_VS_1_1);
6051 TEST_PROFILE(MOJOSHADER_SRC_PROFILE_HLSL_VS_2_0);
6052 TEST_PROFILE(MOJOSHADER_SRC_PROFILE_HLSL_VS_3_0);
6053 TEST_PROFILE(MOJOSHADER_SRC_PROFILE_HLSL_PS_1_1);
6054 TEST_PROFILE(MOJOSHADER_SRC_PROFILE_HLSL_PS_1_2);
6055 TEST_PROFILE(MOJOSHADER_SRC_PROFILE_HLSL_PS_1_3);
6056 TEST_PROFILE(MOJOSHADER_SRC_PROFILE_HLSL_PS_1_4);
6057 TEST_PROFILE(MOJOSHADER_SRC_PROFILE_HLSL_PS_2_0);
6058 TEST_PROFILE(MOJOSHADER_SRC_PROFILE_HLSL_PS_3_0);
6059
6060 #undef TEST_PROFILE
6061
6062 fail(ctx, "Unknown profile");
6063 } // choose_src_profile
6064
6065
6066 static MOJOSHADER_compileData MOJOSHADER_out_of_mem_compile_data = {
6067 1, &MOJOSHADER_out_of_mem_error, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
6068 };
6069
6070
6071 // !!! FIXME: cut and paste from assembler.
build_failed_compile(Context * ctx)6072 static const MOJOSHADER_compileData *build_failed_compile(Context *ctx)
6073 {
6074 assert(isfail(ctx));
6075
6076 MOJOSHADER_compileData *retval = NULL;
6077 retval = (MOJOSHADER_compileData *) Malloc(ctx, sizeof (MOJOSHADER_compileData));
6078 if (retval == NULL)
6079 return &MOJOSHADER_out_of_mem_compile_data;
6080
6081 memset(retval, '\0', sizeof (MOJOSHADER_compileData));
6082 retval->malloc = (ctx->malloc == MOJOSHADER_internal_malloc) ? NULL : ctx->malloc;
6083 retval->free = (ctx->free == MOJOSHADER_internal_free) ? NULL : ctx->free;
6084 retval->malloc_data = ctx->malloc_data;
6085 retval->source_profile = ctx->source_profile;
6086 retval->error_count = errorlist_count(ctx->errors);
6087 retval->errors = errorlist_flatten(ctx->errors);
6088 retval->warning_count = errorlist_count(ctx->warnings);
6089 retval->warnings = errorlist_flatten(ctx->warnings);
6090
6091 if (ctx->out_of_memory) // in case something failed up there.
6092 {
6093 MOJOSHADER_freeCompileData(retval);
6094 return &MOJOSHADER_out_of_mem_compile_data;
6095 } // if
6096
6097 return retval;
6098 } // build_failed_compile
6099
6100
build_compiledata(Context * ctx)6101 static const MOJOSHADER_compileData *build_compiledata(Context *ctx)
6102 {
6103 assert(!isfail(ctx));
6104
6105 MOJOSHADER_compileData *retval = NULL;
6106
6107 retval = (MOJOSHADER_compileData *) Malloc(ctx, sizeof (MOJOSHADER_compileData));
6108 if (retval == NULL)
6109 return &MOJOSHADER_out_of_mem_compile_data;
6110
6111 memset(retval, '\0', sizeof (MOJOSHADER_compileData));
6112 retval->malloc = (ctx->malloc == MOJOSHADER_internal_malloc) ? NULL : ctx->malloc;
6113 retval->free = (ctx->free == MOJOSHADER_internal_free) ? NULL : ctx->free;
6114 retval->malloc_data = ctx->malloc_data;
6115 retval->source_profile = ctx->source_profile;
6116
6117 if (!isfail(ctx))
6118 {
6119 // !!! FIXME: build output and output_len here.
6120 } // if
6121
6122 if (!isfail(ctx))
6123 {
6124 // !!! FIXME: build symbols and symbol_count here.
6125 } // if
6126
6127 retval->error_count = errorlist_count(ctx->errors);
6128 retval->errors = errorlist_flatten(ctx->errors);
6129 retval->warning_count = errorlist_count(ctx->warnings);
6130 retval->warnings = errorlist_flatten(ctx->warnings);
6131
6132 if (ctx->out_of_memory) // in case something failed up there.
6133 {
6134 MOJOSHADER_freeCompileData(retval);
6135 return &MOJOSHADER_out_of_mem_compile_data;
6136 } // if
6137
6138 return retval;
6139 } // build_compiledata
6140
6141
6142 // API entry point...
6143
6144 // !!! FIXME: move this (and a lot of other things) to mojoshader_ast.c.
MOJOSHADER_parseAst(const char * srcprofile,const char * filename,const char * source,unsigned int sourcelen,const MOJOSHADER_preprocessorDefine * defs,unsigned int define_count,MOJOSHADER_includeOpen include_open,MOJOSHADER_includeClose include_close,MOJOSHADER_malloc m,MOJOSHADER_free f,void * d)6145 const MOJOSHADER_astData *MOJOSHADER_parseAst(const char *srcprofile,
6146 const char *filename, const char *source,
6147 unsigned int sourcelen,
6148 const MOJOSHADER_preprocessorDefine *defs,
6149 unsigned int define_count,
6150 MOJOSHADER_includeOpen include_open,
6151 MOJOSHADER_includeClose include_close,
6152 MOJOSHADER_malloc m, MOJOSHADER_free f,
6153 void *d)
6154 {
6155 const MOJOSHADER_astData *retval = NULL;
6156 Context *ctx = NULL;
6157
6158 if ( ((m == NULL) && (f != NULL)) || ((m != NULL) && (f == NULL)) )
6159 return &MOJOSHADER_out_of_mem_ast_data; // supply both or neither.
6160
6161 ctx = build_context(m, f, d);
6162 if (ctx == NULL)
6163 return &MOJOSHADER_out_of_mem_ast_data;
6164
6165 choose_src_profile(ctx, srcprofile);
6166
6167 if (!isfail(ctx))
6168 {
6169 parse_source(ctx, filename, source, sourcelen, defs, define_count,
6170 include_open, include_close);
6171 } // if
6172
6173 if (!isfail(ctx))
6174 retval = build_astdata(ctx); // ctx isn't destroyed yet!
6175 else
6176 {
6177 retval = (MOJOSHADER_astData *) build_failed_ast(ctx);
6178 destroy_context(ctx);
6179 } // else
6180
6181 return retval;
6182 } // MOJOSHADER_parseAst
6183
6184
MOJOSHADER_freeAstData(const MOJOSHADER_astData * _data)6185 void MOJOSHADER_freeAstData(const MOJOSHADER_astData *_data)
6186 {
6187 MOJOSHADER_astData *data = (MOJOSHADER_astData *) _data;
6188 if ((data == NULL) || (data == &MOJOSHADER_out_of_mem_ast_data))
6189 return; // no-op.
6190
6191 // !!! FIXME: this needs to live for deleting the stringcache and the ast.
6192 Context *ctx = (Context *) data->opaque;
6193 MOJOSHADER_free f = (data->free == NULL) ? MOJOSHADER_internal_free : data->free;
6194 void *d = data->malloc_data;
6195 int i;
6196
6197 // we don't f(data->source_profile), because that's internal static data.
6198
6199 for (i = 0; i < data->error_count; i++)
6200 {
6201 f((void *) data->errors[i].error, d);
6202 f((void *) data->errors[i].filename, d);
6203 } // for
6204 f((void *) data->errors, d);
6205
6206 // don't delete data->ast (it'll delete with the context).
6207 f(data, d);
6208
6209 destroy_context(ctx); // finally safe to destroy this.
6210 } // MOJOSHADER_freeAstData
6211
6212
MOJOSHADER_compile(const char * srcprofile,const char * filename,const char * source,unsigned int sourcelen,const MOJOSHADER_preprocessorDefine * defs,unsigned int define_count,MOJOSHADER_includeOpen include_open,MOJOSHADER_includeClose include_close,MOJOSHADER_malloc m,MOJOSHADER_free f,void * d)6213 const MOJOSHADER_compileData *MOJOSHADER_compile(const char *srcprofile,
6214 const char *filename, const char *source,
6215 unsigned int sourcelen,
6216 const MOJOSHADER_preprocessorDefine *defs,
6217 unsigned int define_count,
6218 MOJOSHADER_includeOpen include_open,
6219 MOJOSHADER_includeClose include_close,
6220 MOJOSHADER_malloc m, MOJOSHADER_free f,
6221 void *d)
6222 {
6223 // !!! FIXME: cut and paste from MOJOSHADER_parseAst().
6224 MOJOSHADER_compileData *retval = NULL;
6225 Context *ctx = NULL;
6226
6227 if ( ((m == NULL) && (f != NULL)) || ((m != NULL) && (f == NULL)) )
6228 return &MOJOSHADER_out_of_mem_compile_data; // supply both or neither.
6229
6230 ctx = build_context(m, f, d);
6231 if (ctx == NULL)
6232 return &MOJOSHADER_out_of_mem_compile_data;
6233
6234 choose_src_profile(ctx, srcprofile);
6235
6236 if (!isfail(ctx))
6237 {
6238 parse_source(ctx, filename, source, sourcelen, defs, define_count,
6239 include_open, include_close);
6240 } // if
6241
6242 if (!isfail(ctx))
6243 semantic_analysis(ctx);
6244
6245 if (!isfail(ctx))
6246 intermediate_representation(ctx);
6247
6248 if (isfail(ctx))
6249 retval = (MOJOSHADER_compileData *) build_failed_compile(ctx);
6250 else
6251 retval = (MOJOSHADER_compileData *) build_compiledata(ctx);
6252
6253 destroy_context(ctx);
6254 return retval;
6255 } // MOJOSHADER_compile
6256
6257
MOJOSHADER_freeCompileData(const MOJOSHADER_compileData * _data)6258 void MOJOSHADER_freeCompileData(const MOJOSHADER_compileData *_data)
6259 {
6260 MOJOSHADER_compileData *data = (MOJOSHADER_compileData *) _data;
6261 if ((data == NULL) || (data == &MOJOSHADER_out_of_mem_compile_data))
6262 return; // no-op.
6263
6264 MOJOSHADER_free f = (data->free == NULL) ? MOJOSHADER_internal_free : data->free;
6265 void *d = data->malloc_data;
6266 int i;
6267
6268 // we don't f(data->source_profile), because that's internal static data.
6269
6270 for (i = 0; i < data->error_count; i++)
6271 {
6272 f((void *) data->errors[i].error, d);
6273 f((void *) data->errors[i].filename, d);
6274 } // for
6275 f((void *) data->errors, d);
6276
6277 for (i = 0; i < data->warning_count; i++)
6278 {
6279 f((void *) data->warnings[i].error, d);
6280 f((void *) data->warnings[i].filename, d);
6281 } // for
6282 f((void *) data->warnings, d);
6283
6284 for (i = 0; i < data->symbol_count; i++)
6285 {
6286 f((void *) data->symbols[i].name, d);
6287 // !!! FIXME: this is missing stuff (including freeing substructs).
6288 } // for
6289 f((void *) data->symbols, d);
6290
6291 f((void *) data->output, d);
6292 f(data, d);
6293 } // MOJOSHADER_freeCompileData
6294
6295 // end of mojoshader_compiler.c ...
6296
6297