diff options
-rw-r--r-- | src/gallium/aux/draw/draw_vertex_shader.c | 10 | ||||
-rw-r--r-- | src/gallium/aux/tgsi/exec/tgsi_exec.c | 71 | ||||
-rw-r--r-- | src/gallium/aux/tgsi/exec/tgsi_exec.h | 8 | ||||
-rwxr-xr-x | src/gallium/aux/tgsi/exec/tgsi_sse2.c | 39 | ||||
-rw-r--r-- | src/gallium/drivers/softpipe/Makefile | 3 | ||||
-rw-r--r-- | src/gallium/drivers/softpipe/sp_context.h | 8 | ||||
-rw-r--r-- | src/gallium/drivers/softpipe/sp_fs.h | 54 | ||||
-rw-r--r-- | src/gallium/drivers/softpipe/sp_fs_exec.c | 112 | ||||
-rw-r--r-- | src/gallium/drivers/softpipe/sp_fs_llvm.c | 200 | ||||
-rw-r--r-- | src/gallium/drivers/softpipe/sp_fs_sse.c | 192 | ||||
-rw-r--r-- | src/gallium/drivers/softpipe/sp_quad_fs.c | 200 | ||||
-rw-r--r-- | src/gallium/drivers/softpipe/sp_state.h | 38 | ||||
-rw-r--r-- | src/gallium/drivers/softpipe/sp_state_fs.c | 69 | ||||
-rw-r--r-- | src/gallium/include/pipe/p_state.h | 16 | ||||
-rw-r--r-- | src/mesa/x86/rtasm/x86sse.c | 2 |
15 files changed, 690 insertions, 332 deletions
diff --git a/src/gallium/aux/draw/draw_vertex_shader.c b/src/gallium/aux/draw/draw_vertex_shader.c index 377ecbb931c..9413f8b43a4 100644 --- a/src/gallium/aux/draw/draw_vertex_shader.c +++ b/src/gallium/aux/draw/draw_vertex_shader.c @@ -305,11 +305,13 @@ draw_bind_vertex_shader(struct draw_context *draw, draw->vertex_shader = dvs; draw->num_vs_outputs = dvs->state->num_outputs; + tgsi_exec_machine_init(&draw->machine); + /* specify the vertex program to interpret/execute */ - tgsi_exec_machine_init(&draw->machine, - draw->vertex_shader->state->tokens, - PIPE_MAX_SAMPLERS, - NULL /*samplers*/ ); + tgsi_exec_machine_bind_shader(&draw->machine, + draw->vertex_shader->state->tokens, + PIPE_MAX_SAMPLERS, + NULL /*samplers*/ ); } diff --git a/src/gallium/aux/tgsi/exec/tgsi_exec.c b/src/gallium/aux/tgsi/exec/tgsi_exec.c index a8f64c2287f..d7b18dc9c59 100644 --- a/src/gallium/aux/tgsi/exec/tgsi_exec.c +++ b/src/gallium/aux/tgsi/exec/tgsi_exec.c @@ -120,18 +120,41 @@ -static void -tgsi_exec_prepare( struct tgsi_exec_machine *mach ) +/** + * Initialize machine state by expanding tokens to full instructions, + * allocating temporary storage, setting up constants, etc. + * After this, we can call tgsi_exec_machine_run() many times. + */ +void +tgsi_exec_machine_bind_shader( + struct tgsi_exec_machine *mach, + const struct tgsi_token *tokens, + uint numSamplers, + struct tgsi_sampler *samplers) { - struct tgsi_exec_labels *labels = &mach->Labels; + uint k; struct tgsi_parse_context parse; + struct tgsi_exec_labels *labels = &mach->Labels; struct tgsi_full_instruction *instructions; struct tgsi_full_declaration *declarations; uint maxInstructions = 10, numInstructions = 0; uint maxDeclarations = 10, numDeclarations = 0; - uint k; uint instno = 0; +#if 0 + tgsi_dump(tokens, 0); +#endif + + mach->Tokens = tokens; + mach->Samplers = samplers; + + k = tgsi_parse_init (&parse, mach->Tokens); + if (k != TGSI_PARSE_OK) { + debug_printf( "Problem parsing!\n" ); + return; + } + + mach->Processor = parse.FullHeader.Processor.Processor; mach->ImmLimit = 0; labels->count = 0; @@ -141,11 +164,6 @@ tgsi_exec_prepare( struct tgsi_exec_machine *mach ) instructions = (struct tgsi_full_instruction *) MALLOC( maxInstructions * sizeof(struct tgsi_full_instruction) ); - k = tgsi_parse_init( &parse, mach->Tokens ); - if (k != TGSI_PARSE_OK) { - debug_printf("Problem parsing!\n"); - return; - } while( !tgsi_parse_end_of_tokens( &parse ) ) { uint pointer = parse.Position; @@ -176,7 +194,8 @@ tgsi_exec_prepare( struct tgsi_exec_machine *mach ) assert( mach->ImmLimit + size / 4 <= TGSI_EXEC_NUM_IMMEDIATES ); for( i = 0; i < size; i++ ) { - mach->Imms[mach->ImmLimit + i / 4][i % 4] = parse.FullToken.FullImmediate.u.ImmediateFloat32[i].Float; + mach->Imms[mach->ImmLimit + i / 4][i % 4] = + parse.FullToken.FullImmediate.u.ImmediateFloat32[i].Float; } mach->ImmLimit += size / 4; } @@ -224,37 +243,11 @@ tgsi_exec_prepare( struct tgsi_exec_machine *mach ) } -/** - * Initialize machine state by expanding tokens to full instructions, - * allocating temporary storage, setting up constants, etc. - * After this, we can call tgsi_exec_machine_run() many times. - */ void tgsi_exec_machine_init( - struct tgsi_exec_machine *mach, - const struct tgsi_token *tokens, - uint numSamplers, - struct tgsi_sampler *samplers) + struct tgsi_exec_machine *mach ) { - uint i, k; - struct tgsi_parse_context parse; - -#if 0 - tgsi_dump(tokens, 0); -#endif - - mach->Tokens = tokens; - - mach->Samplers = samplers; - - k = tgsi_parse_init (&parse, mach->Tokens); - if (k != TGSI_PARSE_OK) { - debug_printf( "Problem parsing!\n" ); - return; - } - - mach->Processor = parse.FullHeader.Processor.Processor; - tgsi_parse_free (&parse); + uint i; mach->Temps = (struct tgsi_exec_vector *) tgsi_align_128bit( mach->_Temps); mach->Addrs = &mach->Temps[TGSI_EXEC_NUM_TEMPS]; @@ -270,8 +263,6 @@ tgsi_exec_machine_init( mach->Temps[TEMP_128_I].xyzw[TEMP_128_C].f[i] = 128.0f; mach->Temps[TEMP_M128_I].xyzw[TEMP_M128_C].f[i] = -128.0f; } - - tgsi_exec_prepare( mach ); } diff --git a/src/gallium/aux/tgsi/exec/tgsi_exec.h b/src/gallium/aux/tgsi/exec/tgsi_exec.h index 1fb66ee960f..45c49dd007c 100644 --- a/src/gallium/aux/tgsi/exec/tgsi_exec.h +++ b/src/gallium/aux/tgsi/exec/tgsi_exec.h @@ -215,12 +215,16 @@ struct tgsi_exec_machine struct tgsi_exec_labels Labels; }; - void tgsi_exec_machine_init( + struct tgsi_exec_machine *mach ); + + +void +tgsi_exec_machine_bind_shader( struct tgsi_exec_machine *mach, const struct tgsi_token *tokens, - unsigned numSamplers, + uint numSamplers, struct tgsi_sampler *samplers); uint diff --git a/src/gallium/aux/tgsi/exec/tgsi_sse2.c b/src/gallium/aux/tgsi/exec/tgsi_sse2.c index 593464db3ed..79209575bc4 100755 --- a/src/gallium/aux/tgsi/exec/tgsi_sse2.c +++ b/src/gallium/aux/tgsi/exec/tgsi_sse2.c @@ -1935,13 +1935,20 @@ emit_instruction( break; case TGSI_OPCODE_TEX: - emit_tempf( - func, - 0, - TGSI_EXEC_TEMP_ONE_I, - TGSI_EXEC_TEMP_ONE_C ); - FOR_EACH_DST0_ENABLED_CHANNEL( *inst, chan_index ) { - STORE( func, *inst, 0, 0, chan_index ); + if (0) { + /* Disable dummy texture code: + */ + emit_tempf( + func, + 0, + TGSI_EXEC_TEMP_ONE_I, + TGSI_EXEC_TEMP_ONE_C ); + FOR_EACH_DST0_ENABLED_CHANNEL( *inst, chan_index ) { + STORE( func, *inst, 0, 0, chan_index ); + } + } + else { + return 0; } break; @@ -2169,14 +2176,6 @@ emit_declaration( last = decl->u.DeclarationRange.Last; mask = decl->Declaration.UsageMask; - /* Do not touch WPOS.xy */ - if( first == 0 ) { - mask &= ~TGSI_WRITEMASK_XY; - if( mask == TGSI_WRITEMASK_NONE ) { - first++; - } - } - for( i = first; i <= last; i++ ) { for( j = 0; j < NUM_CHANNELS; j++ ) { if( mask & (1 << j) ) { @@ -2187,9 +2186,9 @@ emit_declaration( break; case TGSI_INTERPOLATE_LINEAR: - emit_inputf( func, 0, 0, TGSI_SWIZZLE_X ); + emit_tempf( func, 0, 0, TGSI_SWIZZLE_X ); emit_coef_dadx( func, 1, i, j ); - emit_inputf( func, 2, 0, TGSI_SWIZZLE_Y ); + emit_tempf( func, 2, 0, TGSI_SWIZZLE_Y ); emit_coef_dady( func, 3, i, j ); emit_mul( func, 0, 1 ); /* x * dadx */ emit_coef_a0( func, 4, i, j ); @@ -2200,12 +2199,12 @@ emit_declaration( break; case TGSI_INTERPOLATE_PERSPECTIVE: - emit_inputf( func, 0, 0, TGSI_SWIZZLE_X ); + emit_tempf( func, 0, 0, TGSI_SWIZZLE_X ); emit_coef_dadx( func, 1, i, j ); - emit_inputf( func, 2, 0, TGSI_SWIZZLE_Y ); + emit_tempf( func, 2, 0, TGSI_SWIZZLE_Y ); emit_coef_dady( func, 3, i, j ); emit_mul( func, 0, 1 ); /* x * dadx */ - emit_inputf( func, 4, 0, TGSI_SWIZZLE_W ); + emit_tempf( func, 4, 0, TGSI_SWIZZLE_W ); emit_coef_a0( func, 5, i, j ); emit_rcp( func, 4, 4 ); /* 1.0 / w */ emit_mul( func, 2, 3 ); /* y * dady */ diff --git a/src/gallium/drivers/softpipe/Makefile b/src/gallium/drivers/softpipe/Makefile index 2304ea4246a..5479daf8ea2 100644 --- a/src/gallium/drivers/softpipe/Makefile +++ b/src/gallium/drivers/softpipe/Makefile @@ -5,6 +5,9 @@ include $(TOP)/configs/current LIBNAME = softpipe DRIVER_SOURCES = \ + sp_fs_exec.c \ + sp_fs_sse.c \ + sp_fs_llvm.c \ sp_clear.c \ sp_flush.c \ sp_query.c \ diff --git a/src/gallium/drivers/softpipe/sp_context.h b/src/gallium/drivers/softpipe/sp_context.h index 8c79cb3ce4f..b70d4fea85a 100644 --- a/src/gallium/drivers/softpipe/sp_context.h +++ b/src/gallium/drivers/softpipe/sp_context.h @@ -44,8 +44,8 @@ struct softpipe_vbuf_render; struct draw_context; struct draw_stage; struct softpipe_tile_cache; -struct sp_fragment_shader_state; -struct sp_vertex_shader_state; +struct sp_fragment_shader; +struct sp_vertex_shader; struct softpipe_context { @@ -59,8 +59,8 @@ struct softpipe_context { const struct pipe_sampler_state *sampler[PIPE_MAX_SAMPLERS]; const struct pipe_depth_stencil_alpha_state *depth_stencil; const struct pipe_rasterizer_state *rasterizer; - const struct sp_fragment_shader_state *fs; - const struct sp_vertex_shader_state *vs; + const struct sp_fragment_shader *fs; + const struct sp_vertex_shader *vs; struct pipe_blend_color blend_color; struct pipe_clip_state clip; diff --git a/src/gallium/drivers/softpipe/sp_fs.h b/src/gallium/drivers/softpipe/sp_fs.h new file mode 100644 index 00000000000..4792ace3a33 --- /dev/null +++ b/src/gallium/drivers/softpipe/sp_fs.h @@ -0,0 +1,54 @@ +/************************************************************************** + * + * Copyright 2007 Tungsten Graphics, Inc., Cedar Park, Texas. + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sub license, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial portions + * of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. + * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + **************************************************************************/ + +/* Authors: Keith Whitwell <[email protected]> + */ + +#ifndef SP_FS_H +#define SP_FS_H + +struct sp_fragment_shader * +softpipe_create_fs_exec(struct softpipe_context *softpipe, + const struct pipe_shader_state *templ); + +struct sp_fragment_shader * +softpipe_create_fs_sse(struct softpipe_context *softpipe, + const struct pipe_shader_state *templ); + +struct sp_fragment_shader * +softpipe_create_fs_llvm(struct softpipe_context *softpipe, + const struct pipe_shader_state *templ); + +struct tgsi_interp_coef; +struct tgsi_exec_vector; + +void sp_setup_pos_vector(const struct tgsi_interp_coef *coef, + float x, float y, + struct tgsi_exec_vector *quadpos); + + +#endif diff --git a/src/gallium/drivers/softpipe/sp_fs_exec.c b/src/gallium/drivers/softpipe/sp_fs_exec.c new file mode 100644 index 00000000000..9ad30a76817 --- /dev/null +++ b/src/gallium/drivers/softpipe/sp_fs_exec.c @@ -0,0 +1,112 @@ +/************************************************************************** + * + * Copyright 2007 Tungsten Graphics, Inc., Cedar Park, Texas. + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sub license, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial portions + * of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. + * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + **************************************************************************/ + + +#include "sp_context.h" +#include "sp_state.h" +#include "sp_fs.h" +#include "sp_headers.h" + + +#include "pipe/p_state.h" +#include "pipe/p_defines.h" +#include "pipe/p_util.h" +#include "pipe/p_inlines.h" +#include "tgsi/exec/tgsi_exec.h" + +struct sp_exec_fragment_shader { + struct sp_fragment_shader base; +}; + + + + +static void +exec_prepare( struct sp_fragment_shader *base, + struct tgsi_exec_machine *machine, + struct tgsi_sampler *samplers ) +{ + tgsi_exec_machine_bind_shader( machine, + base->shader.tokens, + PIPE_MAX_SAMPLERS, + samplers ); +} + + + + +/* TODO: hide the machine struct in here somewhere, remove from this + * interface: + */ +static unsigned +exec_run( struct sp_fragment_shader *base, + struct tgsi_exec_machine *machine, + struct quad_header *quad ) +{ + + /* Compute X, Y, Z, W vals for this quad */ + sp_setup_pos_vector(quad->posCoef, + (float)quad->x0, (float)quad->y0, + &machine->QuadPos); + + return tgsi_exec_machine_run( machine ); +} + + + +static void +exec_delete( struct sp_fragment_shader *base ) +{ + FREE(base); +} + + + + + +struct sp_fragment_shader * +softpipe_create_fs_exec(struct softpipe_context *softpipe, + const struct pipe_shader_state *templ) +{ + struct sp_exec_fragment_shader *shader; + + /* Decide whether we'll be codegenerating this shader and if so do + * that now. + */ + + shader = CALLOC_STRUCT(sp_exec_fragment_shader); + if (!shader) + return NULL; + + shader->base.shader = *templ; + shader->base.prepare = exec_prepare; + shader->base.run = exec_run; + shader->base.delete = exec_delete; + + return &shader->base; +} + diff --git a/src/gallium/drivers/softpipe/sp_fs_llvm.c b/src/gallium/drivers/softpipe/sp_fs_llvm.c new file mode 100644 index 00000000000..22da4714533 --- /dev/null +++ b/src/gallium/drivers/softpipe/sp_fs_llvm.c @@ -0,0 +1,200 @@ +/************************************************************************** + * + * Copyright 2007 Tungsten Graphics, Inc., Cedar Park, Texas. + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sub license, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial portions + * of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. + * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + **************************************************************************/ + +/* Authors: + * Zack Rusin + */ + +#include "sp_context.h" +#include "sp_state.h" +#include "sp_fs.h" + + +#include "pipe/p_state.h" +#include "pipe/p_defines.h" +#include "pipe/p_util.h" +#include "pipe/p_inlines.h" +#include "tgsi/exec/tgsi_sse2.h" + +#if 0 + +struct sp_llvm_fragment_shader { + struct sp_fragment_shader base; + struct gallivm_prog *llvm_prog; +}; + +static void +shade_quad_llvm(struct quad_stage *qs, + struct quad_header *quad) +{ + struct quad_shade_stage *qss = quad_shade_stage(qs); + struct softpipe_context *softpipe = qs->softpipe; + float dests[4][16][4] ALIGN16_ATTRIB; + float inputs[4][16][4] ALIGN16_ATTRIB; + const float fx = (float) quad->x0; + const float fy = (float) quad->y0; + struct gallivm_prog *llvm = qss->llvm_prog; + + inputs[0][0][0] = fx; + inputs[1][0][0] = fx + 1.0f; + inputs[2][0][0] = fx; + inputs[3][0][0] = fx + 1.0f; + + inputs[0][0][1] = fy; + inputs[1][0][1] = fy; + inputs[2][0][1] = fy + 1.0f; + inputs[3][0][1] = fy + 1.0f; + + + gallivm_prog_inputs_interpolate(llvm, inputs, quad->coef); + +#if DLLVM + debug_printf("MASK = %d\n", quad->mask); + for (int i = 0; i < 4; ++i) { + for (int j = 0; j < 2; ++j) { + debug_printf("IN(%d,%d) [%f %f %f %f]\n", i, j, + inputs[i][j][0], inputs[i][j][1], inputs[i][j][2], inputs[i][j][3]); + } + } +#endif + + quad->mask &= + gallivm_fragment_shader_exec(llvm, fx, fy, dests, inputs, + softpipe->mapped_constants[PIPE_SHADER_FRAGMENT], + qss->samplers); +#if DLLVM + debug_printf("OUT LLVM = 1[%f %f %f %f], 2[%f %f %f %f]\n", + dests[0][0][0], dests[0][0][1], dests[0][0][2], dests[0][0][3], + dests[0][1][0], dests[0][1][1], dests[0][1][2], dests[0][1][3]); +#endif + + /* store result color */ + if (qss->colorOutSlot >= 0) { + unsigned i; + /* XXX need to handle multiple color outputs someday */ + allvmrt(qss->stage.softpipe->fs->shader.output_semantic_name[qss->colorOutSlot] + == TGSI_SEMANTIC_COLOR); + for (i = 0; i < QUAD_SIZE; ++i) { + quad->outputs.color[0][i] = dests[i][qss->colorOutSlot][0]; + quad->outputs.color[1][i] = dests[i][qss->colorOutSlot][1]; + quad->outputs.color[2][i] = dests[i][qss->colorOutSlot][2]; + quad->outputs.color[3][i] = dests[i][qss->colorOutSlot][3]; + } + } +#if DLLVM + for (int i = 0; i < QUAD_SIZE; ++i) { + debug_printf("QLLVM%d(%d) [%f, %f, %f, %f]\n", i, qss->colorOutSlot, + quad->outputs.color[0][i], + quad->outputs.color[1][i], + quad->outputs.color[2][i], + quad->outputs.color[3][i]); + } +#endif + + /* store result Z */ + if (qss->depthOutSlot >= 0) { + /* output[slot] is new Z */ + uint i; + for (i = 0; i < 4; i++) { + quad->outputs.depth[i] = dests[i][0][2]; + } + } + else { + /* copy input Z (which was interpolated by the executor) to output Z */ + uint i; + for (i = 0; i < 4; i++) { + quad->outputs.depth[i] = inputs[i][0][2]; + } + } +#if DLLVM + debug_printf("D [%f, %f, %f, %f] mask = %d\n", + quad->outputs.depth[0], + quad->outputs.depth[1], + quad->outputs.depth[2], + quad->outputs.depth[3], quad->mask); +#endif + + /* shader may cull fragments */ + if( quad->mask ) { + qs->next->run( qs->next, quad ); + } +} + + +unsigned +run_llvm_fs( struct sp_fragment_shader *base, + struct foo *machine ) +{ +} + + +void +delete_llvm_fs( struct sp_fragment_shader *base ) +{ + FREE(base); +} + + +struct sp_fragment_shader * +softpipe_create_fs_llvm(struct softpipe_context *softpipe, + const struct pipe_shader_state *templ) +{ + struct sp_llvm_fragment_shader *shader = NULL; + + /* LLVM fragment shaders currently disabled: + */ + state = CALLOC_STRUCT(sp_llvm_shader_state); + if (!state) + return NULL; + + state->llvm_prog = 0; + + if (!gallivm_global_cpu_engine()) { + gallivm_cpu_engine_create(state->llvm_prog); + } + else + gallivm_cpu_jit_compile(gallivm_global_cpu_engine(), state->llvm_prog); + + if (shader) { + shader->base.run = run_llvm_fs; + shader->base.delete = delete_llvm_fs; + } + + return shader; +} + + +#else + +struct sp_fragment_shader * +softpipe_create_fs_llvm(struct softpipe_context *softpipe, + const struct pipe_shader_state *templ) +{ + return NULL; +} + +#endif diff --git a/src/gallium/drivers/softpipe/sp_fs_sse.c b/src/gallium/drivers/softpipe/sp_fs_sse.c new file mode 100644 index 00000000000..28c5d8c556d --- /dev/null +++ b/src/gallium/drivers/softpipe/sp_fs_sse.c @@ -0,0 +1,192 @@ +/************************************************************************** + * + * Copyright 2007 Tungsten Graphics, Inc., Cedar Park, Texas. + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sub license, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial portions + * of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. + * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + **************************************************************************/ + + +#include "sp_context.h" +#include "sp_state.h" +#include "sp_fs.h" +#include "sp_headers.h" + + +#include "pipe/p_state.h" +#include "pipe/p_defines.h" +#include "pipe/p_util.h" +#include "pipe/p_inlines.h" +#include "tgsi/exec/tgsi_exec.h" +#include "tgsi/exec/tgsi_sse2.h" + + +#if defined(__i386__) || defined(__386__) + +#include "x86/rtasm/x86sse.h" + +/* Surely this should be defined somewhere in a tgsi header: + */ +typedef void (XSTDCALL *codegen_function)( + const struct tgsi_exec_vector *input, + struct tgsi_exec_vector *output, + float (*constant)[4], + struct tgsi_exec_vector *temporary, + const struct tgsi_interp_coef *coef + //, const struct tgsi_exec_vector *quadPos + ); + + +struct sp_sse_fragment_shader { + struct sp_fragment_shader base; + struct x86_function sse2_program; + codegen_function func; +}; + + +/** + * Compute quad X,Y,Z,W for the four fragments in a quad. + * + * This should really be part of the compiled shader. + */ +void +sp_setup_pos_vector(const struct tgsi_interp_coef *coef, + float x, float y, + struct tgsi_exec_vector *quadpos) +{ + uint chan; + /* do X */ + quadpos->xyzw[0].f[0] = x; + quadpos->xyzw[0].f[1] = x + 1; + quadpos->xyzw[0].f[2] = x; + quadpos->xyzw[0].f[3] = x + 1; + + /* do Y */ + quadpos->xyzw[1].f[0] = y; + quadpos->xyzw[1].f[1] = y; + quadpos->xyzw[1].f[2] = y + 1; + quadpos->xyzw[1].f[3] = y + 1; + + /* do Z and W for all fragments in the quad */ + for (chan = 2; chan < 4; chan++) { + const float dadx = coef->dadx[chan]; + const float dady = coef->dady[chan]; + const float a0 = coef->a0[chan] + dadx * x + dady * y; + quadpos->xyzw[chan].f[0] = a0; + quadpos->xyzw[chan].f[1] = a0 + dadx; + quadpos->xyzw[chan].f[2] = a0 + dady; + quadpos->xyzw[chan].f[3] = a0 + dadx + dady; + } +} + + +static void +sse_prepare( struct sp_fragment_shader *base, + struct tgsi_exec_machine *machine, + struct tgsi_sampler *samplers ) +{ +} + + +/* TODO: codegenerate the whole run function, skip this wrapper. + * TODO: break dependency on tgsi_exec_machine struct + * TODO: push Position calculation into the generated shader + * TODO: process >1 quad at a time + */ +static unsigned +sse_run( struct sp_fragment_shader *base, + struct tgsi_exec_machine *machine, + struct quad_header *quad ) +{ + struct sp_sse_fragment_shader *shader = (struct sp_sse_fragment_shader *) base; + + /* Compute X, Y, Z, W vals for this quad -- place in temp[0] for now */ + sp_setup_pos_vector(quad->posCoef, + (float)quad->x0, (float)quad->y0, + machine->Temps); + + shader->func( machine->Inputs, + machine->Outputs, + machine->Consts, + machine->Temps, + machine->InterpCoefs + // , &machine->QuadPos + ); + + return ~(machine->Temps[TGSI_EXEC_TEMP_KILMASK_I].xyzw[TGSI_EXEC_TEMP_KILMASK_C].u[0]); +} + + +static void +sse_delete( struct sp_fragment_shader *base ) +{ + struct sp_sse_fragment_shader *shader = (struct sp_sse_fragment_shader *) base; + + x86_release_func( &shader->sse2_program ); + FREE(shader); +} + + +struct sp_fragment_shader * +softpipe_create_fs_sse(struct softpipe_context *softpipe, + const struct pipe_shader_state *templ) +{ + struct sp_sse_fragment_shader *shader; + + if (!softpipe->use_sse) + return NULL; + + shader = CALLOC_STRUCT(sp_sse_fragment_shader); + if (!shader) + return NULL; + + x86_init_func( &shader->sse2_program ); + + if (!tgsi_emit_sse2_fs( templ->tokens, &shader->sse2_program )) { + FREE(shader); + return NULL; + } + + shader->func = (codegen_function) x86_get_func( &shader->sse2_program ); + assert(shader->func); + + shader->base.shader = *templ; + shader->base.prepare = sse_prepare; + shader->base.run = sse_run; + shader->base.delete = sse_delete; + + return &shader->base; +} + + +#else + +/* Maybe put this varient in the header file. + */ +struct sp_fragment_shader * +softpipe_create_fs_sse(struct softpipe_context *softpipe, + const struct pipe_shader_state *templ) +{ + return NULL; +} + +#endif diff --git a/src/gallium/drivers/softpipe/sp_quad_fs.c b/src/gallium/drivers/softpipe/sp_quad_fs.c index b4c01a7ea8c..cf1b1eff75c 100644 --- a/src/gallium/drivers/softpipe/sp_quad_fs.c +++ b/src/gallium/drivers/softpipe/sp_quad_fs.c @@ -39,12 +39,6 @@ #include "pipe/p_defines.h" #include "pipe/p_shader_tokens.h" -#include "x86/rtasm/x86sse.h" - -#ifdef MESA_LLVM -#include "llvm/gallivm.h" -#endif - #include "sp_context.h" #include "sp_state.h" #include "sp_headers.h" @@ -60,9 +54,6 @@ struct quad_shade_stage struct tgsi_exec_machine machine; struct tgsi_exec_vector *inputs, *outputs; int colorOutSlot, depthOutSlot; -#ifdef MESA_LLVM - struct gallivm_prog *llvm_prog; -#endif }; @@ -74,46 +65,6 @@ quad_shade_stage(struct quad_stage *qs) } -/** - * Compute quad X,Y,Z,W for the four fragments in a quad. - * Note that we only need to "compute" X and Y for the upper-left fragment. - * We could do less work if we're not depth testing, or there's no - * perspective-corrected attributes, but that's seldom. - */ -static void -setup_pos_vector(const struct tgsi_interp_coef *coef, - float x, float y, - struct tgsi_exec_vector *quadpos) -{ - uint chan; - /* do X */ - quadpos->xyzw[0].f[0] = x; - /* do Y */ - quadpos->xyzw[1].f[0] = y; - /* do Z and W for all fragments in the quad */ - for (chan = 2; chan < 4; chan++) { - const float dadx = coef->dadx[chan]; - const float dady = coef->dady[chan]; - const float a0 = coef->a0[chan] + dadx * x + dady * y; - quadpos->xyzw[chan].f[0] = a0; - quadpos->xyzw[chan].f[1] = a0 + dadx; - quadpos->xyzw[chan].f[2] = a0 + dady; - quadpos->xyzw[chan].f[3] = a0 + dadx + dady; - } -} - - -typedef void (XSTDCALL *codegen_function)( - const struct tgsi_exec_vector *input, - struct tgsi_exec_vector *output, - float (*constant)[4], - struct tgsi_exec_vector *temporary, - const struct tgsi_interp_coef *coef -#if 0 - ,const struct tgsi_exec_vector *quadPos -#endif - ); - /** * Execute fragment shader for the four fragments in the quad. @@ -132,30 +83,10 @@ shade_quad( machine->InterpCoefs = quad->coef; - /* Compute X, Y, Z, W vals for this quad */ - setup_pos_vector(quad->posCoef, (float) quad->x0, (float) quad->y0, &machine->QuadPos); - /* run shader */ -#if defined(__i386__) || defined(__386__) - if( softpipe->use_sse ) { - codegen_function func = (codegen_function) x86_get_func( &softpipe->fs->sse2_program ); - func( - machine->Inputs, - machine->Outputs, - machine->Consts, - machine->Temps, - machine->InterpCoefs -#if 0 - ,machine->QuadPos -#endif - ); - quad->mask &= ~(machine->Temps[TGSI_EXEC_TEMP_KILMASK_I].xyzw[TGSI_EXEC_TEMP_KILMASK_C].u[0]); - } - else -#endif - { - quad->mask &= tgsi_exec_machine_run( machine ); - } + quad->mask &= softpipe->fs->run( softpipe->fs, + &qss->machine, + quad ); /* store result color */ if (qss->colorOutSlot >= 0) { @@ -199,107 +130,6 @@ shade_quad( } } -#if 0 -#ifdef MESA_LLVM -#define DLLVM 0 -static void -shade_quad_llvm(struct quad_stage *qs, - struct quad_header *quad) -{ - struct quad_shade_stage *qss = quad_shade_stage(qs); - struct softpipe_context *softpipe = qs->softpipe; - float dests[4][16][4] ALIGN16_ATTRIB; - float inputs[4][16][4] ALIGN16_ATTRIB; - const float fx = (float) quad->x0; - const float fy = (float) quad->y0; - struct gallivm_prog *llvm = qss->llvm_prog; - - inputs[0][0][0] = fx; - inputs[1][0][0] = fx + 1.0f; - inputs[2][0][0] = fx; - inputs[3][0][0] = fx + 1.0f; - - inputs[0][0][1] = fy; - inputs[1][0][1] = fy; - inputs[2][0][1] = fy + 1.0f; - inputs[3][0][1] = fy + 1.0f; -#if DLLVM - debug_printf("MASK = %d\n", quad->mask); -#endif - gallivm_prog_inputs_interpolate(llvm, inputs, quad->coef); -#if DLLVM - for (int i = 0; i < 4; ++i) { - for (int j = 0; j < 2; ++j) { - debug_printf("IN(%d,%d) [%f %f %f %f]\n", i, j, - inputs[i][j][0], inputs[i][j][1], inputs[i][j][2], inputs[i][j][3]); - } - } -#endif - - quad->mask &= - gallivm_fragment_shader_exec(llvm, fx, fy, dests, inputs, - softpipe->mapped_constants[PIPE_SHADER_FRAGMENT], - qss->samplers); -#if DLLVM - debug_printf("OUT LLVM = 1[%f %f %f %f], 2[%f %f %f %f]\n", - dests[0][0][0], dests[0][0][1], dests[0][0][2], dests[0][0][3], - dests[0][1][0], dests[0][1][1], dests[0][1][2], dests[0][1][3]); -#endif - - /* store result color */ - if (qss->colorOutSlot >= 0) { - unsigned i; - /* XXX need to handle multiple color outputs someday */ - assert(qss->stage.softpipe->fs->shader.output_semantic_name[qss->colorOutSlot] - == TGSI_SEMANTIC_COLOR); - for (i = 0; i < QUAD_SIZE; ++i) { - quad->outputs.color[0][i] = dests[i][qss->colorOutSlot][0]; - quad->outputs.color[1][i] = dests[i][qss->colorOutSlot][1]; - quad->outputs.color[2][i] = dests[i][qss->colorOutSlot][2]; - quad->outputs.color[3][i] = dests[i][qss->colorOutSlot][3]; - } - } -#if DLLVM - for (int i = 0; i < QUAD_SIZE; ++i) { - debug_printf("QLLVM%d(%d) [%f, %f, %f, %f]\n", i, qss->colorOutSlot, - quad->outputs.color[0][i], - quad->outputs.color[1][i], - quad->outputs.color[2][i], - quad->outputs.color[3][i]); - } -#endif - - /* store result Z */ - if (qss->depthOutSlot >= 0) { - /* output[slot] is new Z */ - uint i; - for (i = 0; i < 4; i++) { - quad->outputs.depth[i] = dests[i][0][2]; - } - } - else { - /* copy input Z (which was interpolated by the executor) to output Z */ - uint i; - for (i = 0; i < 4; i++) { - quad->outputs.depth[i] = inputs[i][0][2]; - } - } -#if DLLVM - debug_printf("D [%f, %f, %f, %f] mask = %d\n", - quad->outputs.depth[0], - quad->outputs.depth[1], - quad->outputs.depth[2], - quad->outputs.depth[3], quad->mask); -#endif - - /* shader may cull fragments */ - if( quad->mask ) { - qs->next->run( qs->next, quad ); - } -} -#endif /*MESA_LLVM*/ -#endif - /** * Per-primitive (or per-begin?) setup */ @@ -315,15 +145,6 @@ static void shade_begin(struct quad_stage *qs) qss->samplers[i].texture = &softpipe->texture[i]->base; } -#ifdef MESA_LLVM - qss->llvm_prog = softpipe->fs->llvm_prog; -#endif - /* XXX only do this if the fragment shader changes... */ - tgsi_exec_machine_init(&qss->machine, - softpipe->fs->shader.tokens, - PIPE_MAX_SAMPLERS, - qss->samplers ); - /* find output slots for depth, color */ qss->colorOutSlot = -1; qss->depthOutSlot = -1; @@ -337,6 +158,10 @@ static void shade_begin(struct quad_stage *qs) break; } } + + softpipe->fs->prepare( softpipe->fs, + &qss->machine, + qss->samplers ); qs->next->begin(qs->next); } @@ -366,16 +191,7 @@ struct quad_stage *sp_quad_shade_stage( struct softpipe_context *softpipe ) qss->stage.softpipe = softpipe; qss->stage.begin = shade_begin; -#ifdef MESA_LLVM - /* disable until ported to accept - * x/y and soa layout - qss->stage.run = shade_quad_llvm; - */ - softpipe->use_sse = FALSE; - qss->stage.run = shade_quad; -#else qss->stage.run = shade_quad; -#endif qss->stage.destroy = shade_destroy; /* set TGSI sampler state that's constant */ @@ -386,5 +202,7 @@ struct quad_stage *sp_quad_shade_stage( struct softpipe_context *softpipe ) qss->samplers[i].cache = softpipe->tex_cache[i]; } + tgsi_exec_machine_init( &qss->machine ); + return &qss->stage; } diff --git a/src/gallium/drivers/softpipe/sp_state.h b/src/gallium/drivers/softpipe/sp_state.h index b79db0d1f19..ef8cf67d4c3 100644 --- a/src/gallium/drivers/softpipe/sp_state.h +++ b/src/gallium/drivers/softpipe/sp_state.h @@ -33,8 +33,6 @@ #include "pipe/p_state.h" -#include "x86/rtasm/x86sse.h" - #define SP_NEW_VIEWPORT 0x1 #define SP_NEW_RASTERIZER 0x2 @@ -53,29 +51,37 @@ #define SP_NEW_QUERY 0x4000 +struct tgsi_sampler; +struct tgsi_interp_coef; +struct tgsi_exec_machine; -#ifdef MESA_LLVM -struct gallivm_prog; -#endif +/** Subclass of pipe_shader_state (though it doesn't really need to be). + * + * This is starting to look an awful lot like a quad pipeline stage... + */ +struct sp_fragment_shader { + struct pipe_shader_state shader; -struct vertex_info; + void (*prepare)( struct sp_fragment_shader *shader, + struct tgsi_exec_machine *machine, + struct tgsi_sampler *samplers); + /* Run the shader - this interface will get cleaned up in the + * future: + */ + unsigned (*run)( struct sp_fragment_shader *shader, + struct tgsi_exec_machine *machine, + struct quad_header *quad ); -/** Subclass of pipe_shader_state */ -struct sp_fragment_shader_state { - struct pipe_shader_state shader; -#if defined(__i386__) || defined(__386__) - struct x86_function sse2_program; -#endif -#ifdef MESA_LLVM - struct gallivm_prog *llvm_prog; -#endif + + void (*delete)( struct sp_fragment_shader * ); }; +struct vertex_info; /** Subclass of pipe_shader_state */ -struct sp_vertex_shader_state { +struct sp_vertex_shader { struct pipe_shader_state shader; struct draw_vertex_shader *draw_data; }; diff --git a/src/gallium/drivers/softpipe/sp_state_fs.c b/src/gallium/drivers/softpipe/sp_state_fs.c index 1e3cadd43d1..b0238f81737 100644 --- a/src/gallium/drivers/softpipe/sp_state_fs.c +++ b/src/gallium/drivers/softpipe/sp_state_fs.c @@ -27,16 +27,15 @@ #include "sp_context.h" #include "sp_state.h" +#include "sp_fs.h" #include "pipe/p_defines.h" #include "pipe/p_util.h" #include "pipe/p_inlines.h" #include "pipe/p_winsys.h" -#include "draw/draw_context.h" #include "pipe/p_shader_tokens.h" -#include "llvm/gallivm.h" +#include "draw/draw_context.h" #include "tgsi/util/tgsi_dump.h" -#include "tgsi/exec/tgsi_sse2.h" void * @@ -44,40 +43,22 @@ softpipe_create_fs_state(struct pipe_context *pipe, const struct pipe_shader_state *templ) { struct softpipe_context *softpipe = softpipe_context(pipe); - struct sp_fragment_shader_state *state; + struct sp_fragment_shader *state; - /* Decide whether we'll be codegenerating this shader and if so do - * that now. - */ - - state = CALLOC_STRUCT(sp_fragment_shader_state); - if (!state) - return NULL; + if (softpipe->dump_fs) + tgsi_dump(templ->tokens, 0); - state->shader = *templ; - - if (softpipe->dump_fs) { - tgsi_dump(state->shader.tokens, 0); - } + state = softpipe_create_fs_llvm( softpipe, templ ); + if (state) + return state; + + state = softpipe_create_fs_sse( softpipe, templ ); + if (state) + return state; -#ifdef MESA_LLVM - state->llvm_prog = 0; - -#if 0 - if (!gallivm_global_cpu_engine()) { - gallivm_cpu_engine_create(state->llvm_prog); - } - else - gallivm_cpu_jit_compile(gallivm_global_cpu_engine(), state->llvm_prog); -#endif - -#elif defined(__i386__) || defined(__386__) - if (softpipe->use_sse) { - x86_init_func( &state->sse2_program ); - tgsi_emit_sse2_fs( state->shader.tokens, &state->sse2_program ); - } -#endif + state = softpipe_create_fs_exec( softpipe, templ ); + assert(state); return state; } @@ -87,7 +68,7 @@ softpipe_bind_fs_state(struct pipe_context *pipe, void *fs) { struct softpipe_context *softpipe = softpipe_context(pipe); - softpipe->fs = (struct sp_fragment_shader_state *) fs; + softpipe->fs = (struct sp_fragment_shader *) fs; softpipe->dirty |= SP_NEW_FS; } @@ -96,13 +77,9 @@ softpipe_bind_fs_state(struct pipe_context *pipe, void *fs) void softpipe_delete_fs_state(struct pipe_context *pipe, void *fs) { - struct sp_fragment_shader_state *state = fs; - -#if defined(__i386__) || defined(__386__) - x86_release_func( &state->sse2_program ); -#endif - - FREE( state ); + struct sp_fragment_shader *state = fs; + + state->delete( state ); } @@ -111,9 +88,9 @@ softpipe_create_vs_state(struct pipe_context *pipe, const struct pipe_shader_state *templ) { struct softpipe_context *softpipe = softpipe_context(pipe); - struct sp_vertex_shader_state *state; + struct sp_vertex_shader *state; - state = CALLOC_STRUCT(sp_vertex_shader_state); + state = CALLOC_STRUCT(sp_vertex_shader); if (state == NULL ) { return NULL; } @@ -136,7 +113,7 @@ softpipe_bind_vs_state(struct pipe_context *pipe, void *vs) { struct softpipe_context *softpipe = softpipe_context(pipe); - softpipe->vs = (const struct sp_vertex_shader_state *)vs; + softpipe->vs = (const struct sp_vertex_shader *)vs; draw_bind_vertex_shader(softpipe->draw, softpipe->vs->draw_data); @@ -149,8 +126,8 @@ softpipe_delete_vs_state(struct pipe_context *pipe, void *vs) { struct softpipe_context *softpipe = softpipe_context(pipe); - struct sp_vertex_shader_state *state = - (struct sp_vertex_shader_state *)vs; + struct sp_vertex_shader *state = + (struct sp_vertex_shader *)vs; draw_delete_vertex_shader(softpipe->draw, state->draw_data); FREE( state ); diff --git a/src/gallium/include/pipe/p_state.h b/src/gallium/include/pipe/p_state.h index 4d3a6b2f413..1082343e2f5 100644 --- a/src/gallium/include/pipe/p_state.h +++ b/src/gallium/include/pipe/p_state.h @@ -253,7 +253,8 @@ struct pipe_surface unsigned status; /**< PIPE_SURFACE_STATUS_x */ unsigned clear_value; /**< may be temporary */ unsigned cpp; /**< bytes per pixel */ - unsigned width, height; + unsigned width; + unsigned height; unsigned pitch; /**< in pixels */ unsigned offset; /**< offset from start of buffer, in bytes */ unsigned refcount; @@ -272,13 +273,12 @@ struct pipe_texture enum pipe_texture_target target; /**< PIPE_TEXTURE_x */ enum pipe_format format; /**< PIPE_FORMAT_x */ - unsigned last_level; /**< Index of last mipmap level present/defined */ - unsigned width[PIPE_MAX_TEXTURE_LEVELS]; unsigned height[PIPE_MAX_TEXTURE_LEVELS]; unsigned depth[PIPE_MAX_TEXTURE_LEVELS]; - unsigned cpp; + unsigned cpp:8; + unsigned last_level:8; /**< Index of last mipmap level present/defined */ unsigned compressed:1; /* These are also refcounted: @@ -294,7 +294,7 @@ struct pipe_texture */ struct pipe_vertex_buffer { - unsigned pitch:11; /**< stride to same attrib in next vertex, in bytes */ + unsigned pitch; /**< stride to same attrib in next vertex, in bytes */ unsigned max_index; /**< number of vertices in this buffer */ unsigned buffer_offset; /**< offset to start of data in buffer, in bytes */ struct pipe_buffer *buffer; /**< the actual buffer */ @@ -307,13 +307,13 @@ struct pipe_vertex_buffer struct pipe_vertex_element { /** Offset of this attribute, in bytes, from the start of the vertex */ - unsigned src_offset:11; + unsigned src_offset; /** Which vertex_buffer (as given to pipe->set_vertex_buffer()) does * this attribute live in? */ - unsigned vertex_buffer_index:5; - unsigned nr_components:3; + unsigned vertex_buffer_index:8; + unsigned nr_components:8; enum pipe_format src_format; /**< PIPE_FORMAT_* */ }; diff --git a/src/mesa/x86/rtasm/x86sse.c b/src/mesa/x86/rtasm/x86sse.c index 1111e8db990..39c0e9b851a 100644 --- a/src/mesa/x86/rtasm/x86sse.c +++ b/src/mesa/x86/rtasm/x86sse.c @@ -820,7 +820,7 @@ static void x87_arith_op( struct x86_function *p, struct x86_reg dst, struct x86 assert(0); } else if (dst.idx == 0) { - assert(arg.file = file_REG32); + assert(arg.file == file_REG32); emit_1ub(p, 0xd8); emit_modrm_noreg(p, argmem_noreg, arg); } |