static void emit_switch(Node *node) { SAVE; char *oswitch = lswitch, *obreak = lbreak; emit_expr(node->switchexpr); lswitch = make_label(); lbreak = make_label(); emit_jmp(lswitch); if (node->switchbody) emit_expr(node->switchbody); emit_label(lswitch); emit_label(lbreak); lswitch = oswitch; lbreak = obreak; }
static void emit_do(Node *node) { SAVE; char *begin = make_label(); char *end = make_label(); SET_JUMP_LABELS(end, begin); emit_label(begin); if (node->forbody) emit_expr(node->forbody); emit_expr(node->forcond); emit_je(end); emit_jmp(begin); emit_label(end); RESTORE_JUMP_LABELS(); }
static void emit_ternary(Node *node) { SAVE; emit_expr(node->cond); char *ne = make_label(); emit_je(ne); if (node->then) emit_expr(node->then); if (node->els) { char *end = make_label(); emit_jmp(end); emit_label(ne); emit_expr(node->els); emit_label(end); } else { emit_label(ne); } }
static void emit_builtin_return_address(Node *node) { push("r11"); assert(vec_len(node->args) == 1); emit_expr(vec_head(node->args)); char *loop = make_label(); char *end = make_label(); emit("mov #rbp, #r11"); emit_label(loop); emit("test #rax, #rax"); emit("jz %s", end); emit("mov (#r11), #r11"); emit("sub $1, #rax"); emit_jmp(loop); emit_label(end); emit("mov 8(#r11), #rax"); pop("r11"); }
static void emit_case(Node *node) { SAVE; if (!lswitch) error("stray case label"); char *skip = make_label(); emit_jmp(skip); emit_label(lswitch); lswitch = make_label(); emit("cmp $%d, %%eax", node->casebeg); if (node->casebeg == node->caseend) { emit("jne %s", lswitch); } else { emit("jl %s", lswitch); emit("cmp $%d, %%eax", node->caseend); emit("jg %s", lswitch); } emit_label(skip); }
static void emit_for(Node *node) { SAVE; if (node->forinit) emit_expr(node->forinit); char *begin = make_label(); char *step = make_label(); char *end = make_label(); SET_JUMP_LABELS(end, step); emit_label(begin); if (node->forcond) { emit_expr(node->forcond); emit_je(end); } if (node->forbody) emit_expr(node->forbody); emit_label(step); if (node->forstep) emit_expr(node->forstep); emit_jmp(begin); emit_label(end); RESTORE_JUMP_LABELS(); }
static void emit_continue(Node *node) { SAVE; if (!lcontinue) error("stray continue statement"); emit_jmp(lcontinue); }
static void emit_break(Node *node) { SAVE; if (!lbreak) error("stray break statement"); emit_jmp(lbreak); }
static void emit_goto(Node *node) { SAVE; assert(node->newlabel); emit_jmp(node->newlabel); }
short *emit_vax_inst(short *inst, oprtype **fst_opr, oprtype **lst_opr) /* fst_opr and lst_opr are triple operands */ { short sav_in; bool oc_int; int4 cnt; oprtype *opr; triple *ct; code_idx = 0; force_32 = 0; switch (cg_phase) { case CGP_ADDR_OPT: case CGP_APPROX_ADDR: case CGP_MACHINE: switch ((sav_in = *inst++)) { case VXI_BEQL: case VXI_BGEQ: case VXI_BGTR: case VXI_BLEQ: case VXI_BLSS: case VXI_BNEQ: case VXI_BRB: case VXI_BRW: emit_jmp(sav_in, &inst); break; case VXI_BLBC: case VXI_BLBS: assert(VXT_REG == *inst); inst++; inst++; emit_xfer(4*xf_dt_get); code_buf[code_idx++] = I386_INS_CMP_eAX_Iv; *((int4 *)&code_buf[code_idx]) = 0; code_idx += SIZEOF(int4); if (sav_in == VXI_BLBC) emit_jmp(VXI_BEQL, &inst); else { assert(sav_in == VXI_BLBS); emit_jmp(VXI_BNEQ, &inst); } break; case VXI_BICB2: case VXI_BISB2: assert(VXT_LIT == *inst); inst++; assert(1 == *inst); inst++; assert(VXT_REG == *inst); inst++; inst++; if (sav_in == VXI_BICB2) emit_xfer(4*xf_dt_false); else { assert(sav_in == VXI_BISB2); emit_xfer(4*xf_dt_true); } break; case VXI_CALLS: oc_int = TRUE; if (VXT_LIT == *inst) { inst++; cnt = (int4) *inst++; } else { assert(VXT_VAL == *inst); inst++; opr = *(fst_opr + *inst); assert(opr->oprclass == TRIP_REF); ct = opr->oprval.tref; if (ct->destination.oprclass) { opr = &ct->destination; } if (opr->oprclass == TRIP_REF) { assert(ct->opcode == OC_ILIT); cnt = ct->operand[0].oprval.ilit; if (cnt >= -128 && cnt <= 127) { code_buf[code_idx++] = I386_INS_PUSH_Ib; code_buf[code_idx++] = cnt & 0xff; } else { code_buf[code_idx++] = I386_INS_PUSH_Iv; *((int4 *)&code_buf[code_idx]) = cnt; code_idx += SIZEOF(int4); } cnt++; inst++; } else { assert(opr->oprclass == TINT_REF); oc_int = FALSE; opr = *(fst_opr + *inst++); emit_trip(PUSH, opr, TRUE, 0); } } assert(VXT_XFER == *inst); inst++; emit_xfer(*inst++); if (oc_int) { if (cnt) { code_buf[code_idx++] = I386_INS_LEA_Gv_M; emit_base_offset(I386_REG_ESP, I386_REG_ESP, 4*cnt); } } else { emit_trip(LOAD, opr, TRUE, I386_REG_EDX); code_buf[code_idx++] = I386_INS_LEA_Gv_M; emit_base_offset(I386_REG_ESP, I386_REG_ESP, 4); } break; case VXI_CLRL: assert(VXT_VAL == *inst); inst++; emit_trip(CLEAR, *(fst_opr + *inst++), TRUE, 0); break; case VXI_CMPL: assert(VXT_VAL == *inst); inst++; emit_trip(LOAD, *(fst_opr + *inst++), TRUE, I386_REG_EDX); assert(VXT_VAL == *inst); inst++; emit_trip(COMPARE, *(fst_opr + *inst++), TRUE, I386_REG_EDX); break; case VXI_INCL: assert(VXT_VAL == *inst); inst++; emit_trip(INCREMENT, *(fst_opr + *inst++), TRUE, 0); break; case VXI_JMP: if (VXT_VAL == *inst) { inst++; emit_trip(JUMP, *(fst_opr + *inst++), FALSE, 0); } else { emit_jmp(sav_in, &inst); } break; case VXI_JSB: assert(VXT_XFER == *inst); inst++; emit_xfer(*inst++); break; case VXI_MOVAB: if (VXT_JMP == *inst) { inst += 2; emit_pcrel(LOAD_ADDRESS, I386_REG_EAX); assert(VXT_ADDR == *inst); inst++; emit_trip(STORE, *(fst_opr + *inst++), FALSE, I386_REG_EAX); } else if ((VXT_ADDR == *inst) || (VXT_VAL == *inst)) { bool addr; unsigned char reg; short save_inst; addr = (VXT_VAL == *inst); inst++; save_inst = *inst++; assert(VXT_REG == *inst); inst++; reg = ((*inst++ & 0x01) ? I386_REG_EDX : I386_REG_EAX); /* r0 and r1 are only ones used */ emit_trip(LOAD_ADDRESS, *(fst_opr + save_inst), addr, reg); } else assertpro(FALSE && *inst); break; case VXI_MOVC3: assert(VXT_LIT == *inst); inst += 2; assert(VXT_VAL == *inst); inst++; code_buf[code_idx++] = I386_INS_PUSH_eSI; code_buf[code_idx++] = I386_INS_PUSH_eDI; emit_trip(LOAD_ADDRESS, *(fst_opr + *inst++), TRUE, I386_REG_ECX); assert(VXT_VAL == *inst); inst++; emit_trip(LOAD_ADDRESS, *(fst_opr + *inst++), TRUE, I386_REG_EDI); code_buf[code_idx++] = I386_INS_MOV_Gv_Ev; modrm_byte.modrm.reg_opcode = I386_REG_ESI; modrm_byte.modrm.mod = I386_MOD32_REGISTER; modrm_byte.modrm.r_m = I386_REG_ECX; code_buf[code_idx++] = modrm_byte.byte; code_buf[code_idx++] = I386_INS_MOV_eCX; *((int4 *)&code_buf[code_idx]) = (int4)SIZEOF(mval); code_idx += SIZEOF(int4); code_buf[code_idx++] = I386_INS_REP_E_Prefix; code_buf[code_idx++] = I386_INS_MOVSB_Xb_Yb; code_buf[code_idx++] = I386_INS_POP_eDI; code_buf[code_idx++] = I386_INS_POP_eSI; break; case VXI_MOVL: if (VXT_REG == *inst) { inst++; if (*inst > 0x5f) /* OC_CURRHD */ /* any mode >= 6 (deferred), any register */ { inst++; assert(VXT_ADDR == *inst); inst++; emit_xfer(4*xf_get_msf); emit_op_base_offset(LOAD, I386_REG_EAX, 0, I386_REG_EAX); emit_trip(STORE, *(fst_opr + *inst++), FALSE, I386_REG_EAX); } else { bool addr; assert(0x50 == *inst); /* register mode: R0 */ inst++; if ((VXT_VAL == *inst) || (VXT_ADDR == *inst)) { addr = (VXT_VAL == *inst); inst++; emit_trip(STORE, *(fst_opr + *inst++), addr, I386_REG_EAX); } else if (VXT_REG == *inst) { unsigned char reg; inst++; if ((*inst & 0x0f) == 10) /* VAX $TEST */ { code_buf[code_idx++] = I386_INS_PUSH_eAX; emit_xfer(4*xf_dt_store); code_buf[code_idx++] = I386_INS_POP_eAX; } else { code_buf[code_idx++] = I386_INS_MOV_Ev_Gv; modrm_byte.modrm.reg_opcode = I386_REG_EAX; modrm_byte.modrm.mod = I386_MOD32_REGISTER; modrm_byte.modrm.r_m = i386_reg(*inst); code_buf[code_idx++] = modrm_byte.byte; } inst++; } else assertpro(FALSE && *inst); } } else if (VXT_VAL == *inst) { inst++; emit_trip(LOAD, *(fst_opr + *inst++), TRUE, I386_REG_EDX); assert(VXT_REG == *inst); inst++; assert(0x51 == *inst); /* register mode: R1 */ inst++; } else assertpro(FALSE && *inst); break; case VXT_IREPAB: assert(VXT_VAL == *inst); inst += 2; emit_trip(PUSH_ADDRESS, *lst_opr, TRUE, 0); break; case VXI_PUSHAB: if (VXT_JMP == *inst) { inst += 2; emit_pcrel(PUSH_ADDRESS, 0); } else if (VXT_VAL == *inst) { inst++; emit_trip(PUSH_ADDRESS, *(fst_opr + *inst++), TRUE, 0); } else assertpro(FALSE && *inst); break; case VXT_IREPL: assert(VXT_VAL == *inst); inst += 2; emit_trip(PUSH, *lst_opr, TRUE, 0); break; case VXI_PUSHL: if (VXT_LIT == *inst) { int4 lit; inst++; lit = *inst++; if (lit >= -128 && lit <= 127) { code_buf[code_idx++] = I386_INS_PUSH_Ib; code_buf[code_idx++] = lit & 0xff; } else { code_buf[code_idx++] = I386_INS_PUSH_Iv; *((int4 *)&code_buf[code_idx]) = lit; code_idx += SIZEOF(int4); } } else if (VXT_ADDR == *inst) { inst++; emit_trip(PUSH, *(fst_opr + *inst++), FALSE, 0); } else if (VXT_VAL == *inst) { inst++; emit_trip(PUSH, *(fst_opr + *inst++), TRUE, 0); } else assertpro(FALSE && *inst); break; case VXI_TSTL: if (VXT_VAL == *inst) { inst++; emit_trip(TEST, *(fst_opr + *inst++), TRUE, 0); } else if (VXT_REG == *inst) { inst++; code_buf[code_idx++] = I386_INS_CMP_eAX_Iv; assert(I386_REG_EAX == i386_reg(*inst)); /* VAX R0 */ inst++; *((int4 *)&code_buf[code_idx]) = 0; /* 32 bit immediate 0 */ code_idx += SIZEOF(int4); } else assertpro(FALSE && *inst); break; default: assertpro(FALSE && sav_in); } break; default: assertpro(FALSE && cg_phase); break; } assert(code_idx < BUFFERED_CODE_SIZE); if (cg_phase == CGP_MACHINE) { generated_code_size += code_idx; emit_immed ((char *)&code_buf[0], SIZEOF(unsigned char) * code_idx); } else if (cg_phase != CGP_ASSEMBLY) { if (cg_phase == CGP_APPROX_ADDR) { calculated_code_size += code_idx; } curr_addr += SIZEOF(unsigned char) * code_idx; } code_reference += SIZEOF(unsigned char) * code_idx; jmp_offset -= SIZEOF(unsigned char) * code_idx; return inst; }