static LLVMValueRef
emit_array_fetch(
	struct lp_build_tgsi_context *bld_base,
	unsigned File, enum tgsi_opcode_type type,
	struct tgsi_declaration_range range,
	unsigned swizzle)
{
	struct lp_build_tgsi_soa_context *bld = lp_soa_context(bld_base);
	struct gallivm_state * gallivm = bld->bld_base.base.gallivm;
	LLVMBuilderRef builder = bld_base->base.gallivm->builder;

	unsigned i, size = range.Last - range.First + 1;
	LLVMTypeRef vec = LLVMVectorType(tgsi2llvmtype(bld_base, type), size);
	LLVMValueRef result = LLVMGetUndef(vec);

	struct tgsi_full_src_register tmp_reg = {};
	tmp_reg.Register.File = File;

	for (i = 0; i < size; ++i) {
		tmp_reg.Register.Index = i + range.First;
		LLVMValueRef temp = emit_fetch(bld_base, &tmp_reg, type, swizzle);
		result = LLVMBuildInsertElement(builder, result, temp,
			lp_build_const_int32(gallivm, i), "");
	}
	return result;
}
static LLVMValueRef
emit_fetch(
	struct lp_build_tgsi_context *bld_base,
	const struct tgsi_full_src_register *reg,
	enum tgsi_opcode_type type,
	unsigned swizzle)
{
	struct radeon_llvm_context * ctx = radeon_llvm_context(bld_base);
	struct lp_build_tgsi_soa_context *bld = lp_soa_context(bld_base);
	LLVMBuilderRef builder = bld_base->base.gallivm->builder;
	LLVMValueRef result, ptr;

	if (swizzle == ~0) {
		LLVMValueRef values[TGSI_NUM_CHANNELS];
		unsigned chan;
		for (chan = 0; chan < TGSI_NUM_CHANNELS; chan++) {
			values[chan] = emit_fetch(bld_base, reg, type, chan);
		}
		return lp_build_gather_values(bld_base->base.gallivm, values,
					      TGSI_NUM_CHANNELS);
	}

	if (reg->Register.Indirect) {
		struct tgsi_declaration_range range = get_array_range(bld_base,
			reg->Register.File, &reg->Indirect);
		return LLVMBuildExtractElement(builder,
			emit_array_fetch(bld_base, reg->Register.File, type, range, swizzle),
			emit_array_index(bld, &reg->Indirect, reg->Register.Index - range.First),
			"");
	}

	switch(reg->Register.File) {
	case TGSI_FILE_IMMEDIATE: {
		LLVMTypeRef ctype = tgsi2llvmtype(bld_base, type);
		return LLVMConstBitCast(bld->immediates[reg->Register.Index][swizzle], ctype);
	}

	case TGSI_FILE_INPUT:
		result = ctx->inputs[radeon_llvm_reg_index_soa(reg->Register.Index, swizzle)];
		break;

	case TGSI_FILE_TEMPORARY:
		ptr = lp_get_temp_ptr_soa(bld, reg->Register.Index, swizzle);
		result = LLVMBuildLoad(builder, ptr, "");
		break;

	case TGSI_FILE_OUTPUT:
		ptr = lp_get_output_ptr(bld, reg->Register.Index, swizzle);
		result = LLVMBuildLoad(builder, ptr, "");
		break;

	default:
		return LLVMGetUndef(tgsi2llvmtype(bld_base, type));
	}

	return bitcast(bld_base, type, result);
}
static LLVMValueRef
emit_tex(struct lp_build_tgsi_aos_context *bld,
         const struct tgsi_full_instruction *inst,
         enum lp_build_tex_modifier modifier)
{
   unsigned target;
   unsigned unit;
   LLVMValueRef coords;
   LLVMValueRef ddx;
   LLVMValueRef ddy;

   if (!bld->sampler) {
      _debug_printf("warning: found texture instruction but no sampler generator supplied\n");
      return bld->base.undef;
   }

   target = inst->Texture.Texture;

   coords = emit_fetch( bld, inst, 0 );

   if (modifier == LP_BLD_TEX_MODIFIER_EXPLICIT_DERIV) {
      ddx = emit_fetch( bld, inst, 1 );
      ddy = emit_fetch( bld, inst, 2 );
      unit = inst->Src[3].Register.Index;
   }  else {
#if 0
      ddx = lp_build_ddx( &bld->base, coords );
      ddy = lp_build_ddy( &bld->base, coords );
#else
      /* TODO */
      ddx = bld->base.one;
      ddy = bld->base.one;
#endif
      unit = inst->Src[1].Register.Index;
   }

   return bld->sampler->emit_fetch_texel(bld->sampler,
                                         &bld->base,
                                         target, unit,
                                         coords, ddx, ddy,
                                         modifier);
}
/**
 * Emit LLVM for one TGSI instruction.
 * \param return TRUE for success, FALSE otherwise
 */
static boolean
emit_instruction(
   struct lp_build_tgsi_aos_context *bld,
   const struct tgsi_full_instruction *inst,
   const struct tgsi_opcode_info *info,
   int *pc)
{
   LLVMValueRef src0, src1, src2;
   LLVMValueRef tmp0, tmp1;
   LLVMValueRef dst0;

   /*
    * Stores and write masks are handled in a general fashion after the long
    * instruction opcode switch statement.
    *
    * Although not stricitly necessary, we avoid generating instructions for
    * channels which won't be stored, in cases where's that easy. For some
    * complex instructions, like texture sampling, it is more convenient to
    * assume a full writemask and then let LLVM optimization passes eliminate
    * redundant code.
    */

   (*pc)++;

   assert(info->num_dst <= 1);
   if (info->num_dst) {
      dst0 = bld->base.undef;
   }

   switch (inst->Instruction.Opcode) {
   case TGSI_OPCODE_ARL:
      src0 = emit_fetch(bld, inst, 0);
      dst0 = lp_build_floor(&bld->base, src0);
      break;

   case TGSI_OPCODE_MOV:
      dst0 = emit_fetch(bld, inst, 0);
      break;

   case TGSI_OPCODE_LIT:
      return FALSE;

   case TGSI_OPCODE_RCP:
   /* TGSI_OPCODE_RECIP */
      src0 = emit_fetch(bld, inst, 0);
      dst0 = lp_build_rcp(&bld->base, src0);
      break;

   case TGSI_OPCODE_RSQ:
   /* TGSI_OPCODE_RECIPSQRT */
      src0 = emit_fetch(bld, inst, 0);
      tmp0 = lp_build_abs(&bld->base, src0);
      dst0 = lp_build_rsqrt(&bld->base, tmp0);
      break;

   case TGSI_OPCODE_EXP:
      return FALSE;

   case TGSI_OPCODE_LOG:
      return FALSE;

   case TGSI_OPCODE_MUL:
      src0 = emit_fetch(bld, inst, 0);
      src1 = emit_fetch(bld, inst, 1);
      dst0 = lp_build_mul(&bld->base, src0, src1);
      break;

   case TGSI_OPCODE_ADD:
      src0 = emit_fetch(bld, inst, 0);
      src1 = emit_fetch(bld, inst, 1);
      dst0 = lp_build_add(&bld->base, src0, src1);
      break;

   case TGSI_OPCODE_DP3:
   /* TGSI_OPCODE_DOT3 */
      return FALSE;

   case TGSI_OPCODE_DP4:
   /* TGSI_OPCODE_DOT4 */
      return FALSE;

   case TGSI_OPCODE_DST:
      return FALSE;

   case TGSI_OPCODE_MIN:
      src0 = emit_fetch(bld, inst, 0);
      src1 = emit_fetch(bld, inst, 1);
      dst0 = lp_build_max(&bld->base, src0, src1);
      break;

   case TGSI_OPCODE_MAX:
      src0 = emit_fetch(bld, inst, 0);
      src1 = emit_fetch(bld, inst, 1);
      dst0 = lp_build_max(&bld->base, src0, src1);
      break;

   case TGSI_OPCODE_SLT:
   /* TGSI_OPCODE_SETLT */
      src0 = emit_fetch(bld, inst, 0);
      src1 = emit_fetch(bld, inst, 1);
      tmp0 = lp_build_cmp(&bld->base, PIPE_FUNC_LESS, src0, src1);
      dst0 = lp_build_select(&bld->base, tmp0, bld->base.one, bld->base.zero);
      break;

   case TGSI_OPCODE_SGE:
   /* TGSI_OPCODE_SETGE */
      src0 = emit_fetch(bld, inst, 0);
      src1 = emit_fetch(bld, inst, 1);
      tmp0 = lp_build_cmp(&bld->base, PIPE_FUNC_GEQUAL, src0, src1);
      dst0 = lp_build_select(&bld->base, tmp0, bld->base.one, bld->base.zero);
      break;

   case TGSI_OPCODE_MAD:
   /* TGSI_OPCODE_MADD */
      src0 = emit_fetch(bld, inst, 0);
      src1 = emit_fetch(bld, inst, 1);
      src2 = emit_fetch(bld, inst, 2);
      tmp0 = lp_build_mul(&bld->base, src0, src1);
      dst0 = lp_build_add(&bld->base, tmp0, src2);
      break;

   case TGSI_OPCODE_SUB:
      src0 = emit_fetch(bld, inst, 0);
      src1 = emit_fetch(bld, inst, 1);
      dst0 = lp_build_sub(&bld->base, src0, src1);
      break;

   case TGSI_OPCODE_LRP:
      src0 = emit_fetch(bld, inst, 0);
      src1 = emit_fetch(bld, inst, 1);
      src2 = emit_fetch(bld, inst, 2);
      tmp0 = lp_build_sub(&bld->base, src1, src2);
      tmp0 = lp_build_mul(&bld->base, src0, tmp0);
      dst0 = lp_build_add(&bld->base, tmp0, src2);
      break;

   case TGSI_OPCODE_CND:
      src0 = emit_fetch(bld, inst, 0);
      src1 = emit_fetch(bld, inst, 1);
      src2 = emit_fetch(bld, inst, 2);
      tmp1 = lp_build_const_vec(bld->base.type, 0.5);
      tmp0 = lp_build_cmp(&bld->base, PIPE_FUNC_GREATER, src2, tmp1);
      dst0 = lp_build_select(&bld->base, tmp0, src0, src1);
      break;

   case TGSI_OPCODE_DP2A:
      return FALSE;

   case TGSI_OPCODE_FRC:
      src0 = emit_fetch(bld, inst, 0);
      tmp0 = lp_build_floor(&bld->base, src0);
      dst0 = lp_build_sub(&bld->base, src0, tmp0);
      break;

   case TGSI_OPCODE_CLAMP:
      src0 = emit_fetch(bld, inst, 0);
      src1 = emit_fetch(bld, inst, 1);
      src2 = emit_fetch(bld, inst, 2);
      tmp0 = lp_build_max(&bld->base, src0, src1);
      dst0 = lp_build_min(&bld->base, tmp0, src2);
      break;

   case TGSI_OPCODE_FLR:
      src0 = emit_fetch(bld, inst, 0);
      dst0 = lp_build_floor(&bld->base, src0);
      break;

   case TGSI_OPCODE_ROUND:
      src0 = emit_fetch(bld, inst, 0);
      dst0 = lp_build_round(&bld->base, src0);
      break;

   case TGSI_OPCODE_EX2:
      src0 = emit_fetch(bld, inst, 0);
      tmp0 = lp_build_swizzle_scalar_aos(&bld->base, src0, TGSI_SWIZZLE_X);
      dst0 = lp_build_exp2(&bld->base, tmp0);
      break;

   case TGSI_OPCODE_LG2:
      src0 = emit_fetch(bld, inst, 0);
      tmp0 = swizzle_scalar_aos(bld, src0, TGSI_SWIZZLE_X);
      dst0 = lp_build_log2(&bld->base, tmp0);
      break;

   case TGSI_OPCODE_POW:
      src0 = emit_fetch(bld, inst, 0);
      src0 = swizzle_scalar_aos(bld, src0, TGSI_SWIZZLE_X);
      src1 = emit_fetch(bld, inst, 1);
      src1 = swizzle_scalar_aos(bld, src1, TGSI_SWIZZLE_X);
      dst0 = lp_build_pow(&bld->base, src0, src1);
      break;

   case TGSI_OPCODE_XPD:
      return FALSE;

   case TGSI_OPCODE_ABS:
      src0 = emit_fetch(bld, inst, 0);
      dst0 = lp_build_abs(&bld->base, src0);
      break;

   case TGSI_OPCODE_RCC:
      /* deprecated? */
      assert(0);
      return FALSE;

   case TGSI_OPCODE_DPH:
      return FALSE;

   case TGSI_OPCODE_COS:
      src0 = emit_fetch(bld, inst, 0);
      tmp0 = swizzle_scalar_aos(bld, src0, TGSI_SWIZZLE_X);
      dst0 = lp_build_cos(&bld->base, tmp0);
      break;

   case TGSI_OPCODE_DDX:
      return FALSE;

   case TGSI_OPCODE_DDY:
      return FALSE;

   case TGSI_OPCODE_KILP:
      /* predicated kill */
      return FALSE;

   case TGSI_OPCODE_KIL:
      /* conditional kill */
      return FALSE;

   case TGSI_OPCODE_PK2H:
      return FALSE;
      break;

   case TGSI_OPCODE_PK2US:
      return FALSE;
      break;

   case TGSI_OPCODE_PK4B:
      return FALSE;
      break;

   case TGSI_OPCODE_PK4UB:
      return FALSE;

   case TGSI_OPCODE_RFL:
      return FALSE;

   case TGSI_OPCODE_SEQ:
      src0 = emit_fetch(bld, inst, 0);
      src1 = emit_fetch(bld, inst, 1);
      tmp0 = lp_build_cmp(&bld->base, PIPE_FUNC_EQUAL, src0, src1);
      dst0 = lp_build_select(&bld->base, tmp0, bld->base.one, bld->base.zero);
      break;

   case TGSI_OPCODE_SFL:
      dst0 = bld->base.zero;
      break;

   case TGSI_OPCODE_SGT:
      src0 = emit_fetch(bld, inst, 0);
      src1 = emit_fetch(bld, inst, 1);
      tmp0 = lp_build_cmp(&bld->base, PIPE_FUNC_GREATER, src0, src1);
      dst0 = lp_build_select(&bld->base, tmp0, bld->base.one, bld->base.zero);
      break;

   case TGSI_OPCODE_SIN:
      src0 = emit_fetch(bld, inst, 0);
      tmp0 = swizzle_scalar_aos(bld, src0, TGSI_SWIZZLE_X);
      dst0 = lp_build_sin(&bld->base, tmp0);
      break;

   case TGSI_OPCODE_SLE:
      src0 = emit_fetch(bld, inst, 0);
      src1 = emit_fetch(bld, inst, 1);
      tmp0 = lp_build_cmp(&bld->base, PIPE_FUNC_LEQUAL, src0, src1);
      dst0 = lp_build_select(&bld->base, tmp0, bld->base.one, bld->base.zero);
      break;

   case TGSI_OPCODE_SNE:
      src0 = emit_fetch(bld, inst, 0);
      src1 = emit_fetch(bld, inst, 1);
      tmp0 = lp_build_cmp(&bld->base, PIPE_FUNC_NOTEQUAL, src0, src1);
      dst0 = lp_build_select(&bld->base, tmp0, bld->base.one, bld->base.zero);
      break;

   case TGSI_OPCODE_STR:
      dst0 = bld->base.one;
      break;

   case TGSI_OPCODE_TEX:
      dst0 = emit_tex(bld, inst, LP_BLD_TEX_MODIFIER_NONE);
      break;

   case TGSI_OPCODE_TXD:
      dst0 = emit_tex(bld, inst, LP_BLD_TEX_MODIFIER_EXPLICIT_DERIV);
      break;

   case TGSI_OPCODE_UP2H:
      /* deprecated */
      assert (0);
      return FALSE;
      break;

   case TGSI_OPCODE_UP2US:
      /* deprecated */
      assert(0);
      return FALSE;
      break;

   case TGSI_OPCODE_UP4B:
      /* deprecated */
      assert(0);
      return FALSE;
      break;

   case TGSI_OPCODE_UP4UB:
      /* deprecated */
      assert(0);
      return FALSE;
      break;

   case TGSI_OPCODE_X2D:
      /* deprecated? */
      assert(0);
      return FALSE;
      break;

   case TGSI_OPCODE_ARA:
      /* deprecated */
      assert(0);
      return FALSE;
      break;

   case TGSI_OPCODE_ARR:
      src0 = emit_fetch(bld, inst, 0);
      dst0 = lp_build_round(&bld->base, src0);
      break;

   case TGSI_OPCODE_BRA:
      /* deprecated */
      assert(0);
      return FALSE;
      break;

   case TGSI_OPCODE_CAL:
      return FALSE;

   case TGSI_OPCODE_RET:
      return FALSE;

   case TGSI_OPCODE_END:
      *pc = -1;
      break;

   case TGSI_OPCODE_SSG:
   /* TGSI_OPCODE_SGN */
      tmp0 = emit_fetch(bld, inst, 0);
      dst0 = lp_build_sgn(&bld->base, tmp0);
      break;

   case TGSI_OPCODE_CMP:
      src0 = emit_fetch(bld, inst, 0);
      src1 = emit_fetch(bld, inst, 1);
      src2 = emit_fetch(bld, inst, 2);
      tmp0 = lp_build_cmp(&bld->base, PIPE_FUNC_LESS, src0, bld->base.zero);
      dst0 = lp_build_select(&bld->base, tmp0, src1, src2);
      break;

   case TGSI_OPCODE_SCS:
      return FALSE;

   case TGSI_OPCODE_TXB:
      dst0 = emit_tex(bld, inst, LP_BLD_TEX_MODIFIER_LOD_BIAS);
      break;

   case TGSI_OPCODE_NRM:
      /* fall-through */
   case TGSI_OPCODE_NRM4:
      return FALSE;

   case TGSI_OPCODE_DIV:
      /* deprecated */
      assert(0);
      return FALSE;
      break;

   case TGSI_OPCODE_DP2:
      return FALSE;

   case TGSI_OPCODE_TXL:
      dst0 = emit_tex(bld, inst, LP_BLD_TEX_MODIFIER_EXPLICIT_LOD);
      break;

   case TGSI_OPCODE_TXP:
      dst0 = emit_tex(bld, inst, LP_BLD_TEX_MODIFIER_PROJECTED);
      break;

   case TGSI_OPCODE_BRK:
      return FALSE;

   case TGSI_OPCODE_IF:
      return FALSE;

   case TGSI_OPCODE_BGNLOOP:
      return FALSE;

   case TGSI_OPCODE_BGNSUB:
      return FALSE;

   case TGSI_OPCODE_ELSE:
      return FALSE;

   case TGSI_OPCODE_ENDIF:
      return FALSE;

   case TGSI_OPCODE_ENDLOOP:
      return FALSE;

   case TGSI_OPCODE_ENDSUB:
      return FALSE;

   case TGSI_OPCODE_PUSHA:
      /* deprecated? */
      assert(0);
      return FALSE;
      break;

   case TGSI_OPCODE_POPA:
      /* deprecated? */
      assert(0);
      return FALSE;
      break;

   case TGSI_OPCODE_CEIL:
      src0 = emit_fetch(bld, inst, 0);
      dst0 = lp_build_ceil(&bld->base, src0);
      break;

   case TGSI_OPCODE_I2F:
      /* deprecated? */
      assert(0);
      return FALSE;
      break;

   case TGSI_OPCODE_NOT:
      /* deprecated? */
      assert(0);
      return FALSE;
      break;

   case TGSI_OPCODE_TRUNC:
      src0 = emit_fetch(bld, inst, 0);
      dst0 = lp_build_trunc(&bld->base, src0);
      break;

   case TGSI_OPCODE_SHL:
      /* deprecated? */
      assert(0);
      return FALSE;
      break;

   case TGSI_OPCODE_ISHR:
      /* deprecated? */
      assert(0);
      return FALSE;
      break;

   case TGSI_OPCODE_AND:
      /* deprecated? */
      assert(0);
      return FALSE;
      break;

   case TGSI_OPCODE_OR:
      /* deprecated? */
      assert(0);
      return FALSE;
      break;

   case TGSI_OPCODE_MOD:
      /* deprecated? */
      assert(0);
      return FALSE;
      break;

   case TGSI_OPCODE_XOR:
      /* deprecated? */
      assert(0);
      return FALSE;
      break;

   case TGSI_OPCODE_SAD:
      /* deprecated? */
      assert(0);
      return FALSE;
      break;

   case TGSI_OPCODE_TXF:
      /* deprecated? */
      assert(0);
      return FALSE;
      break;

   case TGSI_OPCODE_TXQ:
      /* deprecated? */
      assert(0);
      return FALSE;
      break;

   case TGSI_OPCODE_CONT:
      return FALSE;

   case TGSI_OPCODE_EMIT:
      return FALSE;
      break;

   case TGSI_OPCODE_ENDPRIM:
      return FALSE;
      break;

   case TGSI_OPCODE_NOP:
      break;

   default:
      return FALSE;
   }
   
   if (info->num_dst) {
      emit_store(bld, inst, 0, dst0);
   }

   return TRUE;
}
Exemple #5
0
int main(int argc, const char *argv[])
{
	int is_config = (argc == 2) && (strcmp(argv[1], "config") == 0);
	return is_config ? emit_config() : emit_fetch();
}