void fn_lcd(char **args) { char *lwd, *exp; int freep; if (args) { lwd = args[0]; freep = 0; } else { if (rc_inrc) { rc_error("lcd: no directory specified"); return; } lwd = read_string("local directory: ", 1); freep = 1; } exp = local_exp(lwd); if (exp) { if (chdir(exp) < 0 && rc_inrc) rc_error("rc: cannot cd to %s: %s", lwd, strerror(errno)); free(exp); } if (freep) free(lwd); if (!rc_inrc) { lwd = getcwd(NULL, 1024); disp_status(DISP_STATUS, "Current local directory: %s", lwd); free(lwd); } }
extern void assign(List *s1, List *s2, bool stack) { List *val = s2; if (s1 == NULL) rc_error("null variable name"); if (s1->n != NULL) rc_error("multi-word variable name"); if (*s1->w == '\0') rc_error("zero-length variable name"); if (a2u(s1->w) != -1) rc_error("numeric variable name"); if (strchr(s1->w, '=') != NULL) rc_error("'=' in variable name"); if (*s1->w == '*' && s1->w[1] == '\0') val = append(varlookup("0"), s2); /* preserve $0 when * is assigned explicitly */ if (s2 != NULL || stack) { if (dashex) prettyprint_var(2, s1->w, val); varassign(s1->w, val, stack); alias(s1->w, varlookup(s1->w), stack); } else { if (dashex) prettyprint_var(2, s1->w, NULL); varrm(s1->w, stack); } }
static void ei_if(struct r300_vertex_program_compiler * compiler, struct rc_instruction *rci, unsigned int * inst, unsigned int branch_depth) { unsigned int predicate_opcode; int is_math = 0; if (!compiler->Base.is_r500) { rc_error(&compiler->Base,"Opcode IF not supported\n"); return; } /* Reserve a temporary to use as our predicate stack counter, if we * don't already have one. */ if (!compiler->PredicateMask) { unsigned int writemasks[RC_REGISTER_MAX_INDEX]; struct rc_instruction * inst; unsigned int i; memset(writemasks, 0, sizeof(writemasks)); for(inst = compiler->Base.Program.Instructions.Next; inst != &compiler->Base.Program.Instructions; inst = inst->Next) { rc_for_all_writes_mask(inst, mark_write, writemasks); } for(i = 0; i < compiler->Base.max_temp_regs; i++) { unsigned int mask = ~writemasks[i] & RC_MASK_XYZW; /* Only the W component can be used fo the predicate * stack counter. */ if (mask & RC_MASK_W) { compiler->PredicateMask = RC_MASK_W; compiler->PredicateIndex = i; break; } } if (i == compiler->Base.max_temp_regs) { rc_error(&compiler->Base, "No free temporary to use for" " predicate stack counter.\n"); return; } } predicate_opcode = branch_depth ? VE_PRED_SET_NEQ_PUSH : ME_PRED_SET_NEQ; rci->U.I.SrcReg[0].Swizzle = RC_MAKE_SWIZZLE_SMEAR(GET_SWZ(rci->U.I.SrcReg[0].Swizzle,0)); if (branch_depth == 0) { is_math = 1; predicate_opcode = ME_PRED_SET_NEQ; inst[1] = t_src(compiler->code, &rci->U.I.SrcReg[0]); inst[2] = 0; } else { predicate_opcode = VE_PRED_SET_NEQ_PUSH; inst[1] = t_pred_src(compiler); inst[2] = t_src(compiler->code, &rci->U.I.SrcReg[0]); } inst[0] = t_pred_dst(compiler, predicate_opcode, is_math); inst[3] = 0; }
void r500BuildFragmentProgramHwCode(struct radeon_compiler *c, void *user) { struct r300_fragment_program_compiler *compiler = (struct r300_fragment_program_compiler*)c; struct emit_state s; struct r500_fragment_program_code *code = &compiler->code->code.r500; memset(&s, 0, sizeof(s)); s.C = &compiler->Base; s.Code = code; memset(code, 0, sizeof(*code)); code->max_temp_idx = 1; code->inst_end = -1; for(struct rc_instruction * inst = compiler->Base.Program.Instructions.Next; inst != &compiler->Base.Program.Instructions && !compiler->Base.Error; inst = inst->Next) { if (inst->Type == RC_INSTRUCTION_NORMAL) { const struct rc_opcode_info * opcode = rc_get_opcode_info(inst->U.I.Opcode); if (opcode->IsFlowControl) { emit_flowcontrol(&s, inst); } else if (inst->U.I.Opcode == RC_OPCODE_BEGIN_TEX) { continue; } else { emit_tex(compiler, &inst->U.I); } } else { emit_paired(compiler, &inst->U.P); } } if (code->max_temp_idx >= compiler->Base.max_temp_regs) rc_error(&compiler->Base, "Too many hardware temporaries used"); if (compiler->Base.Error) return; if (code->inst_end == -1 || (code->inst[code->inst_end].inst0 & R500_INST_TYPE_MASK) != R500_INST_TYPE_OUT) { /* This may happen when dead-code elimination is disabled or * when most of the fragment program logic is leading to a KIL */ if (code->inst_end >= compiler->Base.max_alu_insts-1) { rc_error(&compiler->Base, "Introducing fake OUT: Too many instructions"); return; } int ip = ++code->inst_end; code->inst[ip].inst0 = R500_INST_TYPE_OUT | R500_INST_TEX_SEM_WAIT; } /* Enable full flow control mode if we are using loops or have if * statements nested at least four deep. */ if (s.MaxBranchDepth >= 4 || s.LoopsReserved > 0) { if (code->max_temp_idx < 1) code->max_temp_idx = 1; code->us_fc_ctrl |= R500_FC_FULL_FC_EN; } }
static void translate_vertex_program(struct r300_vertex_program_compiler * compiler) { struct rc_instruction *rci; compiler->code->pos_end = 0; /* Not supported yet */ compiler->code->length = 0; compiler->SetHwInputOutput(compiler); for(rci = compiler->Base.Program.Instructions.Next; rci != &compiler->Base.Program.Instructions; rci = rci->Next) { struct rc_sub_instruction *vpi = &rci->U.I; unsigned int *inst = compiler->code->body.d + compiler->code->length; /* Skip instructions writing to non-existing destination */ if (!valid_dst(compiler->code, &vpi->DstReg)) continue; if (compiler->code->length >= VSF_MAX_FRAGMENT_LENGTH) { rc_error(&compiler->Base, "Vertex program has too many instructions\n"); return; } switch (vpi->Opcode) { case RC_OPCODE_ADD: ei_vector2(compiler->code, VE_ADD, vpi, inst); break; case RC_OPCODE_ARL: ei_vector1(compiler->code, VE_FLT2FIX_DX, vpi, inst); break; case RC_OPCODE_DP4: ei_vector2(compiler->code, VE_DOT_PRODUCT, vpi, inst); break; case RC_OPCODE_DST: ei_vector2(compiler->code, VE_DISTANCE_VECTOR, vpi, inst); break; case RC_OPCODE_EX2: ei_math1(compiler->code, ME_EXP_BASE2_FULL_DX, vpi, inst); break; case RC_OPCODE_EXP: ei_math1(compiler->code, ME_EXP_BASE2_DX, vpi, inst); break; case RC_OPCODE_FRC: ei_vector1(compiler->code, VE_FRACTION, vpi, inst); break; case RC_OPCODE_LG2: ei_math1(compiler->code, ME_LOG_BASE2_FULL_DX, vpi, inst); break; case RC_OPCODE_LIT: ei_lit(compiler->code, vpi, inst); break; case RC_OPCODE_LOG: ei_math1(compiler->code, ME_LOG_BASE2_DX, vpi, inst); break; case RC_OPCODE_MAD: ei_mad(compiler->code, vpi, inst); break; case RC_OPCODE_MAX: ei_vector2(compiler->code, VE_MAXIMUM, vpi, inst); break; case RC_OPCODE_MIN: ei_vector2(compiler->code, VE_MINIMUM, vpi, inst); break; case RC_OPCODE_MOV: ei_vector1(compiler->code, VE_ADD, vpi, inst); break; case RC_OPCODE_MUL: ei_vector2(compiler->code, VE_MULTIPLY, vpi, inst); break; case RC_OPCODE_POW: ei_pow(compiler->code, vpi, inst); break; case RC_OPCODE_RCP: ei_math1(compiler->code, ME_RECIP_DX, vpi, inst); break; case RC_OPCODE_RSQ: ei_math1(compiler->code, ME_RECIP_SQRT_DX, vpi, inst); break; case RC_OPCODE_SGE: ei_vector2(compiler->code, VE_SET_GREATER_THAN_EQUAL, vpi, inst); break; case RC_OPCODE_SLT: ei_vector2(compiler->code, VE_SET_LESS_THAN, vpi, inst); break; default: rc_error(&compiler->Base, "Unknown opcode %i\n", vpi->Opcode); return; } compiler->code->length += 4; if (compiler->Base.Error) return; } }
static void dopipe(Node *n) { int i, j, sp, pid, fd_prev, fd_out, pids[512], stats[512], p[2]; bool intr; Node *r; fd_prev = fd_out = 1; for (r = n, i = 0; r != NULL && r->type == nPipe; r = r->u[2].p, i++) { if (i > 500) /* the only hard-wired limit in rc? */ rc_error("pipe too long"); if (pipe(p) < 0) { uerror("pipe"); rc_error(NULL); } if ((pid = rc_fork()) == 0) { setsigdefaults(FALSE); redirq = NULL; /* clear preredir queue */ mvfd(p[0], r->u[1].i); if (fd_prev != 1) mvfd(fd_prev, fd_out); close(p[1]); walk(r->u[3].p, FALSE); exit(getstatus()); } if (fd_prev != 1) close(fd_prev); /* parent must close all pipe fd's */ pids[i] = pid; fd_prev = p[1]; fd_out = r->u[0].i; close(p[0]); } if ((pid = rc_fork()) == 0) { setsigdefaults(FALSE); mvfd(fd_prev, fd_out); walk(r, FALSE); exit(getstatus()); /* NOTREACHED */ } redirq = NULL; /* clear preredir queue */ close(fd_prev); pids[i++] = pid; /* collect statuses */ intr = FALSE; for (j = 0; j < i; j++) { rc_wait4(pids[j], &sp, TRUE); stats[j] = sp; intr |= (sp == SIGINT); } setpipestatus(stats, i); sigchk(); }
/** * This function prepares a loop to be unrolled by converting it into an if * statement. Here is an outline of the conversion process: * BGNLOOP; -> BGNLOOP; * <Additional conditional code> -> <Additional conditional code> * SGE/SLT temp[0], temp[1], temp[2]; -> SLT/SGE temp[0], temp[1], temp[2]; * IF temp[0]; -> IF temp[0]; * BRK; -> * ENDIF; -> <Loop Body> * <Loop Body> -> ENDIF; * ENDLOOP; -> ENDLOOP * * @param inst A pointer to a BGNLOOP instruction. * @return 1 for success, 0 for failure */ static int transform_loop(struct emulate_loop_state * s, struct rc_instruction * inst) { struct loop_info * loop; memory_pool_array_reserve(&s->C->Pool, struct loop_info, s->Loops, s->LoopCount, s->LoopReserved, 1); loop = &s->Loops[s->LoopCount++]; if (!build_loop_info(s->C, loop, inst)) { rc_error(s->C, "Failed to build loop info\n"); return 0; } if(try_unroll_loop(s->C, loop)){ return 1; } /* Reverse the conditional instruction */ switch(loop->Cond->U.I.Opcode){ case RC_OPCODE_SGE: loop->Cond->U.I.Opcode = RC_OPCODE_SLT; break; case RC_OPCODE_SLT: loop->Cond->U.I.Opcode = RC_OPCODE_SGE; break; case RC_OPCODE_SLE: loop->Cond->U.I.Opcode = RC_OPCODE_SGT; break; case RC_OPCODE_SGT: loop->Cond->U.I.Opcode = RC_OPCODE_SLE; break; case RC_OPCODE_SEQ: loop->Cond->U.I.Opcode = RC_OPCODE_SNE; break; case RC_OPCODE_SNE: loop->Cond->U.I.Opcode = RC_OPCODE_SEQ; break; default: rc_error(s->C, "loop->Cond is not a conditional.\n"); return 0; } /* Prepare the loop to be emulated */ rc_remove_instruction(loop->Brk); rc_remove_instruction(loop->EndIf); rc_insert_instruction(loop->EndLoop->Prev, loop->EndIf); return 1; }
static void scan_write(void * data, struct rc_instruction * inst, rc_register_file file, unsigned int index, unsigned int chan) { struct schedule_state * s = data; struct reg_value ** pv = get_reg_valuep(s, file, index, chan); if (!pv) return; DBG("%i: write %i[%i] chan %i\n", s->Current->Instruction->IP, file, index, chan); struct reg_value * newv = memory_pool_malloc(&s->C->Pool, sizeof(*newv)); memset(newv, 0, sizeof(*newv)); newv->Writer = s->Current; if (*pv) { (*pv)->Next = newv; s->Current->NumDependencies++; } *pv = newv; if (s->Current->NumWriteValues >= 4) { rc_error(s->C, "%s: NumWriteValues overflow\n", __FUNCTION__); } else { s->Current->WriteValues[s->Current->NumWriteValues++] = newv; } }
static void do_regalloc(struct regalloc_state * s) { /* Simple and stupid greedy register allocation */ for(unsigned int index = 0; index < RC_REGISTER_MAX_INDEX; ++index) { struct register_info * reg = &s->Temporary[index]; if (!reg->Used) continue; for(unsigned int hwreg = 0; hwreg < s->NumHwTemporaries; ++hwreg) { if (try_add_live_intervals(s, &s->HwTemporary[hwreg].Used, ®->Live)) { reg->Allocated = 1; reg->File = RC_FILE_TEMPORARY; reg->Index = hwreg; goto success; } } rc_error(s->C, "Ran out of hardware temporaries\n"); return; success:; } /* Rewrite all instructions based on the translation table we built */ for(struct rc_instruction * inst = s->C->Program.Instructions.Next; inst != &s->C->Program.Instructions; inst = inst->Next) { if (inst->Type == RC_INSTRUCTION_NORMAL) rewrite_normal_instruction(s, &inst->U.I); else rewrite_pair_instruction(s, &inst->U.P); } }
static List *backq(Node *ifs, Node *n) { int p[2], sp; pid_t pid; List *bq; struct termios t; if (n == NULL) return NULL; if (pipe(p) < 0) { uerror("pipe"); rc_error(NULL); } if (interactive) tcgetattr(0, &t); if ((pid = rc_fork()) == 0) { mvfd(p[1], 1); close(p[0]); redirq = NULL; walk(n, FALSE); exit(getstatus()); } close(p[1]); bq = bqinput(glom(ifs), p[0]); close(p[0]); rc_wait4(pid, &sp, TRUE); if (interactive && WIFSIGNALED(sp)) tcsetattr(0, TCSANOW, &t); statprint(-1, sp); varassign("bqstatus", word(strstatus(sp), NULL), FALSE); sigchk(); return bq; }
void rc_validate_final_shader(struct radeon_compiler *c, void *user) { /* Check the number of constants. */ if (c->Program.Constants.Count > c->max_constants) { rc_error(c, "Too many constants. Max: 256, Got: %i\n", c->Program.Constants.Count); } }
static void ei_endif(struct r300_vertex_program_compiler *compiler, unsigned int * inst) { if (!compiler->Base.is_r500) { rc_error(&compiler->Base,"Opcode ENDIF not supported\n"); return; } inst[0] = t_pred_dst(compiler, ME_PRED_SET_POP, 1); inst[1] = t_pred_src(compiler); inst[2] = 0; inst[3] = 0; }
static uint32_t translate_alu_result_op(struct r300_fragment_program_compiler * c, rc_compare_func func) { switch(func) { case RC_COMPARE_FUNC_EQUAL: return R500_INST_ALU_RESULT_OP_EQ; case RC_COMPARE_FUNC_LESS: return R500_INST_ALU_RESULT_OP_LT; case RC_COMPARE_FUNC_GEQUAL: return R500_INST_ALU_RESULT_OP_GE; case RC_COMPARE_FUNC_NOTEQUAL: return R500_INST_ALU_RESULT_OP_NE; default: rc_error(&c->Base, "%s: unsupported compare func %i\n", __FUNCTION__, func); return 0; } }
extern void rc_raise(ecodes e) { if (e == eError && rc_pid != getpid()) exit(1); /* child processes exit on an error/signal */ for (; estack != NULL; estack = estack->prev) if (estack->e != e) { if (e == eBreak && estack->e != eArena && estack->e != eVarstack) rc_error("break outside of loop"); else if (e == eReturn && estack->e == eError) /* can return from loops inside functions */ rc_error("return outside of function"); switch (estack->e) { default: break; case eVarstack: varrm(estack->data.name, TRUE); break; case eArena: restoreblock(estack->data.b); break; case eFifo: unlink(estack->data.name); break; case eFd: close(estack->data.fd); break; } } else { if (e == eError && !estack->interactive) { popinput(); } else { Jbwrap *j = estack->data.jb; interactive = estack->interactive; estack = estack->prev; siglongjmp(j->j, 1); } } rc_exit(1); /* top of exception stack */ }
static float get_constant_value(struct radeon_compiler * c, struct rc_src_register * src, int chan) { float base = 1.0f; int swz = GET_SWZ(src->Swizzle, chan); if(swz >= 4 || src->Index >= c->Program.Constants.Count ){ rc_error(c, "get_constant_value: Can't find a value.\n"); return 0.0f; } if(GET_BIT(src->Negate, chan)){ base = -1.0f; } return base * c->Program.Constants.Constants[src->Index].u.Immediate[swz]; }
/** * This function renames registers in an attempt to get the code close to * SSA form. After this function has completed, most of the register are only * written to one time, with a few exceptions. * * This function assumes all the instructions are still of type * RC_INSTRUCTION_NORMAL. */ void rc_rename_regs(struct radeon_compiler *c, void *user) { unsigned int i, used_length; int new_index; struct rc_instruction * inst; struct rc_reader_data reader_data; unsigned char * used; /* XXX Remove this once the register allocation works with flow control. */ for(inst = c->Program.Instructions.Next; inst != &c->Program.Instructions; inst = inst->Next) { if (inst->U.I.Opcode == RC_OPCODE_BGNLOOP) return; } used_length = 2 * rc_recompute_ips(c); used = memory_pool_malloc(&c->Pool, sizeof(unsigned char) * used_length); memset(used, 0, sizeof(unsigned char) * used_length); rc_get_used_temporaries(c, used, used_length); for(inst = c->Program.Instructions.Next; inst != &c->Program.Instructions; inst = inst->Next) { if (inst->U.I.DstReg.File != RC_FILE_TEMPORARY) continue; reader_data.ExitOnAbort = 1; rc_get_readers(c, inst, &reader_data, NULL, NULL, NULL); if (reader_data.Abort || reader_data.ReaderCount == 0) continue; new_index = rc_find_free_temporary_list(c, used, used_length, RC_MASK_XYZW); if (new_index < 0) { rc_error(c, "Ran out of temporary registers\n"); return; } reader_data.Writer->U.I.DstReg.Index = new_index; for(i = 0; i < reader_data.ReaderCount; i++) { reader_data.Readers[i].U.I.Src->Index = new_index; } } }
unsigned int rc_find_free_temporary(struct radeon_compiler * c) { unsigned char used[RC_REGISTER_MAX_INDEX]; int free; memset(used, 0, sizeof(used)); rc_get_used_temporaries(c, used, RC_REGISTER_MAX_INDEX); free = rc_find_free_temporary_list(c, used, RC_REGISTER_MAX_INDEX, RC_MASK_XYZW); if (free < 0) { rc_error(c, "Ran out of temporary registers\n"); return 0; } return free; }
static void scan_read(void * data, struct rc_instruction * inst, rc_register_file file, unsigned int index, unsigned int chan) { struct schedule_state * s = data; struct reg_value ** v = get_reg_valuep(s, file, index, chan); struct reg_value_reader * reader; if (!v) return; if (*v && (*v)->Writer == s->Current) { /* The instruction reads and writes to a register component. * In this case, we only want to increment dependencies by one. */ return; } DBG("%i: read %i[%i] chan %i\n", s->Current->Instruction->IP, file, index, chan); reader = memory_pool_malloc(&s->C->Pool, sizeof(*reader)); reader->Reader = s->Current; if (!*v) { /* In this situation, the instruction reads from a register * that hasn't been written to or read from in the current * block. */ *v = memory_pool_malloc(&s->C->Pool, sizeof(struct reg_value)); memset(*v, 0, sizeof(struct reg_value)); (*v)->Readers = reader; } else { reader->Next = (*v)->Readers; (*v)->Readers = reader; /* Only update the current instruction's dependencies if the * register it reads from has been written to in this block. */ if ((*v)->Writer) { s->Current->NumDependencies++; } } (*v)->NumReaders++; if (s->Current->NumReadValues >= 12) { rc_error(s->C, "%s: NumReadValues overflow\n", __FUNCTION__); } else { s->Current->ReadValues[s->Current->NumReadValues++] = *v; } }
extern List *concat(List *s1, List *s2) { int n1, n2; List *r, *top; if (s1 == NULL) return s2; if (s2 == NULL) return s1; if ((n1 = listnel(s1)) != (n2 = listnel(s2)) && n1 != 1 && n2 != 1) rc_error("bad concatenation"); for (r = top = nnew(List); 1; r = r->n = nnew(List)) { size_t x = strlen(s1->w); size_t y = strlen(s2->w); size_t z = x + y + 1; r->w = nalloc(z); strcpy(r->w, s1->w); strcat(r->w, s2->w); if (s1->m == NULL && s2->m == NULL) { r->m = NULL; } else { r->m = nalloc(z); if (s1->m == NULL) memzero(r->m, x); else memcpy(r->m, s1->m, x); if (s2->m == NULL) memzero(&r->m[x], y); else memcpy(&r->m[x], s2->m, y); r->m[z] = 0; } if (n1 > 1) s1 = s1->n; if (n2 > 1) s2 = s2->n; if (s1 == NULL || s2 == NULL || (n1 == 1 && n2 == 1)) break; } r->n = NULL; return top; }
extern List *varsub(List *var, List *subs) { List *r, *top; int n = listnel(var); for (top = r = NULL; subs != NULL; subs = subs->n) { int i = a2u(subs->w); if (i < 1) rc_error("bad subscript"); if (i <= n) { List *sub = var; while (--i) sub = sub->n; /* loop until sub == var(i) */ if (top == NULL) top = r = nnew(List); else r = r->n = nnew(List); r->w = sub->w; r->m = sub->m; } } if (top != NULL) r->n = NULL; return top; }
static void rc_emulate_negative_addressing(struct radeon_compiler *compiler, void *user) { struct r300_vertex_program_compiler * c = (struct r300_vertex_program_compiler*)compiler; struct rc_instruction *inst, *lastARL = NULL; int min_offset = 0; for (inst = c->Base.Program.Instructions.Next; inst != &c->Base.Program.Instructions; inst = inst->Next) { const struct rc_opcode_info * opcode = rc_get_opcode_info(inst->U.I.Opcode); if (inst->U.I.Opcode == RC_OPCODE_ARL) { if (lastARL != NULL && min_offset < 0) transform_negative_addressing(c, lastARL, inst, min_offset); lastARL = inst; min_offset = 0; continue; } for (unsigned i = 0; i < opcode->NumSrcRegs; i++) { if (inst->U.I.SrcReg[i].RelAddr && inst->U.I.SrcReg[i].Index < 0) { /* ARL must precede any indirect addressing. */ if (lastARL == NULL) { rc_error(&c->Base, "Vertex shader: Found relative addressing without ARL."); return; } if (inst->U.I.SrcReg[i].Index < min_offset) min_offset = inst->U.I.SrcReg[i].Index; } } } if (lastARL != NULL && min_offset < 0) transform_negative_addressing(c, lastARL, inst, min_offset); }
static void translate_vertex_program(struct radeon_compiler *c, void *user) { struct r300_vertex_program_compiler *compiler = (struct r300_vertex_program_compiler*)c; struct rc_instruction *rci; unsigned loops[R500_PVS_MAX_LOOP_DEPTH]; unsigned loop_depth = 0; compiler->code->pos_end = 0; /* Not supported yet */ compiler->code->length = 0; compiler->code->num_temporaries = 0; compiler->SetHwInputOutput(compiler); for(rci = compiler->Base.Program.Instructions.Next; rci != &compiler->Base.Program.Instructions; rci = rci->Next) { struct rc_sub_instruction *vpi = &rci->U.I; unsigned int *inst = compiler->code->body.d + compiler->code->length; const struct rc_opcode_info *info = rc_get_opcode_info(vpi->Opcode); /* Skip instructions writing to non-existing destination */ if (!valid_dst(compiler->code, &vpi->DstReg)) continue; if (info->HasDstReg) { /* Neither is Saturate. */ if (vpi->SaturateMode != RC_SATURATE_NONE && !c->is_r500) { rc_error(&compiler->Base, "Vertex program does not support the Saturate " "modifier (yet).\n"); } } if (compiler->code->length >= c->max_alu_insts * 4) { rc_error(&compiler->Base, "Vertex program has too many instructions\n"); return; } assert(compiler->Base.is_r500 || (vpi->Opcode != RC_OPCODE_SEQ && vpi->Opcode != RC_OPCODE_SNE)); switch (vpi->Opcode) { case RC_OPCODE_ADD: ei_vector2(compiler->code, VE_ADD, vpi, inst); break; case RC_OPCODE_ARL: ei_vector1(compiler->code, VE_FLT2FIX_DX, vpi, inst); break; case RC_OPCODE_COS: ei_math1(compiler->code, ME_COS, vpi, inst); break; case RC_OPCODE_DP4: ei_vector2(compiler->code, VE_DOT_PRODUCT, vpi, inst); break; case RC_OPCODE_DST: ei_vector2(compiler->code, VE_DISTANCE_VECTOR, vpi, inst); break; case RC_OPCODE_EX2: ei_math1(compiler->code, ME_EXP_BASE2_FULL_DX, vpi, inst); break; case RC_OPCODE_EXP: ei_math1(compiler->code, ME_EXP_BASE2_DX, vpi, inst); break; case RC_OPCODE_FRC: ei_vector1(compiler->code, VE_FRACTION, vpi, inst); break; case RC_OPCODE_LG2: ei_math1(compiler->code, ME_LOG_BASE2_FULL_DX, vpi, inst); break; case RC_OPCODE_LIT: ei_lit(compiler->code, vpi, inst); break; case RC_OPCODE_LOG: ei_math1(compiler->code, ME_LOG_BASE2_DX, vpi, inst); break; case RC_OPCODE_MAD: ei_mad(compiler->code, vpi, inst); break; case RC_OPCODE_MAX: ei_vector2(compiler->code, VE_MAXIMUM, vpi, inst); break; case RC_OPCODE_MIN: ei_vector2(compiler->code, VE_MINIMUM, vpi, inst); break; case RC_OPCODE_MOV: ei_vector1(compiler->code, VE_ADD, vpi, inst); break; case RC_OPCODE_MUL: ei_vector2(compiler->code, VE_MULTIPLY, vpi, inst); break; case RC_OPCODE_POW: ei_pow(compiler->code, vpi, inst); break; case RC_OPCODE_RCP: ei_math1(compiler->code, ME_RECIP_DX, vpi, inst); break; case RC_OPCODE_RSQ: ei_math1(compiler->code, ME_RECIP_SQRT_DX, vpi, inst); break; case RC_OPCODE_SEQ: ei_vector2(compiler->code, VE_SET_EQUAL, vpi, inst); break; case RC_OPCODE_SGE: ei_vector2(compiler->code, VE_SET_GREATER_THAN_EQUAL, vpi, inst); break; case RC_OPCODE_SIN: ei_math1(compiler->code, ME_SIN, vpi, inst); break; case RC_OPCODE_SLT: ei_vector2(compiler->code, VE_SET_LESS_THAN, vpi, inst); break; case RC_OPCODE_SNE: ei_vector2(compiler->code, VE_SET_NOT_EQUAL, vpi, inst); break; case RC_OPCODE_BGNLOOP: { if ((!compiler->Base.is_r500 && loop_depth >= R300_VS_MAX_LOOP_DEPTH) || loop_depth >= R500_PVS_MAX_LOOP_DEPTH) { rc_error(&compiler->Base, "Loops are nested too deep."); return; } loops[loop_depth++] = ((compiler->code->length)/ 4) + 1; break; } case RC_OPCODE_ENDLOOP: { unsigned int act_addr; unsigned int last_addr; unsigned int ret_addr; ret_addr = loops[--loop_depth]; act_addr = ret_addr - 1; last_addr = (compiler->code->length / 4) - 1; if (loop_depth >= R300_VS_MAX_FC_OPS) { rc_error(&compiler->Base, "Too many flow control instructions."); return; } if (compiler->Base.is_r500) { compiler->code->fc_op_addrs.r500 [compiler->code->num_fc_ops].lw = R500_PVS_FC_ACT_ADRS(act_addr) | R500_PVS_FC_LOOP_CNT_JMP_INST(0x00ff) ; compiler->code->fc_op_addrs.r500 [compiler->code->num_fc_ops].uw = R500_PVS_FC_LAST_INST(last_addr) | R500_PVS_FC_RTN_INST(ret_addr) ; } else { compiler->code->fc_op_addrs.r300 [compiler->code->num_fc_ops] = R300_PVS_FC_ACT_ADRS(act_addr) | R300_PVS_FC_LOOP_CNT_JMP_INST(0xff) | R300_PVS_FC_LAST_INST(last_addr) | R300_PVS_FC_RTN_INST(ret_addr) ; } compiler->code->fc_loop_index[compiler->code->num_fc_ops] = R300_PVS_FC_LOOP_INIT_VAL(0x0) | R300_PVS_FC_LOOP_STEP_VAL(0x1) ; compiler->code->fc_ops |= R300_VAP_PVS_FC_OPC_LOOP( compiler->code->num_fc_ops); compiler->code->num_fc_ops++; break; } case RC_ME_PRED_SET_CLR: ei_math1(compiler->code, ME_PRED_SET_CLR, vpi, inst); break; case RC_ME_PRED_SET_INV: ei_math1(compiler->code, ME_PRED_SET_INV, vpi, inst); break; case RC_ME_PRED_SET_POP: ei_math1(compiler->code, ME_PRED_SET_POP, vpi, inst); break; case RC_ME_PRED_SET_RESTORE: ei_math1(compiler->code, ME_PRED_SET_RESTORE, vpi, inst); break; case RC_ME_PRED_SEQ: ei_math1(compiler->code, ME_PRED_SET_EQ, vpi, inst); break; case RC_ME_PRED_SNEQ: ei_math1(compiler->code, ME_PRED_SET_NEQ, vpi, inst); break; case RC_VE_PRED_SNEQ_PUSH: ei_vector2(compiler->code, VE_PRED_SET_NEQ_PUSH, vpi, inst); break; default: rc_error(&compiler->Base, "Unknown opcode %s\n", info->Name); return; } if (vpi->DstReg.Pred != RC_PRED_DISABLED) { inst[0] |= (PVS_DST_PRED_ENABLE_MASK << PVS_DST_PRED_ENABLE_SHIFT); if (vpi->DstReg.Pred == RC_PRED_SET) { inst[0] |= (PVS_DST_PRED_SENSE_MASK << PVS_DST_PRED_SENSE_SHIFT); } } /* Update the number of temporaries. */ if (info->HasDstReg && vpi->DstReg.File == RC_FILE_TEMPORARY && vpi->DstReg.Index >= compiler->code->num_temporaries) compiler->code->num_temporaries = vpi->DstReg.Index + 1; for (unsigned i = 0; i < info->NumSrcRegs; i++) if (vpi->SrcReg[i].File == RC_FILE_TEMPORARY && vpi->SrcReg[i].Index >= compiler->code->num_temporaries) compiler->code->num_temporaries = vpi->SrcReg[i].Index + 1; if (compiler->code->num_temporaries > compiler->Base.max_temp_regs) { rc_error(&compiler->Base, "Too many temporaries.\n"); return; } compiler->code->length += 4; if (compiler->Base.Error) return; } }
static void emit_flowcontrol(struct emit_state * s, struct rc_instruction * inst) { unsigned int newip; if (s->Code->inst_end >= s->C->max_alu_insts-1) { rc_error(s->C, "emit_tex: Too many instructions"); return; } newip = ++s->Code->inst_end; /* Currently all loops use the same integer constant to intialize * the loop variables. */ if(!s->Code->int_constants[0]) { s->Code->int_constants[0] = R500_FC_INT_CONST_KR(0xff); s->Code->int_constant_count = 1; } s->Code->inst[newip].inst0 = R500_INST_TYPE_FC | R500_INST_ALU_WAIT; switch(inst->U.I.Opcode){ struct branch_info * branch; struct r500_loop_info * loop; case RC_OPCODE_BGNLOOP: memory_pool_array_reserve(&s->C->Pool, struct r500_loop_info, s->Loops, s->CurrentLoopDepth, s->LoopsReserved, 1); loop = &s->Loops[s->CurrentLoopDepth++]; memset(loop, 0, sizeof(struct r500_loop_info)); loop->BranchDepth = s->CurrentBranchDepth; loop->BgnLoop = newip; s->Code->inst[newip].inst2 = R500_FC_OP_LOOP | R500_FC_JUMP_FUNC(0x00) | R500_FC_IGNORE_UNCOVERED ; break; case RC_OPCODE_BRK: loop = &s->Loops[s->CurrentLoopDepth - 1]; memory_pool_array_reserve(&s->C->Pool, int, loop->Brks, loop->BrkCount, loop->BrkReserved, 1); loop->Brks[loop->BrkCount++] = newip; s->Code->inst[newip].inst2 = R500_FC_OP_BREAKLOOP | R500_FC_JUMP_FUNC(0xff) | R500_FC_B_OP1_DECR | R500_FC_B_POP_CNT( s->CurrentBranchDepth - loop->BranchDepth) | R500_FC_IGNORE_UNCOVERED ; break; case RC_OPCODE_CONT: loop = &s->Loops[s->CurrentLoopDepth - 1]; memory_pool_array_reserve(&s->C->Pool, int, loop->Conts, loop->ContCount, loop->ContReserved, 1); loop->Conts[loop->ContCount++] = newip; s->Code->inst[newip].inst2 = R500_FC_OP_CONTINUE | R500_FC_JUMP_FUNC(0xff) | R500_FC_B_OP1_DECR | R500_FC_B_POP_CNT( s->CurrentBranchDepth - loop->BranchDepth) | R500_FC_IGNORE_UNCOVERED ; break; case RC_OPCODE_ENDLOOP: { loop = &s->Loops[s->CurrentLoopDepth - 1]; /* Emit ENDLOOP */ s->Code->inst[newip].inst2 = R500_FC_OP_ENDLOOP | R500_FC_JUMP_FUNC(0xff) | R500_FC_JUMP_ANY | R500_FC_IGNORE_UNCOVERED ; /* The constant integer at index 0 is used by all loops. */ s->Code->inst[newip].inst3 = R500_FC_INT_ADDR(0) | R500_FC_JUMP_ADDR(loop->BgnLoop + 1) ; /* Set jump address and int constant for BGNLOOP */ s->Code->inst[loop->BgnLoop].inst3 = R500_FC_INT_ADDR(0) | R500_FC_JUMP_ADDR(newip) ; /* Set jump address for the BRK instructions. */ while(loop->BrkCount--) { s->Code->inst[loop->Brks[loop->BrkCount]].inst3 = R500_FC_JUMP_ADDR(newip + 1); } /* Set jump address for CONT instructions. */ while(loop->ContCount--) { s->Code->inst[loop->Conts[loop->ContCount]].inst3 = R500_FC_JUMP_ADDR(newip); } s->CurrentLoopDepth--; break; } case RC_OPCODE_IF: if ( s->CurrentBranchDepth >= R500_PFS_MAX_BRANCH_DEPTH_FULL) { rc_error(s->C, "Branch depth exceeds hardware limit"); return; } memory_pool_array_reserve(&s->C->Pool, struct branch_info, s->Branches, s->CurrentBranchDepth, s->BranchesReserved, 1); branch = &s->Branches[s->CurrentBranchDepth++]; branch->If = newip; branch->Else = -1; branch->Endif = -1; if (s->CurrentBranchDepth > s->MaxBranchDepth) s->MaxBranchDepth = s->CurrentBranchDepth; /* actual instruction is filled in at ENDIF time */ break; case RC_OPCODE_ELSE: if (!s->CurrentBranchDepth) { rc_error(s->C, "%s: got ELSE outside a branch", __FUNCTION__); return; } branch = &s->Branches[s->CurrentBranchDepth - 1]; branch->Else = newip; /* actual instruction is filled in at ENDIF time */ break; case RC_OPCODE_ENDIF: if (!s->CurrentBranchDepth) { rc_error(s->C, "%s: got ELSE outside a branch", __FUNCTION__); return; } branch = &s->Branches[s->CurrentBranchDepth - 1]; branch->Endif = newip; s->Code->inst[branch->Endif].inst2 = R500_FC_OP_JUMP | R500_FC_A_OP_NONE /* no address stack */ | R500_FC_JUMP_ANY /* docs says set this, but I don't understand why */ | R500_FC_B_OP0_DECR /* decrement branch counter if stay */ | R500_FC_B_OP1_NONE /* no branch counter if stay */ | R500_FC_B_POP_CNT(1) ; s->Code->inst[branch->Endif].inst3 = R500_FC_JUMP_ADDR(branch->Endif + 1); s->Code->inst[branch->If].inst2 = R500_FC_OP_JUMP | R500_FC_A_OP_NONE /* no address stack */ | R500_FC_JUMP_FUNC(0x0f) /* jump if ALU result is false */ | R500_FC_B_OP0_INCR /* increment branch counter if stay */ | R500_FC_IGNORE_UNCOVERED ; if (branch->Else >= 0) { /* increment branch counter also if jump */ s->Code->inst[branch->If].inst2 |= R500_FC_B_OP1_INCR; s->Code->inst[branch->If].inst3 = R500_FC_JUMP_ADDR(branch->Else + 1); s->Code->inst[branch->Else].inst2 = R500_FC_OP_JUMP | R500_FC_A_OP_NONE /* no address stack */ | R500_FC_B_ELSE /* all active pixels want to jump */ | R500_FC_B_OP0_NONE /* no counter op if stay */ | R500_FC_B_OP1_DECR /* decrement branch counter if jump */ | R500_FC_B_POP_CNT(1) ; s->Code->inst[branch->Else].inst3 = R500_FC_JUMP_ADDR(branch->Endif + 1); } else { /* don't touch branch counter on jump */ s->Code->inst[branch->If].inst2 |= R500_FC_B_OP1_NONE; s->Code->inst[branch->If].inst3 = R500_FC_JUMP_ADDR(branch->Endif + 1); } s->CurrentBranchDepth--; break; default: rc_error(s->C, "%s: unknown opcode %s\n", __FUNCTION__, rc_get_opcode_info(inst->U.I.Opcode)->Name); } }
int rc_if_fail_helper(struct radeon_compiler * c, const char * file, int line, const char * assertion) { rc_error(c, "ICE at %s:%i: assertion failed: %s\n", file, line, assertion); return 1; }
static void translate_vertex_program(struct radeon_compiler *c, void *user) { struct r300_vertex_program_compiler *compiler = (struct r300_vertex_program_compiler*)c; struct rc_instruction *rci; struct loop * loops = NULL; int current_loop_depth = 0; int loops_reserved = 0; unsigned int branch_depth = 0; compiler->code->pos_end = 0; /* Not supported yet */ compiler->code->length = 0; compiler->code->num_temporaries = 0; compiler->SetHwInputOutput(compiler); for(rci = compiler->Base.Program.Instructions.Next; rci != &compiler->Base.Program.Instructions; rci = rci->Next) { struct rc_sub_instruction *vpi = &rci->U.I; unsigned int *inst = compiler->code->body.d + compiler->code->length; const struct rc_opcode_info *info = rc_get_opcode_info(vpi->Opcode); /* Skip instructions writing to non-existing destination */ if (!valid_dst(compiler->code, &vpi->DstReg)) continue; if (info->HasDstReg) { /* Neither is Saturate. */ if (vpi->SaturateMode != RC_SATURATE_NONE) { rc_error(&compiler->Base, "Vertex program does not support the Saturate " "modifier (yet).\n"); } } if (compiler->code->length >= c->max_alu_insts * 4) { rc_error(&compiler->Base, "Vertex program has too many instructions\n"); return; } assert(compiler->Base.is_r500 || (vpi->Opcode != RC_OPCODE_SEQ && vpi->Opcode != RC_OPCODE_SNE)); switch (vpi->Opcode) { case RC_OPCODE_ADD: ei_vector2(compiler->code, VE_ADD, vpi, inst); break; case RC_OPCODE_ARL: ei_vector1(compiler->code, VE_FLT2FIX_DX, vpi, inst); break; case RC_OPCODE_COS: ei_math1(compiler->code, ME_COS, vpi, inst); break; case RC_OPCODE_DP4: ei_vector2(compiler->code, VE_DOT_PRODUCT, vpi, inst); break; case RC_OPCODE_DST: ei_vector2(compiler->code, VE_DISTANCE_VECTOR, vpi, inst); break; case RC_OPCODE_ELSE: ei_else(compiler, inst); break; case RC_OPCODE_ENDIF: ei_endif(compiler, inst); branch_depth--; break; case RC_OPCODE_EX2: ei_math1(compiler->code, ME_EXP_BASE2_FULL_DX, vpi, inst); break; case RC_OPCODE_EXP: ei_math1(compiler->code, ME_EXP_BASE2_DX, vpi, inst); break; case RC_OPCODE_FRC: ei_vector1(compiler->code, VE_FRACTION, vpi, inst); break; case RC_OPCODE_IF: ei_if(compiler, rci, inst, branch_depth); branch_depth++; break; case RC_OPCODE_LG2: ei_math1(compiler->code, ME_LOG_BASE2_FULL_DX, vpi, inst); break; case RC_OPCODE_LIT: ei_lit(compiler->code, vpi, inst); break; case RC_OPCODE_LOG: ei_math1(compiler->code, ME_LOG_BASE2_DX, vpi, inst); break; case RC_OPCODE_MAD: ei_mad(compiler->code, vpi, inst); break; case RC_OPCODE_MAX: ei_vector2(compiler->code, VE_MAXIMUM, vpi, inst); break; case RC_OPCODE_MIN: ei_vector2(compiler->code, VE_MINIMUM, vpi, inst); break; case RC_OPCODE_MOV: ei_vector1(compiler->code, VE_ADD, vpi, inst); break; case RC_OPCODE_MUL: ei_vector2(compiler->code, VE_MULTIPLY, vpi, inst); break; case RC_OPCODE_POW: ei_pow(compiler->code, vpi, inst); break; case RC_OPCODE_RCP: ei_math1(compiler->code, ME_RECIP_DX, vpi, inst); break; case RC_OPCODE_RSQ: ei_math1(compiler->code, ME_RECIP_SQRT_DX, vpi, inst); break; case RC_OPCODE_SEQ: ei_vector2(compiler->code, VE_SET_EQUAL, vpi, inst); break; case RC_OPCODE_SGE: ei_vector2(compiler->code, VE_SET_GREATER_THAN_EQUAL, vpi, inst); break; case RC_OPCODE_SIN: ei_math1(compiler->code, ME_SIN, vpi, inst); break; case RC_OPCODE_SLT: ei_vector2(compiler->code, VE_SET_LESS_THAN, vpi, inst); break; case RC_OPCODE_SNE: ei_vector2(compiler->code, VE_SET_NOT_EQUAL, vpi, inst); break; case RC_OPCODE_BGNLOOP: { struct loop * l; if ((!compiler->Base.is_r500 && loops_reserved >= R300_VS_MAX_LOOP_DEPTH) || loops_reserved >= R500_VS_MAX_FC_DEPTH) { rc_error(&compiler->Base, "Loops are nested too deep."); return; } memory_pool_array_reserve(&compiler->Base.Pool, struct loop, loops, current_loop_depth, loops_reserved, 1); l = &loops[current_loop_depth++]; memset(l , 0, sizeof(struct loop)); l->BgnLoop = (compiler->code->length / 4); continue; } case RC_OPCODE_ENDLOOP: { struct loop * l; unsigned int act_addr; unsigned int last_addr; unsigned int ret_addr; assert(loops); l = &loops[current_loop_depth - 1]; act_addr = l->BgnLoop - 1; last_addr = (compiler->code->length / 4) - 1; ret_addr = l->BgnLoop; if (loops_reserved >= R300_VS_MAX_FC_OPS) { rc_error(&compiler->Base, "Too many flow control instructions."); return; } if (compiler->Base.is_r500) { compiler->code->fc_op_addrs.r500 [compiler->code->num_fc_ops].lw = R500_PVS_FC_ACT_ADRS(act_addr) | R500_PVS_FC_LOOP_CNT_JMP_INST(0xffff) ; compiler->code->fc_op_addrs.r500 [compiler->code->num_fc_ops].uw = R500_PVS_FC_LAST_INST(last_addr) | R500_PVS_FC_RTN_INST(ret_addr) ; } else { compiler->code->fc_op_addrs.r300 [compiler->code->num_fc_ops] = R300_PVS_FC_ACT_ADRS(act_addr) | R300_PVS_FC_LOOP_CNT_JMP_INST(0xff) | R300_PVS_FC_LAST_INST(last_addr) | R300_PVS_FC_RTN_INST(ret_addr) ; } compiler->code->fc_loop_index[compiler->code->num_fc_ops] = R300_PVS_FC_LOOP_INIT_VAL(0x0) | R300_PVS_FC_LOOP_STEP_VAL(0x1) ; compiler->code->fc_ops |= R300_VAP_PVS_FC_OPC_LOOP( compiler->code->num_fc_ops); compiler->code->num_fc_ops++; current_loop_depth--; continue; } default: rc_error(&compiler->Base, "Unknown opcode %s\n", info->Name); return; } /* Non-flow control instructions that are inside an if statement * need to pay attention to the predicate bit. */ if (branch_depth && vpi->Opcode != RC_OPCODE_IF && vpi->Opcode != RC_OPCODE_ELSE && vpi->Opcode != RC_OPCODE_ENDIF) { inst[0] |= (PVS_DST_PRED_ENABLE_MASK << PVS_DST_PRED_ENABLE_SHIFT); inst[0] |= (PVS_DST_PRED_SENSE_MASK << PVS_DST_PRED_SENSE_SHIFT); } /* Update the number of temporaries. */ if (info->HasDstReg && vpi->DstReg.File == RC_FILE_TEMPORARY && vpi->DstReg.Index >= compiler->code->num_temporaries) compiler->code->num_temporaries = vpi->DstReg.Index + 1; for (unsigned i = 0; i < info->NumSrcRegs; i++) if (vpi->SrcReg[i].File == RC_FILE_TEMPORARY && vpi->SrcReg[i].Index >= compiler->code->num_temporaries) compiler->code->num_temporaries = vpi->SrcReg[i].Index + 1; if (compiler->PredicateMask) if (compiler->PredicateIndex >= compiler->code->num_temporaries) compiler->code->num_temporaries = compiler->PredicateIndex + 1; if (compiler->code->num_temporaries > compiler->Base.max_temp_regs) { rc_error(&compiler->Base, "Too many temporaries.\n"); return; } compiler->code->length += 4; if (compiler->Base.Error) return; } }
/** * @param c * @param loop * @param inst A pointer to a BGNLOOP instruction. * @return 1 if all of the members of loop where set. * @return 0 if there was an error and some members of loop are still NULL. */ static int build_loop_info(struct radeon_compiler * c, struct loop_info * loop, struct rc_instruction * inst) { struct rc_instruction * ptr; if(inst->U.I.Opcode != RC_OPCODE_BGNLOOP){ rc_error(c, "%s: expected BGNLOOP", __FUNCTION__); return 0; } memset(loop, 0, sizeof(struct loop_info)); loop->BeginLoop = inst; for(ptr = loop->BeginLoop->Next; !loop->EndLoop; ptr = ptr->Next) { if (ptr == &c->Program.Instructions) { rc_error(c, "%s: BGNLOOP without an ENDLOOOP.\n", __FUNCTION__); return 0; } switch(ptr->U.I.Opcode){ case RC_OPCODE_BGNLOOP: { /* Nested loop, skip ahead to the end. */ unsigned int loop_depth = 1; for(ptr = ptr->Next; ptr != &c->Program.Instructions; ptr = ptr->Next){ if (ptr->U.I.Opcode == RC_OPCODE_BGNLOOP) { loop_depth++; } else if (ptr->U.I.Opcode == RC_OPCODE_ENDLOOP) { if (!--loop_depth) { break; } } } if (ptr == &c->Program.Instructions) { rc_error(c, "%s: BGNLOOP without an ENDLOOOP\n", __FUNCTION__); return 0; } break; } case RC_OPCODE_BRK: if(ptr->Next->U.I.Opcode != RC_OPCODE_ENDIF || ptr->Prev->U.I.Opcode != RC_OPCODE_IF || loop->Brk){ continue; } loop->Brk = ptr; loop->If = ptr->Prev; loop->EndIf = ptr->Next; switch(loop->If->Prev->U.I.Opcode){ case RC_OPCODE_SLT: case RC_OPCODE_SGE: case RC_OPCODE_SGT: case RC_OPCODE_SLE: case RC_OPCODE_SEQ: case RC_OPCODE_SNE: break; default: return 0; } loop->Cond = loop->If->Prev; break; case RC_OPCODE_ENDLOOP: loop->EndLoop = ptr; break; } } if (loop->BeginLoop && loop->Brk && loop->If && loop->EndIf && loop->Cond && loop->EndLoop) { return 1; } return 0; }
extern void doredirs() { List *fname; int fd, p[2]; Rq *r; for (r = redirq; r != NULL; r = r->n) { switch(r->r->type) { default: panic("unexpected node in doredirs"); /* NOTREACHED */ case nRedir: if (r->r->u[0].i == rHerestring) { fname = flatten(glom(r->r->u[2].p)); /* fname is really a string */ if (pipe(p) < 0) { uerror("pipe"); rc_error(NULL); } if (rc_fork() == 0) { /* child writes to pipe */ setsigdefaults(FALSE); close(p[0]); if (fname != NULL) writeall(p[1], fname->w, strlen(fname->w)); exit(0); } else { close(p[1]); if (mvfd(p[0], r->r->u[1].i) < 0) rc_error(NULL); } } else { fname = glob(glom(r->r->u[2].p)); if (fname == NULL) rc_error("null filename in redirection"); if (fname->n != NULL) rc_error("multi-word filename in redirection"); switch (r->r->u[0].i) { default: panic("unexpected node in doredirs"); /* NOTREACHED */ case rCreate: case rAppend: case rFrom: fd = rc_open(fname->w, r->r->u[0].i); break; } if (fd < 0) { uerror(fname->w); rc_error(NULL); } if (mvfd(fd, r->r->u[1].i) < 0) rc_error(NULL); } break; case nDup: if (r->r->u[2].i == -1) close(r->r->u[1].i); else if (r->r->u[2].i != r->r->u[1].i) { if (dup2(r->r->u[2].i, r->r->u[1].i) < 0) { uerror("dup2"); rc_error(NULL); } } } } redirq = NULL; }
/** * Emit one paired ALU instruction. */ static int emit_alu(struct r300_emit_state * emit, struct rc_pair_instruction* inst) { int ip; int j; PROG_CODE; if (code->alu.length >= c->Base.max_alu_insts) { error("Too many ALU instructions"); return 0; } ip = code->alu.length++; code->alu.inst[ip].rgb_inst = translate_rgb_opcode(c, inst->RGB.Opcode); code->alu.inst[ip].alpha_inst = translate_alpha_opcode(c, inst->Alpha.Opcode); for(j = 0; j < 3; ++j) { /* Set the RGB address */ unsigned int src = use_source(code, inst->RGB.Src[j]); unsigned int arg; if (inst->RGB.Src[j].Index >= R300_PFS_NUM_TEMP_REGS) code->alu.inst[ip].r400_ext_addr |= R400_ADDR_EXT_RGB_MSB_BIT(j); code->alu.inst[ip].rgb_addr |= src << (6*j); /* Set the Alpha address */ src = use_source(code, inst->Alpha.Src[j]); if (inst->Alpha.Src[j].Index >= R300_PFS_NUM_TEMP_REGS) code->alu.inst[ip].r400_ext_addr |= R400_ADDR_EXT_A_MSB_BIT(j); code->alu.inst[ip].alpha_addr |= src << (6*j); arg = r300FPTranslateRGBSwizzle(inst->RGB.Arg[j].Source, inst->RGB.Arg[j].Swizzle); arg |= inst->RGB.Arg[j].Abs << 6; arg |= inst->RGB.Arg[j].Negate << 5; code->alu.inst[ip].rgb_inst |= arg << (7*j); arg = r300FPTranslateAlphaSwizzle(inst->Alpha.Arg[j].Source, inst->Alpha.Arg[j].Swizzle); arg |= inst->Alpha.Arg[j].Abs << 6; arg |= inst->Alpha.Arg[j].Negate << 5; code->alu.inst[ip].alpha_inst |= arg << (7*j); } /* Presubtract */ if (inst->RGB.Src[RC_PAIR_PRESUB_SRC].Used) { switch(inst->RGB.Src[RC_PAIR_PRESUB_SRC].Index) { case RC_PRESUB_BIAS: code->alu.inst[ip].rgb_inst |= R300_ALU_SRCP_1_MINUS_2_SRC0; break; case RC_PRESUB_ADD: code->alu.inst[ip].rgb_inst |= R300_ALU_SRCP_SRC1_PLUS_SRC0; break; case RC_PRESUB_SUB: code->alu.inst[ip].rgb_inst |= R300_ALU_SRCP_SRC1_MINUS_SRC0; break; case RC_PRESUB_INV: code->alu.inst[ip].rgb_inst |= R300_ALU_SRCP_1_MINUS_SRC0; break; default: break; } } if (inst->Alpha.Src[RC_PAIR_PRESUB_SRC].Used) { switch(inst->Alpha.Src[RC_PAIR_PRESUB_SRC].Index) { case RC_PRESUB_BIAS: code->alu.inst[ip].alpha_inst |= R300_ALU_SRCP_1_MINUS_2_SRC0; break; case RC_PRESUB_ADD: code->alu.inst[ip].alpha_inst |= R300_ALU_SRCP_SRC1_PLUS_SRC0; break; case RC_PRESUB_SUB: code->alu.inst[ip].alpha_inst |= R300_ALU_SRCP_SRC1_MINUS_SRC0; break; case RC_PRESUB_INV: code->alu.inst[ip].alpha_inst |= R300_ALU_SRCP_1_MINUS_SRC0; break; default: break; } } if (inst->RGB.Saturate) code->alu.inst[ip].rgb_inst |= R300_ALU_OUTC_CLAMP; if (inst->Alpha.Saturate) code->alu.inst[ip].alpha_inst |= R300_ALU_OUTA_CLAMP; if (inst->RGB.WriteMask) { use_temporary(code, inst->RGB.DestIndex); if (inst->RGB.DestIndex >= R300_PFS_NUM_TEMP_REGS) code->alu.inst[ip].r400_ext_addr |= R400_ADDRD_EXT_RGB_MSB_BIT; code->alu.inst[ip].rgb_addr |= ((inst->RGB.DestIndex & 0x1f) << R300_ALU_DSTC_SHIFT) | (inst->RGB.WriteMask << R300_ALU_DSTC_REG_MASK_SHIFT); } if (inst->RGB.OutputWriteMask) { code->alu.inst[ip].rgb_addr |= (inst->RGB.OutputWriteMask << R300_ALU_DSTC_OUTPUT_MASK_SHIFT) | R300_RGB_TARGET(inst->RGB.Target); emit->node_flags |= R300_RGBA_OUT; } if (inst->Alpha.WriteMask) { use_temporary(code, inst->Alpha.DestIndex); if (inst->Alpha.DestIndex >= R300_PFS_NUM_TEMP_REGS) code->alu.inst[ip].r400_ext_addr |= R400_ADDRD_EXT_A_MSB_BIT; code->alu.inst[ip].alpha_addr |= ((inst->Alpha.DestIndex & 0x1f) << R300_ALU_DSTA_SHIFT) | R300_ALU_DSTA_REG; } if (inst->Alpha.OutputWriteMask) { code->alu.inst[ip].alpha_addr |= R300_ALU_DSTA_OUTPUT | R300_ALPHA_TARGET(inst->Alpha.Target); emit->node_flags |= R300_RGBA_OUT; } if (inst->Alpha.DepthWriteMask) { code->alu.inst[ip].alpha_addr |= R300_ALU_DSTA_DEPTH; emit->node_flags |= R300_W_OUT; c->code->writes_depth = 1; } if (inst->Nop) code->alu.inst[ip].rgb_inst |= R300_ALU_INSERT_NOP; /* Handle Output Modifier * According to the r300 docs, there is no RC_OMOD_DISABLE for r300 */ if (inst->RGB.Omod) { if (inst->RGB.Omod == RC_OMOD_DISABLE) { rc_error(&c->Base, "RC_OMOD_DISABLE not supported"); } code->alu.inst[ip].rgb_inst |= (inst->RGB.Omod << R300_ALU_OUTC_MOD_SHIFT); } if (inst->Alpha.Omod) { if (inst->Alpha.Omod == RC_OMOD_DISABLE) { rc_error(&c->Base, "RC_OMOD_DISABLE not supported"); } code->alu.inst[ip].alpha_inst |= (inst->Alpha.Omod << R300_ALU_OUTC_MOD_SHIFT); } return 1; }
static struct r300_vertex_program *build_program(GLcontext *ctx, struct r300_vertex_program_key *wanted_key, const struct gl_vertex_program *mesa_vp) { struct r300_vertex_program *vp; struct r300_vertex_program_compiler compiler; vp = _mesa_calloc(sizeof(*vp)); vp->Base = (struct gl_vertex_program *) _mesa_clone_program(ctx, &mesa_vp->Base); _mesa_memcpy(&vp->key, wanted_key, sizeof(vp->key)); rc_init(&compiler.Base); compiler.Base.Debug = (RADEON_DEBUG & RADEON_VERTS) ? GL_TRUE : GL_FALSE; compiler.code = &vp->code; compiler.RequiredOutputs = compute_required_outputs(vp->Base, vp->key.FpReads); compiler.SetHwInputOutput = &t_inputs_outputs; if (compiler.Base.Debug) { fprintf(stderr, "Initial vertex program:\n"); _mesa_print_program(&vp->Base->Base); fflush(stderr); } if (mesa_vp->IsPositionInvariant) { _mesa_insert_mvp_code(ctx, vp->Base); } radeon_mesa_to_rc_program(&compiler.Base, &vp->Base->Base); if (mesa_vp->IsNVProgram) initialize_NV_registers(&compiler.Base); rc_move_output(&compiler.Base, VERT_RESULT_PSIZ, VERT_RESULT_PSIZ, WRITEMASK_X); if (vp->key.WPosAttr != FRAG_ATTRIB_MAX) { rc_copy_output(&compiler.Base, VERT_RESULT_HPOS, vp->key.WPosAttr - FRAG_ATTRIB_TEX0 + VERT_RESULT_TEX0); } if (vp->key.FogAttr != FRAG_ATTRIB_MAX) { rc_move_output(&compiler.Base, VERT_RESULT_FOGC, vp->key.FogAttr - FRAG_ATTRIB_TEX0 + VERT_RESULT_TEX0, WRITEMASK_X); } r3xx_compile_vertex_program(&compiler); if (vp->code.constants.Count > ctx->Const.VertexProgram.MaxParameters) { rc_error(&compiler.Base, "Program exceeds constant buffer size limit\n"); } vp->error = compiler.Base.Error; vp->Base->Base.InputsRead = vp->code.InputsRead; vp->Base->Base.OutputsWritten = vp->code.OutputsWritten; rc_destroy(&compiler.Base); return vp; }
/** * Final compilation step: Turn the intermediate radeon_program into * machine-readable instructions. */ void r300BuildFragmentProgramHwCode(struct radeon_compiler *c, void *user) { struct r300_fragment_program_compiler *compiler = (struct r300_fragment_program_compiler*)c; struct r300_emit_state emit; struct r300_fragment_program_code *code = &compiler->code->code.r300; unsigned int tex_end; memset(&emit, 0, sizeof(emit)); emit.compiler = compiler; memset(code, 0, sizeof(struct r300_fragment_program_code)); for(struct rc_instruction * inst = compiler->Base.Program.Instructions.Next; inst != &compiler->Base.Program.Instructions && !compiler->Base.Error; inst = inst->Next) { if (inst->Type == RC_INSTRUCTION_NORMAL) { if (inst->U.I.Opcode == RC_OPCODE_BEGIN_TEX) { begin_tex(&emit); continue; } emit_tex(&emit, inst); } else { emit_alu(&emit, &inst->U.P); } } if (code->pixsize >= compiler->Base.max_temp_regs) rc_error(&compiler->Base, "Too many hardware temporaries used.\n"); if (compiler->Base.Error) return; /* Finish the program */ finish_node(&emit); code->config |= emit.current_node; /* FIRST_NODE_HAS_TEX set by finish_node */ /* Set r400 extended instruction fields. These values will be ignored * on r300 cards. */ code->r400_code_offset_ext |= (get_msbs_alu(0) << R400_ALU_OFFSET_MSB_SHIFT) | (get_msbs_alu(code->alu.length - 1) << R400_ALU_SIZE_MSB_SHIFT); tex_end = code->tex.length ? code->tex.length - 1 : 0; code->code_offset = ((0 << R300_PFS_CNTL_ALU_OFFSET_SHIFT) & R300_PFS_CNTL_ALU_OFFSET_MASK) | (((code->alu.length - 1) << R300_PFS_CNTL_ALU_END_SHIFT) & R300_PFS_CNTL_ALU_END_MASK) | ((0 << R300_PFS_CNTL_TEX_OFFSET_SHIFT) & R300_PFS_CNTL_TEX_OFFSET_MASK) | ((tex_end << R300_PFS_CNTL_TEX_END_SHIFT) & R300_PFS_CNTL_TEX_END_MASK) | (get_msbs_tex(0, 5) << R400_TEX_START_MSB_SHIFT) | (get_msbs_tex(tex_end, 6) << R400_TEX_SIZE_MSB_SHIFT) ; if (emit.current_node < 3) { int shift = 3 - emit.current_node; int i; for(i = emit.current_node; i >= 0; --i) code->code_addr[shift + i] = code->code_addr[i]; for(i = 0; i < shift; ++i) code->code_addr[i] = 0; } if (code->pixsize >= R300_PFS_NUM_TEMP_REGS || code->alu.length > R300_PFS_MAX_ALU_INST || code->tex.length > R300_PFS_MAX_TEX_INST) { code->r390_mode = 1; } }