void Emit(char * filename) { Var * var; EmitOpen(filename); VarUse(); if (Verbose(NULL)) { PrintHeader(1, "Variables"); for(var = VarFirst(); var != NULL; var = VarNext(var)) { if (var->write >= 1 || var->read >= 1) { if (var->mode == INSTR_VAR && !VarIsReg(var) && !VarIsLabel(var)) { PrintVar(var); PrintEOL(); } } } PrintHeader(1, "Output"); } // verbose EmitLabels(); //TODO: ProcessUsedProc // if (!EmitProc(&ROOT_PROC)) goto failure; EmitProc(&ROOT_PROC); EmitProcedures(); EmitAsmIncludes(); EmitInstrOp(INSTR_CODE_END, NULL, NULL, NULL); VarEmitAlloc(); EmitInstrOp(INSTR_SRC_END, NULL, NULL, NULL); EmitClose(); }
void PrintDelete() { UInt8 color; if (G_VERBOSE) { color = PrintColor(OPTIMIZE_COLOR); Print(" => void"); PrintEOL(); PrintColor(color); } }
void VarSetPrint(VarSet * set) { VarTuple * tuple; UInt16 cnt, i; for(cnt = set->count, tuple = set->arr, i = 0; cnt>0; cnt--, tuple++, i++) { PrintVar(tuple->key); PrintEOL(); } }
void PrintInsert(Instr * i) { UInt8 color; if (G_VERBOSE) { color = PrintColor(OPTIMIZE_COLOR); Print(" + | "); EmitInstrInline(i); PrintColor(color); PrintEOL(); } }
Bool OptimizeLoop(Var * proc, InstrBlock * header, InstrBlock * end) /* 1. Find loop (starting with inner loops) - Every jump to label preceding the jump (backjump) forms a label - In nested labels, we encounter the backjump first <code1> l1@ <code2> l2@ <code3> if.. l2@ <code4> if.. l3@ <code5> 2. Select variable to put to register - Most used variable should be used - Some variables are already moved to index register (this is considered use too) 3. Compute cost of moving the variable to register */ { Instr * i, initial, ti, * last_mod; Var * top_var, * reg, * top_reg, * orig_result; UInt16 r, regi, changed; UInt32 var_size; Int32 q, top_q, n; Bool init, top_init; InstrBlock * blk, * last_mod_blk; InstrBlock * blk_exit; Bool var_modified; Bool verbose; Rule * rule; UInt8 color; blk_exit = end->next; G_VERBOSE = verbose = Verbose(proc); VarResetUse(); InstrVarUse(header, blk_exit); InstrVarLoopDependent(header, end); // When processing, we assign var to register for(regi = 0; regi < CPU->REG_CNT; regi++) CPU->REG[regi]->var = NULL; while(top_var = FindMostUsedVar()) { // if (Verbose(proc)) { // Print("Most user var: "); PrintVar(top_var); PrintEOL(); // } top_var->read = top_var->write = 0; var_size = VarByteSize(top_var); //====== Select the best register for the given variable // let %A,%A => index -3 // use of register instead of variable -1 // spill +3 top_q = 0; top_reg = NULL; top_init = false; for(regi = 0; regi < CPU->REG_CNT; regi++) { reg = CPU->REG[regi]; if (FlagOn(reg->submode, SUBMODE_IN|SUBMODE_OUT)) continue; // exclude input/output registers if (reg->type->range.max == 1) continue; // exclude flag registers if (var_size != VarByteSize(reg)) continue; // exclude registers with different byte size if (reg->var != NULL) continue; if (InstrRule2(INSTR_LET, reg, top_var, NULL)) { // if (StrEqual(reg->name, "x") && StrEqual(top_var->name, "i")) { // Print(" "); // } q = UsageQuotient(header, end, top_var, reg, &init); if (q < top_q) { top_q = q; top_reg = reg; top_init = init; } } } if (top_reg == NULL) continue; reg = top_reg; if (Verbose(proc)) { color = PrintColor(OPTIMIZE_COLOR); PrintFmt("*** Loop %d..%d\n", header->seq_no, end->seq_no); Print("Var: "); PrintVarVal(top_var); PrintEOL(); Print("Register: "); PrintVarName(top_reg); PrintEOL(); PrintFmt("Quotient: %d\n", top_q); PrintColor(color); } //TODO: If there is Let reg = var and var is not top_var, we need to spill store //=== Replace the use of registers // PrintProc(proc); ResetValues(); initial.op = INSTR_LET; initial.result = top_reg; initial.arg1 = top_var; initial.arg2 = NULL; var_modified = false; // Generate instruction initializing the register used to replace the variable // before the start of the loop. // We only do this, if the variable is not initialized inside the loop. // if (FlagOn(top_var->flags, VarUninitialized) && !top_init) { // top_init = true; // } if (top_init) { LoopInsertPrologue(proc, header, INSTR_LET, top_reg, top_var, NULL); VarSetSrcInstr(top_reg, &initial); } r = 0; last_mod = NULL; for(blk = header; blk != blk_exit; blk = blk->next) { if (verbose) PrintBlockHeader(blk); for(i = blk->first, n=0; i != NULL; i = i->next) { retry: n++; if (i->op == INSTR_LINE) { if (verbose) { PrintInstrLine(n); EmitInstrInline(i); PrintEOL(); } continue; } // Delete unnecessary assignment if (i->op == INSTR_LET) { if (!InVar(i->arg1) && !OutVar(i->result) && VarContains(i->result, i->arg1)) { del: if (verbose) { PrintInstrLine(n); EmitInstrInline(i); } del2: if (verbose) { PrintDelete(); } i = InstrDelete(blk, i); if (i == NULL) break; goto retry; //continue; } } // Load the register with variable if necessary if (InstrReadsVar(i, top_var)) { if (!VarContains(top_reg, top_var)) { if (!(i->op == INSTR_LET && i->result == top_reg && i->arg1 == top_var)) { InstrInsertRule(blk, i, INSTR_LET, top_reg, top_var, NULL); } } } if (i->op == INSTR_LET && (i->result == top_var && i->arg1 == top_reg)) { r++; goto del; } if (InstrSpill(i, top_var)) { InstrInsertRule(blk, i, INSTR_LET, top_var, top_reg, NULL); } if (verbose) { PrintInstrLine(n); EmitInstrInline(i); } orig_result = i->result; memcpy(&ti, i, sizeof(Instr)); changed = VarTestReplace(&ti.result, top_var, reg); r += changed; changed += VarTestReplace(&ti.arg1, top_var, reg); changed += VarTestReplace(&ti.arg2, top_var, reg); // If the instruction used variable, that contains same value as replaced register, use the register instead if (ti.arg1 != reg && VarContains(ti.arg1, reg)) { changed += VarTestReplace(&ti.result, ti.arg1, reg); changed += VarTestReplace(&ti.arg2, ti.arg1, reg); changed += VarTestReplace(&ti.arg1, ti.arg1, reg); } if (changed > 0) { if (i->op == INSTR_LET && ti.result == ti.arg1) { goto del2; } rule = InstrRule(&ti); if (rule != NULL && (i->rule->cycles >= rule->cycles)) { InstrReplaceVar(i, top_var, top_reg); if (i->arg1 != reg && VarContains(i->arg1, reg)) { VarTestReplace(&i->result, i->arg1, reg); VarTestReplace(&i->arg2, i->arg1, reg); VarTestReplace(&i->arg1, i->arg1, reg); } i->rule = rule; CheckInstr(i); PrintChange(i); } } if (verbose) PrintEOL(); ResetValue(i->result); if (orig_result == top_var) { // if (!InstrIsSelfReferencing(i)) { VarSetSrcInstr(i->result, &initial); // } else { // VarSetSrcInstr(i->result, NULL); // } last_mod = i; last_mod_blk = blk; } else { VarSetSrcInstr(i->result, i); } } } // Value of register is not known at the end of loop, but it is not initialized at the beginning of the loop // We must load it before first use. if (!top_init && last_mod) { InstrInsertRule(last_mod_blk, last_mod->next, INSTR_LET, top_var, top_reg, NULL); } // If we replaced some destination by the register, store the register to destination if (r > 0) { // There may be exit label as part of the loop // We need to spill after it if (!VarIsConst(top_var)) { if (blk_exit == NULL || blk_exit->callers != NULL || blk_exit->from != end) { blk_exit = InstrBlockAlloc(); blk_exit->to = end->to; blk_exit->next = end->to; end->next = blk_exit; end->to = blk_exit; } InstrInsertRule(blk_exit, blk_exit->first, INSTR_LET, top_var, top_reg, NULL); } // InstrInsert(blk_exit, blk_exit->first, INSTR_LET, top_var, top_reg, NULL); } if (FlagOn(top_var->flags, VarLoopDependent)) { reg->flags |= VarLoopDependent; } return true; } return false; }
void VM_Dsr::EOL( QString /*value*/, long line, long level ) { PrintEOL( line, level ); }