📄 dt_cg.c
字号:
static voiddt_cg_logical_neg(dt_node_t *dnp, dt_irlist_t *dlp, dt_regset_t *drp){ uint_t lbl_zero = dt_irlist_label(dlp); uint_t lbl_post = dt_irlist_label(dlp); dif_instr_t instr; dt_cg_node(dnp->dn_child, dlp, drp); dnp->dn_reg = dnp->dn_child->dn_reg; instr = DIF_INSTR_TST(dnp->dn_reg); dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr)); instr = DIF_INSTR_BRANCH(DIF_OP_BE, lbl_zero); 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_zero, dnp->dn_reg, 1); dt_irlist_append(dlp, dt_cg_node_alloc(lbl_post, DIF_INSTR_NOP));}static voiddt_cg_asgn_op(dt_node_t *dnp, dt_irlist_t *dlp, dt_regset_t *drp){ dif_instr_t instr; /* * If we are performing a structure assignment of a translated type, * we must instantiate all members and create a snapshot of the object * in scratch space. We allocs a chunk of memory, generate code for * each member, and then set dnp->dn_reg to the scratch object address. */ if (dt_node_is_dynamic(dnp->dn_right) && dnp->dn_right->dn_ident->di_kind == DT_IDENT_XLSOU) { ctf_membinfo_t ctm; dt_xlator_t *dxp; dt_node_t *mnp, dn, mn; int r1, r2; /* * Create two fake dt_node_t's representing operator "." and a * right-hand identifier child node. These will be repeatedly * modified according to each instantiated member so that we * can pass them to dt_cg_store() and effect a member store. */ bzero(&dn, sizeof (dt_node_t)); dn.dn_kind = DT_NODE_OP2; dn.dn_op = DT_TOK_DOT; dn.dn_left = dnp; dn.dn_right = &mn; bzero(&mn, sizeof (dt_node_t)); mn.dn_kind = DT_NODE_IDENT; mn.dn_op = DT_TOK_IDENT; /* * Allocate a register for our scratch data pointer. First we * set it to the size of our data structure, and then replace * it with the result of an allocs of the specified size. */ if ((r1 = dt_regset_alloc(drp)) == -1) longjmp(yypcb->pcb_jmpbuf, EDT_NOREG); dxp = dt_ident_resolve(dnp->dn_right->dn_ident)->di_data; dt_cg_setx(dlp, r1, ctf_type_size(dxp->dx_dst_ctfp, dxp->dx_dst_base)); instr = DIF_INSTR_ALLOCS(r1, r1); dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr)); /* * When dt_cg_asgn_op() is called, we have already generated * code for dnp->dn_right, which is the translator input. We * now associate this register with the translator's input * identifier so it can be referenced during our member loop. */ dxp->dx_ident->di_flags |= DT_IDFLG_CGREG; dxp->dx_ident->di_id = dnp->dn_right->dn_reg; for (mnp = dxp->dx_members; mnp != NULL; mnp = mnp->dn_list) { /* * Generate code for the translator member expression, * and then cast the result to the member type. */ dt_cg_node(mnp->dn_membexpr, dlp, drp); mnp->dn_reg = mnp->dn_membexpr->dn_reg; dt_cg_typecast(mnp->dn_membexpr, mnp, dlp, drp); /* * Ask CTF for the offset of the member so we can store * to the appropriate offset. This call has already * been done once by the parser, so it should succeed. */ if (ctf_member_info(dxp->dx_dst_ctfp, dxp->dx_dst_base, mnp->dn_membname, &ctm) == CTF_ERR) { yypcb->pcb_hdl->dt_ctferr = ctf_errno(dxp->dx_dst_ctfp); longjmp(yypcb->pcb_jmpbuf, EDT_CTF); } /* * If the destination member is at offset 0, store the * result directly to r1 (the scratch buffer address). * Otherwise allocate another temporary for the offset * and add r1 to it before storing the result. */ if (ctm.ctm_offset != 0) { if ((r2 = dt_regset_alloc(drp)) == -1) longjmp(yypcb->pcb_jmpbuf, EDT_NOREG); /* * Add the member offset rounded down to the * nearest byte. If the offset was not aligned * on a byte boundary, this member is a bit- * field and dt_cg_store() will handle masking. */ dt_cg_setx(dlp, r2, ctm.ctm_offset / NBBY); instr = DIF_INSTR_FMT(DIF_OP_ADD, r1, r2, r2); dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr)); dt_node_type_propagate(mnp, &dn); dn.dn_right->dn_string = mnp->dn_membname; dn.dn_reg = r2; dt_cg_store(mnp, dlp, drp, &dn); dt_regset_free(drp, r2); } else { dt_node_type_propagate(mnp, &dn); dn.dn_right->dn_string = mnp->dn_membname; dn.dn_reg = r1; dt_cg_store(mnp, dlp, drp, &dn); } dt_regset_free(drp, mnp->dn_reg); } dxp->dx_ident->di_flags &= ~DT_IDFLG_CGREG; dxp->dx_ident->di_id = 0; assert(dnp->dn_reg == dnp->dn_right->dn_reg); dt_regset_free(drp, dnp->dn_right->dn_reg); dnp->dn_reg = r1; } /* * If we are storing to 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 assume dnp->dn_reg already has the new value. */ if (dnp->dn_left->dn_kind == DT_NODE_VAR) { dt_ident_t *idp = dt_ident_resolve(dnp->dn_left->dn_ident); if (idp->di_kind == DT_IDENT_ARRAY) dt_cg_arglist(idp, dnp->dn_left->dn_args, dlp, drp); 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_left->dn_flags & DT_NF_REF; assert(dnp->dn_left->dn_flags & DT_NF_WRITABLE); assert(dnp->dn_left->dn_flags & DT_NF_LVALUE); dnp->dn_left->dn_flags |= DT_NF_REF; /* force pass-by-ref */ dt_cg_node(dnp->dn_left, dlp, drp); dt_cg_store(dnp, dlp, drp, dnp->dn_left); dt_regset_free(drp, dnp->dn_left->dn_reg); dnp->dn_left->dn_flags &= ~DT_NF_REF; dnp->dn_left->dn_flags |= rbit; }}static voiddt_cg_assoc_op(dt_node_t *dnp, dt_irlist_t *dlp, dt_regset_t *drp){ dif_instr_t instr; uint_t op; assert(dnp->dn_kind == DT_NODE_VAR); assert(!(dnp->dn_ident->di_flags & DT_IDFLG_LOCAL)); assert(dnp->dn_args != NULL); dt_cg_arglist(dnp->dn_ident, dnp->dn_args, dlp, drp); if ((dnp->dn_reg = dt_regset_alloc(drp)) == -1) longjmp(yypcb->pcb_jmpbuf, EDT_NOREG); if (dnp->dn_ident->di_flags & DT_IDFLG_TLS) op = DIF_OP_LDTAA; else op = DIF_OP_LDGAA; dnp->dn_ident->di_flags |= DT_IDFLG_DIFR; instr = DIF_INSTR_LDV(op, dnp->dn_ident->di_id, dnp->dn_reg); dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr)); /* * If the associative array is a pass-by-reference type, then we are * loading its value as a pointer to either load or store through it. * The array element in question may not have been faulted in yet, in * which case DIF_OP_LD*AA will return zero. We append an epilogue * of instructions similar to the following: * * ld?aa id, %r1 ! base ld?aa instruction above * tst %r1 ! start of epilogue * +--- bne label * | setx size, %r1 * | allocs %r1, %r1 * | st?aa id, %r1 * | ld?aa id, %r1 * v * label: < rest of code > * * The idea is that we allocs a zero-filled chunk of scratch space and * do a DIF_OP_ST*AA to fault in and initialize the array element, and * then reload it to get the faulted-in address of the new variable * storage. This isn't cheap, but pass-by-ref associative array values * are (thus far) uncommon and the allocs cost only occurs once. If * this path becomes important to DTrace users, we can improve things * by adding a new DIF opcode to fault in associative array elements. */ if (dnp->dn_flags & DT_NF_REF) { uint_t stvop = op == DIF_OP_LDTAA ? DIF_OP_STTAA : DIF_OP_STGAA; uint_t label = dt_irlist_label(dlp); instr = DIF_INSTR_TST(dnp->dn_reg); dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr)); instr = DIF_INSTR_BRANCH(DIF_OP_BNE, label); dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr)); dt_cg_setx(dlp, dnp->dn_reg, dt_node_type_size(dnp)); instr = DIF_INSTR_ALLOCS(dnp->dn_reg, dnp->dn_reg); dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr)); dnp->dn_ident->di_flags |= DT_IDFLG_DIFW; instr = DIF_INSTR_STV(stvop, dnp->dn_ident->di_id, dnp->dn_reg); dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr)); instr = DIF_INSTR_LDV(op, dnp->dn_ident->di_id, dnp->dn_reg); dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr)); dt_irlist_append(dlp, dt_cg_node_alloc(label, DIF_INSTR_NOP)); }}static voiddt_cg_array_op(dt_node_t *dnp, dt_irlist_t *dlp, dt_regset_t *drp){ dif_instr_t instr; uint_t op; uintmax_t saved = dnp->dn_args->dn_value; dt_arg_t *argp; size_t size; int reg, n; assert(dnp->dn_kind == DT_NODE_VAR); assert(!(dnp->dn_ident->di_flags & DT_IDFLG_LOCAL)); assert(dnp->dn_args != NULL); assert(dnp->dn_args->dn_kind == DT_NODE_INT); assert(dnp->dn_args->dn_list == NULL); /* * If this is a reference in the args[] array, we're going to examine * our context to see if the value needs to be modified for the * purposes of remapping. */ if (dnp->dn_ident->di_id == DIF_VAR_ARGS) { for (argp = yypcb->pcb_pargs; argp != NULL; argp = argp->da_next) { if (argp->da_ndx == saved) { dnp->dn_args->dn_value = argp->da_mapping; break; } } } dt_cg_node(dnp->dn_args, dlp, drp); dnp->dn_args->dn_value = saved; dnp->dn_reg = dnp->dn_args->dn_reg; if (dnp->dn_ident->di_flags & DT_IDFLG_TLS) op = DIF_OP_LDTA; else op = DIF_OP_LDGA; dnp->dn_ident->di_flags |= DT_IDFLG_DIFR; instr = DIF_INSTR_LDA(op, dnp->dn_ident->di_id, dnp->dn_args->dn_reg, dnp->dn_reg); dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr)); /* * If this is a reference to the args[] array, we need to take the * additional step of explicitly eliminating any bits larger than the * type size: the DIF interpreter in the kernel will always give us * the raw (64-bit) argument value, and any bits larger than the type * size may be junk. As a practical matter, this arises only on * 64-bit architectures and only when the argument index is larger * than the number of arguments passed directly to DTrace: if a 8-, * 16- or 32-bit argument must be retrieved from the stack, it is * possible (and it some cases, likely) that the upper bits will be * garbage. */ if (dnp->dn_ident->di_id != DIF_VAR_ARGS || !dt_node_is_scalar(dnp)) return; if ((size = dt_node_type_size(dnp)) == sizeof (uint64_t)) return; if ((reg = dt_regset_alloc(drp)) == -1) longjmp(yypcb->pcb_jmpbuf, EDT_NOREG); assert(size < sizeof (uint64_t)); n = sizeof (uint64_t) * NBBY - size * NBBY; dt_cg_setx(dlp, reg, n); instr = DIF_INSTR_FMT(DIF_OP_SLL, dnp->dn_reg, reg, dnp->dn_reg); dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr)); instr = DIF_INSTR_FMT((dnp->dn_flags & DT_NF_SIGNED) ? DIF_OP_SRA : DIF_OP_SRL, dnp->dn_reg, reg, dnp->dn_reg); dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr)); dt_regset_free(drp, reg);}static voiddt_cg_node(dt_node_t *dnp, dt_irlist_t *dlp, dt_regset_t *drp){ ctf_file_t *ctfp = dnp->dn_ctfp; ctf_file_t *octfp; ctf_membinfo_t m; ctf_id_t type; dif_instr_t instr; ssize_t stroff; uint_t op; int reg; switch (dnp->dn_op) { case DT_TOK_COMMA: dt_cg_node(dnp->dn_left, dlp, drp); dt_regset_free(drp, dnp->dn_left->dn_reg); dt_cg_node(dnp->dn_right, dlp, drp); dnp->dn_reg = dnp->dn_right->dn_reg; break; case DT_TOK_ASGN: dt_cg_node(dnp->dn_right, dlp, drp); dnp->dn_reg = dnp->dn_right->dn_reg; dt_cg_asgn_op(dnp, dlp, drp); break; case DT_TOK_ADD_EQ: dt_cg_arithmetic_op(dnp, dlp, drp, DIF_OP_ADD); dt_cg_asgn_op(dnp, dlp, drp); break; case DT_TOK_SUB_EQ: dt_cg_arithmetic_op(dnp, dlp, drp, DIF_OP_SUB); dt_cg_asgn_op(dnp, dlp, drp); break; case DT_TOK_MUL_EQ: dt_cg_arithmetic_op(dnp, dlp, drp, DIF_OP_MUL); dt_cg_asgn_op(dnp, dlp, drp); break; case DT_TOK_DIV_EQ: dt_cg_arithmetic_op(dnp, dlp, drp, (dnp->dn_flags & DT_NF_SIGNED) ? DIF_OP_SDIV : DIF_OP_UDIV); dt_cg_asgn_op(dnp, dlp, drp); break; case DT_TOK_MOD_EQ: dt_cg_arithmetic_op(dnp, dlp, drp, (dnp->dn_flags & DT_NF_SIGNED) ? DIF_OP_SREM : DIF_OP_UREM); dt_cg_asgn_op(dnp, dlp, drp); break; case DT_TOK_AND_EQ: dt_cg_arithmetic_op(dnp, dlp, drp, DIF_OP_AND); dt_cg_asgn_op(dnp, dlp, drp); break; case DT_TOK_XOR_EQ: dt_cg_arithmetic_op(dnp, dlp, drp, DIF_OP_XOR); dt_cg_asgn_op(dnp, dlp, drp); break; case DT_TOK_OR_EQ: dt_cg_arithmetic_op(dnp, dlp, drp, DIF_OP_OR); dt_cg_asgn_op(dnp, dlp, drp); break; case DT_TOK_LSH_EQ: dt_cg_arithmetic_op(dnp, dlp, drp, DIF_OP_SLL); dt_cg_asgn_op(dnp, dlp, drp); break; case DT_TOK_RSH_EQ: dt_cg_arithmetic_op(dnp, dlp, drp, (dnp->dn_flags & DT_NF_SIGNED) ? DIF_OP_SRA : DIF_OP_SRL); dt_cg_asgn_op(dnp, dlp, drp); break; case DT_TOK_QUESTION: dt_cg_ternary_op(dnp, dlp, drp); break; case DT_TOK_LOR: dt_cg_logical_or(dnp, dlp, drp); break; case DT_TOK_LXOR: dt_cg_logical_xor(dnp, dlp, drp); break; case DT_TOK_LAND: dt_cg_logical_and(dnp, dlp, drp); break; case DT_TOK_BOR: dt_cg_arithmetic_op(dnp, dlp, drp, DIF_OP_OR); break; case DT_TOK_XOR: dt_cg_arithmetic_op(dnp, dlp, drp, DIF_OP_XOR); break; case DT_TOK_BAND: dt_cg_arithmetic_op(dnp, dlp, drp, DIF_OP_AND); break; case DT_TOK_EQU: dt_cg_compare_op(dnp, dlp, drp, DIF_OP_BE); break; case DT_TOK_NEQ: dt_cg_compare_op(dnp, dlp, drp, DIF_OP_BNE); break; case DT_TOK_LT:
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -