16ff6d951SJohn Birrell /* 26ff6d951SJohn Birrell * CDDL HEADER START 36ff6d951SJohn Birrell * 46ff6d951SJohn Birrell * The contents of this file are subject to the terms of the 56ff6d951SJohn Birrell * Common Development and Distribution License, Version 1.0 only 66ff6d951SJohn Birrell * (the "License"). You may not use this file except in compliance 76ff6d951SJohn Birrell * with the License. 86ff6d951SJohn Birrell * 96ff6d951SJohn Birrell * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 106ff6d951SJohn Birrell * or http://www.opensolaris.org/os/licensing. 116ff6d951SJohn Birrell * See the License for the specific language governing permissions 126ff6d951SJohn Birrell * and limitations under the License. 136ff6d951SJohn Birrell * 146ff6d951SJohn Birrell * When distributing Covered Code, include this CDDL HEADER in each 156ff6d951SJohn Birrell * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 166ff6d951SJohn Birrell * If applicable, add the following below this CDDL HEADER, with the 176ff6d951SJohn Birrell * fields enclosed by brackets "[]" replaced with your own identifying 186ff6d951SJohn Birrell * information: Portions Copyright [yyyy] [name of copyright owner] 196ff6d951SJohn Birrell * 206ff6d951SJohn Birrell * CDDL HEADER END 216ff6d951SJohn Birrell */ 226ff6d951SJohn Birrell /* 236ff6d951SJohn Birrell * Copyright 2005 Sun Microsystems, Inc. All rights reserved. 246ff6d951SJohn Birrell * Use is subject to license terms. 256ff6d951SJohn Birrell */ 266ff6d951SJohn Birrell 276ff6d951SJohn Birrell #pragma ident "%Z%%M% %I% %E% SMI" 286ff6d951SJohn Birrell 296ff6d951SJohn Birrell #include <sys/types.h> 306ff6d951SJohn Birrell #include <sys/sysmacros.h> 316ff6d951SJohn Birrell #include <sys/isa_defs.h> 326ff6d951SJohn Birrell 336ff6d951SJohn Birrell #include <strings.h> 346ff6d951SJohn Birrell #include <stdlib.h> 356ff6d951SJohn Birrell #include <setjmp.h> 366ff6d951SJohn Birrell #include <assert.h> 376ff6d951SJohn Birrell #include <errno.h> 386ff6d951SJohn Birrell 396ff6d951SJohn Birrell #include <dt_impl.h> 406ff6d951SJohn Birrell #include <dt_grammar.h> 416ff6d951SJohn Birrell #include <dt_parser.h> 426ff6d951SJohn Birrell #include <dt_provider.h> 436ff6d951SJohn Birrell 446ff6d951SJohn Birrell static void dt_cg_node(dt_node_t *, dt_irlist_t *, dt_regset_t *); 456ff6d951SJohn Birrell 466ff6d951SJohn Birrell static dt_irnode_t * 476ff6d951SJohn Birrell dt_cg_node_alloc(uint_t label, dif_instr_t instr) 486ff6d951SJohn Birrell { 496ff6d951SJohn Birrell dt_irnode_t *dip = malloc(sizeof (dt_irnode_t)); 506ff6d951SJohn Birrell 516ff6d951SJohn Birrell if (dip == NULL) 526ff6d951SJohn Birrell longjmp(yypcb->pcb_jmpbuf, EDT_NOMEM); 536ff6d951SJohn Birrell 546ff6d951SJohn Birrell dip->di_label = label; 556ff6d951SJohn Birrell dip->di_instr = instr; 566ff6d951SJohn Birrell dip->di_extern = NULL; 576ff6d951SJohn Birrell dip->di_next = NULL; 586ff6d951SJohn Birrell 596ff6d951SJohn Birrell return (dip); 606ff6d951SJohn Birrell } 616ff6d951SJohn Birrell 626ff6d951SJohn Birrell /* 636ff6d951SJohn Birrell * Code generator wrapper function for ctf_member_info. If we are given a 646ff6d951SJohn Birrell * reference to a forward declaration tag, search the entire type space for 656ff6d951SJohn Birrell * the actual definition and then call ctf_member_info on the result. 666ff6d951SJohn Birrell */ 676ff6d951SJohn Birrell static ctf_file_t * 686ff6d951SJohn Birrell dt_cg_membinfo(ctf_file_t *fp, ctf_id_t type, const char *s, ctf_membinfo_t *mp) 696ff6d951SJohn Birrell { 706ff6d951SJohn Birrell while (ctf_type_kind(fp, type) == CTF_K_FORWARD) { 716ff6d951SJohn Birrell char n[DT_TYPE_NAMELEN]; 726ff6d951SJohn Birrell dtrace_typeinfo_t dtt; 736ff6d951SJohn Birrell 746ff6d951SJohn Birrell if (ctf_type_name(fp, type, n, sizeof (n)) == NULL || 756ff6d951SJohn Birrell dt_type_lookup(n, &dtt) == -1 || ( 766ff6d951SJohn Birrell dtt.dtt_ctfp == fp && dtt.dtt_type == type)) 776ff6d951SJohn Birrell break; /* unable to improve our position */ 786ff6d951SJohn Birrell 796ff6d951SJohn Birrell fp = dtt.dtt_ctfp; 806ff6d951SJohn Birrell type = ctf_type_resolve(fp, dtt.dtt_type); 816ff6d951SJohn Birrell } 826ff6d951SJohn Birrell 836ff6d951SJohn Birrell if (ctf_member_info(fp, type, s, mp) == CTF_ERR) 846ff6d951SJohn Birrell return (NULL); /* ctf_errno is set for us */ 856ff6d951SJohn Birrell 866ff6d951SJohn Birrell return (fp); 876ff6d951SJohn Birrell } 886ff6d951SJohn Birrell 896ff6d951SJohn Birrell static void 906ff6d951SJohn Birrell dt_cg_xsetx(dt_irlist_t *dlp, dt_ident_t *idp, uint_t lbl, int reg, uint64_t x) 916ff6d951SJohn Birrell { 926ff6d951SJohn Birrell int flag = idp != NULL ? DT_INT_PRIVATE : DT_INT_SHARED; 936ff6d951SJohn Birrell int intoff = dt_inttab_insert(yypcb->pcb_inttab, x, flag); 946ff6d951SJohn Birrell dif_instr_t instr = DIF_INSTR_SETX((uint_t)intoff, reg); 956ff6d951SJohn Birrell 966ff6d951SJohn Birrell if (intoff == -1) 976ff6d951SJohn Birrell longjmp(yypcb->pcb_jmpbuf, EDT_NOMEM); 986ff6d951SJohn Birrell 996ff6d951SJohn Birrell if (intoff > DIF_INTOFF_MAX) 1006ff6d951SJohn Birrell longjmp(yypcb->pcb_jmpbuf, EDT_INT2BIG); 1016ff6d951SJohn Birrell 1026ff6d951SJohn Birrell dt_irlist_append(dlp, dt_cg_node_alloc(lbl, instr)); 1036ff6d951SJohn Birrell 1046ff6d951SJohn Birrell if (idp != NULL) 1056ff6d951SJohn Birrell dlp->dl_last->di_extern = idp; 1066ff6d951SJohn Birrell } 1076ff6d951SJohn Birrell 1086ff6d951SJohn Birrell static void 1096ff6d951SJohn Birrell dt_cg_setx(dt_irlist_t *dlp, int reg, uint64_t x) 1106ff6d951SJohn Birrell { 1116ff6d951SJohn Birrell dt_cg_xsetx(dlp, NULL, DT_LBL_NONE, reg, x); 1126ff6d951SJohn Birrell } 1136ff6d951SJohn Birrell 1146ff6d951SJohn Birrell /* 1156ff6d951SJohn Birrell * When loading bit-fields, we want to convert a byte count in the range 1166ff6d951SJohn Birrell * 1-8 to the closest power of 2 (e.g. 3->4, 5->8, etc). The clp2() function 1176ff6d951SJohn Birrell * is a clever implementation from "Hacker's Delight" by Henry Warren, Jr. 1186ff6d951SJohn Birrell */ 1196ff6d951SJohn Birrell static size_t 1206ff6d951SJohn Birrell clp2(size_t x) 1216ff6d951SJohn Birrell { 1226ff6d951SJohn Birrell x--; 1236ff6d951SJohn Birrell 1246ff6d951SJohn Birrell x |= (x >> 1); 1256ff6d951SJohn Birrell x |= (x >> 2); 1266ff6d951SJohn Birrell x |= (x >> 4); 1276ff6d951SJohn Birrell x |= (x >> 8); 1286ff6d951SJohn Birrell x |= (x >> 16); 1296ff6d951SJohn Birrell 1306ff6d951SJohn Birrell return (x + 1); 1316ff6d951SJohn Birrell } 1326ff6d951SJohn Birrell 1336ff6d951SJohn Birrell /* 1346ff6d951SJohn Birrell * Lookup the correct load opcode to use for the specified node and CTF type. 1356ff6d951SJohn Birrell * We determine the size and convert it to a 3-bit index. Our lookup table 1366ff6d951SJohn Birrell * is constructed to use a 5-bit index, consisting of the 3-bit size 0-7, a 1376ff6d951SJohn Birrell * bit for the sign, and a bit for userland address. For example, a 4-byte 1386ff6d951SJohn Birrell * signed load from userland would be at the following table index: 1396ff6d951SJohn Birrell * user=1 sign=1 size=4 => binary index 11011 = decimal index 27 1406ff6d951SJohn Birrell */ 1416ff6d951SJohn Birrell static uint_t 1426ff6d951SJohn Birrell dt_cg_load(dt_node_t *dnp, ctf_file_t *ctfp, ctf_id_t type) 1436ff6d951SJohn Birrell { 1446ff6d951SJohn Birrell static const uint_t ops[] = { 1456ff6d951SJohn Birrell DIF_OP_LDUB, DIF_OP_LDUH, 0, DIF_OP_LDUW, 1466ff6d951SJohn Birrell 0, 0, 0, DIF_OP_LDX, 1476ff6d951SJohn Birrell DIF_OP_LDSB, DIF_OP_LDSH, 0, DIF_OP_LDSW, 1486ff6d951SJohn Birrell 0, 0, 0, DIF_OP_LDX, 1496ff6d951SJohn Birrell DIF_OP_ULDUB, DIF_OP_ULDUH, 0, DIF_OP_ULDUW, 1506ff6d951SJohn Birrell 0, 0, 0, DIF_OP_ULDX, 1516ff6d951SJohn Birrell DIF_OP_ULDSB, DIF_OP_ULDSH, 0, DIF_OP_ULDSW, 1526ff6d951SJohn Birrell 0, 0, 0, DIF_OP_ULDX, 1536ff6d951SJohn Birrell }; 1546ff6d951SJohn Birrell 1556ff6d951SJohn Birrell ctf_encoding_t e; 1566ff6d951SJohn Birrell ssize_t size; 1576ff6d951SJohn Birrell 1586ff6d951SJohn Birrell /* 1596ff6d951SJohn Birrell * If we're loading a bit-field, the size of our load is found by 1606ff6d951SJohn Birrell * rounding cte_bits up to a byte boundary and then finding the 1616ff6d951SJohn Birrell * nearest power of two to this value (see clp2(), above). 1626ff6d951SJohn Birrell */ 1636ff6d951SJohn Birrell if ((dnp->dn_flags & DT_NF_BITFIELD) && 1646ff6d951SJohn Birrell ctf_type_encoding(ctfp, type, &e) != CTF_ERR) 1656ff6d951SJohn Birrell size = clp2(P2ROUNDUP(e.cte_bits, NBBY) / NBBY); 1666ff6d951SJohn Birrell else 1676ff6d951SJohn Birrell size = ctf_type_size(ctfp, type); 1686ff6d951SJohn Birrell 1696ff6d951SJohn Birrell if (size < 1 || size > 8 || (size & (size - 1)) != 0) { 1706ff6d951SJohn Birrell xyerror(D_UNKNOWN, "internal error -- cg cannot load " 1716ff6d951SJohn Birrell "size %ld when passed by value\n", (long)size); 1726ff6d951SJohn Birrell } 1736ff6d951SJohn Birrell 1746ff6d951SJohn Birrell size--; /* convert size to 3-bit index */ 1756ff6d951SJohn Birrell 1766ff6d951SJohn Birrell if (dnp->dn_flags & DT_NF_SIGNED) 1776ff6d951SJohn Birrell size |= 0x08; 1786ff6d951SJohn Birrell if (dnp->dn_flags & DT_NF_USERLAND) 1796ff6d951SJohn Birrell size |= 0x10; 1806ff6d951SJohn Birrell 1816ff6d951SJohn Birrell return (ops[size]); 1826ff6d951SJohn Birrell } 1836ff6d951SJohn Birrell 1846ff6d951SJohn Birrell static void 1856ff6d951SJohn Birrell dt_cg_ptrsize(dt_node_t *dnp, dt_irlist_t *dlp, dt_regset_t *drp, 1866ff6d951SJohn Birrell uint_t op, int dreg) 1876ff6d951SJohn Birrell { 1886ff6d951SJohn Birrell ctf_file_t *ctfp = dnp->dn_ctfp; 1896ff6d951SJohn Birrell ctf_arinfo_t r; 1906ff6d951SJohn Birrell dif_instr_t instr; 1916ff6d951SJohn Birrell ctf_id_t type; 1926ff6d951SJohn Birrell uint_t kind; 1936ff6d951SJohn Birrell ssize_t size; 1946ff6d951SJohn Birrell int sreg; 1956ff6d951SJohn Birrell 1966ff6d951SJohn Birrell if ((sreg = dt_regset_alloc(drp)) == -1) 1976ff6d951SJohn Birrell longjmp(yypcb->pcb_jmpbuf, EDT_NOREG); 1986ff6d951SJohn Birrell 1996ff6d951SJohn Birrell type = ctf_type_resolve(ctfp, dnp->dn_type); 2006ff6d951SJohn Birrell kind = ctf_type_kind(ctfp, type); 2016ff6d951SJohn Birrell assert(kind == CTF_K_POINTER || kind == CTF_K_ARRAY); 2026ff6d951SJohn Birrell 2036ff6d951SJohn Birrell if (kind == CTF_K_ARRAY) { 2046ff6d951SJohn Birrell if (ctf_array_info(ctfp, type, &r) != 0) { 2056ff6d951SJohn Birrell yypcb->pcb_hdl->dt_ctferr = ctf_errno(ctfp); 2066ff6d951SJohn Birrell longjmp(yypcb->pcb_jmpbuf, EDT_CTF); 2076ff6d951SJohn Birrell } 2086ff6d951SJohn Birrell type = r.ctr_contents; 2096ff6d951SJohn Birrell } else 2106ff6d951SJohn Birrell type = ctf_type_reference(ctfp, type); 2116ff6d951SJohn Birrell 2126ff6d951SJohn Birrell if ((size = ctf_type_size(ctfp, type)) == 1) 2136ff6d951SJohn Birrell return; /* multiply or divide by one can be omitted */ 2146ff6d951SJohn Birrell 2156ff6d951SJohn Birrell dt_cg_setx(dlp, sreg, size); 2166ff6d951SJohn Birrell instr = DIF_INSTR_FMT(op, dreg, sreg, dreg); 2176ff6d951SJohn Birrell dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr)); 2186ff6d951SJohn Birrell dt_regset_free(drp, sreg); 2196ff6d951SJohn Birrell } 2206ff6d951SJohn Birrell 2216ff6d951SJohn Birrell /* 2226ff6d951SJohn Birrell * If the result of a "." or "->" operation is a bit-field, we use this routine 2236ff6d951SJohn Birrell * to generate an epilogue to the load instruction that extracts the value. In 2246ff6d951SJohn Birrell * the diagrams below the "ld??" is the load instruction that is generated to 2256ff6d951SJohn Birrell * load the containing word that is generating prior to calling this function. 2266ff6d951SJohn Birrell * 2276ff6d951SJohn Birrell * Epilogue for unsigned fields: Epilogue for signed fields: 2286ff6d951SJohn Birrell * 2296ff6d951SJohn Birrell * ldu? [r1], r1 lds? [r1], r1 2306ff6d951SJohn Birrell * setx USHIFT, r2 setx 64 - SSHIFT, r2 2316ff6d951SJohn Birrell * srl r1, r2, r1 sll r1, r2, r1 2326ff6d951SJohn Birrell * setx (1 << bits) - 1, r2 setx 64 - bits, r2 2336ff6d951SJohn Birrell * and r1, r2, r1 sra r1, r2, r1 2346ff6d951SJohn Birrell * 2356ff6d951SJohn Birrell * The *SHIFT constants above changes value depending on the endian-ness of our 2366ff6d951SJohn Birrell * target architecture. Refer to the comments below for more details. 2376ff6d951SJohn Birrell */ 2386ff6d951SJohn Birrell static void 2396ff6d951SJohn Birrell dt_cg_field_get(dt_node_t *dnp, dt_irlist_t *dlp, dt_regset_t *drp, 2406ff6d951SJohn Birrell ctf_file_t *fp, const ctf_membinfo_t *mp) 2416ff6d951SJohn Birrell { 2426ff6d951SJohn Birrell ctf_encoding_t e; 2436ff6d951SJohn Birrell dif_instr_t instr; 2446ff6d951SJohn Birrell uint64_t shift; 2456ff6d951SJohn Birrell int r1, r2; 2466ff6d951SJohn Birrell 2476ff6d951SJohn Birrell if (ctf_type_encoding(fp, mp->ctm_type, &e) != 0 || e.cte_bits > 64) { 2486ff6d951SJohn Birrell xyerror(D_UNKNOWN, "cg: bad field: off %lu type <%ld> " 2496ff6d951SJohn Birrell "bits %u\n", mp->ctm_offset, mp->ctm_type, e.cte_bits); 2506ff6d951SJohn Birrell } 2516ff6d951SJohn Birrell 2526ff6d951SJohn Birrell assert(dnp->dn_op == DT_TOK_PTR || dnp->dn_op == DT_TOK_DOT); 2536ff6d951SJohn Birrell r1 = dnp->dn_left->dn_reg; 2546ff6d951SJohn Birrell 2556ff6d951SJohn Birrell if ((r2 = dt_regset_alloc(drp)) == -1) 2566ff6d951SJohn Birrell longjmp(yypcb->pcb_jmpbuf, EDT_NOREG); 2576ff6d951SJohn Birrell 2586ff6d951SJohn Birrell /* 2596ff6d951SJohn Birrell * On little-endian architectures, ctm_offset counts from the right so 2606ff6d951SJohn Birrell * ctm_offset % NBBY itself is the amount we want to shift right to 2616ff6d951SJohn Birrell * move the value bits to the little end of the register to mask them. 2626ff6d951SJohn Birrell * On big-endian architectures, ctm_offset counts from the left so we 2636ff6d951SJohn Birrell * must subtract (ctm_offset % NBBY + cte_bits) from the size in bits 2646ff6d951SJohn Birrell * we used for the load. The size of our load in turn is found by 2656ff6d951SJohn Birrell * rounding cte_bits up to a byte boundary and then finding the 2666ff6d951SJohn Birrell * nearest power of two to this value (see clp2(), above). These 2676ff6d951SJohn Birrell * properties are used to compute shift as USHIFT or SSHIFT, below. 2686ff6d951SJohn Birrell */ 2696ff6d951SJohn Birrell if (dnp->dn_flags & DT_NF_SIGNED) { 27018737969SJohn Birrell #if BYTE_ORDER == _BIG_ENDIAN 2716ff6d951SJohn Birrell shift = clp2(P2ROUNDUP(e.cte_bits, NBBY) / NBBY) * NBBY - 2726ff6d951SJohn Birrell mp->ctm_offset % NBBY; 2736ff6d951SJohn Birrell #else 2746ff6d951SJohn Birrell shift = mp->ctm_offset % NBBY + e.cte_bits; 2756ff6d951SJohn Birrell #endif 2766ff6d951SJohn Birrell dt_cg_setx(dlp, r2, 64 - shift); 2776ff6d951SJohn Birrell instr = DIF_INSTR_FMT(DIF_OP_SLL, r1, r2, r1); 2786ff6d951SJohn Birrell dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr)); 2796ff6d951SJohn Birrell 2806ff6d951SJohn Birrell dt_cg_setx(dlp, r2, 64 - e.cte_bits); 2816ff6d951SJohn Birrell instr = DIF_INSTR_FMT(DIF_OP_SRA, r1, r2, r1); 2826ff6d951SJohn Birrell dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr)); 2836ff6d951SJohn Birrell } else { 28418737969SJohn Birrell #if BYTE_ORDER == _BIG_ENDIAN 2856ff6d951SJohn Birrell shift = clp2(P2ROUNDUP(e.cte_bits, NBBY) / NBBY) * NBBY - 2866ff6d951SJohn Birrell (mp->ctm_offset % NBBY + e.cte_bits); 2876ff6d951SJohn Birrell #else 2886ff6d951SJohn Birrell shift = mp->ctm_offset % NBBY; 2896ff6d951SJohn Birrell #endif 2906ff6d951SJohn Birrell dt_cg_setx(dlp, r2, shift); 2916ff6d951SJohn Birrell instr = DIF_INSTR_FMT(DIF_OP_SRL, r1, r2, r1); 2926ff6d951SJohn Birrell dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr)); 2936ff6d951SJohn Birrell 2946ff6d951SJohn Birrell dt_cg_setx(dlp, r2, (1ULL << e.cte_bits) - 1); 2956ff6d951SJohn Birrell instr = DIF_INSTR_FMT(DIF_OP_AND, r1, r2, r1); 2966ff6d951SJohn Birrell dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr)); 2976ff6d951SJohn Birrell } 2986ff6d951SJohn Birrell 2996ff6d951SJohn Birrell dt_regset_free(drp, r2); 3006ff6d951SJohn Birrell } 3016ff6d951SJohn Birrell 3026ff6d951SJohn Birrell /* 3036ff6d951SJohn Birrell * If the destination of a store operation is a bit-field, we use this routine 3046ff6d951SJohn Birrell * to generate a prologue to the store instruction that loads the surrounding 3056ff6d951SJohn Birrell * bits, clears the destination field, and ORs in the new value of the field. 3066ff6d951SJohn Birrell * In the diagram below the "st?" is the store instruction that is generated to 3076ff6d951SJohn Birrell * store the containing word that is generating after calling this function. 3086ff6d951SJohn Birrell * 3096ff6d951SJohn Birrell * ld [dst->dn_reg], r1 3106ff6d951SJohn Birrell * setx ~(((1 << cte_bits) - 1) << (ctm_offset % NBBY)), r2 3116ff6d951SJohn Birrell * and r1, r2, r1 3126ff6d951SJohn Birrell * 3136ff6d951SJohn Birrell * setx (1 << cte_bits) - 1, r2 3146ff6d951SJohn Birrell * and src->dn_reg, r2, r2 3156ff6d951SJohn Birrell * setx ctm_offset % NBBY, r3 3166ff6d951SJohn Birrell * sll r2, r3, r2 3176ff6d951SJohn Birrell * 3186ff6d951SJohn Birrell * or r1, r2, r1 3196ff6d951SJohn Birrell * st? r1, [dst->dn_reg] 3206ff6d951SJohn Birrell * 3216ff6d951SJohn Birrell * This routine allocates a new register to hold the value to be stored and 3226ff6d951SJohn Birrell * returns it. The caller is responsible for freeing this register later. 3236ff6d951SJohn Birrell */ 3246ff6d951SJohn Birrell static int 3256ff6d951SJohn Birrell dt_cg_field_set(dt_node_t *src, dt_irlist_t *dlp, 3266ff6d951SJohn Birrell dt_regset_t *drp, dt_node_t *dst) 3276ff6d951SJohn Birrell { 3286ff6d951SJohn Birrell uint64_t cmask, fmask, shift; 3296ff6d951SJohn Birrell dif_instr_t instr; 3306ff6d951SJohn Birrell int r1, r2, r3; 3316ff6d951SJohn Birrell 3326ff6d951SJohn Birrell ctf_membinfo_t m; 3336ff6d951SJohn Birrell ctf_encoding_t e; 3346ff6d951SJohn Birrell ctf_file_t *fp, *ofp; 3356ff6d951SJohn Birrell ctf_id_t type; 3366ff6d951SJohn Birrell 3376ff6d951SJohn Birrell assert(dst->dn_op == DT_TOK_PTR || dst->dn_op == DT_TOK_DOT); 3386ff6d951SJohn Birrell assert(dst->dn_right->dn_kind == DT_NODE_IDENT); 3396ff6d951SJohn Birrell 3406ff6d951SJohn Birrell fp = dst->dn_left->dn_ctfp; 3416ff6d951SJohn Birrell type = ctf_type_resolve(fp, dst->dn_left->dn_type); 3426ff6d951SJohn Birrell 3436ff6d951SJohn Birrell if (dst->dn_op == DT_TOK_PTR) { 3446ff6d951SJohn Birrell type = ctf_type_reference(fp, type); 3456ff6d951SJohn Birrell type = ctf_type_resolve(fp, type); 3466ff6d951SJohn Birrell } 3476ff6d951SJohn Birrell 3486ff6d951SJohn Birrell if ((fp = dt_cg_membinfo(ofp = fp, type, 3496ff6d951SJohn Birrell dst->dn_right->dn_string, &m)) == NULL) { 3506ff6d951SJohn Birrell yypcb->pcb_hdl->dt_ctferr = ctf_errno(ofp); 3516ff6d951SJohn Birrell longjmp(yypcb->pcb_jmpbuf, EDT_CTF); 3526ff6d951SJohn Birrell } 3536ff6d951SJohn Birrell 3546ff6d951SJohn Birrell if (ctf_type_encoding(fp, m.ctm_type, &e) != 0 || e.cte_bits > 64) { 3556ff6d951SJohn Birrell xyerror(D_UNKNOWN, "cg: bad field: off %lu type <%ld> " 3566ff6d951SJohn Birrell "bits %u\n", m.ctm_offset, m.ctm_type, e.cte_bits); 3576ff6d951SJohn Birrell } 3586ff6d951SJohn Birrell 3596ff6d951SJohn Birrell if ((r1 = dt_regset_alloc(drp)) == -1 || 3606ff6d951SJohn Birrell (r2 = dt_regset_alloc(drp)) == -1 || 3616ff6d951SJohn Birrell (r3 = dt_regset_alloc(drp)) == -1) 3626ff6d951SJohn Birrell longjmp(yypcb->pcb_jmpbuf, EDT_NOREG); 3636ff6d951SJohn Birrell 3646ff6d951SJohn Birrell /* 3656ff6d951SJohn Birrell * Compute shifts and masks. We need to compute "shift" as the amount 3666ff6d951SJohn Birrell * we need to shift left to position our field in the containing word. 3676ff6d951SJohn Birrell * Refer to the comments in dt_cg_field_get(), above, for more info. 3686ff6d951SJohn Birrell * We then compute fmask as the mask that truncates the value in the 3696ff6d951SJohn Birrell * input register to width cte_bits, and cmask as the mask used to 3706ff6d951SJohn Birrell * pass through the containing bits and zero the field bits. 3716ff6d951SJohn Birrell */ 37218737969SJohn Birrell #if BYTE_ORDER == _BIG_ENDIAN 3736ff6d951SJohn Birrell shift = clp2(P2ROUNDUP(e.cte_bits, NBBY) / NBBY) * NBBY - 3746ff6d951SJohn Birrell (m.ctm_offset % NBBY + e.cte_bits); 3756ff6d951SJohn Birrell #else 3766ff6d951SJohn Birrell shift = m.ctm_offset % NBBY; 3776ff6d951SJohn Birrell #endif 3786ff6d951SJohn Birrell fmask = (1ULL << e.cte_bits) - 1; 3796ff6d951SJohn Birrell cmask = ~(fmask << shift); 3806ff6d951SJohn Birrell 3816ff6d951SJohn Birrell instr = DIF_INSTR_LOAD( 3826ff6d951SJohn Birrell dt_cg_load(dst, fp, m.ctm_type), dst->dn_reg, r1); 3836ff6d951SJohn Birrell dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr)); 3846ff6d951SJohn Birrell 3856ff6d951SJohn Birrell dt_cg_setx(dlp, r2, cmask); 3866ff6d951SJohn Birrell instr = DIF_INSTR_FMT(DIF_OP_AND, r1, r2, r1); 3876ff6d951SJohn Birrell dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr)); 3886ff6d951SJohn Birrell 3896ff6d951SJohn Birrell dt_cg_setx(dlp, r2, fmask); 3906ff6d951SJohn Birrell instr = DIF_INSTR_FMT(DIF_OP_AND, src->dn_reg, r2, r2); 3916ff6d951SJohn Birrell dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr)); 3926ff6d951SJohn Birrell 3936ff6d951SJohn Birrell dt_cg_setx(dlp, r3, shift); 3946ff6d951SJohn Birrell instr = DIF_INSTR_FMT(DIF_OP_SLL, r2, r3, r2); 3956ff6d951SJohn Birrell dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr)); 3966ff6d951SJohn Birrell 3976ff6d951SJohn Birrell instr = DIF_INSTR_FMT(DIF_OP_OR, r1, r2, r1); 3986ff6d951SJohn Birrell dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr)); 3996ff6d951SJohn Birrell 4006ff6d951SJohn Birrell dt_regset_free(drp, r3); 4016ff6d951SJohn Birrell dt_regset_free(drp, r2); 4026ff6d951SJohn Birrell 4036ff6d951SJohn Birrell return (r1); 4046ff6d951SJohn Birrell } 4056ff6d951SJohn Birrell 4066ff6d951SJohn Birrell static void 4076ff6d951SJohn Birrell dt_cg_store(dt_node_t *src, dt_irlist_t *dlp, dt_regset_t *drp, dt_node_t *dst) 4086ff6d951SJohn Birrell { 4096ff6d951SJohn Birrell ctf_encoding_t e; 4106ff6d951SJohn Birrell dif_instr_t instr; 4116ff6d951SJohn Birrell size_t size; 4126ff6d951SJohn Birrell int reg; 4136ff6d951SJohn Birrell 4146ff6d951SJohn Birrell /* 4156ff6d951SJohn Birrell * If we're loading a bit-field, the size of our store is found by 4166ff6d951SJohn Birrell * rounding dst's cte_bits up to a byte boundary and then finding the 4176ff6d951SJohn Birrell * nearest power of two to this value (see clp2(), above). 4186ff6d951SJohn Birrell */ 4196ff6d951SJohn Birrell if ((dst->dn_flags & DT_NF_BITFIELD) && 4206ff6d951SJohn Birrell ctf_type_encoding(dst->dn_ctfp, dst->dn_type, &e) != CTF_ERR) 4216ff6d951SJohn Birrell size = clp2(P2ROUNDUP(e.cte_bits, NBBY) / NBBY); 4226ff6d951SJohn Birrell else 4236ff6d951SJohn Birrell size = dt_node_type_size(src); 4246ff6d951SJohn Birrell 4256ff6d951SJohn Birrell if (src->dn_flags & DT_NF_REF) { 4266ff6d951SJohn Birrell if ((reg = dt_regset_alloc(drp)) == -1) 4276ff6d951SJohn Birrell longjmp(yypcb->pcb_jmpbuf, EDT_NOREG); 4286ff6d951SJohn Birrell dt_cg_setx(dlp, reg, size); 4296ff6d951SJohn Birrell instr = DIF_INSTR_COPYS(src->dn_reg, reg, dst->dn_reg); 4306ff6d951SJohn Birrell dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr)); 4316ff6d951SJohn Birrell dt_regset_free(drp, reg); 4326ff6d951SJohn Birrell } else { 4336ff6d951SJohn Birrell if (dst->dn_flags & DT_NF_BITFIELD) 4346ff6d951SJohn Birrell reg = dt_cg_field_set(src, dlp, drp, dst); 4356ff6d951SJohn Birrell else 4366ff6d951SJohn Birrell reg = src->dn_reg; 4376ff6d951SJohn Birrell 4386ff6d951SJohn Birrell switch (size) { 4396ff6d951SJohn Birrell case 1: 4406ff6d951SJohn Birrell instr = DIF_INSTR_STORE(DIF_OP_STB, reg, dst->dn_reg); 4416ff6d951SJohn Birrell break; 4426ff6d951SJohn Birrell case 2: 4436ff6d951SJohn Birrell instr = DIF_INSTR_STORE(DIF_OP_STH, reg, dst->dn_reg); 4446ff6d951SJohn Birrell break; 4456ff6d951SJohn Birrell case 4: 4466ff6d951SJohn Birrell instr = DIF_INSTR_STORE(DIF_OP_STW, reg, dst->dn_reg); 4476ff6d951SJohn Birrell break; 4486ff6d951SJohn Birrell case 8: 4496ff6d951SJohn Birrell instr = DIF_INSTR_STORE(DIF_OP_STX, reg, dst->dn_reg); 4506ff6d951SJohn Birrell break; 4516ff6d951SJohn Birrell default: 4526ff6d951SJohn Birrell xyerror(D_UNKNOWN, "internal error -- cg cannot store " 4536ff6d951SJohn Birrell "size %lu when passed by value\n", (ulong_t)size); 4546ff6d951SJohn Birrell } 4556ff6d951SJohn Birrell dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr)); 4566ff6d951SJohn Birrell 4576ff6d951SJohn Birrell if (dst->dn_flags & DT_NF_BITFIELD) 4586ff6d951SJohn Birrell dt_regset_free(drp, reg); 4596ff6d951SJohn Birrell } 4606ff6d951SJohn Birrell } 4616ff6d951SJohn Birrell 4626ff6d951SJohn Birrell /* 4636ff6d951SJohn Birrell * Generate code for a typecast or for argument promotion from the type of the 4646ff6d951SJohn Birrell * actual to the type of the formal. We need to generate code for casts when 4656ff6d951SJohn Birrell * a scalar type is being narrowed or changing signed-ness. We first shift the 4666ff6d951SJohn Birrell * desired bits high (losing excess bits if narrowing) and then shift them down 4676ff6d951SJohn Birrell * using logical shift (unsigned result) or arithmetic shift (signed result). 4686ff6d951SJohn Birrell */ 4696ff6d951SJohn Birrell static void 4706ff6d951SJohn Birrell dt_cg_typecast(const dt_node_t *src, const dt_node_t *dst, 4716ff6d951SJohn Birrell dt_irlist_t *dlp, dt_regset_t *drp) 4726ff6d951SJohn Birrell { 4736ff6d951SJohn Birrell size_t srcsize = dt_node_type_size(src); 4746ff6d951SJohn Birrell size_t dstsize = dt_node_type_size(dst); 4756ff6d951SJohn Birrell 4766ff6d951SJohn Birrell dif_instr_t instr; 4776ff6d951SJohn Birrell int reg, n; 4786ff6d951SJohn Birrell 4796ff6d951SJohn Birrell if (dt_node_is_scalar(dst) && (dstsize < srcsize || 4806ff6d951SJohn Birrell (src->dn_flags & DT_NF_SIGNED) ^ (dst->dn_flags & DT_NF_SIGNED))) { 4816ff6d951SJohn Birrell if ((reg = dt_regset_alloc(drp)) == -1) 4826ff6d951SJohn Birrell longjmp(yypcb->pcb_jmpbuf, EDT_NOREG); 4836ff6d951SJohn Birrell 4846ff6d951SJohn Birrell if (dstsize < srcsize) 4856ff6d951SJohn Birrell n = sizeof (uint64_t) * NBBY - dstsize * NBBY; 4866ff6d951SJohn Birrell else 4876ff6d951SJohn Birrell n = sizeof (uint64_t) * NBBY - srcsize * NBBY; 4886ff6d951SJohn Birrell 4896ff6d951SJohn Birrell dt_cg_setx(dlp, reg, n); 4906ff6d951SJohn Birrell 4916ff6d951SJohn Birrell instr = DIF_INSTR_FMT(DIF_OP_SLL, 4926ff6d951SJohn Birrell src->dn_reg, reg, dst->dn_reg); 4936ff6d951SJohn Birrell dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr)); 4946ff6d951SJohn Birrell 4956ff6d951SJohn Birrell instr = DIF_INSTR_FMT((dst->dn_flags & DT_NF_SIGNED) ? 4966ff6d951SJohn Birrell DIF_OP_SRA : DIF_OP_SRL, dst->dn_reg, reg, dst->dn_reg); 4976ff6d951SJohn Birrell 4986ff6d951SJohn Birrell dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr)); 4996ff6d951SJohn Birrell dt_regset_free(drp, reg); 5006ff6d951SJohn Birrell } 5016ff6d951SJohn Birrell } 5026ff6d951SJohn Birrell 5036ff6d951SJohn Birrell /* 5046ff6d951SJohn Birrell * Generate code to push the specified argument list on to the tuple stack. 5056ff6d951SJohn Birrell * We use this routine for handling subroutine calls and associative arrays. 5066ff6d951SJohn Birrell * We must first generate code for all subexpressions before loading the stack 5076ff6d951SJohn Birrell * because any subexpression could itself require the use of the tuple stack. 5086ff6d951SJohn Birrell * This holds a number of registers equal to the number of arguments, but this 5096ff6d951SJohn Birrell * is not a huge problem because the number of arguments can't exceed the 5106ff6d951SJohn Birrell * number of tuple register stack elements anyway. At most one extra register 5116ff6d951SJohn Birrell * is required (either by dt_cg_typecast() or for dtdt_size, below). This 5126ff6d951SJohn Birrell * implies that a DIF implementation should offer a number of general purpose 5136ff6d951SJohn Birrell * registers at least one greater than the number of tuple registers. 5146ff6d951SJohn Birrell */ 5156ff6d951SJohn Birrell static void 5166ff6d951SJohn Birrell dt_cg_arglist(dt_ident_t *idp, dt_node_t *args, 5176ff6d951SJohn Birrell dt_irlist_t *dlp, dt_regset_t *drp) 5186ff6d951SJohn Birrell { 5196ff6d951SJohn Birrell const dt_idsig_t *isp = idp->di_data; 5206ff6d951SJohn Birrell dt_node_t *dnp; 5216ff6d951SJohn Birrell int i = 0; 5226ff6d951SJohn Birrell 5236ff6d951SJohn Birrell for (dnp = args; dnp != NULL; dnp = dnp->dn_list) 5246ff6d951SJohn Birrell dt_cg_node(dnp, dlp, drp); 5256ff6d951SJohn Birrell 5266ff6d951SJohn Birrell dt_irlist_append(dlp, 5276ff6d951SJohn Birrell dt_cg_node_alloc(DT_LBL_NONE, DIF_INSTR_FLUSHTS)); 5286ff6d951SJohn Birrell 5296ff6d951SJohn Birrell for (dnp = args; dnp != NULL; dnp = dnp->dn_list, i++) { 5306ff6d951SJohn Birrell dtrace_diftype_t t; 5316ff6d951SJohn Birrell dif_instr_t instr; 5326ff6d951SJohn Birrell uint_t op; 5336ff6d951SJohn Birrell int reg; 5346ff6d951SJohn Birrell 5356ff6d951SJohn Birrell dt_node_diftype(yypcb->pcb_hdl, dnp, &t); 5366ff6d951SJohn Birrell 5376ff6d951SJohn Birrell isp->dis_args[i].dn_reg = dnp->dn_reg; /* re-use register */ 5386ff6d951SJohn Birrell dt_cg_typecast(dnp, &isp->dis_args[i], dlp, drp); 5396ff6d951SJohn Birrell isp->dis_args[i].dn_reg = -1; 5406ff6d951SJohn Birrell 5416ff6d951SJohn Birrell if (t.dtdt_flags & DIF_TF_BYREF) 5426ff6d951SJohn Birrell op = DIF_OP_PUSHTR; 5436ff6d951SJohn Birrell else 5446ff6d951SJohn Birrell op = DIF_OP_PUSHTV; 5456ff6d951SJohn Birrell 5466ff6d951SJohn Birrell if (t.dtdt_size != 0) { 5476ff6d951SJohn Birrell if ((reg = dt_regset_alloc(drp)) == -1) 5486ff6d951SJohn Birrell longjmp(yypcb->pcb_jmpbuf, EDT_NOREG); 5496ff6d951SJohn Birrell dt_cg_setx(dlp, reg, t.dtdt_size); 5506ff6d951SJohn Birrell } else 5516ff6d951SJohn Birrell reg = DIF_REG_R0; 5526ff6d951SJohn Birrell 5536ff6d951SJohn Birrell instr = DIF_INSTR_PUSHTS(op, t.dtdt_kind, reg, dnp->dn_reg); 5546ff6d951SJohn Birrell dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr)); 5556ff6d951SJohn Birrell dt_regset_free(drp, dnp->dn_reg); 5566ff6d951SJohn Birrell 5576ff6d951SJohn Birrell if (reg != DIF_REG_R0) 5586ff6d951SJohn Birrell dt_regset_free(drp, reg); 5596ff6d951SJohn Birrell } 5606ff6d951SJohn Birrell 5616ff6d951SJohn Birrell if (i > yypcb->pcb_hdl->dt_conf.dtc_diftupregs) 5626ff6d951SJohn Birrell longjmp(yypcb->pcb_jmpbuf, EDT_NOTUPREG); 5636ff6d951SJohn Birrell } 5646ff6d951SJohn Birrell 5656ff6d951SJohn Birrell static void 5666ff6d951SJohn Birrell dt_cg_arithmetic_op(dt_node_t *dnp, dt_irlist_t *dlp, 5676ff6d951SJohn Birrell dt_regset_t *drp, uint_t op) 5686ff6d951SJohn Birrell { 5696ff6d951SJohn Birrell int is_ptr_op = (dnp->dn_op == DT_TOK_ADD || dnp->dn_op == DT_TOK_SUB || 5706ff6d951SJohn Birrell dnp->dn_op == DT_TOK_ADD_EQ || dnp->dn_op == DT_TOK_SUB_EQ); 5716ff6d951SJohn Birrell 5726ff6d951SJohn Birrell int lp_is_ptr = dt_node_is_pointer(dnp->dn_left); 5736ff6d951SJohn Birrell int rp_is_ptr = dt_node_is_pointer(dnp->dn_right); 5746ff6d951SJohn Birrell 5756ff6d951SJohn Birrell dif_instr_t instr; 5766ff6d951SJohn Birrell 5776ff6d951SJohn Birrell if (lp_is_ptr && rp_is_ptr) { 5786ff6d951SJohn Birrell assert(dnp->dn_op == DT_TOK_SUB); 5796ff6d951SJohn Birrell is_ptr_op = 0; 5806ff6d951SJohn Birrell } 5816ff6d951SJohn Birrell 5826ff6d951SJohn Birrell dt_cg_node(dnp->dn_left, dlp, drp); 5836ff6d951SJohn Birrell if (is_ptr_op && rp_is_ptr) 5846ff6d951SJohn Birrell dt_cg_ptrsize(dnp, dlp, drp, DIF_OP_MUL, dnp->dn_left->dn_reg); 5856ff6d951SJohn Birrell 5866ff6d951SJohn Birrell dt_cg_node(dnp->dn_right, dlp, drp); 5876ff6d951SJohn Birrell if (is_ptr_op && lp_is_ptr) 5886ff6d951SJohn Birrell dt_cg_ptrsize(dnp, dlp, drp, DIF_OP_MUL, dnp->dn_right->dn_reg); 5896ff6d951SJohn Birrell 5906ff6d951SJohn Birrell instr = DIF_INSTR_FMT(op, dnp->dn_left->dn_reg, 5916ff6d951SJohn Birrell dnp->dn_right->dn_reg, dnp->dn_left->dn_reg); 5926ff6d951SJohn Birrell 5936ff6d951SJohn Birrell dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr)); 5946ff6d951SJohn Birrell dt_regset_free(drp, dnp->dn_right->dn_reg); 5956ff6d951SJohn Birrell dnp->dn_reg = dnp->dn_left->dn_reg; 5966ff6d951SJohn Birrell 5976ff6d951SJohn Birrell if (lp_is_ptr && rp_is_ptr) 5986ff6d951SJohn Birrell dt_cg_ptrsize(dnp->dn_right, 5996ff6d951SJohn Birrell dlp, drp, DIF_OP_UDIV, dnp->dn_reg); 6006ff6d951SJohn Birrell } 6016ff6d951SJohn Birrell 6026ff6d951SJohn Birrell static uint_t 6036ff6d951SJohn Birrell dt_cg_stvar(const dt_ident_t *idp) 6046ff6d951SJohn Birrell { 6056ff6d951SJohn Birrell static const uint_t aops[] = { DIF_OP_STGAA, DIF_OP_STTAA, DIF_OP_NOP }; 6066ff6d951SJohn Birrell static const uint_t sops[] = { DIF_OP_STGS, DIF_OP_STTS, DIF_OP_STLS }; 6076ff6d951SJohn Birrell 6086ff6d951SJohn Birrell uint_t i = (((idp->di_flags & DT_IDFLG_LOCAL) != 0) << 1) | 6096ff6d951SJohn Birrell ((idp->di_flags & DT_IDFLG_TLS) != 0); 6106ff6d951SJohn Birrell 6116ff6d951SJohn Birrell return (idp->di_kind == DT_IDENT_ARRAY ? aops[i] : sops[i]); 6126ff6d951SJohn Birrell } 6136ff6d951SJohn Birrell 6146ff6d951SJohn Birrell static void 6156ff6d951SJohn Birrell dt_cg_prearith_op(dt_node_t *dnp, dt_irlist_t *dlp, dt_regset_t *drp, uint_t op) 6166ff6d951SJohn Birrell { 6176ff6d951SJohn Birrell ctf_file_t *ctfp = dnp->dn_ctfp; 6186ff6d951SJohn Birrell dif_instr_t instr; 6196ff6d951SJohn Birrell ctf_id_t type; 6206ff6d951SJohn Birrell ssize_t size = 1; 6216ff6d951SJohn Birrell int reg; 6226ff6d951SJohn Birrell 6236ff6d951SJohn Birrell if (dt_node_is_pointer(dnp)) { 6246ff6d951SJohn Birrell type = ctf_type_resolve(ctfp, dnp->dn_type); 6256ff6d951SJohn Birrell assert(ctf_type_kind(ctfp, type) == CTF_K_POINTER); 6266ff6d951SJohn Birrell size = ctf_type_size(ctfp, ctf_type_reference(ctfp, type)); 6276ff6d951SJohn Birrell } 6286ff6d951SJohn Birrell 6296ff6d951SJohn Birrell dt_cg_node(dnp->dn_child, dlp, drp); 6306ff6d951SJohn Birrell dnp->dn_reg = dnp->dn_child->dn_reg; 6316ff6d951SJohn Birrell 6326ff6d951SJohn Birrell if ((reg = dt_regset_alloc(drp)) == -1) 6336ff6d951SJohn Birrell longjmp(yypcb->pcb_jmpbuf, EDT_NOREG); 6346ff6d951SJohn Birrell 6356ff6d951SJohn Birrell dt_cg_setx(dlp, reg, size); 6366ff6d951SJohn Birrell 6376ff6d951SJohn Birrell instr = DIF_INSTR_FMT(op, dnp->dn_reg, reg, dnp->dn_reg); 6386ff6d951SJohn Birrell dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr)); 6396ff6d951SJohn Birrell dt_regset_free(drp, reg); 6406ff6d951SJohn Birrell 6416ff6d951SJohn Birrell /* 6426ff6d951SJohn Birrell * If we are modifying a variable, generate an stv instruction from 6436ff6d951SJohn Birrell * the variable specified by the identifier. If we are storing to a 6446ff6d951SJohn Birrell * memory address, generate code again for the left-hand side using 6456ff6d951SJohn Birrell * DT_NF_REF to get the address, and then generate a store to it. 6466ff6d951SJohn Birrell * In both paths, we store the value in dnp->dn_reg (the new value). 6476ff6d951SJohn Birrell */ 6486ff6d951SJohn Birrell if (dnp->dn_child->dn_kind == DT_NODE_VAR) { 6496ff6d951SJohn Birrell dt_ident_t *idp = dt_ident_resolve(dnp->dn_child->dn_ident); 6506ff6d951SJohn Birrell 6516ff6d951SJohn Birrell idp->di_flags |= DT_IDFLG_DIFW; 6526ff6d951SJohn Birrell instr = DIF_INSTR_STV(dt_cg_stvar(idp), 6536ff6d951SJohn Birrell idp->di_id, dnp->dn_reg); 6546ff6d951SJohn Birrell dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr)); 6556ff6d951SJohn Birrell } else { 6566ff6d951SJohn Birrell uint_t rbit = dnp->dn_child->dn_flags & DT_NF_REF; 6576ff6d951SJohn Birrell 6586ff6d951SJohn Birrell assert(dnp->dn_child->dn_flags & DT_NF_WRITABLE); 6596ff6d951SJohn Birrell assert(dnp->dn_child->dn_flags & DT_NF_LVALUE); 6606ff6d951SJohn Birrell 6616ff6d951SJohn Birrell dnp->dn_child->dn_flags |= DT_NF_REF; /* force pass-by-ref */ 6626ff6d951SJohn Birrell dt_cg_node(dnp->dn_child, dlp, drp); 6636ff6d951SJohn Birrell 6646ff6d951SJohn Birrell dt_cg_store(dnp, dlp, drp, dnp->dn_child); 6656ff6d951SJohn Birrell dt_regset_free(drp, dnp->dn_child->dn_reg); 6666ff6d951SJohn Birrell 6676ff6d951SJohn Birrell dnp->dn_left->dn_flags &= ~DT_NF_REF; 6686ff6d951SJohn Birrell dnp->dn_left->dn_flags |= rbit; 6696ff6d951SJohn Birrell } 6706ff6d951SJohn Birrell } 6716ff6d951SJohn Birrell 6726ff6d951SJohn Birrell static void 6736ff6d951SJohn Birrell dt_cg_postarith_op(dt_node_t *dnp, dt_irlist_t *dlp, 6746ff6d951SJohn Birrell dt_regset_t *drp, uint_t op) 6756ff6d951SJohn Birrell { 6766ff6d951SJohn Birrell ctf_file_t *ctfp = dnp->dn_ctfp; 6776ff6d951SJohn Birrell dif_instr_t instr; 6786ff6d951SJohn Birrell ctf_id_t type; 6796ff6d951SJohn Birrell ssize_t size = 1; 6806ff6d951SJohn Birrell int nreg; 6816ff6d951SJohn Birrell 6826ff6d951SJohn Birrell if (dt_node_is_pointer(dnp)) { 6836ff6d951SJohn Birrell type = ctf_type_resolve(ctfp, dnp->dn_type); 6846ff6d951SJohn Birrell assert(ctf_type_kind(ctfp, type) == CTF_K_POINTER); 6856ff6d951SJohn Birrell size = ctf_type_size(ctfp, ctf_type_reference(ctfp, type)); 6866ff6d951SJohn Birrell } 6876ff6d951SJohn Birrell 6886ff6d951SJohn Birrell dt_cg_node(dnp->dn_child, dlp, drp); 6896ff6d951SJohn Birrell dnp->dn_reg = dnp->dn_child->dn_reg; 6906ff6d951SJohn Birrell 6916ff6d951SJohn Birrell if ((nreg = dt_regset_alloc(drp)) == -1) 6926ff6d951SJohn Birrell longjmp(yypcb->pcb_jmpbuf, EDT_NOREG); 6936ff6d951SJohn Birrell 6946ff6d951SJohn Birrell dt_cg_setx(dlp, nreg, size); 6956ff6d951SJohn Birrell instr = DIF_INSTR_FMT(op, dnp->dn_reg, nreg, nreg); 6966ff6d951SJohn Birrell dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr)); 6976ff6d951SJohn Birrell 6986ff6d951SJohn Birrell /* 6996ff6d951SJohn Birrell * If we are modifying a variable, generate an stv instruction from 7006ff6d951SJohn Birrell * the variable specified by the identifier. If we are storing to a 7016ff6d951SJohn Birrell * memory address, generate code again for the left-hand side using 7026ff6d951SJohn Birrell * DT_NF_REF to get the address, and then generate a store to it. 7036ff6d951SJohn Birrell * In both paths, we store the value from 'nreg' (the new value). 7046ff6d951SJohn Birrell */ 7056ff6d951SJohn Birrell if (dnp->dn_child->dn_kind == DT_NODE_VAR) { 7066ff6d951SJohn Birrell dt_ident_t *idp = dt_ident_resolve(dnp->dn_child->dn_ident); 7076ff6d951SJohn Birrell 7086ff6d951SJohn Birrell idp->di_flags |= DT_IDFLG_DIFW; 7096ff6d951SJohn Birrell instr = DIF_INSTR_STV(dt_cg_stvar(idp), idp->di_id, nreg); 7106ff6d951SJohn Birrell dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr)); 7116ff6d951SJohn Birrell } else { 7126ff6d951SJohn Birrell uint_t rbit = dnp->dn_child->dn_flags & DT_NF_REF; 7136ff6d951SJohn Birrell int oreg = dnp->dn_reg; 7146ff6d951SJohn Birrell 7156ff6d951SJohn Birrell assert(dnp->dn_child->dn_flags & DT_NF_WRITABLE); 7166ff6d951SJohn Birrell assert(dnp->dn_child->dn_flags & DT_NF_LVALUE); 7176ff6d951SJohn Birrell 7186ff6d951SJohn Birrell dnp->dn_child->dn_flags |= DT_NF_REF; /* force pass-by-ref */ 7196ff6d951SJohn Birrell dt_cg_node(dnp->dn_child, dlp, drp); 7206ff6d951SJohn Birrell 7216ff6d951SJohn Birrell dnp->dn_reg = nreg; 7226ff6d951SJohn Birrell dt_cg_store(dnp, dlp, drp, dnp->dn_child); 7236ff6d951SJohn Birrell dnp->dn_reg = oreg; 7246ff6d951SJohn Birrell 7256ff6d951SJohn Birrell dt_regset_free(drp, dnp->dn_child->dn_reg); 7266ff6d951SJohn Birrell dnp->dn_left->dn_flags &= ~DT_NF_REF; 7276ff6d951SJohn Birrell dnp->dn_left->dn_flags |= rbit; 7286ff6d951SJohn Birrell } 7296ff6d951SJohn Birrell 7306ff6d951SJohn Birrell dt_regset_free(drp, nreg); 7316ff6d951SJohn Birrell } 7326ff6d951SJohn Birrell 7336ff6d951SJohn Birrell /* 7346ff6d951SJohn Birrell * Determine if we should perform signed or unsigned comparison for an OP2. 7356ff6d951SJohn Birrell * If both operands are of arithmetic type, perform the usual arithmetic 7366ff6d951SJohn Birrell * conversions to determine the common real type for comparison [ISOC 6.5.8.3]. 7376ff6d951SJohn Birrell */ 7386ff6d951SJohn Birrell static int 7396ff6d951SJohn Birrell dt_cg_compare_signed(dt_node_t *dnp) 7406ff6d951SJohn Birrell { 7416ff6d951SJohn Birrell dt_node_t dn; 7426ff6d951SJohn Birrell 7436ff6d951SJohn Birrell if (dt_node_is_string(dnp->dn_left) || 7446ff6d951SJohn Birrell dt_node_is_string(dnp->dn_right)) 7456ff6d951SJohn Birrell return (1); /* strings always compare signed */ 7466ff6d951SJohn Birrell else if (!dt_node_is_arith(dnp->dn_left) || 7476ff6d951SJohn Birrell !dt_node_is_arith(dnp->dn_right)) 7486ff6d951SJohn Birrell return (0); /* non-arithmetic types always compare unsigned */ 7496ff6d951SJohn Birrell 7506ff6d951SJohn Birrell bzero(&dn, sizeof (dn)); 7516ff6d951SJohn Birrell dt_node_promote(dnp->dn_left, dnp->dn_right, &dn); 7526ff6d951SJohn Birrell return (dn.dn_flags & DT_NF_SIGNED); 7536ff6d951SJohn Birrell } 7546ff6d951SJohn Birrell 7556ff6d951SJohn Birrell static void 7566ff6d951SJohn Birrell dt_cg_compare_op(dt_node_t *dnp, dt_irlist_t *dlp, dt_regset_t *drp, uint_t op) 7576ff6d951SJohn Birrell { 7586ff6d951SJohn Birrell uint_t lbl_true = dt_irlist_label(dlp); 7596ff6d951SJohn Birrell uint_t lbl_post = dt_irlist_label(dlp); 7606ff6d951SJohn Birrell 7616ff6d951SJohn Birrell dif_instr_t instr; 7626ff6d951SJohn Birrell uint_t opc; 7636ff6d951SJohn Birrell 7646ff6d951SJohn Birrell dt_cg_node(dnp->dn_left, dlp, drp); 7656ff6d951SJohn Birrell dt_cg_node(dnp->dn_right, dlp, drp); 7666ff6d951SJohn Birrell 7676ff6d951SJohn Birrell if (dt_node_is_string(dnp->dn_left) || dt_node_is_string(dnp->dn_right)) 7686ff6d951SJohn Birrell opc = DIF_OP_SCMP; 7696ff6d951SJohn Birrell else 7706ff6d951SJohn Birrell opc = DIF_OP_CMP; 7716ff6d951SJohn Birrell 7726ff6d951SJohn Birrell instr = DIF_INSTR_CMP(opc, dnp->dn_left->dn_reg, dnp->dn_right->dn_reg); 7736ff6d951SJohn Birrell dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr)); 7746ff6d951SJohn Birrell dt_regset_free(drp, dnp->dn_right->dn_reg); 7756ff6d951SJohn Birrell dnp->dn_reg = dnp->dn_left->dn_reg; 7766ff6d951SJohn Birrell 7776ff6d951SJohn Birrell instr = DIF_INSTR_BRANCH(op, lbl_true); 7786ff6d951SJohn Birrell dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr)); 7796ff6d951SJohn Birrell 7806ff6d951SJohn Birrell instr = DIF_INSTR_MOV(DIF_REG_R0, dnp->dn_reg); 7816ff6d951SJohn Birrell dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr)); 7826ff6d951SJohn Birrell 7836ff6d951SJohn Birrell instr = DIF_INSTR_BRANCH(DIF_OP_BA, lbl_post); 7846ff6d951SJohn Birrell dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr)); 7856ff6d951SJohn Birrell 7866ff6d951SJohn Birrell dt_cg_xsetx(dlp, NULL, lbl_true, dnp->dn_reg, 1); 7876ff6d951SJohn Birrell dt_irlist_append(dlp, dt_cg_node_alloc(lbl_post, DIF_INSTR_NOP)); 7886ff6d951SJohn Birrell } 7896ff6d951SJohn Birrell 7906ff6d951SJohn Birrell /* 7916ff6d951SJohn Birrell * Code generation for the ternary op requires some trickery with the assembler 7926ff6d951SJohn Birrell * in order to conserve registers. We generate code for dn_expr and dn_left 7936ff6d951SJohn Birrell * and free their registers so they do not have be consumed across codegen for 7946ff6d951SJohn Birrell * dn_right. We insert a dummy MOV at the end of dn_left into the destination 7956ff6d951SJohn Birrell * register, which is not yet known because we haven't done dn_right yet, and 7966ff6d951SJohn Birrell * save the pointer to this instruction node. We then generate code for 7976ff6d951SJohn Birrell * dn_right and use its register as our output. Finally, we reach back and 7986ff6d951SJohn Birrell * patch the instruction for dn_left to move its output into this register. 7996ff6d951SJohn Birrell */ 8006ff6d951SJohn Birrell static void 8016ff6d951SJohn Birrell dt_cg_ternary_op(dt_node_t *dnp, dt_irlist_t *dlp, dt_regset_t *drp) 8026ff6d951SJohn Birrell { 8036ff6d951SJohn Birrell uint_t lbl_false = dt_irlist_label(dlp); 8046ff6d951SJohn Birrell uint_t lbl_post = dt_irlist_label(dlp); 8056ff6d951SJohn Birrell 8066ff6d951SJohn Birrell dif_instr_t instr; 8076ff6d951SJohn Birrell dt_irnode_t *dip; 8086ff6d951SJohn Birrell 8096ff6d951SJohn Birrell dt_cg_node(dnp->dn_expr, dlp, drp); 8106ff6d951SJohn Birrell instr = DIF_INSTR_TST(dnp->dn_expr->dn_reg); 8116ff6d951SJohn Birrell dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr)); 8126ff6d951SJohn Birrell dt_regset_free(drp, dnp->dn_expr->dn_reg); 8136ff6d951SJohn Birrell 8146ff6d951SJohn Birrell instr = DIF_INSTR_BRANCH(DIF_OP_BE, lbl_false); 8156ff6d951SJohn Birrell dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr)); 8166ff6d951SJohn Birrell 8176ff6d951SJohn Birrell dt_cg_node(dnp->dn_left, dlp, drp); 8186ff6d951SJohn Birrell instr = DIF_INSTR_MOV(dnp->dn_left->dn_reg, DIF_REG_R0); 8196ff6d951SJohn Birrell dip = dt_cg_node_alloc(DT_LBL_NONE, instr); /* save dip for below */ 8206ff6d951SJohn Birrell dt_irlist_append(dlp, dip); 8216ff6d951SJohn Birrell dt_regset_free(drp, dnp->dn_left->dn_reg); 8226ff6d951SJohn Birrell 8236ff6d951SJohn Birrell instr = DIF_INSTR_BRANCH(DIF_OP_BA, lbl_post); 8246ff6d951SJohn Birrell dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr)); 8256ff6d951SJohn Birrell 8266ff6d951SJohn Birrell dt_irlist_append(dlp, dt_cg_node_alloc(lbl_false, DIF_INSTR_NOP)); 8276ff6d951SJohn Birrell dt_cg_node(dnp->dn_right, dlp, drp); 8286ff6d951SJohn Birrell dnp->dn_reg = dnp->dn_right->dn_reg; 8296ff6d951SJohn Birrell 8306ff6d951SJohn Birrell /* 8316ff6d951SJohn Birrell * Now that dn_reg is assigned, reach back and patch the correct MOV 8326ff6d951SJohn Birrell * instruction into the tail of dn_left. We know dn_reg was unused 8336ff6d951SJohn Birrell * at that point because otherwise dn_right couldn't have allocated it. 8346ff6d951SJohn Birrell */ 8356ff6d951SJohn Birrell dip->di_instr = DIF_INSTR_MOV(dnp->dn_left->dn_reg, dnp->dn_reg); 8366ff6d951SJohn Birrell dt_irlist_append(dlp, dt_cg_node_alloc(lbl_post, DIF_INSTR_NOP)); 8376ff6d951SJohn Birrell } 8386ff6d951SJohn Birrell 8396ff6d951SJohn Birrell static void 8406ff6d951SJohn Birrell dt_cg_logical_and(dt_node_t *dnp, dt_irlist_t *dlp, dt_regset_t *drp) 8416ff6d951SJohn Birrell { 8426ff6d951SJohn Birrell uint_t lbl_false = dt_irlist_label(dlp); 8436ff6d951SJohn Birrell uint_t lbl_post = dt_irlist_label(dlp); 8446ff6d951SJohn Birrell 8456ff6d951SJohn Birrell dif_instr_t instr; 8466ff6d951SJohn Birrell 8476ff6d951SJohn Birrell dt_cg_node(dnp->dn_left, dlp, drp); 8486ff6d951SJohn Birrell instr = DIF_INSTR_TST(dnp->dn_left->dn_reg); 8496ff6d951SJohn Birrell dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr)); 8506ff6d951SJohn Birrell dt_regset_free(drp, dnp->dn_left->dn_reg); 8516ff6d951SJohn Birrell 8526ff6d951SJohn Birrell instr = DIF_INSTR_BRANCH(DIF_OP_BE, lbl_false); 8536ff6d951SJohn Birrell dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr)); 8546ff6d951SJohn Birrell 8556ff6d951SJohn Birrell dt_cg_node(dnp->dn_right, dlp, drp); 8566ff6d951SJohn Birrell instr = DIF_INSTR_TST(dnp->dn_right->dn_reg); 8576ff6d951SJohn Birrell dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr)); 8586ff6d951SJohn Birrell dnp->dn_reg = dnp->dn_right->dn_reg; 8596ff6d951SJohn Birrell 8606ff6d951SJohn Birrell instr = DIF_INSTR_BRANCH(DIF_OP_BE, lbl_false); 8616ff6d951SJohn Birrell dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr)); 8626ff6d951SJohn Birrell 8636ff6d951SJohn Birrell dt_cg_setx(dlp, dnp->dn_reg, 1); 8646ff6d951SJohn Birrell 8656ff6d951SJohn Birrell instr = DIF_INSTR_BRANCH(DIF_OP_BA, lbl_post); 8666ff6d951SJohn Birrell dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr)); 8676ff6d951SJohn Birrell 8686ff6d951SJohn Birrell instr = DIF_INSTR_MOV(DIF_REG_R0, dnp->dn_reg); 8696ff6d951SJohn Birrell dt_irlist_append(dlp, dt_cg_node_alloc(lbl_false, instr)); 8706ff6d951SJohn Birrell 8716ff6d951SJohn Birrell dt_irlist_append(dlp, dt_cg_node_alloc(lbl_post, DIF_INSTR_NOP)); 8726ff6d951SJohn Birrell } 8736ff6d951SJohn Birrell 8746ff6d951SJohn Birrell static void 8756ff6d951SJohn Birrell dt_cg_logical_xor(dt_node_t *dnp, dt_irlist_t *dlp, dt_regset_t *drp) 8766ff6d951SJohn Birrell { 8776ff6d951SJohn Birrell uint_t lbl_next = dt_irlist_label(dlp); 8786ff6d951SJohn Birrell uint_t lbl_tail = dt_irlist_label(dlp); 8796ff6d951SJohn Birrell 8806ff6d951SJohn Birrell dif_instr_t instr; 8816ff6d951SJohn Birrell 8826ff6d951SJohn Birrell dt_cg_node(dnp->dn_left, dlp, drp); 8836ff6d951SJohn Birrell instr = DIF_INSTR_TST(dnp->dn_left->dn_reg); 8846ff6d951SJohn Birrell dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr)); 8856ff6d951SJohn Birrell 8866ff6d951SJohn Birrell instr = DIF_INSTR_BRANCH(DIF_OP_BE, lbl_next); 8876ff6d951SJohn Birrell dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr)); 8886ff6d951SJohn Birrell dt_cg_setx(dlp, dnp->dn_left->dn_reg, 1); 8896ff6d951SJohn Birrell 8906ff6d951SJohn Birrell dt_irlist_append(dlp, dt_cg_node_alloc(lbl_next, DIF_INSTR_NOP)); 8916ff6d951SJohn Birrell dt_cg_node(dnp->dn_right, dlp, drp); 8926ff6d951SJohn Birrell 8936ff6d951SJohn Birrell instr = DIF_INSTR_TST(dnp->dn_right->dn_reg); 8946ff6d951SJohn Birrell dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr)); 8956ff6d951SJohn Birrell 8966ff6d951SJohn Birrell instr = DIF_INSTR_BRANCH(DIF_OP_BE, lbl_tail); 8976ff6d951SJohn Birrell dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr)); 8986ff6d951SJohn Birrell dt_cg_setx(dlp, dnp->dn_right->dn_reg, 1); 8996ff6d951SJohn Birrell 9006ff6d951SJohn Birrell instr = DIF_INSTR_FMT(DIF_OP_XOR, dnp->dn_left->dn_reg, 9016ff6d951SJohn Birrell dnp->dn_right->dn_reg, dnp->dn_left->dn_reg); 9026ff6d951SJohn Birrell 9036ff6d951SJohn Birrell dt_irlist_append(dlp, dt_cg_node_alloc(lbl_tail, instr)); 9046ff6d951SJohn Birrell 9056ff6d951SJohn Birrell dt_regset_free(drp, dnp->dn_right->dn_reg); 9066ff6d951SJohn Birrell dnp->dn_reg = dnp->dn_left->dn_reg; 9076ff6d951SJohn Birrell } 9086ff6d951SJohn Birrell 9096ff6d951SJohn Birrell static void 9106ff6d951SJohn Birrell dt_cg_logical_or(dt_node_t *dnp, dt_irlist_t *dlp, dt_regset_t *drp) 9116ff6d951SJohn Birrell { 9126ff6d951SJohn Birrell uint_t lbl_true = dt_irlist_label(dlp); 9136ff6d951SJohn Birrell uint_t lbl_false = dt_irlist_label(dlp); 9146ff6d951SJohn Birrell uint_t lbl_post = dt_irlist_label(dlp); 9156ff6d951SJohn Birrell 9166ff6d951SJohn Birrell dif_instr_t instr; 9176ff6d951SJohn Birrell 9186ff6d951SJohn Birrell dt_cg_node(dnp->dn_left, dlp, drp); 9196ff6d951SJohn Birrell instr = DIF_INSTR_TST(dnp->dn_left->dn_reg); 9206ff6d951SJohn Birrell dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr)); 9216ff6d951SJohn Birrell dt_regset_free(drp, dnp->dn_left->dn_reg); 9226ff6d951SJohn Birrell 9236ff6d951SJohn Birrell instr = DIF_INSTR_BRANCH(DIF_OP_BNE, lbl_true); 9246ff6d951SJohn Birrell dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr)); 9256ff6d951SJohn Birrell 9266ff6d951SJohn Birrell dt_cg_node(dnp->dn_right, dlp, drp); 9276ff6d951SJohn Birrell instr = DIF_INSTR_TST(dnp->dn_right->dn_reg); 9286ff6d951SJohn Birrell dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr)); 9296ff6d951SJohn Birrell dnp->dn_reg = dnp->dn_right->dn_reg; 9306ff6d951SJohn Birrell 9316ff6d951SJohn Birrell instr = DIF_INSTR_BRANCH(DIF_OP_BE, lbl_false); 9326ff6d951SJohn Birrell dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr)); 9336ff6d951SJohn Birrell 9346ff6d951SJohn Birrell dt_cg_xsetx(dlp, NULL, lbl_true, dnp->dn_reg, 1); 9356ff6d951SJohn Birrell 9366ff6d951SJohn Birrell instr = DIF_INSTR_BRANCH(DIF_OP_BA, lbl_post); 9376ff6d951SJohn Birrell dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr)); 9386ff6d951SJohn Birrell 9396ff6d951SJohn Birrell instr = DIF_INSTR_MOV(DIF_REG_R0, dnp->dn_reg); 9406ff6d951SJohn Birrell dt_irlist_append(dlp, dt_cg_node_alloc(lbl_false, instr)); 9416ff6d951SJohn Birrell 9426ff6d951SJohn Birrell dt_irlist_append(dlp, dt_cg_node_alloc(lbl_post, DIF_INSTR_NOP)); 9436ff6d951SJohn Birrell } 9446ff6d951SJohn Birrell 9456ff6d951SJohn Birrell static void 9466ff6d951SJohn Birrell dt_cg_logical_neg(dt_node_t *dnp, dt_irlist_t *dlp, dt_regset_t *drp) 9476ff6d951SJohn Birrell { 9486ff6d951SJohn Birrell uint_t lbl_zero = dt_irlist_label(dlp); 9496ff6d951SJohn Birrell uint_t lbl_post = dt_irlist_label(dlp); 9506ff6d951SJohn Birrell 9516ff6d951SJohn Birrell dif_instr_t instr; 9526ff6d951SJohn Birrell 9536ff6d951SJohn Birrell dt_cg_node(dnp->dn_child, dlp, drp); 9546ff6d951SJohn Birrell dnp->dn_reg = dnp->dn_child->dn_reg; 9556ff6d951SJohn Birrell 9566ff6d951SJohn Birrell instr = DIF_INSTR_TST(dnp->dn_reg); 9576ff6d951SJohn Birrell dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr)); 9586ff6d951SJohn Birrell 9596ff6d951SJohn Birrell instr = DIF_INSTR_BRANCH(DIF_OP_BE, lbl_zero); 9606ff6d951SJohn Birrell dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr)); 9616ff6d951SJohn Birrell 9626ff6d951SJohn Birrell instr = DIF_INSTR_MOV(DIF_REG_R0, dnp->dn_reg); 9636ff6d951SJohn Birrell dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr)); 9646ff6d951SJohn Birrell 9656ff6d951SJohn Birrell instr = DIF_INSTR_BRANCH(DIF_OP_BA, lbl_post); 9666ff6d951SJohn Birrell dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr)); 9676ff6d951SJohn Birrell 9686ff6d951SJohn Birrell dt_cg_xsetx(dlp, NULL, lbl_zero, dnp->dn_reg, 1); 9696ff6d951SJohn Birrell dt_irlist_append(dlp, dt_cg_node_alloc(lbl_post, DIF_INSTR_NOP)); 9706ff6d951SJohn Birrell } 9716ff6d951SJohn Birrell 9726ff6d951SJohn Birrell static void 9736ff6d951SJohn Birrell dt_cg_asgn_op(dt_node_t *dnp, dt_irlist_t *dlp, dt_regset_t *drp) 9746ff6d951SJohn Birrell { 9756ff6d951SJohn Birrell dif_instr_t instr; 9766ff6d951SJohn Birrell dt_ident_t *idp; 9776ff6d951SJohn Birrell 9786ff6d951SJohn Birrell /* 9796ff6d951SJohn Birrell * If we are performing a structure assignment of a translated type, 9806ff6d951SJohn Birrell * we must instantiate all members and create a snapshot of the object 9816ff6d951SJohn Birrell * in scratch space. We allocs a chunk of memory, generate code for 9826ff6d951SJohn Birrell * each member, and then set dnp->dn_reg to the scratch object address. 9836ff6d951SJohn Birrell */ 9846ff6d951SJohn Birrell if ((idp = dt_node_resolve(dnp->dn_right, DT_IDENT_XLSOU)) != NULL) { 9856ff6d951SJohn Birrell ctf_membinfo_t ctm; 9866ff6d951SJohn Birrell dt_xlator_t *dxp = idp->di_data; 9876ff6d951SJohn Birrell dt_node_t *mnp, dn, mn; 9886ff6d951SJohn Birrell int r1, r2; 9896ff6d951SJohn Birrell 9906ff6d951SJohn Birrell /* 9916ff6d951SJohn Birrell * Create two fake dt_node_t's representing operator "." and a 9926ff6d951SJohn Birrell * right-hand identifier child node. These will be repeatedly 9936ff6d951SJohn Birrell * modified according to each instantiated member so that we 9946ff6d951SJohn Birrell * can pass them to dt_cg_store() and effect a member store. 9956ff6d951SJohn Birrell */ 9966ff6d951SJohn Birrell bzero(&dn, sizeof (dt_node_t)); 9976ff6d951SJohn Birrell dn.dn_kind = DT_NODE_OP2; 9986ff6d951SJohn Birrell dn.dn_op = DT_TOK_DOT; 9996ff6d951SJohn Birrell dn.dn_left = dnp; 10006ff6d951SJohn Birrell dn.dn_right = &mn; 10016ff6d951SJohn Birrell 10026ff6d951SJohn Birrell bzero(&mn, sizeof (dt_node_t)); 10036ff6d951SJohn Birrell mn.dn_kind = DT_NODE_IDENT; 10046ff6d951SJohn Birrell mn.dn_op = DT_TOK_IDENT; 10056ff6d951SJohn Birrell 10066ff6d951SJohn Birrell /* 10076ff6d951SJohn Birrell * Allocate a register for our scratch data pointer. First we 10086ff6d951SJohn Birrell * set it to the size of our data structure, and then replace 10096ff6d951SJohn Birrell * it with the result of an allocs of the specified size. 10106ff6d951SJohn Birrell */ 10116ff6d951SJohn Birrell if ((r1 = dt_regset_alloc(drp)) == -1) 10126ff6d951SJohn Birrell longjmp(yypcb->pcb_jmpbuf, EDT_NOREG); 10136ff6d951SJohn Birrell 10146ff6d951SJohn Birrell dt_cg_setx(dlp, r1, 10156ff6d951SJohn Birrell ctf_type_size(dxp->dx_dst_ctfp, dxp->dx_dst_base)); 10166ff6d951SJohn Birrell 10176ff6d951SJohn Birrell instr = DIF_INSTR_ALLOCS(r1, r1); 10186ff6d951SJohn Birrell dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr)); 10196ff6d951SJohn Birrell 10206ff6d951SJohn Birrell /* 10216ff6d951SJohn Birrell * When dt_cg_asgn_op() is called, we have already generated 10226ff6d951SJohn Birrell * code for dnp->dn_right, which is the translator input. We 10236ff6d951SJohn Birrell * now associate this register with the translator's input 10246ff6d951SJohn Birrell * identifier so it can be referenced during our member loop. 10256ff6d951SJohn Birrell */ 10266ff6d951SJohn Birrell dxp->dx_ident->di_flags |= DT_IDFLG_CGREG; 10276ff6d951SJohn Birrell dxp->dx_ident->di_id = dnp->dn_right->dn_reg; 10286ff6d951SJohn Birrell 10296ff6d951SJohn Birrell for (mnp = dxp->dx_members; mnp != NULL; mnp = mnp->dn_list) { 10306ff6d951SJohn Birrell /* 10316ff6d951SJohn Birrell * Generate code for the translator member expression, 10326ff6d951SJohn Birrell * and then cast the result to the member type. 10336ff6d951SJohn Birrell */ 10346ff6d951SJohn Birrell dt_cg_node(mnp->dn_membexpr, dlp, drp); 10356ff6d951SJohn Birrell mnp->dn_reg = mnp->dn_membexpr->dn_reg; 10366ff6d951SJohn Birrell dt_cg_typecast(mnp->dn_membexpr, mnp, dlp, drp); 10376ff6d951SJohn Birrell 10386ff6d951SJohn Birrell /* 10396ff6d951SJohn Birrell * Ask CTF for the offset of the member so we can store 10406ff6d951SJohn Birrell * to the appropriate offset. This call has already 10416ff6d951SJohn Birrell * been done once by the parser, so it should succeed. 10426ff6d951SJohn Birrell */ 10436ff6d951SJohn Birrell if (ctf_member_info(dxp->dx_dst_ctfp, dxp->dx_dst_base, 10446ff6d951SJohn Birrell mnp->dn_membname, &ctm) == CTF_ERR) { 10456ff6d951SJohn Birrell yypcb->pcb_hdl->dt_ctferr = 10466ff6d951SJohn Birrell ctf_errno(dxp->dx_dst_ctfp); 10476ff6d951SJohn Birrell longjmp(yypcb->pcb_jmpbuf, EDT_CTF); 10486ff6d951SJohn Birrell } 10496ff6d951SJohn Birrell 10506ff6d951SJohn Birrell /* 10516ff6d951SJohn Birrell * If the destination member is at offset 0, store the 10526ff6d951SJohn Birrell * result directly to r1 (the scratch buffer address). 10536ff6d951SJohn Birrell * Otherwise allocate another temporary for the offset 10546ff6d951SJohn Birrell * and add r1 to it before storing the result. 10556ff6d951SJohn Birrell */ 10566ff6d951SJohn Birrell if (ctm.ctm_offset != 0) { 10576ff6d951SJohn Birrell if ((r2 = dt_regset_alloc(drp)) == -1) 10586ff6d951SJohn Birrell longjmp(yypcb->pcb_jmpbuf, EDT_NOREG); 10596ff6d951SJohn Birrell 10606ff6d951SJohn Birrell /* 10616ff6d951SJohn Birrell * Add the member offset rounded down to the 10626ff6d951SJohn Birrell * nearest byte. If the offset was not aligned 10636ff6d951SJohn Birrell * on a byte boundary, this member is a bit- 10646ff6d951SJohn Birrell * field and dt_cg_store() will handle masking. 10656ff6d951SJohn Birrell */ 10666ff6d951SJohn Birrell dt_cg_setx(dlp, r2, ctm.ctm_offset / NBBY); 10676ff6d951SJohn Birrell instr = DIF_INSTR_FMT(DIF_OP_ADD, r1, r2, r2); 10686ff6d951SJohn Birrell dt_irlist_append(dlp, 10696ff6d951SJohn Birrell dt_cg_node_alloc(DT_LBL_NONE, instr)); 10706ff6d951SJohn Birrell 10716ff6d951SJohn Birrell dt_node_type_propagate(mnp, &dn); 10726ff6d951SJohn Birrell dn.dn_right->dn_string = mnp->dn_membname; 10736ff6d951SJohn Birrell dn.dn_reg = r2; 10746ff6d951SJohn Birrell 10756ff6d951SJohn Birrell dt_cg_store(mnp, dlp, drp, &dn); 10766ff6d951SJohn Birrell dt_regset_free(drp, r2); 10776ff6d951SJohn Birrell 10786ff6d951SJohn Birrell } else { 10796ff6d951SJohn Birrell dt_node_type_propagate(mnp, &dn); 10806ff6d951SJohn Birrell dn.dn_right->dn_string = mnp->dn_membname; 10816ff6d951SJohn Birrell dn.dn_reg = r1; 10826ff6d951SJohn Birrell 10836ff6d951SJohn Birrell dt_cg_store(mnp, dlp, drp, &dn); 10846ff6d951SJohn Birrell } 10856ff6d951SJohn Birrell 10866ff6d951SJohn Birrell dt_regset_free(drp, mnp->dn_reg); 10876ff6d951SJohn Birrell } 10886ff6d951SJohn Birrell 10896ff6d951SJohn Birrell dxp->dx_ident->di_flags &= ~DT_IDFLG_CGREG; 10906ff6d951SJohn Birrell dxp->dx_ident->di_id = 0; 10916ff6d951SJohn Birrell 10926ff6d951SJohn Birrell if (dnp->dn_right->dn_reg != -1) 10936ff6d951SJohn Birrell dt_regset_free(drp, dnp->dn_right->dn_reg); 10946ff6d951SJohn Birrell 10956ff6d951SJohn Birrell assert(dnp->dn_reg == dnp->dn_right->dn_reg); 10966ff6d951SJohn Birrell dnp->dn_reg = r1; 10976ff6d951SJohn Birrell } 10986ff6d951SJohn Birrell 10996ff6d951SJohn Birrell /* 11006ff6d951SJohn Birrell * If we are storing to a variable, generate an stv instruction from 11016ff6d951SJohn Birrell * the variable specified by the identifier. If we are storing to a 11026ff6d951SJohn Birrell * memory address, generate code again for the left-hand side using 11036ff6d951SJohn Birrell * DT_NF_REF to get the address, and then generate a store to it. 11046ff6d951SJohn Birrell * In both paths, we assume dnp->dn_reg already has the new value. 11056ff6d951SJohn Birrell */ 11066ff6d951SJohn Birrell if (dnp->dn_left->dn_kind == DT_NODE_VAR) { 11076ff6d951SJohn Birrell idp = dt_ident_resolve(dnp->dn_left->dn_ident); 11086ff6d951SJohn Birrell 11096ff6d951SJohn Birrell if (idp->di_kind == DT_IDENT_ARRAY) 11106ff6d951SJohn Birrell dt_cg_arglist(idp, dnp->dn_left->dn_args, dlp, drp); 11116ff6d951SJohn Birrell 11126ff6d951SJohn Birrell idp->di_flags |= DT_IDFLG_DIFW; 11136ff6d951SJohn Birrell instr = DIF_INSTR_STV(dt_cg_stvar(idp), 11146ff6d951SJohn Birrell idp->di_id, dnp->dn_reg); 11156ff6d951SJohn Birrell dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr)); 11166ff6d951SJohn Birrell } else { 11176ff6d951SJohn Birrell uint_t rbit = dnp->dn_left->dn_flags & DT_NF_REF; 11186ff6d951SJohn Birrell 11196ff6d951SJohn Birrell assert(dnp->dn_left->dn_flags & DT_NF_WRITABLE); 11206ff6d951SJohn Birrell assert(dnp->dn_left->dn_flags & DT_NF_LVALUE); 11216ff6d951SJohn Birrell 11226ff6d951SJohn Birrell dnp->dn_left->dn_flags |= DT_NF_REF; /* force pass-by-ref */ 11236ff6d951SJohn Birrell 11246ff6d951SJohn Birrell dt_cg_node(dnp->dn_left, dlp, drp); 11256ff6d951SJohn Birrell dt_cg_store(dnp, dlp, drp, dnp->dn_left); 11266ff6d951SJohn Birrell dt_regset_free(drp, dnp->dn_left->dn_reg); 11276ff6d951SJohn Birrell 11286ff6d951SJohn Birrell dnp->dn_left->dn_flags &= ~DT_NF_REF; 11296ff6d951SJohn Birrell dnp->dn_left->dn_flags |= rbit; 11306ff6d951SJohn Birrell } 11316ff6d951SJohn Birrell } 11326ff6d951SJohn Birrell 11336ff6d951SJohn Birrell static void 11346ff6d951SJohn Birrell dt_cg_assoc_op(dt_node_t *dnp, dt_irlist_t *dlp, dt_regset_t *drp) 11356ff6d951SJohn Birrell { 11366ff6d951SJohn Birrell dif_instr_t instr; 11376ff6d951SJohn Birrell uint_t op; 11386ff6d951SJohn Birrell 11396ff6d951SJohn Birrell assert(dnp->dn_kind == DT_NODE_VAR); 11406ff6d951SJohn Birrell assert(!(dnp->dn_ident->di_flags & DT_IDFLG_LOCAL)); 11416ff6d951SJohn Birrell assert(dnp->dn_args != NULL); 11426ff6d951SJohn Birrell 11436ff6d951SJohn Birrell dt_cg_arglist(dnp->dn_ident, dnp->dn_args, dlp, drp); 11446ff6d951SJohn Birrell 11456ff6d951SJohn Birrell if ((dnp->dn_reg = dt_regset_alloc(drp)) == -1) 11466ff6d951SJohn Birrell longjmp(yypcb->pcb_jmpbuf, EDT_NOREG); 11476ff6d951SJohn Birrell 11486ff6d951SJohn Birrell if (dnp->dn_ident->di_flags & DT_IDFLG_TLS) 11496ff6d951SJohn Birrell op = DIF_OP_LDTAA; 11506ff6d951SJohn Birrell else 11516ff6d951SJohn Birrell op = DIF_OP_LDGAA; 11526ff6d951SJohn Birrell 11536ff6d951SJohn Birrell dnp->dn_ident->di_flags |= DT_IDFLG_DIFR; 11546ff6d951SJohn Birrell instr = DIF_INSTR_LDV(op, dnp->dn_ident->di_id, dnp->dn_reg); 11556ff6d951SJohn Birrell dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr)); 11566ff6d951SJohn Birrell 11576ff6d951SJohn Birrell /* 11586ff6d951SJohn Birrell * If the associative array is a pass-by-reference type, then we are 11596ff6d951SJohn Birrell * loading its value as a pointer to either load or store through it. 11606ff6d951SJohn Birrell * The array element in question may not have been faulted in yet, in 11616ff6d951SJohn Birrell * which case DIF_OP_LD*AA will return zero. We append an epilogue 11626ff6d951SJohn Birrell * of instructions similar to the following: 11636ff6d951SJohn Birrell * 11646ff6d951SJohn Birrell * ld?aa id, %r1 ! base ld?aa instruction above 11656ff6d951SJohn Birrell * tst %r1 ! start of epilogue 11666ff6d951SJohn Birrell * +--- bne label 11676ff6d951SJohn Birrell * | setx size, %r1 11686ff6d951SJohn Birrell * | allocs %r1, %r1 11696ff6d951SJohn Birrell * | st?aa id, %r1 11706ff6d951SJohn Birrell * | ld?aa id, %r1 11716ff6d951SJohn Birrell * v 11726ff6d951SJohn Birrell * label: < rest of code > 11736ff6d951SJohn Birrell * 11746ff6d951SJohn Birrell * The idea is that we allocs a zero-filled chunk of scratch space and 11756ff6d951SJohn Birrell * do a DIF_OP_ST*AA to fault in and initialize the array element, and 11766ff6d951SJohn Birrell * then reload it to get the faulted-in address of the new variable 11776ff6d951SJohn Birrell * storage. This isn't cheap, but pass-by-ref associative array values 11786ff6d951SJohn Birrell * are (thus far) uncommon and the allocs cost only occurs once. If 11796ff6d951SJohn Birrell * this path becomes important to DTrace users, we can improve things 11806ff6d951SJohn Birrell * by adding a new DIF opcode to fault in associative array elements. 11816ff6d951SJohn Birrell */ 11826ff6d951SJohn Birrell if (dnp->dn_flags & DT_NF_REF) { 11836ff6d951SJohn Birrell uint_t stvop = op == DIF_OP_LDTAA ? DIF_OP_STTAA : DIF_OP_STGAA; 11846ff6d951SJohn Birrell uint_t label = dt_irlist_label(dlp); 11856ff6d951SJohn Birrell 11866ff6d951SJohn Birrell instr = DIF_INSTR_TST(dnp->dn_reg); 11876ff6d951SJohn Birrell dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr)); 11886ff6d951SJohn Birrell 11896ff6d951SJohn Birrell instr = DIF_INSTR_BRANCH(DIF_OP_BNE, label); 11906ff6d951SJohn Birrell dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr)); 11916ff6d951SJohn Birrell 11926ff6d951SJohn Birrell dt_cg_setx(dlp, dnp->dn_reg, dt_node_type_size(dnp)); 11936ff6d951SJohn Birrell instr = DIF_INSTR_ALLOCS(dnp->dn_reg, dnp->dn_reg); 11946ff6d951SJohn Birrell dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr)); 11956ff6d951SJohn Birrell 11966ff6d951SJohn Birrell dnp->dn_ident->di_flags |= DT_IDFLG_DIFW; 11976ff6d951SJohn Birrell instr = DIF_INSTR_STV(stvop, dnp->dn_ident->di_id, dnp->dn_reg); 11986ff6d951SJohn Birrell dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr)); 11996ff6d951SJohn Birrell 12006ff6d951SJohn Birrell instr = DIF_INSTR_LDV(op, dnp->dn_ident->di_id, dnp->dn_reg); 12016ff6d951SJohn Birrell dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr)); 12026ff6d951SJohn Birrell 12036ff6d951SJohn Birrell dt_irlist_append(dlp, dt_cg_node_alloc(label, DIF_INSTR_NOP)); 12046ff6d951SJohn Birrell } 12056ff6d951SJohn Birrell } 12066ff6d951SJohn Birrell 12076ff6d951SJohn Birrell static void 12086ff6d951SJohn Birrell dt_cg_array_op(dt_node_t *dnp, dt_irlist_t *dlp, dt_regset_t *drp) 12096ff6d951SJohn Birrell { 12106ff6d951SJohn Birrell dt_probe_t *prp = yypcb->pcb_probe; 12116ff6d951SJohn Birrell uintmax_t saved = dnp->dn_args->dn_value; 12126ff6d951SJohn Birrell dt_ident_t *idp = dnp->dn_ident; 12136ff6d951SJohn Birrell 12146ff6d951SJohn Birrell dif_instr_t instr; 12156ff6d951SJohn Birrell uint_t op; 12166ff6d951SJohn Birrell size_t size; 12176ff6d951SJohn Birrell int reg, n; 12186ff6d951SJohn Birrell 12196ff6d951SJohn Birrell assert(dnp->dn_kind == DT_NODE_VAR); 12206ff6d951SJohn Birrell assert(!(idp->di_flags & DT_IDFLG_LOCAL)); 12216ff6d951SJohn Birrell 12226ff6d951SJohn Birrell assert(dnp->dn_args->dn_kind == DT_NODE_INT); 12236ff6d951SJohn Birrell assert(dnp->dn_args->dn_list == NULL); 12246ff6d951SJohn Birrell 12256ff6d951SJohn Birrell /* 12266ff6d951SJohn Birrell * If this is a reference in the args[] array, temporarily modify the 12276ff6d951SJohn Birrell * array index according to the static argument mapping (if any), 12286ff6d951SJohn Birrell * unless the argument reference is provided by a dynamic translator. 12296ff6d951SJohn Birrell * If we're using a dynamic translator for args[], then just set dn_reg 12306ff6d951SJohn Birrell * to an invalid reg and return: DIF_OP_XLARG will fetch the arg later. 12316ff6d951SJohn Birrell */ 12326ff6d951SJohn Birrell if (idp->di_id == DIF_VAR_ARGS) { 12336ff6d951SJohn Birrell if ((idp->di_kind == DT_IDENT_XLPTR || 12346ff6d951SJohn Birrell idp->di_kind == DT_IDENT_XLSOU) && 12356ff6d951SJohn Birrell dt_xlator_dynamic(idp->di_data)) { 12366ff6d951SJohn Birrell dnp->dn_reg = -1; 12376ff6d951SJohn Birrell return; 12386ff6d951SJohn Birrell } 12396ff6d951SJohn Birrell dnp->dn_args->dn_value = prp->pr_mapping[saved]; 12406ff6d951SJohn Birrell } 12416ff6d951SJohn Birrell 12426ff6d951SJohn Birrell dt_cg_node(dnp->dn_args, dlp, drp); 12436ff6d951SJohn Birrell dnp->dn_args->dn_value = saved; 12446ff6d951SJohn Birrell 12456ff6d951SJohn Birrell dnp->dn_reg = dnp->dn_args->dn_reg; 12466ff6d951SJohn Birrell 12476ff6d951SJohn Birrell if (idp->di_flags & DT_IDFLG_TLS) 12486ff6d951SJohn Birrell op = DIF_OP_LDTA; 12496ff6d951SJohn Birrell else 12506ff6d951SJohn Birrell op = DIF_OP_LDGA; 12516ff6d951SJohn Birrell 12526ff6d951SJohn Birrell idp->di_flags |= DT_IDFLG_DIFR; 12536ff6d951SJohn Birrell 12546ff6d951SJohn Birrell instr = DIF_INSTR_LDA(op, idp->di_id, 12556ff6d951SJohn Birrell dnp->dn_args->dn_reg, dnp->dn_reg); 12566ff6d951SJohn Birrell 12576ff6d951SJohn Birrell dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr)); 12586ff6d951SJohn Birrell 12596ff6d951SJohn Birrell /* 12606ff6d951SJohn Birrell * If this is a reference to the args[] array, we need to take the 12616ff6d951SJohn Birrell * additional step of explicitly eliminating any bits larger than the 12626ff6d951SJohn Birrell * type size: the DIF interpreter in the kernel will always give us 12636ff6d951SJohn Birrell * the raw (64-bit) argument value, and any bits larger than the type 12646ff6d951SJohn Birrell * size may be junk. As a practical matter, this arises only on 64-bit 12656ff6d951SJohn Birrell * architectures and only when the argument index is larger than the 12666ff6d951SJohn Birrell * number of arguments passed directly to DTrace: if a 8-, 16- or 12676ff6d951SJohn Birrell * 32-bit argument must be retrieved from the stack, it is possible 12686ff6d951SJohn Birrell * (and it some cases, likely) that the upper bits will be garbage. 12696ff6d951SJohn Birrell */ 12706ff6d951SJohn Birrell if (idp->di_id != DIF_VAR_ARGS || !dt_node_is_scalar(dnp)) 12716ff6d951SJohn Birrell return; 12726ff6d951SJohn Birrell 12736ff6d951SJohn Birrell if ((size = dt_node_type_size(dnp)) == sizeof (uint64_t)) 12746ff6d951SJohn Birrell return; 12756ff6d951SJohn Birrell 12766ff6d951SJohn Birrell if ((reg = dt_regset_alloc(drp)) == -1) 12776ff6d951SJohn Birrell longjmp(yypcb->pcb_jmpbuf, EDT_NOREG); 12786ff6d951SJohn Birrell 12796ff6d951SJohn Birrell assert(size < sizeof (uint64_t)); 12806ff6d951SJohn Birrell n = sizeof (uint64_t) * NBBY - size * NBBY; 12816ff6d951SJohn Birrell 12826ff6d951SJohn Birrell dt_cg_setx(dlp, reg, n); 12836ff6d951SJohn Birrell 12846ff6d951SJohn Birrell instr = DIF_INSTR_FMT(DIF_OP_SLL, dnp->dn_reg, reg, dnp->dn_reg); 12856ff6d951SJohn Birrell dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr)); 12866ff6d951SJohn Birrell 12876ff6d951SJohn Birrell instr = DIF_INSTR_FMT((dnp->dn_flags & DT_NF_SIGNED) ? 12886ff6d951SJohn Birrell DIF_OP_SRA : DIF_OP_SRL, dnp->dn_reg, reg, dnp->dn_reg); 12896ff6d951SJohn Birrell 12906ff6d951SJohn Birrell dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr)); 12916ff6d951SJohn Birrell dt_regset_free(drp, reg); 12926ff6d951SJohn Birrell } 12936ff6d951SJohn Birrell 12946ff6d951SJohn Birrell /* 12956ff6d951SJohn Birrell * Generate code for an inlined variable reference. Inlines can be used to 12966ff6d951SJohn Birrell * define either scalar or associative array substitutions. For scalars, we 12976ff6d951SJohn Birrell * simply generate code for the parse tree saved in the identifier's din_root, 12986ff6d951SJohn Birrell * and then cast the resulting expression to the inline's declaration type. 12996ff6d951SJohn Birrell * For arrays, we take the input parameter subtrees from dnp->dn_args and 13006ff6d951SJohn Birrell * temporarily store them in the din_root of each din_argv[i] identifier, 13016ff6d951SJohn Birrell * which are themselves inlines and were set up for us by the parser. The 13026ff6d951SJohn Birrell * result is that any reference to the inlined parameter inside the top-level 13036ff6d951SJohn Birrell * din_root will turn into a recursive call to dt_cg_inline() for a scalar 13046ff6d951SJohn Birrell * inline whose din_root will refer to the subtree pointed to by the argument. 13056ff6d951SJohn Birrell */ 13066ff6d951SJohn Birrell static void 13076ff6d951SJohn Birrell dt_cg_inline(dt_node_t *dnp, dt_irlist_t *dlp, dt_regset_t *drp) 13086ff6d951SJohn Birrell { 13096ff6d951SJohn Birrell dt_ident_t *idp = dnp->dn_ident; 13106ff6d951SJohn Birrell dt_idnode_t *inp = idp->di_iarg; 13116ff6d951SJohn Birrell 13126ff6d951SJohn Birrell dt_idnode_t *pinp; 13136ff6d951SJohn Birrell dt_node_t *pnp; 13146ff6d951SJohn Birrell int i; 13156ff6d951SJohn Birrell 13166ff6d951SJohn Birrell assert(idp->di_flags & DT_IDFLG_INLINE); 13176ff6d951SJohn Birrell assert(idp->di_ops == &dt_idops_inline); 13186ff6d951SJohn Birrell 13196ff6d951SJohn Birrell if (idp->di_kind == DT_IDENT_ARRAY) { 13206ff6d951SJohn Birrell for (i = 0, pnp = dnp->dn_args; 13216ff6d951SJohn Birrell pnp != NULL; pnp = pnp->dn_list, i++) { 13226ff6d951SJohn Birrell if (inp->din_argv[i] != NULL) { 13236ff6d951SJohn Birrell pinp = inp->din_argv[i]->di_iarg; 13246ff6d951SJohn Birrell pinp->din_root = pnp; 13256ff6d951SJohn Birrell } 13266ff6d951SJohn Birrell } 13276ff6d951SJohn Birrell } 13286ff6d951SJohn Birrell 13296ff6d951SJohn Birrell dt_cg_node(inp->din_root, dlp, drp); 13306ff6d951SJohn Birrell dnp->dn_reg = inp->din_root->dn_reg; 13316ff6d951SJohn Birrell dt_cg_typecast(inp->din_root, dnp, dlp, drp); 13326ff6d951SJohn Birrell 13336ff6d951SJohn Birrell if (idp->di_kind == DT_IDENT_ARRAY) { 13346ff6d951SJohn Birrell for (i = 0; i < inp->din_argc; i++) { 13356ff6d951SJohn Birrell pinp = inp->din_argv[i]->di_iarg; 13366ff6d951SJohn Birrell pinp->din_root = NULL; 13376ff6d951SJohn Birrell } 13386ff6d951SJohn Birrell } 13396ff6d951SJohn Birrell } 13406ff6d951SJohn Birrell 13416ff6d951SJohn Birrell static void 134218737969SJohn Birrell dt_cg_func_typeref(dtrace_hdl_t *dtp, dt_node_t *dnp) 134318737969SJohn Birrell { 134418737969SJohn Birrell dtrace_typeinfo_t dtt; 134518737969SJohn Birrell dt_node_t *addr = dnp->dn_args; 134618737969SJohn Birrell dt_node_t *nelm = addr->dn_list; 134718737969SJohn Birrell dt_node_t *strp = nelm->dn_list; 134818737969SJohn Birrell dt_node_t *typs = strp->dn_list; 134918737969SJohn Birrell char buf[DT_TYPE_NAMELEN]; 135018737969SJohn Birrell char *p; 135118737969SJohn Birrell 135218737969SJohn Birrell ctf_type_name(addr->dn_ctfp, addr->dn_type, buf, sizeof (buf)); 135318737969SJohn Birrell 135418737969SJohn Birrell /* 135518737969SJohn Birrell * XXX Hack alert! XXX 135618737969SJohn Birrell * The prototype has two dummy args that we munge to represent 135718737969SJohn Birrell * the type string and the type size. 135818737969SJohn Birrell * 135918737969SJohn Birrell * Yes, I hear your grumble, but it works for now. We'll come 136018737969SJohn Birrell * up with a more elegant implementation later. :-) 136118737969SJohn Birrell */ 136218737969SJohn Birrell free(strp->dn_string); 136318737969SJohn Birrell 136418737969SJohn Birrell if ((p = strchr(buf, '*')) != NULL) 136518737969SJohn Birrell *p = '\0'; 136618737969SJohn Birrell 136718737969SJohn Birrell strp->dn_string = strdup(buf); 136818737969SJohn Birrell 136918737969SJohn Birrell if (dtrace_lookup_by_type(dtp, DTRACE_OBJ_EVERY, buf, &dtt) < 0) 137018737969SJohn Birrell return; 137118737969SJohn Birrell 137218737969SJohn Birrell typs->dn_value = ctf_type_size(dtt.dtt_ctfp, dtt.dtt_type); 137318737969SJohn Birrell } 137418737969SJohn Birrell 137518737969SJohn Birrell static void 13766ff6d951SJohn Birrell dt_cg_node(dt_node_t *dnp, dt_irlist_t *dlp, dt_regset_t *drp) 13776ff6d951SJohn Birrell { 13786ff6d951SJohn Birrell ctf_file_t *ctfp = dnp->dn_ctfp; 13796ff6d951SJohn Birrell ctf_file_t *octfp; 13806ff6d951SJohn Birrell ctf_membinfo_t m; 13816ff6d951SJohn Birrell ctf_id_t type; 13826ff6d951SJohn Birrell 13836ff6d951SJohn Birrell dif_instr_t instr; 13846ff6d951SJohn Birrell dt_ident_t *idp; 13856ff6d951SJohn Birrell ssize_t stroff; 13866ff6d951SJohn Birrell uint_t op; 13876ff6d951SJohn Birrell int reg; 13886ff6d951SJohn Birrell 13896ff6d951SJohn Birrell switch (dnp->dn_op) { 13906ff6d951SJohn Birrell case DT_TOK_COMMA: 13916ff6d951SJohn Birrell dt_cg_node(dnp->dn_left, dlp, drp); 13926ff6d951SJohn Birrell dt_regset_free(drp, dnp->dn_left->dn_reg); 13936ff6d951SJohn Birrell dt_cg_node(dnp->dn_right, dlp, drp); 13946ff6d951SJohn Birrell dnp->dn_reg = dnp->dn_right->dn_reg; 13956ff6d951SJohn Birrell break; 13966ff6d951SJohn Birrell 13976ff6d951SJohn Birrell case DT_TOK_ASGN: 13986ff6d951SJohn Birrell dt_cg_node(dnp->dn_right, dlp, drp); 13996ff6d951SJohn Birrell dnp->dn_reg = dnp->dn_right->dn_reg; 14006ff6d951SJohn Birrell dt_cg_asgn_op(dnp, dlp, drp); 14016ff6d951SJohn Birrell break; 14026ff6d951SJohn Birrell 14036ff6d951SJohn Birrell case DT_TOK_ADD_EQ: 14046ff6d951SJohn Birrell dt_cg_arithmetic_op(dnp, dlp, drp, DIF_OP_ADD); 14056ff6d951SJohn Birrell dt_cg_asgn_op(dnp, dlp, drp); 14066ff6d951SJohn Birrell break; 14076ff6d951SJohn Birrell 14086ff6d951SJohn Birrell case DT_TOK_SUB_EQ: 14096ff6d951SJohn Birrell dt_cg_arithmetic_op(dnp, dlp, drp, DIF_OP_SUB); 14106ff6d951SJohn Birrell dt_cg_asgn_op(dnp, dlp, drp); 14116ff6d951SJohn Birrell break; 14126ff6d951SJohn Birrell 14136ff6d951SJohn Birrell case DT_TOK_MUL_EQ: 14146ff6d951SJohn Birrell dt_cg_arithmetic_op(dnp, dlp, drp, DIF_OP_MUL); 14156ff6d951SJohn Birrell dt_cg_asgn_op(dnp, dlp, drp); 14166ff6d951SJohn Birrell break; 14176ff6d951SJohn Birrell 14186ff6d951SJohn Birrell case DT_TOK_DIV_EQ: 14196ff6d951SJohn Birrell dt_cg_arithmetic_op(dnp, dlp, drp, 14206ff6d951SJohn Birrell (dnp->dn_flags & DT_NF_SIGNED) ? DIF_OP_SDIV : DIF_OP_UDIV); 14216ff6d951SJohn Birrell dt_cg_asgn_op(dnp, dlp, drp); 14226ff6d951SJohn Birrell break; 14236ff6d951SJohn Birrell 14246ff6d951SJohn Birrell case DT_TOK_MOD_EQ: 14256ff6d951SJohn Birrell dt_cg_arithmetic_op(dnp, dlp, drp, 14266ff6d951SJohn Birrell (dnp->dn_flags & DT_NF_SIGNED) ? DIF_OP_SREM : DIF_OP_UREM); 14276ff6d951SJohn Birrell dt_cg_asgn_op(dnp, dlp, drp); 14286ff6d951SJohn Birrell break; 14296ff6d951SJohn Birrell 14306ff6d951SJohn Birrell case DT_TOK_AND_EQ: 14316ff6d951SJohn Birrell dt_cg_arithmetic_op(dnp, dlp, drp, DIF_OP_AND); 14326ff6d951SJohn Birrell dt_cg_asgn_op(dnp, dlp, drp); 14336ff6d951SJohn Birrell break; 14346ff6d951SJohn Birrell 14356ff6d951SJohn Birrell case DT_TOK_XOR_EQ: 14366ff6d951SJohn Birrell dt_cg_arithmetic_op(dnp, dlp, drp, DIF_OP_XOR); 14376ff6d951SJohn Birrell dt_cg_asgn_op(dnp, dlp, drp); 14386ff6d951SJohn Birrell break; 14396ff6d951SJohn Birrell 14406ff6d951SJohn Birrell case DT_TOK_OR_EQ: 14416ff6d951SJohn Birrell dt_cg_arithmetic_op(dnp, dlp, drp, DIF_OP_OR); 14426ff6d951SJohn Birrell dt_cg_asgn_op(dnp, dlp, drp); 14436ff6d951SJohn Birrell break; 14446ff6d951SJohn Birrell 14456ff6d951SJohn Birrell case DT_TOK_LSH_EQ: 14466ff6d951SJohn Birrell dt_cg_arithmetic_op(dnp, dlp, drp, DIF_OP_SLL); 14476ff6d951SJohn Birrell dt_cg_asgn_op(dnp, dlp, drp); 14486ff6d951SJohn Birrell break; 14496ff6d951SJohn Birrell 14506ff6d951SJohn Birrell case DT_TOK_RSH_EQ: 14516ff6d951SJohn Birrell dt_cg_arithmetic_op(dnp, dlp, drp, 14526ff6d951SJohn Birrell (dnp->dn_flags & DT_NF_SIGNED) ? DIF_OP_SRA : DIF_OP_SRL); 14536ff6d951SJohn Birrell dt_cg_asgn_op(dnp, dlp, drp); 14546ff6d951SJohn Birrell break; 14556ff6d951SJohn Birrell 14566ff6d951SJohn Birrell case DT_TOK_QUESTION: 14576ff6d951SJohn Birrell dt_cg_ternary_op(dnp, dlp, drp); 14586ff6d951SJohn Birrell break; 14596ff6d951SJohn Birrell 14606ff6d951SJohn Birrell case DT_TOK_LOR: 14616ff6d951SJohn Birrell dt_cg_logical_or(dnp, dlp, drp); 14626ff6d951SJohn Birrell break; 14636ff6d951SJohn Birrell 14646ff6d951SJohn Birrell case DT_TOK_LXOR: 14656ff6d951SJohn Birrell dt_cg_logical_xor(dnp, dlp, drp); 14666ff6d951SJohn Birrell break; 14676ff6d951SJohn Birrell 14686ff6d951SJohn Birrell case DT_TOK_LAND: 14696ff6d951SJohn Birrell dt_cg_logical_and(dnp, dlp, drp); 14706ff6d951SJohn Birrell break; 14716ff6d951SJohn Birrell 14726ff6d951SJohn Birrell case DT_TOK_BOR: 14736ff6d951SJohn Birrell dt_cg_arithmetic_op(dnp, dlp, drp, DIF_OP_OR); 14746ff6d951SJohn Birrell break; 14756ff6d951SJohn Birrell 14766ff6d951SJohn Birrell case DT_TOK_XOR: 14776ff6d951SJohn Birrell dt_cg_arithmetic_op(dnp, dlp, drp, DIF_OP_XOR); 14786ff6d951SJohn Birrell break; 14796ff6d951SJohn Birrell 14806ff6d951SJohn Birrell case DT_TOK_BAND: 14816ff6d951SJohn Birrell dt_cg_arithmetic_op(dnp, dlp, drp, DIF_OP_AND); 14826ff6d951SJohn Birrell break; 14836ff6d951SJohn Birrell 14846ff6d951SJohn Birrell case DT_TOK_EQU: 14856ff6d951SJohn Birrell dt_cg_compare_op(dnp, dlp, drp, DIF_OP_BE); 14866ff6d951SJohn Birrell break; 14876ff6d951SJohn Birrell 14886ff6d951SJohn Birrell case DT_TOK_NEQ: 14896ff6d951SJohn Birrell dt_cg_compare_op(dnp, dlp, drp, DIF_OP_BNE); 14906ff6d951SJohn Birrell break; 14916ff6d951SJohn Birrell 14926ff6d951SJohn Birrell case DT_TOK_LT: 14936ff6d951SJohn Birrell dt_cg_compare_op(dnp, dlp, drp, 14946ff6d951SJohn Birrell dt_cg_compare_signed(dnp) ? DIF_OP_BL : DIF_OP_BLU); 14956ff6d951SJohn Birrell break; 14966ff6d951SJohn Birrell 14976ff6d951SJohn Birrell case DT_TOK_LE: 14986ff6d951SJohn Birrell dt_cg_compare_op(dnp, dlp, drp, 14996ff6d951SJohn Birrell dt_cg_compare_signed(dnp) ? DIF_OP_BLE : DIF_OP_BLEU); 15006ff6d951SJohn Birrell break; 15016ff6d951SJohn Birrell 15026ff6d951SJohn Birrell case DT_TOK_GT: 15036ff6d951SJohn Birrell dt_cg_compare_op(dnp, dlp, drp, 15046ff6d951SJohn Birrell dt_cg_compare_signed(dnp) ? DIF_OP_BG : DIF_OP_BGU); 15056ff6d951SJohn Birrell break; 15066ff6d951SJohn Birrell 15076ff6d951SJohn Birrell case DT_TOK_GE: 15086ff6d951SJohn Birrell dt_cg_compare_op(dnp, dlp, drp, 15096ff6d951SJohn Birrell dt_cg_compare_signed(dnp) ? DIF_OP_BGE : DIF_OP_BGEU); 15106ff6d951SJohn Birrell break; 15116ff6d951SJohn Birrell 15126ff6d951SJohn Birrell case DT_TOK_LSH: 15136ff6d951SJohn Birrell dt_cg_arithmetic_op(dnp, dlp, drp, DIF_OP_SLL); 15146ff6d951SJohn Birrell break; 15156ff6d951SJohn Birrell 15166ff6d951SJohn Birrell case DT_TOK_RSH: 15176ff6d951SJohn Birrell dt_cg_arithmetic_op(dnp, dlp, drp, 15186ff6d951SJohn Birrell (dnp->dn_flags & DT_NF_SIGNED) ? DIF_OP_SRA : DIF_OP_SRL); 15196ff6d951SJohn Birrell break; 15206ff6d951SJohn Birrell 15216ff6d951SJohn Birrell case DT_TOK_ADD: 15226ff6d951SJohn Birrell dt_cg_arithmetic_op(dnp, dlp, drp, DIF_OP_ADD); 15236ff6d951SJohn Birrell break; 15246ff6d951SJohn Birrell 15256ff6d951SJohn Birrell case DT_TOK_SUB: 15266ff6d951SJohn Birrell dt_cg_arithmetic_op(dnp, dlp, drp, DIF_OP_SUB); 15276ff6d951SJohn Birrell break; 15286ff6d951SJohn Birrell 15296ff6d951SJohn Birrell case DT_TOK_MUL: 15306ff6d951SJohn Birrell dt_cg_arithmetic_op(dnp, dlp, drp, DIF_OP_MUL); 15316ff6d951SJohn Birrell break; 15326ff6d951SJohn Birrell 15336ff6d951SJohn Birrell case DT_TOK_DIV: 15346ff6d951SJohn Birrell dt_cg_arithmetic_op(dnp, dlp, drp, 15356ff6d951SJohn Birrell (dnp->dn_flags & DT_NF_SIGNED) ? DIF_OP_SDIV : DIF_OP_UDIV); 15366ff6d951SJohn Birrell break; 15376ff6d951SJohn Birrell 15386ff6d951SJohn Birrell case DT_TOK_MOD: 15396ff6d951SJohn Birrell dt_cg_arithmetic_op(dnp, dlp, drp, 15406ff6d951SJohn Birrell (dnp->dn_flags & DT_NF_SIGNED) ? DIF_OP_SREM : DIF_OP_UREM); 15416ff6d951SJohn Birrell break; 15426ff6d951SJohn Birrell 15436ff6d951SJohn Birrell case DT_TOK_LNEG: 15446ff6d951SJohn Birrell dt_cg_logical_neg(dnp, dlp, drp); 15456ff6d951SJohn Birrell break; 15466ff6d951SJohn Birrell 15476ff6d951SJohn Birrell case DT_TOK_BNEG: 15486ff6d951SJohn Birrell dt_cg_node(dnp->dn_child, dlp, drp); 15496ff6d951SJohn Birrell dnp->dn_reg = dnp->dn_child->dn_reg; 15506ff6d951SJohn Birrell instr = DIF_INSTR_NOT(dnp->dn_reg, dnp->dn_reg); 15516ff6d951SJohn Birrell dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr)); 15526ff6d951SJohn Birrell break; 15536ff6d951SJohn Birrell 15546ff6d951SJohn Birrell case DT_TOK_PREINC: 15556ff6d951SJohn Birrell dt_cg_prearith_op(dnp, dlp, drp, DIF_OP_ADD); 15566ff6d951SJohn Birrell break; 15576ff6d951SJohn Birrell 15586ff6d951SJohn Birrell case DT_TOK_POSTINC: 15596ff6d951SJohn Birrell dt_cg_postarith_op(dnp, dlp, drp, DIF_OP_ADD); 15606ff6d951SJohn Birrell break; 15616ff6d951SJohn Birrell 15626ff6d951SJohn Birrell case DT_TOK_PREDEC: 15636ff6d951SJohn Birrell dt_cg_prearith_op(dnp, dlp, drp, DIF_OP_SUB); 15646ff6d951SJohn Birrell break; 15656ff6d951SJohn Birrell 15666ff6d951SJohn Birrell case DT_TOK_POSTDEC: 15676ff6d951SJohn Birrell dt_cg_postarith_op(dnp, dlp, drp, DIF_OP_SUB); 15686ff6d951SJohn Birrell break; 15696ff6d951SJohn Birrell 15706ff6d951SJohn Birrell case DT_TOK_IPOS: 15716ff6d951SJohn Birrell dt_cg_node(dnp->dn_child, dlp, drp); 15726ff6d951SJohn Birrell dnp->dn_reg = dnp->dn_child->dn_reg; 15736ff6d951SJohn Birrell break; 15746ff6d951SJohn Birrell 15756ff6d951SJohn Birrell case DT_TOK_INEG: 15766ff6d951SJohn Birrell dt_cg_node(dnp->dn_child, dlp, drp); 15776ff6d951SJohn Birrell dnp->dn_reg = dnp->dn_child->dn_reg; 15786ff6d951SJohn Birrell 15796ff6d951SJohn Birrell instr = DIF_INSTR_FMT(DIF_OP_SUB, DIF_REG_R0, 15806ff6d951SJohn Birrell dnp->dn_reg, dnp->dn_reg); 15816ff6d951SJohn Birrell 15826ff6d951SJohn Birrell dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr)); 15836ff6d951SJohn Birrell break; 15846ff6d951SJohn Birrell 15856ff6d951SJohn Birrell case DT_TOK_DEREF: 15866ff6d951SJohn Birrell dt_cg_node(dnp->dn_child, dlp, drp); 15876ff6d951SJohn Birrell dnp->dn_reg = dnp->dn_child->dn_reg; 15886ff6d951SJohn Birrell 15896ff6d951SJohn Birrell if (!(dnp->dn_flags & DT_NF_REF)) { 15906ff6d951SJohn Birrell uint_t ubit = dnp->dn_flags & DT_NF_USERLAND; 15916ff6d951SJohn Birrell 15926ff6d951SJohn Birrell /* 15936ff6d951SJohn Birrell * Save and restore DT_NF_USERLAND across dt_cg_load(): 15946ff6d951SJohn Birrell * we need the sign bit from dnp and the user bit from 15956ff6d951SJohn Birrell * dnp->dn_child in order to get the proper opcode. 15966ff6d951SJohn Birrell */ 15976ff6d951SJohn Birrell dnp->dn_flags |= 15986ff6d951SJohn Birrell (dnp->dn_child->dn_flags & DT_NF_USERLAND); 15996ff6d951SJohn Birrell 16006ff6d951SJohn Birrell instr = DIF_INSTR_LOAD(dt_cg_load(dnp, ctfp, 16016ff6d951SJohn Birrell dnp->dn_type), dnp->dn_reg, dnp->dn_reg); 16026ff6d951SJohn Birrell 16036ff6d951SJohn Birrell dnp->dn_flags &= ~DT_NF_USERLAND; 16046ff6d951SJohn Birrell dnp->dn_flags |= ubit; 16056ff6d951SJohn Birrell 16066ff6d951SJohn Birrell dt_irlist_append(dlp, 16076ff6d951SJohn Birrell dt_cg_node_alloc(DT_LBL_NONE, instr)); 16086ff6d951SJohn Birrell } 16096ff6d951SJohn Birrell break; 16106ff6d951SJohn Birrell 16116ff6d951SJohn Birrell case DT_TOK_ADDROF: { 16126ff6d951SJohn Birrell uint_t rbit = dnp->dn_child->dn_flags & DT_NF_REF; 16136ff6d951SJohn Birrell 16146ff6d951SJohn Birrell dnp->dn_child->dn_flags |= DT_NF_REF; /* force pass-by-ref */ 16156ff6d951SJohn Birrell dt_cg_node(dnp->dn_child, dlp, drp); 16166ff6d951SJohn Birrell dnp->dn_reg = dnp->dn_child->dn_reg; 16176ff6d951SJohn Birrell 16186ff6d951SJohn Birrell dnp->dn_child->dn_flags &= ~DT_NF_REF; 16196ff6d951SJohn Birrell dnp->dn_child->dn_flags |= rbit; 16206ff6d951SJohn Birrell break; 16216ff6d951SJohn Birrell } 16226ff6d951SJohn Birrell 16236ff6d951SJohn Birrell case DT_TOK_SIZEOF: { 16246ff6d951SJohn Birrell size_t size = dt_node_sizeof(dnp->dn_child); 16256ff6d951SJohn Birrell 16266ff6d951SJohn Birrell if ((dnp->dn_reg = dt_regset_alloc(drp)) == -1) 16276ff6d951SJohn Birrell longjmp(yypcb->pcb_jmpbuf, EDT_NOREG); 16286ff6d951SJohn Birrell 16296ff6d951SJohn Birrell assert(size != 0); 16306ff6d951SJohn Birrell dt_cg_setx(dlp, dnp->dn_reg, size); 16316ff6d951SJohn Birrell break; 16326ff6d951SJohn Birrell } 16336ff6d951SJohn Birrell 16346ff6d951SJohn Birrell case DT_TOK_STRINGOF: 16356ff6d951SJohn Birrell dt_cg_node(dnp->dn_child, dlp, drp); 16366ff6d951SJohn Birrell dnp->dn_reg = dnp->dn_child->dn_reg; 16376ff6d951SJohn Birrell break; 16386ff6d951SJohn Birrell 16396ff6d951SJohn Birrell case DT_TOK_XLATE: 16406ff6d951SJohn Birrell /* 16416ff6d951SJohn Birrell * An xlate operator appears in either an XLATOR, indicating a 16426ff6d951SJohn Birrell * reference to a dynamic translator, or an OP2, indicating 16436ff6d951SJohn Birrell * use of the xlate operator in the user's program. For the 16446ff6d951SJohn Birrell * dynamic case, generate an xlate opcode with a reference to 16456ff6d951SJohn Birrell * the corresponding member, pre-computed for us in dn_members. 16466ff6d951SJohn Birrell */ 16476ff6d951SJohn Birrell if (dnp->dn_kind == DT_NODE_XLATOR) { 16486ff6d951SJohn Birrell dt_xlator_t *dxp = dnp->dn_xlator; 16496ff6d951SJohn Birrell 16506ff6d951SJohn Birrell assert(dxp->dx_ident->di_flags & DT_IDFLG_CGREG); 16516ff6d951SJohn Birrell assert(dxp->dx_ident->di_id != 0); 16526ff6d951SJohn Birrell 16536ff6d951SJohn Birrell if ((dnp->dn_reg = dt_regset_alloc(drp)) == -1) 16546ff6d951SJohn Birrell longjmp(yypcb->pcb_jmpbuf, EDT_NOREG); 16556ff6d951SJohn Birrell 16566ff6d951SJohn Birrell if (dxp->dx_arg == -1) { 16576ff6d951SJohn Birrell instr = DIF_INSTR_MOV( 16586ff6d951SJohn Birrell dxp->dx_ident->di_id, dnp->dn_reg); 16596ff6d951SJohn Birrell dt_irlist_append(dlp, 16606ff6d951SJohn Birrell dt_cg_node_alloc(DT_LBL_NONE, instr)); 16616ff6d951SJohn Birrell op = DIF_OP_XLATE; 16626ff6d951SJohn Birrell } else 16636ff6d951SJohn Birrell op = DIF_OP_XLARG; 16646ff6d951SJohn Birrell 16656ff6d951SJohn Birrell instr = DIF_INSTR_XLATE(op, 0, dnp->dn_reg); 16666ff6d951SJohn Birrell dt_irlist_append(dlp, 16676ff6d951SJohn Birrell dt_cg_node_alloc(DT_LBL_NONE, instr)); 16686ff6d951SJohn Birrell 16696ff6d951SJohn Birrell dlp->dl_last->di_extern = dnp->dn_xmember; 16706ff6d951SJohn Birrell break; 16716ff6d951SJohn Birrell } 16726ff6d951SJohn Birrell 16736ff6d951SJohn Birrell assert(dnp->dn_kind == DT_NODE_OP2); 16746ff6d951SJohn Birrell dt_cg_node(dnp->dn_right, dlp, drp); 16756ff6d951SJohn Birrell dnp->dn_reg = dnp->dn_right->dn_reg; 16766ff6d951SJohn Birrell break; 16776ff6d951SJohn Birrell 16786ff6d951SJohn Birrell case DT_TOK_LPAR: 16796ff6d951SJohn Birrell dt_cg_node(dnp->dn_right, dlp, drp); 16806ff6d951SJohn Birrell dnp->dn_reg = dnp->dn_right->dn_reg; 16816ff6d951SJohn Birrell dt_cg_typecast(dnp->dn_right, dnp, dlp, drp); 16826ff6d951SJohn Birrell break; 16836ff6d951SJohn Birrell 16846ff6d951SJohn Birrell case DT_TOK_PTR: 16856ff6d951SJohn Birrell case DT_TOK_DOT: 16866ff6d951SJohn Birrell assert(dnp->dn_right->dn_kind == DT_NODE_IDENT); 16876ff6d951SJohn Birrell dt_cg_node(dnp->dn_left, dlp, drp); 16886ff6d951SJohn Birrell 16896ff6d951SJohn Birrell /* 16906ff6d951SJohn Birrell * If the left-hand side of PTR or DOT is a dynamic variable, 16916ff6d951SJohn Birrell * we expect it to be the output of a D translator. In this 16926ff6d951SJohn Birrell * case, we look up the parse tree corresponding to the member 16936ff6d951SJohn Birrell * that is being accessed and run the code generator over it. 16946ff6d951SJohn Birrell * We then cast the result as if by the assignment operator. 16956ff6d951SJohn Birrell */ 16966ff6d951SJohn Birrell if ((idp = dt_node_resolve( 16976ff6d951SJohn Birrell dnp->dn_left, DT_IDENT_XLSOU)) != NULL || 16986ff6d951SJohn Birrell (idp = dt_node_resolve( 16996ff6d951SJohn Birrell dnp->dn_left, DT_IDENT_XLPTR)) != NULL) { 17006ff6d951SJohn Birrell 17016ff6d951SJohn Birrell dt_xlator_t *dxp; 17026ff6d951SJohn Birrell dt_node_t *mnp; 17036ff6d951SJohn Birrell 17046ff6d951SJohn Birrell dxp = idp->di_data; 17056ff6d951SJohn Birrell mnp = dt_xlator_member(dxp, dnp->dn_right->dn_string); 17066ff6d951SJohn Birrell assert(mnp != NULL); 17076ff6d951SJohn Birrell 17086ff6d951SJohn Birrell dxp->dx_ident->di_flags |= DT_IDFLG_CGREG; 17096ff6d951SJohn Birrell dxp->dx_ident->di_id = dnp->dn_left->dn_reg; 17106ff6d951SJohn Birrell 17116ff6d951SJohn Birrell dt_cg_node(mnp->dn_membexpr, dlp, drp); 17126ff6d951SJohn Birrell dnp->dn_reg = mnp->dn_membexpr->dn_reg; 17136ff6d951SJohn Birrell dt_cg_typecast(mnp->dn_membexpr, dnp, dlp, drp); 17146ff6d951SJohn Birrell 17156ff6d951SJohn Birrell dxp->dx_ident->di_flags &= ~DT_IDFLG_CGREG; 17166ff6d951SJohn Birrell dxp->dx_ident->di_id = 0; 17176ff6d951SJohn Birrell 17186ff6d951SJohn Birrell if (dnp->dn_left->dn_reg != -1) 17196ff6d951SJohn Birrell dt_regset_free(drp, dnp->dn_left->dn_reg); 17206ff6d951SJohn Birrell break; 17216ff6d951SJohn Birrell } 17226ff6d951SJohn Birrell 17236ff6d951SJohn Birrell ctfp = dnp->dn_left->dn_ctfp; 17246ff6d951SJohn Birrell type = ctf_type_resolve(ctfp, dnp->dn_left->dn_type); 17256ff6d951SJohn Birrell 17266ff6d951SJohn Birrell if (dnp->dn_op == DT_TOK_PTR) { 17276ff6d951SJohn Birrell type = ctf_type_reference(ctfp, type); 17286ff6d951SJohn Birrell type = ctf_type_resolve(ctfp, type); 17296ff6d951SJohn Birrell } 17306ff6d951SJohn Birrell 17316ff6d951SJohn Birrell if ((ctfp = dt_cg_membinfo(octfp = ctfp, type, 17326ff6d951SJohn Birrell dnp->dn_right->dn_string, &m)) == NULL) { 17336ff6d951SJohn Birrell yypcb->pcb_hdl->dt_ctferr = ctf_errno(octfp); 17346ff6d951SJohn Birrell longjmp(yypcb->pcb_jmpbuf, EDT_CTF); 17356ff6d951SJohn Birrell } 17366ff6d951SJohn Birrell 17376ff6d951SJohn Birrell if (m.ctm_offset != 0) { 17386ff6d951SJohn Birrell if ((reg = dt_regset_alloc(drp)) == -1) 17396ff6d951SJohn Birrell longjmp(yypcb->pcb_jmpbuf, EDT_NOREG); 17406ff6d951SJohn Birrell 17416ff6d951SJohn Birrell /* 17426ff6d951SJohn Birrell * If the offset is not aligned on a byte boundary, it 17436ff6d951SJohn Birrell * is a bit-field member and we will extract the value 17446ff6d951SJohn Birrell * bits below after we generate the appropriate load. 17456ff6d951SJohn Birrell */ 17466ff6d951SJohn Birrell dt_cg_setx(dlp, reg, m.ctm_offset / NBBY); 17476ff6d951SJohn Birrell 17486ff6d951SJohn Birrell instr = DIF_INSTR_FMT(DIF_OP_ADD, 17496ff6d951SJohn Birrell dnp->dn_left->dn_reg, reg, dnp->dn_left->dn_reg); 17506ff6d951SJohn Birrell 17516ff6d951SJohn Birrell dt_irlist_append(dlp, 17526ff6d951SJohn Birrell dt_cg_node_alloc(DT_LBL_NONE, instr)); 17536ff6d951SJohn Birrell dt_regset_free(drp, reg); 17546ff6d951SJohn Birrell } 17556ff6d951SJohn Birrell 17566ff6d951SJohn Birrell if (!(dnp->dn_flags & DT_NF_REF)) { 17576ff6d951SJohn Birrell uint_t ubit = dnp->dn_flags & DT_NF_USERLAND; 17586ff6d951SJohn Birrell 17596ff6d951SJohn Birrell /* 17606ff6d951SJohn Birrell * Save and restore DT_NF_USERLAND across dt_cg_load(): 17616ff6d951SJohn Birrell * we need the sign bit from dnp and the user bit from 17626ff6d951SJohn Birrell * dnp->dn_left in order to get the proper opcode. 17636ff6d951SJohn Birrell */ 17646ff6d951SJohn Birrell dnp->dn_flags |= 17656ff6d951SJohn Birrell (dnp->dn_left->dn_flags & DT_NF_USERLAND); 17666ff6d951SJohn Birrell 17676ff6d951SJohn Birrell instr = DIF_INSTR_LOAD(dt_cg_load(dnp, 17686ff6d951SJohn Birrell ctfp, m.ctm_type), dnp->dn_left->dn_reg, 17696ff6d951SJohn Birrell dnp->dn_left->dn_reg); 17706ff6d951SJohn Birrell 17716ff6d951SJohn Birrell dnp->dn_flags &= ~DT_NF_USERLAND; 17726ff6d951SJohn Birrell dnp->dn_flags |= ubit; 17736ff6d951SJohn Birrell 17746ff6d951SJohn Birrell dt_irlist_append(dlp, 17756ff6d951SJohn Birrell dt_cg_node_alloc(DT_LBL_NONE, instr)); 17766ff6d951SJohn Birrell 17776ff6d951SJohn Birrell if (dnp->dn_flags & DT_NF_BITFIELD) 17786ff6d951SJohn Birrell dt_cg_field_get(dnp, dlp, drp, ctfp, &m); 17796ff6d951SJohn Birrell } 17806ff6d951SJohn Birrell 17816ff6d951SJohn Birrell dnp->dn_reg = dnp->dn_left->dn_reg; 17826ff6d951SJohn Birrell break; 17836ff6d951SJohn Birrell 17846ff6d951SJohn Birrell case DT_TOK_STRING: 17856ff6d951SJohn Birrell if ((dnp->dn_reg = dt_regset_alloc(drp)) == -1) 17866ff6d951SJohn Birrell longjmp(yypcb->pcb_jmpbuf, EDT_NOREG); 17876ff6d951SJohn Birrell 17886ff6d951SJohn Birrell assert(dnp->dn_kind == DT_NODE_STRING); 17896ff6d951SJohn Birrell stroff = dt_strtab_insert(yypcb->pcb_strtab, dnp->dn_string); 17906ff6d951SJohn Birrell 17916ff6d951SJohn Birrell if (stroff == -1L) 17926ff6d951SJohn Birrell longjmp(yypcb->pcb_jmpbuf, EDT_NOMEM); 17936ff6d951SJohn Birrell if (stroff > DIF_STROFF_MAX) 17946ff6d951SJohn Birrell longjmp(yypcb->pcb_jmpbuf, EDT_STR2BIG); 17956ff6d951SJohn Birrell 17966ff6d951SJohn Birrell instr = DIF_INSTR_SETS((ulong_t)stroff, dnp->dn_reg); 17976ff6d951SJohn Birrell dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr)); 17986ff6d951SJohn Birrell break; 17996ff6d951SJohn Birrell 18006ff6d951SJohn Birrell case DT_TOK_IDENT: 18016ff6d951SJohn Birrell /* 18026ff6d951SJohn Birrell * If the specified identifier is a variable on which we have 18036ff6d951SJohn Birrell * set the code generator register flag, then this variable 18046ff6d951SJohn Birrell * has already had code generated for it and saved in di_id. 18056ff6d951SJohn Birrell * Allocate a new register and copy the existing value to it. 18066ff6d951SJohn Birrell */ 18076ff6d951SJohn Birrell if (dnp->dn_kind == DT_NODE_VAR && 18086ff6d951SJohn Birrell (dnp->dn_ident->di_flags & DT_IDFLG_CGREG)) { 18096ff6d951SJohn Birrell if ((dnp->dn_reg = dt_regset_alloc(drp)) == -1) 18106ff6d951SJohn Birrell longjmp(yypcb->pcb_jmpbuf, EDT_NOREG); 18116ff6d951SJohn Birrell instr = DIF_INSTR_MOV(dnp->dn_ident->di_id, 18126ff6d951SJohn Birrell dnp->dn_reg); 18136ff6d951SJohn Birrell dt_irlist_append(dlp, 18146ff6d951SJohn Birrell dt_cg_node_alloc(DT_LBL_NONE, instr)); 18156ff6d951SJohn Birrell break; 18166ff6d951SJohn Birrell } 18176ff6d951SJohn Birrell 18186ff6d951SJohn Birrell /* 18196ff6d951SJohn Birrell * Identifiers can represent function calls, variable refs, or 18206ff6d951SJohn Birrell * symbols. First we check for inlined variables, and handle 18216ff6d951SJohn Birrell * them by generating code for the inline parse tree. 18226ff6d951SJohn Birrell */ 18236ff6d951SJohn Birrell if (dnp->dn_kind == DT_NODE_VAR && 18246ff6d951SJohn Birrell (dnp->dn_ident->di_flags & DT_IDFLG_INLINE)) { 18256ff6d951SJohn Birrell dt_cg_inline(dnp, dlp, drp); 18266ff6d951SJohn Birrell break; 18276ff6d951SJohn Birrell } 18286ff6d951SJohn Birrell 18296ff6d951SJohn Birrell switch (dnp->dn_kind) { 183018737969SJohn Birrell case DT_NODE_FUNC: { 183118737969SJohn Birrell dtrace_hdl_t *dtp = yypcb->pcb_hdl; 183218737969SJohn Birrell 18336ff6d951SJohn Birrell if ((idp = dnp->dn_ident)->di_kind != DT_IDENT_FUNC) { 18346ff6d951SJohn Birrell dnerror(dnp, D_CG_EXPR, "%s %s( ) may not be " 18356ff6d951SJohn Birrell "called from a D expression (D program " 18366ff6d951SJohn Birrell "context required)\n", 18376ff6d951SJohn Birrell dt_idkind_name(idp->di_kind), idp->di_name); 18386ff6d951SJohn Birrell } 18396ff6d951SJohn Birrell 184018737969SJohn Birrell switch (idp->di_id) { 184118737969SJohn Birrell case DIF_SUBR_TYPEREF: 184218737969SJohn Birrell dt_cg_func_typeref(dtp, dnp); 184318737969SJohn Birrell break; 184418737969SJohn Birrell 184518737969SJohn Birrell default: 184618737969SJohn Birrell break; 184718737969SJohn Birrell } 184818737969SJohn Birrell 18496ff6d951SJohn Birrell dt_cg_arglist(dnp->dn_ident, dnp->dn_args, dlp, drp); 18506ff6d951SJohn Birrell 18516ff6d951SJohn Birrell if ((dnp->dn_reg = dt_regset_alloc(drp)) == -1) 18526ff6d951SJohn Birrell longjmp(yypcb->pcb_jmpbuf, EDT_NOREG); 18536ff6d951SJohn Birrell 18546ff6d951SJohn Birrell instr = DIF_INSTR_CALL( 18556ff6d951SJohn Birrell dnp->dn_ident->di_id, dnp->dn_reg); 18566ff6d951SJohn Birrell 18576ff6d951SJohn Birrell dt_irlist_append(dlp, 18586ff6d951SJohn Birrell dt_cg_node_alloc(DT_LBL_NONE, instr)); 18596ff6d951SJohn Birrell 18606ff6d951SJohn Birrell break; 186118737969SJohn Birrell } 18626ff6d951SJohn Birrell 18636ff6d951SJohn Birrell case DT_NODE_VAR: 18646ff6d951SJohn Birrell if (dnp->dn_ident->di_kind == DT_IDENT_XLSOU || 18656ff6d951SJohn Birrell dnp->dn_ident->di_kind == DT_IDENT_XLPTR) { 18666ff6d951SJohn Birrell /* 18676ff6d951SJohn Birrell * This can only happen if we have translated 18686ff6d951SJohn Birrell * args[]. See dt_idcook_args() for details. 18696ff6d951SJohn Birrell */ 18706ff6d951SJohn Birrell assert(dnp->dn_ident->di_id == DIF_VAR_ARGS); 18716ff6d951SJohn Birrell dt_cg_array_op(dnp, dlp, drp); 18726ff6d951SJohn Birrell break; 18736ff6d951SJohn Birrell } 18746ff6d951SJohn Birrell 18756ff6d951SJohn Birrell if (dnp->dn_ident->di_kind == DT_IDENT_ARRAY) { 18766ff6d951SJohn Birrell if (dnp->dn_ident->di_id > DIF_VAR_ARRAY_MAX) 18776ff6d951SJohn Birrell dt_cg_assoc_op(dnp, dlp, drp); 18786ff6d951SJohn Birrell else 18796ff6d951SJohn Birrell dt_cg_array_op(dnp, dlp, drp); 18806ff6d951SJohn Birrell break; 18816ff6d951SJohn Birrell } 18826ff6d951SJohn Birrell 18836ff6d951SJohn Birrell if ((dnp->dn_reg = dt_regset_alloc(drp)) == -1) 18846ff6d951SJohn Birrell longjmp(yypcb->pcb_jmpbuf, EDT_NOREG); 18856ff6d951SJohn Birrell 18866ff6d951SJohn Birrell if (dnp->dn_ident->di_flags & DT_IDFLG_LOCAL) 18876ff6d951SJohn Birrell op = DIF_OP_LDLS; 18886ff6d951SJohn Birrell else if (dnp->dn_ident->di_flags & DT_IDFLG_TLS) 18896ff6d951SJohn Birrell op = DIF_OP_LDTS; 18906ff6d951SJohn Birrell else 18916ff6d951SJohn Birrell op = DIF_OP_LDGS; 18926ff6d951SJohn Birrell 18936ff6d951SJohn Birrell dnp->dn_ident->di_flags |= DT_IDFLG_DIFR; 18946ff6d951SJohn Birrell 18956ff6d951SJohn Birrell instr = DIF_INSTR_LDV(op, 18966ff6d951SJohn Birrell dnp->dn_ident->di_id, dnp->dn_reg); 18976ff6d951SJohn Birrell 18986ff6d951SJohn Birrell dt_irlist_append(dlp, 18996ff6d951SJohn Birrell dt_cg_node_alloc(DT_LBL_NONE, instr)); 19006ff6d951SJohn Birrell break; 19016ff6d951SJohn Birrell 19026ff6d951SJohn Birrell case DT_NODE_SYM: { 19036ff6d951SJohn Birrell dtrace_hdl_t *dtp = yypcb->pcb_hdl; 19046ff6d951SJohn Birrell dtrace_syminfo_t *sip = dnp->dn_ident->di_data; 19056ff6d951SJohn Birrell GElf_Sym sym; 19066ff6d951SJohn Birrell 19076ff6d951SJohn Birrell if (dtrace_lookup_by_name(dtp, 19086ff6d951SJohn Birrell sip->dts_object, sip->dts_name, &sym, NULL) == -1) { 19096ff6d951SJohn Birrell xyerror(D_UNKNOWN, "cg failed for symbol %s`%s:" 19106ff6d951SJohn Birrell " %s\n", sip->dts_object, sip->dts_name, 19116ff6d951SJohn Birrell dtrace_errmsg(dtp, dtrace_errno(dtp))); 19126ff6d951SJohn Birrell } 19136ff6d951SJohn Birrell 19146ff6d951SJohn Birrell if ((dnp->dn_reg = dt_regset_alloc(drp)) == -1) 19156ff6d951SJohn Birrell longjmp(yypcb->pcb_jmpbuf, EDT_NOREG); 19166ff6d951SJohn Birrell 19176ff6d951SJohn Birrell dt_cg_xsetx(dlp, dnp->dn_ident, 19186ff6d951SJohn Birrell DT_LBL_NONE, dnp->dn_reg, sym.st_value); 19196ff6d951SJohn Birrell 19206ff6d951SJohn Birrell if (!(dnp->dn_flags & DT_NF_REF)) { 19216ff6d951SJohn Birrell instr = DIF_INSTR_LOAD(dt_cg_load(dnp, ctfp, 19226ff6d951SJohn Birrell dnp->dn_type), dnp->dn_reg, dnp->dn_reg); 19236ff6d951SJohn Birrell dt_irlist_append(dlp, 19246ff6d951SJohn Birrell dt_cg_node_alloc(DT_LBL_NONE, instr)); 19256ff6d951SJohn Birrell } 19266ff6d951SJohn Birrell break; 19276ff6d951SJohn Birrell } 19286ff6d951SJohn Birrell 19296ff6d951SJohn Birrell default: 19306ff6d951SJohn Birrell xyerror(D_UNKNOWN, "internal error -- node type %u is " 19316ff6d951SJohn Birrell "not valid for an identifier\n", dnp->dn_kind); 19326ff6d951SJohn Birrell } 19336ff6d951SJohn Birrell break; 19346ff6d951SJohn Birrell 19356ff6d951SJohn Birrell case DT_TOK_INT: 19366ff6d951SJohn Birrell if ((dnp->dn_reg = dt_regset_alloc(drp)) == -1) 19376ff6d951SJohn Birrell longjmp(yypcb->pcb_jmpbuf, EDT_NOREG); 19386ff6d951SJohn Birrell 19396ff6d951SJohn Birrell dt_cg_setx(dlp, dnp->dn_reg, dnp->dn_value); 19406ff6d951SJohn Birrell break; 19416ff6d951SJohn Birrell 19426ff6d951SJohn Birrell default: 19436ff6d951SJohn Birrell xyerror(D_UNKNOWN, "internal error -- token type %u is not a " 19446ff6d951SJohn Birrell "valid D compilation token\n", dnp->dn_op); 19456ff6d951SJohn Birrell } 19466ff6d951SJohn Birrell } 19476ff6d951SJohn Birrell 19486ff6d951SJohn Birrell void 19496ff6d951SJohn Birrell dt_cg(dt_pcb_t *pcb, dt_node_t *dnp) 19506ff6d951SJohn Birrell { 19516ff6d951SJohn Birrell dif_instr_t instr; 19526ff6d951SJohn Birrell dt_xlator_t *dxp; 19536ff6d951SJohn Birrell 19546ff6d951SJohn Birrell if (pcb->pcb_regs == NULL && (pcb->pcb_regs = 19556ff6d951SJohn Birrell dt_regset_create(pcb->pcb_hdl->dt_conf.dtc_difintregs)) == NULL) 19566ff6d951SJohn Birrell longjmp(pcb->pcb_jmpbuf, EDT_NOMEM); 19576ff6d951SJohn Birrell 19586ff6d951SJohn Birrell dt_regset_reset(pcb->pcb_regs); 19596ff6d951SJohn Birrell (void) dt_regset_alloc(pcb->pcb_regs); /* allocate %r0 */ 19606ff6d951SJohn Birrell 19616ff6d951SJohn Birrell if (pcb->pcb_inttab != NULL) 19626ff6d951SJohn Birrell dt_inttab_destroy(pcb->pcb_inttab); 19636ff6d951SJohn Birrell 19646ff6d951SJohn Birrell if ((pcb->pcb_inttab = dt_inttab_create(yypcb->pcb_hdl)) == NULL) 19656ff6d951SJohn Birrell longjmp(pcb->pcb_jmpbuf, EDT_NOMEM); 19666ff6d951SJohn Birrell 19676ff6d951SJohn Birrell if (pcb->pcb_strtab != NULL) 19686ff6d951SJohn Birrell dt_strtab_destroy(pcb->pcb_strtab); 19696ff6d951SJohn Birrell 19706ff6d951SJohn Birrell if ((pcb->pcb_strtab = dt_strtab_create(BUFSIZ)) == NULL) 19716ff6d951SJohn Birrell longjmp(pcb->pcb_jmpbuf, EDT_NOMEM); 19726ff6d951SJohn Birrell 19736ff6d951SJohn Birrell dt_irlist_destroy(&pcb->pcb_ir); 19746ff6d951SJohn Birrell dt_irlist_create(&pcb->pcb_ir); 19756ff6d951SJohn Birrell 19766ff6d951SJohn Birrell assert(pcb->pcb_dret == NULL); 19776ff6d951SJohn Birrell pcb->pcb_dret = dnp; 19786ff6d951SJohn Birrell 19796ff6d951SJohn Birrell if (dt_node_is_dynamic(dnp)) { 19806ff6d951SJohn Birrell dnerror(dnp, D_CG_DYN, "expression cannot evaluate to result " 19816ff6d951SJohn Birrell "of dynamic type\n"); 19826ff6d951SJohn Birrell } 19836ff6d951SJohn Birrell 19846ff6d951SJohn Birrell /* 19856ff6d951SJohn Birrell * If we're generating code for a translator body, assign the input 19866ff6d951SJohn Birrell * parameter to the first available register (i.e. caller passes %r1). 19876ff6d951SJohn Birrell */ 19886ff6d951SJohn Birrell if (dnp->dn_kind == DT_NODE_MEMBER) { 19896ff6d951SJohn Birrell dxp = dnp->dn_membxlator; 19906ff6d951SJohn Birrell dnp = dnp->dn_membexpr; 19916ff6d951SJohn Birrell 19926ff6d951SJohn Birrell dxp->dx_ident->di_flags |= DT_IDFLG_CGREG; 19936ff6d951SJohn Birrell dxp->dx_ident->di_id = dt_regset_alloc(pcb->pcb_regs); 19946ff6d951SJohn Birrell } 19956ff6d951SJohn Birrell 19966ff6d951SJohn Birrell dt_cg_node(dnp, &pcb->pcb_ir, pcb->pcb_regs); 19976ff6d951SJohn Birrell instr = DIF_INSTR_RET(dnp->dn_reg); 19986ff6d951SJohn Birrell dt_regset_free(pcb->pcb_regs, dnp->dn_reg); 19996ff6d951SJohn Birrell dt_irlist_append(&pcb->pcb_ir, dt_cg_node_alloc(DT_LBL_NONE, instr)); 20006ff6d951SJohn Birrell 20016ff6d951SJohn Birrell if (dnp->dn_kind == DT_NODE_MEMBER) { 20026ff6d951SJohn Birrell dt_regset_free(pcb->pcb_regs, dxp->dx_ident->di_id); 20036ff6d951SJohn Birrell dxp->dx_ident->di_id = 0; 20046ff6d951SJohn Birrell dxp->dx_ident->di_flags &= ~DT_IDFLG_CGREG; 20056ff6d951SJohn Birrell } 20066ff6d951SJohn Birrell } 2007