📄 c67-gen.c
字号:
/* relocation case */ // get add into A0, then start the jump B3 greloc(cur_text_section, vtop->sym, ind, R_C60LO16); // rem the inst need to be patched greloc(cur_text_section, vtop->sym, ind + 4, R_C60HI16); C67_MVKL(C67_A0, 0); //r=reg to load, constant C67_MVKH(C67_A0, 0); //r=reg to load, constant C67_IREG_B_REG(0, C67_CREG_ZERO, C67_A0); // B.S2x A0 if (is_jmp) { C67_NOP(5); // simple jump, just put NOP } else { // Call, must load return address into B3 during delay slots sym = get_sym_ref(&char_pointer_type, cur_text_section, ind + 12, 0); // symbol for return address greloc(cur_text_section, sym, ind, R_C60LO16); // rem the inst need to be patched greloc(cur_text_section, sym, ind + 4, R_C60HI16); C67_MVKL(C67_B3, 0); //r=reg to load, constant C67_MVKH(C67_B3, 0); //r=reg to load, constant C67_NOP(3); // put remaining NOPs } } else { /* put an empty PC32 relocation */ ALWAYS_ASSERT(FALSE); } } else { /* otherwise, indirect call */ r = gv(RC_INT); C67_IREG_B_REG(0, C67_CREG_ZERO, r); // B.S2x r if (is_jmp) { C67_NOP(5); // simple jump, just put NOP } else { // Call, must load return address into B3 during delay slots sym = get_sym_ref(&char_pointer_type, cur_text_section, ind + 12, 0); // symbol for return address greloc(cur_text_section, sym, ind, R_C60LO16); // rem the inst need to be patched greloc(cur_text_section, sym, ind + 4, R_C60HI16); C67_MVKL(C67_B3, 0); //r=reg to load, constant C67_MVKH(C67_B3, 0); //r=reg to load, constant C67_NOP(3); // put remaining NOPs } }}/* generate function call with address in (vtop->t, vtop->c) and free function context. Stack entry is popped */void gfunc_call(int nb_args){ int i, r, size = 0; int args_sizes[NoCallArgsPassedOnStack]; if (nb_args > NoCallArgsPassedOnStack) { error("more than 10 function params not currently supported"); // handle more than 10, put some on the stack } for (i = 0; i < nb_args; i++) { if ((vtop->type.t & VT_BTYPE) == VT_STRUCT) { ALWAYS_ASSERT(FALSE); } else if ((vtop->type.t & VT_BTYPE) == VT_STRUCT) { ALWAYS_ASSERT(FALSE); } else { /* simple type (currently always same size) */ /* XXX: implicit cast ? */ if ((vtop->type.t & VT_BTYPE) == VT_LLONG) { error("long long not supported"); } else if ((vtop->type.t & VT_BTYPE) == VT_LDOUBLE) { error("long double not supported"); } else if ((vtop->type.t & VT_BTYPE) == VT_DOUBLE) { size = 8; } else { size = 4; } // put the parameter into the corresponding reg (pair) r = gv(RC_C67_A4 << (2 * i)); // must put on stack because with 1 pass compiler , no way to tell // if an up coming nested call might overwrite these regs C67_PUSH(r); if (size == 8) { C67_STW_PTR_PRE_INC(r + 1, C67_SP, 3); // STW r, *+SP[3] (go back and put the other) } args_sizes[i] = size; } vtop--; } // POP all the params on the stack into registers for the // immediate call (in reverse order) for (i = nb_args - 1; i >= 0; i--) { if (args_sizes[i] == 8) C67_POP_DW(TREG_C67_A4 + i * 2); else C67_POP(TREG_C67_A4 + i * 2); } gcall_or_jmp(0); vtop--;}// to be compatible with Code Composer for the C67// the first 10 parameters must be passed in registers// (pairs for 64 bits) starting wit; A4:A5, then B4:B5 and// ending with B12:B13.//// When a call is made, if the caller has its parameters// in regs A4-B13 these must be saved before/as the call // parameters are loaded and restored upon return (or if/when needed)./* generate function prolog of type 't' */void gfunc_prolog(CType * func_type){ int addr, align, size, func_call, i; Sym *sym; CType *type; sym = func_type->ref; func_call = sym->r; addr = 8; /* if the function returns a structure, then add an implicit pointer parameter */ func_vt = sym->type; if ((func_vt.t & VT_BTYPE) == VT_STRUCT) { func_vc = addr; addr += 4; } NoOfCurFuncArgs = 0; /* define parameters */ while ((sym = sym->next) != NULL) { type = &sym->type; sym_push(sym->v & ~SYM_FIELD, type, VT_LOCAL | VT_LVAL, addr); size = type_size(type, &align); size = (size + 3) & ~3; // keep track of size of arguments so // we can translate where tcc thinks they // are on the stack into the appropriate reg TranslateStackToReg[NoOfCurFuncArgs] = size; NoOfCurFuncArgs++;#ifdef FUNC_STRUCT_PARAM_AS_PTR /* structs are passed as pointer */ if ((type->t & VT_BTYPE) == VT_STRUCT) { size = 4; }#endif addr += size; } func_ret_sub = 0; /* pascal type call ? */ if (func_call == FUNC_STDCALL) func_ret_sub = addr - 8; C67_MV(C67_FP, C67_A0); // move FP -> A0 C67_MV(C67_SP, C67_FP); // move SP -> FP // place all the args passed in regs onto the stack loc = 0; for (i = 0; i < NoOfCurFuncArgs; i++) { ParamLocOnStack[i] = loc; // remember where the param is loc += -8; C67_PUSH(TREG_C67_A4 + i * 2); if (TranslateStackToReg[i] == 8) { C67_STW_PTR_PRE_INC(TREG_C67_A4 + i * 2 + 1, C67_SP, 3); // STW r, *+SP[1] (go back and put the other) } } TotalBytesPushedOnStack = -loc; func_sub_sp_offset = ind; // remember where we put the stack instruction C67_ADDK(0, C67_SP); // ADDK.L2 loc,SP (just put zero temporarily) C67_PUSH(C67_A0); C67_PUSH(C67_B3);}/* generate function epilog */void gfunc_epilog(void){ { int local = (-loc + 7) & -8; // stack must stay aligned to 8 bytes for LDDW instr C67_POP(C67_B3); C67_NOP(4); // NOP wait for load C67_IREG_B_REG(0, C67_CREG_ZERO, C67_B3); // B.S2 B3 C67_POP(C67_FP); C67_ADDK(local, C67_SP); // ADDK.L2 loc,SP C67_Adjust_ADDK((int *) (cur_text_section->data + func_sub_sp_offset), -local + TotalBytesPushedOnStack); C67_NOP(3); // NOP }}/* generate a jump to a label */int gjmp(int t){ int ind1 = ind; C67_MVKL(C67_A0, t); //r=reg to load, constant C67_MVKH(C67_A0, t); //r=reg to load, constant C67_IREG_B_REG(0, C67_CREG_ZERO, C67_A0); // [!R] B.S2x A0 C67_NOP(5); return ind1;}/* generate a jump to a fixed address */void gjmp_addr(int a){ Sym *sym; // I guess this routine is used for relative short // local jumps, for now just handle it as the general // case // define a label that will be relocated sym = get_sym_ref(&char_pointer_type, cur_text_section, a, 0); greloc(cur_text_section, sym, ind, R_C60LO16); greloc(cur_text_section, sym, ind + 4, R_C60HI16); gjmp(0); // place a zero there later the symbol will be added to it}/* generate a test. set 'inv' to invert test. Stack entry is popped */int gtst(int inv, int t){ int ind1, n; int v, *p; v = vtop->r & VT_VALMASK; if (v == VT_CMP) { /* fast case : can jump directly since flags are set */ // C67 uses B2 sort of as flags register ind1 = ind; C67_MVKL(C67_A0, t); //r=reg to load, constant C67_MVKH(C67_A0, t); //r=reg to load, constant if (C67_compare_reg != TREG_EAX && // check if not already in a conditional test reg C67_compare_reg != TREG_EDX && C67_compare_reg != TREG_ST0 && C67_compare_reg != C67_B2) { C67_MV(C67_compare_reg, C67_B2); C67_compare_reg = C67_B2; } C67_IREG_B_REG(C67_invert_test ^ inv, C67_compare_reg, C67_A0); // [!R] B.S2x A0 C67_NOP(5); t = ind1; //return where we need to patch } else if (v == VT_JMP || v == VT_JMPI) { /* && or || optimization */ if ((v & 1) == inv) { /* insert vtop->c jump list in t */ p = &vtop->c.i; // I guess the idea is to traverse to the // null at the end of the list and store t // there n = *p; while (n != 0) { p = (int *) (cur_text_section->data + n); // extract 32 bit address from MVKH/MVKL n = ((*p >> 7) & 0xffff); n |= ((*(p + 1) >> 7) & 0xffff) << 16; } *p |= (t & 0xffff) << 7; *(p + 1) |= ((t >> 16) & 0xffff) << 7; t = vtop->c.i; } else { t = gjmp(t); gsym(vtop->c.i); } } else { if (is_float(vtop->type.t)) { vpushi(0); gen_op(TOK_NE); } if ((vtop->r & (VT_VALMASK | VT_LVAL | VT_SYM)) == VT_CONST) { /* constant jmp optimization */ if ((vtop->c.i != 0) != inv) t = gjmp(t); } else { // I think we need to get the value on the stack // into a register, test it, and generate a branch // return the address of the branch, so it can be // later patched v = gv(RC_INT); // get value into a reg ind1 = ind; C67_MVKL(C67_A0, t); //r=reg to load, constant C67_MVKH(C67_A0, t); //r=reg to load, constant if (v != TREG_EAX && // check if not already in a conditional test reg v != TREG_EDX && v != TREG_ST0 && v != C67_B2) { C67_MV(v, C67_B2); v = C67_B2; } C67_IREG_B_REG(inv, v, C67_A0); // [!R] B.S2x A0 C67_NOP(5); t = ind1; //return where we need to patch ind1 = ind; } } vtop--; return t;}/* generate an integer binary operation */void gen_opi(int op){ int r, fr, opc, t; switch (op) { case '+': case TOK_ADDC1: /* add with carry generation */ opc = 0; gen_op8:// C67 can't do const compares, must load into a reg// so just go to gv2 directly - tktk if (op >= TOK_ULT && op <= TOK_GT) gv2(RC_INT_BSIDE, RC_INT); // make sure r (src1) is on the B Side of CPU else gv2(RC_INT, RC_INT); r = vtop[-1].r; fr = vtop[0].r; C67_compare_reg = C67_B2; if (op == TOK_LT) { C67_CMPLT(r, fr, C67_B2); C67_invert_test = false; } else if (op == TOK_GE) { C67_CMPLT(r, fr, C67_B2); C67_invert_test = true; } else if (op == TOK_GT) { C67_CMPGT(r, fr, C67_B2); C67_invert_test = false; } else if (op == TOK_LE) { C67_CMPGT(r, fr, C67_B2); C67_invert_test = true; } else if (op == TOK_EQ) { C67_CMPEQ(r, fr, C67_B2); C67_invert_test = false; } else if (op == TOK_NE) { C67_CMPEQ(r, fr, C67_B2); C67_invert_test = true; } else if (op == TOK_ULT) { C67_CMPLTU(r, fr, C67_B2); C67_invert_test = false; } else if (op == TOK_UGE) { C67_CMPLTU(r, fr, C67_B2); C67_invert_test = true; } else if (op == TOK_UGT) { C67_CMPGTU(r, fr, C67_B2); C67_invert_test = false; } else if (op == TOK_ULE) { C67_CMPGTU(r, fr, C67_B2); C67_invert_test = true; } else if (op == '+') C67_ADD(fr, r); // ADD r,fr,r else if (op == '-') C67_SUB(fr, r); // SUB r,fr,r else if (op == '&') C67_AND(fr, r); // AND r,fr,r else if (op == '|') C67_OR(fr, r); // OR r,fr,r else if (op == '^') C67_XOR(fr, r); // XOR r,fr,r else ALWAYS_ASSERT(FALSE); vtop--; if (op >= TOK_ULT && op <= TOK_GT) { vtop->r = VT_CMP; vtop->c.i = op; } break; case '-': case TOK_SUBC1: /* sub with carry generation */ opc = 5; goto gen_op8; case TOK_ADDC2: /* add with carry use */ opc = 2; goto gen_op8; case TOK_SUBC2: /* sub with carry use */ opc = 3; goto gen_op8; case '&': opc = 4; goto gen_op8; case '^': opc = 6; goto gen_op8; case '|': opc = 1; goto gen_op8; case '*': case TOK_UMULL: gv2(RC_INT, RC_INT); r = vtop[-1].r; fr = vtop[0].r; vtop--; C67_MPYI(fr, r); // 32 bit bultiply fr,r,fr C67_NOP(8); // NOP 8 for worst case break; case TOK_SHL: gv2(RC_INT_BSIDE, RC_INT_BSIDE); // shift amount must be on same side as dst r = vtop[-1].r; fr = vtop[0].r; vtop--; C67_SHL(fr, r); // arithmetic/logical shift break; case TOK_SHR: gv2(RC_INT_BSIDE, RC_INT_BSIDE); // shift amount must be on same side as dst r = vtop[-1].r; fr = vtop[0].r; vtop--; C67_SHRU(fr, r); // logical shift break; case TOK_SAR: gv2(RC_INT_BSIDE, RC_INT_BSIDE); // shift amount must be on same side as dst r = vtop[-1].r; fr = vtop[0].r; vtop--; C67_SHR(fr, r); // arithmetic shift break; case '/'
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -