1*0Sstevel@tonic-gate /* 2*0Sstevel@tonic-gate * CDDL HEADER START 3*0Sstevel@tonic-gate * 4*0Sstevel@tonic-gate * The contents of this file are subject to the terms of the 5*0Sstevel@tonic-gate * Common Development and Distribution License, Version 1.0 only 6*0Sstevel@tonic-gate * (the "License"). You may not use this file except in compliance 7*0Sstevel@tonic-gate * with the License. 8*0Sstevel@tonic-gate * 9*0Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10*0Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 11*0Sstevel@tonic-gate * See the License for the specific language governing permissions 12*0Sstevel@tonic-gate * and limitations under the License. 13*0Sstevel@tonic-gate * 14*0Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 15*0Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16*0Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 17*0Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 18*0Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 19*0Sstevel@tonic-gate * 20*0Sstevel@tonic-gate * CDDL HEADER END 21*0Sstevel@tonic-gate */ 22*0Sstevel@tonic-gate /* 23*0Sstevel@tonic-gate * Copyright 2005 Sun Microsystems, Inc. All rights reserved. 24*0Sstevel@tonic-gate * Use is subject to license terms. 25*0Sstevel@tonic-gate */ 26*0Sstevel@tonic-gate 27*0Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 28*0Sstevel@tonic-gate 29*0Sstevel@tonic-gate #include <sys/types.h> 30*0Sstevel@tonic-gate #include <sys/sysmacros.h> 31*0Sstevel@tonic-gate #include <sys/isa_defs.h> 32*0Sstevel@tonic-gate 33*0Sstevel@tonic-gate #include <strings.h> 34*0Sstevel@tonic-gate #include <stdlib.h> 35*0Sstevel@tonic-gate #include <setjmp.h> 36*0Sstevel@tonic-gate #include <assert.h> 37*0Sstevel@tonic-gate #include <errno.h> 38*0Sstevel@tonic-gate 39*0Sstevel@tonic-gate #include <dt_impl.h> 40*0Sstevel@tonic-gate #include <dt_grammar.h> 41*0Sstevel@tonic-gate #include <dt_parser.h> 42*0Sstevel@tonic-gate #include <dt_provider.h> 43*0Sstevel@tonic-gate 44*0Sstevel@tonic-gate static void dt_cg_node(dt_node_t *, dt_irlist_t *, dt_regset_t *); 45*0Sstevel@tonic-gate 46*0Sstevel@tonic-gate static dt_irnode_t * 47*0Sstevel@tonic-gate dt_cg_node_alloc(uint_t label, dif_instr_t instr) 48*0Sstevel@tonic-gate { 49*0Sstevel@tonic-gate dt_irnode_t *dip = malloc(sizeof (dt_irnode_t)); 50*0Sstevel@tonic-gate 51*0Sstevel@tonic-gate if (dip == NULL) 52*0Sstevel@tonic-gate longjmp(yypcb->pcb_jmpbuf, EDT_NOMEM); 53*0Sstevel@tonic-gate 54*0Sstevel@tonic-gate dip->di_label = label; 55*0Sstevel@tonic-gate dip->di_instr = instr; 56*0Sstevel@tonic-gate dip->di_ident = NULL; 57*0Sstevel@tonic-gate dip->di_next = NULL; 58*0Sstevel@tonic-gate 59*0Sstevel@tonic-gate return (dip); 60*0Sstevel@tonic-gate } 61*0Sstevel@tonic-gate 62*0Sstevel@tonic-gate /* 63*0Sstevel@tonic-gate * Code generator wrapper function for ctf_member_info. If we are given a 64*0Sstevel@tonic-gate * reference to a forward declaration tag, search the entire type space for 65*0Sstevel@tonic-gate * the actual definition and then call ctf_member_info on the result. 66*0Sstevel@tonic-gate */ 67*0Sstevel@tonic-gate static ctf_file_t * 68*0Sstevel@tonic-gate dt_cg_membinfo(ctf_file_t *fp, ctf_id_t type, const char *s, ctf_membinfo_t *mp) 69*0Sstevel@tonic-gate { 70*0Sstevel@tonic-gate while (ctf_type_kind(fp, type) == CTF_K_FORWARD) { 71*0Sstevel@tonic-gate char n[DT_TYPE_NAMELEN]; 72*0Sstevel@tonic-gate dtrace_typeinfo_t dtt; 73*0Sstevel@tonic-gate 74*0Sstevel@tonic-gate if (ctf_type_name(fp, type, n, sizeof (n)) == NULL || 75*0Sstevel@tonic-gate dt_type_lookup(n, &dtt) == -1 || ( 76*0Sstevel@tonic-gate dtt.dtt_ctfp == fp && dtt.dtt_type == type)) 77*0Sstevel@tonic-gate break; /* unable to improve our position */ 78*0Sstevel@tonic-gate 79*0Sstevel@tonic-gate fp = dtt.dtt_ctfp; 80*0Sstevel@tonic-gate type = ctf_type_resolve(fp, dtt.dtt_type); 81*0Sstevel@tonic-gate } 82*0Sstevel@tonic-gate 83*0Sstevel@tonic-gate if (ctf_member_info(fp, type, s, mp) == CTF_ERR) 84*0Sstevel@tonic-gate return (NULL); /* ctf_errno is set for us */ 85*0Sstevel@tonic-gate 86*0Sstevel@tonic-gate return (fp); 87*0Sstevel@tonic-gate } 88*0Sstevel@tonic-gate 89*0Sstevel@tonic-gate static void 90*0Sstevel@tonic-gate dt_cg_xsetx(dt_irlist_t *dlp, dt_ident_t *idp, uint_t lbl, int reg, uint64_t x) 91*0Sstevel@tonic-gate { 92*0Sstevel@tonic-gate int flag = idp != NULL ? DT_INT_PRIVATE : DT_INT_SHARED; 93*0Sstevel@tonic-gate int intoff = dt_inttab_insert(yypcb->pcb_inttab, x, flag); 94*0Sstevel@tonic-gate dif_instr_t instr = DIF_INSTR_SETX((uint_t)intoff, reg); 95*0Sstevel@tonic-gate 96*0Sstevel@tonic-gate if (intoff == -1) 97*0Sstevel@tonic-gate longjmp(yypcb->pcb_jmpbuf, EDT_NOMEM); 98*0Sstevel@tonic-gate 99*0Sstevel@tonic-gate if (intoff > DIF_INTOFF_MAX) 100*0Sstevel@tonic-gate longjmp(yypcb->pcb_jmpbuf, EDT_INT2BIG); 101*0Sstevel@tonic-gate 102*0Sstevel@tonic-gate dt_irlist_append(dlp, dt_cg_node_alloc(lbl, instr)); 103*0Sstevel@tonic-gate 104*0Sstevel@tonic-gate if (idp != NULL) 105*0Sstevel@tonic-gate dlp->dl_last->di_ident = idp; 106*0Sstevel@tonic-gate } 107*0Sstevel@tonic-gate 108*0Sstevel@tonic-gate static void 109*0Sstevel@tonic-gate dt_cg_setx(dt_irlist_t *dlp, int reg, uint64_t x) 110*0Sstevel@tonic-gate { 111*0Sstevel@tonic-gate dt_cg_xsetx(dlp, NULL, DT_LBL_NONE, reg, x); 112*0Sstevel@tonic-gate } 113*0Sstevel@tonic-gate 114*0Sstevel@tonic-gate /* 115*0Sstevel@tonic-gate * When loading bit-fields, we want to convert a byte count in the range 116*0Sstevel@tonic-gate * 1-8 to the closest power of 2 (e.g. 3->4, 5->8, etc). The clp2() function 117*0Sstevel@tonic-gate * is a clever implementation from "Hacker's Delight" by Henry Warren, Jr. 118*0Sstevel@tonic-gate */ 119*0Sstevel@tonic-gate static size_t 120*0Sstevel@tonic-gate clp2(size_t x) 121*0Sstevel@tonic-gate { 122*0Sstevel@tonic-gate x--; 123*0Sstevel@tonic-gate 124*0Sstevel@tonic-gate x |= (x >> 1); 125*0Sstevel@tonic-gate x |= (x >> 2); 126*0Sstevel@tonic-gate x |= (x >> 4); 127*0Sstevel@tonic-gate x |= (x >> 8); 128*0Sstevel@tonic-gate x |= (x >> 16); 129*0Sstevel@tonic-gate 130*0Sstevel@tonic-gate return (x + 1); 131*0Sstevel@tonic-gate } 132*0Sstevel@tonic-gate 133*0Sstevel@tonic-gate /* 134*0Sstevel@tonic-gate * Lookup the correct load opcode to use for the specified node and CTF type. 135*0Sstevel@tonic-gate * We determine the size and convert it to a 3-bit index. Our lookup table 136*0Sstevel@tonic-gate * is constructed to use a 5-bit index, consisting of the 3-bit size 0-7, a 137*0Sstevel@tonic-gate * bit for the sign, and a bit for userland address. For example, a 4-byte 138*0Sstevel@tonic-gate * signed load from userland would be at the following table index: 139*0Sstevel@tonic-gate * user=1 sign=1 size=4 => binary index 11011 = decimal index 27 140*0Sstevel@tonic-gate */ 141*0Sstevel@tonic-gate static uint_t 142*0Sstevel@tonic-gate dt_cg_load(dt_node_t *dnp, ctf_file_t *ctfp, ctf_id_t type) 143*0Sstevel@tonic-gate { 144*0Sstevel@tonic-gate static const uint_t ops[] = { 145*0Sstevel@tonic-gate DIF_OP_LDUB, DIF_OP_LDUH, 0, DIF_OP_LDUW, 146*0Sstevel@tonic-gate 0, 0, 0, DIF_OP_LDX, 147*0Sstevel@tonic-gate DIF_OP_LDSB, DIF_OP_LDSH, 0, DIF_OP_LDSW, 148*0Sstevel@tonic-gate 0, 0, 0, DIF_OP_LDX, 149*0Sstevel@tonic-gate DIF_OP_ULDUB, DIF_OP_ULDUH, 0, DIF_OP_ULDUW, 150*0Sstevel@tonic-gate 0, 0, 0, DIF_OP_ULDX, 151*0Sstevel@tonic-gate DIF_OP_ULDSB, DIF_OP_ULDSH, 0, DIF_OP_ULDSW, 152*0Sstevel@tonic-gate 0, 0, 0, DIF_OP_ULDX, 153*0Sstevel@tonic-gate }; 154*0Sstevel@tonic-gate 155*0Sstevel@tonic-gate ctf_encoding_t e; 156*0Sstevel@tonic-gate ssize_t size; 157*0Sstevel@tonic-gate 158*0Sstevel@tonic-gate /* 159*0Sstevel@tonic-gate * If we're loading a bit-field, the size of our load is found by 160*0Sstevel@tonic-gate * rounding cte_bits up to a byte boundary and then finding the 161*0Sstevel@tonic-gate * nearest power of two to this value (see clp2(), above). 162*0Sstevel@tonic-gate */ 163*0Sstevel@tonic-gate if ((dnp->dn_flags & DT_NF_BITFIELD) && 164*0Sstevel@tonic-gate ctf_type_encoding(ctfp, type, &e) != CTF_ERR) 165*0Sstevel@tonic-gate size = clp2(P2ROUNDUP(e.cte_bits, NBBY) / NBBY); 166*0Sstevel@tonic-gate else 167*0Sstevel@tonic-gate size = ctf_type_size(ctfp, type); 168*0Sstevel@tonic-gate 169*0Sstevel@tonic-gate if (size < 1 || size > 8 || (size & (size - 1)) != 0) { 170*0Sstevel@tonic-gate xyerror(D_UNKNOWN, "internal error -- cg cannot load " 171*0Sstevel@tonic-gate "size %ld when passed by value\n", (long)size); 172*0Sstevel@tonic-gate } 173*0Sstevel@tonic-gate 174*0Sstevel@tonic-gate size--; /* convert size to 3-bit index */ 175*0Sstevel@tonic-gate 176*0Sstevel@tonic-gate if (dnp->dn_flags & DT_NF_SIGNED) 177*0Sstevel@tonic-gate size |= 0x08; 178*0Sstevel@tonic-gate if (dnp->dn_flags & DT_NF_USERLAND) 179*0Sstevel@tonic-gate size |= 0x10; 180*0Sstevel@tonic-gate 181*0Sstevel@tonic-gate return (ops[size]); 182*0Sstevel@tonic-gate } 183*0Sstevel@tonic-gate 184*0Sstevel@tonic-gate static void 185*0Sstevel@tonic-gate dt_cg_ptrsize(dt_node_t *dnp, dt_irlist_t *dlp, dt_regset_t *drp, 186*0Sstevel@tonic-gate uint_t op, int dreg) 187*0Sstevel@tonic-gate { 188*0Sstevel@tonic-gate ctf_file_t *ctfp = dnp->dn_ctfp; 189*0Sstevel@tonic-gate ctf_arinfo_t r; 190*0Sstevel@tonic-gate dif_instr_t instr; 191*0Sstevel@tonic-gate ctf_id_t type; 192*0Sstevel@tonic-gate uint_t kind; 193*0Sstevel@tonic-gate ssize_t size; 194*0Sstevel@tonic-gate int sreg; 195*0Sstevel@tonic-gate 196*0Sstevel@tonic-gate if ((sreg = dt_regset_alloc(drp)) == -1) 197*0Sstevel@tonic-gate longjmp(yypcb->pcb_jmpbuf, EDT_NOREG); 198*0Sstevel@tonic-gate 199*0Sstevel@tonic-gate type = ctf_type_resolve(ctfp, dnp->dn_type); 200*0Sstevel@tonic-gate kind = ctf_type_kind(ctfp, type); 201*0Sstevel@tonic-gate assert(kind == CTF_K_POINTER || kind == CTF_K_ARRAY); 202*0Sstevel@tonic-gate 203*0Sstevel@tonic-gate if (kind == CTF_K_ARRAY) { 204*0Sstevel@tonic-gate if (ctf_array_info(ctfp, type, &r) != 0) { 205*0Sstevel@tonic-gate yypcb->pcb_hdl->dt_ctferr = ctf_errno(ctfp); 206*0Sstevel@tonic-gate longjmp(yypcb->pcb_jmpbuf, EDT_CTF); 207*0Sstevel@tonic-gate } 208*0Sstevel@tonic-gate type = r.ctr_contents; 209*0Sstevel@tonic-gate } else 210*0Sstevel@tonic-gate type = ctf_type_reference(ctfp, type); 211*0Sstevel@tonic-gate 212*0Sstevel@tonic-gate if ((size = ctf_type_size(ctfp, type)) == 1) 213*0Sstevel@tonic-gate return; /* multiply or divide by one can be omitted */ 214*0Sstevel@tonic-gate 215*0Sstevel@tonic-gate dt_cg_setx(dlp, sreg, size); 216*0Sstevel@tonic-gate instr = DIF_INSTR_FMT(op, dreg, sreg, dreg); 217*0Sstevel@tonic-gate dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr)); 218*0Sstevel@tonic-gate dt_regset_free(drp, sreg); 219*0Sstevel@tonic-gate } 220*0Sstevel@tonic-gate 221*0Sstevel@tonic-gate /* 222*0Sstevel@tonic-gate * If the result of a "." or "->" operation is a bit-field, we use this routine 223*0Sstevel@tonic-gate * to generate an epilogue to the load instruction that extracts the value. In 224*0Sstevel@tonic-gate * the diagrams below the "ld??" is the load instruction that is generated to 225*0Sstevel@tonic-gate * load the containing word that is generating prior to calling this function. 226*0Sstevel@tonic-gate * 227*0Sstevel@tonic-gate * Epilogue for unsigned fields: Epilogue for signed fields: 228*0Sstevel@tonic-gate * 229*0Sstevel@tonic-gate * ldu? [r1], r1 lds? [r1], r1 230*0Sstevel@tonic-gate * setx USHIFT, r2 setx 64 - SSHIFT, r2 231*0Sstevel@tonic-gate * srl r1, r2, r1 sll r1, r2, r1 232*0Sstevel@tonic-gate * setx (1 << bits) - 1, r2 setx 64 - bits, r2 233*0Sstevel@tonic-gate * and r1, r2, r1 sra r1, r2, r1 234*0Sstevel@tonic-gate * 235*0Sstevel@tonic-gate * The *SHIFT constants above changes value depending on the endian-ness of our 236*0Sstevel@tonic-gate * target architecture. Refer to the comments below for more details. 237*0Sstevel@tonic-gate */ 238*0Sstevel@tonic-gate static void 239*0Sstevel@tonic-gate dt_cg_field_get(dt_node_t *dnp, dt_irlist_t *dlp, dt_regset_t *drp, 240*0Sstevel@tonic-gate ctf_file_t *fp, const ctf_membinfo_t *mp) 241*0Sstevel@tonic-gate { 242*0Sstevel@tonic-gate ctf_encoding_t e; 243*0Sstevel@tonic-gate dif_instr_t instr; 244*0Sstevel@tonic-gate uint64_t shift; 245*0Sstevel@tonic-gate int r1, r2; 246*0Sstevel@tonic-gate 247*0Sstevel@tonic-gate if (ctf_type_encoding(fp, mp->ctm_type, &e) != 0 || e.cte_bits > 64) { 248*0Sstevel@tonic-gate xyerror(D_UNKNOWN, "cg: bad field: off %lu type <%ld> " 249*0Sstevel@tonic-gate "bits %u\n", mp->ctm_offset, mp->ctm_type, e.cte_bits); 250*0Sstevel@tonic-gate } 251*0Sstevel@tonic-gate 252*0Sstevel@tonic-gate assert(dnp->dn_op == DT_TOK_PTR || dnp->dn_op == DT_TOK_DOT); 253*0Sstevel@tonic-gate r1 = dnp->dn_left->dn_reg; 254*0Sstevel@tonic-gate 255*0Sstevel@tonic-gate if ((r2 = dt_regset_alloc(drp)) == -1) 256*0Sstevel@tonic-gate longjmp(yypcb->pcb_jmpbuf, EDT_NOREG); 257*0Sstevel@tonic-gate 258*0Sstevel@tonic-gate /* 259*0Sstevel@tonic-gate * On little-endian architectures, ctm_offset counts from the right so 260*0Sstevel@tonic-gate * ctm_offset % NBBY itself is the amount we want to shift right to 261*0Sstevel@tonic-gate * move the value bits to the little end of the register to mask them. 262*0Sstevel@tonic-gate * On big-endian architectures, ctm_offset counts from the left so we 263*0Sstevel@tonic-gate * must subtract (ctm_offset % NBBY + cte_bits) from the size in bits 264*0Sstevel@tonic-gate * we used for the load. The size of our load in turn is found by 265*0Sstevel@tonic-gate * rounding cte_bits up to a byte boundary and then finding the 266*0Sstevel@tonic-gate * nearest power of two to this value (see clp2(), above). These 267*0Sstevel@tonic-gate * properties are used to compute shift as USHIFT or SSHIFT, below. 268*0Sstevel@tonic-gate */ 269*0Sstevel@tonic-gate if (dnp->dn_flags & DT_NF_SIGNED) { 270*0Sstevel@tonic-gate #ifdef _BIG_ENDIAN 271*0Sstevel@tonic-gate shift = clp2(P2ROUNDUP(e.cte_bits, NBBY) / NBBY) * NBBY - 272*0Sstevel@tonic-gate mp->ctm_offset % NBBY; 273*0Sstevel@tonic-gate #else 274*0Sstevel@tonic-gate shift = mp->ctm_offset % NBBY + e.cte_bits; 275*0Sstevel@tonic-gate #endif 276*0Sstevel@tonic-gate dt_cg_setx(dlp, r2, 64 - shift); 277*0Sstevel@tonic-gate instr = DIF_INSTR_FMT(DIF_OP_SLL, r1, r2, r1); 278*0Sstevel@tonic-gate dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr)); 279*0Sstevel@tonic-gate 280*0Sstevel@tonic-gate dt_cg_setx(dlp, r2, 64 - e.cte_bits); 281*0Sstevel@tonic-gate instr = DIF_INSTR_FMT(DIF_OP_SRA, r1, r2, r1); 282*0Sstevel@tonic-gate dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr)); 283*0Sstevel@tonic-gate } else { 284*0Sstevel@tonic-gate #ifdef _BIG_ENDIAN 285*0Sstevel@tonic-gate shift = clp2(P2ROUNDUP(e.cte_bits, NBBY) / NBBY) * NBBY - 286*0Sstevel@tonic-gate (mp->ctm_offset % NBBY + e.cte_bits); 287*0Sstevel@tonic-gate #else 288*0Sstevel@tonic-gate shift = mp->ctm_offset % NBBY; 289*0Sstevel@tonic-gate #endif 290*0Sstevel@tonic-gate dt_cg_setx(dlp, r2, shift); 291*0Sstevel@tonic-gate instr = DIF_INSTR_FMT(DIF_OP_SRL, r1, r2, r1); 292*0Sstevel@tonic-gate dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr)); 293*0Sstevel@tonic-gate 294*0Sstevel@tonic-gate dt_cg_setx(dlp, r2, (1ULL << e.cte_bits) - 1); 295*0Sstevel@tonic-gate instr = DIF_INSTR_FMT(DIF_OP_AND, r1, r2, r1); 296*0Sstevel@tonic-gate dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr)); 297*0Sstevel@tonic-gate } 298*0Sstevel@tonic-gate 299*0Sstevel@tonic-gate dt_regset_free(drp, r2); 300*0Sstevel@tonic-gate } 301*0Sstevel@tonic-gate 302*0Sstevel@tonic-gate /* 303*0Sstevel@tonic-gate * If the destination of a store operation is a bit-field, we use this routine 304*0Sstevel@tonic-gate * to generate a prologue to the store instruction that loads the surrounding 305*0Sstevel@tonic-gate * bits, clears the destination field, and ORs in the new value of the field. 306*0Sstevel@tonic-gate * In the diagram below the "st?" is the store instruction that is generated to 307*0Sstevel@tonic-gate * store the containing word that is generating after calling this function. 308*0Sstevel@tonic-gate * 309*0Sstevel@tonic-gate * ld [dst->dn_reg], r1 310*0Sstevel@tonic-gate * setx ~(((1 << cte_bits) - 1) << (ctm_offset % NBBY)), r2 311*0Sstevel@tonic-gate * and r1, r2, r1 312*0Sstevel@tonic-gate * 313*0Sstevel@tonic-gate * setx (1 << cte_bits) - 1, r2 314*0Sstevel@tonic-gate * and src->dn_reg, r2, r2 315*0Sstevel@tonic-gate * setx ctm_offset % NBBY, r3 316*0Sstevel@tonic-gate * sll r2, r3, r2 317*0Sstevel@tonic-gate * 318*0Sstevel@tonic-gate * or r1, r2, r1 319*0Sstevel@tonic-gate * st? r1, [dst->dn_reg] 320*0Sstevel@tonic-gate * 321*0Sstevel@tonic-gate * This routine allocates a new register to hold the value to be stored and 322*0Sstevel@tonic-gate * returns it. The caller is responsible for freeing this register later. 323*0Sstevel@tonic-gate */ 324*0Sstevel@tonic-gate static int 325*0Sstevel@tonic-gate dt_cg_field_set(dt_node_t *src, dt_irlist_t *dlp, 326*0Sstevel@tonic-gate dt_regset_t *drp, dt_node_t *dst) 327*0Sstevel@tonic-gate { 328*0Sstevel@tonic-gate uint64_t cmask, fmask, shift; 329*0Sstevel@tonic-gate dif_instr_t instr; 330*0Sstevel@tonic-gate int r1, r2, r3; 331*0Sstevel@tonic-gate 332*0Sstevel@tonic-gate ctf_membinfo_t m; 333*0Sstevel@tonic-gate ctf_encoding_t e; 334*0Sstevel@tonic-gate ctf_file_t *fp, *ofp; 335*0Sstevel@tonic-gate ctf_id_t type; 336*0Sstevel@tonic-gate 337*0Sstevel@tonic-gate assert(dst->dn_op == DT_TOK_PTR || dst->dn_op == DT_TOK_DOT); 338*0Sstevel@tonic-gate assert(dst->dn_right->dn_kind == DT_NODE_IDENT); 339*0Sstevel@tonic-gate 340*0Sstevel@tonic-gate fp = dst->dn_left->dn_ctfp; 341*0Sstevel@tonic-gate type = ctf_type_resolve(fp, dst->dn_left->dn_type); 342*0Sstevel@tonic-gate 343*0Sstevel@tonic-gate if (dst->dn_op == DT_TOK_PTR) { 344*0Sstevel@tonic-gate type = ctf_type_reference(fp, type); 345*0Sstevel@tonic-gate type = ctf_type_resolve(fp, type); 346*0Sstevel@tonic-gate } 347*0Sstevel@tonic-gate 348*0Sstevel@tonic-gate if ((fp = dt_cg_membinfo(ofp = fp, type, 349*0Sstevel@tonic-gate dst->dn_right->dn_string, &m)) == NULL) { 350*0Sstevel@tonic-gate yypcb->pcb_hdl->dt_ctferr = ctf_errno(ofp); 351*0Sstevel@tonic-gate longjmp(yypcb->pcb_jmpbuf, EDT_CTF); 352*0Sstevel@tonic-gate } 353*0Sstevel@tonic-gate 354*0Sstevel@tonic-gate if (ctf_type_encoding(fp, m.ctm_type, &e) != 0 || e.cte_bits > 64) { 355*0Sstevel@tonic-gate xyerror(D_UNKNOWN, "cg: bad field: off %lu type <%ld> " 356*0Sstevel@tonic-gate "bits %u\n", m.ctm_offset, m.ctm_type, e.cte_bits); 357*0Sstevel@tonic-gate } 358*0Sstevel@tonic-gate 359*0Sstevel@tonic-gate if ((r1 = dt_regset_alloc(drp)) == -1 || 360*0Sstevel@tonic-gate (r2 = dt_regset_alloc(drp)) == -1 || 361*0Sstevel@tonic-gate (r3 = dt_regset_alloc(drp)) == -1) 362*0Sstevel@tonic-gate longjmp(yypcb->pcb_jmpbuf, EDT_NOREG); 363*0Sstevel@tonic-gate 364*0Sstevel@tonic-gate /* 365*0Sstevel@tonic-gate * Compute shifts and masks. We need to compute "shift" as the amount 366*0Sstevel@tonic-gate * we need to shift left to position our field in the containing word. 367*0Sstevel@tonic-gate * Refer to the comments in dt_cg_field_get(), above, for more info. 368*0Sstevel@tonic-gate * We then compute fmask as the mask that truncates the value in the 369*0Sstevel@tonic-gate * input register to width cte_bits, and cmask as the mask used to 370*0Sstevel@tonic-gate * pass through the containing bits and zero the field bits. 371*0Sstevel@tonic-gate */ 372*0Sstevel@tonic-gate #ifdef _BIG_ENDIAN 373*0Sstevel@tonic-gate shift = clp2(P2ROUNDUP(e.cte_bits, NBBY) / NBBY) * NBBY - 374*0Sstevel@tonic-gate (m.ctm_offset % NBBY + e.cte_bits); 375*0Sstevel@tonic-gate #else 376*0Sstevel@tonic-gate shift = m.ctm_offset % NBBY; 377*0Sstevel@tonic-gate #endif 378*0Sstevel@tonic-gate fmask = (1ULL << e.cte_bits) - 1; 379*0Sstevel@tonic-gate cmask = ~(fmask << shift); 380*0Sstevel@tonic-gate 381*0Sstevel@tonic-gate instr = DIF_INSTR_LOAD( 382*0Sstevel@tonic-gate dt_cg_load(dst, fp, m.ctm_type), dst->dn_reg, r1); 383*0Sstevel@tonic-gate dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr)); 384*0Sstevel@tonic-gate 385*0Sstevel@tonic-gate dt_cg_setx(dlp, r2, cmask); 386*0Sstevel@tonic-gate instr = DIF_INSTR_FMT(DIF_OP_AND, r1, r2, r1); 387*0Sstevel@tonic-gate dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr)); 388*0Sstevel@tonic-gate 389*0Sstevel@tonic-gate dt_cg_setx(dlp, r2, fmask); 390*0Sstevel@tonic-gate instr = DIF_INSTR_FMT(DIF_OP_AND, src->dn_reg, r2, r2); 391*0Sstevel@tonic-gate dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr)); 392*0Sstevel@tonic-gate 393*0Sstevel@tonic-gate dt_cg_setx(dlp, r3, shift); 394*0Sstevel@tonic-gate instr = DIF_INSTR_FMT(DIF_OP_SLL, r2, r3, r2); 395*0Sstevel@tonic-gate dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr)); 396*0Sstevel@tonic-gate 397*0Sstevel@tonic-gate instr = DIF_INSTR_FMT(DIF_OP_OR, r1, r2, r1); 398*0Sstevel@tonic-gate dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr)); 399*0Sstevel@tonic-gate 400*0Sstevel@tonic-gate dt_regset_free(drp, r3); 401*0Sstevel@tonic-gate dt_regset_free(drp, r2); 402*0Sstevel@tonic-gate 403*0Sstevel@tonic-gate return (r1); 404*0Sstevel@tonic-gate } 405*0Sstevel@tonic-gate 406*0Sstevel@tonic-gate static void 407*0Sstevel@tonic-gate dt_cg_store(dt_node_t *src, dt_irlist_t *dlp, dt_regset_t *drp, dt_node_t *dst) 408*0Sstevel@tonic-gate { 409*0Sstevel@tonic-gate ctf_encoding_t e; 410*0Sstevel@tonic-gate dif_instr_t instr; 411*0Sstevel@tonic-gate size_t size; 412*0Sstevel@tonic-gate int reg; 413*0Sstevel@tonic-gate 414*0Sstevel@tonic-gate /* 415*0Sstevel@tonic-gate * If we're loading a bit-field, the size of our store is found by 416*0Sstevel@tonic-gate * rounding dst's cte_bits up to a byte boundary and then finding the 417*0Sstevel@tonic-gate * nearest power of two to this value (see clp2(), above). 418*0Sstevel@tonic-gate */ 419*0Sstevel@tonic-gate if ((dst->dn_flags & DT_NF_BITFIELD) && 420*0Sstevel@tonic-gate ctf_type_encoding(dst->dn_ctfp, dst->dn_type, &e) != CTF_ERR) 421*0Sstevel@tonic-gate size = clp2(P2ROUNDUP(e.cte_bits, NBBY) / NBBY); 422*0Sstevel@tonic-gate else 423*0Sstevel@tonic-gate size = dt_node_type_size(src); 424*0Sstevel@tonic-gate 425*0Sstevel@tonic-gate if (src->dn_flags & DT_NF_REF) { 426*0Sstevel@tonic-gate if ((reg = dt_regset_alloc(drp)) == -1) 427*0Sstevel@tonic-gate longjmp(yypcb->pcb_jmpbuf, EDT_NOREG); 428*0Sstevel@tonic-gate dt_cg_setx(dlp, reg, size); 429*0Sstevel@tonic-gate instr = DIF_INSTR_COPYS(src->dn_reg, reg, dst->dn_reg); 430*0Sstevel@tonic-gate dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr)); 431*0Sstevel@tonic-gate dt_regset_free(drp, reg); 432*0Sstevel@tonic-gate } else { 433*0Sstevel@tonic-gate if (dst->dn_flags & DT_NF_BITFIELD) 434*0Sstevel@tonic-gate reg = dt_cg_field_set(src, dlp, drp, dst); 435*0Sstevel@tonic-gate else 436*0Sstevel@tonic-gate reg = src->dn_reg; 437*0Sstevel@tonic-gate 438*0Sstevel@tonic-gate switch (size) { 439*0Sstevel@tonic-gate case 1: 440*0Sstevel@tonic-gate instr = DIF_INSTR_STORE(DIF_OP_STB, reg, dst->dn_reg); 441*0Sstevel@tonic-gate break; 442*0Sstevel@tonic-gate case 2: 443*0Sstevel@tonic-gate instr = DIF_INSTR_STORE(DIF_OP_STH, reg, dst->dn_reg); 444*0Sstevel@tonic-gate break; 445*0Sstevel@tonic-gate case 4: 446*0Sstevel@tonic-gate instr = DIF_INSTR_STORE(DIF_OP_STW, reg, dst->dn_reg); 447*0Sstevel@tonic-gate break; 448*0Sstevel@tonic-gate case 8: 449*0Sstevel@tonic-gate instr = DIF_INSTR_STORE(DIF_OP_STX, reg, dst->dn_reg); 450*0Sstevel@tonic-gate break; 451*0Sstevel@tonic-gate default: 452*0Sstevel@tonic-gate xyerror(D_UNKNOWN, "internal error -- cg cannot store " 453*0Sstevel@tonic-gate "size %lu when passed by value\n", (ulong_t)size); 454*0Sstevel@tonic-gate } 455*0Sstevel@tonic-gate dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr)); 456*0Sstevel@tonic-gate 457*0Sstevel@tonic-gate if (dst->dn_flags & DT_NF_BITFIELD) 458*0Sstevel@tonic-gate dt_regset_free(drp, reg); 459*0Sstevel@tonic-gate } 460*0Sstevel@tonic-gate } 461*0Sstevel@tonic-gate 462*0Sstevel@tonic-gate /* 463*0Sstevel@tonic-gate * Generate code for a typecast or for argument promotion from the type of the 464*0Sstevel@tonic-gate * actual to the type of the formal. We need to generate code for casts when 465*0Sstevel@tonic-gate * a scalar type is being narrowed or changing signed-ness. We first shift the 466*0Sstevel@tonic-gate * desired bits high (losing excess bits if narrowing) and then shift them down 467*0Sstevel@tonic-gate * using logical shift (unsigned result) or arithmetic shift (signed result). 468*0Sstevel@tonic-gate */ 469*0Sstevel@tonic-gate static void 470*0Sstevel@tonic-gate dt_cg_typecast(const dt_node_t *src, const dt_node_t *dst, 471*0Sstevel@tonic-gate dt_irlist_t *dlp, dt_regset_t *drp) 472*0Sstevel@tonic-gate { 473*0Sstevel@tonic-gate size_t srcsize = dt_node_type_size(src); 474*0Sstevel@tonic-gate size_t dstsize = dt_node_type_size(dst); 475*0Sstevel@tonic-gate 476*0Sstevel@tonic-gate dif_instr_t instr; 477*0Sstevel@tonic-gate int reg, n; 478*0Sstevel@tonic-gate 479*0Sstevel@tonic-gate if (dt_node_is_scalar(dst) && (dstsize < srcsize || 480*0Sstevel@tonic-gate (src->dn_flags & DT_NF_SIGNED) ^ (dst->dn_flags & DT_NF_SIGNED))) { 481*0Sstevel@tonic-gate if ((reg = dt_regset_alloc(drp)) == -1) 482*0Sstevel@tonic-gate longjmp(yypcb->pcb_jmpbuf, EDT_NOREG); 483*0Sstevel@tonic-gate 484*0Sstevel@tonic-gate if (dstsize < srcsize) 485*0Sstevel@tonic-gate n = sizeof (uint64_t) * NBBY - dstsize * NBBY; 486*0Sstevel@tonic-gate else 487*0Sstevel@tonic-gate n = sizeof (uint64_t) * NBBY - srcsize * NBBY; 488*0Sstevel@tonic-gate 489*0Sstevel@tonic-gate dt_cg_setx(dlp, reg, n); 490*0Sstevel@tonic-gate 491*0Sstevel@tonic-gate instr = DIF_INSTR_FMT(DIF_OP_SLL, 492*0Sstevel@tonic-gate src->dn_reg, reg, dst->dn_reg); 493*0Sstevel@tonic-gate dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr)); 494*0Sstevel@tonic-gate 495*0Sstevel@tonic-gate instr = DIF_INSTR_FMT((dst->dn_flags & DT_NF_SIGNED) ? 496*0Sstevel@tonic-gate DIF_OP_SRA : DIF_OP_SRL, dst->dn_reg, reg, dst->dn_reg); 497*0Sstevel@tonic-gate 498*0Sstevel@tonic-gate dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr)); 499*0Sstevel@tonic-gate dt_regset_free(drp, reg); 500*0Sstevel@tonic-gate } 501*0Sstevel@tonic-gate } 502*0Sstevel@tonic-gate 503*0Sstevel@tonic-gate /* 504*0Sstevel@tonic-gate * Generate code to push the specified argument list on to the tuple stack. 505*0Sstevel@tonic-gate * We use this routine for handling subroutine calls and associative arrays. 506*0Sstevel@tonic-gate * We must first generate code for all subexpressions before loading the stack 507*0Sstevel@tonic-gate * because any subexpression could itself require the use of the tuple stack. 508*0Sstevel@tonic-gate * This holds a number of registers equal to the number of arguments, but this 509*0Sstevel@tonic-gate * is not a huge problem because the number of arguments can't exceed the 510*0Sstevel@tonic-gate * number of tuple register stack elements anyway. At most one extra register 511*0Sstevel@tonic-gate * is required (either by dt_cg_typecast() or for dtdt_size, below). This 512*0Sstevel@tonic-gate * implies that a DIF implementation should offer a number of general purpose 513*0Sstevel@tonic-gate * registers at least one greater than the number of tuple registers. 514*0Sstevel@tonic-gate */ 515*0Sstevel@tonic-gate static void 516*0Sstevel@tonic-gate dt_cg_arglist(dt_ident_t *idp, dt_node_t *args, 517*0Sstevel@tonic-gate dt_irlist_t *dlp, dt_regset_t *drp) 518*0Sstevel@tonic-gate { 519*0Sstevel@tonic-gate const dt_idsig_t *isp = idp->di_data; 520*0Sstevel@tonic-gate dt_node_t *dnp; 521*0Sstevel@tonic-gate int i = 0; 522*0Sstevel@tonic-gate 523*0Sstevel@tonic-gate for (dnp = args; dnp != NULL; dnp = dnp->dn_list) 524*0Sstevel@tonic-gate dt_cg_node(dnp, dlp, drp); 525*0Sstevel@tonic-gate 526*0Sstevel@tonic-gate dt_irlist_append(dlp, 527*0Sstevel@tonic-gate dt_cg_node_alloc(DT_LBL_NONE, DIF_INSTR_FLUSHTS)); 528*0Sstevel@tonic-gate 529*0Sstevel@tonic-gate for (dnp = args; dnp != NULL; dnp = dnp->dn_list, i++) { 530*0Sstevel@tonic-gate dtrace_diftype_t t; 531*0Sstevel@tonic-gate dif_instr_t instr; 532*0Sstevel@tonic-gate uint_t op; 533*0Sstevel@tonic-gate int reg; 534*0Sstevel@tonic-gate 535*0Sstevel@tonic-gate dt_node_diftype(dnp, &t); 536*0Sstevel@tonic-gate 537*0Sstevel@tonic-gate isp->dis_args[i].dn_reg = dnp->dn_reg; /* re-use register */ 538*0Sstevel@tonic-gate dt_cg_typecast(dnp, &isp->dis_args[i], dlp, drp); 539*0Sstevel@tonic-gate isp->dis_args[i].dn_reg = -1; 540*0Sstevel@tonic-gate 541*0Sstevel@tonic-gate if (t.dtdt_flags & DIF_TF_BYREF) 542*0Sstevel@tonic-gate op = DIF_OP_PUSHTR; 543*0Sstevel@tonic-gate else 544*0Sstevel@tonic-gate op = DIF_OP_PUSHTV; 545*0Sstevel@tonic-gate 546*0Sstevel@tonic-gate if (t.dtdt_size != 0) { 547*0Sstevel@tonic-gate if ((reg = dt_regset_alloc(drp)) == -1) 548*0Sstevel@tonic-gate longjmp(yypcb->pcb_jmpbuf, EDT_NOREG); 549*0Sstevel@tonic-gate dt_cg_setx(dlp, reg, t.dtdt_size); 550*0Sstevel@tonic-gate } else 551*0Sstevel@tonic-gate reg = DIF_REG_R0; 552*0Sstevel@tonic-gate 553*0Sstevel@tonic-gate instr = DIF_INSTR_PUSHTS(op, t.dtdt_kind, reg, dnp->dn_reg); 554*0Sstevel@tonic-gate dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr)); 555*0Sstevel@tonic-gate dt_regset_free(drp, dnp->dn_reg); 556*0Sstevel@tonic-gate 557*0Sstevel@tonic-gate if (reg != DIF_REG_R0) 558*0Sstevel@tonic-gate dt_regset_free(drp, reg); 559*0Sstevel@tonic-gate } 560*0Sstevel@tonic-gate 561*0Sstevel@tonic-gate if (i > yypcb->pcb_hdl->dt_conf.dtc_diftupregs) 562*0Sstevel@tonic-gate longjmp(yypcb->pcb_jmpbuf, EDT_NOTUPREG); 563*0Sstevel@tonic-gate } 564*0Sstevel@tonic-gate 565*0Sstevel@tonic-gate static void 566*0Sstevel@tonic-gate dt_cg_arithmetic_op(dt_node_t *dnp, dt_irlist_t *dlp, 567*0Sstevel@tonic-gate dt_regset_t *drp, uint_t op) 568*0Sstevel@tonic-gate { 569*0Sstevel@tonic-gate int is_ptr_op = (dnp->dn_op == DT_TOK_ADD || dnp->dn_op == DT_TOK_SUB || 570*0Sstevel@tonic-gate dnp->dn_op == DT_TOK_ADD_EQ || dnp->dn_op == DT_TOK_SUB_EQ); 571*0Sstevel@tonic-gate 572*0Sstevel@tonic-gate int lp_is_ptr = dt_node_is_pointer(dnp->dn_left); 573*0Sstevel@tonic-gate int rp_is_ptr = dt_node_is_pointer(dnp->dn_right); 574*0Sstevel@tonic-gate 575*0Sstevel@tonic-gate dif_instr_t instr; 576*0Sstevel@tonic-gate 577*0Sstevel@tonic-gate if (lp_is_ptr && rp_is_ptr) { 578*0Sstevel@tonic-gate assert(dnp->dn_op == DT_TOK_SUB); 579*0Sstevel@tonic-gate is_ptr_op = 0; 580*0Sstevel@tonic-gate } 581*0Sstevel@tonic-gate 582*0Sstevel@tonic-gate dt_cg_node(dnp->dn_left, dlp, drp); 583*0Sstevel@tonic-gate if (is_ptr_op && rp_is_ptr) 584*0Sstevel@tonic-gate dt_cg_ptrsize(dnp, dlp, drp, DIF_OP_MUL, dnp->dn_left->dn_reg); 585*0Sstevel@tonic-gate 586*0Sstevel@tonic-gate dt_cg_node(dnp->dn_right, dlp, drp); 587*0Sstevel@tonic-gate if (is_ptr_op && lp_is_ptr) 588*0Sstevel@tonic-gate dt_cg_ptrsize(dnp, dlp, drp, DIF_OP_MUL, dnp->dn_right->dn_reg); 589*0Sstevel@tonic-gate 590*0Sstevel@tonic-gate instr = DIF_INSTR_FMT(op, dnp->dn_left->dn_reg, 591*0Sstevel@tonic-gate dnp->dn_right->dn_reg, dnp->dn_left->dn_reg); 592*0Sstevel@tonic-gate 593*0Sstevel@tonic-gate dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr)); 594*0Sstevel@tonic-gate dt_regset_free(drp, dnp->dn_right->dn_reg); 595*0Sstevel@tonic-gate dnp->dn_reg = dnp->dn_left->dn_reg; 596*0Sstevel@tonic-gate 597*0Sstevel@tonic-gate if (lp_is_ptr && rp_is_ptr) 598*0Sstevel@tonic-gate dt_cg_ptrsize(dnp->dn_right, 599*0Sstevel@tonic-gate dlp, drp, DIF_OP_UDIV, dnp->dn_reg); 600*0Sstevel@tonic-gate } 601*0Sstevel@tonic-gate 602*0Sstevel@tonic-gate static uint_t 603*0Sstevel@tonic-gate dt_cg_stvar(const dt_ident_t *idp) 604*0Sstevel@tonic-gate { 605*0Sstevel@tonic-gate static const uint_t aops[] = { DIF_OP_STGAA, DIF_OP_STTAA, DIF_OP_NOP }; 606*0Sstevel@tonic-gate static const uint_t sops[] = { DIF_OP_STGS, DIF_OP_STTS, DIF_OP_STLS }; 607*0Sstevel@tonic-gate 608*0Sstevel@tonic-gate uint_t i = (((idp->di_flags & DT_IDFLG_LOCAL) != 0) << 1) | 609*0Sstevel@tonic-gate ((idp->di_flags & DT_IDFLG_TLS) != 0); 610*0Sstevel@tonic-gate 611*0Sstevel@tonic-gate return (idp->di_kind == DT_IDENT_ARRAY ? aops[i] : sops[i]); 612*0Sstevel@tonic-gate } 613*0Sstevel@tonic-gate 614*0Sstevel@tonic-gate static void 615*0Sstevel@tonic-gate dt_cg_prearith_op(dt_node_t *dnp, dt_irlist_t *dlp, dt_regset_t *drp, uint_t op) 616*0Sstevel@tonic-gate { 617*0Sstevel@tonic-gate ctf_file_t *ctfp = dnp->dn_ctfp; 618*0Sstevel@tonic-gate dif_instr_t instr; 619*0Sstevel@tonic-gate ctf_id_t type; 620*0Sstevel@tonic-gate ssize_t size = 1; 621*0Sstevel@tonic-gate int reg; 622*0Sstevel@tonic-gate 623*0Sstevel@tonic-gate if (dt_node_is_pointer(dnp)) { 624*0Sstevel@tonic-gate type = ctf_type_resolve(ctfp, dnp->dn_type); 625*0Sstevel@tonic-gate assert(ctf_type_kind(ctfp, type) == CTF_K_POINTER); 626*0Sstevel@tonic-gate size = ctf_type_size(ctfp, ctf_type_reference(ctfp, type)); 627*0Sstevel@tonic-gate } 628*0Sstevel@tonic-gate 629*0Sstevel@tonic-gate dt_cg_node(dnp->dn_child, dlp, drp); 630*0Sstevel@tonic-gate dnp->dn_reg = dnp->dn_child->dn_reg; 631*0Sstevel@tonic-gate 632*0Sstevel@tonic-gate if ((reg = dt_regset_alloc(drp)) == -1) 633*0Sstevel@tonic-gate longjmp(yypcb->pcb_jmpbuf, EDT_NOREG); 634*0Sstevel@tonic-gate 635*0Sstevel@tonic-gate dt_cg_setx(dlp, reg, size); 636*0Sstevel@tonic-gate 637*0Sstevel@tonic-gate instr = DIF_INSTR_FMT(op, dnp->dn_reg, reg, dnp->dn_reg); 638*0Sstevel@tonic-gate dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr)); 639*0Sstevel@tonic-gate dt_regset_free(drp, reg); 640*0Sstevel@tonic-gate 641*0Sstevel@tonic-gate /* 642*0Sstevel@tonic-gate * If we are modifying a variable, generate an stv instruction from 643*0Sstevel@tonic-gate * the variable specified by the identifier. If we are storing to a 644*0Sstevel@tonic-gate * memory address, generate code again for the left-hand side using 645*0Sstevel@tonic-gate * DT_NF_REF to get the address, and then generate a store to it. 646*0Sstevel@tonic-gate * In both paths, we store the value in dnp->dn_reg (the new value). 647*0Sstevel@tonic-gate */ 648*0Sstevel@tonic-gate if (dnp->dn_child->dn_kind == DT_NODE_VAR) { 649*0Sstevel@tonic-gate dt_ident_t *idp = dt_ident_resolve(dnp->dn_child->dn_ident); 650*0Sstevel@tonic-gate 651*0Sstevel@tonic-gate idp->di_flags |= DT_IDFLG_DIFW; 652*0Sstevel@tonic-gate instr = DIF_INSTR_STV(dt_cg_stvar(idp), 653*0Sstevel@tonic-gate idp->di_id, dnp->dn_reg); 654*0Sstevel@tonic-gate dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr)); 655*0Sstevel@tonic-gate } else { 656*0Sstevel@tonic-gate uint_t rbit = dnp->dn_child->dn_flags & DT_NF_REF; 657*0Sstevel@tonic-gate 658*0Sstevel@tonic-gate assert(dnp->dn_child->dn_flags & DT_NF_WRITABLE); 659*0Sstevel@tonic-gate assert(dnp->dn_child->dn_flags & DT_NF_LVALUE); 660*0Sstevel@tonic-gate 661*0Sstevel@tonic-gate dnp->dn_child->dn_flags |= DT_NF_REF; /* force pass-by-ref */ 662*0Sstevel@tonic-gate dt_cg_node(dnp->dn_child, dlp, drp); 663*0Sstevel@tonic-gate 664*0Sstevel@tonic-gate dt_cg_store(dnp, dlp, drp, dnp->dn_child); 665*0Sstevel@tonic-gate dt_regset_free(drp, dnp->dn_child->dn_reg); 666*0Sstevel@tonic-gate 667*0Sstevel@tonic-gate dnp->dn_left->dn_flags &= ~DT_NF_REF; 668*0Sstevel@tonic-gate dnp->dn_left->dn_flags |= rbit; 669*0Sstevel@tonic-gate } 670*0Sstevel@tonic-gate } 671*0Sstevel@tonic-gate 672*0Sstevel@tonic-gate static void 673*0Sstevel@tonic-gate dt_cg_postarith_op(dt_node_t *dnp, dt_irlist_t *dlp, 674*0Sstevel@tonic-gate dt_regset_t *drp, uint_t op) 675*0Sstevel@tonic-gate { 676*0Sstevel@tonic-gate ctf_file_t *ctfp = dnp->dn_ctfp; 677*0Sstevel@tonic-gate dif_instr_t instr; 678*0Sstevel@tonic-gate ctf_id_t type; 679*0Sstevel@tonic-gate ssize_t size = 1; 680*0Sstevel@tonic-gate int nreg; 681*0Sstevel@tonic-gate 682*0Sstevel@tonic-gate if (dt_node_is_pointer(dnp)) { 683*0Sstevel@tonic-gate type = ctf_type_resolve(ctfp, dnp->dn_type); 684*0Sstevel@tonic-gate assert(ctf_type_kind(ctfp, type) == CTF_K_POINTER); 685*0Sstevel@tonic-gate size = ctf_type_size(ctfp, ctf_type_reference(ctfp, type)); 686*0Sstevel@tonic-gate } 687*0Sstevel@tonic-gate 688*0Sstevel@tonic-gate dt_cg_node(dnp->dn_child, dlp, drp); 689*0Sstevel@tonic-gate dnp->dn_reg = dnp->dn_child->dn_reg; 690*0Sstevel@tonic-gate 691*0Sstevel@tonic-gate if ((nreg = dt_regset_alloc(drp)) == -1) 692*0Sstevel@tonic-gate longjmp(yypcb->pcb_jmpbuf, EDT_NOREG); 693*0Sstevel@tonic-gate 694*0Sstevel@tonic-gate dt_cg_setx(dlp, nreg, size); 695*0Sstevel@tonic-gate instr = DIF_INSTR_FMT(op, dnp->dn_reg, nreg, nreg); 696*0Sstevel@tonic-gate dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr)); 697*0Sstevel@tonic-gate 698*0Sstevel@tonic-gate /* 699*0Sstevel@tonic-gate * If we are modifying a variable, generate an stv instruction from 700*0Sstevel@tonic-gate * the variable specified by the identifier. If we are storing to a 701*0Sstevel@tonic-gate * memory address, generate code again for the left-hand side using 702*0Sstevel@tonic-gate * DT_NF_REF to get the address, and then generate a store to it. 703*0Sstevel@tonic-gate * In both paths, we store the value from 'nreg' (the new value). 704*0Sstevel@tonic-gate */ 705*0Sstevel@tonic-gate if (dnp->dn_child->dn_kind == DT_NODE_VAR) { 706*0Sstevel@tonic-gate dt_ident_t *idp = dt_ident_resolve(dnp->dn_child->dn_ident); 707*0Sstevel@tonic-gate 708*0Sstevel@tonic-gate idp->di_flags |= DT_IDFLG_DIFW; 709*0Sstevel@tonic-gate instr = DIF_INSTR_STV(dt_cg_stvar(idp), idp->di_id, nreg); 710*0Sstevel@tonic-gate dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr)); 711*0Sstevel@tonic-gate } else { 712*0Sstevel@tonic-gate uint_t rbit = dnp->dn_child->dn_flags & DT_NF_REF; 713*0Sstevel@tonic-gate int oreg = dnp->dn_reg; 714*0Sstevel@tonic-gate 715*0Sstevel@tonic-gate assert(dnp->dn_child->dn_flags & DT_NF_WRITABLE); 716*0Sstevel@tonic-gate assert(dnp->dn_child->dn_flags & DT_NF_LVALUE); 717*0Sstevel@tonic-gate 718*0Sstevel@tonic-gate dnp->dn_child->dn_flags |= DT_NF_REF; /* force pass-by-ref */ 719*0Sstevel@tonic-gate dt_cg_node(dnp->dn_child, dlp, drp); 720*0Sstevel@tonic-gate 721*0Sstevel@tonic-gate dnp->dn_reg = nreg; 722*0Sstevel@tonic-gate dt_cg_store(dnp, dlp, drp, dnp->dn_child); 723*0Sstevel@tonic-gate dnp->dn_reg = oreg; 724*0Sstevel@tonic-gate 725*0Sstevel@tonic-gate dt_regset_free(drp, dnp->dn_child->dn_reg); 726*0Sstevel@tonic-gate dnp->dn_left->dn_flags &= ~DT_NF_REF; 727*0Sstevel@tonic-gate dnp->dn_left->dn_flags |= rbit; 728*0Sstevel@tonic-gate } 729*0Sstevel@tonic-gate 730*0Sstevel@tonic-gate dt_regset_free(drp, nreg); 731*0Sstevel@tonic-gate } 732*0Sstevel@tonic-gate 733*0Sstevel@tonic-gate /* 734*0Sstevel@tonic-gate * Determine if we should perform signed or unsigned comparison for an OP2. 735*0Sstevel@tonic-gate * If both operands are of arithmetic type, perform the usual arithmetic 736*0Sstevel@tonic-gate * conversions to determine the common real type for comparison [ISOC 6.5.8.3]. 737*0Sstevel@tonic-gate */ 738*0Sstevel@tonic-gate static int 739*0Sstevel@tonic-gate dt_cg_compare_signed(dt_node_t *dnp) 740*0Sstevel@tonic-gate { 741*0Sstevel@tonic-gate dt_node_t dn; 742*0Sstevel@tonic-gate 743*0Sstevel@tonic-gate if (dt_node_is_string(dnp->dn_left) || 744*0Sstevel@tonic-gate dt_node_is_string(dnp->dn_right)) 745*0Sstevel@tonic-gate return (1); /* strings always compare signed */ 746*0Sstevel@tonic-gate else if (!dt_node_is_arith(dnp->dn_left) || 747*0Sstevel@tonic-gate !dt_node_is_arith(dnp->dn_right)) 748*0Sstevel@tonic-gate return (0); /* non-arithmetic types always compare unsigned */ 749*0Sstevel@tonic-gate 750*0Sstevel@tonic-gate bzero(&dn, sizeof (dn)); 751*0Sstevel@tonic-gate dt_node_promote(dnp->dn_left, dnp->dn_right, &dn); 752*0Sstevel@tonic-gate return (dn.dn_flags & DT_NF_SIGNED); 753*0Sstevel@tonic-gate } 754*0Sstevel@tonic-gate 755*0Sstevel@tonic-gate static void 756*0Sstevel@tonic-gate dt_cg_compare_op(dt_node_t *dnp, dt_irlist_t *dlp, dt_regset_t *drp, uint_t op) 757*0Sstevel@tonic-gate { 758*0Sstevel@tonic-gate uint_t lbl_true = dt_irlist_label(dlp); 759*0Sstevel@tonic-gate uint_t lbl_post = dt_irlist_label(dlp); 760*0Sstevel@tonic-gate 761*0Sstevel@tonic-gate dif_instr_t instr; 762*0Sstevel@tonic-gate uint_t opc; 763*0Sstevel@tonic-gate 764*0Sstevel@tonic-gate dt_cg_node(dnp->dn_left, dlp, drp); 765*0Sstevel@tonic-gate dt_cg_node(dnp->dn_right, dlp, drp); 766*0Sstevel@tonic-gate 767*0Sstevel@tonic-gate if (dt_node_is_string(dnp->dn_left) || dt_node_is_string(dnp->dn_right)) 768*0Sstevel@tonic-gate opc = DIF_OP_SCMP; 769*0Sstevel@tonic-gate else 770*0Sstevel@tonic-gate opc = DIF_OP_CMP; 771*0Sstevel@tonic-gate 772*0Sstevel@tonic-gate instr = DIF_INSTR_CMP(opc, dnp->dn_left->dn_reg, dnp->dn_right->dn_reg); 773*0Sstevel@tonic-gate dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr)); 774*0Sstevel@tonic-gate dt_regset_free(drp, dnp->dn_right->dn_reg); 775*0Sstevel@tonic-gate dnp->dn_reg = dnp->dn_left->dn_reg; 776*0Sstevel@tonic-gate 777*0Sstevel@tonic-gate instr = DIF_INSTR_BRANCH(op, lbl_true); 778*0Sstevel@tonic-gate dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr)); 779*0Sstevel@tonic-gate 780*0Sstevel@tonic-gate instr = DIF_INSTR_MOV(DIF_REG_R0, dnp->dn_reg); 781*0Sstevel@tonic-gate dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr)); 782*0Sstevel@tonic-gate 783*0Sstevel@tonic-gate instr = DIF_INSTR_BRANCH(DIF_OP_BA, lbl_post); 784*0Sstevel@tonic-gate dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr)); 785*0Sstevel@tonic-gate 786*0Sstevel@tonic-gate dt_cg_xsetx(dlp, NULL, lbl_true, dnp->dn_reg, 1); 787*0Sstevel@tonic-gate dt_irlist_append(dlp, dt_cg_node_alloc(lbl_post, DIF_INSTR_NOP)); 788*0Sstevel@tonic-gate } 789*0Sstevel@tonic-gate 790*0Sstevel@tonic-gate /* 791*0Sstevel@tonic-gate * Code generation for the ternary op requires some trickery with the assembler 792*0Sstevel@tonic-gate * in order to conserve registers. We generate code for dn_expr and dn_left 793*0Sstevel@tonic-gate * and free their registers so they do not have be consumed across codegen for 794*0Sstevel@tonic-gate * dn_right. We insert a dummy MOV at the end of dn_left into the destination 795*0Sstevel@tonic-gate * register, which is not yet known because we haven't done dn_right yet, and 796*0Sstevel@tonic-gate * save the pointer to this instruction node. We then generate code for 797*0Sstevel@tonic-gate * dn_right and use its register as our output. Finally, we reach back and 798*0Sstevel@tonic-gate * patch the instruction for dn_left to move its output into this register. 799*0Sstevel@tonic-gate */ 800*0Sstevel@tonic-gate static void 801*0Sstevel@tonic-gate dt_cg_ternary_op(dt_node_t *dnp, dt_irlist_t *dlp, dt_regset_t *drp) 802*0Sstevel@tonic-gate { 803*0Sstevel@tonic-gate uint_t lbl_false = dt_irlist_label(dlp); 804*0Sstevel@tonic-gate uint_t lbl_post = dt_irlist_label(dlp); 805*0Sstevel@tonic-gate 806*0Sstevel@tonic-gate dif_instr_t instr; 807*0Sstevel@tonic-gate dt_irnode_t *dip; 808*0Sstevel@tonic-gate 809*0Sstevel@tonic-gate dt_cg_node(dnp->dn_expr, dlp, drp); 810*0Sstevel@tonic-gate instr = DIF_INSTR_TST(dnp->dn_expr->dn_reg); 811*0Sstevel@tonic-gate dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr)); 812*0Sstevel@tonic-gate dt_regset_free(drp, dnp->dn_expr->dn_reg); 813*0Sstevel@tonic-gate 814*0Sstevel@tonic-gate instr = DIF_INSTR_BRANCH(DIF_OP_BE, lbl_false); 815*0Sstevel@tonic-gate dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr)); 816*0Sstevel@tonic-gate 817*0Sstevel@tonic-gate dt_cg_node(dnp->dn_left, dlp, drp); 818*0Sstevel@tonic-gate instr = DIF_INSTR_MOV(dnp->dn_left->dn_reg, DIF_REG_R0); 819*0Sstevel@tonic-gate dip = dt_cg_node_alloc(DT_LBL_NONE, instr); /* save dip for below */ 820*0Sstevel@tonic-gate dt_irlist_append(dlp, dip); 821*0Sstevel@tonic-gate dt_regset_free(drp, dnp->dn_left->dn_reg); 822*0Sstevel@tonic-gate 823*0Sstevel@tonic-gate instr = DIF_INSTR_BRANCH(DIF_OP_BA, lbl_post); 824*0Sstevel@tonic-gate dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr)); 825*0Sstevel@tonic-gate 826*0Sstevel@tonic-gate dt_irlist_append(dlp, dt_cg_node_alloc(lbl_false, DIF_INSTR_NOP)); 827*0Sstevel@tonic-gate dt_cg_node(dnp->dn_right, dlp, drp); 828*0Sstevel@tonic-gate dnp->dn_reg = dnp->dn_right->dn_reg; 829*0Sstevel@tonic-gate 830*0Sstevel@tonic-gate /* 831*0Sstevel@tonic-gate * Now that dn_reg is assigned, reach back and patch the correct MOV 832*0Sstevel@tonic-gate * instruction into the tail of dn_left. We know dn_reg was unused 833*0Sstevel@tonic-gate * at that point because otherwise dn_right couldn't have allocated it. 834*0Sstevel@tonic-gate */ 835*0Sstevel@tonic-gate dip->di_instr = DIF_INSTR_MOV(dnp->dn_left->dn_reg, dnp->dn_reg); 836*0Sstevel@tonic-gate dt_irlist_append(dlp, dt_cg_node_alloc(lbl_post, DIF_INSTR_NOP)); 837*0Sstevel@tonic-gate } 838*0Sstevel@tonic-gate 839*0Sstevel@tonic-gate static void 840*0Sstevel@tonic-gate dt_cg_logical_and(dt_node_t *dnp, dt_irlist_t *dlp, dt_regset_t *drp) 841*0Sstevel@tonic-gate { 842*0Sstevel@tonic-gate uint_t lbl_false = dt_irlist_label(dlp); 843*0Sstevel@tonic-gate uint_t lbl_post = dt_irlist_label(dlp); 844*0Sstevel@tonic-gate 845*0Sstevel@tonic-gate dif_instr_t instr; 846*0Sstevel@tonic-gate 847*0Sstevel@tonic-gate dt_cg_node(dnp->dn_left, dlp, drp); 848*0Sstevel@tonic-gate instr = DIF_INSTR_TST(dnp->dn_left->dn_reg); 849*0Sstevel@tonic-gate dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr)); 850*0Sstevel@tonic-gate dt_regset_free(drp, dnp->dn_left->dn_reg); 851*0Sstevel@tonic-gate 852*0Sstevel@tonic-gate instr = DIF_INSTR_BRANCH(DIF_OP_BE, lbl_false); 853*0Sstevel@tonic-gate dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr)); 854*0Sstevel@tonic-gate 855*0Sstevel@tonic-gate dt_cg_node(dnp->dn_right, dlp, drp); 856*0Sstevel@tonic-gate instr = DIF_INSTR_TST(dnp->dn_right->dn_reg); 857*0Sstevel@tonic-gate dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr)); 858*0Sstevel@tonic-gate dnp->dn_reg = dnp->dn_right->dn_reg; 859*0Sstevel@tonic-gate 860*0Sstevel@tonic-gate instr = DIF_INSTR_BRANCH(DIF_OP_BE, lbl_false); 861*0Sstevel@tonic-gate dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr)); 862*0Sstevel@tonic-gate 863*0Sstevel@tonic-gate dt_cg_setx(dlp, dnp->dn_reg, 1); 864*0Sstevel@tonic-gate 865*0Sstevel@tonic-gate instr = DIF_INSTR_BRANCH(DIF_OP_BA, lbl_post); 866*0Sstevel@tonic-gate dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr)); 867*0Sstevel@tonic-gate 868*0Sstevel@tonic-gate instr = DIF_INSTR_MOV(DIF_REG_R0, dnp->dn_reg); 869*0Sstevel@tonic-gate dt_irlist_append(dlp, dt_cg_node_alloc(lbl_false, instr)); 870*0Sstevel@tonic-gate 871*0Sstevel@tonic-gate dt_irlist_append(dlp, dt_cg_node_alloc(lbl_post, DIF_INSTR_NOP)); 872*0Sstevel@tonic-gate } 873*0Sstevel@tonic-gate 874*0Sstevel@tonic-gate static void 875*0Sstevel@tonic-gate dt_cg_logical_xor(dt_node_t *dnp, dt_irlist_t *dlp, dt_regset_t *drp) 876*0Sstevel@tonic-gate { 877*0Sstevel@tonic-gate uint_t lbl_next = dt_irlist_label(dlp); 878*0Sstevel@tonic-gate uint_t lbl_tail = dt_irlist_label(dlp); 879*0Sstevel@tonic-gate 880*0Sstevel@tonic-gate dif_instr_t instr; 881*0Sstevel@tonic-gate 882*0Sstevel@tonic-gate dt_cg_node(dnp->dn_left, dlp, drp); 883*0Sstevel@tonic-gate instr = DIF_INSTR_TST(dnp->dn_left->dn_reg); 884*0Sstevel@tonic-gate dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr)); 885*0Sstevel@tonic-gate 886*0Sstevel@tonic-gate instr = DIF_INSTR_BRANCH(DIF_OP_BE, lbl_next); 887*0Sstevel@tonic-gate dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr)); 888*0Sstevel@tonic-gate dt_cg_setx(dlp, dnp->dn_left->dn_reg, 1); 889*0Sstevel@tonic-gate 890*0Sstevel@tonic-gate dt_irlist_append(dlp, dt_cg_node_alloc(lbl_next, DIF_INSTR_NOP)); 891*0Sstevel@tonic-gate dt_cg_node(dnp->dn_right, dlp, drp); 892*0Sstevel@tonic-gate 893*0Sstevel@tonic-gate instr = DIF_INSTR_TST(dnp->dn_right->dn_reg); 894*0Sstevel@tonic-gate dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr)); 895*0Sstevel@tonic-gate 896*0Sstevel@tonic-gate instr = DIF_INSTR_BRANCH(DIF_OP_BE, lbl_tail); 897*0Sstevel@tonic-gate dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr)); 898*0Sstevel@tonic-gate dt_cg_setx(dlp, dnp->dn_right->dn_reg, 1); 899*0Sstevel@tonic-gate 900*0Sstevel@tonic-gate instr = DIF_INSTR_FMT(DIF_OP_XOR, dnp->dn_left->dn_reg, 901*0Sstevel@tonic-gate dnp->dn_right->dn_reg, dnp->dn_left->dn_reg); 902*0Sstevel@tonic-gate 903*0Sstevel@tonic-gate dt_irlist_append(dlp, dt_cg_node_alloc(lbl_tail, instr)); 904*0Sstevel@tonic-gate 905*0Sstevel@tonic-gate dt_regset_free(drp, dnp->dn_right->dn_reg); 906*0Sstevel@tonic-gate dnp->dn_reg = dnp->dn_left->dn_reg; 907*0Sstevel@tonic-gate } 908*0Sstevel@tonic-gate 909*0Sstevel@tonic-gate static void 910*0Sstevel@tonic-gate dt_cg_logical_or(dt_node_t *dnp, dt_irlist_t *dlp, dt_regset_t *drp) 911*0Sstevel@tonic-gate { 912*0Sstevel@tonic-gate uint_t lbl_true = dt_irlist_label(dlp); 913*0Sstevel@tonic-gate uint_t lbl_false = dt_irlist_label(dlp); 914*0Sstevel@tonic-gate uint_t lbl_post = dt_irlist_label(dlp); 915*0Sstevel@tonic-gate 916*0Sstevel@tonic-gate dif_instr_t instr; 917*0Sstevel@tonic-gate 918*0Sstevel@tonic-gate dt_cg_node(dnp->dn_left, dlp, drp); 919*0Sstevel@tonic-gate instr = DIF_INSTR_TST(dnp->dn_left->dn_reg); 920*0Sstevel@tonic-gate dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr)); 921*0Sstevel@tonic-gate dt_regset_free(drp, dnp->dn_left->dn_reg); 922*0Sstevel@tonic-gate 923*0Sstevel@tonic-gate instr = DIF_INSTR_BRANCH(DIF_OP_BNE, lbl_true); 924*0Sstevel@tonic-gate dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr)); 925*0Sstevel@tonic-gate 926*0Sstevel@tonic-gate dt_cg_node(dnp->dn_right, dlp, drp); 927*0Sstevel@tonic-gate instr = DIF_INSTR_TST(dnp->dn_right->dn_reg); 928*0Sstevel@tonic-gate dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr)); 929*0Sstevel@tonic-gate dnp->dn_reg = dnp->dn_right->dn_reg; 930*0Sstevel@tonic-gate 931*0Sstevel@tonic-gate instr = DIF_INSTR_BRANCH(DIF_OP_BE, lbl_false); 932*0Sstevel@tonic-gate dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr)); 933*0Sstevel@tonic-gate 934*0Sstevel@tonic-gate dt_cg_xsetx(dlp, NULL, lbl_true, dnp->dn_reg, 1); 935*0Sstevel@tonic-gate 936*0Sstevel@tonic-gate instr = DIF_INSTR_BRANCH(DIF_OP_BA, lbl_post); 937*0Sstevel@tonic-gate dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr)); 938*0Sstevel@tonic-gate 939*0Sstevel@tonic-gate instr = DIF_INSTR_MOV(DIF_REG_R0, dnp->dn_reg); 940*0Sstevel@tonic-gate dt_irlist_append(dlp, dt_cg_node_alloc(lbl_false, instr)); 941*0Sstevel@tonic-gate 942*0Sstevel@tonic-gate dt_irlist_append(dlp, dt_cg_node_alloc(lbl_post, DIF_INSTR_NOP)); 943*0Sstevel@tonic-gate } 944*0Sstevel@tonic-gate 945*0Sstevel@tonic-gate static void 946*0Sstevel@tonic-gate dt_cg_logical_neg(dt_node_t *dnp, dt_irlist_t *dlp, dt_regset_t *drp) 947*0Sstevel@tonic-gate { 948*0Sstevel@tonic-gate uint_t lbl_zero = dt_irlist_label(dlp); 949*0Sstevel@tonic-gate uint_t lbl_post = dt_irlist_label(dlp); 950*0Sstevel@tonic-gate 951*0Sstevel@tonic-gate dif_instr_t instr; 952*0Sstevel@tonic-gate 953*0Sstevel@tonic-gate dt_cg_node(dnp->dn_child, dlp, drp); 954*0Sstevel@tonic-gate dnp->dn_reg = dnp->dn_child->dn_reg; 955*0Sstevel@tonic-gate 956*0Sstevel@tonic-gate instr = DIF_INSTR_TST(dnp->dn_reg); 957*0Sstevel@tonic-gate dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr)); 958*0Sstevel@tonic-gate 959*0Sstevel@tonic-gate instr = DIF_INSTR_BRANCH(DIF_OP_BE, lbl_zero); 960*0Sstevel@tonic-gate dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr)); 961*0Sstevel@tonic-gate 962*0Sstevel@tonic-gate instr = DIF_INSTR_MOV(DIF_REG_R0, dnp->dn_reg); 963*0Sstevel@tonic-gate dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr)); 964*0Sstevel@tonic-gate 965*0Sstevel@tonic-gate instr = DIF_INSTR_BRANCH(DIF_OP_BA, lbl_post); 966*0Sstevel@tonic-gate dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr)); 967*0Sstevel@tonic-gate 968*0Sstevel@tonic-gate dt_cg_xsetx(dlp, NULL, lbl_zero, dnp->dn_reg, 1); 969*0Sstevel@tonic-gate dt_irlist_append(dlp, dt_cg_node_alloc(lbl_post, DIF_INSTR_NOP)); 970*0Sstevel@tonic-gate } 971*0Sstevel@tonic-gate 972*0Sstevel@tonic-gate static void 973*0Sstevel@tonic-gate dt_cg_asgn_op(dt_node_t *dnp, dt_irlist_t *dlp, dt_regset_t *drp) 974*0Sstevel@tonic-gate { 975*0Sstevel@tonic-gate dif_instr_t instr; 976*0Sstevel@tonic-gate dt_ident_t *idp; 977*0Sstevel@tonic-gate 978*0Sstevel@tonic-gate /* 979*0Sstevel@tonic-gate * If we are performing a structure assignment of a translated type, 980*0Sstevel@tonic-gate * we must instantiate all members and create a snapshot of the object 981*0Sstevel@tonic-gate * in scratch space. We allocs a chunk of memory, generate code for 982*0Sstevel@tonic-gate * each member, and then set dnp->dn_reg to the scratch object address. 983*0Sstevel@tonic-gate */ 984*0Sstevel@tonic-gate if ((idp = dt_node_resolve(dnp->dn_right, DT_IDENT_XLSOU)) != NULL) { 985*0Sstevel@tonic-gate ctf_membinfo_t ctm; 986*0Sstevel@tonic-gate dt_xlator_t *dxp = idp->di_data; 987*0Sstevel@tonic-gate dt_node_t *mnp, dn, mn; 988*0Sstevel@tonic-gate int r1, r2; 989*0Sstevel@tonic-gate 990*0Sstevel@tonic-gate /* 991*0Sstevel@tonic-gate * Create two fake dt_node_t's representing operator "." and a 992*0Sstevel@tonic-gate * right-hand identifier child node. These will be repeatedly 993*0Sstevel@tonic-gate * modified according to each instantiated member so that we 994*0Sstevel@tonic-gate * can pass them to dt_cg_store() and effect a member store. 995*0Sstevel@tonic-gate */ 996*0Sstevel@tonic-gate bzero(&dn, sizeof (dt_node_t)); 997*0Sstevel@tonic-gate dn.dn_kind = DT_NODE_OP2; 998*0Sstevel@tonic-gate dn.dn_op = DT_TOK_DOT; 999*0Sstevel@tonic-gate dn.dn_left = dnp; 1000*0Sstevel@tonic-gate dn.dn_right = &mn; 1001*0Sstevel@tonic-gate 1002*0Sstevel@tonic-gate bzero(&mn, sizeof (dt_node_t)); 1003*0Sstevel@tonic-gate mn.dn_kind = DT_NODE_IDENT; 1004*0Sstevel@tonic-gate mn.dn_op = DT_TOK_IDENT; 1005*0Sstevel@tonic-gate 1006*0Sstevel@tonic-gate /* 1007*0Sstevel@tonic-gate * Allocate a register for our scratch data pointer. First we 1008*0Sstevel@tonic-gate * set it to the size of our data structure, and then replace 1009*0Sstevel@tonic-gate * it with the result of an allocs of the specified size. 1010*0Sstevel@tonic-gate */ 1011*0Sstevel@tonic-gate if ((r1 = dt_regset_alloc(drp)) == -1) 1012*0Sstevel@tonic-gate longjmp(yypcb->pcb_jmpbuf, EDT_NOREG); 1013*0Sstevel@tonic-gate 1014*0Sstevel@tonic-gate dt_cg_setx(dlp, r1, 1015*0Sstevel@tonic-gate ctf_type_size(dxp->dx_dst_ctfp, dxp->dx_dst_base)); 1016*0Sstevel@tonic-gate 1017*0Sstevel@tonic-gate instr = DIF_INSTR_ALLOCS(r1, r1); 1018*0Sstevel@tonic-gate dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr)); 1019*0Sstevel@tonic-gate 1020*0Sstevel@tonic-gate /* 1021*0Sstevel@tonic-gate * When dt_cg_asgn_op() is called, we have already generated 1022*0Sstevel@tonic-gate * code for dnp->dn_right, which is the translator input. We 1023*0Sstevel@tonic-gate * now associate this register with the translator's input 1024*0Sstevel@tonic-gate * identifier so it can be referenced during our member loop. 1025*0Sstevel@tonic-gate */ 1026*0Sstevel@tonic-gate dxp->dx_ident->di_flags |= DT_IDFLG_CGREG; 1027*0Sstevel@tonic-gate dxp->dx_ident->di_id = dnp->dn_right->dn_reg; 1028*0Sstevel@tonic-gate 1029*0Sstevel@tonic-gate for (mnp = dxp->dx_members; mnp != NULL; mnp = mnp->dn_list) { 1030*0Sstevel@tonic-gate /* 1031*0Sstevel@tonic-gate * Generate code for the translator member expression, 1032*0Sstevel@tonic-gate * and then cast the result to the member type. 1033*0Sstevel@tonic-gate */ 1034*0Sstevel@tonic-gate dt_cg_node(mnp->dn_membexpr, dlp, drp); 1035*0Sstevel@tonic-gate mnp->dn_reg = mnp->dn_membexpr->dn_reg; 1036*0Sstevel@tonic-gate dt_cg_typecast(mnp->dn_membexpr, mnp, dlp, drp); 1037*0Sstevel@tonic-gate 1038*0Sstevel@tonic-gate /* 1039*0Sstevel@tonic-gate * Ask CTF for the offset of the member so we can store 1040*0Sstevel@tonic-gate * to the appropriate offset. This call has already 1041*0Sstevel@tonic-gate * been done once by the parser, so it should succeed. 1042*0Sstevel@tonic-gate */ 1043*0Sstevel@tonic-gate if (ctf_member_info(dxp->dx_dst_ctfp, dxp->dx_dst_base, 1044*0Sstevel@tonic-gate mnp->dn_membname, &ctm) == CTF_ERR) { 1045*0Sstevel@tonic-gate yypcb->pcb_hdl->dt_ctferr = 1046*0Sstevel@tonic-gate ctf_errno(dxp->dx_dst_ctfp); 1047*0Sstevel@tonic-gate longjmp(yypcb->pcb_jmpbuf, EDT_CTF); 1048*0Sstevel@tonic-gate } 1049*0Sstevel@tonic-gate 1050*0Sstevel@tonic-gate /* 1051*0Sstevel@tonic-gate * If the destination member is at offset 0, store the 1052*0Sstevel@tonic-gate * result directly to r1 (the scratch buffer address). 1053*0Sstevel@tonic-gate * Otherwise allocate another temporary for the offset 1054*0Sstevel@tonic-gate * and add r1 to it before storing the result. 1055*0Sstevel@tonic-gate */ 1056*0Sstevel@tonic-gate if (ctm.ctm_offset != 0) { 1057*0Sstevel@tonic-gate if ((r2 = dt_regset_alloc(drp)) == -1) 1058*0Sstevel@tonic-gate longjmp(yypcb->pcb_jmpbuf, EDT_NOREG); 1059*0Sstevel@tonic-gate 1060*0Sstevel@tonic-gate /* 1061*0Sstevel@tonic-gate * Add the member offset rounded down to the 1062*0Sstevel@tonic-gate * nearest byte. If the offset was not aligned 1063*0Sstevel@tonic-gate * on a byte boundary, this member is a bit- 1064*0Sstevel@tonic-gate * field and dt_cg_store() will handle masking. 1065*0Sstevel@tonic-gate */ 1066*0Sstevel@tonic-gate dt_cg_setx(dlp, r2, ctm.ctm_offset / NBBY); 1067*0Sstevel@tonic-gate instr = DIF_INSTR_FMT(DIF_OP_ADD, r1, r2, r2); 1068*0Sstevel@tonic-gate dt_irlist_append(dlp, 1069*0Sstevel@tonic-gate dt_cg_node_alloc(DT_LBL_NONE, instr)); 1070*0Sstevel@tonic-gate 1071*0Sstevel@tonic-gate dt_node_type_propagate(mnp, &dn); 1072*0Sstevel@tonic-gate dn.dn_right->dn_string = mnp->dn_membname; 1073*0Sstevel@tonic-gate dn.dn_reg = r2; 1074*0Sstevel@tonic-gate 1075*0Sstevel@tonic-gate dt_cg_store(mnp, dlp, drp, &dn); 1076*0Sstevel@tonic-gate dt_regset_free(drp, r2); 1077*0Sstevel@tonic-gate 1078*0Sstevel@tonic-gate } else { 1079*0Sstevel@tonic-gate dt_node_type_propagate(mnp, &dn); 1080*0Sstevel@tonic-gate dn.dn_right->dn_string = mnp->dn_membname; 1081*0Sstevel@tonic-gate dn.dn_reg = r1; 1082*0Sstevel@tonic-gate 1083*0Sstevel@tonic-gate dt_cg_store(mnp, dlp, drp, &dn); 1084*0Sstevel@tonic-gate } 1085*0Sstevel@tonic-gate 1086*0Sstevel@tonic-gate dt_regset_free(drp, mnp->dn_reg); 1087*0Sstevel@tonic-gate } 1088*0Sstevel@tonic-gate 1089*0Sstevel@tonic-gate dxp->dx_ident->di_flags &= ~DT_IDFLG_CGREG; 1090*0Sstevel@tonic-gate dxp->dx_ident->di_id = 0; 1091*0Sstevel@tonic-gate 1092*0Sstevel@tonic-gate assert(dnp->dn_reg == dnp->dn_right->dn_reg); 1093*0Sstevel@tonic-gate dt_regset_free(drp, dnp->dn_right->dn_reg); 1094*0Sstevel@tonic-gate dnp->dn_reg = r1; 1095*0Sstevel@tonic-gate } 1096*0Sstevel@tonic-gate 1097*0Sstevel@tonic-gate /* 1098*0Sstevel@tonic-gate * If we are storing to a variable, generate an stv instruction from 1099*0Sstevel@tonic-gate * the variable specified by the identifier. If we are storing to a 1100*0Sstevel@tonic-gate * memory address, generate code again for the left-hand side using 1101*0Sstevel@tonic-gate * DT_NF_REF to get the address, and then generate a store to it. 1102*0Sstevel@tonic-gate * In both paths, we assume dnp->dn_reg already has the new value. 1103*0Sstevel@tonic-gate */ 1104*0Sstevel@tonic-gate if (dnp->dn_left->dn_kind == DT_NODE_VAR) { 1105*0Sstevel@tonic-gate idp = dt_ident_resolve(dnp->dn_left->dn_ident); 1106*0Sstevel@tonic-gate 1107*0Sstevel@tonic-gate if (idp->di_kind == DT_IDENT_ARRAY) 1108*0Sstevel@tonic-gate dt_cg_arglist(idp, dnp->dn_left->dn_args, dlp, drp); 1109*0Sstevel@tonic-gate 1110*0Sstevel@tonic-gate idp->di_flags |= DT_IDFLG_DIFW; 1111*0Sstevel@tonic-gate instr = DIF_INSTR_STV(dt_cg_stvar(idp), 1112*0Sstevel@tonic-gate idp->di_id, dnp->dn_reg); 1113*0Sstevel@tonic-gate dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr)); 1114*0Sstevel@tonic-gate } else { 1115*0Sstevel@tonic-gate uint_t rbit = dnp->dn_left->dn_flags & DT_NF_REF; 1116*0Sstevel@tonic-gate 1117*0Sstevel@tonic-gate assert(dnp->dn_left->dn_flags & DT_NF_WRITABLE); 1118*0Sstevel@tonic-gate assert(dnp->dn_left->dn_flags & DT_NF_LVALUE); 1119*0Sstevel@tonic-gate 1120*0Sstevel@tonic-gate dnp->dn_left->dn_flags |= DT_NF_REF; /* force pass-by-ref */ 1121*0Sstevel@tonic-gate 1122*0Sstevel@tonic-gate dt_cg_node(dnp->dn_left, dlp, drp); 1123*0Sstevel@tonic-gate dt_cg_store(dnp, dlp, drp, dnp->dn_left); 1124*0Sstevel@tonic-gate dt_regset_free(drp, dnp->dn_left->dn_reg); 1125*0Sstevel@tonic-gate 1126*0Sstevel@tonic-gate dnp->dn_left->dn_flags &= ~DT_NF_REF; 1127*0Sstevel@tonic-gate dnp->dn_left->dn_flags |= rbit; 1128*0Sstevel@tonic-gate } 1129*0Sstevel@tonic-gate } 1130*0Sstevel@tonic-gate 1131*0Sstevel@tonic-gate static void 1132*0Sstevel@tonic-gate dt_cg_assoc_op(dt_node_t *dnp, dt_irlist_t *dlp, dt_regset_t *drp) 1133*0Sstevel@tonic-gate { 1134*0Sstevel@tonic-gate dif_instr_t instr; 1135*0Sstevel@tonic-gate uint_t op; 1136*0Sstevel@tonic-gate 1137*0Sstevel@tonic-gate assert(dnp->dn_kind == DT_NODE_VAR); 1138*0Sstevel@tonic-gate assert(!(dnp->dn_ident->di_flags & DT_IDFLG_LOCAL)); 1139*0Sstevel@tonic-gate assert(dnp->dn_args != NULL); 1140*0Sstevel@tonic-gate 1141*0Sstevel@tonic-gate dt_cg_arglist(dnp->dn_ident, dnp->dn_args, dlp, drp); 1142*0Sstevel@tonic-gate 1143*0Sstevel@tonic-gate if ((dnp->dn_reg = dt_regset_alloc(drp)) == -1) 1144*0Sstevel@tonic-gate longjmp(yypcb->pcb_jmpbuf, EDT_NOREG); 1145*0Sstevel@tonic-gate 1146*0Sstevel@tonic-gate if (dnp->dn_ident->di_flags & DT_IDFLG_TLS) 1147*0Sstevel@tonic-gate op = DIF_OP_LDTAA; 1148*0Sstevel@tonic-gate else 1149*0Sstevel@tonic-gate op = DIF_OP_LDGAA; 1150*0Sstevel@tonic-gate 1151*0Sstevel@tonic-gate dnp->dn_ident->di_flags |= DT_IDFLG_DIFR; 1152*0Sstevel@tonic-gate instr = DIF_INSTR_LDV(op, dnp->dn_ident->di_id, dnp->dn_reg); 1153*0Sstevel@tonic-gate dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr)); 1154*0Sstevel@tonic-gate 1155*0Sstevel@tonic-gate /* 1156*0Sstevel@tonic-gate * If the associative array is a pass-by-reference type, then we are 1157*0Sstevel@tonic-gate * loading its value as a pointer to either load or store through it. 1158*0Sstevel@tonic-gate * The array element in question may not have been faulted in yet, in 1159*0Sstevel@tonic-gate * which case DIF_OP_LD*AA will return zero. We append an epilogue 1160*0Sstevel@tonic-gate * of instructions similar to the following: 1161*0Sstevel@tonic-gate * 1162*0Sstevel@tonic-gate * ld?aa id, %r1 ! base ld?aa instruction above 1163*0Sstevel@tonic-gate * tst %r1 ! start of epilogue 1164*0Sstevel@tonic-gate * +--- bne label 1165*0Sstevel@tonic-gate * | setx size, %r1 1166*0Sstevel@tonic-gate * | allocs %r1, %r1 1167*0Sstevel@tonic-gate * | st?aa id, %r1 1168*0Sstevel@tonic-gate * | ld?aa id, %r1 1169*0Sstevel@tonic-gate * v 1170*0Sstevel@tonic-gate * label: < rest of code > 1171*0Sstevel@tonic-gate * 1172*0Sstevel@tonic-gate * The idea is that we allocs a zero-filled chunk of scratch space and 1173*0Sstevel@tonic-gate * do a DIF_OP_ST*AA to fault in and initialize the array element, and 1174*0Sstevel@tonic-gate * then reload it to get the faulted-in address of the new variable 1175*0Sstevel@tonic-gate * storage. This isn't cheap, but pass-by-ref associative array values 1176*0Sstevel@tonic-gate * are (thus far) uncommon and the allocs cost only occurs once. If 1177*0Sstevel@tonic-gate * this path becomes important to DTrace users, we can improve things 1178*0Sstevel@tonic-gate * by adding a new DIF opcode to fault in associative array elements. 1179*0Sstevel@tonic-gate */ 1180*0Sstevel@tonic-gate if (dnp->dn_flags & DT_NF_REF) { 1181*0Sstevel@tonic-gate uint_t stvop = op == DIF_OP_LDTAA ? DIF_OP_STTAA : DIF_OP_STGAA; 1182*0Sstevel@tonic-gate uint_t label = dt_irlist_label(dlp); 1183*0Sstevel@tonic-gate 1184*0Sstevel@tonic-gate instr = DIF_INSTR_TST(dnp->dn_reg); 1185*0Sstevel@tonic-gate dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr)); 1186*0Sstevel@tonic-gate 1187*0Sstevel@tonic-gate instr = DIF_INSTR_BRANCH(DIF_OP_BNE, label); 1188*0Sstevel@tonic-gate dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr)); 1189*0Sstevel@tonic-gate 1190*0Sstevel@tonic-gate dt_cg_setx(dlp, dnp->dn_reg, dt_node_type_size(dnp)); 1191*0Sstevel@tonic-gate instr = DIF_INSTR_ALLOCS(dnp->dn_reg, dnp->dn_reg); 1192*0Sstevel@tonic-gate dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr)); 1193*0Sstevel@tonic-gate 1194*0Sstevel@tonic-gate dnp->dn_ident->di_flags |= DT_IDFLG_DIFW; 1195*0Sstevel@tonic-gate instr = DIF_INSTR_STV(stvop, dnp->dn_ident->di_id, dnp->dn_reg); 1196*0Sstevel@tonic-gate dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr)); 1197*0Sstevel@tonic-gate 1198*0Sstevel@tonic-gate instr = DIF_INSTR_LDV(op, dnp->dn_ident->di_id, dnp->dn_reg); 1199*0Sstevel@tonic-gate dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr)); 1200*0Sstevel@tonic-gate 1201*0Sstevel@tonic-gate dt_irlist_append(dlp, dt_cg_node_alloc(label, DIF_INSTR_NOP)); 1202*0Sstevel@tonic-gate } 1203*0Sstevel@tonic-gate } 1204*0Sstevel@tonic-gate 1205*0Sstevel@tonic-gate static void 1206*0Sstevel@tonic-gate dt_cg_array_op(dt_node_t *dnp, dt_irlist_t *dlp, dt_regset_t *drp) 1207*0Sstevel@tonic-gate { 1208*0Sstevel@tonic-gate dt_probe_t *prp = yypcb->pcb_probe; 1209*0Sstevel@tonic-gate uintmax_t saved = dnp->dn_args->dn_value; 1210*0Sstevel@tonic-gate 1211*0Sstevel@tonic-gate dif_instr_t instr; 1212*0Sstevel@tonic-gate uint_t op; 1213*0Sstevel@tonic-gate size_t size; 1214*0Sstevel@tonic-gate int reg, n; 1215*0Sstevel@tonic-gate 1216*0Sstevel@tonic-gate assert(dnp->dn_kind == DT_NODE_VAR); 1217*0Sstevel@tonic-gate assert(!(dnp->dn_ident->di_flags & DT_IDFLG_LOCAL)); 1218*0Sstevel@tonic-gate 1219*0Sstevel@tonic-gate assert(dnp->dn_args->dn_kind == DT_NODE_INT); 1220*0Sstevel@tonic-gate assert(dnp->dn_args->dn_list == NULL); 1221*0Sstevel@tonic-gate 1222*0Sstevel@tonic-gate /* 1223*0Sstevel@tonic-gate * If this is a reference in the args[] array, temporarily modify the 1224*0Sstevel@tonic-gate * array index according to the static argument mapping (if any). 1225*0Sstevel@tonic-gate */ 1226*0Sstevel@tonic-gate if (dnp->dn_ident->di_id == DIF_VAR_ARGS) 1227*0Sstevel@tonic-gate dnp->dn_args->dn_value = prp->pr_mapping[saved]; 1228*0Sstevel@tonic-gate 1229*0Sstevel@tonic-gate dt_cg_node(dnp->dn_args, dlp, drp); 1230*0Sstevel@tonic-gate dnp->dn_args->dn_value = saved; 1231*0Sstevel@tonic-gate 1232*0Sstevel@tonic-gate dnp->dn_reg = dnp->dn_args->dn_reg; 1233*0Sstevel@tonic-gate 1234*0Sstevel@tonic-gate if (dnp->dn_ident->di_flags & DT_IDFLG_TLS) 1235*0Sstevel@tonic-gate op = DIF_OP_LDTA; 1236*0Sstevel@tonic-gate else 1237*0Sstevel@tonic-gate op = DIF_OP_LDGA; 1238*0Sstevel@tonic-gate 1239*0Sstevel@tonic-gate dnp->dn_ident->di_flags |= DT_IDFLG_DIFR; 1240*0Sstevel@tonic-gate 1241*0Sstevel@tonic-gate instr = DIF_INSTR_LDA(op, dnp->dn_ident->di_id, 1242*0Sstevel@tonic-gate dnp->dn_args->dn_reg, dnp->dn_reg); 1243*0Sstevel@tonic-gate 1244*0Sstevel@tonic-gate dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr)); 1245*0Sstevel@tonic-gate 1246*0Sstevel@tonic-gate /* 1247*0Sstevel@tonic-gate * If this is a reference to the args[] array, we need to take the 1248*0Sstevel@tonic-gate * additional step of explicitly eliminating any bits larger than the 1249*0Sstevel@tonic-gate * type size: the DIF interpreter in the kernel will always give us 1250*0Sstevel@tonic-gate * the raw (64-bit) argument value, and any bits larger than the type 1251*0Sstevel@tonic-gate * size may be junk. As a practical matter, this arises only on 64-bit 1252*0Sstevel@tonic-gate * architectures and only when the argument index is larger than the 1253*0Sstevel@tonic-gate * number of arguments passed directly to DTrace: if a 8-, 16- or 1254*0Sstevel@tonic-gate * 32-bit argument must be retrieved from the stack, it is possible 1255*0Sstevel@tonic-gate * (and it some cases, likely) that the upper bits will be garbage. 1256*0Sstevel@tonic-gate */ 1257*0Sstevel@tonic-gate if (dnp->dn_ident->di_id != DIF_VAR_ARGS || !dt_node_is_scalar(dnp)) 1258*0Sstevel@tonic-gate return; 1259*0Sstevel@tonic-gate 1260*0Sstevel@tonic-gate if ((size = dt_node_type_size(dnp)) == sizeof (uint64_t)) 1261*0Sstevel@tonic-gate return; 1262*0Sstevel@tonic-gate 1263*0Sstevel@tonic-gate if ((reg = dt_regset_alloc(drp)) == -1) 1264*0Sstevel@tonic-gate longjmp(yypcb->pcb_jmpbuf, EDT_NOREG); 1265*0Sstevel@tonic-gate 1266*0Sstevel@tonic-gate assert(size < sizeof (uint64_t)); 1267*0Sstevel@tonic-gate n = sizeof (uint64_t) * NBBY - size * NBBY; 1268*0Sstevel@tonic-gate 1269*0Sstevel@tonic-gate dt_cg_setx(dlp, reg, n); 1270*0Sstevel@tonic-gate 1271*0Sstevel@tonic-gate instr = DIF_INSTR_FMT(DIF_OP_SLL, dnp->dn_reg, reg, dnp->dn_reg); 1272*0Sstevel@tonic-gate dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr)); 1273*0Sstevel@tonic-gate 1274*0Sstevel@tonic-gate instr = DIF_INSTR_FMT((dnp->dn_flags & DT_NF_SIGNED) ? 1275*0Sstevel@tonic-gate DIF_OP_SRA : DIF_OP_SRL, dnp->dn_reg, reg, dnp->dn_reg); 1276*0Sstevel@tonic-gate 1277*0Sstevel@tonic-gate dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr)); 1278*0Sstevel@tonic-gate dt_regset_free(drp, reg); 1279*0Sstevel@tonic-gate } 1280*0Sstevel@tonic-gate 1281*0Sstevel@tonic-gate /* 1282*0Sstevel@tonic-gate * Generate code for an inlined variable reference. Inlines can be used to 1283*0Sstevel@tonic-gate * define either scalar or associative array substitutions. For scalars, we 1284*0Sstevel@tonic-gate * simply generate code for the parse tree saved in the identifier's din_root, 1285*0Sstevel@tonic-gate * and then cast the resulting expression to the inline's declaration type. 1286*0Sstevel@tonic-gate * For arrays, we take the input parameter subtrees from dnp->dn_args and 1287*0Sstevel@tonic-gate * temporarily store them in the din_root of each din_argv[i] identifier, 1288*0Sstevel@tonic-gate * which are themselves inlines and were set up for us by the parser. The 1289*0Sstevel@tonic-gate * result is that any reference to the inlined parameter inside the top-level 1290*0Sstevel@tonic-gate * din_root will turn into a recursive call to dt_cg_inline() for a scalar 1291*0Sstevel@tonic-gate * inline whose din_root will refer to the subtree pointed to by the argument. 1292*0Sstevel@tonic-gate */ 1293*0Sstevel@tonic-gate static void 1294*0Sstevel@tonic-gate dt_cg_inline(dt_node_t *dnp, dt_irlist_t *dlp, dt_regset_t *drp) 1295*0Sstevel@tonic-gate { 1296*0Sstevel@tonic-gate dt_ident_t *idp = dnp->dn_ident; 1297*0Sstevel@tonic-gate dt_idnode_t *inp = idp->di_iarg; 1298*0Sstevel@tonic-gate 1299*0Sstevel@tonic-gate dt_idnode_t *pinp; 1300*0Sstevel@tonic-gate dt_node_t *pnp; 1301*0Sstevel@tonic-gate int i; 1302*0Sstevel@tonic-gate 1303*0Sstevel@tonic-gate assert(idp->di_flags & DT_IDFLG_INLINE); 1304*0Sstevel@tonic-gate assert(idp->di_ops == &dt_idops_inline); 1305*0Sstevel@tonic-gate 1306*0Sstevel@tonic-gate if (idp->di_kind == DT_IDENT_ARRAY) { 1307*0Sstevel@tonic-gate for (i = 0, pnp = dnp->dn_args; 1308*0Sstevel@tonic-gate pnp != NULL; pnp = pnp->dn_list, i++) { 1309*0Sstevel@tonic-gate if (inp->din_argv[i] != NULL) { 1310*0Sstevel@tonic-gate pinp = inp->din_argv[i]->di_iarg; 1311*0Sstevel@tonic-gate pinp->din_root = pnp; 1312*0Sstevel@tonic-gate } 1313*0Sstevel@tonic-gate } 1314*0Sstevel@tonic-gate } 1315*0Sstevel@tonic-gate 1316*0Sstevel@tonic-gate dt_cg_node(inp->din_root, dlp, drp); 1317*0Sstevel@tonic-gate dnp->dn_reg = inp->din_root->dn_reg; 1318*0Sstevel@tonic-gate dt_cg_typecast(inp->din_root, dnp, dlp, drp); 1319*0Sstevel@tonic-gate 1320*0Sstevel@tonic-gate if (idp->di_kind == DT_IDENT_ARRAY) { 1321*0Sstevel@tonic-gate for (i = 0; i < inp->din_argc; i++) { 1322*0Sstevel@tonic-gate pinp = inp->din_argv[i]->di_iarg; 1323*0Sstevel@tonic-gate pinp->din_root = NULL; 1324*0Sstevel@tonic-gate } 1325*0Sstevel@tonic-gate } 1326*0Sstevel@tonic-gate } 1327*0Sstevel@tonic-gate 1328*0Sstevel@tonic-gate static void 1329*0Sstevel@tonic-gate dt_cg_node(dt_node_t *dnp, dt_irlist_t *dlp, dt_regset_t *drp) 1330*0Sstevel@tonic-gate { 1331*0Sstevel@tonic-gate ctf_file_t *ctfp = dnp->dn_ctfp; 1332*0Sstevel@tonic-gate ctf_file_t *octfp; 1333*0Sstevel@tonic-gate ctf_membinfo_t m; 1334*0Sstevel@tonic-gate ctf_id_t type; 1335*0Sstevel@tonic-gate 1336*0Sstevel@tonic-gate dif_instr_t instr; 1337*0Sstevel@tonic-gate dt_ident_t *idp; 1338*0Sstevel@tonic-gate ssize_t stroff; 1339*0Sstevel@tonic-gate uint_t op; 1340*0Sstevel@tonic-gate int reg; 1341*0Sstevel@tonic-gate 1342*0Sstevel@tonic-gate switch (dnp->dn_op) { 1343*0Sstevel@tonic-gate case DT_TOK_COMMA: 1344*0Sstevel@tonic-gate dt_cg_node(dnp->dn_left, dlp, drp); 1345*0Sstevel@tonic-gate dt_regset_free(drp, dnp->dn_left->dn_reg); 1346*0Sstevel@tonic-gate dt_cg_node(dnp->dn_right, dlp, drp); 1347*0Sstevel@tonic-gate dnp->dn_reg = dnp->dn_right->dn_reg; 1348*0Sstevel@tonic-gate break; 1349*0Sstevel@tonic-gate 1350*0Sstevel@tonic-gate case DT_TOK_ASGN: 1351*0Sstevel@tonic-gate dt_cg_node(dnp->dn_right, dlp, drp); 1352*0Sstevel@tonic-gate dnp->dn_reg = dnp->dn_right->dn_reg; 1353*0Sstevel@tonic-gate dt_cg_asgn_op(dnp, dlp, drp); 1354*0Sstevel@tonic-gate break; 1355*0Sstevel@tonic-gate 1356*0Sstevel@tonic-gate case DT_TOK_ADD_EQ: 1357*0Sstevel@tonic-gate dt_cg_arithmetic_op(dnp, dlp, drp, DIF_OP_ADD); 1358*0Sstevel@tonic-gate dt_cg_asgn_op(dnp, dlp, drp); 1359*0Sstevel@tonic-gate break; 1360*0Sstevel@tonic-gate 1361*0Sstevel@tonic-gate case DT_TOK_SUB_EQ: 1362*0Sstevel@tonic-gate dt_cg_arithmetic_op(dnp, dlp, drp, DIF_OP_SUB); 1363*0Sstevel@tonic-gate dt_cg_asgn_op(dnp, dlp, drp); 1364*0Sstevel@tonic-gate break; 1365*0Sstevel@tonic-gate 1366*0Sstevel@tonic-gate case DT_TOK_MUL_EQ: 1367*0Sstevel@tonic-gate dt_cg_arithmetic_op(dnp, dlp, drp, DIF_OP_MUL); 1368*0Sstevel@tonic-gate dt_cg_asgn_op(dnp, dlp, drp); 1369*0Sstevel@tonic-gate break; 1370*0Sstevel@tonic-gate 1371*0Sstevel@tonic-gate case DT_TOK_DIV_EQ: 1372*0Sstevel@tonic-gate dt_cg_arithmetic_op(dnp, dlp, drp, 1373*0Sstevel@tonic-gate (dnp->dn_flags & DT_NF_SIGNED) ? DIF_OP_SDIV : DIF_OP_UDIV); 1374*0Sstevel@tonic-gate dt_cg_asgn_op(dnp, dlp, drp); 1375*0Sstevel@tonic-gate break; 1376*0Sstevel@tonic-gate 1377*0Sstevel@tonic-gate case DT_TOK_MOD_EQ: 1378*0Sstevel@tonic-gate dt_cg_arithmetic_op(dnp, dlp, drp, 1379*0Sstevel@tonic-gate (dnp->dn_flags & DT_NF_SIGNED) ? DIF_OP_SREM : DIF_OP_UREM); 1380*0Sstevel@tonic-gate dt_cg_asgn_op(dnp, dlp, drp); 1381*0Sstevel@tonic-gate break; 1382*0Sstevel@tonic-gate 1383*0Sstevel@tonic-gate case DT_TOK_AND_EQ: 1384*0Sstevel@tonic-gate dt_cg_arithmetic_op(dnp, dlp, drp, DIF_OP_AND); 1385*0Sstevel@tonic-gate dt_cg_asgn_op(dnp, dlp, drp); 1386*0Sstevel@tonic-gate break; 1387*0Sstevel@tonic-gate 1388*0Sstevel@tonic-gate case DT_TOK_XOR_EQ: 1389*0Sstevel@tonic-gate dt_cg_arithmetic_op(dnp, dlp, drp, DIF_OP_XOR); 1390*0Sstevel@tonic-gate dt_cg_asgn_op(dnp, dlp, drp); 1391*0Sstevel@tonic-gate break; 1392*0Sstevel@tonic-gate 1393*0Sstevel@tonic-gate case DT_TOK_OR_EQ: 1394*0Sstevel@tonic-gate dt_cg_arithmetic_op(dnp, dlp, drp, DIF_OP_OR); 1395*0Sstevel@tonic-gate dt_cg_asgn_op(dnp, dlp, drp); 1396*0Sstevel@tonic-gate break; 1397*0Sstevel@tonic-gate 1398*0Sstevel@tonic-gate case DT_TOK_LSH_EQ: 1399*0Sstevel@tonic-gate dt_cg_arithmetic_op(dnp, dlp, drp, DIF_OP_SLL); 1400*0Sstevel@tonic-gate dt_cg_asgn_op(dnp, dlp, drp); 1401*0Sstevel@tonic-gate break; 1402*0Sstevel@tonic-gate 1403*0Sstevel@tonic-gate case DT_TOK_RSH_EQ: 1404*0Sstevel@tonic-gate dt_cg_arithmetic_op(dnp, dlp, drp, 1405*0Sstevel@tonic-gate (dnp->dn_flags & DT_NF_SIGNED) ? DIF_OP_SRA : DIF_OP_SRL); 1406*0Sstevel@tonic-gate dt_cg_asgn_op(dnp, dlp, drp); 1407*0Sstevel@tonic-gate break; 1408*0Sstevel@tonic-gate 1409*0Sstevel@tonic-gate case DT_TOK_QUESTION: 1410*0Sstevel@tonic-gate dt_cg_ternary_op(dnp, dlp, drp); 1411*0Sstevel@tonic-gate break; 1412*0Sstevel@tonic-gate 1413*0Sstevel@tonic-gate case DT_TOK_LOR: 1414*0Sstevel@tonic-gate dt_cg_logical_or(dnp, dlp, drp); 1415*0Sstevel@tonic-gate break; 1416*0Sstevel@tonic-gate 1417*0Sstevel@tonic-gate case DT_TOK_LXOR: 1418*0Sstevel@tonic-gate dt_cg_logical_xor(dnp, dlp, drp); 1419*0Sstevel@tonic-gate break; 1420*0Sstevel@tonic-gate 1421*0Sstevel@tonic-gate case DT_TOK_LAND: 1422*0Sstevel@tonic-gate dt_cg_logical_and(dnp, dlp, drp); 1423*0Sstevel@tonic-gate break; 1424*0Sstevel@tonic-gate 1425*0Sstevel@tonic-gate case DT_TOK_BOR: 1426*0Sstevel@tonic-gate dt_cg_arithmetic_op(dnp, dlp, drp, DIF_OP_OR); 1427*0Sstevel@tonic-gate break; 1428*0Sstevel@tonic-gate 1429*0Sstevel@tonic-gate case DT_TOK_XOR: 1430*0Sstevel@tonic-gate dt_cg_arithmetic_op(dnp, dlp, drp, DIF_OP_XOR); 1431*0Sstevel@tonic-gate break; 1432*0Sstevel@tonic-gate 1433*0Sstevel@tonic-gate case DT_TOK_BAND: 1434*0Sstevel@tonic-gate dt_cg_arithmetic_op(dnp, dlp, drp, DIF_OP_AND); 1435*0Sstevel@tonic-gate break; 1436*0Sstevel@tonic-gate 1437*0Sstevel@tonic-gate case DT_TOK_EQU: 1438*0Sstevel@tonic-gate dt_cg_compare_op(dnp, dlp, drp, DIF_OP_BE); 1439*0Sstevel@tonic-gate break; 1440*0Sstevel@tonic-gate 1441*0Sstevel@tonic-gate case DT_TOK_NEQ: 1442*0Sstevel@tonic-gate dt_cg_compare_op(dnp, dlp, drp, DIF_OP_BNE); 1443*0Sstevel@tonic-gate break; 1444*0Sstevel@tonic-gate 1445*0Sstevel@tonic-gate case DT_TOK_LT: 1446*0Sstevel@tonic-gate dt_cg_compare_op(dnp, dlp, drp, 1447*0Sstevel@tonic-gate dt_cg_compare_signed(dnp) ? DIF_OP_BL : DIF_OP_BLU); 1448*0Sstevel@tonic-gate break; 1449*0Sstevel@tonic-gate 1450*0Sstevel@tonic-gate case DT_TOK_LE: 1451*0Sstevel@tonic-gate dt_cg_compare_op(dnp, dlp, drp, 1452*0Sstevel@tonic-gate dt_cg_compare_signed(dnp) ? DIF_OP_BLE : DIF_OP_BLEU); 1453*0Sstevel@tonic-gate break; 1454*0Sstevel@tonic-gate 1455*0Sstevel@tonic-gate case DT_TOK_GT: 1456*0Sstevel@tonic-gate dt_cg_compare_op(dnp, dlp, drp, 1457*0Sstevel@tonic-gate dt_cg_compare_signed(dnp) ? DIF_OP_BG : DIF_OP_BGU); 1458*0Sstevel@tonic-gate break; 1459*0Sstevel@tonic-gate 1460*0Sstevel@tonic-gate case DT_TOK_GE: 1461*0Sstevel@tonic-gate dt_cg_compare_op(dnp, dlp, drp, 1462*0Sstevel@tonic-gate dt_cg_compare_signed(dnp) ? DIF_OP_BGE : DIF_OP_BGEU); 1463*0Sstevel@tonic-gate break; 1464*0Sstevel@tonic-gate 1465*0Sstevel@tonic-gate case DT_TOK_LSH: 1466*0Sstevel@tonic-gate dt_cg_arithmetic_op(dnp, dlp, drp, DIF_OP_SLL); 1467*0Sstevel@tonic-gate break; 1468*0Sstevel@tonic-gate 1469*0Sstevel@tonic-gate case DT_TOK_RSH: 1470*0Sstevel@tonic-gate dt_cg_arithmetic_op(dnp, dlp, drp, 1471*0Sstevel@tonic-gate (dnp->dn_flags & DT_NF_SIGNED) ? DIF_OP_SRA : DIF_OP_SRL); 1472*0Sstevel@tonic-gate break; 1473*0Sstevel@tonic-gate 1474*0Sstevel@tonic-gate case DT_TOK_ADD: 1475*0Sstevel@tonic-gate dt_cg_arithmetic_op(dnp, dlp, drp, DIF_OP_ADD); 1476*0Sstevel@tonic-gate break; 1477*0Sstevel@tonic-gate 1478*0Sstevel@tonic-gate case DT_TOK_SUB: 1479*0Sstevel@tonic-gate dt_cg_arithmetic_op(dnp, dlp, drp, DIF_OP_SUB); 1480*0Sstevel@tonic-gate break; 1481*0Sstevel@tonic-gate 1482*0Sstevel@tonic-gate case DT_TOK_MUL: 1483*0Sstevel@tonic-gate dt_cg_arithmetic_op(dnp, dlp, drp, DIF_OP_MUL); 1484*0Sstevel@tonic-gate break; 1485*0Sstevel@tonic-gate 1486*0Sstevel@tonic-gate case DT_TOK_DIV: 1487*0Sstevel@tonic-gate dt_cg_arithmetic_op(dnp, dlp, drp, 1488*0Sstevel@tonic-gate (dnp->dn_flags & DT_NF_SIGNED) ? DIF_OP_SDIV : DIF_OP_UDIV); 1489*0Sstevel@tonic-gate break; 1490*0Sstevel@tonic-gate 1491*0Sstevel@tonic-gate case DT_TOK_MOD: 1492*0Sstevel@tonic-gate dt_cg_arithmetic_op(dnp, dlp, drp, 1493*0Sstevel@tonic-gate (dnp->dn_flags & DT_NF_SIGNED) ? DIF_OP_SREM : DIF_OP_UREM); 1494*0Sstevel@tonic-gate break; 1495*0Sstevel@tonic-gate 1496*0Sstevel@tonic-gate case DT_TOK_LNEG: 1497*0Sstevel@tonic-gate dt_cg_logical_neg(dnp, dlp, drp); 1498*0Sstevel@tonic-gate break; 1499*0Sstevel@tonic-gate 1500*0Sstevel@tonic-gate case DT_TOK_BNEG: 1501*0Sstevel@tonic-gate dt_cg_node(dnp->dn_child, dlp, drp); 1502*0Sstevel@tonic-gate dnp->dn_reg = dnp->dn_child->dn_reg; 1503*0Sstevel@tonic-gate instr = DIF_INSTR_NOT(dnp->dn_reg, dnp->dn_reg); 1504*0Sstevel@tonic-gate dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr)); 1505*0Sstevel@tonic-gate break; 1506*0Sstevel@tonic-gate 1507*0Sstevel@tonic-gate case DT_TOK_PREINC: 1508*0Sstevel@tonic-gate dt_cg_prearith_op(dnp, dlp, drp, DIF_OP_ADD); 1509*0Sstevel@tonic-gate break; 1510*0Sstevel@tonic-gate 1511*0Sstevel@tonic-gate case DT_TOK_POSTINC: 1512*0Sstevel@tonic-gate dt_cg_postarith_op(dnp, dlp, drp, DIF_OP_ADD); 1513*0Sstevel@tonic-gate break; 1514*0Sstevel@tonic-gate 1515*0Sstevel@tonic-gate case DT_TOK_PREDEC: 1516*0Sstevel@tonic-gate dt_cg_prearith_op(dnp, dlp, drp, DIF_OP_SUB); 1517*0Sstevel@tonic-gate break; 1518*0Sstevel@tonic-gate 1519*0Sstevel@tonic-gate case DT_TOK_POSTDEC: 1520*0Sstevel@tonic-gate dt_cg_postarith_op(dnp, dlp, drp, DIF_OP_SUB); 1521*0Sstevel@tonic-gate break; 1522*0Sstevel@tonic-gate 1523*0Sstevel@tonic-gate case DT_TOK_IPOS: 1524*0Sstevel@tonic-gate dt_cg_node(dnp->dn_child, dlp, drp); 1525*0Sstevel@tonic-gate dnp->dn_reg = dnp->dn_child->dn_reg; 1526*0Sstevel@tonic-gate break; 1527*0Sstevel@tonic-gate 1528*0Sstevel@tonic-gate case DT_TOK_INEG: 1529*0Sstevel@tonic-gate dt_cg_node(dnp->dn_child, dlp, drp); 1530*0Sstevel@tonic-gate dnp->dn_reg = dnp->dn_child->dn_reg; 1531*0Sstevel@tonic-gate 1532*0Sstevel@tonic-gate instr = DIF_INSTR_FMT(DIF_OP_SUB, DIF_REG_R0, 1533*0Sstevel@tonic-gate dnp->dn_reg, dnp->dn_reg); 1534*0Sstevel@tonic-gate 1535*0Sstevel@tonic-gate dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr)); 1536*0Sstevel@tonic-gate break; 1537*0Sstevel@tonic-gate 1538*0Sstevel@tonic-gate case DT_TOK_DEREF: 1539*0Sstevel@tonic-gate dt_cg_node(dnp->dn_child, dlp, drp); 1540*0Sstevel@tonic-gate dnp->dn_reg = dnp->dn_child->dn_reg; 1541*0Sstevel@tonic-gate 1542*0Sstevel@tonic-gate if (!(dnp->dn_flags & DT_NF_REF)) { 1543*0Sstevel@tonic-gate uint_t ubit = dnp->dn_flags & DT_NF_USERLAND; 1544*0Sstevel@tonic-gate 1545*0Sstevel@tonic-gate /* 1546*0Sstevel@tonic-gate * Save and restore DT_NF_USERLAND across dt_cg_load(): 1547*0Sstevel@tonic-gate * we need the sign bit from dnp and the user bit from 1548*0Sstevel@tonic-gate * dnp->dn_child in order to get the proper opcode. 1549*0Sstevel@tonic-gate */ 1550*0Sstevel@tonic-gate dnp->dn_flags |= 1551*0Sstevel@tonic-gate (dnp->dn_child->dn_flags & DT_NF_USERLAND); 1552*0Sstevel@tonic-gate 1553*0Sstevel@tonic-gate instr = DIF_INSTR_LOAD(dt_cg_load(dnp, ctfp, 1554*0Sstevel@tonic-gate dnp->dn_type), dnp->dn_reg, dnp->dn_reg); 1555*0Sstevel@tonic-gate 1556*0Sstevel@tonic-gate dnp->dn_flags &= ~DT_NF_USERLAND; 1557*0Sstevel@tonic-gate dnp->dn_flags |= ubit; 1558*0Sstevel@tonic-gate 1559*0Sstevel@tonic-gate dt_irlist_append(dlp, 1560*0Sstevel@tonic-gate dt_cg_node_alloc(DT_LBL_NONE, instr)); 1561*0Sstevel@tonic-gate } 1562*0Sstevel@tonic-gate break; 1563*0Sstevel@tonic-gate 1564*0Sstevel@tonic-gate case DT_TOK_ADDROF: { 1565*0Sstevel@tonic-gate uint_t rbit = dnp->dn_child->dn_flags & DT_NF_REF; 1566*0Sstevel@tonic-gate 1567*0Sstevel@tonic-gate dnp->dn_child->dn_flags |= DT_NF_REF; /* force pass-by-ref */ 1568*0Sstevel@tonic-gate dt_cg_node(dnp->dn_child, dlp, drp); 1569*0Sstevel@tonic-gate dnp->dn_reg = dnp->dn_child->dn_reg; 1570*0Sstevel@tonic-gate 1571*0Sstevel@tonic-gate dnp->dn_child->dn_flags &= ~DT_NF_REF; 1572*0Sstevel@tonic-gate dnp->dn_child->dn_flags |= rbit; 1573*0Sstevel@tonic-gate break; 1574*0Sstevel@tonic-gate } 1575*0Sstevel@tonic-gate 1576*0Sstevel@tonic-gate case DT_TOK_SIZEOF: { 1577*0Sstevel@tonic-gate size_t size = dt_node_sizeof(dnp->dn_child); 1578*0Sstevel@tonic-gate 1579*0Sstevel@tonic-gate if ((dnp->dn_reg = dt_regset_alloc(drp)) == -1) 1580*0Sstevel@tonic-gate longjmp(yypcb->pcb_jmpbuf, EDT_NOREG); 1581*0Sstevel@tonic-gate 1582*0Sstevel@tonic-gate assert(size != 0); 1583*0Sstevel@tonic-gate dt_cg_setx(dlp, dnp->dn_reg, size); 1584*0Sstevel@tonic-gate break; 1585*0Sstevel@tonic-gate } 1586*0Sstevel@tonic-gate 1587*0Sstevel@tonic-gate case DT_TOK_STRINGOF: 1588*0Sstevel@tonic-gate dt_cg_node(dnp->dn_child, dlp, drp); 1589*0Sstevel@tonic-gate dnp->dn_reg = dnp->dn_child->dn_reg; 1590*0Sstevel@tonic-gate break; 1591*0Sstevel@tonic-gate 1592*0Sstevel@tonic-gate case DT_TOK_XLATE: 1593*0Sstevel@tonic-gate dt_cg_node(dnp->dn_right, dlp, drp); 1594*0Sstevel@tonic-gate dnp->dn_reg = dnp->dn_right->dn_reg; 1595*0Sstevel@tonic-gate break; 1596*0Sstevel@tonic-gate 1597*0Sstevel@tonic-gate case DT_TOK_LPAR: 1598*0Sstevel@tonic-gate dt_cg_node(dnp->dn_right, dlp, drp); 1599*0Sstevel@tonic-gate dnp->dn_reg = dnp->dn_right->dn_reg; 1600*0Sstevel@tonic-gate dt_cg_typecast(dnp->dn_right, dnp, dlp, drp); 1601*0Sstevel@tonic-gate break; 1602*0Sstevel@tonic-gate 1603*0Sstevel@tonic-gate case DT_TOK_PTR: 1604*0Sstevel@tonic-gate case DT_TOK_DOT: 1605*0Sstevel@tonic-gate assert(dnp->dn_right->dn_kind == DT_NODE_IDENT); 1606*0Sstevel@tonic-gate dt_cg_node(dnp->dn_left, dlp, drp); 1607*0Sstevel@tonic-gate 1608*0Sstevel@tonic-gate /* 1609*0Sstevel@tonic-gate * If the left-hand side of PTR or DOT is a dynamic variable, 1610*0Sstevel@tonic-gate * we expect it to be the output of a D translator. In this 1611*0Sstevel@tonic-gate * case, we look up the parse tree corresponding to the member 1612*0Sstevel@tonic-gate * that is being accessed and run the code generator over it. 1613*0Sstevel@tonic-gate * We then cast the result as if by the assignment operator. 1614*0Sstevel@tonic-gate */ 1615*0Sstevel@tonic-gate if ((idp = dt_node_resolve( 1616*0Sstevel@tonic-gate dnp->dn_left, DT_IDENT_XLSOU)) != NULL || 1617*0Sstevel@tonic-gate (idp = dt_node_resolve( 1618*0Sstevel@tonic-gate dnp->dn_left, DT_IDENT_XLPTR)) != NULL) { 1619*0Sstevel@tonic-gate 1620*0Sstevel@tonic-gate dt_xlator_t *dxp; 1621*0Sstevel@tonic-gate dt_node_t *mnp; 1622*0Sstevel@tonic-gate 1623*0Sstevel@tonic-gate dxp = idp->di_data; 1624*0Sstevel@tonic-gate mnp = dt_xlator_member(dxp, dnp->dn_right->dn_string); 1625*0Sstevel@tonic-gate assert(mnp != NULL); 1626*0Sstevel@tonic-gate 1627*0Sstevel@tonic-gate dxp->dx_ident->di_flags |= DT_IDFLG_CGREG; 1628*0Sstevel@tonic-gate dxp->dx_ident->di_id = dnp->dn_left->dn_reg; 1629*0Sstevel@tonic-gate 1630*0Sstevel@tonic-gate dt_cg_node(mnp->dn_membexpr, dlp, drp); 1631*0Sstevel@tonic-gate dnp->dn_reg = mnp->dn_membexpr->dn_reg; 1632*0Sstevel@tonic-gate dt_cg_typecast(mnp->dn_membexpr, dnp, dlp, drp); 1633*0Sstevel@tonic-gate 1634*0Sstevel@tonic-gate dxp->dx_ident->di_flags &= ~DT_IDFLG_CGREG; 1635*0Sstevel@tonic-gate dxp->dx_ident->di_id = 0; 1636*0Sstevel@tonic-gate 1637*0Sstevel@tonic-gate dt_regset_free(drp, dnp->dn_left->dn_reg); 1638*0Sstevel@tonic-gate break; 1639*0Sstevel@tonic-gate } 1640*0Sstevel@tonic-gate 1641*0Sstevel@tonic-gate ctfp = dnp->dn_left->dn_ctfp; 1642*0Sstevel@tonic-gate type = ctf_type_resolve(ctfp, dnp->dn_left->dn_type); 1643*0Sstevel@tonic-gate 1644*0Sstevel@tonic-gate if (dnp->dn_op == DT_TOK_PTR) { 1645*0Sstevel@tonic-gate type = ctf_type_reference(ctfp, type); 1646*0Sstevel@tonic-gate type = ctf_type_resolve(ctfp, type); 1647*0Sstevel@tonic-gate } 1648*0Sstevel@tonic-gate 1649*0Sstevel@tonic-gate if ((ctfp = dt_cg_membinfo(octfp = ctfp, type, 1650*0Sstevel@tonic-gate dnp->dn_right->dn_string, &m)) == NULL) { 1651*0Sstevel@tonic-gate yypcb->pcb_hdl->dt_ctferr = ctf_errno(octfp); 1652*0Sstevel@tonic-gate longjmp(yypcb->pcb_jmpbuf, EDT_CTF); 1653*0Sstevel@tonic-gate } 1654*0Sstevel@tonic-gate 1655*0Sstevel@tonic-gate if (m.ctm_offset != 0) { 1656*0Sstevel@tonic-gate if ((reg = dt_regset_alloc(drp)) == -1) 1657*0Sstevel@tonic-gate longjmp(yypcb->pcb_jmpbuf, EDT_NOREG); 1658*0Sstevel@tonic-gate 1659*0Sstevel@tonic-gate /* 1660*0Sstevel@tonic-gate * If the offset is not aligned on a byte boundary, it 1661*0Sstevel@tonic-gate * is a bit-field member and we will extract the value 1662*0Sstevel@tonic-gate * bits below after we generate the appropriate load. 1663*0Sstevel@tonic-gate */ 1664*0Sstevel@tonic-gate dt_cg_setx(dlp, reg, m.ctm_offset / NBBY); 1665*0Sstevel@tonic-gate 1666*0Sstevel@tonic-gate instr = DIF_INSTR_FMT(DIF_OP_ADD, 1667*0Sstevel@tonic-gate dnp->dn_left->dn_reg, reg, dnp->dn_left->dn_reg); 1668*0Sstevel@tonic-gate 1669*0Sstevel@tonic-gate dt_irlist_append(dlp, 1670*0Sstevel@tonic-gate dt_cg_node_alloc(DT_LBL_NONE, instr)); 1671*0Sstevel@tonic-gate dt_regset_free(drp, reg); 1672*0Sstevel@tonic-gate } 1673*0Sstevel@tonic-gate 1674*0Sstevel@tonic-gate if (!(dnp->dn_flags & DT_NF_REF)) { 1675*0Sstevel@tonic-gate uint_t ubit = dnp->dn_flags & DT_NF_USERLAND; 1676*0Sstevel@tonic-gate 1677*0Sstevel@tonic-gate /* 1678*0Sstevel@tonic-gate * Save and restore DT_NF_USERLAND across dt_cg_load(): 1679*0Sstevel@tonic-gate * we need the sign bit from dnp and the user bit from 1680*0Sstevel@tonic-gate * dnp->dn_left in order to get the proper opcode. 1681*0Sstevel@tonic-gate */ 1682*0Sstevel@tonic-gate dnp->dn_flags |= 1683*0Sstevel@tonic-gate (dnp->dn_left->dn_flags & DT_NF_USERLAND); 1684*0Sstevel@tonic-gate 1685*0Sstevel@tonic-gate instr = DIF_INSTR_LOAD(dt_cg_load(dnp, 1686*0Sstevel@tonic-gate ctfp, m.ctm_type), dnp->dn_left->dn_reg, 1687*0Sstevel@tonic-gate dnp->dn_left->dn_reg); 1688*0Sstevel@tonic-gate 1689*0Sstevel@tonic-gate dnp->dn_flags &= ~DT_NF_USERLAND; 1690*0Sstevel@tonic-gate dnp->dn_flags |= ubit; 1691*0Sstevel@tonic-gate 1692*0Sstevel@tonic-gate dt_irlist_append(dlp, 1693*0Sstevel@tonic-gate dt_cg_node_alloc(DT_LBL_NONE, instr)); 1694*0Sstevel@tonic-gate 1695*0Sstevel@tonic-gate if (dnp->dn_flags & DT_NF_BITFIELD) 1696*0Sstevel@tonic-gate dt_cg_field_get(dnp, dlp, drp, ctfp, &m); 1697*0Sstevel@tonic-gate } 1698*0Sstevel@tonic-gate 1699*0Sstevel@tonic-gate dnp->dn_reg = dnp->dn_left->dn_reg; 1700*0Sstevel@tonic-gate break; 1701*0Sstevel@tonic-gate 1702*0Sstevel@tonic-gate case DT_TOK_STRING: 1703*0Sstevel@tonic-gate if ((dnp->dn_reg = dt_regset_alloc(drp)) == -1) 1704*0Sstevel@tonic-gate longjmp(yypcb->pcb_jmpbuf, EDT_NOREG); 1705*0Sstevel@tonic-gate 1706*0Sstevel@tonic-gate assert(dnp->dn_kind == DT_NODE_STRING); 1707*0Sstevel@tonic-gate stroff = dt_strtab_insert(yypcb->pcb_strtab, dnp->dn_string); 1708*0Sstevel@tonic-gate 1709*0Sstevel@tonic-gate if (stroff == -1L) 1710*0Sstevel@tonic-gate longjmp(yypcb->pcb_jmpbuf, EDT_NOMEM); 1711*0Sstevel@tonic-gate if (stroff > DIF_STROFF_MAX) 1712*0Sstevel@tonic-gate longjmp(yypcb->pcb_jmpbuf, EDT_STR2BIG); 1713*0Sstevel@tonic-gate 1714*0Sstevel@tonic-gate instr = DIF_INSTR_SETS((ulong_t)stroff, dnp->dn_reg); 1715*0Sstevel@tonic-gate dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr)); 1716*0Sstevel@tonic-gate break; 1717*0Sstevel@tonic-gate 1718*0Sstevel@tonic-gate case DT_TOK_IDENT: 1719*0Sstevel@tonic-gate /* 1720*0Sstevel@tonic-gate * If the specified identifier is a variable on which we have 1721*0Sstevel@tonic-gate * set the code generator register flag, then this variable 1722*0Sstevel@tonic-gate * has already had code generated for it and saved in di_id. 1723*0Sstevel@tonic-gate * Allocate a new register and copy the existing value to it. 1724*0Sstevel@tonic-gate */ 1725*0Sstevel@tonic-gate if (dnp->dn_kind == DT_NODE_VAR && 1726*0Sstevel@tonic-gate (dnp->dn_ident->di_flags & DT_IDFLG_CGREG)) { 1727*0Sstevel@tonic-gate if ((dnp->dn_reg = dt_regset_alloc(drp)) == -1) 1728*0Sstevel@tonic-gate longjmp(yypcb->pcb_jmpbuf, EDT_NOREG); 1729*0Sstevel@tonic-gate instr = DIF_INSTR_MOV(dnp->dn_ident->di_id, 1730*0Sstevel@tonic-gate dnp->dn_reg); 1731*0Sstevel@tonic-gate dt_irlist_append(dlp, 1732*0Sstevel@tonic-gate dt_cg_node_alloc(DT_LBL_NONE, instr)); 1733*0Sstevel@tonic-gate break; 1734*0Sstevel@tonic-gate } 1735*0Sstevel@tonic-gate 1736*0Sstevel@tonic-gate /* 1737*0Sstevel@tonic-gate * Identifiers can represent function calls, variable refs, or 1738*0Sstevel@tonic-gate * symbols. First we check for inlined variables, and handle 1739*0Sstevel@tonic-gate * them by generating code for the inline parse tree. 1740*0Sstevel@tonic-gate */ 1741*0Sstevel@tonic-gate if (dnp->dn_kind == DT_NODE_VAR && 1742*0Sstevel@tonic-gate (dnp->dn_ident->di_flags & DT_IDFLG_INLINE)) { 1743*0Sstevel@tonic-gate dt_cg_inline(dnp, dlp, drp); 1744*0Sstevel@tonic-gate break; 1745*0Sstevel@tonic-gate } 1746*0Sstevel@tonic-gate 1747*0Sstevel@tonic-gate switch (dnp->dn_kind) { 1748*0Sstevel@tonic-gate case DT_NODE_FUNC: 1749*0Sstevel@tonic-gate if ((idp = dnp->dn_ident)->di_kind != DT_IDENT_FUNC) { 1750*0Sstevel@tonic-gate dnerror(dnp, D_CG_EXPR, "%s %s( ) may not be " 1751*0Sstevel@tonic-gate "called from a D expression (D program " 1752*0Sstevel@tonic-gate "context required)\n", 1753*0Sstevel@tonic-gate dt_idkind_name(idp->di_kind), idp->di_name); 1754*0Sstevel@tonic-gate } 1755*0Sstevel@tonic-gate 1756*0Sstevel@tonic-gate dt_cg_arglist(dnp->dn_ident, dnp->dn_args, dlp, drp); 1757*0Sstevel@tonic-gate 1758*0Sstevel@tonic-gate if ((dnp->dn_reg = dt_regset_alloc(drp)) == -1) 1759*0Sstevel@tonic-gate longjmp(yypcb->pcb_jmpbuf, EDT_NOREG); 1760*0Sstevel@tonic-gate 1761*0Sstevel@tonic-gate instr = DIF_INSTR_CALL( 1762*0Sstevel@tonic-gate dnp->dn_ident->di_id, dnp->dn_reg); 1763*0Sstevel@tonic-gate 1764*0Sstevel@tonic-gate dt_irlist_append(dlp, 1765*0Sstevel@tonic-gate dt_cg_node_alloc(DT_LBL_NONE, instr)); 1766*0Sstevel@tonic-gate 1767*0Sstevel@tonic-gate break; 1768*0Sstevel@tonic-gate 1769*0Sstevel@tonic-gate case DT_NODE_VAR: 1770*0Sstevel@tonic-gate if (dnp->dn_ident->di_kind == DT_IDENT_XLSOU || 1771*0Sstevel@tonic-gate dnp->dn_ident->di_kind == DT_IDENT_XLPTR) { 1772*0Sstevel@tonic-gate /* 1773*0Sstevel@tonic-gate * This can only happen if we have translated 1774*0Sstevel@tonic-gate * args[]. See dt_idcook_args() for details. 1775*0Sstevel@tonic-gate */ 1776*0Sstevel@tonic-gate assert(dnp->dn_ident->di_id == DIF_VAR_ARGS); 1777*0Sstevel@tonic-gate dt_cg_array_op(dnp, dlp, drp); 1778*0Sstevel@tonic-gate break; 1779*0Sstevel@tonic-gate } 1780*0Sstevel@tonic-gate 1781*0Sstevel@tonic-gate if (dnp->dn_ident->di_kind == DT_IDENT_ARRAY) { 1782*0Sstevel@tonic-gate if (dnp->dn_ident->di_id > DIF_VAR_ARRAY_MAX) 1783*0Sstevel@tonic-gate dt_cg_assoc_op(dnp, dlp, drp); 1784*0Sstevel@tonic-gate else 1785*0Sstevel@tonic-gate dt_cg_array_op(dnp, dlp, drp); 1786*0Sstevel@tonic-gate break; 1787*0Sstevel@tonic-gate } 1788*0Sstevel@tonic-gate 1789*0Sstevel@tonic-gate if ((dnp->dn_reg = dt_regset_alloc(drp)) == -1) 1790*0Sstevel@tonic-gate longjmp(yypcb->pcb_jmpbuf, EDT_NOREG); 1791*0Sstevel@tonic-gate 1792*0Sstevel@tonic-gate if (dnp->dn_ident->di_flags & DT_IDFLG_LOCAL) 1793*0Sstevel@tonic-gate op = DIF_OP_LDLS; 1794*0Sstevel@tonic-gate else if (dnp->dn_ident->di_flags & DT_IDFLG_TLS) 1795*0Sstevel@tonic-gate op = DIF_OP_LDTS; 1796*0Sstevel@tonic-gate else 1797*0Sstevel@tonic-gate op = DIF_OP_LDGS; 1798*0Sstevel@tonic-gate 1799*0Sstevel@tonic-gate dnp->dn_ident->di_flags |= DT_IDFLG_DIFR; 1800*0Sstevel@tonic-gate 1801*0Sstevel@tonic-gate instr = DIF_INSTR_LDV(op, 1802*0Sstevel@tonic-gate dnp->dn_ident->di_id, dnp->dn_reg); 1803*0Sstevel@tonic-gate 1804*0Sstevel@tonic-gate dt_irlist_append(dlp, 1805*0Sstevel@tonic-gate dt_cg_node_alloc(DT_LBL_NONE, instr)); 1806*0Sstevel@tonic-gate break; 1807*0Sstevel@tonic-gate 1808*0Sstevel@tonic-gate case DT_NODE_SYM: { 1809*0Sstevel@tonic-gate dtrace_hdl_t *dtp = yypcb->pcb_hdl; 1810*0Sstevel@tonic-gate dtrace_syminfo_t *sip = dnp->dn_ident->di_data; 1811*0Sstevel@tonic-gate GElf_Sym sym; 1812*0Sstevel@tonic-gate 1813*0Sstevel@tonic-gate if (dtrace_lookup_by_name(dtp, 1814*0Sstevel@tonic-gate sip->dts_object, sip->dts_name, &sym, NULL) == -1) { 1815*0Sstevel@tonic-gate xyerror(D_UNKNOWN, "cg failed for symbol %s`%s:" 1816*0Sstevel@tonic-gate " %s\n", sip->dts_object, sip->dts_name, 1817*0Sstevel@tonic-gate dtrace_errmsg(dtp, dtrace_errno(dtp))); 1818*0Sstevel@tonic-gate } 1819*0Sstevel@tonic-gate 1820*0Sstevel@tonic-gate if ((dnp->dn_reg = dt_regset_alloc(drp)) == -1) 1821*0Sstevel@tonic-gate longjmp(yypcb->pcb_jmpbuf, EDT_NOREG); 1822*0Sstevel@tonic-gate 1823*0Sstevel@tonic-gate dt_cg_xsetx(dlp, dnp->dn_ident, 1824*0Sstevel@tonic-gate DT_LBL_NONE, dnp->dn_reg, sym.st_value); 1825*0Sstevel@tonic-gate 1826*0Sstevel@tonic-gate if (!(dnp->dn_flags & DT_NF_REF)) { 1827*0Sstevel@tonic-gate instr = DIF_INSTR_LOAD(dt_cg_load(dnp, ctfp, 1828*0Sstevel@tonic-gate dnp->dn_type), dnp->dn_reg, dnp->dn_reg); 1829*0Sstevel@tonic-gate dt_irlist_append(dlp, 1830*0Sstevel@tonic-gate dt_cg_node_alloc(DT_LBL_NONE, instr)); 1831*0Sstevel@tonic-gate } 1832*0Sstevel@tonic-gate break; 1833*0Sstevel@tonic-gate } 1834*0Sstevel@tonic-gate 1835*0Sstevel@tonic-gate default: 1836*0Sstevel@tonic-gate xyerror(D_UNKNOWN, "internal error -- node type %u is " 1837*0Sstevel@tonic-gate "not valid for an identifier\n", dnp->dn_kind); 1838*0Sstevel@tonic-gate } 1839*0Sstevel@tonic-gate break; 1840*0Sstevel@tonic-gate 1841*0Sstevel@tonic-gate case DT_TOK_INT: 1842*0Sstevel@tonic-gate if ((dnp->dn_reg = dt_regset_alloc(drp)) == -1) 1843*0Sstevel@tonic-gate longjmp(yypcb->pcb_jmpbuf, EDT_NOREG); 1844*0Sstevel@tonic-gate 1845*0Sstevel@tonic-gate dt_cg_setx(dlp, dnp->dn_reg, dnp->dn_value); 1846*0Sstevel@tonic-gate break; 1847*0Sstevel@tonic-gate 1848*0Sstevel@tonic-gate default: 1849*0Sstevel@tonic-gate xyerror(D_UNKNOWN, "internal error -- token type %u is not a " 1850*0Sstevel@tonic-gate "valid D compilation token\n", dnp->dn_op); 1851*0Sstevel@tonic-gate } 1852*0Sstevel@tonic-gate } 1853*0Sstevel@tonic-gate 1854*0Sstevel@tonic-gate void 1855*0Sstevel@tonic-gate dt_cg(dt_pcb_t *pcb, dt_node_t *dnp) 1856*0Sstevel@tonic-gate { 1857*0Sstevel@tonic-gate dif_instr_t instr; 1858*0Sstevel@tonic-gate 1859*0Sstevel@tonic-gate if (pcb->pcb_regs == NULL && (pcb->pcb_regs = 1860*0Sstevel@tonic-gate dt_regset_create(pcb->pcb_hdl->dt_conf.dtc_difintregs)) == NULL) 1861*0Sstevel@tonic-gate longjmp(pcb->pcb_jmpbuf, EDT_NOMEM); 1862*0Sstevel@tonic-gate 1863*0Sstevel@tonic-gate dt_regset_reset(pcb->pcb_regs); 1864*0Sstevel@tonic-gate (void) dt_regset_alloc(pcb->pcb_regs); /* allocate %r0 */ 1865*0Sstevel@tonic-gate 1866*0Sstevel@tonic-gate if (pcb->pcb_inttab != NULL) 1867*0Sstevel@tonic-gate dt_inttab_destroy(pcb->pcb_inttab); 1868*0Sstevel@tonic-gate 1869*0Sstevel@tonic-gate if ((pcb->pcb_inttab = dt_inttab_create(yypcb->pcb_hdl)) == NULL) 1870*0Sstevel@tonic-gate longjmp(pcb->pcb_jmpbuf, EDT_NOMEM); 1871*0Sstevel@tonic-gate 1872*0Sstevel@tonic-gate if (pcb->pcb_strtab != NULL) 1873*0Sstevel@tonic-gate dt_strtab_destroy(pcb->pcb_strtab); 1874*0Sstevel@tonic-gate 1875*0Sstevel@tonic-gate if ((pcb->pcb_strtab = dt_strtab_create(BUFSIZ)) == NULL) 1876*0Sstevel@tonic-gate longjmp(pcb->pcb_jmpbuf, EDT_NOMEM); 1877*0Sstevel@tonic-gate 1878*0Sstevel@tonic-gate dt_irlist_destroy(&pcb->pcb_ir); 1879*0Sstevel@tonic-gate dt_irlist_create(&pcb->pcb_ir); 1880*0Sstevel@tonic-gate 1881*0Sstevel@tonic-gate assert(pcb->pcb_dret == NULL); 1882*0Sstevel@tonic-gate pcb->pcb_dret = dnp; 1883*0Sstevel@tonic-gate 1884*0Sstevel@tonic-gate if (dt_node_is_dynamic(dnp)) { 1885*0Sstevel@tonic-gate dnerror(dnp, D_CG_DYN, "expression cannot evaluate to result " 1886*0Sstevel@tonic-gate "of dynamic type\n"); 1887*0Sstevel@tonic-gate } 1888*0Sstevel@tonic-gate 1889*0Sstevel@tonic-gate dt_cg_node(dnp, &pcb->pcb_ir, pcb->pcb_regs); 1890*0Sstevel@tonic-gate instr = DIF_INSTR_RET(dnp->dn_reg); 1891*0Sstevel@tonic-gate dt_regset_free(pcb->pcb_regs, dnp->dn_reg); 1892*0Sstevel@tonic-gate dt_irlist_append(&pcb->pcb_ir, dt_cg_node_alloc(DT_LBL_NONE, instr)); 1893*0Sstevel@tonic-gate } 1894