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, ®->Indirect); return LLVMBuildExtractElement(builder, emit_array_fetch(bld_base, reg->Register.File, type, range, swizzle), emit_array_index(bld, ®->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; }
int main(int argc, const char *argv[]) { int is_config = (argc == 2) && (strcmp(argv[1], "config") == 0); return is_config ? emit_config() : emit_fetch(); }