Commit 37ee70a9 authored by Matthias Braun's avatar Matthias Braun
Browse files

amd64: Redo PIC handling, introduce pic prep phase

parent 48563c75
......@@ -13,15 +13,13 @@ Correctness:
- Support ASM node
- fail on long double
- (Support 80bit long double with x87 instructions)
- Finish PIC code implementation. gen_Address / call with immediate should be
fine. However the address mode matcher must not treat GOTPCREL things as
addresses, we have to load from the GOT first. The easiest solution is
probably a preparation phase similar to ia32_pic.c that create loads.
- Finish PIC code implementation. This is mostly done now, usual accesses to
functions and variables including address mode matching looks fine now.
Jumptables are not accessed correctly in PIC yet and
Improve Quality:
- Immediate32 matching could be better and match SymConst, Add(SymConst, Const)
combinations where possible. Be careful with PIC code this may usually not
be legal!
combinations where possible.
- Support Destination Address Mode
- Match Immediate + Address mode for Cmp
- Support Read-Modify-Store operations (aka destination address mode)
......
......@@ -263,7 +263,7 @@ static void amd64_emit_addr(const ir_node *const node,
if (is_fp_relative(entity)) {
entity = NULL; /* only emit offset for frame entities */
} else {
be_gas_emit_entity(entity);
emit_relocation_no_offset(addr->immediate.kind, entity);
}
}
......
/*
* This file is part of libFirm.
* Copyright (C) 2015 Matthias Braun
*/
/**
* @file
* @brief position independent code adjustments
* @author Matthias Braun
*/
#include "bearch_amd64_t.h"
#include "be_t.h"
#include "beutil.h"
#include "entity_t.h"
#include "amd64_new_nodes.h"
#include "ircons_t.h"
#include "irgwalk.h"
#include "irnode_t.h"
#include "x86_imm.h"
static void fix_address_pic(ir_node *const node, void *const data)
{
(void)data;
foreach_irn_in(node, i, pred) {
if (!is_Address(pred))
continue;
ir_entity *const entity = get_Address_entity(pred);
if (is_tls_entity(entity))
continue;
ir_graph *const irg = get_irn_irg(node);
ir_node * res;
if (i == n_Call_ptr && is_Call(node)) {
// Somehow we can always call PC relative. Are there trampolines
// involved?
res = be_new_Relocation(irg, X86_IMM_PCREL, entity);
} else if (entity_has_definition(entity)
&& !(get_entity_linkage(entity) & IR_LINKAGE_MERGE)) {
res = be_new_Relocation(irg, X86_IMM_PCREL, entity);
} else {
ir_node *const addr
= be_new_Relocation(irg, X86_IMM_GOTPCREL, entity);
ir_type *const type = get_entity_type(entity);
ir_node *const nomem = get_irg_no_mem(irg);
ir_node *const block = get_irg_start_block(irg);
ir_node *const load = new_rd_Load(NULL, block, nomem, addr, mode_P,
type, cons_floats);
res = new_r_Proj(load, mode_P, pn_Load_res);
}
set_irn_n(node, i, res);
}
}
void amd64_adjust_pic(ir_graph *irg)
{
if (!be_options.pic)
return;
irg_walk_graph(irg, fix_address_pic, NULL, NULL);
be_dump(DUMP_BE, irg, "pic");
}
......@@ -303,22 +303,17 @@ ir_entity *create_float_const_entity(ir_tarval *const tv)
return entity;
}
typedef enum reference_mode_t {
REFERENCE_DIRECT,
REFERENCE_IP_RELATIVE,
REFERENCE_GOT,
} reference_mode_t;
static reference_mode_t need_relative_addressing(const ir_entity *entity)
static void init_lconst_addr(amd64_addr_t *addr, ir_entity *entity)
{
if (!be_options.pic)
return REFERENCE_DIRECT;
/* simply everything is instruction pointer relative, external functions
* use a global offset table */
return entity_has_definition(entity)
&& (get_entity_linkage(entity) & IR_LINKAGE_MERGE) == 0
? REFERENCE_IP_RELATIVE : REFERENCE_GOT;
assert(entity_has_definition(entity));
assert(get_entity_linkage(entity) == IR_LINKAGE_CONSTANT);
assert(get_entity_visibility(entity) == ir_visibility_private);
memset(addr, 0, sizeof(*addr));
x86_immediate_kind_t kind = be_options.pic ? X86_IMM_PCREL : X86_IMM_ADDR;
addr->immediate.entity = entity;
addr->immediate.kind = kind;
addr->index_input = NO_INPUT;
addr->base_input = kind == X86_IMM_PCREL ? RIP_INPUT : NO_INPUT;
}
static ir_node *create_float_const(dbg_info *dbgi, ir_node *block,
......@@ -331,21 +326,11 @@ static ir_node *create_float_const(dbg_info *dbgi, ir_node *block,
ir_node *in[] = { nomem };
amd64_addr_t addr;
memset(&addr, 0, sizeof(addr));
addr.immediate.entity = entity;
amd64_insn_mode_t insn_mode = get_insn_mode_from_mode(tv_mode);
addr.index_input = NO_INPUT;
if (need_relative_addressing(entity) == REFERENCE_DIRECT) {
addr.base_input = NO_INPUT;
} else {
assert(need_relative_addressing(entity) == REFERENCE_IP_RELATIVE);
addr.base_input = RIP_INPUT;
}
init_lconst_addr(&addr, entity);
ir_node *load;
unsigned pn_res;
amd64_insn_mode_t insn_mode = get_insn_mode_from_mode(tv_mode);
if (insn_mode == INSN_MODE_128) {
load = new_bd_amd64_movdqa(dbgi, block, ARRAY_SIZE(in), in,
AMD64_OP_ADDR, addr);
......@@ -403,40 +388,45 @@ static ir_node *gen_Address(ir_node *node)
dbg_info *dbgi = get_irn_dbg_info(node);
ir_entity *entity = get_Address_entity(node);
/* do we need RIP-relative addressing because of PIC? */
reference_mode_t mode = need_relative_addressing(entity);
if (mode == REFERENCE_DIRECT) {
amd64_imm64_t const imm = {
.kind = X86_IMM_ADDR,
.entity = entity,
};
return new_bd_amd64_mov_imm(dbgi, block, INSN_MODE_64, &imm);
}
amd64_imm64_t const imm = {
.kind = X86_IMM_ADDR,
.entity = entity,
};
return new_bd_amd64_mov_imm(dbgi, block, INSN_MODE_64, &imm);
}
amd64_addr_t addr;
memset(&addr, 0, sizeof(addr));
addr.base_input = RIP_INPUT;
addr.index_input = NO_INPUT;
addr.mem_input = NO_INPUT;
static ir_node *gen_be_Relocation(ir_node *node)
{
ir_node *const block = be_transform_nodes_block(node);
ir_entity *const entity = be_get_Relocation_entity(node);
x86_immediate_kind_t const kind
= (x86_immediate_kind_t)be_get_Relocation_kind(node);
if (mode == REFERENCE_IP_RELATIVE) {
addr.immediate = (x86_imm32_t) {
/* TODO: create an ip-relative kind? (even though it looks the same
* in the assembler) */
switch (kind) {
case X86_IMM_ADDR: {
amd64_imm64_t const imm = {
.kind = X86_IMM_ADDR,
.entity = entity,
};
return new_bd_amd64_lea(dbgi, block, 0, NULL, INSN_MODE_64, addr);
} else {
assert(mode == REFERENCE_GOT);
return new_bd_amd64_mov_imm(NULL, block, INSN_MODE_64, &imm);
}
case X86_IMM_PCREL:
case X86_IMM_GOTPCREL: { /* can GOTPCREL happen here? */
amd64_addr_t addr;
memset(&addr, 0, sizeof(addr));
addr.base_input = RIP_INPUT;
addr.index_input = NO_INPUT;
addr.mem_input = NO_INPUT;
addr.immediate = (x86_imm32_t) {
.kind = X86_IMM_GOTPCREL,
.kind = kind,
.entity = entity,
};
ir_node *load = new_bd_amd64_mov_gp(dbgi, block, 0, NULL, INSN_MODE_64,
AMD64_OP_ADDR, addr);
return be_new_Proj(load, pn_amd64_mov_gp_res);
return new_bd_amd64_lea(NULL, block, 0, NULL, INSN_MODE_64, addr);
}
default:
break;
}
panic("Unexpected relocation kind");
}
ir_node *amd64_new_IncSP(ir_node *block, ir_node *old_sp, int offset,
......@@ -503,12 +493,12 @@ static bool match_immediate_32(x86_imm32_t *imm, const ir_node *op,
x86_immediate_kind_t kind = (x86_immediate_kind_t)reloc_kind;
if (entity != NULL) {
if (!can_match_ip_relative) {
/* TODO: check if entity is in lower 4GB address space/relative */
if (!can_match_ip_relative)
return false;
if (kind == X86_IMM_VALUE || kind == X86_IMM_ADDR) {
kind = X86_IMM_PCREL;
} else if (kind != X86_IMM_PCREL)
return false;
}
if (kind == X86_IMM_VALUE)
kind = X86_IMM_ADDR;
}
imm->entity = entity;
......@@ -637,13 +627,7 @@ static void perform_address_matching(ir_node *ptr, int *arity,
addr->base_input = base_input;
in[base_input] = be_transform_node(maddr.base);
} else {
ir_entity *entity = maddr.imm.entity;
if (entity != NULL
&& need_relative_addressing(entity) != REFERENCE_DIRECT) {
addr->base_input = RIP_INPUT;
} else {
addr->base_input = NO_INPUT;
}
addr->base_input = maddr.ip_base ? RIP_INPUT : NO_INPUT;
}
if (maddr.index != NULL) {
int index_input = (*arity)++;
......@@ -2643,8 +2627,9 @@ static void amd64_register_transformers(void)
be_set_transform_function(op_Switch, gen_Switch);
be_set_transform_function(op_Unknown, gen_Unknown);
be_set_transform_function(op_amd64_l_punpckldq, gen_amd64_l_punpckldq);
be_set_transform_function(op_amd64_l_subpd, gen_amd64_l_subpd);
be_set_transform_function(op_amd64_l_haddpd, gen_amd64_l_haddpd);
be_set_transform_function(op_amd64_l_subpd, gen_amd64_l_subpd);
be_set_transform_function(op_be_Relocation, gen_be_Relocation);
be_set_transform_proj_function(op_Alloc, gen_Proj_Alloc);
be_set_transform_proj_function(op_Builtin, gen_Proj_Builtin);
......
......@@ -497,6 +497,8 @@ static int determine_rbp_input(ir_node *ret)
*/
static void amd64_select_instructions(ir_graph *irg)
{
amd64_adjust_pic(irg);
be_timer_push(T_CODEGEN);
amd64_transform_graph(irg);
be_timer_pop(T_CODEGEN);
......
......@@ -37,4 +37,6 @@ x86_cconv_t *amd64_decide_calling_convention(ir_type *function_type,
void amd64_cconv_init(void);
void amd64_adjust_pic(ir_graph *irg);
#endif
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