/*
 * 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<String> returnRegisters;
    protected HashMap<String, String> AddressCalculated = new HashMap<>();
    protected HashMap<String, String> comments = new HashMap<String, String>() {
        {
            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<String, Boolean> 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<Instruction> 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<Instruction> 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 <br>
     * - x = *b - x recebe o conteudo da variavel referenciada por b<br>
     * - *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<br>
                 * Utiliza o valor como endereço em um segundo load que carrega
                 * o dado<br>
                 * lw ${p1},12($fp)<br>
                 * lw ${dst},0(${p1}) $s<br>
                 */
                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 <br>
                 * lw ${p1},12(${fp|gp})<br>
                 * lw ${dst},0(${p1}) $s<br>
                 * 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<String, Node> dst, LinkedHashMap<String, Node> src) throws Exception {
//    public void CopyData(DataLayout dst, DataLayout src) throws Exception {
//        Node value;
//        LinkedHashMap<String, Node> svalues = src.values(),
//                dvalues = dst.values();
//
//        for (Map.Entry<String, Node> 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<String>() {
            {
                add("v0");
                add("v1");
                add("a0");
                add("a1");
                add("a2");
                add("a3");
            }
        };
    }

}
