From: Matthias Braun Date: Fri, 31 Aug 2007 14:53:11 +0000 (+0000) Subject: forgot these 2 files in my last committ X-Git-Url: http://nsz.repo.hu/git/?a=commitdiff_plain;h=3b30943ac5097c10b4d681189b80d8d0e694ac7c;p=libfirm forgot these 2 files in my last committ [r15644] --- diff --git a/ir/be/ia32/ia32_address_mode.c b/ir/be/ia32/ia32_address_mode.c new file mode 100644 index 000000000..72f204a6c --- /dev/null +++ b/ir/be/ia32/ia32_address_mode.c @@ -0,0 +1,335 @@ +/* + * Copyright (C) 1995-2007 University of Karlsruhe. All right reserved. + * + * This file is part of libFirm. + * + * This file may be distributed and/or modified under the terms of the + * GNU General Public License version 2 as published by the Free Software + * Foundation and appearing in the file LICENSE.GPL included in the + * packaging of this file. + * + * Licensees holding valid libFirm Professional Edition licenses may use + * this file in accordance with the libFirm Commercial License. + * Agreement provided with the Software. + * + * This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE + * WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE. + */ + +/** + * @file + * @brief This file contains functions for matching firm graphs for + * nodes that can be used as addressmode for x86 commands + * @author Matthias Braun + * @version $Id: ia32_transform.c 15462 2007-08-03 16:50:59Z matze $ + */ +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "ia32_address_mode.h" + +#include "irtypes.h" +#include "irnode_t.h" +#include "irprintf.h" +#include "error.h" +#include "iredges_t.h" + +#include "../benode_t.h" + +#undef AGGRESSIVE_AM + +static int is_immediate_2(const ir_node *node, int *symconsts) +{ + ir_node *left; + ir_node *right; + + switch(get_irn_opcode(node)) { + case iro_Const: + if(!tarval_is_long(get_Const_tarval(node))) { +#ifdef DEBUG_libfirm + ir_fprintf(stderr, "Optimisation warning tarval of %+F is not a " + "long."); +#endif + return 0; + } + return 1; + case iro_SymConst: + if(get_SymConst_kind(node) != symconst_addr_ent) + return 0; + (*symconsts)++; + if(*symconsts > 1) + return 0; + + return 1; + case iro_Add: + case iro_Sub: + left = get_binop_left(node); + right = get_binop_right(node); + if(!is_immediate_2(left, symconsts)) + return 0; + if(!is_immediate_2(right, symconsts)) + return 0; + + return 1; + default: + break; + } + + return 0; +} + +static int is_immediate(ia32_address_t *addr, const ir_node *node) +{ + int symconsts = 0; + if(addr->symconst_ent != NULL) + symconsts = 1; + + return is_immediate_2(node, &symconsts); +} + +static void eat_immediate(ia32_address_t *addr, ir_node *node, int negate) +{ + tarval *tv; + ir_node *left; + ir_node *right; + + switch(get_irn_opcode(node)) { + case iro_Const: + tv = get_Const_tarval(node); + if(negate) { + addr->offset -= get_tarval_long(tv); + } else { + addr->offset += get_tarval_long(tv); + } + break; + case iro_SymConst: + if(addr->symconst_ent != NULL) { + panic("Internal error: more than 1 symconst in address " + "calculation"); + } + addr->symconst_ent = get_SymConst_entity(node); + addr->symconst_sign = negate; + break; + case iro_Add: + left = get_Add_left(node); + right = get_Add_right(node); + eat_immediate(addr, left, negate); + eat_immediate(addr, right, negate); + break; + case iro_Sub: + left = get_Sub_left(node); + right = get_Sub_right(node); + eat_immediate(addr, left, negate); + eat_immediate(addr, right, !negate); + break; + default: + panic("Internal error in immediate address calculation"); + } +} + +static ir_node *eat_immediates(ia32_address_t *addr, ir_node *node, int force) +{ + if(is_Add(node)) { + ir_node *left = get_Add_left(node); + ir_node *right = get_Add_right(node); + +#if 0 +#ifndef AGGRESSIVE_AM + if(!force && get_irn_n_edges(node) > 1) + return node; +#else + (void) force; +#endif +#endif + + if(is_immediate(addr, left)) { + eat_immediate(addr, left, 0); + return eat_immediates(addr, right, 0); + } + if(is_immediate(addr, right)) { + eat_immediate(addr, right, 0); + return eat_immediates(addr, left, 0); + } + } else if(is_Sub(node)) { + ir_node *left = get_Sub_left(node); + ir_node *right = get_Sub_right(node); + +#if 0 +#ifndef AGGRESSIVE_AM + if(!force && get_irn_n_edges(node) > 1) + return node; +#endif +#endif + + if(is_immediate(addr, right)) { + eat_immediate(addr, right, 1); + return eat_immediates(addr, left, 0); + } + } + + return node; +} + +static int eat_shl(ia32_address_t *addr, ir_node *node) +{ + ir_node *right = get_Shl_right(node); + tarval *tv; + long val; + + /* we can only eat a shl if we don't have a scale or index set */ + if(addr->scale != 0 || addr->index != NULL) + return 0; + + /* we can use shl with 1, 2 or 3 shift */ + if(!is_Const(right)) + return 0; + tv = get_Const_tarval(right); + if(!tarval_is_long(tv)) + return 0; + val = get_tarval_long(tv); + if(val < 0 || val > 3) + return 0; + if(val == 0) { + ir_fprintf(stderr, "Optimisation warning: unoptimized Shl(,0) found\n"); + } + +#ifndef AGGRESSIVE_AM + if(get_irn_n_edges(node) > 1) + return 0; +#endif + + addr->scale = val; + addr->index = eat_immediates(addr, get_Shl_left(node), 0); + return 1; +} + +void ia32_create_address_mode(ia32_address_t *addr, ir_node *node, int force) +{ + int res = 0; + ir_node *eat_imms; + + if(is_immediate(addr, node)) { + eat_immediate(addr, node, 0); + return; + } + +#ifndef AGGRESSIVE_AM + if(!force && get_irn_n_edges(node) > 1) { + addr->base = node; + return; + } +#endif + + eat_imms = eat_immediates(addr, node, force); + if(eat_imms != node) { + res = 1; + node = eat_imms; +#ifndef AGGRESSIVE_AM + if(get_irn_n_edges(node) > 1) { + addr->base = node; + return; + } +#endif + } + + /* starting point Add, Sub or Shl, FrameAddr */ + if(is_Shl(node)) { + if(eat_shl(addr, node)) + return; + } else if(is_immediate(addr, node)) { + eat_immediate(addr, node, 0); + return; + } else if(be_is_FrameAddr(node)) { + assert(addr->base == NULL); + assert(addr->frame_entity == NULL); + addr->base = be_get_FrameAddr_frame(node); + addr->use_frame = 1; + addr->frame_entity = be_get_FrameAddr_entity(node); + return; + } else if(is_Add(node)) { + ir_node *left = get_Add_left(node); + ir_node *right = get_Add_right(node); + assert(force || !is_immediate(addr, left)); + assert(force || !is_immediate(addr, right)); + + if(is_Shl(left) && eat_shl(addr, left)) { + left = NULL; + } else if(is_Shl(right) && eat_shl(addr, right)) { + right = NULL; + } + if(left != NULL && be_is_FrameAddr(left)) { + assert(addr->base == NULL); + assert(addr->frame_entity == NULL); + addr->base = be_get_FrameAddr_frame(left); + addr->use_frame = 1; + addr->frame_entity = be_get_FrameAddr_entity(left); + left = NULL; + } else if(right != NULL && be_is_FrameAddr(right)) { + assert(addr->base == NULL); + assert(addr->frame_entity == NULL); + addr->base = be_get_FrameAddr_frame(right); + addr->use_frame = 1; + addr->frame_entity = be_get_FrameAddr_entity(right); + right = NULL; + } + + if(left != NULL) { + if(addr->base != NULL) { + assert(addr->index == NULL && addr->scale == 0); + assert(right == NULL); + addr->index = left; + } else { + addr->base = left; + } + } + if(right != NULL) { + if(addr->base == NULL) { + addr->base = right; + } else { + assert(addr->index == NULL && addr->scale == 0); + addr->index = right; + } + } + return; + } + + addr->base = node; +} + + +typedef struct mark_evn_t mark_evn_t; +struct mark_evn_t { + bitset_t *non_address_nodes; +}; + + +static void mark_non_address_nodes(mark_evn_t *env, ir_node *node) +{ + bitset_set(env->non_address_nodes, get_irn_idx(node)); + + if(is_Load(node)) { + ir_node *ptr = get_Load_ptr(node); + ir_node *mem = get_Load_mem(node); + + mark_non_address_nodes(env, mem); + (void) ptr; + } else if(is_Store(node)) { + ir_node *val = get_Store_value(node); + ir_node *ptr = get_Store_ptr(node); + ir_node *mem = get_Store_mem(node); + + mark_non_address_nodes(env, val); + mark_non_address_nodes(env, mem); + (void) ptr; + } else { + int i; + int arity = get_irn_arity(node); + + for(i = 0; i < arity; ++i) { + ir_node *in = get_irn_n(node, i); + mark_non_address_nodes(env, in); + } + } +} diff --git a/ir/be/ia32/ia32_address_mode.h b/ir/be/ia32/ia32_address_mode.h new file mode 100644 index 000000000..59cd30c7b --- /dev/null +++ b/ir/be/ia32/ia32_address_mode.h @@ -0,0 +1,47 @@ +/* + * Copyright (C) 1995-2007 University of Karlsruhe. All right reserved. + * + * This file is part of libFirm. + * + * This file may be distributed and/or modified under the terms of the + * GNU General Public License version 2 as published by the Free Software + * Foundation and appearing in the file LICENSE.GPL included in the + * packaging of this file. + * + * Licensees holding valid libFirm Professional Edition licenses may use + * this file in accordance with the libFirm Commercial License. + * Agreement provided with the Software. + * + * This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE + * WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE. + */ + +/** + * @file + * @brief This file contains functions for matching firm graphs for + * nodes that can be used as addressmode for x86 commands + * @author Matthias Braun + * @version $Id: ia32_transform.c 15462 2007-08-03 16:50:59Z matze $ + */ +#ifndef IA32_ADDRESS_MODE_H +#define IA32_ADDRESS_MODE_H + +#include "irtypes.h" + +typedef struct ia32_address_t ia32_address_t; +struct ia32_address_t { + ir_node *base; + ir_node *index; + ir_node *mem; + int offset; + int scale; + ir_entity *symconst_ent; + int use_frame; + ir_entity *frame_entity; + int symconst_sign; +}; + +void ia32_create_address_mode(ia32_address_t *addr, ir_node *node, int force); + +#endif