static bool eat_imm(x86_address_t *const addr, ir_node const *const node, bool basereg_usable) { switch (get_irn_opcode(node)) { case iro_Add: /* Add is supported as long as both operands are immediates. */ return !x86_is_non_address_mode_node(node) && eat_imm(addr, get_Add_left(node), basereg_usable) && eat_imm(addr, get_Add_right(node), basereg_usable); case iro_Address: /* The first Address of a DAG can be folded into an immediate. */ if (addr->imm.entity) return false; addr->imm.entity = get_Address_entity(node); addr->imm.kind = X86_IMM_ADDR; if (is_tls_entity(addr->imm.entity)) addr->tls_segment = true; return true; case iro_Const: { /* Add the value to the offset. */ ir_tarval *const tv = get_Const_tarval(node); if (!tarval_possible(tv)) return false; addr->imm.offset += get_tarval_long(tv); return true; } case iro_Unknown: /* Use '0' for Unknowns. */ return true; default: if (be_is_Relocation(node)) { if (addr->imm.entity) return false; addr->imm.entity = be_get_Relocation_entity(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; } /* All other nodes are no immediates. */ return false; } }
/** * Place a DAG with root @p node into an address mode. * * @param addr the address mode data so far (only modified on success) * @param node the node * * @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) { x86_address_t try_addr = *addr; if (eat_imm(&try_addr, node)) { *addr = try_addr; return true; } return false; }