/* * To change this license header, choose License Headers in Project Properties. * To change this template file, choose Tools | Templates * and open the template in the editor. */ package targets.mips; import common.Code; import common.DataLayout; import common.Instruction; import common.IvannosysTargetArch; import common.Offset; import java.util.ArrayList; import java.util.HashMap; import java.util.LinkedList; import java.util.logging.Level; import java.util.logging.Logger; /** * MipS tranSlation * * @author EUGENIO CARVALHO */ public class Translate extends API.TargetGen { protected String[] registersKeys = "reg.p1,reg.p2".split(","); protected ArrayList returnRegisters; protected HashMap AddressCalculated = new HashMap<>(); protected HashMap comments = new HashMap() { { put("beq", "branch if equals"); put("bne", "branch if not equals"); put("blez", "branch if register <= 0"); put("bltz", "branch if register < 0"); put("bgez", "branch if register >= 0"); put("bgtz", "branch if register > 0"); } }; protected HashMap ctrlDataUpdate = new HashMap<>(); public Translate() { super("mips"); } @Override public void TranslateLabel(Instruction inst) throws Exception { Add(new Instruction() .Set("type", "label") .Set("format", "norender") .Set("label", inst.Get("label"))); getTarget().RegisterLabelAddress(inst.Get("label")); } @Override public void TranslateCopy(Instruction inst) throws Exception { Copy(inst, inst.Get("reg.dst")) .Set("comment", F("copy %s ← %s", inst.Get("dst"), inst.Get("p1"))); } @Override public void TranslateAssign(Instruction inst) throws Exception { String instruction = Descriprion.InstructionByOperator(inst); String rd = inst.Get("reg.dst"), dst = inst.Get("dst"); Instruction ninst = new Instruction(instruction); switch (Descriprion.Codops.get(instruction).Get("type")) { //addi, addiu, slti, sltiu case "I": ninst.Set("rt", rd); // System.out.println("Assign:" + inst); if (inst.eq("p2value", "true")) { String op = inst.Get("op"); LoadParam(inst, "p1"); ninst.Set("offset", (op.equals("-") ? "-" : "") + inst.Get("p2")) .Set("rs", inst.Get("reg.p1")); } else { LoadParam(inst, "p2"); ninst.Set("offset", inst.Get("p1")) .Set("rs", inst.Get("reg.p2")); } break; // mult, divu, sgtu ,sltu // sra, srl, sll case "R": LoadParam(inst); // if (ninst.in("inst", "sll,srl,sra".split(","))) { rd = inst.Get("reg.dst"); ninst.Set("sa", inst.Get("p2")) .Set("rt", inst.Get("reg.p1")); } else { ninst.Set("rs", inst.Get("reg.p1")) .Set("rt", inst.Get("reg.p2")); } ninst.Set("rd", rd); // System.out.println("inst["+rd+"]" + inst + ":" + ninst); break; } Add(ninst).Set("comment", F( "%s = %s %s %s", dst, inst.Get("p1"), inst.Get("op"), inst.Get("p2") )); // Verifica se a expr possui overflow String overflow = Descriprion.Instruction(instruction).Get("overflow"); if (!overflow.equals("")) { Add(new Instruction("R", overflow) .Set("rd", rd) ); } // StoreResult(inst, rd, dst); } @Override public void TranslateJump(Instruction inst) throws Exception { Add(new Instruction("J", "j") .copy("label", inst) .Set("comment", F("jump to %s", inst.Get("label"))) ); Nop(false); } @Override public void TranslateCall(Instruction inst) throws Exception { // allocation.registers.ResetArgs(); // Before load params // Copy(inst, returnRegisters.remove(2)) // .Set("IR.position", inst.Get("block.position")) // .Set("comment", "push param"); // System.out.println("Call" + inst); ResetReturnArgs(); Instruction retur; LinkedList intructions = getIR().Block().Instructions(); int base = intructions.indexOf(inst); for (int i = inst.GetInt("numParams"); i > 0; i--) { retur = intructions.get(base - i); Copy(retur, returnRegisters.remove(2)) .Set("comment", "push param"); } Add(new Instruction("J", "jal") .Set("label", inst.Get("funcname")) .Set("comment", F("jump to <%s>", inst.Get("funcname"))) ); // After store results // Restaura o array de registradores de retorno para fazer o pop dos returns ResetReturnArgs(); Nop(false); } @Override public void TranslateReturn(Instruction inst) throws Exception { // Restaura o array de registradores de retorno ResetReturnArgs(); Instruction retur; LinkedList intructions = getIR().Block().Instructions(); int base = intructions.indexOf(inst); for (int i = inst.GetInt("p1"); i > 0; i--) { retur = intructions.get(base - i); // System.out.println("Return:" + retur); Copy(retur, returnRegisters.remove(0)) .Set("comment", "push return "); } } @Override public void TranslatePopReturn(Instruction inst) throws Exception { String p1 = inst.Get("p1"), reg = returnRegisters.remove(0); // Se for uma variavel temporaria if (p1.contains("_T")) { CopyReg(reg, inst.Get("reg.p1")); } else { StoreWord( target.DEFAULT_WORD_TYPE, reg, FrameRegister(p1), Offset(p1) ); } // System.out.println("Translate pop return" + inst); } @Override public void TranslatePopParam(Instruction inst) throws Exception { // todo - resetar args // System.out.println("PopParam:" + inst); String p1 = inst.Get("p1"); // O indice é 2 por conta dos dois primeiros registradores {v0, v1} // System.out.println("PopParams:" + inst); StoreWord( target.DEFAULT_WORD_TYPE, returnRegisters.remove(2), FrameRegister(p1), Offset(p1) ).Set("comment", "pop param"); // System.out.println("POPpARAM:" + inst); // LoadWord(inst.Get("reg.p1"), "fp", offset); } @Override public void TranslateBranch(Instruction inst) throws Exception { String instruction = Descriprion.InstructionByOperator(inst); LoadParam(inst); String rs = inst.Get("reg.p1"), rt = inst.Get("reg.p2"); Instruction branch = Descriprion.Instruction(instruction); // .Set("label", inst.Get("funcname")); switch (instruction) { case "beq": // == {[inst]}' ' {[rt]},{[rs]},{immediate} case "bne": // != branch.Set("rs", rs).Set("rt", rt); break; case "blez": // <= 0{[inst]}' ' {[rs]},{immediate} case "bltz": // < 0 case "bgez": // >= 0 case "bgtz": // > 0 Add(new Instruction("R", "subu")// Rd <-- [Rs] - [Rt]; .Set("rs", rs) .Set("rt", rt) .Set("rd", "v0") .Set("comment", "") ); branch.Set("rs", "v0"); break; } Add(branch) .Set("label", inst.Get("label")) .Set("comment", comments.get(instruction)); Nop(false); } protected void Nop(Boolean checkDependence) throws Exception { if (checkDependence) { Instruction n = Next(); Integer dep = 0; // Se existe uma proxima intrucao if (n != null) { String dst = currentIrInstruction.Get( currentIrInstruction.Has("reg.dst") ? "reg.dst" : "reg.p1" ); for (String reg : registersKeys) { if (n.eq(reg, dst)) { dep++; break; } } if (dep == 0) { return; } } } Add(Descriprion.Instruction("nop")); } @Override public void Prolog(String id) throws Exception { DataLayout data = Context(); // Adiciona o label Add(new Instruction() .Set("type", "label") .Set("format", "label") .Set("label", id) ); // Aloca o espaco da pilha Instruction alloc = Copy("sp", "sp", "-" + data.Size()) .Set("comment", "prolog| push stack frame"); if (!getTarget().Block().getName().equals("main")) { // Restaura o fp // Restaura o ra // boolean call = getIR().Block().HasCall(); if (getIR().Block().HasCall()) { // int newvars = 0; for (String reg : new String[]{"fp", "ra"}) { data.Add(reg, "int32", 1); StoreWord( target.DEFAULT_WORD_TYPE, reg, "sp", data.Offset(reg) ).Set("comment", F("prolog| backup %s", reg)); } alloc.Set("offset", (data.Size() - 0)); } } if (alloc.getInt("offset", 0) != 0) { // Copia o sp para o fp CopyReg("sp", "fp").Prepend("comment", "prolog|"); ResetReturnArgs(); } else { getTarget().Block().Remove(alloc); } } /** * Encerra a chamada de uma funcao * * @param id * @throws Exception */ @Override public void Epilog(String id) throws Exception { DataLayout data = Context(); if (!getTarget().Block().getName().equals("main")) { // Restaura o fp // Restaura o ra boolean call = getIR().Block().HasCall(); for (String reg : new String[]{"fp", "ra"}) { if (call) { LoadWord( target.DEFAULT_WORD_TYPE, reg, "sp", data.Offset(reg) ).Set("comment", F("epilog| restore ", reg)); } } // Desaloca a pilha Copy("sp", "sp", Long.valueOf(data.Size()).toString()) .Set("comment", "epilog| pop stack frame"); CopyReg("sp", "fp") .Set("comment", "epilog| pop stack frame"); Add(new Instruction("jr") .Set("rs", "ra") .Set("comment", "epilog| return")); } else { Add(Descriprion.Instruction("stop").copy()); } } @Override public void TranslateIndexedAssignment(Instruction inst) throws Exception { //Fase de leitura IndexedRead(inst); //Fase de atribuicao IndexedDest(inst); } @Override public void TranslateUnary(Instruction inst) throws Exception { // Carrega o valor se nao esta em registrador // System.out.println("Translate Unary:" + inst); switch (inst.Get("op")) { case "-": // Retorna o valor negado 10 -> -10 Add(new Instruction("subu")// Rd <-- [Rs] - [Rt]; .Set("rd", inst.Get("reg.dst")) .Set("rs", "zero") .Set("rt", inst.Get("reg.p1")) .Set("comment", "negation arith") ); break; case "!": // XOR ( 0 1 -> 1) XOR( 1 1 -> 0) Add(new Instruction("xori") // Rt <-- [Rs] AND (016 || [I15..0]); ; .Set("rt", inst.Get("reg.dst")) .Set("rs", inst.Get("reg.p1")) .Set("offset", "1") .Set("comment", "negation bool") ); break; // case "*": // Copia do conteudo do ponteiro // // case "&": // Copia do endereco da variavel // break;// case "*": // Copia do conteudo do ponteiro // // case "&": // Copia do endereco da variavel // break;// case "*": // Copia do conteudo do ponteiro // // case "&": // Copia do endereco da variavel // break;// case "*": // Copia do conteudo do ponteiro // // case "&": // Copia do endereco da variavel // break;// case "*": // Copia do conteudo do ponteiro // // case "&": // Copia do endereco da variavel // break;// case "*": // Copia do conteudo do ponteiro // // case "&": // Copia do endereco da variavel // break;// case "*": // Copia do conteudo do ponteiro // // case "&": // Copia do endereco da variavel // break;// case "*": // Copia do conteudo do ponteiro // // case "&": // Copia do endereco da variavel // break; } } @Override public void TranslateLoad(Instruction inst) throws Exception { String addr = inst.Get("p1"), rd = inst.Get("reg.p1"); // System.out.println("Load " + inst + " on block "); LoadWord( target.DEFAULT_WORD_TYPE, rd, FrameRegister(addr), Offset(addr) ).Set("comment", F("load content from %s in %s", addr, rd)); } @Override public void TranslateStore(Instruction inst) throws Exception { String addr = inst.Get("p1"), rs = inst.Get("reg.p1"); StoreWord( target.DEFAULT_WORD_TYPE, rs, FrameRegister(addr), Offset(addr) ).Set("comment", F("store content of %s in %s", rs, addr)); } /** * Traducao de intrucoeS do tipo * * - x = &a - copia do endereco de uma varaivel
* - x = *b - x recebe o conteudo da variavel referenciada por b
* - *x = y - conpia o conteudo de y para o endereco armazenado em x * * @param inst * @throws Exception */ @Override public void TranslatePointerAssignment(Instruction inst) throws Exception { String p1 = inst.Get("p1"), dst = inst.Get("dst"), regdst = inst.Get("reg.dst"), regp1 = inst.Get("reg.p1"); switch (inst.Get("op")) { case "&": // Lendo o endereco de um ponteiro Copy(regp1, FrameRegister(p1), Offset(p1) ).Set("comment", F("copy address of ", p1)); System.out.println("PointerAssi&:" + inst); // Se nao fez o store // if (StoreResult(inst, regp1, dst) == null) { // CopyReg(regp1, regdst); // .Set("comment", "store content of " + regdst + " in " + dst); // } break; case "*": // Lendo o conteudo de um ponteiro /** * Carrega o valor contido no ponteiro
* Utiliza o valor como endereço em um segundo load que carrega * o dado
* lw ${p1},12($fp)
* lw ${dst},0(${p1}) $s
*/ LoadWord( target.DEFAULT_WORD_TYPE, regp1, FrameRegister(p1), Offset(p1) ).Set("comment", F("load address stored in %s", p1)); LoadWord( target.DEFAULT_WORD_TYPE, regdst, regp1, "0" ).Set("comment", F("load content of address stored in %s", regp1)); /*Se for a ultima operacao de escrita nessa variavel salva em memoria*/ // Instruction store = StoreResult(inst, regdst, dst); // if (store != null) { // store.Set("comment", "store content of " + regdst + " in " + dst); // } break; default: // Atribuicao a um ponteiro LoadParam(inst); /** * Carrega o valor dentro do endereco do ponteiro
* lw ${p1},12(${fp|gp})
* lw ${dst},0(${p1}) $s
* conteudo da variavel referenciada */ LoadWord( target.DEFAULT_WORD_TYPE, regdst, FrameRegister(dst), Offset(dst) ).Set("comment", F("load address stored in %s", dst)); // Grava o valor do registrador na memoria StoreWord( target.DEFAULT_WORD_TYPE, regp1, regdst, "0" ).Set("comment", F("store content of %s in *%s", regp1, dst)); } } @Override public void TranslatePushReturn(Instruction inst) { // Tratado no metodo 'TranslateReturn' } @Override public void TranslatePushParam(Instruction inst) { // Tratado no metodo 'TranslateCall' } // public void CopyData(LinkedHashMap dst, LinkedHashMap src) throws Exception { // public void CopyData(DataLayout dst, DataLayout src) throws Exception { // Node value; // LinkedHashMap svalues = src.values(), // dvalues = dst.values(); // // for (Map.Entry x : svalues.entrySet()) { // value = x.getValue().copy(); // value.S("size", value.GetInt("size") * WORD_INC); //// System.out.println("Copy:[" + x.getKey() + "][" + value.Get("id") + "]" + value.Get("size") + "\n" + value); //// dvalues.put(x.getKey(), value); // // dst.Set(x.getKey(), value); // } // } @Override public IvannosysTargetArch Init(Code tac) throws Exception { this.IR = tac; getTarget() .setAddressIncrement(4) .Template(new MipsTemplateDescription()); // getTarget().AfterTranslateBlock("Copy.dep", new CopyDeps(tac)); // CopyData(target.GlobalContext().values(), IR.GlobalContext().values()); // CopyData( // target.GlobalContext(), // tac.GlobalContext() // ); return this; } /** * Criar uma inStrucao que copia o valor ou conteudo do regiStrador para o * regiStrador 'r' * * @param inst * @param rt * @return */ protected Instruction Copy(Instruction inst, String rt) throws Exception { Instruction c; if (inst.IsValue("p1")) { // andi Rt,Rs,immediate | Rt <-- [Rs] + ([I15]16 || [I15..0]); c = Copy(rt, "zero", inst.Get("p1")); } else { // addu Rd,Rs,Rt | Rd <-- [Rs] + [Rt]; LoadParam(inst, "p1"); c = CopyReg(inst.Get("reg.p1"), rt); } return c; } protected void IndexedRead(Instruction inst) throws Exception { // Se a fonte é indexada if (inst.eq("src_indexed", "true")) { try { String p1 = inst.Get("p1"), rt = inst.Get("reg.p1"), rs = FrameRegister(p1); // System.out.println("Indexed read:" + inst); if (!inst.isNumber("p1.indice")) { String rd = inst.Get("reg.p1.indice"); if (!AddressCalculated.containsKey(p1)) { Add(new Instruction("addu") .Set("rd", rd) .Set("rs", rs) .Set("rt", rd)); AddressCalculated.put(p1, rs); } rs = rd; } // Carrega o conteudo enderecado em rt para rt LoadWord( target.DEFAULT_WORD_TYPE, rt, rs, Offset(p1) ); } catch (Exception ex) { Logger.getLogger(Translate.class.getName()).log(Level.SEVERE, null, ex); } } else { // Se não é indexada carrega o parametro normalmente LoadParam(inst); } } /** * FaSe de atribuicao * * @param inst */ protected void IndexedDest(Instruction inst) throws Exception { // System.out.println("Indexeds:" + inst); String regp1 = inst.Get("reg.p1"), regdst = inst.Get("reg.dst"); // Valor atribuido é indexado // 1 - Verificar se deve ser armazenado ou copiado // boolean dstIndexed = inst.eq("dst.indexed", "true"); if (inst.eq("dst.indexed", "true")) { // if (dstIndexed || inst.eq("reg.dst.store", "true")) { // deve ser armazenado String dst = inst.Get("dst"), rs = FrameRegister(dst); // if (dstIndexed) { if (!inst.isNumber("dst.indice")) { // Offset agora deve ser 0 pois o registrador conterá o endereco completo // offset = 0; String rd = inst.Get("reg.dst.indice"); if (!AddressCalculated.containsKey(dst)) { Add(new Instruction("addu") .Set("rd", rd) .Set("rs", rs) .Set("rt", rd) ); AddressCalculated.put(dst, rs); } rs = rd; } // comment = "store in loaded address"; // } else { // comment = "store in " + dst; // }// System.out.println("Inst:" + inst); StoreWord( target.DEFAULT_WORD_TYPE, regp1, rs, Offset(dst) ).Set("comment", F("store content of %s in %s", rs, dst)); } else { // deve ser copiado CopyReg(regp1, regdst); } } /** * Verificar Se o valor da atribuição ja eSta em regiStrador. CaSo não * eSteja o valor é carregado e o valor retornado é o nome do regiStrador * * @param inst * @return */ protected void LoadParam(Instruction inst) throws Exception { LoadParam(inst, "p1,p2"); } protected void LoadParam(Instruction inst, String params) throws Exception { LoadParam(inst, params.split(",")); } protected void LoadParam(Instruction inst, String[] params) throws Exception { String offset; for (String param : params) { if (inst.IsValue(param) && inst.Has("reg." + param)) { offset = inst.Get(param); if (offset.equals("0")) { inst.Set("reg." + param, "zero"); continue; } Copy(inst.Get("reg." + param), "zero", offset); } } } /** * Copia o valor do regiStrador Src para o dSt * * @param src * @param dst * @return */ protected Instruction CopyReg(String src, String dst) throws Exception { return Add(new Instruction("addu") .Set("rs", "zero") .Set("rt", src) .Set("rd", dst) .Set("comment", F("copy %s ← %s", dst, src))); } protected Instruction Copy(String rt, String rs, Offset offset) throws Exception { return Copy(rt, rs, "" + offset); } protected Instruction Copy(String rt, String rs, String offset) throws Exception { return Add(new Instruction("addiu") // lw $rt, imm($rs) .Set("rt", rt) .Set("rs", rs) .Set("offset", offset) .Set("comment", F("copy %s ← %s", rs, rt)) ); } protected Instruction StoreWord(String type, String rt, String rs, Offset offset) throws Exception { Instruction n = Next(); String inst; switch (type) { case "byte": case "int8": case "uint8": case "bool": inst = "sb"; // Load byte break; case "int16": case "uint16": inst = "sh"; //Load half break; default: inst = "sw"; // Load word } Instruction sw = Add(new Instruction(inst) .Set("rt", rt) .Set("rs", rs) .Set("offset", offset.getAddress() + offset.getShift())); return sw; } protected Instruction StoreWord(String type, String rt, String rs, String offset) throws Exception { return StoreWord(type, rt, rs, new Offset(Long.parseLong(offset), 0L)); } protected Instruction LoadWord(String type, String rt, String rs, Offset offset) throws Exception { Instruction n = Next(); String inst; switch (type) { case "byte": case "int8": case "uint8": case "bool": // LB -- Load byte 8 bits // Operation:$t = MEM[$s + offset]; advance_pc (4); // Syntax: lb $t, offset($s) // Offset é o endereço base da variavel // Shift é o byte a ser lido inst = "lb"; break; case "int16": case "uint16": // LW -- Load half 16 bits // Operation:$t = MEM[$s + offset]; advance_pc (4); // Syntax: lw $t, offset($s) inst = "lh"; break; default: // LW -- Load word 32 bits // Operation:$t = MEM[$s + offset]; advance_pc (4); // Syntax: lw $t, offset($s) inst = "lw"; // Load word } Instruction lw = Add(new Instruction(inst) // lw $rt, imm($rs) .Set("rt", rt) .Set("rs", rs) .Set("offset", offset.getAddress() + offset.getShift()) ); Nop(true); return lw; } protected Instruction LoadWord(String type, String rt, String rs, String offset) throws Exception { return LoadWord(type, rt, rs, new Offset(Long.parseLong(offset), 0L)); } @Override protected Instruction Add(Instruction inst) throws Exception { if (!inst.eq("type", "label")) { getTarget().PositionInc(); Instruction definiction = Descriprion.Instruction(inst.Get("inst")); inst.Merge("sa,type,inst,codop,func,format", definiction); } if (currentIrInstruction != null) { inst.Set("inloop", currentIrInstruction.Get("inloop")); } // System.out.println("Add:" + inst); return super.Add(inst); //To change body of generated methods, choose Tools | Templates. } protected String FrameRegister(String var) { return var.contains("_G") ? "gp" : "fp"; } private void ResetReturnArgs() { returnRegisters = new ArrayList() { { add("v0"); add("v1"); add("a0"); add("a1"); add("a2"); add("a3"); } }; } }