+static inline void callstack_check_depth(struct r600_shader_ctx *ctx, unsigned reason, unsigned check_max_only);
+static void fc_pushlevel(struct r600_shader_ctx *ctx, int type);
+static int tgsi_else(struct r600_shader_ctx *ctx);
+static int tgsi_endif(struct r600_shader_ctx *ctx);
+static int tgsi_bgnloop(struct r600_shader_ctx *ctx);
+static int tgsi_endloop(struct r600_shader_ctx *ctx);
+static int tgsi_loop_brk_cont(struct r600_shader_ctx *ctx);
+
+/*
+ * bytestream -> r600 shader
+ *
+ * These functions are used to transform the output of the LLVM backend into
+ * struct r600_bytecode.
+ */
+
+static unsigned r600_src_from_byte_stream(unsigned char * bytes,
+ unsigned bytes_read, struct r600_bytecode_alu * alu, unsigned src_idx)
+{
+ unsigned i;
+ unsigned sel0, sel1;
+ sel0 = bytes[bytes_read++];
+ sel1 = bytes[bytes_read++];
+ alu->src[src_idx].sel = sel0 | (sel1 << 8);
+ alu->src[src_idx].chan = bytes[bytes_read++];
+ alu->src[src_idx].neg = bytes[bytes_read++];
+ alu->src[src_idx].abs = bytes[bytes_read++];
+ alu->src[src_idx].rel = bytes[bytes_read++];
+ alu->src[src_idx].kc_bank = bytes[bytes_read++];
+ for (i = 0; i < 4; i++) {
+ alu->src[src_idx].value |= bytes[bytes_read++] << (i * 8);
+ }
+ return bytes_read;
+}
+
+static unsigned r600_alu_from_byte_stream(struct r600_shader_ctx *ctx,
+ unsigned char * bytes, unsigned bytes_read)
+{
+ unsigned src_idx;
+ unsigned inst0, inst1;
+ struct r600_bytecode_alu alu;
+ memset(&alu, 0, sizeof(alu));
+ for(src_idx = 0; src_idx < 3; src_idx++) {
+ bytes_read = r600_src_from_byte_stream(bytes, bytes_read,
+ &alu, src_idx);
+ }
+
+ alu.dst.sel = bytes[bytes_read++];
+ alu.dst.chan = bytes[bytes_read++];
+ alu.dst.clamp = bytes[bytes_read++];
+ alu.dst.write = bytes[bytes_read++];
+ alu.dst.rel = bytes[bytes_read++];
+ inst0 = bytes[bytes_read++];
+ inst1 = bytes[bytes_read++];
+ alu.inst = inst0 | (inst1 << 8);
+ alu.last = bytes[bytes_read++];
+ alu.is_op3 = bytes[bytes_read++];
+ alu.predicate = bytes[bytes_read++];
+ alu.bank_swizzle = bytes[bytes_read++];
+ alu.bank_swizzle_force = bytes[bytes_read++];
+ alu.omod = bytes[bytes_read++];
+ alu.index_mode = bytes[bytes_read++];
+ r600_bytecode_add_alu(ctx->bc, &alu);
+
+ /* XXX: Handle other KILL instructions */
+ if (alu.inst == CTX_INST(V_SQ_ALU_WORD1_OP2_SQ_OP2_INST_KILLGT)) {
+ ctx->shader->uses_kill = 1;
+ /* XXX: This should be enforced in the LLVM backend. */
+ ctx->bc->force_add_cf = 1;
+ }
+ return bytes_read;
+}
+
+static void llvm_if(struct r600_shader_ctx *ctx, struct r600_bytecode_alu * alu,
+ unsigned pred_inst)
+{
+ alu->inst = pred_inst;
+ alu->predicate = 1;
+ alu->dst.write = 0;
+ alu->src[1].sel = V_SQ_ALU_SRC_0;
+ alu->src[1].chan = 0;
+ alu->last = 1;
+ r600_bytecode_add_alu_type(ctx->bc, alu,
+ CTX_INST(V_SQ_CF_ALU_WORD1_SQ_CF_INST_ALU_PUSH_BEFORE));
+
+ r600_bytecode_add_cfinst(ctx->bc, CTX_INST(V_SQ_CF_WORD1_SQ_CF_INST_JUMP));
+ fc_pushlevel(ctx, FC_IF);
+ callstack_check_depth(ctx, FC_PUSH_VPM, 0);
+}
+
+static void r600_break_from_byte_stream(struct r600_shader_ctx *ctx,
+ struct r600_bytecode_alu *alu, unsigned compare_opcode)
+{
+ unsigned opcode = TGSI_OPCODE_BRK;
+ if (ctx->bc->chip_class == CAYMAN)
+ ctx->inst_info = &cm_shader_tgsi_instruction[opcode];
+ else if (ctx->bc->chip_class >= EVERGREEN)
+ ctx->inst_info = &eg_shader_tgsi_instruction[opcode];
+ else
+ ctx->inst_info = &r600_shader_tgsi_instruction[opcode];
+ llvm_if(ctx, alu, compare_opcode);
+ tgsi_loop_brk_cont(ctx);
+ tgsi_endif(ctx);
+}
+
+static unsigned r600_fc_from_byte_stream(struct r600_shader_ctx *ctx,
+ unsigned char * bytes, unsigned bytes_read)
+{
+ struct r600_bytecode_alu alu;
+ unsigned inst;
+ memset(&alu, 0, sizeof(alu));
+ bytes_read = r600_src_from_byte_stream(bytes, bytes_read, &alu, 0);
+ inst = bytes[bytes_read++];
+ switch (inst) {
+ case 0:
+ llvm_if(ctx, &alu,
+ CTX_INST(V_SQ_ALU_WORD1_OP2_SQ_OP2_INST_PRED_SETNE));
+ break;
+ case 1:
+ tgsi_else(ctx);
+ break;
+ case 2:
+ tgsi_endif(ctx);
+ break;
+ case 3:
+ tgsi_bgnloop(ctx);
+ break;
+ case 4:
+ tgsi_endloop(ctx);
+ break;
+ case 5:
+ r600_break_from_byte_stream(ctx, &alu,
+ CTX_INST(V_SQ_ALU_WORD1_OP2_SQ_OP2_INST_PRED_SETE));
+ break;
+ case 6:
+ r600_break_from_byte_stream(ctx, &alu,
+ CTX_INST(V_SQ_ALU_WORD1_OP2_SQ_OP2_INST_PRED_SETNE_INT));
+ break;
+ case 7:
+ {
+ unsigned opcode = TGSI_OPCODE_CONT;
+ if (ctx->bc->chip_class == CAYMAN) {
+ ctx->inst_info =
+ &cm_shader_tgsi_instruction[opcode];
+ } else if (ctx->bc->chip_class >= EVERGREEN) {
+ ctx->inst_info =
+ &eg_shader_tgsi_instruction[opcode];
+ } else {
+ ctx->inst_info =
+ &r600_shader_tgsi_instruction[opcode];
+ }
+ tgsi_loop_brk_cont(ctx);
+ }
+ break;
+ case 8:
+ r600_break_from_byte_stream(ctx, &alu,
+ CTX_INST(V_SQ_ALU_WORD1_OP2_SQ_OP2_INST_PRED_SETE_INT));
+ break;
+ }
+
+ return bytes_read;
+}
+
+static unsigned r600_tex_from_byte_stream(struct r600_shader_ctx *ctx,
+ unsigned char * bytes, unsigned bytes_read)
+{
+ struct r600_bytecode_tex tex;
+
+ tex.inst = bytes[bytes_read++];
+ tex.resource_id = bytes[bytes_read++];
+ tex.src_gpr = bytes[bytes_read++];
+ tex.src_rel = bytes[bytes_read++];
+ tex.dst_gpr = bytes[bytes_read++];
+ tex.dst_rel = bytes[bytes_read++];
+ tex.dst_sel_x = bytes[bytes_read++];
+ tex.dst_sel_y = bytes[bytes_read++];
+ tex.dst_sel_z = bytes[bytes_read++];
+ tex.dst_sel_w = bytes[bytes_read++];
+ tex.lod_bias = bytes[bytes_read++];
+ tex.coord_type_x = bytes[bytes_read++];
+ tex.coord_type_y = bytes[bytes_read++];
+ tex.coord_type_z = bytes[bytes_read++];
+ tex.coord_type_w = bytes[bytes_read++];
+ tex.offset_x = bytes[bytes_read++];
+ tex.offset_y = bytes[bytes_read++];
+ tex.offset_z = bytes[bytes_read++];
+ tex.sampler_id = bytes[bytes_read++];
+ tex.src_sel_x = bytes[bytes_read++];
+ tex.src_sel_y = bytes[bytes_read++];
+ tex.src_sel_z = bytes[bytes_read++];
+ tex.src_sel_w = bytes[bytes_read++];
+
+ r600_bytecode_add_tex(ctx->bc, &tex);
+
+ return bytes_read;
+}
+
+static int r600_vtx_from_byte_stream(struct r600_shader_ctx *ctx,
+ unsigned char * bytes, unsigned bytes_read)
+{
+ struct r600_bytecode_vtx vtx;
+ memset(&vtx, 0, sizeof(vtx));
+ vtx.inst = bytes[bytes_read++];
+ vtx.fetch_type = bytes[bytes_read++];
+ vtx.buffer_id = bytes[bytes_read++];
+ vtx.src_gpr = bytes[bytes_read++];
+ vtx.src_sel_x = bytes[bytes_read++];
+ vtx.mega_fetch_count = bytes[bytes_read++];
+ vtx.dst_gpr = bytes[bytes_read++];
+ vtx.dst_sel_x = bytes[bytes_read++];
+ vtx.dst_sel_y = bytes[bytes_read++];
+ vtx.dst_sel_z = bytes[bytes_read++];
+ vtx.dst_sel_w = bytes[bytes_read++];
+ vtx.use_const_fields = bytes[bytes_read++];
+ vtx.data_format = bytes[bytes_read++];
+ vtx.num_format_all = bytes[bytes_read++];
+ vtx.format_comp_all = bytes[bytes_read++];
+ vtx.srf_mode_all = bytes[bytes_read++];
+ vtx.offset = bytes[bytes_read++];
+ vtx.endian = bytes[bytes_read++];
+
+ if (r600_bytecode_add_vtx(ctx->bc, &vtx)) {
+ fprintf(stderr, "Error adding vtx\n");
+ }
+ /* Use the Texture Cache */
+ ctx->bc->cf_last->inst = EG_V_SQ_CF_WORD1_SQ_CF_INST_TEX;
+ return bytes_read;
+}
+
+static void r600_bytecode_from_byte_stream(struct r600_shader_ctx *ctx,
+ unsigned char * bytes, unsigned num_bytes)
+{
+ unsigned bytes_read = 0;
+ unsigned i, byte;
+ while (bytes_read < num_bytes) {
+ char inst_type = bytes[bytes_read++];
+ switch (inst_type) {
+ case 0:
+ bytes_read = r600_alu_from_byte_stream(ctx, bytes,
+ bytes_read);
+ break;
+ case 1:
+ bytes_read = r600_tex_from_byte_stream(ctx, bytes,
+ bytes_read);
+ break;
+ case 2:
+ bytes_read = r600_fc_from_byte_stream(ctx, bytes,
+ bytes_read);
+ break;
+ case 3:
+ r600_bytecode_add_cfinst(ctx->bc, CF_NATIVE);
+ for (i = 0; i < 2; i++) {
+ for (byte = 0 ; byte < 4; byte++) {
+ ctx->bc->cf_last->isa[i] |=
+ (bytes[bytes_read++] << (byte * 8));
+ }
+ }
+ break;
+
+ case 4:
+ bytes_read = r600_vtx_from_byte_stream(ctx, bytes,
+ bytes_read);
+ break;
+ default:
+ /* XXX: Error here */
+ break;
+ }
+ }
+}
+
+/* End bytestream -> r600 shader functions*/