mojoshader_compiler.c
changeset 997 a5f4e546b24e
parent 996 164238a438e1
child 998 8f82dca9a374
equal deleted inserted replaced
996:164238a438e1 997:a5f4e546b24e
  2256         default:
  2256         default:
  2257             return 0;
  2257             return 0;
  2258     } // switch
  2258     } // switch
  2259 } // is_scalar_datatype
  2259 } // is_scalar_datatype
  2260 
  2260 
       
  2261 static inline int is_float_datatype(const MOJOSHADER_astDataType *dt)
       
  2262 {
       
  2263     switch (dt->type)
       
  2264     {
       
  2265         case MOJOSHADER_AST_DATATYPE_FLOAT: return 1;
       
  2266         case MOJOSHADER_AST_DATATYPE_FLOAT_SNORM: return 1;
       
  2267         case MOJOSHADER_AST_DATATYPE_FLOAT_UNORM: return 1;
       
  2268         default: return 0;
       
  2269     } // switch
       
  2270 } // is_float_datatype
       
  2271 
  2261 static const MOJOSHADER_astDataType *datatype_base(Context *ctx, const MOJOSHADER_astDataType *dt)
  2272 static const MOJOSHADER_astDataType *datatype_base(Context *ctx, const MOJOSHADER_astDataType *dt)
  2262 {
  2273 {
  2263     dt = reduce_datatype(ctx, dt);
  2274     dt = reduce_datatype(ctx, dt);
  2264     switch (dt->type)
  2275     switch (dt->type)
  2265     {
  2276     {
  2281     return dt;
  2292     return dt;
  2282 } // datatype_base
  2293 } // datatype_base
  2283 
  2294 
  2284 typedef enum
  2295 typedef enum
  2285 {
  2296 {
  2286     DT_MATCH_INCOMPATIBLE,
  2297     DT_MATCH_INCOMPATIBLE,         // flatly incompatible
  2287     DT_MATCH_COMPATIBLE_DOWNCAST,
  2298     DT_MATCH_COMPATIBLE_DOWNCAST,  // would have to lose precision
  2288     DT_MATCH_COMPATIBLE_UPCAST,
  2299     DT_MATCH_COMPATIBLE_UPCAST,    // would have to gain precision
  2289     DT_MATCH_COMPATIBLE,
  2300     DT_MATCH_COMPATIBLE,           // can cast to without serious change.
  2290     DT_MATCH_PERFECT
  2301     DT_MATCH_PERFECT               // identical datatype.
  2291 } DatatypeMatch;
  2302 } DatatypeMatch;
  2292 
  2303 
  2293 static DatatypeMatch compatible_arg_datatype(Context *ctx,
  2304 static DatatypeMatch compatible_arg_datatype(Context *ctx,
  2294                                    const MOJOSHADER_astDataType *arg,
  2305                                    const MOJOSHADER_astDataType *arg,
  2295                                    const MOJOSHADER_astDataType *param)
  2306                                    const MOJOSHADER_astDataType *param)
  2297     // The matching rules for HLSL function overloading, as far as I can
  2308     // The matching rules for HLSL function overloading, as far as I can
  2298     //  tell from experimenting with Microsoft's compiler, seem to be this:
  2309     //  tell from experimenting with Microsoft's compiler, seem to be this:
  2299     //
  2310     //
  2300     // - All parameters of a function must match what the caller specified
  2311     // - All parameters of a function must match what the caller specified
  2301     //   after possible type promotion via the following rules.
  2312     //   after possible type promotion via the following rules.
       
  2313     // - If the number of arguments and the number of parameters don't match,
       
  2314     //   that overload is immediately rejected.
       
  2315     // - Each overloaded function is given a score that is the sum of the
       
  2316     //   "worth" of each parameter vs the caller's arguments
       
  2317     //   (see DatatypeMatch). The higher the score, the more favorable this
       
  2318     //   function overload would be.
       
  2319     // - If there is a tie for highest score between two or more function
       
  2320     //   overloads, we declare that function call to be ambiguous and fail().
  2302     // - Scalars can be promoted to vectors to make a parameter match.
  2321     // - Scalars can be promoted to vectors to make a parameter match.
  2303     // - Scalars can promote to other scalars (short to int, etc).
  2322     // - Scalars can promote to other scalars (short to int, etc).
  2304     // - Datatypes can downcast, but should generate a warning.
  2323     // - Datatypes can downcast, but should generate a warning.
  2305     //   (calling void fn(float x); as fn((double)1.0) should warn).
  2324     //   (calling void fn(float x); as fn((double)1.0) should warn).
  2306     // - Vectors may NOT be extend (a float2 can't implicity extend to a
  2325     // - Vectors may NOT be extend (a float2 can't implicity extend to a
  2307     //   float4).
  2326     //   float4).
  2308     // - Vectors with the same elements can promote (a half2 can become
  2327     // - Vectors with the same elements can promote (a half2 can become
  2309     //   a float2...I _think_ it can't downcast here.).
  2328     //   a float2). Downcasting between vectors with the same number of
       
  2329     //   elements is allowed.
  2310     // - A perfect match of all params will be favored over any functions
  2330     // - A perfect match of all params will be favored over any functions
  2311     //   that only match if type promotion is applied.
  2331     //   that only match if type promotion is applied (given a perfect match
  2312     // - An imperfect match that doesn't require downcasting will be
  2332     //   of all parameters, we'll stop looking for other matches).
  2313     //   favored over one that does.
       
  2314     // - If more than one function matches after this (all params that
       
  2315     //   would be different between two functions can be legally type-promoted)
       
  2316     //   then fail().
       
  2317 
  2333 
  2318     if (datatypes_match(arg, param))
  2334     if (datatypes_match(arg, param))
  2319         return DT_MATCH_PERFECT;  // that was easy.
  2335         return DT_MATCH_PERFECT;  // that was easy.
  2320 
  2336 
  2321     arg = reduce_datatype(ctx, arg);
  2337     arg = reduce_datatype(ctx, arg);
  2322     param = reduce_datatype(ctx, param);
  2338     param = reduce_datatype(ctx, param);
  2323 
  2339 
  2324     int do_size_test = 0;
  2340     int do_base_test = 0;
  2325 
  2341 
  2326     if (is_scalar_datatype(arg))
  2342     if (is_scalar_datatype(arg))
  2327         do_size_test = 1; // we let these all go through for now.
  2343         do_base_test = 1; // we let these all go through for now.
  2328 
  2344 
  2329     else if (arg->type == param->type)
  2345     else if (arg->type == param->type)
  2330     {
  2346     {
  2331         if (arg->type == MOJOSHADER_AST_DATATYPE_VECTOR)
  2347         if (arg->type == MOJOSHADER_AST_DATATYPE_VECTOR)
  2332             do_size_test = (arg->vector.elements == param->vector.elements);
  2348             do_base_test = (arg->vector.elements == param->vector.elements);
  2333         else if (arg->type == MOJOSHADER_AST_DATATYPE_MATRIX)
  2349         else if (arg->type == MOJOSHADER_AST_DATATYPE_MATRIX)
  2334         {
  2350         {
  2335             do_size_test =
  2351             do_base_test =
  2336                 ((arg->matrix.rows == param->matrix.rows) &&
  2352                 ((arg->matrix.rows == param->matrix.rows) &&
  2337                  (arg->matrix.columns == param->matrix.columns));
  2353                  (arg->matrix.columns == param->matrix.columns));
  2338         } // if
  2354         } // if
  2339     } // if
  2355     } // if
  2340 
  2356 
  2341     if (do_size_test)
  2357     if (do_base_test)
  2342     {
  2358     {
  2343         const int argsize = datatype_size(datatype_base(ctx, arg));
  2359         arg = datatype_base(ctx, arg);
  2344         const int paramsize = datatype_size(datatype_base(ctx, param));
  2360         param = datatype_base(ctx, param);
  2345         if (argsize == paramsize)
  2361 
       
  2362         const int argsize = datatype_size(arg);
       
  2363         const int paramsize = datatype_size(param);
       
  2364         const int argfloat = is_float_datatype(arg);
       
  2365         const int paramfloat = is_float_datatype(param);
       
  2366 
       
  2367         if (argfloat && !paramfloat)
       
  2368             return DT_MATCH_COMPATIBLE_DOWNCAST;  // always loss of precision.
       
  2369         else if (argfloat && !paramfloat)
       
  2370         {
       
  2371             if (argsize < paramsize)
       
  2372                 return DT_MATCH_COMPATIBLE_UPCAST;
       
  2373             else
       
  2374                 return DT_MATCH_COMPATIBLE_DOWNCAST;  // loss of precision.
       
  2375         } // else if
       
  2376         else if (argsize == paramsize)
  2346             return DT_MATCH_COMPATIBLE;
  2377             return DT_MATCH_COMPATIBLE;
  2347         else if (argsize < paramsize)
  2378         else if (argsize < paramsize)
  2348             return DT_MATCH_COMPATIBLE_UPCAST;
  2379             return DT_MATCH_COMPATIBLE_UPCAST;
  2349         else /* if (argsize > paramsize) */
  2380         else /* if (argsize > paramsize) */
  2350             return DT_MATCH_COMPATIBLE_DOWNCAST;
  2381             return DT_MATCH_COMPATIBLE_DOWNCAST;
  2463 // !!! FIXME: this function sucks.
  2494 // !!! FIXME: this function sucks.
  2464 static const MOJOSHADER_astDataType *match_func_to_call(Context *ctx,
  2495 static const MOJOSHADER_astDataType *match_func_to_call(Context *ctx,
  2465                                     MOJOSHADER_astExpressionCallFunction *ast)
  2496                                     MOJOSHADER_astExpressionCallFunction *ast)
  2466 {
  2497 {
  2467     SymbolScope *best = NULL;  // best choice we find.
  2498     SymbolScope *best = NULL;  // best choice we find.
  2468     DatatypeMatch best_match = DT_MATCH_INCOMPATIBLE;
  2499     int best_score = 0;
  2469     MOJOSHADER_astExpressionIdentifier *ident = ast->identifier;
  2500     MOJOSHADER_astExpressionIdentifier *ident = ast->identifier;
  2470     const char *sym = ident->identifier;
  2501     const char *sym = ident->identifier;
  2471     const void *value = NULL;
  2502     const void *value = NULL;
  2472     void *iter = NULL;
  2503     void *iter = NULL;
  2473 
  2504 
  2478         argcount++;
  2509         argcount++;
  2479         type_check_ast(ctx, args->argument);
  2510         type_check_ast(ctx, args->argument);
  2480         args = args->next;
  2511         args = args->next;
  2481     } // while;
  2512     } // while;
  2482 
  2513 
       
  2514 #define DEBUG_OVERLOADS 1
       
  2515 #if DEBUG_OVERLOADS
  2483 printf("Attempt to call function %s(", sym);
  2516 printf("Attempt to call function %s(", sym);
  2484 args = ast->args;
  2517 args = ast->args;
  2485 int qq = 0;
  2518 int qq = 0;
  2486 for (qq = 0; qq < argcount; qq++)
  2519 for (qq = 0; qq < argcount; qq++)
  2487 {
  2520 {
  2490 args = args->next;
  2523 args = args->next;
  2491 print_ast_datatype(stdout, x);
  2524 print_ast_datatype(stdout, x);
  2492 if (args) printf(", ");
  2525 if (args) printf(", ");
  2493 }
  2526 }
  2494 printf("); ...\n");
  2527 printf("); ...\n");
       
  2528 #endif
  2495 
  2529 
  2496     // we do some tapdancing to handle function overloading here.
  2530     // we do some tapdancing to handle function overloading here.
  2497     DatatypeMatch match = 0;
  2531     int match = 0;
  2498     while (hash_iter(ctx->variables.hash, sym, &value, &iter))
  2532     while (hash_iter(ctx->variables.hash, sym, &value, &iter))
  2499     {
  2533     {
  2500         SymbolScope *item = (SymbolScope *) value;
  2534         SymbolScope *item = (SymbolScope *) value;
  2501         const MOJOSHADER_astDataType *dt = item->datatype;
  2535         const MOJOSHADER_astDataType *dt = item->datatype;
  2502         dt = reduce_datatype(ctx, dt);
  2536         dt = reduce_datatype(ctx, dt);
  2503         // there's a locally-scoped symbol with this name? It takes precedence.
  2537         // there's a locally-scoped symbol with this name? It takes precedence.
  2504         if (dt->type != MOJOSHADER_AST_DATATYPE_FUNCTION)
  2538         if (dt->type != MOJOSHADER_AST_DATATYPE_FUNCTION)
  2505             return dt;
  2539             return dt;
  2506 
  2540 
  2507         const MOJOSHADER_astDataTypeFunction *dtfn = (MOJOSHADER_astDataTypeFunction *) dt;
  2541         const MOJOSHADER_astDataTypeFunction *dtfn = (MOJOSHADER_astDataTypeFunction *) dt;
  2508         int this_match = DT_MATCH_PERFECT;
  2542         const int perfect = argcount * ((int) DT_MATCH_PERFECT);
  2509         int i;
  2543         int score = 0;
  2510 
  2544 
  2511         if (argcount != dtfn->num_params)  // !!! FIXME: default args.
  2545         if (argcount == dtfn->num_params)  // !!! FIXME: default args.
  2512             this_match = 0;
       
  2513         else
       
  2514         {
  2546         {
  2515             args = ast->args;
  2547             args = ast->args;
       
  2548             int i;
  2516             for (i = 0; i < argcount; i++)
  2549             for (i = 0; i < argcount; i++)
  2517             {
  2550             {
  2518                 assert(args != NULL);
  2551                 assert(args != NULL);
  2519                 dt = args->argument->datatype;
  2552                 dt = args->argument->datatype;
  2520                 args = args->next;
  2553                 args = args->next;
  2521                 const int compatible = compatible_arg_datatype(ctx, dt, dtfn->params[i]);
  2554                 const DatatypeMatch compatible = compatible_arg_datatype(ctx, dt, dtfn->params[i]);
  2522                 if (this_match > compatible)
  2555                 if (compatible == DT_MATCH_INCOMPATIBLE)
  2523                     this_match = compatible;
  2556                 {
  2524                 if (!this_match)
  2557                     args = NULL;
       
  2558                     score = 0;
  2525                     break;
  2559                     break;
       
  2560                 } // if
       
  2561 
       
  2562                 score += (int) compatible;
  2526             } // for
  2563             } // for
  2527 
  2564 
  2528             if (args != NULL)
  2565             if (args != NULL)
  2529                 this_match = DT_MATCH_INCOMPATIBLE;  // too many arguments supplied. No match.
  2566                 score = 0;  // too many arguments supplied. No match.
  2530         } // else
  2567         } // else
  2531 
  2568 
  2532 #if 0
  2569         if (score == 0)  // incompatible.
  2533         if (this_match == DT_MATCH_PERFECT)  // perfect match.
  2570             continue;
       
  2571 
       
  2572         else if (score == perfect)  // perfection! stop looking!
  2534         {
  2573         {
       
  2574 #if DEBUG_OVERLOADS
  2535 FILE *io = stdout;
  2575 FILE *io = stdout;
  2536 printf("%d PERFECT MATCH: ", ctx->sourceline);
  2576 printf("%d PERFECT MATCH (%d/%d): ", ctx->sourceline, score, perfect);
  2537 if (dtfn->intrinsic)
       
  2538     printf("/* intrinsic */ ");
       
  2539 print_ast_datatype(io, dt->function.retval);
       
  2540 printf(" %s(", sym);
       
  2541 int i;
       
  2542 for (i = 0; i < dtfn->num_params; i++) {
       
  2543     print_ast_datatype(io, dtfn->params[i]);
       
  2544     if (i < dtfn->num_params-1)
       
  2545         printf(", ");
       
  2546 }
       
  2547 printf(");\n");
       
  2548             match = 1;  // ignore all other compatible matches.
       
  2549             best = item;
       
  2550             break;
       
  2551         } // if
       
  2552 
       
  2553         else
       
  2554 #endif
       
  2555 
       
  2556         if (this_match > DT_MATCH_INCOMPATIBLE)  // compatible, but not perfect, match.
       
  2557         {
       
  2558 #if 1
       
  2559 FILE *io = stdout;
       
  2560 printf("%d COMPATIBLE MATCH (%d): ", ctx->sourceline, (int) this_match);
       
  2561 if (dtfn->intrinsic)
  2577 if (dtfn->intrinsic)
  2562     printf("/* intrinsic */ ");
  2578     printf("/* intrinsic */ ");
  2563 if (dt->function.retval)
  2579 if (dt->function.retval)
  2564     print_ast_datatype(io, dt->function.retval);
  2580     print_ast_datatype(io, dt->function.retval);
  2565 else
  2581 else
  2571     if (i < dtfn->num_params-1)
  2587     if (i < dtfn->num_params-1)
  2572         printf(", ");
  2588         printf(", ");
  2573 }
  2589 }
  2574 printf(");\n");
  2590 printf(");\n");
  2575 #endif
  2591 #endif
  2576 
  2592             match = 1;  // ignore all other compatible matches.
  2577             if (this_match == best_match)
  2593             best = item;
       
  2594             break;
       
  2595         } // if
       
  2596 
       
  2597         else if (score >= best_score)  // compatible, but not perfect, match.
       
  2598         {
       
  2599 #if DEBUG_OVERLOADS
       
  2600 FILE *io = stdout;
       
  2601 printf("%d COMPATIBLE MATCH (%d/%d): ", ctx->sourceline, score, perfect);
       
  2602 if (dtfn->intrinsic)
       
  2603     printf("/* intrinsic */ ");
       
  2604 if (dt->function.retval)
       
  2605     print_ast_datatype(io, dt->function.retval);
       
  2606 else
       
  2607     printf("void");
       
  2608 printf(" %s(", sym);
       
  2609 int i;
       
  2610 for (i = 0; i < dtfn->num_params; i++) {
       
  2611     print_ast_datatype(io, dtfn->params[i]);
       
  2612     if (i < dtfn->num_params-1)
       
  2613         printf(", ");
       
  2614 }
       
  2615 printf(");\n");
       
  2616 #endif
       
  2617 
       
  2618             if (score == best_score)
  2578             {
  2619             {
  2579                 match++;
  2620                 match++;
  2580                 // !!! FIXME: list each possible function in a fail(),
  2621                 // !!! FIXME: list each possible function in a fail(),
  2581                 // !!! FIXME:  but you can't actually fail() here, since
  2622                 // !!! FIXME:  but you can't actually fail() here, since
  2582                 // !!! FIXME:  this will cease to be ambiguous if we get
  2623                 // !!! FIXME:  this may cease to be ambiguous if we get
  2583                 // !!! FIXME:  a perfect match on a later overload.
  2624                 // !!! FIXME:  a better match on a later overload.
  2584             } // if
  2625             } // if
  2585             else if (this_match > best_match)
  2626 
       
  2627             else if (score > best_score)
  2586             {
  2628             {
  2587                 match = 1;  // reset the ambiguousness count.
  2629                 match = 1;  // reset the ambiguousness count.
  2588                 best = item;
  2630                 best = item;
  2589                 best_match = this_match;
  2631                 best_score = score;
  2590             } // if
  2632             } // if
  2591         } // else if
  2633         } // else if
  2592     } // while
  2634     } // while
  2593 
  2635 
  2594     if (match > 1)
  2636     if (match > 1)
  2597         failf(ctx, "Ambiguous function call to '%s'", sym);
  2639         failf(ctx, "Ambiguous function call to '%s'", sym);
  2598     } // if
  2640     } // if
  2599 
  2641 
  2600     if (best == NULL)
  2642     if (best == NULL)
  2601     {
  2643     {
  2602         assert(best == NULL);
  2644         assert(match == 0);
       
  2645         assert(best_score == 0);
       
  2646         // !!! FIXME: ident->datatype = ?
  2603         failf(ctx, "No matching function named '%s'", sym);
  2647         failf(ctx, "No matching function named '%s'", sym);
  2604     } // if
  2648     } // if
  2605     else
  2649     else
  2606     {
  2650     {
  2607         ident->datatype = reduce_datatype(ctx, best->datatype);
  2651         ident->datatype = reduce_datatype(ctx, best->datatype);