Commit 58ef2bef authored by Matthias Braun's avatar Matthias Braun
Browse files

move beabi/PIC code into ia32 backend

The code was only working on ia32 and contains several ia32 specific
bits, so keep it in the ia32 backend for now. At least the amd64 backend
will require a different implementation of PIC.
parent 57cc436b
......@@ -327,7 +327,6 @@ const arch_isa_if_t TEMPLATE_isa_if = {
TEMPLATE_init_graph,
TEMPLATE_get_call_abi,
NULL, /* mark remat */
NULL, /* get_pic_base */
be_new_spill,
be_new_reload,
TEMPLATE_register_saved_by,
......
......@@ -448,7 +448,6 @@ const arch_isa_if_t amd64_isa_if = {
NULL,
amd64_get_call_abi,
NULL, /* mark remat */
NULL, /* get_pic_base */
be_new_spill,
be_new_reload,
amd64_register_saved_by,
......
......@@ -518,7 +518,6 @@ const arch_isa_if_t arm_isa_if = {
NULL,
NULL, /* get call abi */
NULL, /* mark remat */
NULL, /* get_pic_base */
be_new_spill,
be_new_reload,
NULL, /* register_saved_by */
......
......@@ -1477,142 +1477,6 @@ static void fix_call_state_inputs(ir_graph *const irg, be_abi_irg_t *const env)
DEL_ARR_F(stateregs);
}
/**
* Create a trampoline entity for the given method.
*/
static ir_entity *create_trampoline(be_main_env_t *be, ir_entity *method)
{
ir_type *type = get_entity_type(method);
ident *old_id = get_entity_ld_ident(method);
ident *id = id_mangle3("", old_id, "$stub");
ir_type *parent = be->pic_trampolines_type;
ir_entity *ent = new_entity(parent, old_id, type);
set_entity_ld_ident(ent, id);
set_entity_visibility(ent, ir_visibility_private);
return ent;
}
/**
* Returns the trampoline entity for the given method.
*/
static ir_entity *get_trampoline(be_main_env_t *env, ir_entity *method)
{
ir_entity *result = pmap_get(ir_entity, env->ent_trampoline_map, method);
if (result == NULL) {
result = create_trampoline(env, method);
pmap_insert(env->ent_trampoline_map, method, result);
}
return result;
}
static ir_entity *create_pic_symbol(be_main_env_t *be, ir_entity *entity)
{
ident *old_id = get_entity_ld_ident(entity);
ident *id = id_mangle3("", old_id, "$non_lazy_ptr");
ir_type *e_type = get_entity_type(entity);
ir_type *type = new_type_pointer(e_type);
ir_type *parent = be->pic_symbols_type;
ir_entity *ent = new_entity(parent, old_id, type);
set_entity_ld_ident(ent, id);
set_entity_visibility(ent, ir_visibility_private);
return ent;
}
static ir_entity *get_pic_symbol(be_main_env_t *env, ir_entity *entity)
{
ir_entity *result = pmap_get(ir_entity, env->ent_pic_symbol_map, entity);
if (result == NULL) {
result = create_pic_symbol(env, entity);
pmap_insert(env->ent_pic_symbol_map, entity, result);
}
return result;
}
/**
* Returns non-zero if a given entity can be accessed using a relative address.
*/
static int can_address_relative(ir_entity *entity)
{
return entity_has_definition(entity) && !(get_entity_linkage(entity) & IR_LINKAGE_MERGE);
}
static ir_node *get_pic_base(ir_graph *irg)
{
const arch_env_t *arch_env = be_get_irg_arch_env(irg);
if (arch_env->impl->get_pic_base == NULL)
return NULL;
return arch_env->impl->get_pic_base(irg);
}
/** patches SymConsts to work in position independent code */
static void fix_pic_symconsts(ir_node *node, void *data)
{
(void) data;
ir_graph *irg = get_irn_irg(node);
be_main_env_t *be = be_get_irg_main_env(irg);
for (int i = 0, arity = get_irn_arity(node); i < arity; ++i) {
ir_node *pred = get_irn_n(node, i);
if (!is_SymConst(pred))
continue;
/* calls can jump to relative addresses, so we can directly jump to
the (relatively) known call address or the trampoline */
ir_entity *const entity = get_SymConst_entity(pred);
ir_node *const block = get_nodes_block(pred);
dbg_info *const dbgi = get_irn_dbg_info(pred);
if (i == 1 && is_Call(node)) {
if (can_address_relative(entity))
continue;
ir_entity *const trampoline = get_trampoline(be, entity);
ir_node *const trampoline_const
= new_rd_SymConst_addr_ent(dbgi, irg, mode_P_code, trampoline);
set_irn_n(node, i, trampoline_const);
continue;
} else if (get_entity_type(entity) == get_code_type()) {
/* block labels can always be addressed directly */
continue;
}
/* everything else is accessed relative to EIP */
ir_mode *const mode = get_irn_mode(pred);
ir_node *const pic_base = get_pic_base(irg);
/* all ok now for locally constructed stuff */
if (can_address_relative(entity)) {
ir_node *add = new_r_Add(block, pic_base, pred, mode);
/* make sure the walker doesn't visit this add again */
mark_irn_visited(add);
set_irn_n(node, i, add);
continue;
}
/* get entry from pic symbol segment */
ir_entity *const pic_symbol = get_pic_symbol(be, entity);
ir_node *const pic_symconst
= new_rd_SymConst_addr_ent(dbgi, irg, mode_P_code, pic_symbol);
ir_node *const add = new_r_Add(block, pic_base, pic_symconst, mode);
mark_irn_visited(add);
/* we need an extra indirection for global data outside our current
module. The loads are always safe and can therefore float
and need no memory input */
ir_node *const load
= new_r_Load(block, get_irg_no_mem(irg), add, mode, cons_floats);
ir_node *const load_res = new_r_Proj(load, mode, pn_Load_res);
set_irn_n(node, i, load_res);
}
}
void be_abi_introduce(ir_graph *irg)
{
ir_node *const old_frame = get_irg_frame(irg);
......@@ -1645,10 +1509,6 @@ void be_abi_introduce(ir_graph *irg)
assure_edges(irg);
if (be_options.pic) {
irg_walk_graph(irg, fix_pic_symconsts, NULL, NULL);
}
/* Lower all call nodes in the IRG. */
process_calls(irg, &env);
......
......@@ -431,11 +431,6 @@ struct arch_isa_if_t {
*/
void (*mark_remat)(ir_node *node);
/**
* return node used as base in pic code addresses
*/
ir_node* (*get_pic_base)(ir_graph *irg);
/**
* Create a spill instruction. We assume that spill instructions
* do not need any additional registers and do not affect cpu-flags in any
......
......@@ -453,6 +453,9 @@ static void ia32_before_abi(ir_graph *irg)
}
instrument_initcall(irg, mcount);
}
if (be_options.pic) {
ia32_adjust_pic(irg);
}
}
/**
......@@ -1141,24 +1144,6 @@ static void ia32_emit(ir_graph *irg)
}
}
/**
* Returns the node representing the PIC base.
*/
static ir_node *ia32_get_pic_base(ir_graph *irg)
{
ia32_irg_data_t *irg_data = ia32_get_irg_data(irg);
ir_node *block;
ir_node *get_eip = irg_data->get_eip;
if (get_eip != NULL)
return get_eip;
block = get_irg_start_block(irg);
get_eip = new_bd_ia32_GetEIP(NULL, block);
irg_data->get_eip = get_eip;
return get_eip;
}
/**
* Initializes a IA32 code generator.
*/
......@@ -1944,7 +1929,6 @@ const arch_isa_if_t ia32_isa_if = {
ia32_init_graph,
ia32_get_call_abi,
ia32_mark_remat,
ia32_get_pic_base, /* return node used as base in pic code addresses */
be_new_spill,
be_new_reload,
ia32_register_saved_by,
......
......@@ -136,4 +136,12 @@ ir_entity *ia32_get_return_address_entity(ir_graph *irg);
*/
ir_entity *ia32_get_frame_address_entity(ir_graph *irg);
/**
* creates global offset table (GOT) for position independent code (PIC) and
* adjusts address calculations for it.
*/
void ia32_adjust_pic(ir_graph *irg);
ir_node *ia32_get_pic_base(ir_graph *irg);
#endif
/*
* This file is part of libFirm.
* Copyright (C) 2013 University of Karlsruhe.
*/
/**
* @file
* @brief position independent code adjustments
* @author Matthias Braun
*/
#include "bearch_ia32_t.h"
#include "adt/pmap.h"
#include "bearch.h"
#include "begnuas.h"
#include "beirg.h"
#include "be_t.h"
#include "entity_t.h"
#include "ident_t.h"
#include "ircons_t.h"
#include "irgwalk.h"
#include "irnode_t.h"
/**
* Create a trampoline entity for the given method.
*/
static ir_entity *create_trampoline(be_main_env_t *be, ir_entity *method)
{
ir_type *type = get_entity_type(method);
ident *old_id = get_entity_ld_ident(method);
ident *id = id_mangle3("", old_id, "$stub");
ir_type *parent = be->pic_trampolines_type;
ir_entity *ent = new_entity(parent, old_id, type);
set_entity_ld_ident(ent, id);
set_entity_visibility(ent, ir_visibility_private);
return ent;
}
/**
* Returns the trampoline entity for the given method.
*/
static ir_entity *get_trampoline(be_main_env_t *env, ir_entity *method)
{
ir_entity *result = pmap_get(ir_entity, env->ent_trampoline_map, method);
if (result == NULL) {
result = create_trampoline(env, method);
pmap_insert(env->ent_trampoline_map, method, result);
}
return result;
}
static ir_entity *create_pic_symbol(be_main_env_t *be, ir_entity *entity)
{
ident *old_id = get_entity_ld_ident(entity);
ident *id = id_mangle3("", old_id, "$non_lazy_ptr");
ir_type *e_type = get_entity_type(entity);
ir_type *type = new_type_pointer(e_type);
ir_type *parent = be->pic_symbols_type;
ir_entity *ent = new_entity(parent, old_id, type);
set_entity_ld_ident(ent, id);
set_entity_visibility(ent, ir_visibility_private);
return ent;
}
static ir_entity *get_pic_symbol(be_main_env_t *env, ir_entity *entity)
{
ir_entity *result = pmap_get(ir_entity, env->ent_pic_symbol_map, entity);
if (result == NULL) {
result = create_pic_symbol(env, entity);
pmap_insert(env->ent_pic_symbol_map, entity, result);
}
return result;
}
/**
* Returns non-zero if a given entity can be accessed using a relative address.
*/
static int can_address_relative(ir_entity *entity)
{
return entity_has_definition(entity) && !(get_entity_linkage(entity) & IR_LINKAGE_MERGE);
}
/** patches SymConsts to work in position independent code */
static void fix_pic_symconsts(ir_node *node, void *data)
{
(void) data;
ir_graph *irg = get_irn_irg(node);
be_main_env_t *be = be_get_irg_main_env(irg);
for (int i = 0, arity = get_irn_arity(node); i < arity; ++i) {
ir_node *pred = get_irn_n(node, i);
if (!is_SymConst(pred))
continue;
/* calls can jump to relative addresses, so we can directly jump to
the (relatively) known call address or the trampoline */
ir_entity *const entity = get_SymConst_entity(pred);
ir_node *const block = get_nodes_block(pred);
dbg_info *const dbgi = get_irn_dbg_info(pred);
if (i == 1 && is_Call(node)) {
if (can_address_relative(entity))
continue;
ir_entity *const trampoline = get_trampoline(be, entity);
ir_node *const trampoline_const
= new_rd_SymConst_addr_ent(dbgi, irg, mode_P_code, trampoline);
set_irn_n(node, i, trampoline_const);
continue;
} else if (get_entity_type(entity) == get_code_type()) {
/* block labels can always be addressed directly */
continue;
}
/* everything else is accessed relative to EIP */
ir_mode *const mode = get_irn_mode(pred);
ir_node *const pic_base = ia32_get_pic_base(irg);
/* all ok now for locally constructed stuff */
if (can_address_relative(entity)) {
ir_node *add = new_r_Add(block, pic_base, pred, mode);
/* make sure the walker doesn't visit this add again */
mark_irn_visited(add);
set_irn_n(node, i, add);
continue;
}
/* get entry from pic symbol segment */
ir_entity *const pic_symbol = get_pic_symbol(be, entity);
ir_node *const pic_symconst
= new_rd_SymConst_addr_ent(dbgi, irg, mode_P_code, pic_symbol);
ir_node *const add = new_r_Add(block, pic_base, pic_symconst, mode);
mark_irn_visited(add);
/* we need an extra indirection for global data outside our current
module. The loads are always safe and can therefore float
and need no memory input */
ir_node *const load
= new_r_Load(block, get_irg_no_mem(irg), add, mode, cons_floats);
ir_node *const load_res = new_r_Proj(load, mode, pn_Load_res);
set_irn_n(node, i, load_res);
}
}
void ia32_adjust_pic(ir_graph *irg)
{
irg_walk_graph(irg, fix_pic_symconsts, NULL, NULL);
}
......@@ -162,6 +162,21 @@ static bool is_simple_sse_Const(ir_node *node)
return false;
}
ir_node *ia32_get_pic_base(ir_graph *irg)
{
ia32_irg_data_t *irg_data = ia32_get_irg_data(irg);
ir_node *block;
ir_node *get_eip = irg_data->get_eip;
if (get_eip != NULL)
return get_eip;
block = get_irg_start_block(irg);
get_eip = new_bd_ia32_GetEIP(NULL, block);
irg_data->get_eip = get_eip;
return get_eip;
}
/**
* return NoREG or pic_base in case of PIC.
* This is necessary as base address for newly created symbols
......@@ -171,8 +186,7 @@ static ir_node *get_symconst_base(void)
ir_graph *irg = current_ir_graph;
if (be_options.pic) {
const arch_env_t *arch_env = be_get_irg_arch_env(irg);
return arch_env->impl->get_pic_base(irg);
return ia32_get_pic_base(irg);
}
return noreg_GP;
......
......@@ -638,7 +638,6 @@ const arch_isa_if_t sparc_isa_if = {
NULL,
NULL, /* get call abi */
NULL, /* mark remat */
NULL, /* get_pic_base */
sparc_new_spill,
sparc_new_reload,
NULL, /* register_saved_by */
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment