📄 dt_cg.c
字号:
longjmp(yypcb->pcb_jmpbuf, EDT_NOREG); if (dstsize < srcsize) n = sizeof (uint64_t) * NBBY - dstsize * NBBY; else n = sizeof (uint64_t) * NBBY - srcsize * NBBY; dt_cg_setx(dlp, reg, n); instr = DIF_INSTR_FMT(DIF_OP_SLL, src->dn_reg, reg, dst->dn_reg); dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr)); instr = DIF_INSTR_FMT((dst->dn_flags & DT_NF_SIGNED) ? DIF_OP_SRA : DIF_OP_SRL, dst->dn_reg, reg, dst->dn_reg); dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr)); dt_regset_free(drp, reg); }}/* * Generate code to push the specified argument list on to the tuple stack. * We use this routine for handling subroutine calls and associative arrays. * We must first generate code for all subexpressions before loading the stack * because any subexpression could itself require the use of the tuple stack. * This holds a number of registers equal to the number of arguments, but this * is not a huge problem because the number of arguments can't exceed the * number of tuple register stack elements anyway. At most one extra register * is required (either by dt_cg_typecast() or for dtdt_size, below). This * implies that a DIF implementation should offer a number of general purpose * registers at least one greater than the number of tuple registers. */static voiddt_cg_arglist(dt_ident_t *idp, dt_node_t *args, dt_irlist_t *dlp, dt_regset_t *drp){ const dt_idsig_t *isp = idp->di_data; dt_node_t *dnp; int i = 0; for (dnp = args; dnp != NULL; dnp = dnp->dn_list) dt_cg_node(dnp, dlp, drp); dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, DIF_INSTR_FLUSHTS)); for (dnp = args; dnp != NULL; dnp = dnp->dn_list, i++) { dtrace_diftype_t t; dif_instr_t instr; uint_t op; int reg; dt_node_diftype(dnp, &t); isp->dis_args[i].dn_reg = dnp->dn_reg; /* re-use register */ dt_cg_typecast(dnp, &isp->dis_args[i], dlp, drp); isp->dis_args[i].dn_reg = -1; if (t.dtdt_flags & DIF_TF_BYREF) op = DIF_OP_PUSHTR; else op = DIF_OP_PUSHTV; if (t.dtdt_size != 0) { if ((reg = dt_regset_alloc(drp)) == -1) longjmp(yypcb->pcb_jmpbuf, EDT_NOREG); dt_cg_setx(dlp, reg, t.dtdt_size); } else reg = DIF_REG_R0; instr = DIF_INSTR_PUSHTS(op, t.dtdt_kind, reg, dnp->dn_reg); dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr)); dt_regset_free(drp, dnp->dn_reg); if (reg != DIF_REG_R0) dt_regset_free(drp, reg); } if (i > yypcb->pcb_hdl->dt_conf.dtc_diftupregs) longjmp(yypcb->pcb_jmpbuf, EDT_NOTUPREG);}static voiddt_cg_arithmetic_op(dt_node_t *dnp, dt_irlist_t *dlp, dt_regset_t *drp, uint_t op){ int is_ptr_op = (dnp->dn_op == DT_TOK_ADD || dnp->dn_op == DT_TOK_SUB || dnp->dn_op == DT_TOK_ADD_EQ || dnp->dn_op == DT_TOK_SUB_EQ); int lp_is_ptr = dt_node_is_pointer(dnp->dn_left); int rp_is_ptr = dt_node_is_pointer(dnp->dn_right); dif_instr_t instr; if (lp_is_ptr && rp_is_ptr) { assert(dnp->dn_op == DT_TOK_SUB); is_ptr_op = 0; } dt_cg_node(dnp->dn_left, dlp, drp); if (is_ptr_op && rp_is_ptr) dt_cg_ptrsize(dnp, dlp, drp, DIF_OP_MUL, dnp->dn_left->dn_reg); dt_cg_node(dnp->dn_right, dlp, drp); if (is_ptr_op && lp_is_ptr) dt_cg_ptrsize(dnp, dlp, drp, DIF_OP_MUL, dnp->dn_right->dn_reg); instr = DIF_INSTR_FMT(op, dnp->dn_left->dn_reg, dnp->dn_right->dn_reg, dnp->dn_left->dn_reg); dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr)); dt_regset_free(drp, dnp->dn_right->dn_reg); dnp->dn_reg = dnp->dn_left->dn_reg; if (lp_is_ptr && rp_is_ptr) dt_cg_ptrsize(dnp->dn_right, dlp, drp, DIF_OP_UDIV, dnp->dn_reg);}static uint_tdt_cg_stvar(const dt_ident_t *idp){ static const uint_t aops[] = { DIF_OP_STGAA, DIF_OP_STTAA, DIF_OP_NOP }; static const uint_t sops[] = { DIF_OP_STGS, DIF_OP_STTS, DIF_OP_STLS }; uint_t i = (((idp->di_flags & DT_IDFLG_LOCAL) != 0) << 1) | ((idp->di_flags & DT_IDFLG_TLS) != 0); return (idp->di_kind == DT_IDENT_ARRAY ? aops[i] : sops[i]);}static voiddt_cg_prearith_op(dt_node_t *dnp, dt_irlist_t *dlp, dt_regset_t *drp, uint_t op){ ctf_file_t *ctfp = dnp->dn_ctfp; dif_instr_t instr; ctf_id_t type; ssize_t size = 1; int reg; if (dt_node_is_pointer(dnp)) { type = ctf_type_resolve(ctfp, dnp->dn_type); assert(ctf_type_kind(ctfp, type) == CTF_K_POINTER); size = ctf_type_size(ctfp, ctf_type_reference(ctfp, type)); } dt_cg_node(dnp->dn_child, dlp, drp); dnp->dn_reg = dnp->dn_child->dn_reg; if ((reg = dt_regset_alloc(drp)) == -1) longjmp(yypcb->pcb_jmpbuf, EDT_NOREG); dt_cg_setx(dlp, reg, size); instr = DIF_INSTR_FMT(op, dnp->dn_reg, reg, dnp->dn_reg); dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr)); dt_regset_free(drp, reg); /* * If we are modifying a variable, generate an stv instruction from * the variable specified by the identifier. If we are storing to a * memory address, generate code again for the left-hand side using * DT_NF_REF to get the address, and then generate a store to it. * In both paths, we store the value in dnp->dn_reg (the new value). */ if (dnp->dn_child->dn_kind == DT_NODE_VAR) { dt_ident_t *idp = dt_ident_resolve(dnp->dn_child->dn_ident); idp->di_flags |= DT_IDFLG_DIFW; instr = DIF_INSTR_STV(dt_cg_stvar(idp), idp->di_id, dnp->dn_reg); dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr)); } else { uint_t rbit = dnp->dn_child->dn_flags & DT_NF_REF; assert(dnp->dn_child->dn_flags & DT_NF_WRITABLE); assert(dnp->dn_child->dn_flags & DT_NF_LVALUE); dnp->dn_child->dn_flags |= DT_NF_REF; /* force pass-by-ref */ dt_cg_node(dnp->dn_child, dlp, drp); dt_cg_store(dnp, dlp, drp, dnp->dn_child); dt_regset_free(drp, dnp->dn_child->dn_reg); dnp->dn_left->dn_flags &= ~DT_NF_REF; dnp->dn_left->dn_flags |= rbit; }}static voiddt_cg_postarith_op(dt_node_t *dnp, dt_irlist_t *dlp, dt_regset_t *drp, uint_t op){ ctf_file_t *ctfp = dnp->dn_ctfp; dif_instr_t instr; ctf_id_t type; ssize_t size = 1; int nreg; if (dt_node_is_pointer(dnp)) { type = ctf_type_resolve(ctfp, dnp->dn_type); assert(ctf_type_kind(ctfp, type) == CTF_K_POINTER); size = ctf_type_size(ctfp, ctf_type_reference(ctfp, type)); } dt_cg_node(dnp->dn_child, dlp, drp); dnp->dn_reg = dnp->dn_child->dn_reg; if ((nreg = dt_regset_alloc(drp)) == -1) longjmp(yypcb->pcb_jmpbuf, EDT_NOREG); dt_cg_setx(dlp, nreg, size); instr = DIF_INSTR_FMT(op, dnp->dn_reg, nreg, nreg); dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr)); /* * If we are modifying a variable, generate an stv instruction from * the variable specified by the identifier. If we are storing to a * memory address, generate code again for the left-hand side using * DT_NF_REF to get the address, and then generate a store to it. * In both paths, we store the value from 'nreg' (the new value). */ if (dnp->dn_child->dn_kind == DT_NODE_VAR) { dt_ident_t *idp = dt_ident_resolve(dnp->dn_child->dn_ident); idp->di_flags |= DT_IDFLG_DIFW; instr = DIF_INSTR_STV(dt_cg_stvar(idp), idp->di_id, nreg); dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr)); } else { uint_t rbit = dnp->dn_child->dn_flags & DT_NF_REF; int oreg = dnp->dn_reg; assert(dnp->dn_child->dn_flags & DT_NF_WRITABLE); assert(dnp->dn_child->dn_flags & DT_NF_LVALUE); dnp->dn_child->dn_flags |= DT_NF_REF; /* force pass-by-ref */ dt_cg_node(dnp->dn_child, dlp, drp); dnp->dn_reg = nreg; dt_cg_store(dnp, dlp, drp, dnp->dn_child); dnp->dn_reg = oreg; dt_regset_free(drp, dnp->dn_child->dn_reg); dnp->dn_left->dn_flags &= ~DT_NF_REF; dnp->dn_left->dn_flags |= rbit; } dt_regset_free(drp, nreg);}/* * Determine if we should perform signed or unsigned comparison for an OP2. * If both operands are of arithmetic type, perform the usual arithmetic * conversions to determine the common real type for comparison [ISOC 6.5.8.3]. */static intdt_cg_compare_signed(dt_node_t *dnp){ dt_node_t dn; if (dt_node_is_string(dnp->dn_left) || dt_node_is_string(dnp->dn_right)) return (1); /* strings always compare signed */ else if (!dt_node_is_arith(dnp->dn_left) || !dt_node_is_arith(dnp->dn_right)) return (0); /* non-arithmetic types always compare unsigned */ bzero(&dn, sizeof (dn)); dt_node_promote(dnp->dn_left, dnp->dn_right, &dn); return (dn.dn_flags & DT_NF_SIGNED);}static voiddt_cg_compare_op(dt_node_t *dnp, dt_irlist_t *dlp, dt_regset_t *drp, uint_t op){ uint_t lbl_true = dt_irlist_label(dlp); uint_t lbl_post = dt_irlist_label(dlp); dif_instr_t instr; uint_t opc; dt_cg_node(dnp->dn_left, dlp, drp); dt_cg_node(dnp->dn_right, dlp, drp); if (dt_node_is_string(dnp->dn_left) || dt_node_is_string(dnp->dn_right)) opc = DIF_OP_SCMP; else opc = DIF_OP_CMP; instr = DIF_INSTR_CMP(opc, dnp->dn_left->dn_reg, dnp->dn_right->dn_reg); dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr)); dt_regset_free(drp, dnp->dn_right->dn_reg); dnp->dn_reg = dnp->dn_left->dn_reg; instr = DIF_INSTR_BRANCH(op, lbl_true); dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr)); instr = DIF_INSTR_MOV(DIF_REG_R0, dnp->dn_reg); dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr)); instr = DIF_INSTR_BRANCH(DIF_OP_BA, lbl_post); dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr)); dt_cg_xsetx(dlp, NULL, lbl_true, dnp->dn_reg, 1); dt_irlist_append(dlp, dt_cg_node_alloc(lbl_post, DIF_INSTR_NOP));}/* * Code generation for the ternary op requires some trickery with the assembler * in order to conserve registers. We generate code for dn_expr and dn_left * and free their registers so they do not have be consumed across codegen for * dn_right. We insert a dummy MOV at the end of dn_left into the destination * register, which is not yet known because we haven't done dn_right yet, and * save the pointer to this instruction node. We then generate code for * dn_right and use its register as our output. Finally, we reach back and * patch the instruction for dn_left to move its output into this register. */static voiddt_cg_ternary_op(dt_node_t *dnp, dt_irlist_t *dlp, dt_regset_t *drp){ uint_t lbl_false = dt_irlist_label(dlp); uint_t lbl_post = dt_irlist_label(dlp); dif_instr_t instr; dt_irnode_t *dip; dt_cg_node(dnp->dn_expr, dlp, drp); instr = DIF_INSTR_TST(dnp->dn_expr->dn_reg); dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr)); dt_regset_free(drp, dnp->dn_expr->dn_reg); instr = DIF_INSTR_BRANCH(DIF_OP_BE, lbl_false); dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr)); dt_cg_node(dnp->dn_left, dlp, drp); instr = DIF_INSTR_MOV(dnp->dn_left->dn_reg, DIF_REG_R0); dip = dt_cg_node_alloc(DT_LBL_NONE, instr); /* save dip for below */ dt_irlist_append(dlp, dip); dt_regset_free(drp, dnp->dn_left->dn_reg); instr = DIF_INSTR_BRANCH(DIF_OP_BA, lbl_post); dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr)); dt_irlist_append(dlp, dt_cg_node_alloc(lbl_false, DIF_INSTR_NOP)); dt_cg_node(dnp->dn_right, dlp, drp); dnp->dn_reg = dnp->dn_right->dn_reg; /* * Now that dn_reg is assigned, reach back and patch the correct MOV * instruction into the tail of dn_left. We know dn_reg was unused * at that point because otherwise dn_right couldn't have allocated it. */ dip->di_instr = DIF_INSTR_MOV(dnp->dn_left->dn_reg, dnp->dn_reg); dt_irlist_append(dlp, dt_cg_node_alloc(lbl_post, DIF_INSTR_NOP));}static voiddt_cg_logical_and(dt_node_t *dnp, dt_irlist_t *dlp, dt_regset_t *drp){ uint_t lbl_false = dt_irlist_label(dlp); uint_t lbl_post = dt_irlist_label(dlp); dif_instr_t instr; dt_cg_node(dnp->dn_left, dlp, drp); instr = DIF_INSTR_TST(dnp->dn_left->dn_reg); dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr)); dt_regset_free(drp, dnp->dn_left->dn_reg); instr = DIF_INSTR_BRANCH(DIF_OP_BE, lbl_false); dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr)); dt_cg_node(dnp->dn_right, dlp, drp); instr = DIF_INSTR_TST(dnp->dn_right->dn_reg); dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr)); dnp->dn_reg = dnp->dn_right->dn_reg; instr = DIF_INSTR_BRANCH(DIF_OP_BE, lbl_false); dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr)); dt_cg_setx(dlp, dnp->dn_reg, 1); instr = DIF_INSTR_BRANCH(DIF_OP_BA, lbl_post); dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr)); instr = DIF_INSTR_MOV(DIF_REG_R0, dnp->dn_reg); dt_irlist_append(dlp, dt_cg_node_alloc(lbl_false, instr)); dt_irlist_append(dlp, dt_cg_node_alloc(lbl_post, DIF_INSTR_NOP));}static voiddt_cg_logical_xor(dt_node_t *dnp, dt_irlist_t *dlp, dt_regset_t *drp){ uint_t lbl_next = dt_irlist_label(dlp); uint_t lbl_tail = dt_irlist_label(dlp); dif_instr_t instr; dt_cg_node(dnp->dn_left, dlp, drp); instr = DIF_INSTR_TST(dnp->dn_left->dn_reg); dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr)); instr = DIF_INSTR_BRANCH(DIF_OP_BE, lbl_next); dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr)); dt_cg_setx(dlp, dnp->dn_left->dn_reg, 1); dt_irlist_append(dlp, dt_cg_node_alloc(lbl_next, DIF_INSTR_NOP)); dt_cg_node(dnp->dn_right, dlp, drp); instr = DIF_INSTR_TST(dnp->dn_right->dn_reg); dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr)); instr = DIF_INSTR_BRANCH(DIF_OP_BE, lbl_tail); dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr)); dt_cg_setx(dlp, dnp->dn_right->dn_reg, 1); instr = DIF_INSTR_FMT(DIF_OP_XOR, dnp->dn_left->dn_reg, dnp->dn_right->dn_reg, dnp->dn_left->dn_reg); dt_irlist_append(dlp, dt_cg_node_alloc(lbl_tail, instr)); dt_regset_free(drp, dnp->dn_right->dn_reg); dnp->dn_reg = dnp->dn_left->dn_reg;}static voiddt_cg_logical_or(dt_node_t *dnp, dt_irlist_t *dlp, dt_regset_t *drp){ uint_t lbl_true = dt_irlist_label(dlp); uint_t lbl_false = dt_irlist_label(dlp); uint_t lbl_post = dt_irlist_label(dlp); dif_instr_t instr; dt_cg_node(dnp->dn_left, dlp, drp); instr = DIF_INSTR_TST(dnp->dn_left->dn_reg); dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr)); dt_regset_free(drp, dnp->dn_left->dn_reg); instr = DIF_INSTR_BRANCH(DIF_OP_BNE, lbl_true); dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr)); dt_cg_node(dnp->dn_right, dlp, drp); instr = DIF_INSTR_TST(dnp->dn_right->dn_reg); dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr)); dnp->dn_reg = dnp->dn_right->dn_reg; instr = DIF_INSTR_BRANCH(DIF_OP_BE, lbl_false); dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr)); dt_cg_xsetx(dlp, NULL, lbl_true, dnp->dn_reg, 1); instr = DIF_INSTR_BRANCH(DIF_OP_BA, lbl_post); dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr)); instr = DIF_INSTR_MOV(DIF_REG_R0, dnp->dn_reg); dt_irlist_append(dlp, dt_cg_node_alloc(lbl_false, instr)); dt_irlist_append(dlp, dt_cg_node_alloc(lbl_post, DIF_INSTR_NOP));}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -