arm_finish.c 5.43 KB
Newer Older
1
2
3
4
5
6
7
8
9
10
11
12
/*
 * This file is part of libFirm.
 * Copyright (C) 2014 University of Karlsruhe.
 */

/**
 * @file
 * @brief   arm graph touchups before emitting
 * @author  Matthias Braun
 */
#include "bearch_arm_t.h"

13
14
#include "arm_new_nodes.h"
#include "arm_optimize.h"
15
16
17
#include "beirg.h"
#include "benode.h"
#include "besched.h"
18
19
20
21
#include "bespillslots.h"
#include "bestack.h"
#include "be_types.h"
#include "firm_types.h"
22
#include "gen_arm_regalloc_if.h"
23
#include "iredges_t.h"
24
25
#include "irgwalk.h"
#include "panic.h"
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

static bool is_frame_load(const ir_node *node)
{
	return is_arm_Ldr(node) || is_arm_Ldf(node);
}

static void arm_collect_frame_entity_nodes(ir_node *node, void *data)
{
	if (!is_frame_load(node))
		return;

	const arm_load_store_attr_t *attr = get_arm_load_store_attr_const(node);
	if (!attr->is_frame_entity)
		return;
	const ir_entity *entity = attr->entity;
	if (entity != NULL)
		return;
	const ir_mode *mode = attr->load_store_mode;
	const ir_type *type = get_type_for_mode(mode);

	be_fec_env_t *env = (be_fec_env_t*)data;
	be_load_needs_frame_entity(env, node, type);
}

static void arm_set_frame_entity(ir_node *node, ir_entity *entity,
                                 const ir_type *type)
{
	(void)type;
	arm_load_store_attr_t *attr = get_arm_load_store_attr(node);
	attr->entity = entity;
}

static void introduce_epilog(ir_node *ret)
{
	arch_register_t const *const sp_reg = &arm_registers[REG_SP];
	assert(arch_get_irn_register_req_in(ret, n_arm_Return_sp) == sp_reg->single_req);

	ir_node  *const sp         = get_irn_n(ret, n_arm_Return_sp);
	ir_node  *const block      = get_nodes_block(ret);
	ir_graph *const irg        = get_irn_irg(ret);
	ir_type  *const frame_type = get_irg_frame_type(irg);
67
	unsigned  const frame_size = get_type_size(frame_type);
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
	ir_node  *const incsp      = be_new_IncSP(sp_reg, block, sp, -frame_size, 0);
	set_irn_n(ret, n_arm_Return_sp, incsp);
	sched_add_before(ret, incsp);
}

static void introduce_prolog_epilog(ir_graph *irg)
{
	/* introduce epilog for every return node */
	foreach_irn_in(get_irg_end_block(irg), i, ret) {
		assert(is_arm_Return(ret));
		introduce_epilog(ret);
	}

	const arch_register_t *sp_reg     = &arm_registers[REG_SP];
	ir_node               *start      = get_irg_start(irg);
	ir_node               *block      = get_nodes_block(start);
Christoph Mallon's avatar
Christoph Mallon committed
84
	ir_node               *initial_sp = be_get_Start_proj(irg, sp_reg);
85
	ir_type               *frame_type = get_irg_frame_type(irg);
86
	unsigned               frame_size = get_type_size(frame_type);
87
88
89

	ir_node *const incsp = be_new_IncSP(sp_reg, block, initial_sp, frame_size, 0);
	edges_reroute_except(initial_sp, incsp, incsp);
90
	sched_add_after(start, incsp);
91
92
}

93
94
static int get_first_same(const arch_register_req_t* req)
{
95
	const unsigned other = req->should_be_same;
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
	for (int i = 0; i < 32; ++i) {
		if (other & (1U << i))
			return i;
	}
	panic("same position not found");
}

static void fix_should_be_same(ir_node *block, void *data)
{
	(void)data;
	sched_foreach(block, node) {
		/* ignore non-arm nodes like Copy */
		if (!is_arm_irn(node))
			continue;

		be_foreach_out(node, i) {
			const arch_register_req_t *req
				= arch_get_irn_register_req_out(node, i);
114
			if (req->should_be_same == 0)
115
116
117
118
119
120
121
122
123
124
125
126
127
128
				continue;

			int same_pos = get_first_same(req);

			const arch_register_t *out_reg = arch_get_irn_register_out(node, i);
			ir_node               *in_node = get_irn_n(node, same_pos);
			const arch_register_t *in_reg  = arch_get_irn_register(in_node);
			if (in_reg == out_reg)
				continue;
			panic("arm: should_be_same fixup not implemented yet");
		}
	}
}

129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
/**
 * This function is called by the generic backend to correct offsets for
 * nodes accessing the stack.
 */
static void arm_set_frame_offset(ir_node *irn, int bias)
{
	if (be_is_MemPerm(irn)) {
		be_set_MemPerm_offset(irn, bias);
	} else if (is_arm_FrameAddr(irn)) {
		arm_Address_attr_t *attr = get_arm_Address_attr(irn);
		attr->fp_offset += bias;
	} else {
		arm_load_store_attr_t *attr = get_arm_load_store_attr(irn);
		assert(attr->base.is_load_store);
		attr->offset += bias;
	}
}

static int arm_get_sp_bias(const ir_node *node)
{
	(void)node;
	return 0;
}

153
154
155
156
static ir_entity *arm_get_frame_entity(const ir_node *irn)
{
	if (be_is_MemPerm(irn))
		return be_get_MemPerm_in_entity(irn, 0);
157
158
	if (!is_arm_irn(irn))
		return NULL;
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
	const arm_attr_t *attr = get_arm_attr_const(irn);
	if (is_arm_FrameAddr(irn)) {
		const arm_Address_attr_t *frame_attr = get_arm_Address_attr_const(irn);
		return frame_attr->entity;
	}
	if (attr->is_load_store) {
		const arm_load_store_attr_t *load_store_attr
			= get_arm_load_store_attr_const(irn);
		if (load_store_attr->is_frame_entity) {
			return load_store_attr->entity;
		}
	}
	return NULL;
}

174
175
176
177
178
179
180
181
182
183
184
185
186
void arm_finish_graph(ir_graph *irg)
{
	be_stack_layout_t *stack_layout = be_get_irg_stack_layout(irg);
	bool               at_begin     = stack_layout->sp_relative;
	be_fec_env_t      *fec_env      = be_new_frame_entity_coalescer(irg);

	irg_walk_graph(irg, NULL, arm_collect_frame_entity_nodes, fec_env);
	be_assign_entities(fec_env, arm_set_frame_entity, at_begin);
	be_free_frame_entity_coalescer(fec_env);

	introduce_prolog_epilog(irg);

	/* fix stack entity offsets */
187
	be_fix_stack_nodes(irg, &arm_registers[REG_SP]);
188
	be_birg_from_irg(irg)->non_ssa_regs = NULL;
189
190
	be_abi_fix_stack_bias(irg, arm_get_sp_bias, arm_set_frame_offset,
	                      arm_get_frame_entity);
191
192
193

	/* do peephole optimizations and fix stack offsets */
	arm_peephole_optimization(irg);
194
195

	irg_block_walk_graph(irg, NULL, fix_should_be_same, NULL);
196
}