/* * Copyright (c) 2005 - 2007, Nils R. Weller * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ #include "icode.h" #include #include #include #include #include #include #include #include "misc.h" #include "token.h" #include "control.h" #include "decl.h" #include "type.h" #include "debug.h" #include "defs.h" #include "expr.h" #include "error.h" #include "subexpr.h" #include "symlist.h" #include "reg.h" #include "functions.h" #include "backend.h" /* for get_sizeof() */ #include "scope.h" #include "cc1_main.h" /* flags */ #include "inlineasm.h" #include "n_libc.h" struct icode_instr * alloc_icode_instr(void) { struct icode_instr *ret = n_xmalloc(sizeof *ret); static struct icode_instr nullinstr; static unsigned long seq; *ret = nullinstr; ret->seqno = ++seq; return ret; } struct icode_list * alloc_icode_list(void) { struct icode_list *ret = n_xmalloc(sizeof *ret); static struct icode_list nullil; *ret = nullil; return ret; } void append_icode_list(struct icode_list *list, struct icode_instr *instr) { if (list->tail == NULL) { list->head = list->tail = instr; } else { list->tail->next = instr; list->tail = instr; } /* * XXX stuff below is a kludge to ensure that pointer pregs are * always recorded properly */ if (instr->src_vreg && instr->src_ptr_preg == NULL) { if (instr->src_vreg->from_ptr) { instr->src_ptr_preg = instr->src_vreg->from_ptr->pregs[0]; } else if (instr->src_vreg->parent) { struct vreg *vr2 = get_parent_struct(instr->src_vreg); if (vr2->from_ptr) { instr->src_parent_struct = vr2; instr->src_ptr_preg = vr2->from_ptr->pregs[0]; } } } if (instr->dest_vreg && instr->dest_ptr_preg == NULL) { if (instr->dest_vreg->from_ptr) { instr->dest_ptr_preg = instr->dest_vreg->from_ptr->pregs[0]; } else if (instr->dest_vreg->parent) { struct vreg *vr2 = get_parent_struct(instr->dest_vreg); if (vr2->from_ptr) { instr->dest_parent_struct = vr2; instr->dest_ptr_preg = vr2->from_ptr->pregs[0]; } } } if (instr->type == INSTR_COPYSTRUCT) { struct copystruct *cs = instr->dat; struct vreg *structtop; if (cs->src_vreg && cs->src_vreg->parent) { structtop = get_parent_struct(cs->src_vreg); if (structtop->from_ptr) { instr->src_parent_struct = structtop; instr->src_ptr_preg = structtop->from_ptr->pregs[0]; } } if (cs->dest_vreg && cs->dest_vreg->parent) { structtop = get_parent_struct(cs->dest_vreg); if (structtop->from_ptr) { instr->dest_parent_struct = structtop; instr->dest_ptr_preg = structtop->from_ptr->pregs[0]; } } } } void merge_icode_lists(struct icode_list *dest, struct icode_list *src) { if (src->head == NULL) { /* XXX ??? */ dest->res = src->res; return; } if (dest->head == NULL) { if (dest->tail != NULL) { puts("icode list corruption detected"); exit(EXIT_FAILURE); } dest->head = src->head; dest->tail = src->tail; } else { dest->tail->next = src->head; if (src->tail != NULL) { dest->tail = src->tail; } } dest->res = src->res; } struct reg ** make_icode_pregs(struct vreg *vr, struct reg *r) { struct reg **ret; if (vr == NULL || !vr->is_multi_reg_obj) { ret = n_xmalloc(2 * sizeof *ret); ret[0] = vr? vr->pregs[0]: r; ret[1] = NULL; } else { ret = n_xmalloc(vr->is_multi_reg_obj * sizeof *ret); if (vr->is_multi_reg_obj != 2) abort(); /* XXX hardcoded x86 */ ret[0] = vr->pregs[0]; ret[1] = vr->pregs[1]; } return ret; } struct icode_instr * generic_icode_make_instr(struct vreg *dest, struct vreg *src, int type) { struct icode_instr *ret = alloc_icode_instr(); ret->type = type; ret->dest_vreg = dest; if (dest != NULL) { ret->dest_pregs = make_icode_pregs(dest, NULL); } ret->src_vreg = src; if (src != NULL) { ret->src_pregs = make_icode_pregs(src, NULL); } return ret; } static unsigned long lnum = 0; unsigned long get_label_count(void) { return lnum; } struct icode_instr * icode_make_label(const char *name) { struct icode_instr *ret; char buf[1024]; ret = alloc_icode_instr(); ret->type = INSTR_LABEL; if (name == NULL) { sprintf(buf, "L%lu", lnum++); ret->dat = n_xstrdup(buf); } else { ret->dat = n_xstrdup(name); } return ret; } struct icode_instr * icode_make_adj_allocated(int bytes) { struct icode_instr *ii = alloc_icode_instr(); ii->dat = n_xmemdup(&bytes, sizeof bytes); ii->type = INSTR_ADJ_ALLOCATED; return ii; } struct icode_instr * icode_make_setreg(struct reg *r, int value) { struct icode_instr *ret = alloc_icode_instr(); ret->type = INSTR_SETREG; ret->src_pregs = make_icode_pregs(NULL, r); ret->dat = n_xmemdup(&value, sizeof value); /* XXX :-( */ return ret; } struct icode_instr * icode_make_freestack(size_t bytes) { struct icode_instr *ret = alloc_icode_instr(); ret->type = INSTR_FREESTACK; ret->dat = n_xmemdup(&bytes, sizeof bytes); return ret; } struct icode_instr * icode_make_branch(struct icode_instr *dest, int btype, struct vreg *vr) { struct icode_instr *ret = alloc_icode_instr(); ret->type = btype; ret->dat = dest; ret->dest_vreg = vr; return ret; } struct icode_instr * icode_make_call(const char *name) { struct icode_instr *ret = alloc_icode_instr(); ret->type = INSTR_CALL; ret->dat = (char *)name; return ret; } struct icode_instr * icode_make_call_indir(struct reg *r) { struct icode_instr *ret = alloc_icode_instr(); ret->type = INSTR_CALLINDIR; ret->dat = r; return ret; } void icode_make_xchg(struct reg *r1, struct reg *r2, struct icode_list *il) { struct icode_instr *ret = alloc_icode_instr(); ret->type = INSTR_XCHG; ret->src_pregs = make_icode_pregs(NULL, r1); ret->dest_pregs = make_icode_pregs(NULL, r2); append_icode_list(il, ret); } static struct icode_instr * icode_make_load_vla(struct reg *r, struct type *ty) { struct icode_instr *ii = alloc_icode_instr(); ii->type = INSTR_LOAD_VLA; ii->dest_pregs = make_icode_pregs(NULL, r); ii->dat = ty; return ii; } /* * XXX pass vreg instead?? * Note that this really only deals with one register at a time - * multi-register objects are dealt with in vreg_faultin() */ struct icode_instr * icode_make_load(struct reg *r, struct vreg *parent_struct) { struct icode_instr *ret = alloc_icode_instr(); struct vreg *vr = r->vreg; if (vr->type->is_vla && is_immediate_vla_type(vr->type)) { return icode_make_load_vla(r, vr->type); } if (vr->from_const && vr->from_const->data2) { /* Too big to be immediate */ struct ty_llong *tll; tll = vr->from_const->data2; tll->loaded = 1; } if (vr->type->code == TY_STRUCT && vr->type->tlist == NULL) { puts("BUG: Attempt to load struct into register :-("); abort(); } if (vr->parent != NULL && parent_struct != NULL) { if (parent_struct->from_ptr) { ret->src_parent_struct = parent_struct; ret->src_ptr_preg = parent_struct->from_ptr->pregs[0]; } } else if (vr->from_ptr) { ret->src_ptr_preg = vr->from_ptr->pregs[0]; } ret->type = INSTR_LOAD; ret->src_vreg = vr; ret->src_pregs = make_icode_pregs(NULL, r); if (!vr->var_backed && !vr->from_const && !vr->from_ptr && !vr->parent && !vr->stack_addr) { printf("BUG: load from unbacked vreg %p\n", vr); printf("calling abort()\n"); abort(); #if 0 } else { debug_print_vreg_backing(vr); #endif } return ret; } /* * Store current item to virtual register vr * XXX this is complete messed up * Store current item (INSTR_SETITEM) to vr * */ void icode_make_store(struct function *f, struct vreg *dest, struct vreg *src, /* XXX order is WRONG!! */ struct icode_list *il) { struct icode_instr *ret = alloc_icode_instr(); #if 0 if (src->pregs[0] == NULL) { puts ( " SRC PREG = NULL"); abort(); } #endif ret->type = INSTR_STORE; ret->dest_vreg = dest; ret->dest_pregs = make_icode_pregs(dest, NULL); ret->src_vreg = src; #if 0 /* * XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX * this triggers when compiling evalexpr.c on amd64!!! * with an xmm* register! */ if (src && src->pregs[0] && src->pregs[0]->size == 4 && src->size == 1) abort(); #endif if (src != NULL) { ret->src_pregs = make_icode_pregs(src, NULL); if (src->type->code == TY_STRUCT && src->type->tlist == NULL) { puts("BUG: Attempt to store register to struct :-(((("); abort(); } } if (src != NULL && !src->var_backed && !src->from_ptr && !src->from_const && !src->parent) { /* * Need to allocate anonymous storage * for register */ if (src->stack_addr == NULL) { /* Offset will be patched later */ /* XXX long long !?!?!!! */ size_t size = src->pregs[0]->size; if (src->is_multi_reg_obj) { size += src->pregs[1]->size; } else if (backend->arch == ARCH_SPARC) { /* * XXX hmm this seems wrong and ugly */ if (src->pregs[0]->type == REG_FPR) { switch (src->type->code) { case TY_FLOAT: size = 4; break; case TY_DOUBLE: size = 8; break; case TY_LDOUBLE: size = 16; break; default: unimpl(); } } } src->stack_addr = make_stack_block(0, size); if (f->regs_head == NULL) { f->regs_head = f->regs_tail = src->stack_addr; } else { f->regs_tail->next = src->stack_addr; f->regs_tail = f->regs_tail->next; } } } else if (src->from_ptr) { vreg_faultin_protected(src, NULL, NULL, src->from_ptr, il, 0); } append_icode_list(il, ret); #if 0 if (src->type->tlist == NULL && IS_FLOATING(src->type->code)) { /* * If using x87, we should NEVER cache any values.. so * upon doing ``fstp'', the stack top will be popped - * Invalidate references */ if (backend->arch == ARCH_X86 || (backend->arch == ARCH_AMD64 && src->type->code == TY_LDOUBLE)) { free_preg(src->pregs[0], il, 1, 0); } } #endif } struct icode_instr * icode_make_store_indir(struct vreg *dest, struct vreg *src) { struct icode_instr *ii = alloc_icode_instr(); if (src->pregs[0] == NULL) abort(); ii->type = INSTR_STORE; ii->dest_vreg = dest; ii->dest_pregs = make_icode_pregs(dest, NULL); ii->src_vreg = src; ii->src_pregs = make_icode_pregs(src, NULL); return ii; } struct icode_instr * icode_make_sub(struct vreg *dest, struct vreg *src) { return generic_icode_make_instr(dest, src, INSTR_SUB); } struct icode_instr * icode_make_neg(struct vreg *vr) { return generic_icode_make_instr(NULL, vr, INSTR_NEG); } struct icode_instr * icode_make_add(struct vreg *dest, struct vreg *src) { return generic_icode_make_instr(dest, src, INSTR_ADD); } struct icode_instr * icode_make_div(struct vreg *dest, struct vreg *src) { return generic_icode_make_instr(dest, src, INSTR_DIV); } struct icode_instr * icode_make_mod(struct vreg *dest, struct vreg *src) { return generic_icode_make_instr(dest, src, INSTR_MOD); } struct icode_instr * icode_make_mul(struct vreg *dest, struct vreg *src) { return generic_icode_make_instr(dest, src, INSTR_MUL); } struct icode_instr * icode_make_shl(struct vreg *dest, struct vreg *src) { return generic_icode_make_instr(dest, src, INSTR_SHL); } struct icode_instr * icode_make_shr(struct vreg *dest, struct vreg *src) { return generic_icode_make_instr(dest, src, INSTR_SHR); } struct icode_instr * icode_make_and(struct vreg *dest, struct vreg *src) { return generic_icode_make_instr(dest, src, INSTR_AND); } struct icode_instr * icode_make_xor(struct vreg *dest, struct vreg *src) { struct icode_instr *ret = alloc_icode_instr(); ret->type = INSTR_XOR; ret->dest_vreg = dest; ret->dest_pregs = make_icode_pregs(dest, NULL); if (src != NULL) { ret->src_pregs = make_icode_pregs(src, NULL); } ret->src_vreg = src; return ret; } struct icode_instr * icode_make_not(struct vreg *vr) { return generic_icode_make_instr(NULL, vr, INSTR_NOT); } struct icode_instr * icode_make_or(struct vreg *dest, struct vreg *src) { return generic_icode_make_instr(dest, src, INSTR_OR); } void icode_make_preg_or(struct reg *dest, struct reg *src, struct icode_list *il) { struct icode_instr *ret = alloc_icode_instr(); ret->type = INSTR_PREG_OR; ret->dest_pregs = make_icode_pregs(NULL, dest); ret->src_pregs = make_icode_pregs(NULL, src); append_icode_list(il, ret); } struct icode_instr * icode_make_push(struct vreg *vr, struct icode_list *il) { struct icode_instr *ret = alloc_icode_instr(); ret->type = INSTR_PUSH; if (vr->type && vr->type->is_vla) { if (vr->type->tlist->type == TN_ARRAY_OF || vr->type->tlist->type == TN_VARARRAY_OF) { struct reg *r; struct icode_instr *ii; if (vr->pregs[0] == NULL || vr->pregs[0]->vreg != vr) { r = ALLOC_GPR(curfunc, backend->get_ptr_size(), il, 0); vreg_map_preg(vr, r); ii = icode_make_load(r, NULL); append_icode_list(il, ii); free_preg(r, il, 0, 0); } } } ret->src_vreg = vr; ret->src_pregs= make_icode_pregs(vr, NULL); return ret; } struct icode_instr * icode_make_ret(struct vreg *vr) { struct icode_instr *ret = alloc_icode_instr(); ret->type = INSTR_RET; #if 0 if (vr != NULL) { /*ret->src_preg = vr->preg; seems never used*/ ret->src_vreg = vr; } #endif ret->src_vreg = vr; return ret; } struct icode_instr * icode_make_indir(struct reg *r) { struct icode_instr *ret = alloc_icode_instr(); ret->type = INSTR_INDIR; ret->dat = r; return ret; } /* * vr = NULL means take address of next argument on stack in * variadic function */ struct icode_instr * icode_make_addrof(struct vreg *vr, struct icode_list *il) { struct icode_instr *ret; ret = alloc_icode_instr(); ret->type = INSTR_ADDROF; ret->src_vreg = vr; #if 0 ret->dat = backend->alloc_gpr(curfunc, 4, il, NULL); /* XXX */ #endif ret->dat = ALLOC_GPR(curfunc, backend->get_ptr_size(), il, NULL); /* XXX */ return ret; } struct icode_instr * icode_make_inc(struct vreg *vr) { return generic_icode_make_instr(NULL, vr, INSTR_INC); } struct icode_instr * icode_make_dec(struct vreg *vr) { return generic_icode_make_instr(NULL, vr, INSTR_DEC); } /* * ===================================================== * x86-specific instructions * ===================================================== */ void icode_make_x86_fxch(struct reg *r, struct reg *r2, struct icode_list *il) { struct icode_instr *ret = alloc_icode_instr(); struct vreg *tmp = r2->vreg; ret->type = INSTR_X86_FXCH; ret->src_pregs = make_icode_pregs(NULL, r); ret->dest_pregs = make_icode_pregs(NULL, r2); append_icode_list(il, ret); if (r->vreg != NULL) { r->vreg->pregs[0] = r2; r2->vreg = r->vreg; } if (tmp != NULL) { r->vreg = tmp; r->vreg->pregs[0] = r; } } void icode_make_asm(struct inline_asm_stmt *inl, struct icode_list *il) { struct icode_instr *ret = alloc_icode_instr(); ret->type = INSTR_ASM; ret->dat = inl; append_icode_list(il, ret); } void icode_make_x86_cdq(struct icode_list *il) { struct icode_instr *ret = alloc_icode_instr(); ret->type = INSTR_X86_CDQ; append_icode_list(il, ret); } void icode_make_x86_ffree(struct reg *r, struct icode_list *il) { struct icode_instr *ret = alloc_icode_instr(); ret->type = INSTR_X86_FFREE; ret->src_pregs = make_icode_pregs(NULL, r); append_icode_list(il, ret); } void icode_make_x86_store_x87cw(struct vreg *vr, struct icode_list *il) { struct icode_instr *ii; ii = generic_icode_make_instr(NULL, vr, INSTR_X86_FNSTCW); append_icode_list(il, ii); } void icode_make_x86_load_x87cw(struct vreg *vr, struct icode_list *il) { struct icode_instr *ii; ii = generic_icode_make_instr(NULL, vr, INSTR_X86_FLDCW); append_icode_list(il, ii); } /* * ===================================================== * MIPS-specific instructions * ===================================================== */ void icode_make_mips_mtc1( struct reg *dest, struct vreg *src, struct icode_list *il) { struct icode_instr *ii; ii = generic_icode_make_instr(NULL, src, INSTR_MIPS_MTC1); ii->dat = dest; append_icode_list(il, ii); } void icode_make_mips_mfc1( struct reg *dest, struct vreg *src, struct icode_list *il) { struct icode_instr *ii; ii = generic_icode_make_instr(NULL, src, INSTR_MIPS_MFC1); ii->dat = dest; append_icode_list(il, ii); } void icode_make_mips_cvt( struct vreg *dest, struct vreg *src, struct icode_list *il) { struct icode_instr *ii; ii = generic_icode_make_instr(dest, src, INSTR_MIPS_CVT); append_icode_list(il, ii); } void icode_make_mips_trunc( struct vreg *dest, struct vreg *src, struct icode_list *il) { struct icode_instr *ii; ii = generic_icode_make_instr(dest, src, INSTR_MIPS_TRUNC); append_icode_list(il, ii); } void icode_make_mips_make_32bit_mask(struct reg *r, struct icode_list *il) { struct icode_instr *ii = alloc_icode_instr(); ii->type = INSTR_MIPS_MAKE_32BIT_MASK; ii->dat = r; append_icode_list(il, ii); } /* * ===================================================== * PowerPC-specific instructions * ===================================================== */ void icode_make_power_srawi(struct reg *dest, struct reg *src, int bits, struct icode_list *il) { struct icode_instr *ii; ii = generic_icode_make_instr(NULL, NULL, INSTR_POWER_SRAWI); ii->dest_pregs = make_icode_pregs(NULL, dest); ii->src_pregs = make_icode_pregs(NULL, src); ii->dat = n_xmemdup(&bits, sizeof(int)); append_icode_list(il, ii); } void icode_make_power_rldicl(struct reg *dest, struct reg *src, int bits, struct icode_list *il) { struct icode_instr *ii; ii = generic_icode_make_instr(NULL, NULL, INSTR_POWER_RLDICL); ii->dest_pregs = make_icode_pregs(NULL, dest); ii->src_pregs = make_icode_pregs(NULL, src); ii->dat = n_xmemdup(&bits, sizeof(int)); append_icode_list(il, ii); } void icode_make_power_fcfid(struct reg *dest, struct reg *src, struct icode_list *il) { struct icode_instr *ii; ii = generic_icode_make_instr(NULL, NULL, INSTR_POWER_FCFID); ii->dest_pregs = make_icode_pregs(NULL, dest); ii->src_pregs = make_icode_pregs(NULL, src); append_icode_list(il, ii); } void icode_make_power_frsp(struct reg *dest, struct icode_list *il) { struct icode_instr *ii; ii = generic_icode_make_instr(NULL, NULL, INSTR_POWER_FRSP); ii->dat = dest; append_icode_list(il, ii); } void icode_make_power_slwi(struct reg *dest, struct reg *src, int bits, struct icode_list *il) { struct icode_instr *ii; ii = generic_icode_make_instr(NULL, NULL, INSTR_POWER_SLWI); ii->dest_pregs = make_icode_pregs(NULL, dest); ii->src_pregs = make_icode_pregs(NULL, src); ii->dat = n_xmemdup(&bits, sizeof(int)); append_icode_list(il, ii); } void icode_make_power_rlwinm(struct reg *dest, struct reg *src, int value, struct icode_list *il) { struct icode_instr *ii; ii = generic_icode_make_instr(NULL, NULL, INSTR_POWER_RLWINM); ii->dest_pregs = make_icode_pregs(NULL, dest); ii->src_pregs = make_icode_pregs(NULL, src); ii->dat = n_xmemdup(&value, sizeof(int)); append_icode_list(il, ii); } void icode_make_power_extsb(struct reg *r, struct icode_list *il) { struct icode_instr *ii; ii = generic_icode_make_instr(NULL, NULL, INSTR_POWER_EXTSB); ii->dat = r; append_icode_list(il, ii); } void icode_make_power_extsh(struct reg *r, struct icode_list *il) { struct icode_instr *ii; ii = generic_icode_make_instr(NULL, NULL, INSTR_POWER_EXTSH); ii->dat = r; append_icode_list(il, ii); } void icode_make_power_extsw(struct reg *r, struct icode_list *il) { struct icode_instr *ii; ii = generic_icode_make_instr(NULL, NULL, INSTR_POWER_EXTSW); ii->dat = r; append_icode_list(il, ii); } void icode_make_power_xoris(struct reg *dest, int val, struct icode_list *il) { struct icode_instr *ii; ii = generic_icode_make_instr(NULL, NULL, INSTR_POWER_XORIS); ii->dest_pregs = make_icode_pregs(NULL, dest); ii->dat = n_xmemdup(&val, sizeof(int)); append_icode_list(il, ii); } void icode_make_power_lis(struct reg *dest, int val, struct icode_list *il) { struct icode_instr *ii; ii = generic_icode_make_instr(NULL, NULL, INSTR_POWER_LIS); ii->dest_pregs = make_icode_pregs(NULL, dest); ii->dat = n_xmemdup(&val, sizeof(int)); append_icode_list(il, ii); } void icode_make_power_loadup4(struct reg *dest, struct vreg *src, struct icode_list *il) { struct icode_instr *ii; ii = generic_icode_make_instr(NULL, src, INSTR_POWER_LOADUP4); ii->dest_pregs = make_icode_pregs(NULL, dest); append_icode_list(il, ii); } void icode_make_power_fctiwz(struct reg *r, struct icode_list *il) { struct icode_instr *ii; ii = generic_icode_make_instr(NULL, NULL, INSTR_POWER_FCTIWZ); ii->dat = r; append_icode_list(il, ii); } /* * ===================================================== * AMD64-specific instructions * ===================================================== */ void icode_make_amd64_cvtsi2sd( struct reg *dest, struct vreg *src, struct icode_list *il) { struct icode_instr *ii; ii = generic_icode_make_instr(NULL, src, INSTR_AMD64_CVTSI2SD); ii->dest_pregs = make_icode_pregs(NULL, dest); append_icode_list(il, ii); } void icode_make_amd64_cvtsi2ss( struct reg *dest, struct vreg *src, struct icode_list *il) { struct icode_instr *ii; ii = generic_icode_make_instr(NULL, src, INSTR_AMD64_CVTSI2SS); ii->dest_pregs = make_icode_pregs(NULL, dest); append_icode_list(il, ii); } void icode_make_amd64_cvttss2si( struct reg *dest, struct reg *src, struct icode_list *il) { struct icode_instr *ii; ii = generic_icode_make_instr(NULL, NULL, INSTR_AMD64_CVTTSS2SI); ii->dest_pregs = make_icode_pregs(NULL, dest); ii->src_pregs = make_icode_pregs(NULL, src); append_icode_list(il, ii); } void icode_make_amd64_cvttsd2si( struct reg *dest, struct reg *src, struct icode_list *il) { struct icode_instr *ii; ii = generic_icode_make_instr(NULL, NULL, INSTR_AMD64_CVTTSD2SI); ii->dest_pregs = make_icode_pregs(NULL, dest); ii->src_pregs = make_icode_pregs(NULL, src); append_icode_list(il, ii); } void icode_make_amd64_cvtss2sd(struct reg *r, struct icode_list *il) { struct icode_instr *ii; ii = generic_icode_make_instr(NULL, NULL, INSTR_AMD64_CVTSS2SD); ii->dat = r; append_icode_list(il, ii); } void icode_make_amd64_cvtsd2ss(struct reg *r, struct icode_list *il) { struct icode_instr *ii; ii = generic_icode_make_instr(NULL, NULL, INSTR_AMD64_CVTSD2SS); ii->dat = r; append_icode_list(il, ii); } struct icode_instr * icode_make_seqpoint(struct var_access *stores) { struct icode_instr *ret = alloc_icode_instr(); ret->type = INSTR_SEQPOINT; ret->dat = stores; return ret; } struct icode_instr * icode_make_debug(const char *fmt, ...) { struct icode_instr *ret = alloc_icode_instr(); char buf[2048]; va_list va; va_start(va, fmt); vsprintf(buf, fmt, va); va_end(va); ret->type = INSTR_DEBUG; ret->dat = n_xstrdup(buf); return ret; } void icode_make_dbginfo_line(struct statement *stmt, struct icode_list *il) { struct icode_instr *ii = NULL; struct decl *dec; struct expr *ex; if (!gflag) return; switch (stmt->type) { case ST_CODE: ii = alloc_icode_instr(); ii->type = INSTR_DBGINFO_LINE; ex = stmt->data; ii->dat = ex->tok; break; case ST_DECL: /* A declaration with initializer has ``code'' */ dec = stmt->data; if (dec->init != NULL) { ii = alloc_icode_instr(); ii->type = INSTR_DBGINFO_LINE; ex = dec->init->data; ii->dat = ex->tok; } break; default: abort(); } if (ii != NULL) { /* XXX */ append_icode_list(il, ii); } } int unimpl_instr; void icode_make_unimpl(struct icode_list *il) { struct icode_instr *ii = alloc_icode_instr(); unimpl_instr = 1; ii->type = INSTR_UNIMPL; append_icode_list(il, ii); } void icode_make_copyinit(struct decl *d, struct icode_list *il) { struct icode_instr *ii = alloc_icode_instr(); ii->type = INSTR_COPYINIT; ii->dat = d; append_icode_list(il, ii); } /* * Copy struct src to struct dest. Both may be automatic, static, * indirect, etc. If dest is a null pointer, then it is assumed that * the current function returns a structure type, and src will be * copied to the hidden pointer for struct returns (hidden_pointer * member of ``struct function''). This only works with the MIPS * backend right now. * * If any argument comes from a pointer, that pointer will be loaded * into a register as necessary. Note that most backends currently * call memcpy() to copy structs, so it is essential to save all GPRs * as necessary (backend->invalidate_gprs().) Perhaps it would make * sense to add a backend->prepare_copystruct() for register saving. * * XXX seems dest_preg and src_preg are never used and conceptually * totally nonsense because a struct is never gpr-resident */ void icode_make_copystruct( struct vreg *dest, struct vreg *src, struct icode_list *il) { struct icode_instr *ii = alloc_icode_instr(); struct copystruct *cs; struct vreg *stop; static struct copystruct nullcs; cs = n_xmalloc(sizeof *cs); *cs = nullcs; /* If source is indirect, do not trash pointer register */ vreg_set_unallocatable(src); cs->dest_vreg = dest; if (dest != NULL) { vreg_faultin_ptr(dest, il); cs->dest_preg = dest->pregs[0]; if (dest->from_ptr) { cs->dest_from_ptr = dest->from_ptr->pregs[0]; } else if (dest->parent && (stop = get_parent_struct(dest))->from_ptr) { cs->dest_from_ptr = NULL; cs->dest_from_ptr_struct = stop->from_ptr->pregs[0]; } else { cs->dest_from_ptr = NULL; } vreg_set_unallocatable(dest); } cs->src_vreg = src; cs->src_preg = src->pregs[0]; vreg_faultin_ptr(src, il); vreg_set_allocatable(src); if (dest != NULL) { vreg_set_allocatable(dest); } if (src->from_ptr) { cs->src_from_ptr = src->from_ptr->pregs[0]; } else if (src->parent && (stop = get_parent_struct(src))->from_ptr) { cs->src_from_ptr = NULL; cs->src_from_ptr_struct = stop->from_ptr->pregs[0]; } else { cs->src_from_ptr = NULL; } if (backend->icode_make_structreloc) { backend->icode_make_structreloc(cs, il); } ii->type = INSTR_COPYSTRUCT; ii->dat = cs; append_icode_list(il, ii); } /* * Intrinsically copy nbytes of src to dest. Currently dest and src must * be pointers or arrays. This is currently only used by __builtin_memcpy, * but should eventually replace INSTR_COPYSTRUCT and INSTR_COPYINIT. * If may_call_lib is set, the library memcpy() may be called, which * makes sense for huge data items (the primary point of __builtin_memcpy * is probably to avoid library dependencies.) */ void icode_make_intrinsic_memcpy(struct vreg *dest, struct vreg *src, struct vreg *nbytes, int may_call_lib, struct icode_list *il) { struct icode_instr *ii = alloc_icode_instr(); struct int_memcpy_data *imdata = n_xmalloc(sizeof *imdata); struct reg *dest_reg; struct reg *src_reg; struct reg *temp_reg; ii->type = INSTR_INTRINSIC_MEMCPY; if (src->type->tlist == NULL || src->type->tlist == NULL) { /* * In the future we should allow copying non- * pointer objects too (take the address here) * for convenient struct and initializer copying */ unimpl(); } vreg_faultin_ptr(dest, il); if (dest->from_ptr) { dest_reg = dest->from_ptr->pregs[0]; } else { /* Array or function */ dest_reg = dest->pregs[0]; } reg_set_unallocatable(dest_reg); vreg_faultin_ptr(src, il); if (src->from_ptr) { src_reg = src->from_ptr->pregs[0]; } else { /* Array or function */ src_reg = src->pregs[0]; } reg_set_unallocatable(src_reg); vreg_faultin(NULL, NULL, nbytes, il, 0); reg_set_unallocatable(nbytes->pregs[0]); /* * Now allocate temporary register for holding one byte. This * will be used for byte-wise simplistic copying by all * backends until more sophisticated implementations are * written. Then it will be time to have some sort of backend * flag which tells us whether such a temp reg is needed or * not, and what else may have to be done here */ temp_reg = ALLOC_GPR(curfunc, 1, il, NULL); reg_set_allocatable(dest_reg); reg_set_allocatable(src_reg); reg_set_allocatable(nbytes->pregs[0]); imdata->dest_addr = dest_reg; imdata->src_addr = src_reg; imdata->nbytes = nbytes->pregs[0]; imdata->temp_reg = temp_reg; if (may_call_lib /* && makes_sense_to_call_lib */) { imdata->dest_addr->used = 0; imdata->src_addr->used = 0; imdata->nbytes->used = 0; imdata->temp_reg->used = 0; backend->invalidate_gprs(il, 1); } ii->dat = imdata; append_icode_list(il, ii); } void icode_make_dealloca(struct stack_block *sb, struct icode_list *il) { struct icode_instr *ii = alloc_icode_instr(); struct reg *r; struct type *st; st = backend->get_size_t(); r = backend->get_abi_reg(0, st); if (r == NULL) { r = ALLOC_GPR(curfunc, backend->get_sizeof_type(st, 0), il, 0); } ii->type = INSTR_DEALLOCA; ii->src_pregs = make_icode_pregs(NULL, r); ii->dat = sb; append_icode_list(il, ii); } void icode_make_alloca(struct reg *r, struct vreg *size_vr, struct stack_block *sb, struct icode_list *il) { struct allocadata *a = n_xmalloc(sizeof *a); struct icode_instr *ii = alloc_icode_instr(); /* * First we unconditionally free the hidden pointer slot * for this allocation. Such that * * for (i = 0; i < 10; ++i) { * void *p = __builtin_alloca(20); * * ... always performs a free() before overwriting the * saved pointer with a newly allocated one. This is OK * even at the first call because the save area is * initialized to all-null-pointers, and free(NULL) is ok * * XXX 08/09/07: This is completely wrong. Removed the * free, thus repeated allocas leak memory now. But better * than not having it work at all */ backend->invalidate_gprs(il, 1); #if 0 icode_make_dealloca(sb, il); #endif reg_set_unallocatable(r); vreg_faultin(NULL, NULL, size_vr, il, 0); a->result_reg = r; a->size_reg = size_vr->pregs[0]; a->addr = sb; ii->dat = a; ii->type = INSTR_ALLOCA; /* * Because the current implementation is carried out * using malloc() and free(), we have to save all * registers except for the size argument register! */ a->result_reg->used = 0; a->size_reg->used = 0; reg_set_allocatable(r); backend->invalidate_gprs(il, 1); append_icode_list(il, ii); #if 0 store_reg_to_stack_block(a->result_reg, a->addr); #endif } void icode_make_dealloc_vla(struct stack_block *sb, struct icode_list *il) { struct icode_instr *ii = alloc_icode_instr(); struct type *st; st = backend->get_size_t(); #if 0 r = backend->get_abi_reg(0, st); if (r == NULL) { r = ALLOC_GPR(curfunc, backend->get_sizeof_type(st, 0), il, 0); } #endif ii->type = INSTR_DEALLOC_VLA; #if 0 ii->src_pregs = make_icode_pregs(NULL, r); #endif ii->dat = sb; append_icode_list(il, ii); } void icode_make_alloc_vla( struct stack_block *sb, struct icode_list *il) { struct allocadata *a = n_xmalloc(sizeof *a); struct icode_instr *ii = alloc_icode_instr(); /* * First we unconditionally free the hidden pointer slot * for this allocation. Such that * * for (i = 0; i < 10; ++i) { * void *p = __builtin_alloca(20); * * ... always performs a free() before overwriting the * saved pointer with a newly allocated one. This is OK * even at the first call because the save area is * initialized to all-null-pointers, and free(NULL) is ok */ backend->invalidate_gprs(il, 1); icode_make_dealloc_vla(sb, il); ii->dat = sb; ii->type = INSTR_ALLOC_VLA; /* * Because the current implementation is carried out * using malloc() and free(), we have to save all * registers */ backend->invalidate_gprs(il, 1); append_icode_list(il, ii); } void icode_make_builtin_frame_address(struct reg *r, struct reg *r2, size_t *n, struct icode_list *il) { struct icode_instr *ii = alloc_icode_instr(); struct builtinframeaddressdata *dat = n_xmalloc(sizeof *dat); ii->type = INSTR_BUILTIN_FRAME_ADDRESS; dat->result_reg = r; dat->temp_reg = r2; dat->count = n; ii->dat = dat; append_icode_list(il, ii); } void icode_make_put_vla_whole_size(struct reg *size, struct stack_block *sb, struct icode_list *il) { struct icode_instr *ii = alloc_icode_instr(); struct vlasizedata *dat = n_xmalloc(sizeof *dat); ii->type = INSTR_PUT_VLA_SIZE; dat->size = size; dat->offset = backend->get_ptr_size(); dat->blockaddr = sb; ii->dat = dat; append_icode_list(il, ii); } void icode_make_put_vla_size(struct reg *size, struct stack_block *sb, int idx, struct icode_list *il) { struct icode_instr *ii = alloc_icode_instr(); struct vlasizedata *dat = n_xmalloc(sizeof *dat); int offset; offset = backend->get_ptr_size() + (1 + idx) * backend->get_sizeof_type( make_basic_type(TY_ULONG), NULL); ii->type = INSTR_PUT_VLA_SIZE; dat->size = size; dat->blockaddr = sb; dat->offset = offset; ii->dat = dat; append_icode_list(il, ii); } struct vreg * icode_make_retr_vla_size(struct reg *size, struct stack_block *sb, int idx, struct icode_list *il) { struct icode_instr *ii = alloc_icode_instr(); struct vlasizedata *dat = n_xmalloc(sizeof *dat); struct vreg *ret; int offset; offset = backend->get_ptr_size() + (1 + idx) * backend->get_sizeof_type( make_basic_type(TY_ULONG), NULL); ii->type = INSTR_RETR_VLA_SIZE; dat->size = size; dat->blockaddr = sb; dat->offset = offset; ii->dat = dat; append_icode_list(il, ii); ret = vreg_alloc(NULL, NULL, NULL, NULL); vreg_set_new_type(ret, make_basic_type(TY_ULONG)); vreg_map_preg(ret, size); return ret; } void icode_make_allocstack(struct vreg *vr, size_t size, struct icode_list *il) { struct icode_instr *ii = alloc_icode_instr(); struct allocstack *as = n_xmalloc(sizeof *as); as->nbytes = size; as->patchme = vr; ii->type = INSTR_ALLOCSTACK; ii->dat = as; append_icode_list(il, ii); } /* * XXX should this really deal with multi-gpr objects?! */ struct icode_instr * icode_make_cmp(struct vreg *dest, struct vreg *src) { struct icode_instr *ret = alloc_icode_instr(); ret->type = INSTR_CMP; ret->dest_vreg = dest; ret->dest_pregs = make_icode_pregs(dest, NULL); if (src != NULL) { ret->src_pregs = make_icode_pregs(src, NULL); ret->src_vreg = src; } return ret; } void icode_make_extend_sign(struct vreg *vr, struct type *to, struct type *from, struct icode_list *il) { struct icode_instr *ret = alloc_icode_instr(); struct extendsign *data = n_xmalloc(sizeof *data); data->dest_preg = vr->pregs[0]; data->dest_type = to; data->src_type = from; ret->dat = data; ret->type = INSTR_EXTEND_SIGN; append_icode_list(il, ret); } /* XXX misleading order of to/from :/ */ void icode_make_conv_fp(struct reg *destr, struct reg *srcr, struct type *to, struct type *from, struct icode_list *il) { struct icode_instr *ret = alloc_icode_instr(); struct extendsign *data = n_xmalloc(sizeof *data); data->dest_preg = destr; data->src_preg = srcr; data->dest_type = to; data->src_type = from; ret->dat = data; ret->type = INSTR_CONV_FP; append_icode_list(il, ret); } struct icode_instr * icode_make_jump(struct icode_instr *label) { struct icode_instr *ret = alloc_icode_instr(); ret->type = INSTR_JUMP; ret->dat = label; return ret; } void put_label_scope(struct label *l) { struct statement *stmt; stmt = alloc_statement(); stmt->type = ST_LABEL; stmt->data = l; append_statement( &curscope->code, &curscope->code_tail, stmt); append_label_list(&curfunc->labels_head, &curfunc->labels_tail, l); } void put_expr_scope(struct expr *e) { struct statement *stmt; stmt = alloc_statement(); stmt->type = ST_CODE; stmt->data = e; append_statement(&curscope->code, &curscope->code_tail, stmt); } void put_ctrl_scope(struct control *c) { struct statement *stmt; stmt = alloc_statement(); stmt->type = ST_CTRL; stmt->data = c; append_statement(&curscope->code, &curscope->code_tail, stmt); } /* * XXX acts as fxch for x86 fp...is this ok? */ void icode_make_copyreg( struct reg *dest, struct reg *src, struct type *desttype, struct type *srctype, struct icode_list *il) { struct icode_instr *ii = alloc_icode_instr(); struct copyreg *cr = n_xmalloc(sizeof *cr); cr->src_preg = src; cr->dest_preg = dest; cr->src_type = srctype; cr->dest_type = desttype; ii->type = INSTR_MOV; ii->dat = cr; append_icode_list(il, ii); }