summaryrefslogtreecommitdiffhomepage
path: root/ir/be/ia32/x86_address_mode.h
blob: d28e6b01dba8e95781e867f1eb4aad2502d557f1 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
/*
 * This file is part of libFirm.
 * Copyright (C) 2012 University of Karlsruhe.
 */

/**
 * @file
 * @brief       This file contains functions for matching firm graphs for
 *              nodes that can be used as address mode for x86 instructions
 * @author      Matthias Braun
 */
#ifndef X86_ADDRESS_MODE_H
#define X86_ADDRESS_MODE_H

#include <stdbool.h>
#include <stdint.h>
#include "x86_node.h"

typedef enum x86_addr_variant_t {
	X86_ADDR_INVALID,
	X86_ADDR_REG,
	X86_ADDR_JUST_IMM,
	X86_ADDR_BASE,
	X86_ADDR_BASE_INDEX,
	X86_ADDR_INDEX,
	X86_ADDR_RIP,
} x86_addr_variant_t;

char const *x86_get_addr_variant_str(x86_addr_variant_t);

static inline bool x86_addr_variant_has_base(x86_addr_variant_t const variant)
{
	return variant == X86_ADDR_BASE || variant == X86_ADDR_BASE_INDEX;
}

static inline bool x86_addr_variant_has_index(x86_addr_variant_t const variant)
{
	return variant == X86_ADDR_INDEX || variant == X86_ADDR_BASE_INDEX;
}

/**
 * The address mode data: Used to match (memory) address mode patterns.
 */
typedef struct x86_address_t {
	ir_node    *base;            /**< value for base register (if any) */
	ir_node    *index;           /**< value for index register (if any). */
	ir_node    *mem;             /**< value for memory input (if any). */
	x86_imm32_t imm;
	unsigned   scale       : 8; /**< An integer scale. {0,1,2,3} */
	ENUMBF(x86_addr_variant_t) variant : 8; /**< Address mode variant */
	bool       tls_segment : 1; /**< Set if AM is relative to TLS */
	bool       ip_base     : 1; /**< Base is instruction pointer (IP) */
} x86_address_t;

/**
 * Additional flags for the address mode creation.
 */
typedef enum x86_create_am_flags_t {
	x86_create_am_normal     = 0,
	/** Ignore non-address-mode markings on the root node. */
	x86_create_am_force      = 1U << 0,
	/** Fold AM, even if the root node has two users. */
	x86_create_am_double_use = 1U << 1,
} x86_create_am_flags_t;

typedef enum x86_segment_selector_t {
	X86_SEGMENT_DEFAULT,
	X86_SEGMENT_CS,
	X86_SEGMENT_SS,
	X86_SEGMENT_DS,
	X86_SEGMENT_ES,
	X86_SEGMENT_FS,
	X86_SEGMENT_GS,
} x86_segment_selector_t;

/**
 * Address mode data. Used as node attribute for nodes supporting address mode.
 */
typedef struct x86_addr_t {
	x86_imm32_t immediate;
	uint8_t     base_input;
	uint8_t     index_input;
	uint8_t     mem_input;
	unsigned    log_scale : 2; /* 0, 1, 2, 3  (giving scale 1, 2, 4, 8) */
	ENUMBF(x86_segment_selector_t) segment : 3;
	ENUMBF(x86_addr_variant_t)     variant : 3;
} x86_addr_t;

static inline bool x86_addrs_equal(const x86_addr_t *const addr0,
                                   const x86_addr_t *const addr1)
{
	return x86_imm32_equal(&addr0->immediate, &addr1->immediate)
	    && addr0->variant == addr1->variant
	    && (!x86_addr_variant_has_base(addr0->variant)
	        || addr0->base_input == addr1->base_input)
	    && (!x86_addr_variant_has_index(addr0->variant)
	        || (addr0->index_input == addr1->index_input
	            && addr0->log_scale == addr1->log_scale))
	    && addr0->segment == addr1->segment;
}

/**
 * Create an address mode for a given node.
 */
void x86_create_address_mode(x86_address_t *addr, ir_node *node,
                             x86_create_am_flags_t);

/**
 * Mark those nodes of the given graph that cannot be used inside an
 * address mode because there values must be materialized in registers.
 */
void x86_calculate_non_address_mode_nodes(ir_graph *irg);

/**
 * Free the non_address_mode information.
 */
void x86_free_non_address_mode_nodes(void);

/**
 * Tells whether the given node is a non address mode node.
 */
bool x86_is_non_address_mode_node(ir_node const *node);

/**
 * mark a node so it will not be used as part of address modes
 */
void x86_mark_non_am(ir_node *node);

/**
 * Emit address in gnu assembler syntax.
 */
void x86_emit_addr(ir_node const *node, x86_addr_t const *addr);

#endif