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