14c1403f667c6047a44ff494364725b3b7da82c68Brian/**************************************************************************
24c1403f667c6047a44ff494364725b3b7da82c68Brian *
34c1403f667c6047a44ff494364725b3b7da82c68Brian * Copyright 2008 Tungsten Graphics, Inc., Cedar Park, Texas.
44c1403f667c6047a44ff494364725b3b7da82c68Brian * All Rights Reserved.
54c1403f667c6047a44ff494364725b3b7da82c68Brian *
64c1403f667c6047a44ff494364725b3b7da82c68Brian * Permission is hereby granted, free of charge, to any person obtaining a
74c1403f667c6047a44ff494364725b3b7da82c68Brian * copy of this software and associated documentation files (the
84c1403f667c6047a44ff494364725b3b7da82c68Brian * "Software"), to deal in the Software without restriction, including
94c1403f667c6047a44ff494364725b3b7da82c68Brian * without limitation the rights to use, copy, modify, merge, publish,
104c1403f667c6047a44ff494364725b3b7da82c68Brian * distribute, sub license, and/or sell copies of the Software, and to
114c1403f667c6047a44ff494364725b3b7da82c68Brian * permit persons to whom the Software is furnished to do so, subject to
124c1403f667c6047a44ff494364725b3b7da82c68Brian * the following conditions:
134c1403f667c6047a44ff494364725b3b7da82c68Brian *
144c1403f667c6047a44ff494364725b3b7da82c68Brian * The above copyright notice and this permission notice (including the
154c1403f667c6047a44ff494364725b3b7da82c68Brian * next paragraph) shall be included in all copies or substantial portions
164c1403f667c6047a44ff494364725b3b7da82c68Brian * of the Software.
174c1403f667c6047a44ff494364725b3b7da82c68Brian *
184c1403f667c6047a44ff494364725b3b7da82c68Brian * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
194c1403f667c6047a44ff494364725b3b7da82c68Brian * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
204c1403f667c6047a44ff494364725b3b7da82c68Brian * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
214c1403f667c6047a44ff494364725b3b7da82c68Brian * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR
224c1403f667c6047a44ff494364725b3b7da82c68Brian * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
234c1403f667c6047a44ff494364725b3b7da82c68Brian * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
244c1403f667c6047a44ff494364725b3b7da82c68Brian * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
254c1403f667c6047a44ff494364725b3b7da82c68Brian *
264c1403f667c6047a44ff494364725b3b7da82c68Brian **************************************************************************/
274c1403f667c6047a44ff494364725b3b7da82c68Brian
284c1403f667c6047a44ff494364725b3b7da82c68Brian/**
294c1403f667c6047a44ff494364725b3b7da82c68Brian * TGSI program transformation utility.
304c1403f667c6047a44ff494364725b3b7da82c68Brian *
314c1403f667c6047a44ff494364725b3b7da82c68Brian * Authors:  Brian Paul
324c1403f667c6047a44ff494364725b3b7da82c68Brian */
334c1403f667c6047a44ff494364725b3b7da82c68Brian
34ea4bf267e4b023b08043f91ac44592fed1736e7fJosé Fonseca#include "util/u_debug.h"
354c1403f667c6047a44ff494364725b3b7da82c68Brian
364c1403f667c6047a44ff494364725b3b7da82c68Brian#include "tgsi_transform.h"
374c1403f667c6047a44ff494364725b3b7da82c68Brian
384c1403f667c6047a44ff494364725b3b7da82c68Brian
394c1403f667c6047a44ff494364725b3b7da82c68Brian
404c1403f667c6047a44ff494364725b3b7da82c68Brianstatic void
414c1403f667c6047a44ff494364725b3b7da82c68Brianemit_instruction(struct tgsi_transform_context *ctx,
424c1403f667c6047a44ff494364725b3b7da82c68Brian                 const struct tgsi_full_instruction *inst)
434c1403f667c6047a44ff494364725b3b7da82c68Brian{
444c1403f667c6047a44ff494364725b3b7da82c68Brian   uint ti = ctx->ti;
454c1403f667c6047a44ff494364725b3b7da82c68Brian
464c1403f667c6047a44ff494364725b3b7da82c68Brian   ti += tgsi_build_full_instruction(inst,
474c1403f667c6047a44ff494364725b3b7da82c68Brian                                     ctx->tokens_out + ti,
484c1403f667c6047a44ff494364725b3b7da82c68Brian                                     ctx->header,
494c1403f667c6047a44ff494364725b3b7da82c68Brian                                     ctx->max_tokens_out - ti);
504c1403f667c6047a44ff494364725b3b7da82c68Brian   ctx->ti = ti;
514c1403f667c6047a44ff494364725b3b7da82c68Brian}
524c1403f667c6047a44ff494364725b3b7da82c68Brian
534c1403f667c6047a44ff494364725b3b7da82c68Brian
544c1403f667c6047a44ff494364725b3b7da82c68Brianstatic void
554c1403f667c6047a44ff494364725b3b7da82c68Brianemit_declaration(struct tgsi_transform_context *ctx,
564c1403f667c6047a44ff494364725b3b7da82c68Brian                 const struct tgsi_full_declaration *decl)
574c1403f667c6047a44ff494364725b3b7da82c68Brian{
584c1403f667c6047a44ff494364725b3b7da82c68Brian   uint ti = ctx->ti;
594c1403f667c6047a44ff494364725b3b7da82c68Brian
604c1403f667c6047a44ff494364725b3b7da82c68Brian   ti += tgsi_build_full_declaration(decl,
614c1403f667c6047a44ff494364725b3b7da82c68Brian                                     ctx->tokens_out + ti,
624c1403f667c6047a44ff494364725b3b7da82c68Brian                                     ctx->header,
634c1403f667c6047a44ff494364725b3b7da82c68Brian                                     ctx->max_tokens_out - ti);
644c1403f667c6047a44ff494364725b3b7da82c68Brian   ctx->ti = ti;
654c1403f667c6047a44ff494364725b3b7da82c68Brian}
664c1403f667c6047a44ff494364725b3b7da82c68Brian
674c1403f667c6047a44ff494364725b3b7da82c68Brian
684c1403f667c6047a44ff494364725b3b7da82c68Brianstatic void
694c1403f667c6047a44ff494364725b3b7da82c68Brianemit_immediate(struct tgsi_transform_context *ctx,
704c1403f667c6047a44ff494364725b3b7da82c68Brian               const struct tgsi_full_immediate *imm)
714c1403f667c6047a44ff494364725b3b7da82c68Brian{
724c1403f667c6047a44ff494364725b3b7da82c68Brian   uint ti = ctx->ti;
734c1403f667c6047a44ff494364725b3b7da82c68Brian
744c1403f667c6047a44ff494364725b3b7da82c68Brian   ti += tgsi_build_full_immediate(imm,
754c1403f667c6047a44ff494364725b3b7da82c68Brian                                   ctx->tokens_out + ti,
764c1403f667c6047a44ff494364725b3b7da82c68Brian                                   ctx->header,
774c1403f667c6047a44ff494364725b3b7da82c68Brian                                   ctx->max_tokens_out - ti);
784c1403f667c6047a44ff494364725b3b7da82c68Brian   ctx->ti = ti;
794c1403f667c6047a44ff494364725b3b7da82c68Brian}
804c1403f667c6047a44ff494364725b3b7da82c68Brian
814c1403f667c6047a44ff494364725b3b7da82c68Brian
823ff688ea299581e60caf5d6e1a464f68c717fe83Zack Rusinstatic void
833ff688ea299581e60caf5d6e1a464f68c717fe83Zack Rusinemit_property(struct tgsi_transform_context *ctx,
843ff688ea299581e60caf5d6e1a464f68c717fe83Zack Rusin              const struct tgsi_full_property *prop)
853ff688ea299581e60caf5d6e1a464f68c717fe83Zack Rusin{
863ff688ea299581e60caf5d6e1a464f68c717fe83Zack Rusin   uint ti = ctx->ti;
873ff688ea299581e60caf5d6e1a464f68c717fe83Zack Rusin
883ff688ea299581e60caf5d6e1a464f68c717fe83Zack Rusin   ti += tgsi_build_full_property(prop,
893ff688ea299581e60caf5d6e1a464f68c717fe83Zack Rusin                                  ctx->tokens_out + ti,
903ff688ea299581e60caf5d6e1a464f68c717fe83Zack Rusin                                  ctx->header,
913ff688ea299581e60caf5d6e1a464f68c717fe83Zack Rusin                                  ctx->max_tokens_out - ti);
923ff688ea299581e60caf5d6e1a464f68c717fe83Zack Rusin   ctx->ti = ti;
933ff688ea299581e60caf5d6e1a464f68c717fe83Zack Rusin}
943ff688ea299581e60caf5d6e1a464f68c717fe83Zack Rusin
954c1403f667c6047a44ff494364725b3b7da82c68Brian
964c1403f667c6047a44ff494364725b3b7da82c68Brian/**
974c1403f667c6047a44ff494364725b3b7da82c68Brian * Apply user-defined transformations to the input shader to produce
984c1403f667c6047a44ff494364725b3b7da82c68Brian * the output shader.
994c1403f667c6047a44ff494364725b3b7da82c68Brian * For example, a register search-and-replace operation could be applied
1004c1403f667c6047a44ff494364725b3b7da82c68Brian * by defining a transform_instruction() callback that examined and changed
1014c1403f667c6047a44ff494364725b3b7da82c68Brian * the instruction src/dest regs.
1024c1403f667c6047a44ff494364725b3b7da82c68Brian *
1034c1403f667c6047a44ff494364725b3b7da82c68Brian * \return number of tokens emitted
1044c1403f667c6047a44ff494364725b3b7da82c68Brian */
1054c1403f667c6047a44ff494364725b3b7da82c68Brianint
1064c1403f667c6047a44ff494364725b3b7da82c68Briantgsi_transform_shader(const struct tgsi_token *tokens_in,
1074c1403f667c6047a44ff494364725b3b7da82c68Brian                      struct tgsi_token *tokens_out,
1084c1403f667c6047a44ff494364725b3b7da82c68Brian                      uint max_tokens_out,
1094c1403f667c6047a44ff494364725b3b7da82c68Brian                      struct tgsi_transform_context *ctx)
1104c1403f667c6047a44ff494364725b3b7da82c68Brian{
1114c1403f667c6047a44ff494364725b3b7da82c68Brian   uint procType;
1124c1403f667c6047a44ff494364725b3b7da82c68Brian
1134c1403f667c6047a44ff494364725b3b7da82c68Brian   /* input shader */
1144c1403f667c6047a44ff494364725b3b7da82c68Brian   struct tgsi_parse_context parse;
1154c1403f667c6047a44ff494364725b3b7da82c68Brian
1164c1403f667c6047a44ff494364725b3b7da82c68Brian   /* output shader */
1174c1403f667c6047a44ff494364725b3b7da82c68Brian   struct tgsi_processor *processor;
1184c1403f667c6047a44ff494364725b3b7da82c68Brian
1194c1403f667c6047a44ff494364725b3b7da82c68Brian
1204c1403f667c6047a44ff494364725b3b7da82c68Brian   /**
1214c1403f667c6047a44ff494364725b3b7da82c68Brian    ** callback context init
1224c1403f667c6047a44ff494364725b3b7da82c68Brian    **/
1234c1403f667c6047a44ff494364725b3b7da82c68Brian   ctx->emit_instruction = emit_instruction;
1244c1403f667c6047a44ff494364725b3b7da82c68Brian   ctx->emit_declaration = emit_declaration;
1254c1403f667c6047a44ff494364725b3b7da82c68Brian   ctx->emit_immediate = emit_immediate;
1263ff688ea299581e60caf5d6e1a464f68c717fe83Zack Rusin   ctx->emit_property = emit_property;
1274c1403f667c6047a44ff494364725b3b7da82c68Brian   ctx->tokens_out = tokens_out;
1284c1403f667c6047a44ff494364725b3b7da82c68Brian   ctx->max_tokens_out = max_tokens_out;
1294c1403f667c6047a44ff494364725b3b7da82c68Brian
1304c1403f667c6047a44ff494364725b3b7da82c68Brian
1314c1403f667c6047a44ff494364725b3b7da82c68Brian   /**
1324c1403f667c6047a44ff494364725b3b7da82c68Brian    ** Setup to begin parsing input shader
1334c1403f667c6047a44ff494364725b3b7da82c68Brian    **/
1344c1403f667c6047a44ff494364725b3b7da82c68Brian   if (tgsi_parse_init( &parse, tokens_in ) != TGSI_PARSE_OK) {
1354c1403f667c6047a44ff494364725b3b7da82c68Brian      debug_printf("tgsi_parse_init() failed in tgsi_transform_shader()!\n");
1364c1403f667c6047a44ff494364725b3b7da82c68Brian      return -1;
1374c1403f667c6047a44ff494364725b3b7da82c68Brian   }
1384c1403f667c6047a44ff494364725b3b7da82c68Brian   procType = parse.FullHeader.Processor.Processor;
1394c1403f667c6047a44ff494364725b3b7da82c68Brian   assert(procType == TGSI_PROCESSOR_FRAGMENT ||
1404c1403f667c6047a44ff494364725b3b7da82c68Brian          procType == TGSI_PROCESSOR_VERTEX ||
1414c1403f667c6047a44ff494364725b3b7da82c68Brian          procType == TGSI_PROCESSOR_GEOMETRY);
1424c1403f667c6047a44ff494364725b3b7da82c68Brian
1434c1403f667c6047a44ff494364725b3b7da82c68Brian
1444c1403f667c6047a44ff494364725b3b7da82c68Brian   /**
1454c1403f667c6047a44ff494364725b3b7da82c68Brian    **  Setup output shader
1464c1403f667c6047a44ff494364725b3b7da82c68Brian    **/
147e6133564bf2e65fc86f626a45d7977bdeaff8579Michal Krol   ctx->header = (struct tgsi_header *)tokens_out;
1484c1403f667c6047a44ff494364725b3b7da82c68Brian   *ctx->header = tgsi_build_header();
1494c1403f667c6047a44ff494364725b3b7da82c68Brian
150e6133564bf2e65fc86f626a45d7977bdeaff8579Michal Krol   processor = (struct tgsi_processor *) (tokens_out + 1);
1514c1403f667c6047a44ff494364725b3b7da82c68Brian   *processor = tgsi_build_processor( procType, ctx->header );
1524c1403f667c6047a44ff494364725b3b7da82c68Brian
153e6133564bf2e65fc86f626a45d7977bdeaff8579Michal Krol   ctx->ti = 2;
1544c1403f667c6047a44ff494364725b3b7da82c68Brian
1554c1403f667c6047a44ff494364725b3b7da82c68Brian
1564c1403f667c6047a44ff494364725b3b7da82c68Brian   /**
1574c1403f667c6047a44ff494364725b3b7da82c68Brian    ** Loop over incoming program tokens/instructions
1584c1403f667c6047a44ff494364725b3b7da82c68Brian    */
1594c1403f667c6047a44ff494364725b3b7da82c68Brian   while( !tgsi_parse_end_of_tokens( &parse ) ) {
1604c1403f667c6047a44ff494364725b3b7da82c68Brian
1614c1403f667c6047a44ff494364725b3b7da82c68Brian      tgsi_parse_token( &parse );
1624c1403f667c6047a44ff494364725b3b7da82c68Brian
1634c1403f667c6047a44ff494364725b3b7da82c68Brian      switch( parse.FullToken.Token.Type ) {
1644c1403f667c6047a44ff494364725b3b7da82c68Brian      case TGSI_TOKEN_TYPE_INSTRUCTION:
1654c1403f667c6047a44ff494364725b3b7da82c68Brian         {
1664c1403f667c6047a44ff494364725b3b7da82c68Brian            struct tgsi_full_instruction *fullinst
1674c1403f667c6047a44ff494364725b3b7da82c68Brian               = &parse.FullToken.FullInstruction;
1684c1403f667c6047a44ff494364725b3b7da82c68Brian
1694c1403f667c6047a44ff494364725b3b7da82c68Brian            if (ctx->transform_instruction)
1704c1403f667c6047a44ff494364725b3b7da82c68Brian               ctx->transform_instruction(ctx, fullinst);
1714c1403f667c6047a44ff494364725b3b7da82c68Brian            else
1724c1403f667c6047a44ff494364725b3b7da82c68Brian               ctx->emit_instruction(ctx, fullinst);
1734c1403f667c6047a44ff494364725b3b7da82c68Brian         }
1744c1403f667c6047a44ff494364725b3b7da82c68Brian         break;
1754c1403f667c6047a44ff494364725b3b7da82c68Brian
1764c1403f667c6047a44ff494364725b3b7da82c68Brian      case TGSI_TOKEN_TYPE_DECLARATION:
1774c1403f667c6047a44ff494364725b3b7da82c68Brian         {
1784c1403f667c6047a44ff494364725b3b7da82c68Brian            struct tgsi_full_declaration *fulldecl
1794c1403f667c6047a44ff494364725b3b7da82c68Brian               = &parse.FullToken.FullDeclaration;
1804c1403f667c6047a44ff494364725b3b7da82c68Brian
1814c1403f667c6047a44ff494364725b3b7da82c68Brian            if (ctx->transform_declaration)
1824c1403f667c6047a44ff494364725b3b7da82c68Brian               ctx->transform_declaration(ctx, fulldecl);
1834c1403f667c6047a44ff494364725b3b7da82c68Brian            else
1844c1403f667c6047a44ff494364725b3b7da82c68Brian               ctx->emit_declaration(ctx, fulldecl);
1854c1403f667c6047a44ff494364725b3b7da82c68Brian         }
1864c1403f667c6047a44ff494364725b3b7da82c68Brian         break;
1874c1403f667c6047a44ff494364725b3b7da82c68Brian
1884c1403f667c6047a44ff494364725b3b7da82c68Brian      case TGSI_TOKEN_TYPE_IMMEDIATE:
1894c1403f667c6047a44ff494364725b3b7da82c68Brian         {
1904c1403f667c6047a44ff494364725b3b7da82c68Brian            struct tgsi_full_immediate *fullimm
1914c1403f667c6047a44ff494364725b3b7da82c68Brian               = &parse.FullToken.FullImmediate;
1924c1403f667c6047a44ff494364725b3b7da82c68Brian
1934c1403f667c6047a44ff494364725b3b7da82c68Brian            if (ctx->transform_immediate)
1944c1403f667c6047a44ff494364725b3b7da82c68Brian               ctx->transform_immediate(ctx, fullimm);
1954c1403f667c6047a44ff494364725b3b7da82c68Brian            else
1964c1403f667c6047a44ff494364725b3b7da82c68Brian               ctx->emit_immediate(ctx, fullimm);
1974c1403f667c6047a44ff494364725b3b7da82c68Brian         }
1984c1403f667c6047a44ff494364725b3b7da82c68Brian         break;
1993ff688ea299581e60caf5d6e1a464f68c717fe83Zack Rusin      case TGSI_TOKEN_TYPE_PROPERTY:
2003ff688ea299581e60caf5d6e1a464f68c717fe83Zack Rusin         {
2013ff688ea299581e60caf5d6e1a464f68c717fe83Zack Rusin            struct tgsi_full_property *fullprop
2023ff688ea299581e60caf5d6e1a464f68c717fe83Zack Rusin               = &parse.FullToken.FullProperty;
2033ff688ea299581e60caf5d6e1a464f68c717fe83Zack Rusin
2043ff688ea299581e60caf5d6e1a464f68c717fe83Zack Rusin            if (ctx->transform_property)
2053ff688ea299581e60caf5d6e1a464f68c717fe83Zack Rusin               ctx->transform_property(ctx, fullprop);
2063ff688ea299581e60caf5d6e1a464f68c717fe83Zack Rusin            else
2073ff688ea299581e60caf5d6e1a464f68c717fe83Zack Rusin               ctx->emit_property(ctx, fullprop);
2083ff688ea299581e60caf5d6e1a464f68c717fe83Zack Rusin         }
2093ff688ea299581e60caf5d6e1a464f68c717fe83Zack Rusin         break;
2104c1403f667c6047a44ff494364725b3b7da82c68Brian
2114c1403f667c6047a44ff494364725b3b7da82c68Brian      default:
2124c1403f667c6047a44ff494364725b3b7da82c68Brian         assert( 0 );
2134c1403f667c6047a44ff494364725b3b7da82c68Brian      }
2144c1403f667c6047a44ff494364725b3b7da82c68Brian   }
2154c1403f667c6047a44ff494364725b3b7da82c68Brian
2164c1403f667c6047a44ff494364725b3b7da82c68Brian   if (ctx->epilog) {
2174c1403f667c6047a44ff494364725b3b7da82c68Brian      ctx->epilog(ctx);
2184c1403f667c6047a44ff494364725b3b7da82c68Brian   }
2194c1403f667c6047a44ff494364725b3b7da82c68Brian
2204c1403f667c6047a44ff494364725b3b7da82c68Brian   tgsi_parse_free (&parse);
2214c1403f667c6047a44ff494364725b3b7da82c68Brian
2224c1403f667c6047a44ff494364725b3b7da82c68Brian   return ctx->ti;
2234c1403f667c6047a44ff494364725b3b7da82c68Brian}
224b865501bda8f2f99bfa8ee365aa4a3da64291e6eKeith Whitwell
225b865501bda8f2f99bfa8ee365aa4a3da64291e6eKeith Whitwell
226b865501bda8f2f99bfa8ee365aa4a3da64291e6eKeith Whitwell#include "tgsi_text.h"
227b865501bda8f2f99bfa8ee365aa4a3da64291e6eKeith Whitwell
228b865501bda8f2f99bfa8ee365aa4a3da64291e6eKeith Whitwellextern int tgsi_transform_foo( struct tgsi_token *tokens_out,
229b865501bda8f2f99bfa8ee365aa4a3da64291e6eKeith Whitwell                               uint max_tokens_out );
230b865501bda8f2f99bfa8ee365aa4a3da64291e6eKeith Whitwell
231b865501bda8f2f99bfa8ee365aa4a3da64291e6eKeith Whitwell/* This function exists only so that tgsi_text_translate() doesn't get
232b865501bda8f2f99bfa8ee365aa4a3da64291e6eKeith Whitwell * magic-ed out of the libtgsi.a archive by the build system.  Don't
233b865501bda8f2f99bfa8ee365aa4a3da64291e6eKeith Whitwell * remove unless you know this has been fixed - check on mingw/scons
234b865501bda8f2f99bfa8ee365aa4a3da64291e6eKeith Whitwell * builds as well.
235b865501bda8f2f99bfa8ee365aa4a3da64291e6eKeith Whitwell */
236b865501bda8f2f99bfa8ee365aa4a3da64291e6eKeith Whitwellint
237b865501bda8f2f99bfa8ee365aa4a3da64291e6eKeith Whitwelltgsi_transform_foo( struct tgsi_token *tokens_out,
238b865501bda8f2f99bfa8ee365aa4a3da64291e6eKeith Whitwell                    uint max_tokens_out )
239b865501bda8f2f99bfa8ee365aa4a3da64291e6eKeith Whitwell{
240b865501bda8f2f99bfa8ee365aa4a3da64291e6eKeith Whitwell   const char *text =
241e6133564bf2e65fc86f626a45d7977bdeaff8579Michal Krol      "FRAG\n"
242b865501bda8f2f99bfa8ee365aa4a3da64291e6eKeith Whitwell      "DCL IN[0], COLOR, CONSTANT\n"
243b865501bda8f2f99bfa8ee365aa4a3da64291e6eKeith Whitwell      "DCL OUT[0], COLOR\n"
244b865501bda8f2f99bfa8ee365aa4a3da64291e6eKeith Whitwell      "  0: MOV OUT[0], IN[0]\n"
245b865501bda8f2f99bfa8ee365aa4a3da64291e6eKeith Whitwell      "  1: END";
246b865501bda8f2f99bfa8ee365aa4a3da64291e6eKeith Whitwell
247b865501bda8f2f99bfa8ee365aa4a3da64291e6eKeith Whitwell   return tgsi_text_translate( text,
248b865501bda8f2f99bfa8ee365aa4a3da64291e6eKeith Whitwell                               tokens_out,
249b865501bda8f2f99bfa8ee365aa4a3da64291e6eKeith Whitwell                               max_tokens_out );
250b865501bda8f2f99bfa8ee365aa4a3da64291e6eKeith Whitwell}
251