[Mesa-dev] [PATCH 2/2] r600g: add doubles support for CAYMAN

Glenn Kennard glenn.kennard at gmail.com
Thu Feb 19 18:59:13 PST 2015


On Fri, 20 Feb 2015 01:54:03 +0100, Dave Airlie <airlied at gmail.com> wrote:

> From: Dave Airlie <airlied at redhat.com>
>
> Only a subset of AMD GPUs supported by r600g support doubles,
> CAYMAN and CYPRESS are probably all we'll try and support, however
> I don't have a CYPRESS so ignore that for now.
>
> This disables SB support for doubles, as we think we need to
> make the scheduler smarter to introduce delay slots.
>
> Signed-off-by: Dave Airlie <airlied at redhat.com>
> ---
>  src/gallium/drivers/r600/r600_asm.c    |  14 ++
>  src/gallium/drivers/r600/r600_asm.h    |  15 ++
>  src/gallium/drivers/r600/r600_isa.h    |   8 +-
>  src/gallium/drivers/r600/r600_pipe.c   |   2 +
>  src/gallium/drivers/r600/r600_shader.c | 389  
> ++++++++++++++++++++++++++++++++-
>  src/gallium/drivers/r600/r600_shader.h |   2 +
>  6 files changed, 424 insertions(+), 6 deletions(-)
>
> diff --git a/src/gallium/drivers/r600/r600_asm.c  
> b/src/gallium/drivers/r600/r600_asm.c
> index 79e7f74..dc26b63 100644
> --- a/src/gallium/drivers/r600/r600_asm.c
> +++ b/src/gallium/drivers/r600/r600_asm.c
> @@ -252,6 +252,12 @@ static int alu_uses_rel(struct r600_bytecode *bc,  
> struct r600_bytecode_alu *alu)
>  	return 0;
>  }
> +static int is_alu_64bit_inst(struct r600_bytecode *bc, struct  
> r600_bytecode_alu *alu)
> +{
> +	const struct alu_op_info *op = r600_isa_alu(alu->op);
> +	return (op->flags & AF_64);
> +}
> +
>  static int is_alu_vec_unit_inst(struct r600_bytecode *bc, struct  
> r600_bytecode_alu *alu)
>  {
>  	unsigned slots = r600_isa_alu_slots(bc->isa->hw_class, alu->op);
> @@ -576,6 +582,12 @@ static int replace_gpr_with_pv_ps(struct  
> r600_bytecode *bc,
> 	for (i = 0; i < max_slots; ++i) {
>  		if (prev[i] && (prev[i]->dst.write || prev[i]->is_op3) &&  
> !prev[i]->dst.rel) {
> +
> +			if (is_alu_64bit_inst(bc, prev[i])) {
> +				gpr[i] = -1;
> +				continue;
> +			}
> +
>  			gpr[i] = prev[i]->dst.sel;
>  			/* cube writes more than PV.X */
>  			if (is_alu_reduction_inst(bc, prev[i]))
> @@ -591,6 +603,8 @@ static int replace_gpr_with_pv_ps(struct  
> r600_bytecode *bc,
>  		if(!alu)
>  			continue;
> +		if (is_alu_64bit_inst(bc, alu))
> +			continue;
>  		num_src = r600_bytecode_get_num_operands(bc, alu);
>  		for (src = 0; src < num_src; ++src) {
>  			if (!is_gpr(alu->src[src].sel) || alu->src[src].rel)
> diff --git a/src/gallium/drivers/r600/r600_asm.h  
> b/src/gallium/drivers/r600/r600_asm.h
> index e37d926..7b2734c 100644
> --- a/src/gallium/drivers/r600/r600_asm.h
> +++ b/src/gallium/drivers/r600/r600_asm.h
> @@ -279,4 +279,19 @@ void eg_bytecode_export_read(struct r600_bytecode  
> *bc,
> void r600_vertex_data_type(enum pipe_format pformat, unsigned *format,
>  			   unsigned *num_format, unsigned *format_comp, unsigned *endian);
> +
> +static INLINE int fp64_switch(int i)
> +{

Rather hard to decipher what this function does. How about  
fp64_gpr_channel_swizzle?

> +	switch (i) {
> +	case 0:
> +		return 1;
> +	case 1:
> +		return 0;
> +	case 2:
> +		return 3;
> +	case 3:
> +		return 2;
> +	}
> +	return 0;
> +}
>  #endif
> diff --git a/src/gallium/drivers/r600/r600_isa.h  
> b/src/gallium/drivers/r600/r600_isa.h
> index ec3f702..3cc135e 100644
> --- a/src/gallium/drivers/r600/r600_isa.h
> +++ b/src/gallium/drivers/r600/r600_isa.h
> @@ -339,11 +339,11 @@ static const struct alu_op_info alu_op_table[] = {

Might be an idea to fix up the table entries for MULADD for R6xx/R7xx,  
they are 4 slot too.

FREXP_64 is a 4 slot instruction, not 2.

>  		{"PRED_SETGT_64",             2, { 0x7C, 0xC7 },{   AF_V,  AF_V,   
> AF_V,  AF_V},  AF_PRED | AF_CC_GT | AF_64 },
>  		{"PRED_SETE_64",              2, { 0x7D, 0xC8 },{   AF_V,  AF_V,   
> AF_V,  AF_V},  AF_PRED | AF_CC_E | AF_64 },
>  		{"PRED_SETGE_64",             2, { 0x7E, 0xC9 },{   AF_V,  AF_V,   
> AF_V,  AF_V},  AF_PRED | AF_CC_GE | AF_64 },
> -		{"MUL_64",                    2, { 0x1B, 0xCA },{   AF_V,  AF_V,   
> AF_V,  AF_V},  AF_64 },
> +		{"MUL_64",                    2, { 0x1B, 0xCA },{   AF_V,  AF_V,

4 slot instruction also on r600/r700/evergreen, might as well fix the  
table entries while touching this

> AF_V,  AF_4V}, AF_64 },
>  		{"ADD_64",                    2, { 0x17, 0xCB },{   AF_V,  AF_V,   
> AF_V,  AF_V},  AF_64 },
>  		{"MOVA_INT",                  1, { 0x18, 0xCC },{   AF_V,  AF_V,   
> AF_V,  AF_V},  AF_MOVA },
> -		{"FLT64_TO_FLT32",            1, { 0x1C, 0xCD },{   AF_V,  AF_V,   
> AF_V,  AF_V},  0 },
> -		{"FLT32_TO_FLT64",            1, { 0x1D, 0xCE },{   AF_V,  AF_V,   
> AF_V,  AF_V},  0 },
> +		{"FLT64_TO_FLT32",            1, { 0x1C, 0xCD },{   AF_V,  AF_V,   
> AF_V,  AF_V},  AF_64 },
> +		{"FLT32_TO_FLT64",            1, { 0x1D, 0xCE },{   AF_V,  AF_V,   
> AF_V,  AF_V},  AF_64 },
>  		{"SAD_ACCUM_PREV_UINT",       2, {   -1, 0xCF },{      0,     0,   
> AF_V,  AF_V},  AF_UINT_DST | AF_PREV_NEXT },
>  		{"DOT",                       2, {   -1, 0xD0 },{      0,     0,   
> AF_V,  AF_V},  AF_PREV_NEXT },
>  		{"MUL_PREV",                  1, {   -1, 0xD1 },{      0,     0,   
> AF_V,  AF_V},  AF_PREV_INTERLEAVE },
> @@ -369,7 +369,7 @@ static const struct alu_op_info alu_op_table[] = {
>  		{"FMA",                       3, {   -1, 0x07 },{      0,     0,   
> AF_V,  AF_V},  0 },
>  		{"MULADD_INT24",              3, {   -1, 0x08 },{      0,     0,      
> 0,  AF_V},  AF_INT_DST | AF_24 },
>  		{"CNDNE_64",                  3, {   -1, 0x09 },{      0,     0,   
> AF_V,  AF_V},  AF_CMOV | AF_64 },
> -		{"FMA_64",                    3, {   -1, 0x0A },{      0,     0,   
> AF_V,  AF_V},  AF_64 },
> +		{"FMA_64",                    3, {   -1, 0x0A },{      0,     0,   
> AF_V,  AF_4V}, AF_64 },

4 slot also on evergreen

>  		{"LERP_UINT",                 3, {   -1, 0x0B },{      0,     0,   
> AF_V,  AF_V},  AF_UINT_DST },
>  		{"BIT_ALIGN_INT",             3, {   -1, 0x0C },{      0,     0,   
> AF_V,  AF_V},  AF_INT_DST },
>  		{"BYTE_ALIGN_INT",            3, {   -1, 0x0D },{      0,     0,   
> AF_V,  AF_V},  AF_INT_DST },
> diff --git a/src/gallium/drivers/r600/r600_pipe.c  
> b/src/gallium/drivers/r600/r600_pipe.c
> index a4b7b66..9d9f1d4 100644
> --- a/src/gallium/drivers/r600/r600_pipe.c
> +++ b/src/gallium/drivers/r600/r600_pipe.c
> @@ -488,6 +488,8 @@ static int r600_get_shader_param(struct pipe_screen*  
> pscreen, unsigned shader, e
>  			return PIPE_SHADER_IR_TGSI;
>  		}
>  	case PIPE_SHADER_CAP_DOUBLES:
> +		if (rscreen->b.family == CHIP_CAYMAN)
> +			return 1;
>  		return 0;
>  	}
>  	return 0;
> diff --git a/src/gallium/drivers/r600/r600_shader.c  
> b/src/gallium/drivers/r600/r600_shader.c
> index 77c9909..34c4e14 100644
> --- a/src/gallium/drivers/r600/r600_shader.c
> +++ b/src/gallium/drivers/r600/r600_shader.c
> @@ -47,7 +47,7 @@ MUL_LIT, FLT_TO_UINT, INT_TO_FLT, UINT_TO_FLT
>  These 8xx t-slot only opcodes become vector ops, with all four
>  slots expecting the arguments on sources a and b. Result is
>  broadcast to all channels.
> -MULLO_INT, MULHI_INT, MULLO_UINT, MULHI_UINT
> +MULLO_INT, MULHI_INT, MULLO_UINT, MULHI_UINT, MUL_64

Drop this hunk, its 4 slot on prior chips too, though the documentation is  
a bit contradictory in claiming its a t-slot instruction which it cannot  
possibly be due to the 4 inputs it takes...

>  These 8xx t-slot only opcodes become vector ops in the z, y, and
>  x slots.
>  EXP_IEEE, LOG_IEEE/CLAMPED,  
> RECIP_IEEE/CLAMPED/FF/INT/UINT/_64/CLAMPED_64
> @@ -163,6 +163,8 @@ int r600_pipe_shader_create(struct pipe_context *ctx,
>  	use_sb &= (shader->shader.processor_type != TGSI_PROCESSOR_GEOMETRY);
>  	/* disable SB for shaders using CF_INDEX_0/1 (sampler/ubo array  
> indexing) as it doesn't handle those currently */
>  	use_sb &= !shader->shader.uses_index_registers;
> +	/* disable SB for shaders using doubles */

Note that its a scheduling issue

> +	use_sb &= !shader->shader.uses_doubles;
> 	/* Check if the bytecode has already been built.  When using the llvm
>  	 * backend, r600_shader_from_tgsi() will take care of building the
> @@ -339,7 +341,7 @@ static int tgsi_is_supported(struct r600_shader_ctx  
> *ctx)
>  	struct tgsi_full_instruction *i =  
> &ctx->parse.FullToken.FullInstruction;
>  	int j;
> -	if (i->Instruction.NumDstRegs > 1) {
> +	if (i->Instruction.NumDstRegs > 1 && i->Instruction.Opcode !=  
> TGSI_OPCODE_DFRACEXP) {
>  		R600_ERR("too many dst (%d)\n", i->Instruction.NumDstRegs);
>  		return -EINVAL;
>  	}
> @@ -1827,6 +1829,9 @@ static int r600_shader_from_tgsi(struct  
> r600_context *rctx,
>  	ctx.tokens = tokens;
>  	tgsi_scan_shader(tokens, &ctx.info);
>  	shader->indirect_files = ctx.info.indirect_files;
> +
> +	shader->uses_doubles = ctx.info.uses_doubles;
> +
>  	indirect_gprs = ctx.info.indirect_files & ~(1 << TGSI_FILE_CONSTANT);
>  	tgsi_parse_init(&ctx.parse, tokens);
>  	ctx.type = ctx.parse.FullHeader.Processor.Processor;
> @@ -2608,6 +2613,168 @@ static int tgsi_last_instruction(unsigned  
> writemask)
>  	return lasti;
>  }
> +
> +
> +static int tgsi_op2_64_params(struct r600_shader_ctx *ctx, bool  
> singledest, bool swap)
> +{
> +	struct tgsi_full_instruction *inst =  
> &ctx->parse.FullToken.FullInstruction;
> +	unsigned write_mask = inst->Dst[0].Register.WriteMask;
> +	struct r600_bytecode_alu alu;
> +	int i, j, r, lasti = tgsi_last_instruction(write_mask);

dead assignment

> +	int use_tmp = 0;
> +
> +	if (singledest) {
> +		switch (write_mask) {
> +		case 0x1:
> +			write_mask = 0x3;
> +			break;
> +		case 0x2:
> +			use_tmp = 1;
> +			write_mask = 0x3;
> +			break;
> +		case 0x4:
> +			write_mask = 0xc;
> +			break;
> +		case 0x8:
> +			write_mask = 0xc;
> +			use_tmp = 3;
> +			break;
> +		}
> +	}
> +
> +	lasti = tgsi_last_instruction(write_mask);
> +	for (i = 0; i <= lasti; i++) {
> +
> +		if (!(write_mask & (1 << i)))
> +			continue;
> +
> +		memset(&alu, 0, sizeof(struct r600_bytecode_alu));
> +
> +		if (singledest) {
> +			tgsi_dst(ctx, &inst->Dst[0], i, &alu.dst);
> +			if (use_tmp) {
> +				alu.dst.sel = ctx->temp_reg;
> +				alu.dst.chan = i;
> +				alu.dst.write = 1;
> +			}
> +			if (i == 1 || i == 3)
> +				alu.dst.write = 0;
> +		} else
> +			tgsi_dst(ctx, &inst->Dst[0], i, &alu.dst);
> +
> +		alu.op = ctx->inst_info->op;
> +
> +		if (ctx->inst_info->tgsi_opcode == TGSI_OPCODE_DABS) {
> +			r600_bytecode_src(&alu.src[0], &ctx->src[0], i);
> +		} else if (!swap) {
> +			for (j = 0; j < inst->Instruction.NumSrcRegs; j++) {
> +				r600_bytecode_src(&alu.src[j], &ctx->src[j], fp64_switch(i));
> +			}
> +		} else {
> +			r600_bytecode_src(&alu.src[0], &ctx->src[1], fp64_switch(i));
> +			r600_bytecode_src(&alu.src[1], &ctx->src[0], fp64_switch(i));
> +		}
> +
> +		/* handle some special cases */
> +		if (i == 1 || i == 3) {
> +			switch (ctx->inst_info->tgsi_opcode) {
> +			case TGSI_OPCODE_SUB:
> +				r600_bytecode_src_toggle_neg(&alu.src[1]);
> +				break;
> +			case TGSI_OPCODE_DABS:
> +				r600_bytecode_src_set_abs(&alu.src[0]);
> +				break;
> +			default:
> +				break;
> +			}
> +		}
> +		if (i == lasti) {
> +			alu.last = 1;
> +		}
> +		r = r600_bytecode_add_alu(ctx->bc, &alu);
> +		if (r)
> +			return r;
> +	}
> +
> +	if (use_tmp) {
> +		write_mask = inst->Dst[0].Register.WriteMask;
> +
> +		/* move result from temp to dst */
> +		for (i = 0; i <= lasti; i++) {
> +			if (!(write_mask & (1 << i)))
> +				continue;
> +
> +			memset(&alu, 0, sizeof(struct r600_bytecode_alu));
> +			alu.op = ALU_OP1_MOV;
> +			tgsi_dst(ctx, &inst->Dst[0], i, &alu.dst);
> +			alu.src[0].sel = ctx->temp_reg;
> +			alu.src[0].chan = use_tmp - 1;
> +			alu.last = (i == lasti);
> +
> +			r = r600_bytecode_add_alu(ctx->bc, &alu);
> +			if (r)
> +				return r;
> +		}
> +	}
> +	return 0;
> +}
> +
> +static int tgsi_op2_64(struct r600_shader_ctx *ctx)
> +{
> +	struct tgsi_full_instruction *inst =  
> &ctx->parse.FullToken.FullInstruction;
> +	unsigned write_mask = inst->Dst[0].Register.WriteMask;
> +	/* confirm writemaskiing */

assiiert?

> +	if ((write_mask & 0x3) != 0x3 &&
> +	    (write_mask & 0xc) != 0xc) {
> +		fprintf(stderr, "illegal writemask for 64-bit: 0x%x\n", write_mask);
> +		return -1;
> +	}
> +	return tgsi_op2_64_params(ctx, false, false);
> +}
> +
> +static int tgsi_op2_64_single_dest(struct r600_shader_ctx *ctx)
> +{
> +	return tgsi_op2_64_params(ctx, true, false);
> +}
> +
> +static int tgsi_op2_64_single_dest_s(struct r600_shader_ctx *ctx)

shortage of string? tgsi_op2_64_single_dest_swap?

> +{
> +	return tgsi_op2_64_params(ctx, true, true);
> +}
> +
> +static int tgsi_op3_64(struct r600_shader_ctx *ctx)
> +{
> +	struct tgsi_full_instruction *inst =  
> &ctx->parse.FullToken.FullInstruction;
> +	struct r600_bytecode_alu alu;
> +	int i, j, r;
> +	int lasti = 3;
> +	int tmp = r600_get_temp(ctx);
> +
> +	for (i = 0; i < lasti + 1; i++) {
> +
> +		memset(&alu, 0, sizeof(struct r600_bytecode_alu));
> +		alu.op = ctx->inst_info->op;
> +		for (j = 0; j < inst->Instruction.NumSrcRegs; j++) {
> +			r600_bytecode_src(&alu.src[j], &ctx->src[j], i == 3 ? 0 : 1);

i == 3 Might deserve a comment

> +		}
> +
> +		if (inst->Dst[0].Register.WriteMask & (1 << i))
> +			tgsi_dst(ctx, &inst->Dst[0], i, &alu.dst);
> +		else
> +			alu.dst.sel = tmp;
> +
> +		alu.dst.chan = i;
> +		alu.is_op3 = 1;
> +		if (i == lasti) {
> +			alu.last = 1;
> +		}
> +		r = r600_bytecode_add_alu(ctx->bc, &alu);
> +		if (r)
> +			return r;
> +	}
> +	return 0;
> +}
> +
>  static int tgsi_op2_s(struct r600_shader_ctx *ctx, int swap, int  
> trans_only)
>  {
>  	struct tgsi_full_instruction *inst =  
> &ctx->parse.FullToken.FullInstruction;
> @@ -2724,6 +2891,152 @@ static int tgsi_ineg(struct r600_shader_ctx *ctx)
> }
> +static int tgsi_dneg(struct r600_shader_ctx *ctx)
> +{
> +	struct tgsi_full_instruction *inst =  
> &ctx->parse.FullToken.FullInstruction;
> +	struct r600_bytecode_alu alu;
> +	int i, r;
> +	int lasti = tgsi_last_instruction(inst->Dst[0].Register.WriteMask);
> +
> +	for (i = 0; i < lasti + 1; i++) {
> +
> +		if (!(inst->Dst[0].Register.WriteMask & (1 << i)))
> +			continue;
> +		memset(&alu, 0, sizeof(struct r600_bytecode_alu));
> +		alu.op = ALU_OP1_MOV;
> +
> +		r600_bytecode_src(&alu.src[0], &ctx->src[0], i);
> +
> +		if (i == 1 || i == 3)
> +			r600_bytecode_src_toggle_neg(&alu.src[0]);
> +		tgsi_dst(ctx, &inst->Dst[0], i, &alu.dst);
> +
> +		if (i == lasti) {
> +			alu.last = 1;
> +		}
> +		r = r600_bytecode_add_alu(ctx->bc, &alu);
> +		if (r)
> +			return r;
> +	}
> +	return 0;
> +
> +}
> +
> +static int tgsi_dfracexp(struct r600_shader_ctx *ctx)
> +{
> +	struct tgsi_full_instruction *inst =  
> &ctx->parse.FullToken.FullInstruction;
> +	struct r600_bytecode_alu alu;
> +	unsigned write_mask = inst->Dst[0].Register.WriteMask;
> +	int i, j, r;
> +	int firsti = write_mask == 0xc ? 2 : 0;
> +
> +	for (i = 0; i <= 3; i++) {
> +		memset(&alu, 0, sizeof(struct r600_bytecode_alu));
> +		alu.op = ctx->inst_info->op;
> +
> +		alu.dst.sel = ctx->temp_reg;
> +		alu.dst.chan = i;
> +		alu.dst.write = 1;
> +		for (j = 0; j < inst->Instruction.NumSrcRegs; j++) {
> +			r600_bytecode_src(&alu.src[j], &ctx->src[j], fp64_switch(i));
> +		}
> +
> +		if (i == 3)
> +			alu.last = 1;
> +
> +		r = r600_bytecode_add_alu(ctx->bc, &alu);
> +		if (r)
> +			return r;
> +	}
> +
> +	/* MOV first two channels to writemask dst0 */
> +	for (i = 0; i <= 1; i++) {
> +		memset(&alu, 0, sizeof(struct r600_bytecode_alu));
> +		alu.op = ALU_OP1_MOV;
> +		alu.src[0].chan = i + 2;
> +		alu.src[0].sel = ctx->temp_reg;
> +
> +		tgsi_dst(ctx, &inst->Dst[0], firsti + i, &alu.dst);
> +		alu.dst.write = (inst->Dst[0].Register.WriteMask >> (firsti + i)) & 1;
> +		alu.last = 1;
> +		r = r600_bytecode_add_alu(ctx->bc, &alu);
> +		if (r)
> +			return r;
> +	}
> +
> +	for (i = 0; i <= 3; i++) {
> +		if (inst->Dst[1].Register.WriteMask & (1 << i)) {
> +			/* MOV third channels to writemask dst1 */
> +			memset(&alu, 0, sizeof(struct r600_bytecode_alu));
> +			alu.op = ALU_OP1_MOV;
> +			alu.src[0].chan = 1;
> +			alu.src[0].sel = ctx->temp_reg;
> +
> +			tgsi_dst(ctx, &inst->Dst[1], i, &alu.dst);
> +			alu.last = 1;
> +			r = r600_bytecode_add_alu(ctx->bc, &alu);
> +			if (r)
> +				return r;
> +			break;
> +		}
> +	}
> +	return 0;
> +}
> +
> +static int cayman_emit_double_instr(struct r600_shader_ctx *ctx)
> +{
> +	struct tgsi_full_instruction *inst =  
> &ctx->parse.FullToken.FullInstruction;
> +	int i, r;
> +	struct r600_bytecode_alu alu;
> +	int last_slot = 3;
> +	int lasti = tgsi_last_instruction(inst->Dst[0].Register.WriteMask);
> +	int t1 = ctx->temp_reg;
> +
> +	/* these have to write the result to X/Y by the looks of it */
> +	for (i = 0 ; i < last_slot; i++) {
> +		memset(&alu, 0, sizeof(struct r600_bytecode_alu));
> +		alu.op = ctx->inst_info->op;
> +
> +		/* should only be one src regs */
> +		assert (inst->Instruction.NumSrcRegs == 1);
> +
> +		r600_bytecode_src(&alu.src[0], &ctx->src[0], 1);
> +		r600_bytecode_src(&alu.src[1], &ctx->src[0], 0);
> +
> +		/* RSQ should take the absolute value of src */
> +		if (ctx->inst_info->tgsi_opcode == TGSI_OPCODE_DRSQ ||
> +		    ctx->inst_info->tgsi_opcode == TGSI_OPCODE_DSQRT) {
> +			r600_bytecode_src_set_abs(&alu.src[1]);
> +		}
> +		alu.dst.sel = t1;
> +		alu.dst.chan = i;
> +		alu.dst.write = (i == 0 || i == 1);
> +
> +		if (i == last_slot - 1)
> +			alu.last = 1;
> +		r = r600_bytecode_add_alu(ctx->bc, &alu);
> +		if (r)
> +			return r;
> +	}
> +
> +	for (i = 0 ; i <= lasti; i++) {
> +		if (!(inst->Dst[0].Register.WriteMask & (1 << i)))
> +			continue;
> +		memset(&alu, 0, sizeof(struct r600_bytecode_alu));
> +		alu.op = ALU_OP1_MOV;
> +		alu.src[0].sel = t1;
> +		alu.src[0].chan = (i == 0 || i == 2) ? 0 : 1;
> +		tgsi_dst(ctx, &inst->Dst[0], i, &alu.dst);
> +		alu.dst.write = 1;
> +		if (i == lasti)
> +			alu.last = 1;
> +		r = r600_bytecode_add_alu(ctx->bc, &alu);
> +		if (r)
> +			return r;
> +	}
> +	return 0;
> +}
> +
>  static int cayman_emit_float_instr(struct r600_shader_ctx *ctx)
>  {
>  	struct tgsi_full_instruction *inst =  
> &ctx->parse.FullToken.FullInstruction;
> @@ -2802,6 +3115,55 @@ static int cayman_mul_int_instr(struct  
> r600_shader_ctx *ctx)
>  	return 0;
>  }
> +
> +static int cayman_mul_double_instr(struct r600_shader_ctx *ctx)
> +{
> +	struct tgsi_full_instruction *inst =  
> &ctx->parse.FullToken.FullInstruction;
> +	int i, j, k, r;
> +	struct r600_bytecode_alu alu;
> +	int lasti = tgsi_last_instruction(inst->Dst[0].Register.WriteMask);
> +	int t1 = ctx->temp_reg;
> +
> +	for (k = 0; k <= 2; k++) {
> +		if (!(inst->Dst[0].Register.WriteMask & (0x3 << (k * 2))))
> +			continue;
> +
> +		for (i = 0; i < 4; i++) {
> +			memset(&alu, 0, sizeof(struct r600_bytecode_alu));
> +			alu.op = ctx->inst_info->op;
> +			for (j = 0; j < inst->Instruction.NumSrcRegs; j++) {
> +				r600_bytecode_src(&alu.src[j], &ctx->src[j], k * 2 + ((i == 3) ? 0  
> : 1));;
> +			}
> +			alu.dst.sel = t1;
> +			alu.dst.chan = i;
> +			alu.dst.write = 1;
> +			if (i == 3)
> +				alu.last = 1;
> +			r = r600_bytecode_add_alu(ctx->bc, &alu);
> +			if (r)
> +				return r;
> +		}
> +	}
> +
> +	for (i = 0; i <= lasti; i++) {
> +		if (!(inst->Dst[0].Register.WriteMask & (1 << i)))
> +			continue;
> +		memset(&alu, 0, sizeof(struct r600_bytecode_alu));
> +		alu.op = ALU_OP1_MOV;
> +		alu.src[0].sel = t1;
> +		alu.src[0].chan = i;
> +		tgsi_dst(ctx, &inst->Dst[0], i, &alu.dst);
> +		alu.dst.write = 1;
> +		if (i == lasti)
> +			alu.last = 1;
> +		r = r600_bytecode_add_alu(ctx->bc, &alu);
> +		if (r)
> +			return r;
> +	}
> +
> +	return 0;
> +}
> +
>  /*
>   * r600 - trunc to -PI..PI range
>   * r700 - normalize by dividing by 2PI
> @@ -7869,5 +8231,28 @@ static struct r600_shader_tgsi_instruction  
> cm_shader_tgsi_instruction[] = {
>  	{TGSI_OPCODE_INTERP_CENTROID,	0, ALU_OP0_NOP, tgsi_interp_egcm},
>  	{TGSI_OPCODE_INTERP_SAMPLE,		0, ALU_OP0_NOP, tgsi_interp_egcm},
>  	{TGSI_OPCODE_INTF2DERP_OFFSET,		0, ALU_OP0_NOP, tgsi_interp_egcm},
> +	{TGSI_OPCODE_F2D,	0, ALU_OP1_FLT32_TO_FLT64, tgsi_op2_64},
> +	{TGSI_OPCODE_D2F,	0, ALU_OP1_FLT64_TO_FLT32, tgsi_op2_64_single_dest},
> +	{TGSI_OPCODE_DABS,	0, ALU_OP1_MOV, tgsi_op2_64},
> +	{TGSI_OPCODE_DNEG,	0, ALU_OP2_ADD_64, tgsi_dneg},
> +	{TGSI_OPCODE_DADD,	0, ALU_OP2_ADD_64, tgsi_op2_64},
> +	{TGSI_OPCODE_DMUL,	0, ALU_OP2_MUL_64, cayman_mul_double_instr},
> +	{TGSI_OPCODE_DMAX,	0, ALU_OP2_MAX_64, tgsi_op2_64},
> +	{TGSI_OPCODE_DMIN,	0, ALU_OP2_MIN_64, tgsi_op2_64},
> +	{TGSI_OPCODE_DSLT,	0, ALU_OP2_SETGT_64, tgsi_op2_64_single_dest_s},
> +	{TGSI_OPCODE_DSGE,	0, ALU_OP2_SETGE_64, tgsi_op2_64_single_dest},
> +	{TGSI_OPCODE_DSEQ,	0, ALU_OP2_SETE_64, tgsi_op2_64_single_dest},
> +	{TGSI_OPCODE_DSNE,	0, ALU_OP2_SETNE_64, tgsi_op2_64_single_dest},
> +	{TGSI_OPCODE_DRCP,	0, ALU_OP2_RECIP_64, cayman_emit_double_instr},
> +	{TGSI_OPCODE_DSQRT,	0, ALU_OP2_SQRT_64, cayman_emit_double_instr},
> +	{TGSI_OPCODE_DMAD,	0, ALU_OP3_FMA_64, tgsi_op3_64},
> +	{TGSI_OPCODE_DFRAC,	0, ALU_OP1_FRACT_64, tgsi_op2_64},
> +	{TGSI_OPCODE_DLDEXP,	0, ALU_OP2_LDEXP_64, tgsi_op2_64},
> +	{TGSI_OPCODE_DFRACEXP,	0, ALU_OP1_FREXP_64, tgsi_dfracexp},
> +	{TGSI_OPCODE_D2I,	0, ALU_OP0_NOP, tgsi_unsupported},
> +	{TGSI_OPCODE_I2D,	0, ALU_OP0_NOP, tgsi_unsupported},
> +	{TGSI_OPCODE_D2U,	0, ALU_OP0_NOP, tgsi_unsupported},
> +	{TGSI_OPCODE_U2D,	0, ALU_OP0_NOP, tgsi_unsupported},
> +	{TGSI_OPCODE_DRSQ,	0, ALU_OP2_RECIPSQRT_64, cayman_emit_double_instr},
>  	{TGSI_OPCODE_LAST,	0, ALU_OP0_NOP, tgsi_unsupported},
>  };
> diff --git a/src/gallium/drivers/r600/r600_shader.h  
> b/src/gallium/drivers/r600/r600_shader.h
> index b2559e9..a10004c 100644
> --- a/src/gallium/drivers/r600/r600_shader.h
> +++ b/src/gallium/drivers/r600/r600_shader.h
> @@ -87,6 +87,8 @@ struct r600_shader {
>  	unsigned		vs_as_gs_a;
>  	unsigned                ps_prim_id_input;
>  	struct r600_shader_array * arrays;
> +
> +	boolean			uses_doubles;
>  };
> struct r600_shader_key {

With above nits fixed,
Reviewed-by: Glenn Kennard <glenn.kennard at gmail.com>


More information about the mesa-dev mailing list