17c478bd9Sstevel@tonic-gate /* 27c478bd9Sstevel@tonic-gate * CDDL HEADER START 37c478bd9Sstevel@tonic-gate * 47c478bd9Sstevel@tonic-gate * The contents of this file are subject to the terms of the 57c478bd9Sstevel@tonic-gate * Common Development and Distribution License, Version 1.0 only 67c478bd9Sstevel@tonic-gate * (the "License"). You may not use this file except in compliance 77c478bd9Sstevel@tonic-gate * with the License. 87c478bd9Sstevel@tonic-gate * 97c478bd9Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 107c478bd9Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 117c478bd9Sstevel@tonic-gate * See the License for the specific language governing permissions 127c478bd9Sstevel@tonic-gate * and limitations under the License. 137c478bd9Sstevel@tonic-gate * 147c478bd9Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 157c478bd9Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 167c478bd9Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 177c478bd9Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 187c478bd9Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 197c478bd9Sstevel@tonic-gate * 207c478bd9Sstevel@tonic-gate * CDDL HEADER END 217c478bd9Sstevel@tonic-gate */ 22e5803b76SAdam H. Leventhal 237c478bd9Sstevel@tonic-gate /* 247c478bd9Sstevel@tonic-gate * Copyright 2005 Sun Microsystems, Inc. All rights reserved. 257c478bd9Sstevel@tonic-gate * Use is subject to license terms. 267c478bd9Sstevel@tonic-gate */ 277c478bd9Sstevel@tonic-gate 28e5803b76SAdam H. Leventhal /* 29e5803b76SAdam H. Leventhal * Copyright (c) 2012 by Delphix. All rights reserved. 30e5803b76SAdam H. Leventhal */ 317c478bd9Sstevel@tonic-gate 327c478bd9Sstevel@tonic-gate #include <sys/types.h> 337c478bd9Sstevel@tonic-gate #include <sys/sysmacros.h> 347c478bd9Sstevel@tonic-gate #include <sys/isa_defs.h> 357c478bd9Sstevel@tonic-gate 367c478bd9Sstevel@tonic-gate #include <strings.h> 377c478bd9Sstevel@tonic-gate #include <stdlib.h> 387c478bd9Sstevel@tonic-gate #include <setjmp.h> 397c478bd9Sstevel@tonic-gate #include <assert.h> 407c478bd9Sstevel@tonic-gate #include <errno.h> 417c478bd9Sstevel@tonic-gate 427c478bd9Sstevel@tonic-gate #include <dt_impl.h> 437c478bd9Sstevel@tonic-gate #include <dt_grammar.h> 447c478bd9Sstevel@tonic-gate #include <dt_parser.h> 457c478bd9Sstevel@tonic-gate #include <dt_provider.h> 467c478bd9Sstevel@tonic-gate 477c478bd9Sstevel@tonic-gate static void dt_cg_node(dt_node_t *, dt_irlist_t *, dt_regset_t *); 487c478bd9Sstevel@tonic-gate 497c478bd9Sstevel@tonic-gate static dt_irnode_t * 507c478bd9Sstevel@tonic-gate dt_cg_node_alloc(uint_t label, dif_instr_t instr) 517c478bd9Sstevel@tonic-gate { 527c478bd9Sstevel@tonic-gate dt_irnode_t *dip = malloc(sizeof (dt_irnode_t)); 537c478bd9Sstevel@tonic-gate 547c478bd9Sstevel@tonic-gate if (dip == NULL) 557c478bd9Sstevel@tonic-gate longjmp(yypcb->pcb_jmpbuf, EDT_NOMEM); 567c478bd9Sstevel@tonic-gate 577c478bd9Sstevel@tonic-gate dip->di_label = label; 587c478bd9Sstevel@tonic-gate dip->di_instr = instr; 591a7c1b72Smws dip->di_extern = NULL; 607c478bd9Sstevel@tonic-gate dip->di_next = NULL; 617c478bd9Sstevel@tonic-gate 627c478bd9Sstevel@tonic-gate return (dip); 637c478bd9Sstevel@tonic-gate } 647c478bd9Sstevel@tonic-gate 657c478bd9Sstevel@tonic-gate /* 667c478bd9Sstevel@tonic-gate * Code generator wrapper function for ctf_member_info. If we are given a 677c478bd9Sstevel@tonic-gate * reference to a forward declaration tag, search the entire type space for 687c478bd9Sstevel@tonic-gate * the actual definition and then call ctf_member_info on the result. 697c478bd9Sstevel@tonic-gate */ 707c478bd9Sstevel@tonic-gate static ctf_file_t * 717c478bd9Sstevel@tonic-gate dt_cg_membinfo(ctf_file_t *fp, ctf_id_t type, const char *s, ctf_membinfo_t *mp) 727c478bd9Sstevel@tonic-gate { 737c478bd9Sstevel@tonic-gate while (ctf_type_kind(fp, type) == CTF_K_FORWARD) { 747c478bd9Sstevel@tonic-gate char n[DT_TYPE_NAMELEN]; 757c478bd9Sstevel@tonic-gate dtrace_typeinfo_t dtt; 767c478bd9Sstevel@tonic-gate 777c478bd9Sstevel@tonic-gate if (ctf_type_name(fp, type, n, sizeof (n)) == NULL || 787c478bd9Sstevel@tonic-gate dt_type_lookup(n, &dtt) == -1 || ( 797c478bd9Sstevel@tonic-gate dtt.dtt_ctfp == fp && dtt.dtt_type == type)) 807c478bd9Sstevel@tonic-gate break; /* unable to improve our position */ 817c478bd9Sstevel@tonic-gate 827c478bd9Sstevel@tonic-gate fp = dtt.dtt_ctfp; 837c478bd9Sstevel@tonic-gate type = ctf_type_resolve(fp, dtt.dtt_type); 847c478bd9Sstevel@tonic-gate } 857c478bd9Sstevel@tonic-gate 867c478bd9Sstevel@tonic-gate if (ctf_member_info(fp, type, s, mp) == CTF_ERR) 877c478bd9Sstevel@tonic-gate return (NULL); /* ctf_errno is set for us */ 887c478bd9Sstevel@tonic-gate 897c478bd9Sstevel@tonic-gate return (fp); 907c478bd9Sstevel@tonic-gate } 917c478bd9Sstevel@tonic-gate 927c478bd9Sstevel@tonic-gate static void 937c478bd9Sstevel@tonic-gate dt_cg_xsetx(dt_irlist_t *dlp, dt_ident_t *idp, uint_t lbl, int reg, uint64_t x) 947c478bd9Sstevel@tonic-gate { 957c478bd9Sstevel@tonic-gate int flag = idp != NULL ? DT_INT_PRIVATE : DT_INT_SHARED; 967c478bd9Sstevel@tonic-gate int intoff = dt_inttab_insert(yypcb->pcb_inttab, x, flag); 977c478bd9Sstevel@tonic-gate dif_instr_t instr = DIF_INSTR_SETX((uint_t)intoff, reg); 987c478bd9Sstevel@tonic-gate 997c478bd9Sstevel@tonic-gate if (intoff == -1) 1007c478bd9Sstevel@tonic-gate longjmp(yypcb->pcb_jmpbuf, EDT_NOMEM); 1017c478bd9Sstevel@tonic-gate 1027c478bd9Sstevel@tonic-gate if (intoff > DIF_INTOFF_MAX) 1037c478bd9Sstevel@tonic-gate longjmp(yypcb->pcb_jmpbuf, EDT_INT2BIG); 1047c478bd9Sstevel@tonic-gate 1057c478bd9Sstevel@tonic-gate dt_irlist_append(dlp, dt_cg_node_alloc(lbl, instr)); 1067c478bd9Sstevel@tonic-gate 1077c478bd9Sstevel@tonic-gate if (idp != NULL) 1081a7c1b72Smws dlp->dl_last->di_extern = idp; 1097c478bd9Sstevel@tonic-gate } 1107c478bd9Sstevel@tonic-gate 1117c478bd9Sstevel@tonic-gate static void 1127c478bd9Sstevel@tonic-gate dt_cg_setx(dt_irlist_t *dlp, int reg, uint64_t x) 1137c478bd9Sstevel@tonic-gate { 1147c478bd9Sstevel@tonic-gate dt_cg_xsetx(dlp, NULL, DT_LBL_NONE, reg, x); 1157c478bd9Sstevel@tonic-gate } 1167c478bd9Sstevel@tonic-gate 1177c478bd9Sstevel@tonic-gate /* 1187c478bd9Sstevel@tonic-gate * When loading bit-fields, we want to convert a byte count in the range 1197c478bd9Sstevel@tonic-gate * 1-8 to the closest power of 2 (e.g. 3->4, 5->8, etc). The clp2() function 1207c478bd9Sstevel@tonic-gate * is a clever implementation from "Hacker's Delight" by Henry Warren, Jr. 1217c478bd9Sstevel@tonic-gate */ 1227c478bd9Sstevel@tonic-gate static size_t 1237c478bd9Sstevel@tonic-gate clp2(size_t x) 1247c478bd9Sstevel@tonic-gate { 1257c478bd9Sstevel@tonic-gate x--; 1267c478bd9Sstevel@tonic-gate 1277c478bd9Sstevel@tonic-gate x |= (x >> 1); 1287c478bd9Sstevel@tonic-gate x |= (x >> 2); 1297c478bd9Sstevel@tonic-gate x |= (x >> 4); 1307c478bd9Sstevel@tonic-gate x |= (x >> 8); 1317c478bd9Sstevel@tonic-gate x |= (x >> 16); 1327c478bd9Sstevel@tonic-gate 1337c478bd9Sstevel@tonic-gate return (x + 1); 1347c478bd9Sstevel@tonic-gate } 1357c478bd9Sstevel@tonic-gate 1367c478bd9Sstevel@tonic-gate /* 1377c478bd9Sstevel@tonic-gate * Lookup the correct load opcode to use for the specified node and CTF type. 1387c478bd9Sstevel@tonic-gate * We determine the size and convert it to a 3-bit index. Our lookup table 1397c478bd9Sstevel@tonic-gate * is constructed to use a 5-bit index, consisting of the 3-bit size 0-7, a 1407c478bd9Sstevel@tonic-gate * bit for the sign, and a bit for userland address. For example, a 4-byte 1417c478bd9Sstevel@tonic-gate * signed load from userland would be at the following table index: 1427c478bd9Sstevel@tonic-gate * user=1 sign=1 size=4 => binary index 11011 = decimal index 27 1437c478bd9Sstevel@tonic-gate */ 1447c478bd9Sstevel@tonic-gate static uint_t 1457c478bd9Sstevel@tonic-gate dt_cg_load(dt_node_t *dnp, ctf_file_t *ctfp, ctf_id_t type) 1467c478bd9Sstevel@tonic-gate { 1477c478bd9Sstevel@tonic-gate static const uint_t ops[] = { 1487c478bd9Sstevel@tonic-gate DIF_OP_LDUB, DIF_OP_LDUH, 0, DIF_OP_LDUW, 1497c478bd9Sstevel@tonic-gate 0, 0, 0, DIF_OP_LDX, 1507c478bd9Sstevel@tonic-gate DIF_OP_LDSB, DIF_OP_LDSH, 0, DIF_OP_LDSW, 1517c478bd9Sstevel@tonic-gate 0, 0, 0, DIF_OP_LDX, 1527c478bd9Sstevel@tonic-gate DIF_OP_ULDUB, DIF_OP_ULDUH, 0, DIF_OP_ULDUW, 1537c478bd9Sstevel@tonic-gate 0, 0, 0, DIF_OP_ULDX, 1547c478bd9Sstevel@tonic-gate DIF_OP_ULDSB, DIF_OP_ULDSH, 0, DIF_OP_ULDSW, 1557c478bd9Sstevel@tonic-gate 0, 0, 0, DIF_OP_ULDX, 1567c478bd9Sstevel@tonic-gate }; 1577c478bd9Sstevel@tonic-gate 1587c478bd9Sstevel@tonic-gate ctf_encoding_t e; 1597c478bd9Sstevel@tonic-gate ssize_t size; 1607c478bd9Sstevel@tonic-gate 1617c478bd9Sstevel@tonic-gate /* 1627c478bd9Sstevel@tonic-gate * If we're loading a bit-field, the size of our load is found by 1637c478bd9Sstevel@tonic-gate * rounding cte_bits up to a byte boundary and then finding the 1647c478bd9Sstevel@tonic-gate * nearest power of two to this value (see clp2(), above). 1657c478bd9Sstevel@tonic-gate */ 1667c478bd9Sstevel@tonic-gate if ((dnp->dn_flags & DT_NF_BITFIELD) && 1677c478bd9Sstevel@tonic-gate ctf_type_encoding(ctfp, type, &e) != CTF_ERR) 1687c478bd9Sstevel@tonic-gate size = clp2(P2ROUNDUP(e.cte_bits, NBBY) / NBBY); 1697c478bd9Sstevel@tonic-gate else 1707c478bd9Sstevel@tonic-gate size = ctf_type_size(ctfp, type); 1717c478bd9Sstevel@tonic-gate 1727c478bd9Sstevel@tonic-gate if (size < 1 || size > 8 || (size & (size - 1)) != 0) { 1737c478bd9Sstevel@tonic-gate xyerror(D_UNKNOWN, "internal error -- cg cannot load " 1747c478bd9Sstevel@tonic-gate "size %ld when passed by value\n", (long)size); 1757c478bd9Sstevel@tonic-gate } 1767c478bd9Sstevel@tonic-gate 1777c478bd9Sstevel@tonic-gate size--; /* convert size to 3-bit index */ 1787c478bd9Sstevel@tonic-gate 1797c478bd9Sstevel@tonic-gate if (dnp->dn_flags & DT_NF_SIGNED) 1807c478bd9Sstevel@tonic-gate size |= 0x08; 1817c478bd9Sstevel@tonic-gate if (dnp->dn_flags & DT_NF_USERLAND) 1827c478bd9Sstevel@tonic-gate size |= 0x10; 1837c478bd9Sstevel@tonic-gate 1847c478bd9Sstevel@tonic-gate return (ops[size]); 1857c478bd9Sstevel@tonic-gate } 1867c478bd9Sstevel@tonic-gate 1877c478bd9Sstevel@tonic-gate static void 1887c478bd9Sstevel@tonic-gate dt_cg_ptrsize(dt_node_t *dnp, dt_irlist_t *dlp, dt_regset_t *drp, 1897c478bd9Sstevel@tonic-gate uint_t op, int dreg) 1907c478bd9Sstevel@tonic-gate { 1917c478bd9Sstevel@tonic-gate ctf_file_t *ctfp = dnp->dn_ctfp; 1927c478bd9Sstevel@tonic-gate ctf_arinfo_t r; 1937c478bd9Sstevel@tonic-gate dif_instr_t instr; 1947c478bd9Sstevel@tonic-gate ctf_id_t type; 1957c478bd9Sstevel@tonic-gate uint_t kind; 1967c478bd9Sstevel@tonic-gate ssize_t size; 1977c478bd9Sstevel@tonic-gate int sreg; 1987c478bd9Sstevel@tonic-gate 1997c478bd9Sstevel@tonic-gate type = ctf_type_resolve(ctfp, dnp->dn_type); 2007c478bd9Sstevel@tonic-gate kind = ctf_type_kind(ctfp, type); 2017c478bd9Sstevel@tonic-gate assert(kind == CTF_K_POINTER || kind == CTF_K_ARRAY); 2027c478bd9Sstevel@tonic-gate 2037c478bd9Sstevel@tonic-gate if (kind == CTF_K_ARRAY) { 2047c478bd9Sstevel@tonic-gate if (ctf_array_info(ctfp, type, &r) != 0) { 2057c478bd9Sstevel@tonic-gate yypcb->pcb_hdl->dt_ctferr = ctf_errno(ctfp); 2067c478bd9Sstevel@tonic-gate longjmp(yypcb->pcb_jmpbuf, EDT_CTF); 2077c478bd9Sstevel@tonic-gate } 2087c478bd9Sstevel@tonic-gate type = r.ctr_contents; 2097c478bd9Sstevel@tonic-gate } else 2107c478bd9Sstevel@tonic-gate type = ctf_type_reference(ctfp, type); 2117c478bd9Sstevel@tonic-gate 2127c478bd9Sstevel@tonic-gate if ((size = ctf_type_size(ctfp, type)) == 1) 2137c478bd9Sstevel@tonic-gate return; /* multiply or divide by one can be omitted */ 2147c478bd9Sstevel@tonic-gate 215e5803b76SAdam H. Leventhal sreg = dt_regset_alloc(drp); 2167c478bd9Sstevel@tonic-gate dt_cg_setx(dlp, sreg, size); 2177c478bd9Sstevel@tonic-gate instr = DIF_INSTR_FMT(op, dreg, sreg, dreg); 2187c478bd9Sstevel@tonic-gate dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr)); 2197c478bd9Sstevel@tonic-gate dt_regset_free(drp, sreg); 2207c478bd9Sstevel@tonic-gate } 2217c478bd9Sstevel@tonic-gate 2227c478bd9Sstevel@tonic-gate /* 2237c478bd9Sstevel@tonic-gate * If the result of a "." or "->" operation is a bit-field, we use this routine 2247c478bd9Sstevel@tonic-gate * to generate an epilogue to the load instruction that extracts the value. In 2257c478bd9Sstevel@tonic-gate * the diagrams below the "ld??" is the load instruction that is generated to 2267c478bd9Sstevel@tonic-gate * load the containing word that is generating prior to calling this function. 2277c478bd9Sstevel@tonic-gate * 2287c478bd9Sstevel@tonic-gate * Epilogue for unsigned fields: Epilogue for signed fields: 2297c478bd9Sstevel@tonic-gate * 2307c478bd9Sstevel@tonic-gate * ldu? [r1], r1 lds? [r1], r1 2317c478bd9Sstevel@tonic-gate * setx USHIFT, r2 setx 64 - SSHIFT, r2 2327c478bd9Sstevel@tonic-gate * srl r1, r2, r1 sll r1, r2, r1 2337c478bd9Sstevel@tonic-gate * setx (1 << bits) - 1, r2 setx 64 - bits, r2 2347c478bd9Sstevel@tonic-gate * and r1, r2, r1 sra r1, r2, r1 2357c478bd9Sstevel@tonic-gate * 2367c478bd9Sstevel@tonic-gate * The *SHIFT constants above changes value depending on the endian-ness of our 2377c478bd9Sstevel@tonic-gate * target architecture. Refer to the comments below for more details. 2387c478bd9Sstevel@tonic-gate */ 2397c478bd9Sstevel@tonic-gate static void 2407c478bd9Sstevel@tonic-gate dt_cg_field_get(dt_node_t *dnp, dt_irlist_t *dlp, dt_regset_t *drp, 2417c478bd9Sstevel@tonic-gate ctf_file_t *fp, const ctf_membinfo_t *mp) 2427c478bd9Sstevel@tonic-gate { 2437c478bd9Sstevel@tonic-gate ctf_encoding_t e; 2447c478bd9Sstevel@tonic-gate dif_instr_t instr; 2457c478bd9Sstevel@tonic-gate uint64_t shift; 2467c478bd9Sstevel@tonic-gate int r1, r2; 2477c478bd9Sstevel@tonic-gate 2487c478bd9Sstevel@tonic-gate if (ctf_type_encoding(fp, mp->ctm_type, &e) != 0 || e.cte_bits > 64) { 2497c478bd9Sstevel@tonic-gate xyerror(D_UNKNOWN, "cg: bad field: off %lu type <%ld> " 2507c478bd9Sstevel@tonic-gate "bits %u\n", mp->ctm_offset, mp->ctm_type, e.cte_bits); 2517c478bd9Sstevel@tonic-gate } 2527c478bd9Sstevel@tonic-gate 2537c478bd9Sstevel@tonic-gate assert(dnp->dn_op == DT_TOK_PTR || dnp->dn_op == DT_TOK_DOT); 2547c478bd9Sstevel@tonic-gate r1 = dnp->dn_left->dn_reg; 255e5803b76SAdam H. Leventhal r2 = dt_regset_alloc(drp); 2567c478bd9Sstevel@tonic-gate 2577c478bd9Sstevel@tonic-gate /* 2587c478bd9Sstevel@tonic-gate * On little-endian architectures, ctm_offset counts from the right so 2597c478bd9Sstevel@tonic-gate * ctm_offset % NBBY itself is the amount we want to shift right to 2607c478bd9Sstevel@tonic-gate * move the value bits to the little end of the register to mask them. 2617c478bd9Sstevel@tonic-gate * On big-endian architectures, ctm_offset counts from the left so we 2627c478bd9Sstevel@tonic-gate * must subtract (ctm_offset % NBBY + cte_bits) from the size in bits 2637c478bd9Sstevel@tonic-gate * we used for the load. The size of our load in turn is found by 2647c478bd9Sstevel@tonic-gate * rounding cte_bits up to a byte boundary and then finding the 2657c478bd9Sstevel@tonic-gate * nearest power of two to this value (see clp2(), above). These 2667c478bd9Sstevel@tonic-gate * properties are used to compute shift as USHIFT or SSHIFT, below. 2677c478bd9Sstevel@tonic-gate */ 2687c478bd9Sstevel@tonic-gate if (dnp->dn_flags & DT_NF_SIGNED) { 2697c478bd9Sstevel@tonic-gate #ifdef _BIG_ENDIAN 2707c478bd9Sstevel@tonic-gate shift = clp2(P2ROUNDUP(e.cte_bits, NBBY) / NBBY) * NBBY - 2717c478bd9Sstevel@tonic-gate mp->ctm_offset % NBBY; 2727c478bd9Sstevel@tonic-gate #else 2737c478bd9Sstevel@tonic-gate shift = mp->ctm_offset % NBBY + e.cte_bits; 2747c478bd9Sstevel@tonic-gate #endif 2757c478bd9Sstevel@tonic-gate dt_cg_setx(dlp, r2, 64 - shift); 2767c478bd9Sstevel@tonic-gate instr = DIF_INSTR_FMT(DIF_OP_SLL, r1, r2, r1); 2777c478bd9Sstevel@tonic-gate dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr)); 2787c478bd9Sstevel@tonic-gate 2797c478bd9Sstevel@tonic-gate dt_cg_setx(dlp, r2, 64 - e.cte_bits); 2807c478bd9Sstevel@tonic-gate instr = DIF_INSTR_FMT(DIF_OP_SRA, r1, r2, r1); 2817c478bd9Sstevel@tonic-gate dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr)); 2827c478bd9Sstevel@tonic-gate } else { 2837c478bd9Sstevel@tonic-gate #ifdef _BIG_ENDIAN 2847c478bd9Sstevel@tonic-gate shift = clp2(P2ROUNDUP(e.cte_bits, NBBY) / NBBY) * NBBY - 2857c478bd9Sstevel@tonic-gate (mp->ctm_offset % NBBY + e.cte_bits); 2867c478bd9Sstevel@tonic-gate #else 2877c478bd9Sstevel@tonic-gate shift = mp->ctm_offset % NBBY; 2887c478bd9Sstevel@tonic-gate #endif 2897c478bd9Sstevel@tonic-gate dt_cg_setx(dlp, r2, shift); 2907c478bd9Sstevel@tonic-gate instr = DIF_INSTR_FMT(DIF_OP_SRL, r1, r2, r1); 2917c478bd9Sstevel@tonic-gate dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr)); 2927c478bd9Sstevel@tonic-gate 2937c478bd9Sstevel@tonic-gate dt_cg_setx(dlp, r2, (1ULL << e.cte_bits) - 1); 2947c478bd9Sstevel@tonic-gate instr = DIF_INSTR_FMT(DIF_OP_AND, r1, r2, r1); 2957c478bd9Sstevel@tonic-gate dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr)); 2967c478bd9Sstevel@tonic-gate } 2977c478bd9Sstevel@tonic-gate 2987c478bd9Sstevel@tonic-gate dt_regset_free(drp, r2); 2997c478bd9Sstevel@tonic-gate } 3007c478bd9Sstevel@tonic-gate 3017c478bd9Sstevel@tonic-gate /* 3027c478bd9Sstevel@tonic-gate * If the destination of a store operation is a bit-field, we use this routine 3037c478bd9Sstevel@tonic-gate * to generate a prologue to the store instruction that loads the surrounding 3047c478bd9Sstevel@tonic-gate * bits, clears the destination field, and ORs in the new value of the field. 3057c478bd9Sstevel@tonic-gate * In the diagram below the "st?" is the store instruction that is generated to 3067c478bd9Sstevel@tonic-gate * store the containing word that is generating after calling this function. 3077c478bd9Sstevel@tonic-gate * 3087c478bd9Sstevel@tonic-gate * ld [dst->dn_reg], r1 3097c478bd9Sstevel@tonic-gate * setx ~(((1 << cte_bits) - 1) << (ctm_offset % NBBY)), r2 3107c478bd9Sstevel@tonic-gate * and r1, r2, r1 3117c478bd9Sstevel@tonic-gate * 3127c478bd9Sstevel@tonic-gate * setx (1 << cte_bits) - 1, r2 3137c478bd9Sstevel@tonic-gate * and src->dn_reg, r2, r2 3147c478bd9Sstevel@tonic-gate * setx ctm_offset % NBBY, r3 3157c478bd9Sstevel@tonic-gate * sll r2, r3, r2 3167c478bd9Sstevel@tonic-gate * 3177c478bd9Sstevel@tonic-gate * or r1, r2, r1 3187c478bd9Sstevel@tonic-gate * st? r1, [dst->dn_reg] 3197c478bd9Sstevel@tonic-gate * 3207c478bd9Sstevel@tonic-gate * This routine allocates a new register to hold the value to be stored and 3217c478bd9Sstevel@tonic-gate * returns it. The caller is responsible for freeing this register later. 3227c478bd9Sstevel@tonic-gate */ 3237c478bd9Sstevel@tonic-gate static int 3247c478bd9Sstevel@tonic-gate dt_cg_field_set(dt_node_t *src, dt_irlist_t *dlp, 3257c478bd9Sstevel@tonic-gate dt_regset_t *drp, dt_node_t *dst) 3267c478bd9Sstevel@tonic-gate { 3277c478bd9Sstevel@tonic-gate uint64_t cmask, fmask, shift; 3287c478bd9Sstevel@tonic-gate dif_instr_t instr; 3297c478bd9Sstevel@tonic-gate int r1, r2, r3; 3307c478bd9Sstevel@tonic-gate 3317c478bd9Sstevel@tonic-gate ctf_membinfo_t m; 3327c478bd9Sstevel@tonic-gate ctf_encoding_t e; 3337c478bd9Sstevel@tonic-gate ctf_file_t *fp, *ofp; 3347c478bd9Sstevel@tonic-gate ctf_id_t type; 3357c478bd9Sstevel@tonic-gate 3367c478bd9Sstevel@tonic-gate assert(dst->dn_op == DT_TOK_PTR || dst->dn_op == DT_TOK_DOT); 3377c478bd9Sstevel@tonic-gate assert(dst->dn_right->dn_kind == DT_NODE_IDENT); 3387c478bd9Sstevel@tonic-gate 3397c478bd9Sstevel@tonic-gate fp = dst->dn_left->dn_ctfp; 3407c478bd9Sstevel@tonic-gate type = ctf_type_resolve(fp, dst->dn_left->dn_type); 3417c478bd9Sstevel@tonic-gate 3427c478bd9Sstevel@tonic-gate if (dst->dn_op == DT_TOK_PTR) { 3437c478bd9Sstevel@tonic-gate type = ctf_type_reference(fp, type); 3447c478bd9Sstevel@tonic-gate type = ctf_type_resolve(fp, type); 3457c478bd9Sstevel@tonic-gate } 3467c478bd9Sstevel@tonic-gate 3477c478bd9Sstevel@tonic-gate if ((fp = dt_cg_membinfo(ofp = fp, type, 3487c478bd9Sstevel@tonic-gate dst->dn_right->dn_string, &m)) == NULL) { 3497c478bd9Sstevel@tonic-gate yypcb->pcb_hdl->dt_ctferr = ctf_errno(ofp); 3507c478bd9Sstevel@tonic-gate longjmp(yypcb->pcb_jmpbuf, EDT_CTF); 3517c478bd9Sstevel@tonic-gate } 3527c478bd9Sstevel@tonic-gate 3537c478bd9Sstevel@tonic-gate if (ctf_type_encoding(fp, m.ctm_type, &e) != 0 || e.cte_bits > 64) { 3547c478bd9Sstevel@tonic-gate xyerror(D_UNKNOWN, "cg: bad field: off %lu type <%ld> " 3557c478bd9Sstevel@tonic-gate "bits %u\n", m.ctm_offset, m.ctm_type, e.cte_bits); 3567c478bd9Sstevel@tonic-gate } 3577c478bd9Sstevel@tonic-gate 358e5803b76SAdam H. Leventhal r1 = dt_regset_alloc(drp); 359e5803b76SAdam H. Leventhal r2 = dt_regset_alloc(drp); 360e5803b76SAdam H. Leventhal r3 = dt_regset_alloc(drp); 3617c478bd9Sstevel@tonic-gate 3627c478bd9Sstevel@tonic-gate /* 3637c478bd9Sstevel@tonic-gate * Compute shifts and masks. We need to compute "shift" as the amount 3647c478bd9Sstevel@tonic-gate * we need to shift left to position our field in the containing word. 3657c478bd9Sstevel@tonic-gate * Refer to the comments in dt_cg_field_get(), above, for more info. 3667c478bd9Sstevel@tonic-gate * We then compute fmask as the mask that truncates the value in the 3677c478bd9Sstevel@tonic-gate * input register to width cte_bits, and cmask as the mask used to 3687c478bd9Sstevel@tonic-gate * pass through the containing bits and zero the field bits. 3697c478bd9Sstevel@tonic-gate */ 3707c478bd9Sstevel@tonic-gate #ifdef _BIG_ENDIAN 3717c478bd9Sstevel@tonic-gate shift = clp2(P2ROUNDUP(e.cte_bits, NBBY) / NBBY) * NBBY - 3727c478bd9Sstevel@tonic-gate (m.ctm_offset % NBBY + e.cte_bits); 3737c478bd9Sstevel@tonic-gate #else 3747c478bd9Sstevel@tonic-gate shift = m.ctm_offset % NBBY; 3757c478bd9Sstevel@tonic-gate #endif 3767c478bd9Sstevel@tonic-gate fmask = (1ULL << e.cte_bits) - 1; 3777c478bd9Sstevel@tonic-gate cmask = ~(fmask << shift); 3787c478bd9Sstevel@tonic-gate 3797c478bd9Sstevel@tonic-gate instr = DIF_INSTR_LOAD( 3807c478bd9Sstevel@tonic-gate dt_cg_load(dst, fp, m.ctm_type), dst->dn_reg, r1); 3817c478bd9Sstevel@tonic-gate dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr)); 3827c478bd9Sstevel@tonic-gate 3837c478bd9Sstevel@tonic-gate dt_cg_setx(dlp, r2, cmask); 3847c478bd9Sstevel@tonic-gate instr = DIF_INSTR_FMT(DIF_OP_AND, r1, r2, r1); 3857c478bd9Sstevel@tonic-gate dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr)); 3867c478bd9Sstevel@tonic-gate 3877c478bd9Sstevel@tonic-gate dt_cg_setx(dlp, r2, fmask); 3887c478bd9Sstevel@tonic-gate instr = DIF_INSTR_FMT(DIF_OP_AND, src->dn_reg, r2, r2); 3897c478bd9Sstevel@tonic-gate dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr)); 3907c478bd9Sstevel@tonic-gate 3917c478bd9Sstevel@tonic-gate dt_cg_setx(dlp, r3, shift); 3927c478bd9Sstevel@tonic-gate instr = DIF_INSTR_FMT(DIF_OP_SLL, r2, r3, r2); 3937c478bd9Sstevel@tonic-gate dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr)); 3947c478bd9Sstevel@tonic-gate 3957c478bd9Sstevel@tonic-gate instr = DIF_INSTR_FMT(DIF_OP_OR, r1, r2, r1); 3967c478bd9Sstevel@tonic-gate dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr)); 3977c478bd9Sstevel@tonic-gate 3987c478bd9Sstevel@tonic-gate dt_regset_free(drp, r3); 3997c478bd9Sstevel@tonic-gate dt_regset_free(drp, r2); 4007c478bd9Sstevel@tonic-gate 4017c478bd9Sstevel@tonic-gate return (r1); 4027c478bd9Sstevel@tonic-gate } 4037c478bd9Sstevel@tonic-gate 4047c478bd9Sstevel@tonic-gate static void 4057c478bd9Sstevel@tonic-gate dt_cg_store(dt_node_t *src, dt_irlist_t *dlp, dt_regset_t *drp, dt_node_t *dst) 4067c478bd9Sstevel@tonic-gate { 4077c478bd9Sstevel@tonic-gate ctf_encoding_t e; 4087c478bd9Sstevel@tonic-gate dif_instr_t instr; 4097c478bd9Sstevel@tonic-gate size_t size; 4107c478bd9Sstevel@tonic-gate int reg; 4117c478bd9Sstevel@tonic-gate 4127c478bd9Sstevel@tonic-gate /* 4137c478bd9Sstevel@tonic-gate * If we're loading a bit-field, the size of our store is found by 4147c478bd9Sstevel@tonic-gate * rounding dst's cte_bits up to a byte boundary and then finding the 4157c478bd9Sstevel@tonic-gate * nearest power of two to this value (see clp2(), above). 4167c478bd9Sstevel@tonic-gate */ 4177c478bd9Sstevel@tonic-gate if ((dst->dn_flags & DT_NF_BITFIELD) && 4187c478bd9Sstevel@tonic-gate ctf_type_encoding(dst->dn_ctfp, dst->dn_type, &e) != CTF_ERR) 4197c478bd9Sstevel@tonic-gate size = clp2(P2ROUNDUP(e.cte_bits, NBBY) / NBBY); 4207c478bd9Sstevel@tonic-gate else 4217c478bd9Sstevel@tonic-gate size = dt_node_type_size(src); 4227c478bd9Sstevel@tonic-gate 4237c478bd9Sstevel@tonic-gate if (src->dn_flags & DT_NF_REF) { 424e5803b76SAdam H. Leventhal reg = dt_regset_alloc(drp); 4257c478bd9Sstevel@tonic-gate dt_cg_setx(dlp, reg, size); 4267c478bd9Sstevel@tonic-gate instr = DIF_INSTR_COPYS(src->dn_reg, reg, dst->dn_reg); 4277c478bd9Sstevel@tonic-gate dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr)); 4287c478bd9Sstevel@tonic-gate dt_regset_free(drp, reg); 4297c478bd9Sstevel@tonic-gate } else { 4307c478bd9Sstevel@tonic-gate if (dst->dn_flags & DT_NF_BITFIELD) 4317c478bd9Sstevel@tonic-gate reg = dt_cg_field_set(src, dlp, drp, dst); 4327c478bd9Sstevel@tonic-gate else 4337c478bd9Sstevel@tonic-gate reg = src->dn_reg; 4347c478bd9Sstevel@tonic-gate 4357c478bd9Sstevel@tonic-gate switch (size) { 4367c478bd9Sstevel@tonic-gate case 1: 4377c478bd9Sstevel@tonic-gate instr = DIF_INSTR_STORE(DIF_OP_STB, reg, dst->dn_reg); 4387c478bd9Sstevel@tonic-gate break; 4397c478bd9Sstevel@tonic-gate case 2: 4407c478bd9Sstevel@tonic-gate instr = DIF_INSTR_STORE(DIF_OP_STH, reg, dst->dn_reg); 4417c478bd9Sstevel@tonic-gate break; 4427c478bd9Sstevel@tonic-gate case 4: 4437c478bd9Sstevel@tonic-gate instr = DIF_INSTR_STORE(DIF_OP_STW, reg, dst->dn_reg); 4447c478bd9Sstevel@tonic-gate break; 4457c478bd9Sstevel@tonic-gate case 8: 4467c478bd9Sstevel@tonic-gate instr = DIF_INSTR_STORE(DIF_OP_STX, reg, dst->dn_reg); 4477c478bd9Sstevel@tonic-gate break; 4487c478bd9Sstevel@tonic-gate default: 4497c478bd9Sstevel@tonic-gate xyerror(D_UNKNOWN, "internal error -- cg cannot store " 4507c478bd9Sstevel@tonic-gate "size %lu when passed by value\n", (ulong_t)size); 4517c478bd9Sstevel@tonic-gate } 4527c478bd9Sstevel@tonic-gate dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr)); 4537c478bd9Sstevel@tonic-gate 4547c478bd9Sstevel@tonic-gate if (dst->dn_flags & DT_NF_BITFIELD) 4557c478bd9Sstevel@tonic-gate dt_regset_free(drp, reg); 4567c478bd9Sstevel@tonic-gate } 4577c478bd9Sstevel@tonic-gate } 4587c478bd9Sstevel@tonic-gate 4597c478bd9Sstevel@tonic-gate /* 4607c478bd9Sstevel@tonic-gate * Generate code for a typecast or for argument promotion from the type of the 4617c478bd9Sstevel@tonic-gate * actual to the type of the formal. We need to generate code for casts when 4627c478bd9Sstevel@tonic-gate * a scalar type is being narrowed or changing signed-ness. We first shift the 4637c478bd9Sstevel@tonic-gate * desired bits high (losing excess bits if narrowing) and then shift them down 4647c478bd9Sstevel@tonic-gate * using logical shift (unsigned result) or arithmetic shift (signed result). 4657c478bd9Sstevel@tonic-gate */ 4667c478bd9Sstevel@tonic-gate static void 4677c478bd9Sstevel@tonic-gate dt_cg_typecast(const dt_node_t *src, const dt_node_t *dst, 4687c478bd9Sstevel@tonic-gate dt_irlist_t *dlp, dt_regset_t *drp) 4697c478bd9Sstevel@tonic-gate { 4707c478bd9Sstevel@tonic-gate size_t srcsize = dt_node_type_size(src); 4717c478bd9Sstevel@tonic-gate size_t dstsize = dt_node_type_size(dst); 4727c478bd9Sstevel@tonic-gate 4737c478bd9Sstevel@tonic-gate dif_instr_t instr; 474e5803b76SAdam H. Leventhal int rg; 4757c478bd9Sstevel@tonic-gate 476e5803b76SAdam H. Leventhal if (!dt_node_is_scalar(dst)) 477e5803b76SAdam H. Leventhal return; /* not a scalar */ 478e5803b76SAdam H. Leventhal if (dstsize == srcsize && 479*2e055267SBryan Cantrill ((src->dn_flags ^ dst->dn_flags) & DT_NF_SIGNED) == 0) 480e5803b76SAdam H. Leventhal return; /* not narrowing or changing signed-ness */ 481e5803b76SAdam H. Leventhal if (dstsize > srcsize && (src->dn_flags & DT_NF_SIGNED) == 0) 482e5803b76SAdam H. Leventhal return; /* nothing to do in this case */ 4837c478bd9Sstevel@tonic-gate 484e5803b76SAdam H. Leventhal rg = dt_regset_alloc(drp); 4857c478bd9Sstevel@tonic-gate 486e5803b76SAdam H. Leventhal if (dstsize > srcsize) { 487e5803b76SAdam H. Leventhal int n = sizeof (uint64_t) * NBBY - srcsize * NBBY; 488e5803b76SAdam H. Leventhal int s = (dstsize - srcsize) * NBBY; 4897c478bd9Sstevel@tonic-gate 490e5803b76SAdam H. Leventhal dt_cg_setx(dlp, rg, n); 491e5803b76SAdam H. Leventhal 492e5803b76SAdam H. Leventhal instr = DIF_INSTR_FMT(DIF_OP_SLL, src->dn_reg, rg, dst->dn_reg); 493e5803b76SAdam H. Leventhal dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr)); 494e5803b76SAdam H. Leventhal 495e5803b76SAdam H. Leventhal if ((dst->dn_flags & DT_NF_SIGNED) || n == s) { 496e5803b76SAdam H. Leventhal instr = DIF_INSTR_FMT(DIF_OP_SRA, 497e5803b76SAdam H. Leventhal dst->dn_reg, rg, dst->dn_reg); 498e5803b76SAdam H. Leventhal dt_irlist_append(dlp, 499e5803b76SAdam H. Leventhal dt_cg_node_alloc(DT_LBL_NONE, instr)); 500e5803b76SAdam H. Leventhal } else { 501e5803b76SAdam H. Leventhal dt_cg_setx(dlp, rg, s); 502e5803b76SAdam H. Leventhal instr = DIF_INSTR_FMT(DIF_OP_SRA, 503e5803b76SAdam H. Leventhal dst->dn_reg, rg, dst->dn_reg); 504e5803b76SAdam H. Leventhal dt_irlist_append(dlp, 505e5803b76SAdam H. Leventhal dt_cg_node_alloc(DT_LBL_NONE, instr)); 506e5803b76SAdam H. Leventhal dt_cg_setx(dlp, rg, n - s); 507e5803b76SAdam H. Leventhal instr = DIF_INSTR_FMT(DIF_OP_SRL, 508e5803b76SAdam H. Leventhal dst->dn_reg, rg, dst->dn_reg); 509e5803b76SAdam H. Leventhal dt_irlist_append(dlp, 510e5803b76SAdam H. Leventhal dt_cg_node_alloc(DT_LBL_NONE, instr)); 511e5803b76SAdam H. Leventhal } 512e5803b76SAdam H. Leventhal } else if (dstsize != sizeof (uint64_t)) { 513e5803b76SAdam H. Leventhal int n = sizeof (uint64_t) * NBBY - dstsize * NBBY; 514e5803b76SAdam H. Leventhal 515e5803b76SAdam H. Leventhal dt_cg_setx(dlp, rg, n); 516e5803b76SAdam H. Leventhal 517e5803b76SAdam H. Leventhal instr = DIF_INSTR_FMT(DIF_OP_SLL, src->dn_reg, rg, dst->dn_reg); 5187c478bd9Sstevel@tonic-gate dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr)); 5197c478bd9Sstevel@tonic-gate 5207c478bd9Sstevel@tonic-gate instr = DIF_INSTR_FMT((dst->dn_flags & DT_NF_SIGNED) ? 521e5803b76SAdam H. Leventhal DIF_OP_SRA : DIF_OP_SRL, dst->dn_reg, rg, dst->dn_reg); 5227c478bd9Sstevel@tonic-gate dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr)); 5237c478bd9Sstevel@tonic-gate } 524e5803b76SAdam H. Leventhal 525e5803b76SAdam H. Leventhal dt_regset_free(drp, rg); 5267c478bd9Sstevel@tonic-gate } 5277c478bd9Sstevel@tonic-gate 5287c478bd9Sstevel@tonic-gate /* 5297c478bd9Sstevel@tonic-gate * Generate code to push the specified argument list on to the tuple stack. 5307c478bd9Sstevel@tonic-gate * We use this routine for handling subroutine calls and associative arrays. 5317c478bd9Sstevel@tonic-gate * We must first generate code for all subexpressions before loading the stack 5327c478bd9Sstevel@tonic-gate * because any subexpression could itself require the use of the tuple stack. 5337c478bd9Sstevel@tonic-gate * This holds a number of registers equal to the number of arguments, but this 5347c478bd9Sstevel@tonic-gate * is not a huge problem because the number of arguments can't exceed the 5357c478bd9Sstevel@tonic-gate * number of tuple register stack elements anyway. At most one extra register 5367c478bd9Sstevel@tonic-gate * is required (either by dt_cg_typecast() or for dtdt_size, below). This 5377c478bd9Sstevel@tonic-gate * implies that a DIF implementation should offer a number of general purpose 5387c478bd9Sstevel@tonic-gate * registers at least one greater than the number of tuple registers. 5397c478bd9Sstevel@tonic-gate */ 5407c478bd9Sstevel@tonic-gate static void 5417c478bd9Sstevel@tonic-gate dt_cg_arglist(dt_ident_t *idp, dt_node_t *args, 5427c478bd9Sstevel@tonic-gate dt_irlist_t *dlp, dt_regset_t *drp) 5437c478bd9Sstevel@tonic-gate { 5447c478bd9Sstevel@tonic-gate const dt_idsig_t *isp = idp->di_data; 5457c478bd9Sstevel@tonic-gate dt_node_t *dnp; 5467c478bd9Sstevel@tonic-gate int i = 0; 5477c478bd9Sstevel@tonic-gate 5487c478bd9Sstevel@tonic-gate for (dnp = args; dnp != NULL; dnp = dnp->dn_list) 5497c478bd9Sstevel@tonic-gate dt_cg_node(dnp, dlp, drp); 5507c478bd9Sstevel@tonic-gate 551e5803b76SAdam H. Leventhal dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, DIF_INSTR_FLUSHTS)); 5527c478bd9Sstevel@tonic-gate 5537c478bd9Sstevel@tonic-gate for (dnp = args; dnp != NULL; dnp = dnp->dn_list, i++) { 5547c478bd9Sstevel@tonic-gate dtrace_diftype_t t; 5557c478bd9Sstevel@tonic-gate dif_instr_t instr; 5567c478bd9Sstevel@tonic-gate uint_t op; 5577c478bd9Sstevel@tonic-gate int reg; 5587c478bd9Sstevel@tonic-gate 5591a7c1b72Smws dt_node_diftype(yypcb->pcb_hdl, dnp, &t); 5607c478bd9Sstevel@tonic-gate 5617c478bd9Sstevel@tonic-gate isp->dis_args[i].dn_reg = dnp->dn_reg; /* re-use register */ 5627c478bd9Sstevel@tonic-gate dt_cg_typecast(dnp, &isp->dis_args[i], dlp, drp); 5637c478bd9Sstevel@tonic-gate isp->dis_args[i].dn_reg = -1; 5647c478bd9Sstevel@tonic-gate 565e5803b76SAdam H. Leventhal if (t.dtdt_flags & DIF_TF_BYREF) { 5667c478bd9Sstevel@tonic-gate op = DIF_OP_PUSHTR; 5677c478bd9Sstevel@tonic-gate if (t.dtdt_size != 0) { 568e5803b76SAdam H. Leventhal reg = dt_regset_alloc(drp); 5697c478bd9Sstevel@tonic-gate dt_cg_setx(dlp, reg, t.dtdt_size); 570e5803b76SAdam H. Leventhal } else { 5717c478bd9Sstevel@tonic-gate reg = DIF_REG_R0; 572e5803b76SAdam H. Leventhal } 573e5803b76SAdam H. Leventhal } else { 574e5803b76SAdam H. Leventhal op = DIF_OP_PUSHTV; 575e5803b76SAdam H. Leventhal reg = DIF_REG_R0; 576e5803b76SAdam H. Leventhal } 5777c478bd9Sstevel@tonic-gate 5787c478bd9Sstevel@tonic-gate instr = DIF_INSTR_PUSHTS(op, t.dtdt_kind, reg, dnp->dn_reg); 5797c478bd9Sstevel@tonic-gate dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr)); 5807c478bd9Sstevel@tonic-gate dt_regset_free(drp, dnp->dn_reg); 5817c478bd9Sstevel@tonic-gate 5827c478bd9Sstevel@tonic-gate if (reg != DIF_REG_R0) 5837c478bd9Sstevel@tonic-gate dt_regset_free(drp, reg); 5847c478bd9Sstevel@tonic-gate } 5857c478bd9Sstevel@tonic-gate 5867c478bd9Sstevel@tonic-gate if (i > yypcb->pcb_hdl->dt_conf.dtc_diftupregs) 5877c478bd9Sstevel@tonic-gate longjmp(yypcb->pcb_jmpbuf, EDT_NOTUPREG); 5887c478bd9Sstevel@tonic-gate } 5897c478bd9Sstevel@tonic-gate 5907c478bd9Sstevel@tonic-gate static void 5917c478bd9Sstevel@tonic-gate dt_cg_arithmetic_op(dt_node_t *dnp, dt_irlist_t *dlp, 5927c478bd9Sstevel@tonic-gate dt_regset_t *drp, uint_t op) 5937c478bd9Sstevel@tonic-gate { 5947c478bd9Sstevel@tonic-gate int is_ptr_op = (dnp->dn_op == DT_TOK_ADD || dnp->dn_op == DT_TOK_SUB || 5957c478bd9Sstevel@tonic-gate dnp->dn_op == DT_TOK_ADD_EQ || dnp->dn_op == DT_TOK_SUB_EQ); 5967c478bd9Sstevel@tonic-gate 5977c478bd9Sstevel@tonic-gate int lp_is_ptr = dt_node_is_pointer(dnp->dn_left); 5987c478bd9Sstevel@tonic-gate int rp_is_ptr = dt_node_is_pointer(dnp->dn_right); 5997c478bd9Sstevel@tonic-gate 6007c478bd9Sstevel@tonic-gate dif_instr_t instr; 6017c478bd9Sstevel@tonic-gate 6027c478bd9Sstevel@tonic-gate if (lp_is_ptr && rp_is_ptr) { 6037c478bd9Sstevel@tonic-gate assert(dnp->dn_op == DT_TOK_SUB); 6047c478bd9Sstevel@tonic-gate is_ptr_op = 0; 6057c478bd9Sstevel@tonic-gate } 6067c478bd9Sstevel@tonic-gate 6077c478bd9Sstevel@tonic-gate dt_cg_node(dnp->dn_left, dlp, drp); 6087c478bd9Sstevel@tonic-gate if (is_ptr_op && rp_is_ptr) 6097c478bd9Sstevel@tonic-gate dt_cg_ptrsize(dnp, dlp, drp, DIF_OP_MUL, dnp->dn_left->dn_reg); 6107c478bd9Sstevel@tonic-gate 6117c478bd9Sstevel@tonic-gate dt_cg_node(dnp->dn_right, dlp, drp); 6127c478bd9Sstevel@tonic-gate if (is_ptr_op && lp_is_ptr) 6137c478bd9Sstevel@tonic-gate dt_cg_ptrsize(dnp, dlp, drp, DIF_OP_MUL, dnp->dn_right->dn_reg); 6147c478bd9Sstevel@tonic-gate 6157c478bd9Sstevel@tonic-gate instr = DIF_INSTR_FMT(op, dnp->dn_left->dn_reg, 6167c478bd9Sstevel@tonic-gate dnp->dn_right->dn_reg, dnp->dn_left->dn_reg); 6177c478bd9Sstevel@tonic-gate 6187c478bd9Sstevel@tonic-gate dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr)); 6197c478bd9Sstevel@tonic-gate dt_regset_free(drp, dnp->dn_right->dn_reg); 6207c478bd9Sstevel@tonic-gate dnp->dn_reg = dnp->dn_left->dn_reg; 6217c478bd9Sstevel@tonic-gate 6227c478bd9Sstevel@tonic-gate if (lp_is_ptr && rp_is_ptr) 6237c478bd9Sstevel@tonic-gate dt_cg_ptrsize(dnp->dn_right, 6247c478bd9Sstevel@tonic-gate dlp, drp, DIF_OP_UDIV, dnp->dn_reg); 6257c478bd9Sstevel@tonic-gate } 6267c478bd9Sstevel@tonic-gate 6277c478bd9Sstevel@tonic-gate static uint_t 6287c478bd9Sstevel@tonic-gate dt_cg_stvar(const dt_ident_t *idp) 6297c478bd9Sstevel@tonic-gate { 6307c478bd9Sstevel@tonic-gate static const uint_t aops[] = { DIF_OP_STGAA, DIF_OP_STTAA, DIF_OP_NOP }; 6317c478bd9Sstevel@tonic-gate static const uint_t sops[] = { DIF_OP_STGS, DIF_OP_STTS, DIF_OP_STLS }; 6327c478bd9Sstevel@tonic-gate 6337c478bd9Sstevel@tonic-gate uint_t i = (((idp->di_flags & DT_IDFLG_LOCAL) != 0) << 1) | 6347c478bd9Sstevel@tonic-gate ((idp->di_flags & DT_IDFLG_TLS) != 0); 6357c478bd9Sstevel@tonic-gate 6367c478bd9Sstevel@tonic-gate return (idp->di_kind == DT_IDENT_ARRAY ? aops[i] : sops[i]); 6377c478bd9Sstevel@tonic-gate } 6387c478bd9Sstevel@tonic-gate 6397c478bd9Sstevel@tonic-gate static void 6407c478bd9Sstevel@tonic-gate dt_cg_prearith_op(dt_node_t *dnp, dt_irlist_t *dlp, dt_regset_t *drp, uint_t op) 6417c478bd9Sstevel@tonic-gate { 6427c478bd9Sstevel@tonic-gate ctf_file_t *ctfp = dnp->dn_ctfp; 6437c478bd9Sstevel@tonic-gate dif_instr_t instr; 6447c478bd9Sstevel@tonic-gate ctf_id_t type; 6457c478bd9Sstevel@tonic-gate ssize_t size = 1; 6467c478bd9Sstevel@tonic-gate int reg; 6477c478bd9Sstevel@tonic-gate 6487c478bd9Sstevel@tonic-gate if (dt_node_is_pointer(dnp)) { 6497c478bd9Sstevel@tonic-gate type = ctf_type_resolve(ctfp, dnp->dn_type); 6507c478bd9Sstevel@tonic-gate assert(ctf_type_kind(ctfp, type) == CTF_K_POINTER); 6517c478bd9Sstevel@tonic-gate size = ctf_type_size(ctfp, ctf_type_reference(ctfp, type)); 6527c478bd9Sstevel@tonic-gate } 6537c478bd9Sstevel@tonic-gate 6547c478bd9Sstevel@tonic-gate dt_cg_node(dnp->dn_child, dlp, drp); 6557c478bd9Sstevel@tonic-gate dnp->dn_reg = dnp->dn_child->dn_reg; 6567c478bd9Sstevel@tonic-gate 657e5803b76SAdam H. Leventhal reg = dt_regset_alloc(drp); 6587c478bd9Sstevel@tonic-gate dt_cg_setx(dlp, reg, size); 6597c478bd9Sstevel@tonic-gate 6607c478bd9Sstevel@tonic-gate instr = DIF_INSTR_FMT(op, dnp->dn_reg, reg, dnp->dn_reg); 6617c478bd9Sstevel@tonic-gate dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr)); 6627c478bd9Sstevel@tonic-gate dt_regset_free(drp, reg); 6637c478bd9Sstevel@tonic-gate 6647c478bd9Sstevel@tonic-gate /* 6657c478bd9Sstevel@tonic-gate * If we are modifying a variable, generate an stv instruction from 6667c478bd9Sstevel@tonic-gate * the variable specified by the identifier. If we are storing to a 6677c478bd9Sstevel@tonic-gate * memory address, generate code again for the left-hand side using 6687c478bd9Sstevel@tonic-gate * DT_NF_REF to get the address, and then generate a store to it. 6697c478bd9Sstevel@tonic-gate * In both paths, we store the value in dnp->dn_reg (the new value). 6707c478bd9Sstevel@tonic-gate */ 6717c478bd9Sstevel@tonic-gate if (dnp->dn_child->dn_kind == DT_NODE_VAR) { 6727c478bd9Sstevel@tonic-gate dt_ident_t *idp = dt_ident_resolve(dnp->dn_child->dn_ident); 6737c478bd9Sstevel@tonic-gate 6747c478bd9Sstevel@tonic-gate idp->di_flags |= DT_IDFLG_DIFW; 6757c478bd9Sstevel@tonic-gate instr = DIF_INSTR_STV(dt_cg_stvar(idp), 6767c478bd9Sstevel@tonic-gate idp->di_id, dnp->dn_reg); 6777c478bd9Sstevel@tonic-gate dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr)); 6787c478bd9Sstevel@tonic-gate } else { 6797c478bd9Sstevel@tonic-gate uint_t rbit = dnp->dn_child->dn_flags & DT_NF_REF; 6807c478bd9Sstevel@tonic-gate 6817c478bd9Sstevel@tonic-gate assert(dnp->dn_child->dn_flags & DT_NF_WRITABLE); 6827c478bd9Sstevel@tonic-gate assert(dnp->dn_child->dn_flags & DT_NF_LVALUE); 6837c478bd9Sstevel@tonic-gate 6847c478bd9Sstevel@tonic-gate dnp->dn_child->dn_flags |= DT_NF_REF; /* force pass-by-ref */ 6857c478bd9Sstevel@tonic-gate dt_cg_node(dnp->dn_child, dlp, drp); 6867c478bd9Sstevel@tonic-gate 6877c478bd9Sstevel@tonic-gate dt_cg_store(dnp, dlp, drp, dnp->dn_child); 6887c478bd9Sstevel@tonic-gate dt_regset_free(drp, dnp->dn_child->dn_reg); 6897c478bd9Sstevel@tonic-gate 6907c478bd9Sstevel@tonic-gate dnp->dn_left->dn_flags &= ~DT_NF_REF; 6917c478bd9Sstevel@tonic-gate dnp->dn_left->dn_flags |= rbit; 6927c478bd9Sstevel@tonic-gate } 6937c478bd9Sstevel@tonic-gate } 6947c478bd9Sstevel@tonic-gate 6957c478bd9Sstevel@tonic-gate static void 6967c478bd9Sstevel@tonic-gate dt_cg_postarith_op(dt_node_t *dnp, dt_irlist_t *dlp, 6977c478bd9Sstevel@tonic-gate dt_regset_t *drp, uint_t op) 6987c478bd9Sstevel@tonic-gate { 6997c478bd9Sstevel@tonic-gate ctf_file_t *ctfp = dnp->dn_ctfp; 7007c478bd9Sstevel@tonic-gate dif_instr_t instr; 7017c478bd9Sstevel@tonic-gate ctf_id_t type; 7027c478bd9Sstevel@tonic-gate ssize_t size = 1; 7037c478bd9Sstevel@tonic-gate int nreg; 7047c478bd9Sstevel@tonic-gate 7057c478bd9Sstevel@tonic-gate if (dt_node_is_pointer(dnp)) { 7067c478bd9Sstevel@tonic-gate type = ctf_type_resolve(ctfp, dnp->dn_type); 7077c478bd9Sstevel@tonic-gate assert(ctf_type_kind(ctfp, type) == CTF_K_POINTER); 7087c478bd9Sstevel@tonic-gate size = ctf_type_size(ctfp, ctf_type_reference(ctfp, type)); 7097c478bd9Sstevel@tonic-gate } 7107c478bd9Sstevel@tonic-gate 7117c478bd9Sstevel@tonic-gate dt_cg_node(dnp->dn_child, dlp, drp); 7127c478bd9Sstevel@tonic-gate dnp->dn_reg = dnp->dn_child->dn_reg; 7137c478bd9Sstevel@tonic-gate 714e5803b76SAdam H. Leventhal nreg = dt_regset_alloc(drp); 7157c478bd9Sstevel@tonic-gate dt_cg_setx(dlp, nreg, size); 7167c478bd9Sstevel@tonic-gate instr = DIF_INSTR_FMT(op, dnp->dn_reg, nreg, nreg); 7177c478bd9Sstevel@tonic-gate dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr)); 7187c478bd9Sstevel@tonic-gate 7197c478bd9Sstevel@tonic-gate /* 7207c478bd9Sstevel@tonic-gate * If we are modifying a variable, generate an stv instruction from 7217c478bd9Sstevel@tonic-gate * the variable specified by the identifier. If we are storing to a 7227c478bd9Sstevel@tonic-gate * memory address, generate code again for the left-hand side using 7237c478bd9Sstevel@tonic-gate * DT_NF_REF to get the address, and then generate a store to it. 7247c478bd9Sstevel@tonic-gate * In both paths, we store the value from 'nreg' (the new value). 7257c478bd9Sstevel@tonic-gate */ 7267c478bd9Sstevel@tonic-gate if (dnp->dn_child->dn_kind == DT_NODE_VAR) { 7277c478bd9Sstevel@tonic-gate dt_ident_t *idp = dt_ident_resolve(dnp->dn_child->dn_ident); 7287c478bd9Sstevel@tonic-gate 7297c478bd9Sstevel@tonic-gate idp->di_flags |= DT_IDFLG_DIFW; 7307c478bd9Sstevel@tonic-gate instr = DIF_INSTR_STV(dt_cg_stvar(idp), idp->di_id, nreg); 7317c478bd9Sstevel@tonic-gate dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr)); 7327c478bd9Sstevel@tonic-gate } else { 7337c478bd9Sstevel@tonic-gate uint_t rbit = dnp->dn_child->dn_flags & DT_NF_REF; 7347c478bd9Sstevel@tonic-gate int oreg = dnp->dn_reg; 7357c478bd9Sstevel@tonic-gate 7367c478bd9Sstevel@tonic-gate assert(dnp->dn_child->dn_flags & DT_NF_WRITABLE); 7377c478bd9Sstevel@tonic-gate assert(dnp->dn_child->dn_flags & DT_NF_LVALUE); 7387c478bd9Sstevel@tonic-gate 7397c478bd9Sstevel@tonic-gate dnp->dn_child->dn_flags |= DT_NF_REF; /* force pass-by-ref */ 7407c478bd9Sstevel@tonic-gate dt_cg_node(dnp->dn_child, dlp, drp); 7417c478bd9Sstevel@tonic-gate 7427c478bd9Sstevel@tonic-gate dnp->dn_reg = nreg; 7437c478bd9Sstevel@tonic-gate dt_cg_store(dnp, dlp, drp, dnp->dn_child); 7447c478bd9Sstevel@tonic-gate dnp->dn_reg = oreg; 7457c478bd9Sstevel@tonic-gate 7467c478bd9Sstevel@tonic-gate dt_regset_free(drp, dnp->dn_child->dn_reg); 7477c478bd9Sstevel@tonic-gate dnp->dn_left->dn_flags &= ~DT_NF_REF; 7487c478bd9Sstevel@tonic-gate dnp->dn_left->dn_flags |= rbit; 7497c478bd9Sstevel@tonic-gate } 7507c478bd9Sstevel@tonic-gate 7517c478bd9Sstevel@tonic-gate dt_regset_free(drp, nreg); 7527c478bd9Sstevel@tonic-gate } 7537c478bd9Sstevel@tonic-gate 7547c478bd9Sstevel@tonic-gate /* 7557c478bd9Sstevel@tonic-gate * Determine if we should perform signed or unsigned comparison for an OP2. 7567c478bd9Sstevel@tonic-gate * If both operands are of arithmetic type, perform the usual arithmetic 7577c478bd9Sstevel@tonic-gate * conversions to determine the common real type for comparison [ISOC 6.5.8.3]. 7587c478bd9Sstevel@tonic-gate */ 7597c478bd9Sstevel@tonic-gate static int 7607c478bd9Sstevel@tonic-gate dt_cg_compare_signed(dt_node_t *dnp) 7617c478bd9Sstevel@tonic-gate { 7627c478bd9Sstevel@tonic-gate dt_node_t dn; 7637c478bd9Sstevel@tonic-gate 7647c478bd9Sstevel@tonic-gate if (dt_node_is_string(dnp->dn_left) || 7657c478bd9Sstevel@tonic-gate dt_node_is_string(dnp->dn_right)) 7667c478bd9Sstevel@tonic-gate return (1); /* strings always compare signed */ 7677c478bd9Sstevel@tonic-gate else if (!dt_node_is_arith(dnp->dn_left) || 7687c478bd9Sstevel@tonic-gate !dt_node_is_arith(dnp->dn_right)) 7697c478bd9Sstevel@tonic-gate return (0); /* non-arithmetic types always compare unsigned */ 7707c478bd9Sstevel@tonic-gate 7717c478bd9Sstevel@tonic-gate bzero(&dn, sizeof (dn)); 7727c478bd9Sstevel@tonic-gate dt_node_promote(dnp->dn_left, dnp->dn_right, &dn); 7737c478bd9Sstevel@tonic-gate return (dn.dn_flags & DT_NF_SIGNED); 7747c478bd9Sstevel@tonic-gate } 7757c478bd9Sstevel@tonic-gate 7767c478bd9Sstevel@tonic-gate static void 7777c478bd9Sstevel@tonic-gate dt_cg_compare_op(dt_node_t *dnp, dt_irlist_t *dlp, dt_regset_t *drp, uint_t op) 7787c478bd9Sstevel@tonic-gate { 7797c478bd9Sstevel@tonic-gate uint_t lbl_true = dt_irlist_label(dlp); 7807c478bd9Sstevel@tonic-gate uint_t lbl_post = dt_irlist_label(dlp); 7817c478bd9Sstevel@tonic-gate 7827c478bd9Sstevel@tonic-gate dif_instr_t instr; 7837c478bd9Sstevel@tonic-gate uint_t opc; 7847c478bd9Sstevel@tonic-gate 7857c478bd9Sstevel@tonic-gate dt_cg_node(dnp->dn_left, dlp, drp); 7867c478bd9Sstevel@tonic-gate dt_cg_node(dnp->dn_right, dlp, drp); 7877c478bd9Sstevel@tonic-gate 7887c478bd9Sstevel@tonic-gate if (dt_node_is_string(dnp->dn_left) || dt_node_is_string(dnp->dn_right)) 7897c478bd9Sstevel@tonic-gate opc = DIF_OP_SCMP; 7907c478bd9Sstevel@tonic-gate else 7917c478bd9Sstevel@tonic-gate opc = DIF_OP_CMP; 7927c478bd9Sstevel@tonic-gate 7937c478bd9Sstevel@tonic-gate instr = DIF_INSTR_CMP(opc, dnp->dn_left->dn_reg, dnp->dn_right->dn_reg); 7947c478bd9Sstevel@tonic-gate dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr)); 7957c478bd9Sstevel@tonic-gate dt_regset_free(drp, dnp->dn_right->dn_reg); 7967c478bd9Sstevel@tonic-gate dnp->dn_reg = dnp->dn_left->dn_reg; 7977c478bd9Sstevel@tonic-gate 7987c478bd9Sstevel@tonic-gate instr = DIF_INSTR_BRANCH(op, lbl_true); 7997c478bd9Sstevel@tonic-gate dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr)); 8007c478bd9Sstevel@tonic-gate 8017c478bd9Sstevel@tonic-gate instr = DIF_INSTR_MOV(DIF_REG_R0, dnp->dn_reg); 8027c478bd9Sstevel@tonic-gate dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr)); 8037c478bd9Sstevel@tonic-gate 8047c478bd9Sstevel@tonic-gate instr = DIF_INSTR_BRANCH(DIF_OP_BA, lbl_post); 8057c478bd9Sstevel@tonic-gate dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr)); 8067c478bd9Sstevel@tonic-gate 8077c478bd9Sstevel@tonic-gate dt_cg_xsetx(dlp, NULL, lbl_true, dnp->dn_reg, 1); 8087c478bd9Sstevel@tonic-gate dt_irlist_append(dlp, dt_cg_node_alloc(lbl_post, DIF_INSTR_NOP)); 8097c478bd9Sstevel@tonic-gate } 8107c478bd9Sstevel@tonic-gate 8117c478bd9Sstevel@tonic-gate /* 8127c478bd9Sstevel@tonic-gate * Code generation for the ternary op requires some trickery with the assembler 8137c478bd9Sstevel@tonic-gate * in order to conserve registers. We generate code for dn_expr and dn_left 8147c478bd9Sstevel@tonic-gate * and free their registers so they do not have be consumed across codegen for 8157c478bd9Sstevel@tonic-gate * dn_right. We insert a dummy MOV at the end of dn_left into the destination 8167c478bd9Sstevel@tonic-gate * register, which is not yet known because we haven't done dn_right yet, and 8177c478bd9Sstevel@tonic-gate * save the pointer to this instruction node. We then generate code for 8187c478bd9Sstevel@tonic-gate * dn_right and use its register as our output. Finally, we reach back and 8197c478bd9Sstevel@tonic-gate * patch the instruction for dn_left to move its output into this register. 8207c478bd9Sstevel@tonic-gate */ 8217c478bd9Sstevel@tonic-gate static void 8227c478bd9Sstevel@tonic-gate dt_cg_ternary_op(dt_node_t *dnp, dt_irlist_t *dlp, dt_regset_t *drp) 8237c478bd9Sstevel@tonic-gate { 8247c478bd9Sstevel@tonic-gate uint_t lbl_false = dt_irlist_label(dlp); 8257c478bd9Sstevel@tonic-gate uint_t lbl_post = dt_irlist_label(dlp); 8267c478bd9Sstevel@tonic-gate 8277c478bd9Sstevel@tonic-gate dif_instr_t instr; 8287c478bd9Sstevel@tonic-gate dt_irnode_t *dip; 8297c478bd9Sstevel@tonic-gate 8307c478bd9Sstevel@tonic-gate dt_cg_node(dnp->dn_expr, dlp, drp); 8317c478bd9Sstevel@tonic-gate instr = DIF_INSTR_TST(dnp->dn_expr->dn_reg); 8327c478bd9Sstevel@tonic-gate dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr)); 8337c478bd9Sstevel@tonic-gate dt_regset_free(drp, dnp->dn_expr->dn_reg); 8347c478bd9Sstevel@tonic-gate 8357c478bd9Sstevel@tonic-gate instr = DIF_INSTR_BRANCH(DIF_OP_BE, lbl_false); 8367c478bd9Sstevel@tonic-gate dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr)); 8377c478bd9Sstevel@tonic-gate 8387c478bd9Sstevel@tonic-gate dt_cg_node(dnp->dn_left, dlp, drp); 8397c478bd9Sstevel@tonic-gate instr = DIF_INSTR_MOV(dnp->dn_left->dn_reg, DIF_REG_R0); 8407c478bd9Sstevel@tonic-gate dip = dt_cg_node_alloc(DT_LBL_NONE, instr); /* save dip for below */ 8417c478bd9Sstevel@tonic-gate dt_irlist_append(dlp, dip); 8427c478bd9Sstevel@tonic-gate dt_regset_free(drp, dnp->dn_left->dn_reg); 8437c478bd9Sstevel@tonic-gate 8447c478bd9Sstevel@tonic-gate instr = DIF_INSTR_BRANCH(DIF_OP_BA, lbl_post); 8457c478bd9Sstevel@tonic-gate dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr)); 8467c478bd9Sstevel@tonic-gate 8477c478bd9Sstevel@tonic-gate dt_irlist_append(dlp, dt_cg_node_alloc(lbl_false, DIF_INSTR_NOP)); 8487c478bd9Sstevel@tonic-gate dt_cg_node(dnp->dn_right, dlp, drp); 8497c478bd9Sstevel@tonic-gate dnp->dn_reg = dnp->dn_right->dn_reg; 8507c478bd9Sstevel@tonic-gate 8517c478bd9Sstevel@tonic-gate /* 8527c478bd9Sstevel@tonic-gate * Now that dn_reg is assigned, reach back and patch the correct MOV 8537c478bd9Sstevel@tonic-gate * instruction into the tail of dn_left. We know dn_reg was unused 8547c478bd9Sstevel@tonic-gate * at that point because otherwise dn_right couldn't have allocated it. 8557c478bd9Sstevel@tonic-gate */ 8567c478bd9Sstevel@tonic-gate dip->di_instr = DIF_INSTR_MOV(dnp->dn_left->dn_reg, dnp->dn_reg); 8577c478bd9Sstevel@tonic-gate dt_irlist_append(dlp, dt_cg_node_alloc(lbl_post, DIF_INSTR_NOP)); 8587c478bd9Sstevel@tonic-gate } 8597c478bd9Sstevel@tonic-gate 8607c478bd9Sstevel@tonic-gate static void 8617c478bd9Sstevel@tonic-gate dt_cg_logical_and(dt_node_t *dnp, dt_irlist_t *dlp, dt_regset_t *drp) 8627c478bd9Sstevel@tonic-gate { 8637c478bd9Sstevel@tonic-gate uint_t lbl_false = dt_irlist_label(dlp); 8647c478bd9Sstevel@tonic-gate uint_t lbl_post = dt_irlist_label(dlp); 8657c478bd9Sstevel@tonic-gate 8667c478bd9Sstevel@tonic-gate dif_instr_t instr; 8677c478bd9Sstevel@tonic-gate 8687c478bd9Sstevel@tonic-gate dt_cg_node(dnp->dn_left, dlp, drp); 8697c478bd9Sstevel@tonic-gate instr = DIF_INSTR_TST(dnp->dn_left->dn_reg); 8707c478bd9Sstevel@tonic-gate dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr)); 8717c478bd9Sstevel@tonic-gate dt_regset_free(drp, dnp->dn_left->dn_reg); 8727c478bd9Sstevel@tonic-gate 8737c478bd9Sstevel@tonic-gate instr = DIF_INSTR_BRANCH(DIF_OP_BE, lbl_false); 8747c478bd9Sstevel@tonic-gate dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr)); 8757c478bd9Sstevel@tonic-gate 8767c478bd9Sstevel@tonic-gate dt_cg_node(dnp->dn_right, dlp, drp); 8777c478bd9Sstevel@tonic-gate instr = DIF_INSTR_TST(dnp->dn_right->dn_reg); 8787c478bd9Sstevel@tonic-gate dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr)); 8797c478bd9Sstevel@tonic-gate dnp->dn_reg = dnp->dn_right->dn_reg; 8807c478bd9Sstevel@tonic-gate 8817c478bd9Sstevel@tonic-gate instr = DIF_INSTR_BRANCH(DIF_OP_BE, lbl_false); 8827c478bd9Sstevel@tonic-gate dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr)); 8837c478bd9Sstevel@tonic-gate 8847c478bd9Sstevel@tonic-gate dt_cg_setx(dlp, dnp->dn_reg, 1); 8857c478bd9Sstevel@tonic-gate 8867c478bd9Sstevel@tonic-gate instr = DIF_INSTR_BRANCH(DIF_OP_BA, lbl_post); 8877c478bd9Sstevel@tonic-gate dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr)); 8887c478bd9Sstevel@tonic-gate 8897c478bd9Sstevel@tonic-gate instr = DIF_INSTR_MOV(DIF_REG_R0, dnp->dn_reg); 8907c478bd9Sstevel@tonic-gate dt_irlist_append(dlp, dt_cg_node_alloc(lbl_false, instr)); 8917c478bd9Sstevel@tonic-gate 8927c478bd9Sstevel@tonic-gate dt_irlist_append(dlp, dt_cg_node_alloc(lbl_post, DIF_INSTR_NOP)); 8937c478bd9Sstevel@tonic-gate } 8947c478bd9Sstevel@tonic-gate 8957c478bd9Sstevel@tonic-gate static void 8967c478bd9Sstevel@tonic-gate dt_cg_logical_xor(dt_node_t *dnp, dt_irlist_t *dlp, dt_regset_t *drp) 8977c478bd9Sstevel@tonic-gate { 8987c478bd9Sstevel@tonic-gate uint_t lbl_next = dt_irlist_label(dlp); 8997c478bd9Sstevel@tonic-gate uint_t lbl_tail = dt_irlist_label(dlp); 9007c478bd9Sstevel@tonic-gate 9017c478bd9Sstevel@tonic-gate dif_instr_t instr; 9027c478bd9Sstevel@tonic-gate 9037c478bd9Sstevel@tonic-gate dt_cg_node(dnp->dn_left, dlp, drp); 9047c478bd9Sstevel@tonic-gate instr = DIF_INSTR_TST(dnp->dn_left->dn_reg); 9057c478bd9Sstevel@tonic-gate dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr)); 9067c478bd9Sstevel@tonic-gate 9077c478bd9Sstevel@tonic-gate instr = DIF_INSTR_BRANCH(DIF_OP_BE, lbl_next); 9087c478bd9Sstevel@tonic-gate dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr)); 9097c478bd9Sstevel@tonic-gate dt_cg_setx(dlp, dnp->dn_left->dn_reg, 1); 9107c478bd9Sstevel@tonic-gate 9117c478bd9Sstevel@tonic-gate dt_irlist_append(dlp, dt_cg_node_alloc(lbl_next, DIF_INSTR_NOP)); 9127c478bd9Sstevel@tonic-gate dt_cg_node(dnp->dn_right, dlp, drp); 9137c478bd9Sstevel@tonic-gate 9147c478bd9Sstevel@tonic-gate instr = DIF_INSTR_TST(dnp->dn_right->dn_reg); 9157c478bd9Sstevel@tonic-gate dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr)); 9167c478bd9Sstevel@tonic-gate 9177c478bd9Sstevel@tonic-gate instr = DIF_INSTR_BRANCH(DIF_OP_BE, lbl_tail); 9187c478bd9Sstevel@tonic-gate dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr)); 9197c478bd9Sstevel@tonic-gate dt_cg_setx(dlp, dnp->dn_right->dn_reg, 1); 9207c478bd9Sstevel@tonic-gate 9217c478bd9Sstevel@tonic-gate instr = DIF_INSTR_FMT(DIF_OP_XOR, dnp->dn_left->dn_reg, 9227c478bd9Sstevel@tonic-gate dnp->dn_right->dn_reg, dnp->dn_left->dn_reg); 9237c478bd9Sstevel@tonic-gate 9247c478bd9Sstevel@tonic-gate dt_irlist_append(dlp, dt_cg_node_alloc(lbl_tail, instr)); 9257c478bd9Sstevel@tonic-gate 9267c478bd9Sstevel@tonic-gate dt_regset_free(drp, dnp->dn_right->dn_reg); 9277c478bd9Sstevel@tonic-gate dnp->dn_reg = dnp->dn_left->dn_reg; 9287c478bd9Sstevel@tonic-gate } 9297c478bd9Sstevel@tonic-gate 9307c478bd9Sstevel@tonic-gate static void 9317c478bd9Sstevel@tonic-gate dt_cg_logical_or(dt_node_t *dnp, dt_irlist_t *dlp, dt_regset_t *drp) 9327c478bd9Sstevel@tonic-gate { 9337c478bd9Sstevel@tonic-gate uint_t lbl_true = dt_irlist_label(dlp); 9347c478bd9Sstevel@tonic-gate uint_t lbl_false = dt_irlist_label(dlp); 9357c478bd9Sstevel@tonic-gate uint_t lbl_post = dt_irlist_label(dlp); 9367c478bd9Sstevel@tonic-gate 9377c478bd9Sstevel@tonic-gate dif_instr_t instr; 9387c478bd9Sstevel@tonic-gate 9397c478bd9Sstevel@tonic-gate dt_cg_node(dnp->dn_left, dlp, drp); 9407c478bd9Sstevel@tonic-gate instr = DIF_INSTR_TST(dnp->dn_left->dn_reg); 9417c478bd9Sstevel@tonic-gate dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr)); 9427c478bd9Sstevel@tonic-gate dt_regset_free(drp, dnp->dn_left->dn_reg); 9437c478bd9Sstevel@tonic-gate 9447c478bd9Sstevel@tonic-gate instr = DIF_INSTR_BRANCH(DIF_OP_BNE, lbl_true); 9457c478bd9Sstevel@tonic-gate dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr)); 9467c478bd9Sstevel@tonic-gate 9477c478bd9Sstevel@tonic-gate dt_cg_node(dnp->dn_right, dlp, drp); 9487c478bd9Sstevel@tonic-gate instr = DIF_INSTR_TST(dnp->dn_right->dn_reg); 9497c478bd9Sstevel@tonic-gate dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr)); 9507c478bd9Sstevel@tonic-gate dnp->dn_reg = dnp->dn_right->dn_reg; 9517c478bd9Sstevel@tonic-gate 9527c478bd9Sstevel@tonic-gate instr = DIF_INSTR_BRANCH(DIF_OP_BE, lbl_false); 9537c478bd9Sstevel@tonic-gate dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr)); 9547c478bd9Sstevel@tonic-gate 9557c478bd9Sstevel@tonic-gate dt_cg_xsetx(dlp, NULL, lbl_true, dnp->dn_reg, 1); 9567c478bd9Sstevel@tonic-gate 9577c478bd9Sstevel@tonic-gate instr = DIF_INSTR_BRANCH(DIF_OP_BA, lbl_post); 9587c478bd9Sstevel@tonic-gate dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr)); 9597c478bd9Sstevel@tonic-gate 9607c478bd9Sstevel@tonic-gate instr = DIF_INSTR_MOV(DIF_REG_R0, dnp->dn_reg); 9617c478bd9Sstevel@tonic-gate dt_irlist_append(dlp, dt_cg_node_alloc(lbl_false, instr)); 9627c478bd9Sstevel@tonic-gate 9637c478bd9Sstevel@tonic-gate dt_irlist_append(dlp, dt_cg_node_alloc(lbl_post, DIF_INSTR_NOP)); 9647c478bd9Sstevel@tonic-gate } 9657c478bd9Sstevel@tonic-gate 9667c478bd9Sstevel@tonic-gate static void 9677c478bd9Sstevel@tonic-gate dt_cg_logical_neg(dt_node_t *dnp, dt_irlist_t *dlp, dt_regset_t *drp) 9687c478bd9Sstevel@tonic-gate { 9697c478bd9Sstevel@tonic-gate uint_t lbl_zero = dt_irlist_label(dlp); 9707c478bd9Sstevel@tonic-gate uint_t lbl_post = dt_irlist_label(dlp); 9717c478bd9Sstevel@tonic-gate 9727c478bd9Sstevel@tonic-gate dif_instr_t instr; 9737c478bd9Sstevel@tonic-gate 9747c478bd9Sstevel@tonic-gate dt_cg_node(dnp->dn_child, dlp, drp); 9757c478bd9Sstevel@tonic-gate dnp->dn_reg = dnp->dn_child->dn_reg; 9767c478bd9Sstevel@tonic-gate 9777c478bd9Sstevel@tonic-gate instr = DIF_INSTR_TST(dnp->dn_reg); 9787c478bd9Sstevel@tonic-gate dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr)); 9797c478bd9Sstevel@tonic-gate 9807c478bd9Sstevel@tonic-gate instr = DIF_INSTR_BRANCH(DIF_OP_BE, lbl_zero); 9817c478bd9Sstevel@tonic-gate dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr)); 9827c478bd9Sstevel@tonic-gate 9837c478bd9Sstevel@tonic-gate instr = DIF_INSTR_MOV(DIF_REG_R0, dnp->dn_reg); 9847c478bd9Sstevel@tonic-gate dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr)); 9857c478bd9Sstevel@tonic-gate 9867c478bd9Sstevel@tonic-gate instr = DIF_INSTR_BRANCH(DIF_OP_BA, lbl_post); 9877c478bd9Sstevel@tonic-gate dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr)); 9887c478bd9Sstevel@tonic-gate 9897c478bd9Sstevel@tonic-gate dt_cg_xsetx(dlp, NULL, lbl_zero, dnp->dn_reg, 1); 9907c478bd9Sstevel@tonic-gate dt_irlist_append(dlp, dt_cg_node_alloc(lbl_post, DIF_INSTR_NOP)); 9917c478bd9Sstevel@tonic-gate } 9927c478bd9Sstevel@tonic-gate 9937c478bd9Sstevel@tonic-gate static void 9947c478bd9Sstevel@tonic-gate dt_cg_asgn_op(dt_node_t *dnp, dt_irlist_t *dlp, dt_regset_t *drp) 9957c478bd9Sstevel@tonic-gate { 9967c478bd9Sstevel@tonic-gate dif_instr_t instr; 9977c478bd9Sstevel@tonic-gate dt_ident_t *idp; 9987c478bd9Sstevel@tonic-gate 9997c478bd9Sstevel@tonic-gate /* 10007c478bd9Sstevel@tonic-gate * If we are performing a structure assignment of a translated type, 10017c478bd9Sstevel@tonic-gate * we must instantiate all members and create a snapshot of the object 10027c478bd9Sstevel@tonic-gate * in scratch space. We allocs a chunk of memory, generate code for 10037c478bd9Sstevel@tonic-gate * each member, and then set dnp->dn_reg to the scratch object address. 10047c478bd9Sstevel@tonic-gate */ 10057c478bd9Sstevel@tonic-gate if ((idp = dt_node_resolve(dnp->dn_right, DT_IDENT_XLSOU)) != NULL) { 10067c478bd9Sstevel@tonic-gate ctf_membinfo_t ctm; 10077c478bd9Sstevel@tonic-gate dt_xlator_t *dxp = idp->di_data; 10087c478bd9Sstevel@tonic-gate dt_node_t *mnp, dn, mn; 10097c478bd9Sstevel@tonic-gate int r1, r2; 10107c478bd9Sstevel@tonic-gate 10117c478bd9Sstevel@tonic-gate /* 10127c478bd9Sstevel@tonic-gate * Create two fake dt_node_t's representing operator "." and a 10137c478bd9Sstevel@tonic-gate * right-hand identifier child node. These will be repeatedly 10147c478bd9Sstevel@tonic-gate * modified according to each instantiated member so that we 10157c478bd9Sstevel@tonic-gate * can pass them to dt_cg_store() and effect a member store. 10167c478bd9Sstevel@tonic-gate */ 10177c478bd9Sstevel@tonic-gate bzero(&dn, sizeof (dt_node_t)); 10187c478bd9Sstevel@tonic-gate dn.dn_kind = DT_NODE_OP2; 10197c478bd9Sstevel@tonic-gate dn.dn_op = DT_TOK_DOT; 10207c478bd9Sstevel@tonic-gate dn.dn_left = dnp; 10217c478bd9Sstevel@tonic-gate dn.dn_right = &mn; 10227c478bd9Sstevel@tonic-gate 10237c478bd9Sstevel@tonic-gate bzero(&mn, sizeof (dt_node_t)); 10247c478bd9Sstevel@tonic-gate mn.dn_kind = DT_NODE_IDENT; 10257c478bd9Sstevel@tonic-gate mn.dn_op = DT_TOK_IDENT; 10267c478bd9Sstevel@tonic-gate 10277c478bd9Sstevel@tonic-gate /* 10287c478bd9Sstevel@tonic-gate * Allocate a register for our scratch data pointer. First we 10297c478bd9Sstevel@tonic-gate * set it to the size of our data structure, and then replace 10307c478bd9Sstevel@tonic-gate * it with the result of an allocs of the specified size. 10317c478bd9Sstevel@tonic-gate */ 1032e5803b76SAdam H. Leventhal r1 = dt_regset_alloc(drp); 10337c478bd9Sstevel@tonic-gate dt_cg_setx(dlp, r1, 10347c478bd9Sstevel@tonic-gate ctf_type_size(dxp->dx_dst_ctfp, dxp->dx_dst_base)); 10357c478bd9Sstevel@tonic-gate 10367c478bd9Sstevel@tonic-gate instr = DIF_INSTR_ALLOCS(r1, r1); 10377c478bd9Sstevel@tonic-gate dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr)); 10387c478bd9Sstevel@tonic-gate 10397c478bd9Sstevel@tonic-gate /* 10407c478bd9Sstevel@tonic-gate * When dt_cg_asgn_op() is called, we have already generated 10417c478bd9Sstevel@tonic-gate * code for dnp->dn_right, which is the translator input. We 10427c478bd9Sstevel@tonic-gate * now associate this register with the translator's input 10437c478bd9Sstevel@tonic-gate * identifier so it can be referenced during our member loop. 10447c478bd9Sstevel@tonic-gate */ 10457c478bd9Sstevel@tonic-gate dxp->dx_ident->di_flags |= DT_IDFLG_CGREG; 10467c478bd9Sstevel@tonic-gate dxp->dx_ident->di_id = dnp->dn_right->dn_reg; 10477c478bd9Sstevel@tonic-gate 10487c478bd9Sstevel@tonic-gate for (mnp = dxp->dx_members; mnp != NULL; mnp = mnp->dn_list) { 10497c478bd9Sstevel@tonic-gate /* 10507c478bd9Sstevel@tonic-gate * Generate code for the translator member expression, 10517c478bd9Sstevel@tonic-gate * and then cast the result to the member type. 10527c478bd9Sstevel@tonic-gate */ 10537c478bd9Sstevel@tonic-gate dt_cg_node(mnp->dn_membexpr, dlp, drp); 10547c478bd9Sstevel@tonic-gate mnp->dn_reg = mnp->dn_membexpr->dn_reg; 10557c478bd9Sstevel@tonic-gate dt_cg_typecast(mnp->dn_membexpr, mnp, dlp, drp); 10567c478bd9Sstevel@tonic-gate 10577c478bd9Sstevel@tonic-gate /* 10587c478bd9Sstevel@tonic-gate * Ask CTF for the offset of the member so we can store 10597c478bd9Sstevel@tonic-gate * to the appropriate offset. This call has already 10607c478bd9Sstevel@tonic-gate * been done once by the parser, so it should succeed. 10617c478bd9Sstevel@tonic-gate */ 10627c478bd9Sstevel@tonic-gate if (ctf_member_info(dxp->dx_dst_ctfp, dxp->dx_dst_base, 10637c478bd9Sstevel@tonic-gate mnp->dn_membname, &ctm) == CTF_ERR) { 10647c478bd9Sstevel@tonic-gate yypcb->pcb_hdl->dt_ctferr = 10657c478bd9Sstevel@tonic-gate ctf_errno(dxp->dx_dst_ctfp); 10667c478bd9Sstevel@tonic-gate longjmp(yypcb->pcb_jmpbuf, EDT_CTF); 10677c478bd9Sstevel@tonic-gate } 10687c478bd9Sstevel@tonic-gate 10697c478bd9Sstevel@tonic-gate /* 10707c478bd9Sstevel@tonic-gate * If the destination member is at offset 0, store the 10717c478bd9Sstevel@tonic-gate * result directly to r1 (the scratch buffer address). 10727c478bd9Sstevel@tonic-gate * Otherwise allocate another temporary for the offset 10737c478bd9Sstevel@tonic-gate * and add r1 to it before storing the result. 10747c478bd9Sstevel@tonic-gate */ 10757c478bd9Sstevel@tonic-gate if (ctm.ctm_offset != 0) { 1076e5803b76SAdam H. Leventhal r2 = dt_regset_alloc(drp); 10777c478bd9Sstevel@tonic-gate 10787c478bd9Sstevel@tonic-gate /* 10797c478bd9Sstevel@tonic-gate * Add the member offset rounded down to the 10807c478bd9Sstevel@tonic-gate * nearest byte. If the offset was not aligned 10817c478bd9Sstevel@tonic-gate * on a byte boundary, this member is a bit- 10827c478bd9Sstevel@tonic-gate * field and dt_cg_store() will handle masking. 10837c478bd9Sstevel@tonic-gate */ 10847c478bd9Sstevel@tonic-gate dt_cg_setx(dlp, r2, ctm.ctm_offset / NBBY); 10857c478bd9Sstevel@tonic-gate instr = DIF_INSTR_FMT(DIF_OP_ADD, r1, r2, r2); 10867c478bd9Sstevel@tonic-gate dt_irlist_append(dlp, 10877c478bd9Sstevel@tonic-gate dt_cg_node_alloc(DT_LBL_NONE, instr)); 10887c478bd9Sstevel@tonic-gate 10897c478bd9Sstevel@tonic-gate dt_node_type_propagate(mnp, &dn); 10907c478bd9Sstevel@tonic-gate dn.dn_right->dn_string = mnp->dn_membname; 10917c478bd9Sstevel@tonic-gate dn.dn_reg = r2; 10927c478bd9Sstevel@tonic-gate 10937c478bd9Sstevel@tonic-gate dt_cg_store(mnp, dlp, drp, &dn); 10947c478bd9Sstevel@tonic-gate dt_regset_free(drp, r2); 10957c478bd9Sstevel@tonic-gate 10967c478bd9Sstevel@tonic-gate } else { 10977c478bd9Sstevel@tonic-gate dt_node_type_propagate(mnp, &dn); 10987c478bd9Sstevel@tonic-gate dn.dn_right->dn_string = mnp->dn_membname; 10997c478bd9Sstevel@tonic-gate dn.dn_reg = r1; 11007c478bd9Sstevel@tonic-gate 11017c478bd9Sstevel@tonic-gate dt_cg_store(mnp, dlp, drp, &dn); 11027c478bd9Sstevel@tonic-gate } 11037c478bd9Sstevel@tonic-gate 11047c478bd9Sstevel@tonic-gate dt_regset_free(drp, mnp->dn_reg); 11057c478bd9Sstevel@tonic-gate } 11067c478bd9Sstevel@tonic-gate 11077c478bd9Sstevel@tonic-gate dxp->dx_ident->di_flags &= ~DT_IDFLG_CGREG; 11087c478bd9Sstevel@tonic-gate dxp->dx_ident->di_id = 0; 11097c478bd9Sstevel@tonic-gate 11101a7c1b72Smws if (dnp->dn_right->dn_reg != -1) 11117c478bd9Sstevel@tonic-gate dt_regset_free(drp, dnp->dn_right->dn_reg); 11121a7c1b72Smws 11131a7c1b72Smws assert(dnp->dn_reg == dnp->dn_right->dn_reg); 11147c478bd9Sstevel@tonic-gate dnp->dn_reg = r1; 11157c478bd9Sstevel@tonic-gate } 11167c478bd9Sstevel@tonic-gate 11177c478bd9Sstevel@tonic-gate /* 11187c478bd9Sstevel@tonic-gate * If we are storing to a variable, generate an stv instruction from 11197c478bd9Sstevel@tonic-gate * the variable specified by the identifier. If we are storing to a 11207c478bd9Sstevel@tonic-gate * memory address, generate code again for the left-hand side using 11217c478bd9Sstevel@tonic-gate * DT_NF_REF to get the address, and then generate a store to it. 11227c478bd9Sstevel@tonic-gate * In both paths, we assume dnp->dn_reg already has the new value. 11237c478bd9Sstevel@tonic-gate */ 11247c478bd9Sstevel@tonic-gate if (dnp->dn_left->dn_kind == DT_NODE_VAR) { 11257c478bd9Sstevel@tonic-gate idp = dt_ident_resolve(dnp->dn_left->dn_ident); 11267c478bd9Sstevel@tonic-gate 11277c478bd9Sstevel@tonic-gate if (idp->di_kind == DT_IDENT_ARRAY) 11287c478bd9Sstevel@tonic-gate dt_cg_arglist(idp, dnp->dn_left->dn_args, dlp, drp); 11297c478bd9Sstevel@tonic-gate 11307c478bd9Sstevel@tonic-gate idp->di_flags |= DT_IDFLG_DIFW; 11317c478bd9Sstevel@tonic-gate instr = DIF_INSTR_STV(dt_cg_stvar(idp), 11327c478bd9Sstevel@tonic-gate idp->di_id, dnp->dn_reg); 11337c478bd9Sstevel@tonic-gate dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr)); 11347c478bd9Sstevel@tonic-gate } else { 11357c478bd9Sstevel@tonic-gate uint_t rbit = dnp->dn_left->dn_flags & DT_NF_REF; 11367c478bd9Sstevel@tonic-gate 11377c478bd9Sstevel@tonic-gate assert(dnp->dn_left->dn_flags & DT_NF_WRITABLE); 11387c478bd9Sstevel@tonic-gate assert(dnp->dn_left->dn_flags & DT_NF_LVALUE); 11397c478bd9Sstevel@tonic-gate 11407c478bd9Sstevel@tonic-gate dnp->dn_left->dn_flags |= DT_NF_REF; /* force pass-by-ref */ 11417c478bd9Sstevel@tonic-gate 11427c478bd9Sstevel@tonic-gate dt_cg_node(dnp->dn_left, dlp, drp); 11437c478bd9Sstevel@tonic-gate dt_cg_store(dnp, dlp, drp, dnp->dn_left); 11447c478bd9Sstevel@tonic-gate dt_regset_free(drp, dnp->dn_left->dn_reg); 11457c478bd9Sstevel@tonic-gate 11467c478bd9Sstevel@tonic-gate dnp->dn_left->dn_flags &= ~DT_NF_REF; 11477c478bd9Sstevel@tonic-gate dnp->dn_left->dn_flags |= rbit; 11487c478bd9Sstevel@tonic-gate } 11497c478bd9Sstevel@tonic-gate } 11507c478bd9Sstevel@tonic-gate 11517c478bd9Sstevel@tonic-gate static void 11527c478bd9Sstevel@tonic-gate dt_cg_assoc_op(dt_node_t *dnp, dt_irlist_t *dlp, dt_regset_t *drp) 11537c478bd9Sstevel@tonic-gate { 11547c478bd9Sstevel@tonic-gate dif_instr_t instr; 11557c478bd9Sstevel@tonic-gate uint_t op; 11567c478bd9Sstevel@tonic-gate 11577c478bd9Sstevel@tonic-gate assert(dnp->dn_kind == DT_NODE_VAR); 11587c478bd9Sstevel@tonic-gate assert(!(dnp->dn_ident->di_flags & DT_IDFLG_LOCAL)); 11597c478bd9Sstevel@tonic-gate assert(dnp->dn_args != NULL); 11607c478bd9Sstevel@tonic-gate 11617c478bd9Sstevel@tonic-gate dt_cg_arglist(dnp->dn_ident, dnp->dn_args, dlp, drp); 11627c478bd9Sstevel@tonic-gate 1163e5803b76SAdam H. Leventhal dnp->dn_reg = dt_regset_alloc(drp); 11647c478bd9Sstevel@tonic-gate 11657c478bd9Sstevel@tonic-gate if (dnp->dn_ident->di_flags & DT_IDFLG_TLS) 11667c478bd9Sstevel@tonic-gate op = DIF_OP_LDTAA; 11677c478bd9Sstevel@tonic-gate else 11687c478bd9Sstevel@tonic-gate op = DIF_OP_LDGAA; 11697c478bd9Sstevel@tonic-gate 11707c478bd9Sstevel@tonic-gate dnp->dn_ident->di_flags |= DT_IDFLG_DIFR; 11717c478bd9Sstevel@tonic-gate instr = DIF_INSTR_LDV(op, dnp->dn_ident->di_id, dnp->dn_reg); 11727c478bd9Sstevel@tonic-gate dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr)); 11737c478bd9Sstevel@tonic-gate 11747c478bd9Sstevel@tonic-gate /* 11757c478bd9Sstevel@tonic-gate * If the associative array is a pass-by-reference type, then we are 11767c478bd9Sstevel@tonic-gate * loading its value as a pointer to either load or store through it. 11777c478bd9Sstevel@tonic-gate * The array element in question may not have been faulted in yet, in 11787c478bd9Sstevel@tonic-gate * which case DIF_OP_LD*AA will return zero. We append an epilogue 11797c478bd9Sstevel@tonic-gate * of instructions similar to the following: 11807c478bd9Sstevel@tonic-gate * 11817c478bd9Sstevel@tonic-gate * ld?aa id, %r1 ! base ld?aa instruction above 11827c478bd9Sstevel@tonic-gate * tst %r1 ! start of epilogue 11837c478bd9Sstevel@tonic-gate * +--- bne label 11847c478bd9Sstevel@tonic-gate * | setx size, %r1 11857c478bd9Sstevel@tonic-gate * | allocs %r1, %r1 11867c478bd9Sstevel@tonic-gate * | st?aa id, %r1 11877c478bd9Sstevel@tonic-gate * | ld?aa id, %r1 11887c478bd9Sstevel@tonic-gate * v 11897c478bd9Sstevel@tonic-gate * label: < rest of code > 11907c478bd9Sstevel@tonic-gate * 11917c478bd9Sstevel@tonic-gate * The idea is that we allocs a zero-filled chunk of scratch space and 11927c478bd9Sstevel@tonic-gate * do a DIF_OP_ST*AA to fault in and initialize the array element, and 11937c478bd9Sstevel@tonic-gate * then reload it to get the faulted-in address of the new variable 11947c478bd9Sstevel@tonic-gate * storage. This isn't cheap, but pass-by-ref associative array values 11957c478bd9Sstevel@tonic-gate * are (thus far) uncommon and the allocs cost only occurs once. If 11967c478bd9Sstevel@tonic-gate * this path becomes important to DTrace users, we can improve things 11977c478bd9Sstevel@tonic-gate * by adding a new DIF opcode to fault in associative array elements. 11987c478bd9Sstevel@tonic-gate */ 11997c478bd9Sstevel@tonic-gate if (dnp->dn_flags & DT_NF_REF) { 12007c478bd9Sstevel@tonic-gate uint_t stvop = op == DIF_OP_LDTAA ? DIF_OP_STTAA : DIF_OP_STGAA; 12017c478bd9Sstevel@tonic-gate uint_t label = dt_irlist_label(dlp); 12027c478bd9Sstevel@tonic-gate 12037c478bd9Sstevel@tonic-gate instr = DIF_INSTR_TST(dnp->dn_reg); 12047c478bd9Sstevel@tonic-gate dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr)); 12057c478bd9Sstevel@tonic-gate 12067c478bd9Sstevel@tonic-gate instr = DIF_INSTR_BRANCH(DIF_OP_BNE, label); 12077c478bd9Sstevel@tonic-gate dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr)); 12087c478bd9Sstevel@tonic-gate 12097c478bd9Sstevel@tonic-gate dt_cg_setx(dlp, dnp->dn_reg, dt_node_type_size(dnp)); 12107c478bd9Sstevel@tonic-gate instr = DIF_INSTR_ALLOCS(dnp->dn_reg, dnp->dn_reg); 12117c478bd9Sstevel@tonic-gate dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr)); 12127c478bd9Sstevel@tonic-gate 12137c478bd9Sstevel@tonic-gate dnp->dn_ident->di_flags |= DT_IDFLG_DIFW; 12147c478bd9Sstevel@tonic-gate instr = DIF_INSTR_STV(stvop, dnp->dn_ident->di_id, dnp->dn_reg); 12157c478bd9Sstevel@tonic-gate dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr)); 12167c478bd9Sstevel@tonic-gate 12177c478bd9Sstevel@tonic-gate instr = DIF_INSTR_LDV(op, dnp->dn_ident->di_id, dnp->dn_reg); 12187c478bd9Sstevel@tonic-gate dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr)); 12197c478bd9Sstevel@tonic-gate 12207c478bd9Sstevel@tonic-gate dt_irlist_append(dlp, dt_cg_node_alloc(label, DIF_INSTR_NOP)); 12217c478bd9Sstevel@tonic-gate } 12227c478bd9Sstevel@tonic-gate } 12237c478bd9Sstevel@tonic-gate 12247c478bd9Sstevel@tonic-gate static void 12257c478bd9Sstevel@tonic-gate dt_cg_array_op(dt_node_t *dnp, dt_irlist_t *dlp, dt_regset_t *drp) 12267c478bd9Sstevel@tonic-gate { 12277c478bd9Sstevel@tonic-gate dt_probe_t *prp = yypcb->pcb_probe; 12287c478bd9Sstevel@tonic-gate uintmax_t saved = dnp->dn_args->dn_value; 12291a7c1b72Smws dt_ident_t *idp = dnp->dn_ident; 12307c478bd9Sstevel@tonic-gate 12317c478bd9Sstevel@tonic-gate dif_instr_t instr; 12327c478bd9Sstevel@tonic-gate uint_t op; 12337c478bd9Sstevel@tonic-gate size_t size; 12347c478bd9Sstevel@tonic-gate int reg, n; 12357c478bd9Sstevel@tonic-gate 12367c478bd9Sstevel@tonic-gate assert(dnp->dn_kind == DT_NODE_VAR); 12371a7c1b72Smws assert(!(idp->di_flags & DT_IDFLG_LOCAL)); 12387c478bd9Sstevel@tonic-gate 12397c478bd9Sstevel@tonic-gate assert(dnp->dn_args->dn_kind == DT_NODE_INT); 12407c478bd9Sstevel@tonic-gate assert(dnp->dn_args->dn_list == NULL); 12417c478bd9Sstevel@tonic-gate 12427c478bd9Sstevel@tonic-gate /* 12437c478bd9Sstevel@tonic-gate * If this is a reference in the args[] array, temporarily modify the 12441a7c1b72Smws * array index according to the static argument mapping (if any), 12451a7c1b72Smws * unless the argument reference is provided by a dynamic translator. 12461a7c1b72Smws * If we're using a dynamic translator for args[], then just set dn_reg 12471a7c1b72Smws * to an invalid reg and return: DIF_OP_XLARG will fetch the arg later. 12487c478bd9Sstevel@tonic-gate */ 12491a7c1b72Smws if (idp->di_id == DIF_VAR_ARGS) { 12501a7c1b72Smws if ((idp->di_kind == DT_IDENT_XLPTR || 12511a7c1b72Smws idp->di_kind == DT_IDENT_XLSOU) && 12521a7c1b72Smws dt_xlator_dynamic(idp->di_data)) { 12531a7c1b72Smws dnp->dn_reg = -1; 12541a7c1b72Smws return; 12551a7c1b72Smws } 12567c478bd9Sstevel@tonic-gate dnp->dn_args->dn_value = prp->pr_mapping[saved]; 12571a7c1b72Smws } 12587c478bd9Sstevel@tonic-gate 12597c478bd9Sstevel@tonic-gate dt_cg_node(dnp->dn_args, dlp, drp); 12607c478bd9Sstevel@tonic-gate dnp->dn_args->dn_value = saved; 12617c478bd9Sstevel@tonic-gate 12627c478bd9Sstevel@tonic-gate dnp->dn_reg = dnp->dn_args->dn_reg; 12637c478bd9Sstevel@tonic-gate 12641a7c1b72Smws if (idp->di_flags & DT_IDFLG_TLS) 12657c478bd9Sstevel@tonic-gate op = DIF_OP_LDTA; 12667c478bd9Sstevel@tonic-gate else 12677c478bd9Sstevel@tonic-gate op = DIF_OP_LDGA; 12687c478bd9Sstevel@tonic-gate 12691a7c1b72Smws idp->di_flags |= DT_IDFLG_DIFR; 12707c478bd9Sstevel@tonic-gate 12711a7c1b72Smws instr = DIF_INSTR_LDA(op, idp->di_id, 12727c478bd9Sstevel@tonic-gate dnp->dn_args->dn_reg, dnp->dn_reg); 12737c478bd9Sstevel@tonic-gate 12747c478bd9Sstevel@tonic-gate dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr)); 12757c478bd9Sstevel@tonic-gate 12767c478bd9Sstevel@tonic-gate /* 12777c478bd9Sstevel@tonic-gate * If this is a reference to the args[] array, we need to take the 12787c478bd9Sstevel@tonic-gate * additional step of explicitly eliminating any bits larger than the 12797c478bd9Sstevel@tonic-gate * type size: the DIF interpreter in the kernel will always give us 12807c478bd9Sstevel@tonic-gate * the raw (64-bit) argument value, and any bits larger than the type 12817c478bd9Sstevel@tonic-gate * size may be junk. As a practical matter, this arises only on 64-bit 12827c478bd9Sstevel@tonic-gate * architectures and only when the argument index is larger than the 12837c478bd9Sstevel@tonic-gate * number of arguments passed directly to DTrace: if a 8-, 16- or 12847c478bd9Sstevel@tonic-gate * 32-bit argument must be retrieved from the stack, it is possible 12857c478bd9Sstevel@tonic-gate * (and it some cases, likely) that the upper bits will be garbage. 12867c478bd9Sstevel@tonic-gate */ 12871a7c1b72Smws if (idp->di_id != DIF_VAR_ARGS || !dt_node_is_scalar(dnp)) 12887c478bd9Sstevel@tonic-gate return; 12897c478bd9Sstevel@tonic-gate 12907c478bd9Sstevel@tonic-gate if ((size = dt_node_type_size(dnp)) == sizeof (uint64_t)) 12917c478bd9Sstevel@tonic-gate return; 12927c478bd9Sstevel@tonic-gate 1293e5803b76SAdam H. Leventhal reg = dt_regset_alloc(drp); 12947c478bd9Sstevel@tonic-gate assert(size < sizeof (uint64_t)); 12957c478bd9Sstevel@tonic-gate n = sizeof (uint64_t) * NBBY - size * NBBY; 12967c478bd9Sstevel@tonic-gate 12977c478bd9Sstevel@tonic-gate dt_cg_setx(dlp, reg, n); 12987c478bd9Sstevel@tonic-gate 12997c478bd9Sstevel@tonic-gate instr = DIF_INSTR_FMT(DIF_OP_SLL, dnp->dn_reg, reg, dnp->dn_reg); 13007c478bd9Sstevel@tonic-gate dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr)); 13017c478bd9Sstevel@tonic-gate 13027c478bd9Sstevel@tonic-gate instr = DIF_INSTR_FMT((dnp->dn_flags & DT_NF_SIGNED) ? 13037c478bd9Sstevel@tonic-gate DIF_OP_SRA : DIF_OP_SRL, dnp->dn_reg, reg, dnp->dn_reg); 13047c478bd9Sstevel@tonic-gate 13057c478bd9Sstevel@tonic-gate dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr)); 13067c478bd9Sstevel@tonic-gate dt_regset_free(drp, reg); 13077c478bd9Sstevel@tonic-gate } 13087c478bd9Sstevel@tonic-gate 13097c478bd9Sstevel@tonic-gate /* 13107c478bd9Sstevel@tonic-gate * Generate code for an inlined variable reference. Inlines can be used to 13117c478bd9Sstevel@tonic-gate * define either scalar or associative array substitutions. For scalars, we 13127c478bd9Sstevel@tonic-gate * simply generate code for the parse tree saved in the identifier's din_root, 13137c478bd9Sstevel@tonic-gate * and then cast the resulting expression to the inline's declaration type. 13147c478bd9Sstevel@tonic-gate * For arrays, we take the input parameter subtrees from dnp->dn_args and 13157c478bd9Sstevel@tonic-gate * temporarily store them in the din_root of each din_argv[i] identifier, 13167c478bd9Sstevel@tonic-gate * which are themselves inlines and were set up for us by the parser. The 13177c478bd9Sstevel@tonic-gate * result is that any reference to the inlined parameter inside the top-level 13187c478bd9Sstevel@tonic-gate * din_root will turn into a recursive call to dt_cg_inline() for a scalar 13197c478bd9Sstevel@tonic-gate * inline whose din_root will refer to the subtree pointed to by the argument. 13207c478bd9Sstevel@tonic-gate */ 13217c478bd9Sstevel@tonic-gate static void 13227c478bd9Sstevel@tonic-gate dt_cg_inline(dt_node_t *dnp, dt_irlist_t *dlp, dt_regset_t *drp) 13237c478bd9Sstevel@tonic-gate { 13247c478bd9Sstevel@tonic-gate dt_ident_t *idp = dnp->dn_ident; 13257c478bd9Sstevel@tonic-gate dt_idnode_t *inp = idp->di_iarg; 13267c478bd9Sstevel@tonic-gate 13277c478bd9Sstevel@tonic-gate dt_idnode_t *pinp; 13287c478bd9Sstevel@tonic-gate dt_node_t *pnp; 13297c478bd9Sstevel@tonic-gate int i; 13307c478bd9Sstevel@tonic-gate 13317c478bd9Sstevel@tonic-gate assert(idp->di_flags & DT_IDFLG_INLINE); 13327c478bd9Sstevel@tonic-gate assert(idp->di_ops == &dt_idops_inline); 13337c478bd9Sstevel@tonic-gate 13347c478bd9Sstevel@tonic-gate if (idp->di_kind == DT_IDENT_ARRAY) { 13357c478bd9Sstevel@tonic-gate for (i = 0, pnp = dnp->dn_args; 13367c478bd9Sstevel@tonic-gate pnp != NULL; pnp = pnp->dn_list, i++) { 13377c478bd9Sstevel@tonic-gate if (inp->din_argv[i] != NULL) { 13387c478bd9Sstevel@tonic-gate pinp = inp->din_argv[i]->di_iarg; 13397c478bd9Sstevel@tonic-gate pinp->din_root = pnp; 13407c478bd9Sstevel@tonic-gate } 13417c478bd9Sstevel@tonic-gate } 13427c478bd9Sstevel@tonic-gate } 13437c478bd9Sstevel@tonic-gate 13447c478bd9Sstevel@tonic-gate dt_cg_node(inp->din_root, dlp, drp); 13457c478bd9Sstevel@tonic-gate dnp->dn_reg = inp->din_root->dn_reg; 13467c478bd9Sstevel@tonic-gate dt_cg_typecast(inp->din_root, dnp, dlp, drp); 13477c478bd9Sstevel@tonic-gate 13487c478bd9Sstevel@tonic-gate if (idp->di_kind == DT_IDENT_ARRAY) { 13497c478bd9Sstevel@tonic-gate for (i = 0; i < inp->din_argc; i++) { 13507c478bd9Sstevel@tonic-gate pinp = inp->din_argv[i]->di_iarg; 13517c478bd9Sstevel@tonic-gate pinp->din_root = NULL; 13527c478bd9Sstevel@tonic-gate } 13537c478bd9Sstevel@tonic-gate } 13547c478bd9Sstevel@tonic-gate } 13557c478bd9Sstevel@tonic-gate 1356e5803b76SAdam H. Leventhal typedef struct dt_xlmemb { 1357e5803b76SAdam H. Leventhal dt_ident_t *dtxl_idp; /* translated ident */ 1358e5803b76SAdam H. Leventhal dt_irlist_t *dtxl_dlp; /* instruction list */ 1359e5803b76SAdam H. Leventhal dt_regset_t *dtxl_drp; /* register set */ 1360e5803b76SAdam H. Leventhal int dtxl_sreg; /* location of the translation input */ 1361e5803b76SAdam H. Leventhal int dtxl_dreg; /* location of our allocated buffer */ 1362e5803b76SAdam H. Leventhal } dt_xlmemb_t; 1363e5803b76SAdam H. Leventhal 1364e5803b76SAdam H. Leventhal /*ARGSUSED*/ 1365e5803b76SAdam H. Leventhal static int 1366e5803b76SAdam H. Leventhal dt_cg_xlate_member(const char *name, ctf_id_t type, ulong_t off, void *arg) 1367e5803b76SAdam H. Leventhal { 1368e5803b76SAdam H. Leventhal dt_xlmemb_t *dx = arg; 1369e5803b76SAdam H. Leventhal dt_ident_t *idp = dx->dtxl_idp; 1370e5803b76SAdam H. Leventhal dt_irlist_t *dlp = dx->dtxl_dlp; 1371e5803b76SAdam H. Leventhal dt_regset_t *drp = dx->dtxl_drp; 1372e5803b76SAdam H. Leventhal 1373e5803b76SAdam H. Leventhal dt_node_t *mnp; 1374e5803b76SAdam H. Leventhal dt_xlator_t *dxp; 1375e5803b76SAdam H. Leventhal 1376e5803b76SAdam H. Leventhal int reg, treg; 1377e5803b76SAdam H. Leventhal uint32_t instr; 1378e5803b76SAdam H. Leventhal size_t size; 1379e5803b76SAdam H. Leventhal 1380e5803b76SAdam H. Leventhal /* Generate code for the translation. */ 1381e5803b76SAdam H. Leventhal dxp = idp->di_data; 1382e5803b76SAdam H. Leventhal mnp = dt_xlator_member(dxp, name); 1383e5803b76SAdam H. Leventhal 1384e5803b76SAdam H. Leventhal /* If there's no translator for the given member, skip it. */ 1385e5803b76SAdam H. Leventhal if (mnp == NULL) 1386e5803b76SAdam H. Leventhal return (0); 1387e5803b76SAdam H. Leventhal 1388e5803b76SAdam H. Leventhal dxp->dx_ident->di_flags |= DT_IDFLG_CGREG; 1389e5803b76SAdam H. Leventhal dxp->dx_ident->di_id = dx->dtxl_sreg; 1390e5803b76SAdam H. Leventhal 1391e5803b76SAdam H. Leventhal dt_cg_node(mnp->dn_membexpr, dlp, drp); 1392e5803b76SAdam H. Leventhal 1393e5803b76SAdam H. Leventhal dxp->dx_ident->di_flags &= ~DT_IDFLG_CGREG; 1394e5803b76SAdam H. Leventhal dxp->dx_ident->di_id = 0; 1395e5803b76SAdam H. Leventhal 1396e5803b76SAdam H. Leventhal treg = mnp->dn_membexpr->dn_reg; 1397e5803b76SAdam H. Leventhal 1398e5803b76SAdam H. Leventhal /* Compute the offset into our buffer and store the result there. */ 1399e5803b76SAdam H. Leventhal reg = dt_regset_alloc(drp); 1400e5803b76SAdam H. Leventhal 1401e5803b76SAdam H. Leventhal dt_cg_setx(dlp, reg, off / NBBY); 1402e5803b76SAdam H. Leventhal instr = DIF_INSTR_FMT(DIF_OP_ADD, dx->dtxl_dreg, reg, reg); 1403e5803b76SAdam H. Leventhal dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr)); 1404e5803b76SAdam H. Leventhal 1405e5803b76SAdam H. Leventhal size = ctf_type_size(mnp->dn_membexpr->dn_ctfp, 1406e5803b76SAdam H. Leventhal mnp->dn_membexpr->dn_type); 1407e5803b76SAdam H. Leventhal if (dt_node_is_scalar(mnp->dn_membexpr)) { 1408e5803b76SAdam H. Leventhal /* 1409e5803b76SAdam H. Leventhal * Copying scalars is simple. 1410e5803b76SAdam H. Leventhal */ 1411e5803b76SAdam H. Leventhal switch (size) { 1412e5803b76SAdam H. Leventhal case 1: 1413e5803b76SAdam H. Leventhal instr = DIF_INSTR_STORE(DIF_OP_STB, treg, reg); 1414e5803b76SAdam H. Leventhal break; 1415e5803b76SAdam H. Leventhal case 2: 1416e5803b76SAdam H. Leventhal instr = DIF_INSTR_STORE(DIF_OP_STH, treg, reg); 1417e5803b76SAdam H. Leventhal break; 1418e5803b76SAdam H. Leventhal case 4: 1419e5803b76SAdam H. Leventhal instr = DIF_INSTR_STORE(DIF_OP_STW, treg, reg); 1420e5803b76SAdam H. Leventhal break; 1421e5803b76SAdam H. Leventhal case 8: 1422e5803b76SAdam H. Leventhal instr = DIF_INSTR_STORE(DIF_OP_STX, treg, reg); 1423e5803b76SAdam H. Leventhal break; 1424e5803b76SAdam H. Leventhal default: 1425e5803b76SAdam H. Leventhal xyerror(D_UNKNOWN, "internal error -- unexpected " 1426e5803b76SAdam H. Leventhal "size: %lu\n", (ulong_t)size); 1427e5803b76SAdam H. Leventhal } 1428e5803b76SAdam H. Leventhal 1429e5803b76SAdam H. Leventhal dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr)); 1430e5803b76SAdam H. Leventhal 1431e5803b76SAdam H. Leventhal } else if (dt_node_is_string(mnp->dn_membexpr)) { 1432e5803b76SAdam H. Leventhal int szreg; 1433e5803b76SAdam H. Leventhal 1434e5803b76SAdam H. Leventhal /* 1435e5803b76SAdam H. Leventhal * Use the copys instruction for strings. 1436e5803b76SAdam H. Leventhal */ 1437e5803b76SAdam H. Leventhal szreg = dt_regset_alloc(drp); 1438e5803b76SAdam H. Leventhal dt_cg_setx(dlp, szreg, size); 1439e5803b76SAdam H. Leventhal instr = DIF_INSTR_COPYS(treg, szreg, reg); 1440e5803b76SAdam H. Leventhal dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr)); 1441e5803b76SAdam H. Leventhal dt_regset_free(drp, szreg); 1442e5803b76SAdam H. Leventhal } else { 1443e5803b76SAdam H. Leventhal int szreg; 1444e5803b76SAdam H. Leventhal 1445e5803b76SAdam H. Leventhal /* 1446e5803b76SAdam H. Leventhal * If it's anything else then we'll just bcopy it. 1447e5803b76SAdam H. Leventhal */ 1448e5803b76SAdam H. Leventhal szreg = dt_regset_alloc(drp); 1449e5803b76SAdam H. Leventhal dt_cg_setx(dlp, szreg, size); 1450e5803b76SAdam H. Leventhal dt_irlist_append(dlp, 1451e5803b76SAdam H. Leventhal dt_cg_node_alloc(DT_LBL_NONE, DIF_INSTR_FLUSHTS)); 1452e5803b76SAdam H. Leventhal instr = DIF_INSTR_PUSHTS(DIF_OP_PUSHTV, DIF_TYPE_CTF, 1453e5803b76SAdam H. Leventhal DIF_REG_R0, treg); 1454e5803b76SAdam H. Leventhal dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr)); 1455e5803b76SAdam H. Leventhal instr = DIF_INSTR_PUSHTS(DIF_OP_PUSHTV, DIF_TYPE_CTF, 1456e5803b76SAdam H. Leventhal DIF_REG_R0, reg); 1457e5803b76SAdam H. Leventhal dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr)); 1458e5803b76SAdam H. Leventhal instr = DIF_INSTR_PUSHTS(DIF_OP_PUSHTV, DIF_TYPE_CTF, 1459e5803b76SAdam H. Leventhal DIF_REG_R0, szreg); 1460e5803b76SAdam H. Leventhal dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr)); 1461e5803b76SAdam H. Leventhal instr = DIF_INSTR_CALL(DIF_SUBR_BCOPY, szreg); 1462e5803b76SAdam H. Leventhal dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr)); 1463e5803b76SAdam H. Leventhal dt_regset_free(drp, szreg); 1464e5803b76SAdam H. Leventhal } 1465e5803b76SAdam H. Leventhal 1466e5803b76SAdam H. Leventhal dt_regset_free(drp, reg); 1467e5803b76SAdam H. Leventhal dt_regset_free(drp, treg); 1468e5803b76SAdam H. Leventhal 1469e5803b76SAdam H. Leventhal return (0); 1470e5803b76SAdam H. Leventhal } 1471e5803b76SAdam H. Leventhal 1472e5803b76SAdam H. Leventhal /* 1473e5803b76SAdam H. Leventhal * If we're expanding a translated type, we create an appropriately sized 1474e5803b76SAdam H. Leventhal * buffer with alloca() and then translate each member into it. 1475e5803b76SAdam H. Leventhal */ 1476e5803b76SAdam H. Leventhal static int 1477e5803b76SAdam H. Leventhal dt_cg_xlate_expand(dt_node_t *dnp, dt_ident_t *idp, dt_irlist_t *dlp, 1478e5803b76SAdam H. Leventhal dt_regset_t *drp) 1479e5803b76SAdam H. Leventhal { 1480e5803b76SAdam H. Leventhal dt_xlmemb_t dlm; 1481e5803b76SAdam H. Leventhal uint32_t instr; 1482e5803b76SAdam H. Leventhal int dreg; 1483e5803b76SAdam H. Leventhal size_t size; 1484e5803b76SAdam H. Leventhal 1485e5803b76SAdam H. Leventhal dreg = dt_regset_alloc(drp); 1486e5803b76SAdam H. Leventhal size = ctf_type_size(dnp->dn_ident->di_ctfp, dnp->dn_ident->di_type); 1487e5803b76SAdam H. Leventhal 1488e5803b76SAdam H. Leventhal /* Call alloca() to create the buffer. */ 1489e5803b76SAdam H. Leventhal dt_cg_setx(dlp, dreg, size); 1490e5803b76SAdam H. Leventhal 1491e5803b76SAdam H. Leventhal dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, DIF_INSTR_FLUSHTS)); 1492e5803b76SAdam H. Leventhal 1493e5803b76SAdam H. Leventhal instr = DIF_INSTR_PUSHTS(DIF_OP_PUSHTV, DIF_TYPE_CTF, DIF_REG_R0, dreg); 1494e5803b76SAdam H. Leventhal dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr)); 1495e5803b76SAdam H. Leventhal 1496e5803b76SAdam H. Leventhal instr = DIF_INSTR_CALL(DIF_SUBR_ALLOCA, dreg); 1497e5803b76SAdam H. Leventhal dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr)); 1498e5803b76SAdam H. Leventhal 1499e5803b76SAdam H. Leventhal /* Generate the translation for each member. */ 1500e5803b76SAdam H. Leventhal dlm.dtxl_idp = idp; 1501e5803b76SAdam H. Leventhal dlm.dtxl_dlp = dlp; 1502e5803b76SAdam H. Leventhal dlm.dtxl_drp = drp; 1503e5803b76SAdam H. Leventhal dlm.dtxl_sreg = dnp->dn_reg; 1504e5803b76SAdam H. Leventhal dlm.dtxl_dreg = dreg; 1505e5803b76SAdam H. Leventhal (void) ctf_member_iter(dnp->dn_ident->di_ctfp, 1506e5803b76SAdam H. Leventhal dnp->dn_ident->di_type, dt_cg_xlate_member, 1507e5803b76SAdam H. Leventhal &dlm); 1508e5803b76SAdam H. Leventhal 1509e5803b76SAdam H. Leventhal return (dreg); 1510e5803b76SAdam H. Leventhal } 1511e5803b76SAdam H. Leventhal 15127c478bd9Sstevel@tonic-gate static void 15137c478bd9Sstevel@tonic-gate dt_cg_node(dt_node_t *dnp, dt_irlist_t *dlp, dt_regset_t *drp) 15147c478bd9Sstevel@tonic-gate { 15157c478bd9Sstevel@tonic-gate ctf_file_t *ctfp = dnp->dn_ctfp; 15167c478bd9Sstevel@tonic-gate ctf_file_t *octfp; 15177c478bd9Sstevel@tonic-gate ctf_membinfo_t m; 15187c478bd9Sstevel@tonic-gate ctf_id_t type; 15197c478bd9Sstevel@tonic-gate 15207c478bd9Sstevel@tonic-gate dif_instr_t instr; 15217c478bd9Sstevel@tonic-gate dt_ident_t *idp; 15227c478bd9Sstevel@tonic-gate ssize_t stroff; 15237c478bd9Sstevel@tonic-gate uint_t op; 15247c478bd9Sstevel@tonic-gate 15257c478bd9Sstevel@tonic-gate switch (dnp->dn_op) { 15267c478bd9Sstevel@tonic-gate case DT_TOK_COMMA: 15277c478bd9Sstevel@tonic-gate dt_cg_node(dnp->dn_left, dlp, drp); 15287c478bd9Sstevel@tonic-gate dt_regset_free(drp, dnp->dn_left->dn_reg); 15297c478bd9Sstevel@tonic-gate dt_cg_node(dnp->dn_right, dlp, drp); 15307c478bd9Sstevel@tonic-gate dnp->dn_reg = dnp->dn_right->dn_reg; 15317c478bd9Sstevel@tonic-gate break; 15327c478bd9Sstevel@tonic-gate 15337c478bd9Sstevel@tonic-gate case DT_TOK_ASGN: 15347c478bd9Sstevel@tonic-gate dt_cg_node(dnp->dn_right, dlp, drp); 15357c478bd9Sstevel@tonic-gate dnp->dn_reg = dnp->dn_right->dn_reg; 15367c478bd9Sstevel@tonic-gate dt_cg_asgn_op(dnp, dlp, drp); 15377c478bd9Sstevel@tonic-gate break; 15387c478bd9Sstevel@tonic-gate 15397c478bd9Sstevel@tonic-gate case DT_TOK_ADD_EQ: 15407c478bd9Sstevel@tonic-gate dt_cg_arithmetic_op(dnp, dlp, drp, DIF_OP_ADD); 15417c478bd9Sstevel@tonic-gate dt_cg_asgn_op(dnp, dlp, drp); 15427c478bd9Sstevel@tonic-gate break; 15437c478bd9Sstevel@tonic-gate 15447c478bd9Sstevel@tonic-gate case DT_TOK_SUB_EQ: 15457c478bd9Sstevel@tonic-gate dt_cg_arithmetic_op(dnp, dlp, drp, DIF_OP_SUB); 15467c478bd9Sstevel@tonic-gate dt_cg_asgn_op(dnp, dlp, drp); 15477c478bd9Sstevel@tonic-gate break; 15487c478bd9Sstevel@tonic-gate 15497c478bd9Sstevel@tonic-gate case DT_TOK_MUL_EQ: 15507c478bd9Sstevel@tonic-gate dt_cg_arithmetic_op(dnp, dlp, drp, DIF_OP_MUL); 15517c478bd9Sstevel@tonic-gate dt_cg_asgn_op(dnp, dlp, drp); 15527c478bd9Sstevel@tonic-gate break; 15537c478bd9Sstevel@tonic-gate 15547c478bd9Sstevel@tonic-gate case DT_TOK_DIV_EQ: 15557c478bd9Sstevel@tonic-gate dt_cg_arithmetic_op(dnp, dlp, drp, 15567c478bd9Sstevel@tonic-gate (dnp->dn_flags & DT_NF_SIGNED) ? DIF_OP_SDIV : DIF_OP_UDIV); 15577c478bd9Sstevel@tonic-gate dt_cg_asgn_op(dnp, dlp, drp); 15587c478bd9Sstevel@tonic-gate break; 15597c478bd9Sstevel@tonic-gate 15607c478bd9Sstevel@tonic-gate case DT_TOK_MOD_EQ: 15617c478bd9Sstevel@tonic-gate dt_cg_arithmetic_op(dnp, dlp, drp, 15627c478bd9Sstevel@tonic-gate (dnp->dn_flags & DT_NF_SIGNED) ? DIF_OP_SREM : DIF_OP_UREM); 15637c478bd9Sstevel@tonic-gate dt_cg_asgn_op(dnp, dlp, drp); 15647c478bd9Sstevel@tonic-gate break; 15657c478bd9Sstevel@tonic-gate 15667c478bd9Sstevel@tonic-gate case DT_TOK_AND_EQ: 15677c478bd9Sstevel@tonic-gate dt_cg_arithmetic_op(dnp, dlp, drp, DIF_OP_AND); 15687c478bd9Sstevel@tonic-gate dt_cg_asgn_op(dnp, dlp, drp); 15697c478bd9Sstevel@tonic-gate break; 15707c478bd9Sstevel@tonic-gate 15717c478bd9Sstevel@tonic-gate case DT_TOK_XOR_EQ: 15727c478bd9Sstevel@tonic-gate dt_cg_arithmetic_op(dnp, dlp, drp, DIF_OP_XOR); 15737c478bd9Sstevel@tonic-gate dt_cg_asgn_op(dnp, dlp, drp); 15747c478bd9Sstevel@tonic-gate break; 15757c478bd9Sstevel@tonic-gate 15767c478bd9Sstevel@tonic-gate case DT_TOK_OR_EQ: 15777c478bd9Sstevel@tonic-gate dt_cg_arithmetic_op(dnp, dlp, drp, DIF_OP_OR); 15787c478bd9Sstevel@tonic-gate dt_cg_asgn_op(dnp, dlp, drp); 15797c478bd9Sstevel@tonic-gate break; 15807c478bd9Sstevel@tonic-gate 15817c478bd9Sstevel@tonic-gate case DT_TOK_LSH_EQ: 15827c478bd9Sstevel@tonic-gate dt_cg_arithmetic_op(dnp, dlp, drp, DIF_OP_SLL); 15837c478bd9Sstevel@tonic-gate dt_cg_asgn_op(dnp, dlp, drp); 15847c478bd9Sstevel@tonic-gate break; 15857c478bd9Sstevel@tonic-gate 15867c478bd9Sstevel@tonic-gate case DT_TOK_RSH_EQ: 15877c478bd9Sstevel@tonic-gate dt_cg_arithmetic_op(dnp, dlp, drp, 15887c478bd9Sstevel@tonic-gate (dnp->dn_flags & DT_NF_SIGNED) ? DIF_OP_SRA : DIF_OP_SRL); 15897c478bd9Sstevel@tonic-gate dt_cg_asgn_op(dnp, dlp, drp); 15907c478bd9Sstevel@tonic-gate break; 15917c478bd9Sstevel@tonic-gate 15927c478bd9Sstevel@tonic-gate case DT_TOK_QUESTION: 15937c478bd9Sstevel@tonic-gate dt_cg_ternary_op(dnp, dlp, drp); 15947c478bd9Sstevel@tonic-gate break; 15957c478bd9Sstevel@tonic-gate 15967c478bd9Sstevel@tonic-gate case DT_TOK_LOR: 15977c478bd9Sstevel@tonic-gate dt_cg_logical_or(dnp, dlp, drp); 15987c478bd9Sstevel@tonic-gate break; 15997c478bd9Sstevel@tonic-gate 16007c478bd9Sstevel@tonic-gate case DT_TOK_LXOR: 16017c478bd9Sstevel@tonic-gate dt_cg_logical_xor(dnp, dlp, drp); 16027c478bd9Sstevel@tonic-gate break; 16037c478bd9Sstevel@tonic-gate 16047c478bd9Sstevel@tonic-gate case DT_TOK_LAND: 16057c478bd9Sstevel@tonic-gate dt_cg_logical_and(dnp, dlp, drp); 16067c478bd9Sstevel@tonic-gate break; 16077c478bd9Sstevel@tonic-gate 16087c478bd9Sstevel@tonic-gate case DT_TOK_BOR: 16097c478bd9Sstevel@tonic-gate dt_cg_arithmetic_op(dnp, dlp, drp, DIF_OP_OR); 16107c478bd9Sstevel@tonic-gate break; 16117c478bd9Sstevel@tonic-gate 16127c478bd9Sstevel@tonic-gate case DT_TOK_XOR: 16137c478bd9Sstevel@tonic-gate dt_cg_arithmetic_op(dnp, dlp, drp, DIF_OP_XOR); 16147c478bd9Sstevel@tonic-gate break; 16157c478bd9Sstevel@tonic-gate 16167c478bd9Sstevel@tonic-gate case DT_TOK_BAND: 16177c478bd9Sstevel@tonic-gate dt_cg_arithmetic_op(dnp, dlp, drp, DIF_OP_AND); 16187c478bd9Sstevel@tonic-gate break; 16197c478bd9Sstevel@tonic-gate 16207c478bd9Sstevel@tonic-gate case DT_TOK_EQU: 16217c478bd9Sstevel@tonic-gate dt_cg_compare_op(dnp, dlp, drp, DIF_OP_BE); 16227c478bd9Sstevel@tonic-gate break; 16237c478bd9Sstevel@tonic-gate 16247c478bd9Sstevel@tonic-gate case DT_TOK_NEQ: 16257c478bd9Sstevel@tonic-gate dt_cg_compare_op(dnp, dlp, drp, DIF_OP_BNE); 16267c478bd9Sstevel@tonic-gate break; 16277c478bd9Sstevel@tonic-gate 16287c478bd9Sstevel@tonic-gate case DT_TOK_LT: 16297c478bd9Sstevel@tonic-gate dt_cg_compare_op(dnp, dlp, drp, 16307c478bd9Sstevel@tonic-gate dt_cg_compare_signed(dnp) ? DIF_OP_BL : DIF_OP_BLU); 16317c478bd9Sstevel@tonic-gate break; 16327c478bd9Sstevel@tonic-gate 16337c478bd9Sstevel@tonic-gate case DT_TOK_LE: 16347c478bd9Sstevel@tonic-gate dt_cg_compare_op(dnp, dlp, drp, 16357c478bd9Sstevel@tonic-gate dt_cg_compare_signed(dnp) ? DIF_OP_BLE : DIF_OP_BLEU); 16367c478bd9Sstevel@tonic-gate break; 16377c478bd9Sstevel@tonic-gate 16387c478bd9Sstevel@tonic-gate case DT_TOK_GT: 16397c478bd9Sstevel@tonic-gate dt_cg_compare_op(dnp, dlp, drp, 16407c478bd9Sstevel@tonic-gate dt_cg_compare_signed(dnp) ? DIF_OP_BG : DIF_OP_BGU); 16417c478bd9Sstevel@tonic-gate break; 16427c478bd9Sstevel@tonic-gate 16437c478bd9Sstevel@tonic-gate case DT_TOK_GE: 16447c478bd9Sstevel@tonic-gate dt_cg_compare_op(dnp, dlp, drp, 16457c478bd9Sstevel@tonic-gate dt_cg_compare_signed(dnp) ? DIF_OP_BGE : DIF_OP_BGEU); 16467c478bd9Sstevel@tonic-gate break; 16477c478bd9Sstevel@tonic-gate 16487c478bd9Sstevel@tonic-gate case DT_TOK_LSH: 16497c478bd9Sstevel@tonic-gate dt_cg_arithmetic_op(dnp, dlp, drp, DIF_OP_SLL); 16507c478bd9Sstevel@tonic-gate break; 16517c478bd9Sstevel@tonic-gate 16527c478bd9Sstevel@tonic-gate case DT_TOK_RSH: 16537c478bd9Sstevel@tonic-gate dt_cg_arithmetic_op(dnp, dlp, drp, 16547c478bd9Sstevel@tonic-gate (dnp->dn_flags & DT_NF_SIGNED) ? DIF_OP_SRA : DIF_OP_SRL); 16557c478bd9Sstevel@tonic-gate break; 16567c478bd9Sstevel@tonic-gate 16577c478bd9Sstevel@tonic-gate case DT_TOK_ADD: 16587c478bd9Sstevel@tonic-gate dt_cg_arithmetic_op(dnp, dlp, drp, DIF_OP_ADD); 16597c478bd9Sstevel@tonic-gate break; 16607c478bd9Sstevel@tonic-gate 16617c478bd9Sstevel@tonic-gate case DT_TOK_SUB: 16627c478bd9Sstevel@tonic-gate dt_cg_arithmetic_op(dnp, dlp, drp, DIF_OP_SUB); 16637c478bd9Sstevel@tonic-gate break; 16647c478bd9Sstevel@tonic-gate 16657c478bd9Sstevel@tonic-gate case DT_TOK_MUL: 16667c478bd9Sstevel@tonic-gate dt_cg_arithmetic_op(dnp, dlp, drp, DIF_OP_MUL); 16677c478bd9Sstevel@tonic-gate break; 16687c478bd9Sstevel@tonic-gate 16697c478bd9Sstevel@tonic-gate case DT_TOK_DIV: 16707c478bd9Sstevel@tonic-gate dt_cg_arithmetic_op(dnp, dlp, drp, 16717c478bd9Sstevel@tonic-gate (dnp->dn_flags & DT_NF_SIGNED) ? DIF_OP_SDIV : DIF_OP_UDIV); 16727c478bd9Sstevel@tonic-gate break; 16737c478bd9Sstevel@tonic-gate 16747c478bd9Sstevel@tonic-gate case DT_TOK_MOD: 16757c478bd9Sstevel@tonic-gate dt_cg_arithmetic_op(dnp, dlp, drp, 16767c478bd9Sstevel@tonic-gate (dnp->dn_flags & DT_NF_SIGNED) ? DIF_OP_SREM : DIF_OP_UREM); 16777c478bd9Sstevel@tonic-gate break; 16787c478bd9Sstevel@tonic-gate 16797c478bd9Sstevel@tonic-gate case DT_TOK_LNEG: 16807c478bd9Sstevel@tonic-gate dt_cg_logical_neg(dnp, dlp, drp); 16817c478bd9Sstevel@tonic-gate break; 16827c478bd9Sstevel@tonic-gate 16837c478bd9Sstevel@tonic-gate case DT_TOK_BNEG: 16847c478bd9Sstevel@tonic-gate dt_cg_node(dnp->dn_child, dlp, drp); 16857c478bd9Sstevel@tonic-gate dnp->dn_reg = dnp->dn_child->dn_reg; 16867c478bd9Sstevel@tonic-gate instr = DIF_INSTR_NOT(dnp->dn_reg, dnp->dn_reg); 16877c478bd9Sstevel@tonic-gate dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr)); 16887c478bd9Sstevel@tonic-gate break; 16897c478bd9Sstevel@tonic-gate 16907c478bd9Sstevel@tonic-gate case DT_TOK_PREINC: 16917c478bd9Sstevel@tonic-gate dt_cg_prearith_op(dnp, dlp, drp, DIF_OP_ADD); 16927c478bd9Sstevel@tonic-gate break; 16937c478bd9Sstevel@tonic-gate 16947c478bd9Sstevel@tonic-gate case DT_TOK_POSTINC: 16957c478bd9Sstevel@tonic-gate dt_cg_postarith_op(dnp, dlp, drp, DIF_OP_ADD); 16967c478bd9Sstevel@tonic-gate break; 16977c478bd9Sstevel@tonic-gate 16987c478bd9Sstevel@tonic-gate case DT_TOK_PREDEC: 16997c478bd9Sstevel@tonic-gate dt_cg_prearith_op(dnp, dlp, drp, DIF_OP_SUB); 17007c478bd9Sstevel@tonic-gate break; 17017c478bd9Sstevel@tonic-gate 17027c478bd9Sstevel@tonic-gate case DT_TOK_POSTDEC: 17037c478bd9Sstevel@tonic-gate dt_cg_postarith_op(dnp, dlp, drp, DIF_OP_SUB); 17047c478bd9Sstevel@tonic-gate break; 17057c478bd9Sstevel@tonic-gate 17067c478bd9Sstevel@tonic-gate case DT_TOK_IPOS: 17077c478bd9Sstevel@tonic-gate dt_cg_node(dnp->dn_child, dlp, drp); 17087c478bd9Sstevel@tonic-gate dnp->dn_reg = dnp->dn_child->dn_reg; 17097c478bd9Sstevel@tonic-gate break; 17107c478bd9Sstevel@tonic-gate 17117c478bd9Sstevel@tonic-gate case DT_TOK_INEG: 17127c478bd9Sstevel@tonic-gate dt_cg_node(dnp->dn_child, dlp, drp); 17137c478bd9Sstevel@tonic-gate dnp->dn_reg = dnp->dn_child->dn_reg; 17147c478bd9Sstevel@tonic-gate 17157c478bd9Sstevel@tonic-gate instr = DIF_INSTR_FMT(DIF_OP_SUB, DIF_REG_R0, 17167c478bd9Sstevel@tonic-gate dnp->dn_reg, dnp->dn_reg); 17177c478bd9Sstevel@tonic-gate 17187c478bd9Sstevel@tonic-gate dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr)); 17197c478bd9Sstevel@tonic-gate break; 17207c478bd9Sstevel@tonic-gate 17217c478bd9Sstevel@tonic-gate case DT_TOK_DEREF: 17227c478bd9Sstevel@tonic-gate dt_cg_node(dnp->dn_child, dlp, drp); 17237c478bd9Sstevel@tonic-gate dnp->dn_reg = dnp->dn_child->dn_reg; 17247c478bd9Sstevel@tonic-gate 1725e5803b76SAdam H. Leventhal if (dt_node_is_dynamic(dnp->dn_child)) { 1726e5803b76SAdam H. Leventhal int reg; 1727e5803b76SAdam H. Leventhal idp = dt_node_resolve(dnp->dn_child, DT_IDENT_XLPTR); 1728e5803b76SAdam H. Leventhal assert(idp != NULL); 1729e5803b76SAdam H. Leventhal reg = dt_cg_xlate_expand(dnp, idp, dlp, drp); 1730e5803b76SAdam H. Leventhal 1731e5803b76SAdam H. Leventhal dt_regset_free(drp, dnp->dn_child->dn_reg); 1732e5803b76SAdam H. Leventhal dnp->dn_reg = reg; 1733e5803b76SAdam H. Leventhal 1734e5803b76SAdam H. Leventhal } else if (!(dnp->dn_flags & DT_NF_REF)) { 17357c478bd9Sstevel@tonic-gate uint_t ubit = dnp->dn_flags & DT_NF_USERLAND; 17367c478bd9Sstevel@tonic-gate 17377c478bd9Sstevel@tonic-gate /* 17387c478bd9Sstevel@tonic-gate * Save and restore DT_NF_USERLAND across dt_cg_load(): 17397c478bd9Sstevel@tonic-gate * we need the sign bit from dnp and the user bit from 17407c478bd9Sstevel@tonic-gate * dnp->dn_child in order to get the proper opcode. 17417c478bd9Sstevel@tonic-gate */ 17427c478bd9Sstevel@tonic-gate dnp->dn_flags |= 17437c478bd9Sstevel@tonic-gate (dnp->dn_child->dn_flags & DT_NF_USERLAND); 17447c478bd9Sstevel@tonic-gate 17457c478bd9Sstevel@tonic-gate instr = DIF_INSTR_LOAD(dt_cg_load(dnp, ctfp, 17467c478bd9Sstevel@tonic-gate dnp->dn_type), dnp->dn_reg, dnp->dn_reg); 17477c478bd9Sstevel@tonic-gate 17487c478bd9Sstevel@tonic-gate dnp->dn_flags &= ~DT_NF_USERLAND; 17497c478bd9Sstevel@tonic-gate dnp->dn_flags |= ubit; 17507c478bd9Sstevel@tonic-gate 17517c478bd9Sstevel@tonic-gate dt_irlist_append(dlp, 17527c478bd9Sstevel@tonic-gate dt_cg_node_alloc(DT_LBL_NONE, instr)); 17537c478bd9Sstevel@tonic-gate } 17547c478bd9Sstevel@tonic-gate break; 17557c478bd9Sstevel@tonic-gate 17567c478bd9Sstevel@tonic-gate case DT_TOK_ADDROF: { 17577c478bd9Sstevel@tonic-gate uint_t rbit = dnp->dn_child->dn_flags & DT_NF_REF; 17587c478bd9Sstevel@tonic-gate 17597c478bd9Sstevel@tonic-gate dnp->dn_child->dn_flags |= DT_NF_REF; /* force pass-by-ref */ 17607c478bd9Sstevel@tonic-gate dt_cg_node(dnp->dn_child, dlp, drp); 17617c478bd9Sstevel@tonic-gate dnp->dn_reg = dnp->dn_child->dn_reg; 17627c478bd9Sstevel@tonic-gate 17637c478bd9Sstevel@tonic-gate dnp->dn_child->dn_flags &= ~DT_NF_REF; 17647c478bd9Sstevel@tonic-gate dnp->dn_child->dn_flags |= rbit; 17657c478bd9Sstevel@tonic-gate break; 17667c478bd9Sstevel@tonic-gate } 17677c478bd9Sstevel@tonic-gate 17687c478bd9Sstevel@tonic-gate case DT_TOK_SIZEOF: { 17697c478bd9Sstevel@tonic-gate size_t size = dt_node_sizeof(dnp->dn_child); 1770e5803b76SAdam H. Leventhal dnp->dn_reg = dt_regset_alloc(drp); 17717c478bd9Sstevel@tonic-gate assert(size != 0); 17727c478bd9Sstevel@tonic-gate dt_cg_setx(dlp, dnp->dn_reg, size); 17737c478bd9Sstevel@tonic-gate break; 17747c478bd9Sstevel@tonic-gate } 17757c478bd9Sstevel@tonic-gate 17767c478bd9Sstevel@tonic-gate case DT_TOK_STRINGOF: 17777c478bd9Sstevel@tonic-gate dt_cg_node(dnp->dn_child, dlp, drp); 17787c478bd9Sstevel@tonic-gate dnp->dn_reg = dnp->dn_child->dn_reg; 17797c478bd9Sstevel@tonic-gate break; 17807c478bd9Sstevel@tonic-gate 17817c478bd9Sstevel@tonic-gate case DT_TOK_XLATE: 17821a7c1b72Smws /* 17831a7c1b72Smws * An xlate operator appears in either an XLATOR, indicating a 17841a7c1b72Smws * reference to a dynamic translator, or an OP2, indicating 17851a7c1b72Smws * use of the xlate operator in the user's program. For the 17861a7c1b72Smws * dynamic case, generate an xlate opcode with a reference to 17871a7c1b72Smws * the corresponding member, pre-computed for us in dn_members. 17881a7c1b72Smws */ 17891a7c1b72Smws if (dnp->dn_kind == DT_NODE_XLATOR) { 17901a7c1b72Smws dt_xlator_t *dxp = dnp->dn_xlator; 17911a7c1b72Smws 17921a7c1b72Smws assert(dxp->dx_ident->di_flags & DT_IDFLG_CGREG); 17931a7c1b72Smws assert(dxp->dx_ident->di_id != 0); 17941a7c1b72Smws 1795e5803b76SAdam H. Leventhal dnp->dn_reg = dt_regset_alloc(drp); 17961a7c1b72Smws 17971a7c1b72Smws if (dxp->dx_arg == -1) { 17981a7c1b72Smws instr = DIF_INSTR_MOV( 17991a7c1b72Smws dxp->dx_ident->di_id, dnp->dn_reg); 18001a7c1b72Smws dt_irlist_append(dlp, 18011a7c1b72Smws dt_cg_node_alloc(DT_LBL_NONE, instr)); 18021a7c1b72Smws op = DIF_OP_XLATE; 18031a7c1b72Smws } else 18041a7c1b72Smws op = DIF_OP_XLARG; 18051a7c1b72Smws 18061a7c1b72Smws instr = DIF_INSTR_XLATE(op, 0, dnp->dn_reg); 18071a7c1b72Smws dt_irlist_append(dlp, 18081a7c1b72Smws dt_cg_node_alloc(DT_LBL_NONE, instr)); 18091a7c1b72Smws 18101a7c1b72Smws dlp->dl_last->di_extern = dnp->dn_xmember; 18111a7c1b72Smws break; 18121a7c1b72Smws } 18131a7c1b72Smws 18141a7c1b72Smws assert(dnp->dn_kind == DT_NODE_OP2); 18157c478bd9Sstevel@tonic-gate dt_cg_node(dnp->dn_right, dlp, drp); 18167c478bd9Sstevel@tonic-gate dnp->dn_reg = dnp->dn_right->dn_reg; 18177c478bd9Sstevel@tonic-gate break; 18187c478bd9Sstevel@tonic-gate 18197c478bd9Sstevel@tonic-gate case DT_TOK_LPAR: 18207c478bd9Sstevel@tonic-gate dt_cg_node(dnp->dn_right, dlp, drp); 18217c478bd9Sstevel@tonic-gate dnp->dn_reg = dnp->dn_right->dn_reg; 18227c478bd9Sstevel@tonic-gate dt_cg_typecast(dnp->dn_right, dnp, dlp, drp); 18237c478bd9Sstevel@tonic-gate break; 18247c478bd9Sstevel@tonic-gate 18257c478bd9Sstevel@tonic-gate case DT_TOK_PTR: 18267c478bd9Sstevel@tonic-gate case DT_TOK_DOT: 18277c478bd9Sstevel@tonic-gate assert(dnp->dn_right->dn_kind == DT_NODE_IDENT); 18287c478bd9Sstevel@tonic-gate dt_cg_node(dnp->dn_left, dlp, drp); 18297c478bd9Sstevel@tonic-gate 18307c478bd9Sstevel@tonic-gate /* 18317c478bd9Sstevel@tonic-gate * If the left-hand side of PTR or DOT is a dynamic variable, 18327c478bd9Sstevel@tonic-gate * we expect it to be the output of a D translator. In this 18337c478bd9Sstevel@tonic-gate * case, we look up the parse tree corresponding to the member 18347c478bd9Sstevel@tonic-gate * that is being accessed and run the code generator over it. 18357c478bd9Sstevel@tonic-gate * We then cast the result as if by the assignment operator. 18367c478bd9Sstevel@tonic-gate */ 18377c478bd9Sstevel@tonic-gate if ((idp = dt_node_resolve( 18387c478bd9Sstevel@tonic-gate dnp->dn_left, DT_IDENT_XLSOU)) != NULL || 18397c478bd9Sstevel@tonic-gate (idp = dt_node_resolve( 18407c478bd9Sstevel@tonic-gate dnp->dn_left, DT_IDENT_XLPTR)) != NULL) { 18417c478bd9Sstevel@tonic-gate 18427c478bd9Sstevel@tonic-gate dt_xlator_t *dxp; 18437c478bd9Sstevel@tonic-gate dt_node_t *mnp; 18447c478bd9Sstevel@tonic-gate 18457c478bd9Sstevel@tonic-gate dxp = idp->di_data; 18467c478bd9Sstevel@tonic-gate mnp = dt_xlator_member(dxp, dnp->dn_right->dn_string); 18477c478bd9Sstevel@tonic-gate assert(mnp != NULL); 18487c478bd9Sstevel@tonic-gate 18497c478bd9Sstevel@tonic-gate dxp->dx_ident->di_flags |= DT_IDFLG_CGREG; 18507c478bd9Sstevel@tonic-gate dxp->dx_ident->di_id = dnp->dn_left->dn_reg; 18517c478bd9Sstevel@tonic-gate 18527c478bd9Sstevel@tonic-gate dt_cg_node(mnp->dn_membexpr, dlp, drp); 18537c478bd9Sstevel@tonic-gate dnp->dn_reg = mnp->dn_membexpr->dn_reg; 18547c478bd9Sstevel@tonic-gate dt_cg_typecast(mnp->dn_membexpr, dnp, dlp, drp); 18557c478bd9Sstevel@tonic-gate 18567c478bd9Sstevel@tonic-gate dxp->dx_ident->di_flags &= ~DT_IDFLG_CGREG; 18577c478bd9Sstevel@tonic-gate dxp->dx_ident->di_id = 0; 18587c478bd9Sstevel@tonic-gate 18591a7c1b72Smws if (dnp->dn_left->dn_reg != -1) 18607c478bd9Sstevel@tonic-gate dt_regset_free(drp, dnp->dn_left->dn_reg); 18617c478bd9Sstevel@tonic-gate break; 18627c478bd9Sstevel@tonic-gate } 18637c478bd9Sstevel@tonic-gate 18647c478bd9Sstevel@tonic-gate ctfp = dnp->dn_left->dn_ctfp; 18657c478bd9Sstevel@tonic-gate type = ctf_type_resolve(ctfp, dnp->dn_left->dn_type); 18667c478bd9Sstevel@tonic-gate 18677c478bd9Sstevel@tonic-gate if (dnp->dn_op == DT_TOK_PTR) { 18687c478bd9Sstevel@tonic-gate type = ctf_type_reference(ctfp, type); 18697c478bd9Sstevel@tonic-gate type = ctf_type_resolve(ctfp, type); 18707c478bd9Sstevel@tonic-gate } 18717c478bd9Sstevel@tonic-gate 18727c478bd9Sstevel@tonic-gate if ((ctfp = dt_cg_membinfo(octfp = ctfp, type, 18737c478bd9Sstevel@tonic-gate dnp->dn_right->dn_string, &m)) == NULL) { 18747c478bd9Sstevel@tonic-gate yypcb->pcb_hdl->dt_ctferr = ctf_errno(octfp); 18757c478bd9Sstevel@tonic-gate longjmp(yypcb->pcb_jmpbuf, EDT_CTF); 18767c478bd9Sstevel@tonic-gate } 18777c478bd9Sstevel@tonic-gate 18787c478bd9Sstevel@tonic-gate if (m.ctm_offset != 0) { 1879e5803b76SAdam H. Leventhal int reg; 1880e5803b76SAdam H. Leventhal 1881e5803b76SAdam H. Leventhal reg = dt_regset_alloc(drp); 18827c478bd9Sstevel@tonic-gate 18837c478bd9Sstevel@tonic-gate /* 18847c478bd9Sstevel@tonic-gate * If the offset is not aligned on a byte boundary, it 18857c478bd9Sstevel@tonic-gate * is a bit-field member and we will extract the value 18867c478bd9Sstevel@tonic-gate * bits below after we generate the appropriate load. 18877c478bd9Sstevel@tonic-gate */ 18887c478bd9Sstevel@tonic-gate dt_cg_setx(dlp, reg, m.ctm_offset / NBBY); 18897c478bd9Sstevel@tonic-gate 18907c478bd9Sstevel@tonic-gate instr = DIF_INSTR_FMT(DIF_OP_ADD, 18917c478bd9Sstevel@tonic-gate dnp->dn_left->dn_reg, reg, dnp->dn_left->dn_reg); 18927c478bd9Sstevel@tonic-gate 18937c478bd9Sstevel@tonic-gate dt_irlist_append(dlp, 18947c478bd9Sstevel@tonic-gate dt_cg_node_alloc(DT_LBL_NONE, instr)); 18957c478bd9Sstevel@tonic-gate dt_regset_free(drp, reg); 18967c478bd9Sstevel@tonic-gate } 18977c478bd9Sstevel@tonic-gate 18987c478bd9Sstevel@tonic-gate if (!(dnp->dn_flags & DT_NF_REF)) { 18997c478bd9Sstevel@tonic-gate uint_t ubit = dnp->dn_flags & DT_NF_USERLAND; 19007c478bd9Sstevel@tonic-gate 19017c478bd9Sstevel@tonic-gate /* 19027c478bd9Sstevel@tonic-gate * Save and restore DT_NF_USERLAND across dt_cg_load(): 19037c478bd9Sstevel@tonic-gate * we need the sign bit from dnp and the user bit from 19047c478bd9Sstevel@tonic-gate * dnp->dn_left in order to get the proper opcode. 19057c478bd9Sstevel@tonic-gate */ 19067c478bd9Sstevel@tonic-gate dnp->dn_flags |= 19077c478bd9Sstevel@tonic-gate (dnp->dn_left->dn_flags & DT_NF_USERLAND); 19087c478bd9Sstevel@tonic-gate 19097c478bd9Sstevel@tonic-gate instr = DIF_INSTR_LOAD(dt_cg_load(dnp, 19107c478bd9Sstevel@tonic-gate ctfp, m.ctm_type), dnp->dn_left->dn_reg, 19117c478bd9Sstevel@tonic-gate dnp->dn_left->dn_reg); 19127c478bd9Sstevel@tonic-gate 19137c478bd9Sstevel@tonic-gate dnp->dn_flags &= ~DT_NF_USERLAND; 19147c478bd9Sstevel@tonic-gate dnp->dn_flags |= ubit; 19157c478bd9Sstevel@tonic-gate 19167c478bd9Sstevel@tonic-gate dt_irlist_append(dlp, 19177c478bd9Sstevel@tonic-gate dt_cg_node_alloc(DT_LBL_NONE, instr)); 19187c478bd9Sstevel@tonic-gate 19197c478bd9Sstevel@tonic-gate if (dnp->dn_flags & DT_NF_BITFIELD) 19207c478bd9Sstevel@tonic-gate dt_cg_field_get(dnp, dlp, drp, ctfp, &m); 19217c478bd9Sstevel@tonic-gate } 19227c478bd9Sstevel@tonic-gate 19237c478bd9Sstevel@tonic-gate dnp->dn_reg = dnp->dn_left->dn_reg; 19247c478bd9Sstevel@tonic-gate break; 19257c478bd9Sstevel@tonic-gate 19267c478bd9Sstevel@tonic-gate case DT_TOK_STRING: 1927e5803b76SAdam H. Leventhal dnp->dn_reg = dt_regset_alloc(drp); 19287c478bd9Sstevel@tonic-gate 19297c478bd9Sstevel@tonic-gate assert(dnp->dn_kind == DT_NODE_STRING); 19307c478bd9Sstevel@tonic-gate stroff = dt_strtab_insert(yypcb->pcb_strtab, dnp->dn_string); 19317c478bd9Sstevel@tonic-gate 19327c478bd9Sstevel@tonic-gate if (stroff == -1L) 19337c478bd9Sstevel@tonic-gate longjmp(yypcb->pcb_jmpbuf, EDT_NOMEM); 19347c478bd9Sstevel@tonic-gate if (stroff > DIF_STROFF_MAX) 19357c478bd9Sstevel@tonic-gate longjmp(yypcb->pcb_jmpbuf, EDT_STR2BIG); 19367c478bd9Sstevel@tonic-gate 19377c478bd9Sstevel@tonic-gate instr = DIF_INSTR_SETS((ulong_t)stroff, dnp->dn_reg); 19387c478bd9Sstevel@tonic-gate dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr)); 19397c478bd9Sstevel@tonic-gate break; 19407c478bd9Sstevel@tonic-gate 19417c478bd9Sstevel@tonic-gate case DT_TOK_IDENT: 19427c478bd9Sstevel@tonic-gate /* 19437c478bd9Sstevel@tonic-gate * If the specified identifier is a variable on which we have 19447c478bd9Sstevel@tonic-gate * set the code generator register flag, then this variable 19457c478bd9Sstevel@tonic-gate * has already had code generated for it and saved in di_id. 19467c478bd9Sstevel@tonic-gate * Allocate a new register and copy the existing value to it. 19477c478bd9Sstevel@tonic-gate */ 19487c478bd9Sstevel@tonic-gate if (dnp->dn_kind == DT_NODE_VAR && 19497c478bd9Sstevel@tonic-gate (dnp->dn_ident->di_flags & DT_IDFLG_CGREG)) { 1950e5803b76SAdam H. Leventhal dnp->dn_reg = dt_regset_alloc(drp); 19517c478bd9Sstevel@tonic-gate instr = DIF_INSTR_MOV(dnp->dn_ident->di_id, 19527c478bd9Sstevel@tonic-gate dnp->dn_reg); 19537c478bd9Sstevel@tonic-gate dt_irlist_append(dlp, 19547c478bd9Sstevel@tonic-gate dt_cg_node_alloc(DT_LBL_NONE, instr)); 19557c478bd9Sstevel@tonic-gate break; 19567c478bd9Sstevel@tonic-gate } 19577c478bd9Sstevel@tonic-gate 19587c478bd9Sstevel@tonic-gate /* 19597c478bd9Sstevel@tonic-gate * Identifiers can represent function calls, variable refs, or 19607c478bd9Sstevel@tonic-gate * symbols. First we check for inlined variables, and handle 19617c478bd9Sstevel@tonic-gate * them by generating code for the inline parse tree. 19627c478bd9Sstevel@tonic-gate */ 19637c478bd9Sstevel@tonic-gate if (dnp->dn_kind == DT_NODE_VAR && 19647c478bd9Sstevel@tonic-gate (dnp->dn_ident->di_flags & DT_IDFLG_INLINE)) { 19657c478bd9Sstevel@tonic-gate dt_cg_inline(dnp, dlp, drp); 19667c478bd9Sstevel@tonic-gate break; 19677c478bd9Sstevel@tonic-gate } 19687c478bd9Sstevel@tonic-gate 19697c478bd9Sstevel@tonic-gate switch (dnp->dn_kind) { 19707c478bd9Sstevel@tonic-gate case DT_NODE_FUNC: 19717c478bd9Sstevel@tonic-gate if ((idp = dnp->dn_ident)->di_kind != DT_IDENT_FUNC) { 19727c478bd9Sstevel@tonic-gate dnerror(dnp, D_CG_EXPR, "%s %s( ) may not be " 19737c478bd9Sstevel@tonic-gate "called from a D expression (D program " 19747c478bd9Sstevel@tonic-gate "context required)\n", 19757c478bd9Sstevel@tonic-gate dt_idkind_name(idp->di_kind), idp->di_name); 19767c478bd9Sstevel@tonic-gate } 19777c478bd9Sstevel@tonic-gate 19787c478bd9Sstevel@tonic-gate dt_cg_arglist(dnp->dn_ident, dnp->dn_args, dlp, drp); 19797c478bd9Sstevel@tonic-gate 1980e5803b76SAdam H. Leventhal dnp->dn_reg = dt_regset_alloc(drp); 1981e5803b76SAdam H. Leventhal instr = DIF_INSTR_CALL(dnp->dn_ident->di_id, 1982e5803b76SAdam H. Leventhal dnp->dn_reg); 19837c478bd9Sstevel@tonic-gate 19847c478bd9Sstevel@tonic-gate dt_irlist_append(dlp, 19857c478bd9Sstevel@tonic-gate dt_cg_node_alloc(DT_LBL_NONE, instr)); 19867c478bd9Sstevel@tonic-gate 19877c478bd9Sstevel@tonic-gate break; 19887c478bd9Sstevel@tonic-gate 19897c478bd9Sstevel@tonic-gate case DT_NODE_VAR: 19907c478bd9Sstevel@tonic-gate if (dnp->dn_ident->di_kind == DT_IDENT_XLSOU || 19917c478bd9Sstevel@tonic-gate dnp->dn_ident->di_kind == DT_IDENT_XLPTR) { 19927c478bd9Sstevel@tonic-gate /* 19937c478bd9Sstevel@tonic-gate * This can only happen if we have translated 19947c478bd9Sstevel@tonic-gate * args[]. See dt_idcook_args() for details. 19957c478bd9Sstevel@tonic-gate */ 19967c478bd9Sstevel@tonic-gate assert(dnp->dn_ident->di_id == DIF_VAR_ARGS); 19977c478bd9Sstevel@tonic-gate dt_cg_array_op(dnp, dlp, drp); 19987c478bd9Sstevel@tonic-gate break; 19997c478bd9Sstevel@tonic-gate } 20007c478bd9Sstevel@tonic-gate 20017c478bd9Sstevel@tonic-gate if (dnp->dn_ident->di_kind == DT_IDENT_ARRAY) { 20027c478bd9Sstevel@tonic-gate if (dnp->dn_ident->di_id > DIF_VAR_ARRAY_MAX) 20037c478bd9Sstevel@tonic-gate dt_cg_assoc_op(dnp, dlp, drp); 20047c478bd9Sstevel@tonic-gate else 20057c478bd9Sstevel@tonic-gate dt_cg_array_op(dnp, dlp, drp); 20067c478bd9Sstevel@tonic-gate break; 20077c478bd9Sstevel@tonic-gate } 20087c478bd9Sstevel@tonic-gate 2009e5803b76SAdam H. Leventhal dnp->dn_reg = dt_regset_alloc(drp); 20107c478bd9Sstevel@tonic-gate 20117c478bd9Sstevel@tonic-gate if (dnp->dn_ident->di_flags & DT_IDFLG_LOCAL) 20127c478bd9Sstevel@tonic-gate op = DIF_OP_LDLS; 20137c478bd9Sstevel@tonic-gate else if (dnp->dn_ident->di_flags & DT_IDFLG_TLS) 20147c478bd9Sstevel@tonic-gate op = DIF_OP_LDTS; 20157c478bd9Sstevel@tonic-gate else 20167c478bd9Sstevel@tonic-gate op = DIF_OP_LDGS; 20177c478bd9Sstevel@tonic-gate 20187c478bd9Sstevel@tonic-gate dnp->dn_ident->di_flags |= DT_IDFLG_DIFR; 20197c478bd9Sstevel@tonic-gate 20207c478bd9Sstevel@tonic-gate instr = DIF_INSTR_LDV(op, 20217c478bd9Sstevel@tonic-gate dnp->dn_ident->di_id, dnp->dn_reg); 20227c478bd9Sstevel@tonic-gate 20237c478bd9Sstevel@tonic-gate dt_irlist_append(dlp, 20247c478bd9Sstevel@tonic-gate dt_cg_node_alloc(DT_LBL_NONE, instr)); 20257c478bd9Sstevel@tonic-gate break; 20267c478bd9Sstevel@tonic-gate 20277c478bd9Sstevel@tonic-gate case DT_NODE_SYM: { 20287c478bd9Sstevel@tonic-gate dtrace_hdl_t *dtp = yypcb->pcb_hdl; 20297c478bd9Sstevel@tonic-gate dtrace_syminfo_t *sip = dnp->dn_ident->di_data; 20307c478bd9Sstevel@tonic-gate GElf_Sym sym; 20317c478bd9Sstevel@tonic-gate 20327c478bd9Sstevel@tonic-gate if (dtrace_lookup_by_name(dtp, 20337c478bd9Sstevel@tonic-gate sip->dts_object, sip->dts_name, &sym, NULL) == -1) { 20347c478bd9Sstevel@tonic-gate xyerror(D_UNKNOWN, "cg failed for symbol %s`%s:" 20357c478bd9Sstevel@tonic-gate " %s\n", sip->dts_object, sip->dts_name, 20367c478bd9Sstevel@tonic-gate dtrace_errmsg(dtp, dtrace_errno(dtp))); 20377c478bd9Sstevel@tonic-gate } 20387c478bd9Sstevel@tonic-gate 2039e5803b76SAdam H. Leventhal dnp->dn_reg = dt_regset_alloc(drp); 20407c478bd9Sstevel@tonic-gate dt_cg_xsetx(dlp, dnp->dn_ident, 20417c478bd9Sstevel@tonic-gate DT_LBL_NONE, dnp->dn_reg, sym.st_value); 20427c478bd9Sstevel@tonic-gate 20437c478bd9Sstevel@tonic-gate if (!(dnp->dn_flags & DT_NF_REF)) { 20447c478bd9Sstevel@tonic-gate instr = DIF_INSTR_LOAD(dt_cg_load(dnp, ctfp, 20457c478bd9Sstevel@tonic-gate dnp->dn_type), dnp->dn_reg, dnp->dn_reg); 20467c478bd9Sstevel@tonic-gate dt_irlist_append(dlp, 20477c478bd9Sstevel@tonic-gate dt_cg_node_alloc(DT_LBL_NONE, instr)); 20487c478bd9Sstevel@tonic-gate } 20497c478bd9Sstevel@tonic-gate break; 20507c478bd9Sstevel@tonic-gate } 20517c478bd9Sstevel@tonic-gate 20527c478bd9Sstevel@tonic-gate default: 20537c478bd9Sstevel@tonic-gate xyerror(D_UNKNOWN, "internal error -- node type %u is " 20547c478bd9Sstevel@tonic-gate "not valid for an identifier\n", dnp->dn_kind); 20557c478bd9Sstevel@tonic-gate } 20567c478bd9Sstevel@tonic-gate break; 20577c478bd9Sstevel@tonic-gate 20587c478bd9Sstevel@tonic-gate case DT_TOK_INT: 2059e5803b76SAdam H. Leventhal dnp->dn_reg = dt_regset_alloc(drp); 20607c478bd9Sstevel@tonic-gate dt_cg_setx(dlp, dnp->dn_reg, dnp->dn_value); 20617c478bd9Sstevel@tonic-gate break; 20627c478bd9Sstevel@tonic-gate 20637c478bd9Sstevel@tonic-gate default: 20647c478bd9Sstevel@tonic-gate xyerror(D_UNKNOWN, "internal error -- token type %u is not a " 20657c478bd9Sstevel@tonic-gate "valid D compilation token\n", dnp->dn_op); 20667c478bd9Sstevel@tonic-gate } 20677c478bd9Sstevel@tonic-gate } 20687c478bd9Sstevel@tonic-gate 20697c478bd9Sstevel@tonic-gate void 20707c478bd9Sstevel@tonic-gate dt_cg(dt_pcb_t *pcb, dt_node_t *dnp) 20717c478bd9Sstevel@tonic-gate { 20727c478bd9Sstevel@tonic-gate dif_instr_t instr; 20731a7c1b72Smws dt_xlator_t *dxp; 2074e5803b76SAdam H. Leventhal dt_ident_t *idp; 20757c478bd9Sstevel@tonic-gate 20767c478bd9Sstevel@tonic-gate if (pcb->pcb_regs == NULL && (pcb->pcb_regs = 20777c478bd9Sstevel@tonic-gate dt_regset_create(pcb->pcb_hdl->dt_conf.dtc_difintregs)) == NULL) 20787c478bd9Sstevel@tonic-gate longjmp(pcb->pcb_jmpbuf, EDT_NOMEM); 20797c478bd9Sstevel@tonic-gate 20807c478bd9Sstevel@tonic-gate dt_regset_reset(pcb->pcb_regs); 20817c478bd9Sstevel@tonic-gate (void) dt_regset_alloc(pcb->pcb_regs); /* allocate %r0 */ 20827c478bd9Sstevel@tonic-gate 20837c478bd9Sstevel@tonic-gate if (pcb->pcb_inttab != NULL) 20847c478bd9Sstevel@tonic-gate dt_inttab_destroy(pcb->pcb_inttab); 20857c478bd9Sstevel@tonic-gate 20867c478bd9Sstevel@tonic-gate if ((pcb->pcb_inttab = dt_inttab_create(yypcb->pcb_hdl)) == NULL) 20877c478bd9Sstevel@tonic-gate longjmp(pcb->pcb_jmpbuf, EDT_NOMEM); 20887c478bd9Sstevel@tonic-gate 20897c478bd9Sstevel@tonic-gate if (pcb->pcb_strtab != NULL) 20907c478bd9Sstevel@tonic-gate dt_strtab_destroy(pcb->pcb_strtab); 20917c478bd9Sstevel@tonic-gate 20927c478bd9Sstevel@tonic-gate if ((pcb->pcb_strtab = dt_strtab_create(BUFSIZ)) == NULL) 20937c478bd9Sstevel@tonic-gate longjmp(pcb->pcb_jmpbuf, EDT_NOMEM); 20947c478bd9Sstevel@tonic-gate 20957c478bd9Sstevel@tonic-gate dt_irlist_destroy(&pcb->pcb_ir); 20967c478bd9Sstevel@tonic-gate dt_irlist_create(&pcb->pcb_ir); 20977c478bd9Sstevel@tonic-gate 20987c478bd9Sstevel@tonic-gate assert(pcb->pcb_dret == NULL); 20997c478bd9Sstevel@tonic-gate pcb->pcb_dret = dnp; 21007c478bd9Sstevel@tonic-gate 2101e5803b76SAdam H. Leventhal if (dt_node_resolve(dnp, DT_IDENT_XLPTR) != NULL) { 21027c478bd9Sstevel@tonic-gate dnerror(dnp, D_CG_DYN, "expression cannot evaluate to result " 2103e5803b76SAdam H. Leventhal "of a translated pointer\n"); 21047c478bd9Sstevel@tonic-gate } 21057c478bd9Sstevel@tonic-gate 21061a7c1b72Smws /* 21071a7c1b72Smws * If we're generating code for a translator body, assign the input 21081a7c1b72Smws * parameter to the first available register (i.e. caller passes %r1). 21091a7c1b72Smws */ 21101a7c1b72Smws if (dnp->dn_kind == DT_NODE_MEMBER) { 21111a7c1b72Smws dxp = dnp->dn_membxlator; 21121a7c1b72Smws dnp = dnp->dn_membexpr; 21131a7c1b72Smws 21141a7c1b72Smws dxp->dx_ident->di_flags |= DT_IDFLG_CGREG; 21151a7c1b72Smws dxp->dx_ident->di_id = dt_regset_alloc(pcb->pcb_regs); 21161a7c1b72Smws } 21171a7c1b72Smws 21187c478bd9Sstevel@tonic-gate dt_cg_node(dnp, &pcb->pcb_ir, pcb->pcb_regs); 2119e5803b76SAdam H. Leventhal 2120e5803b76SAdam H. Leventhal if ((idp = dt_node_resolve(dnp, DT_IDENT_XLSOU)) != NULL) { 2121e5803b76SAdam H. Leventhal int reg = dt_cg_xlate_expand(dnp, idp, 2122e5803b76SAdam H. Leventhal &pcb->pcb_ir, pcb->pcb_regs); 2123e5803b76SAdam H. Leventhal dt_regset_free(pcb->pcb_regs, dnp->dn_reg); 2124e5803b76SAdam H. Leventhal dnp->dn_reg = reg; 2125e5803b76SAdam H. Leventhal } 2126e5803b76SAdam H. Leventhal 21277c478bd9Sstevel@tonic-gate instr = DIF_INSTR_RET(dnp->dn_reg); 21287c478bd9Sstevel@tonic-gate dt_regset_free(pcb->pcb_regs, dnp->dn_reg); 21297c478bd9Sstevel@tonic-gate dt_irlist_append(&pcb->pcb_ir, dt_cg_node_alloc(DT_LBL_NONE, instr)); 21301a7c1b72Smws 21311a7c1b72Smws if (dnp->dn_kind == DT_NODE_MEMBER) { 21321a7c1b72Smws dt_regset_free(pcb->pcb_regs, dxp->dx_ident->di_id); 21331a7c1b72Smws dxp->dx_ident->di_id = 0; 21341a7c1b72Smws dxp->dx_ident->di_flags &= ~DT_IDFLG_CGREG; 21351a7c1b72Smws } 2136e5803b76SAdam H. Leventhal 2137e5803b76SAdam H. Leventhal dt_regset_free(pcb->pcb_regs, 0); 2138e5803b76SAdam H. Leventhal dt_regset_assert_free(pcb->pcb_regs); 21397c478bd9Sstevel@tonic-gate } 2140