Commit 48563c75 authored by Matthias Braun's avatar Matthias Braun
Browse files

x86_address_mode: Recognize pc-relative relocations

PC relative relocations need %rip as base register so we cannot match
anything else for base.
parent 672a3898
...@@ -41,15 +41,16 @@ static bool tarval_possible(ir_tarval *tv) ...@@ -41,15 +41,16 @@ static bool tarval_possible(ir_tarval *tv)
return val == (long)val32; return val == (long)val32;
} }
static bool eat_imm(x86_address_t *const addr, ir_node const *const node) static bool eat_imm(x86_address_t *const addr, ir_node const *const node,
bool basereg_usable)
{ {
switch (get_irn_opcode(node)) { switch (get_irn_opcode(node)) {
case iro_Add: case iro_Add:
/* Add is supported as long as both operands are immediates. */ /* Add is supported as long as both operands are immediates. */
return return
!x86_is_non_address_mode_node(node) && !x86_is_non_address_mode_node(node) &&
eat_imm(addr, get_Add_left(node)) && eat_imm(addr, get_Add_left(node), basereg_usable) &&
eat_imm(addr, get_Add_right(node)); eat_imm(addr, get_Add_right(node), basereg_usable);
case iro_Address: case iro_Address:
/* The first Address of a DAG can be folded into an immediate. */ /* The first Address of a DAG can be folded into an immediate. */
...@@ -79,7 +80,14 @@ static bool eat_imm(x86_address_t *const addr, ir_node const *const node) ...@@ -79,7 +80,14 @@ static bool eat_imm(x86_address_t *const addr, ir_node const *const node)
if (addr->imm.entity) if (addr->imm.entity)
return false; return false;
addr->imm.entity = be_get_Relocation_entity(node); addr->imm.entity = be_get_Relocation_entity(node);
addr->imm.kind = (x86_immediate_kind_t)be_get_Relocation_kind(node); x86_immediate_kind_t const kind
= (x86_immediate_kind_t)be_get_Relocation_kind(node);
addr->imm.kind = kind;
if (kind == X86_IMM_GOTPCREL || kind == X86_IMM_PCREL) {
if (!basereg_usable)
return false;
addr->ip_base = true;
}
return true; return true;
} }
/* All other nodes are no immediates. */ /* All other nodes are no immediates. */
...@@ -95,10 +103,11 @@ static bool eat_imm(x86_address_t *const addr, ir_node const *const node) ...@@ -95,10 +103,11 @@ static bool eat_imm(x86_address_t *const addr, ir_node const *const node)
* *
* @return Whether the whole DAG at @p node could be matched as immediate. * @return Whether the whole DAG at @p node could be matched as immediate.
*/ */
static bool eat_immediate(x86_address_t *const addr, ir_node const *const node) static bool eat_immediate(x86_address_t *const addr, ir_node const *const node,
bool basereg_usable)
{ {
x86_address_t try_addr = *addr; x86_address_t try_addr = *addr;
if (eat_imm(&try_addr, node)) { if (eat_imm(&try_addr, node, basereg_usable)) {
*addr = try_addr; *addr = try_addr;
return true; return true;
} }
...@@ -115,7 +124,8 @@ static bool eat_immediate(x86_address_t *const addr, ir_node const *const node) ...@@ -115,7 +124,8 @@ static bool eat_immediate(x86_address_t *const addr, ir_node const *const node)
* @return the folded node * @return the folded node
*/ */
static ir_node *eat_immediates(x86_address_t *addr, ir_node *node, static ir_node *eat_immediates(x86_address_t *addr, ir_node *node,
x86_create_am_flags_t flags) x86_create_am_flags_t flags,
bool basereg_usable)
{ {
if (!(flags & x86_create_am_force) if (!(flags & x86_create_am_force)
&& x86_is_non_address_mode_node(node) && x86_is_non_address_mode_node(node)
...@@ -125,10 +135,12 @@ static ir_node *eat_immediates(x86_address_t *addr, ir_node *node, ...@@ -125,10 +135,12 @@ static ir_node *eat_immediates(x86_address_t *addr, ir_node *node,
if (is_Add(node)) { if (is_Add(node)) {
ir_node *left = get_Add_left(node); ir_node *left = get_Add_left(node);
ir_node *right = get_Add_right(node); ir_node *right = get_Add_right(node);
if (eat_immediate(addr, left)) if (eat_immediate(addr, left, basereg_usable))
return eat_immediates(addr, right, x86_create_am_normal); return eat_immediates(addr, right, x86_create_am_normal,
if (eat_immediate(addr, right)) basereg_usable);
return eat_immediates(addr, left, x86_create_am_normal); if (eat_immediate(addr, right, basereg_usable))
return eat_immediates(addr, left, x86_create_am_normal,
basereg_usable);
} else if (is_Member(node)) { } else if (is_Member(node)) {
assert(addr->imm.entity == NULL); assert(addr->imm.entity == NULL);
addr->imm.entity = get_Member_entity(node); addr->imm.entity = get_Member_entity(node);
...@@ -200,17 +212,17 @@ void x86_create_address_mode(x86_address_t *addr, ir_node *node, ...@@ -200,17 +212,17 @@ void x86_create_address_mode(x86_address_t *addr, ir_node *node,
x86_create_am_flags_t flags) x86_create_am_flags_t flags)
{ {
addr->imm.kind = X86_IMM_VALUE; addr->imm.kind = X86_IMM_VALUE;
if (eat_immediate(addr, node)) { if (eat_immediate(addr, node, true))
return; return;
}
assert(!addr->ip_base);
if (!(flags & x86_create_am_force) && x86_is_non_address_mode_node(node) if (!(flags & x86_create_am_force) && x86_is_non_address_mode_node(node)
&& (!(flags & x86_create_am_double_use) || get_irn_n_edges(node) > 2)) { && (!(flags & x86_create_am_double_use) || get_irn_n_edges(node) > 2)) {
addr->base = node; addr->base = node;
return; return;
} }
ir_node *eat_imms = eat_immediates(addr, node, flags); ir_node *eat_imms = eat_immediates(addr, node, flags, false);
if (eat_imms != node) { if (eat_imms != node) {
if (flags & x86_create_am_force) { if (flags & x86_create_am_force) {
eat_imms = be_skip_downconv(eat_imms, true); eat_imms = be_skip_downconv(eat_imms, true);
...@@ -229,7 +241,7 @@ void x86_create_address_mode(x86_address_t *addr, ir_node *node, ...@@ -229,7 +241,7 @@ void x86_create_address_mode(x86_address_t *addr, ir_node *node,
* instructions, because we want the former as Lea x, x, not Shl x, 1 */ * instructions, because we want the former as Lea x, x, not Shl x, 1 */
if (eat_shl(addr, node)) if (eat_shl(addr, node))
return; return;
} else if (eat_immediate(addr, node)) { } else if (eat_immediate(addr, node, true)) {
/* we can hit this case in x86_create_am_force mode */ /* we can hit this case in x86_create_am_force mode */
return; return;
} else if (is_Add(node)) { } else if (is_Add(node)) {
...@@ -240,8 +252,8 @@ void x86_create_address_mode(x86_address_t *addr, ir_node *node, ...@@ -240,8 +252,8 @@ void x86_create_address_mode(x86_address_t *addr, ir_node *node,
left = be_skip_downconv(left, true); left = be_skip_downconv(left, true);
right = be_skip_downconv(right, true); right = be_skip_downconv(right, true);
} }
left = eat_immediates(addr, left, flags); left = eat_immediates(addr, left, flags, false);
right = eat_immediates(addr, right, flags); right = eat_immediates(addr, right, flags, false);
if (eat_shl(addr, left)) { if (eat_shl(addr, left)) {
left = NULL; left = NULL;
...@@ -402,7 +414,8 @@ static void mark_non_address_nodes(ir_node *node, void *env) ...@@ -402,7 +414,8 @@ static void mark_non_address_nodes(ir_node *node, void *env)
* increase register pressure */ * increase register pressure */
x86_address_t addr; x86_address_t addr;
memset(&addr, 0, sizeof(addr)); memset(&addr, 0, sizeof(addr));
if (eat_immediate(&addr, left) || eat_immediate(&addr, right)) if (eat_immediate(&addr, left, false)
|| eat_immediate(&addr, right, false))
return; return;
/* Fold AM if any of the two operands does not die here. This duplicates /* Fold AM if any of the two operands does not die here. This duplicates
......
...@@ -28,6 +28,7 @@ typedef struct x86_address_t { ...@@ -28,6 +28,7 @@ typedef struct x86_address_t {
unsigned scale : 8; /**< An integer scale. {0,1,2,3} */ unsigned scale : 8; /**< An integer scale. {0,1,2,3} */
bool use_frame : 1; /**< Set, if the frame is accessed */ bool use_frame : 1; /**< Set, if the frame is accessed */
bool tls_segment : 1; /**< Set if AM is relative to TLS */ bool tls_segment : 1; /**< Set if AM is relative to TLS */
bool ip_base : 1; /**< Base is instruction pointer (IP) */
} x86_address_t; } x86_address_t;
/** /**
......
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