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

/**
 * @file
 * @brief       Implements several optimizations for ARM.
 * @author      Michael Beck
 */
#include "irgmod.h"
#include "ircons.h"
13
#include "iredges.h"
14
15
#include "error.h"

16
#include "benode.h"
17
18
19
20
21
22
#include "bepeephole.h"
#include "besched.h"

#include "arm_optimize.h"
#include "gen_arm_regalloc_if.h"
#include "gen_arm_new_nodes.h"
23
24
#include "arm_nodes_attr.h"
#include "arm_new_nodes.h"
25

Matthias Braun's avatar
Matthias Braun committed
26
static uint32_t arm_ror(uint32_t v, uint32_t ror)
27
28
{
	return (v << (32 - ror)) | (v >> ror);
29
30
31
}

/**
32
33
 * Returns non.zero if the given offset can be directly encoded into an ARM
 * instruction.
34
 */
Matthias Braun's avatar
Matthias Braun committed
35
static bool allowed_arm_immediate(int offset, arm_vals *result)
36
{
37
38
39
40
41
42
43
	arm_gen_vals_from_word(offset, result);
	return result->ops <= 1;
}

/**
 * Fix an IncSP node if the offset gets too big
 */
44
45
static void peephole_be_IncSP(ir_node *node)
{
46
	/* first optimize incsp->incsp combinations */
47
	node = be_peephole_IncSP_IncSP(node);
48

Matthias Braun's avatar
Matthias Braun committed
49
	int offset = be_get_IncSP_offset(node);
50
	/* can be transformed into Add OR Sub */
Matthias Braun's avatar
Matthias Braun committed
51
	int sign = 1;
52
53
54
55
	if (offset < 0) {
		sign = -1;
		offset = -offset;
	}
Matthias Braun's avatar
Matthias Braun committed
56
	arm_vals v;
57
58
59
	if (allowed_arm_immediate(offset, &v))
		return;

60
	be_set_IncSP_offset(node, sign * arm_ror(v.values[0], v.rors[0]));
61

Matthias Braun's avatar
Matthias Braun committed
62
63
64
	ir_node *first = node;
	ir_node *block = get_nodes_block(node);
	for (unsigned cnt = 1; cnt < v.ops; ++cnt) {
65
66
		int      value = sign * arm_ror(v.values[cnt], v.rors[cnt]);
		ir_node *incsp = be_new_IncSP(&arm_registers[REG_SP], block, node,
67
		                             value, 1);
68
69
		sched_add_after(node, incsp);
		node = incsp;
70
	}
71
72

	/* reattach IncSP users */
Matthias Braun's avatar
Matthias Braun committed
73
	ir_node *last = node;
74
	node = sched_next(first);
75
	foreach_out_edge_safe(first, edge) {
76
77
78
79
80
81
		ir_node *user = get_edge_src_irn(edge);
		int      pos  = get_edge_src_pos(edge);
		if (user == node)
			continue;
		set_irn_n(user, pos, last);
	}
82
83
84
85
86
}

/**
 * creates the address by Adds
 */
Matthias Braun's avatar
Matthias Braun committed
87
static ir_node *gen_ptr_add(ir_node *node, ir_node *frame, const arm_vals *v)
88
{
89
	dbg_info *dbgi  = get_irn_dbg_info(node);
90
	ir_node  *block = get_nodes_block(node);
Matthias Braun's avatar
Matthias Braun committed
91
92
	ir_node  *ptr   = new_bd_arm_Add_imm(dbgi, block, frame, v->values[0],
	                                     v->rors[0]);
93
	arch_set_irn_register(ptr, &arm_registers[REG_R12]);
94
95
	sched_add_before(node, ptr);

Matthias Braun's avatar
Matthias Braun committed
96
	for (unsigned cnt = 1; cnt < v->ops; ++cnt) {
97
98
		ir_node *next = new_bd_arm_Add_imm(dbgi, block, ptr, v->values[cnt],
		                                   v->rors[cnt]);
99
		arch_set_irn_register(next, &arm_registers[REG_R12]);
100
101
102
103
104
105
106
107
108
		sched_add_before(node, next);
		ptr = next;
	}
	return ptr;
}

/**
* creates the address by Subs
*/
Matthias Braun's avatar
Matthias Braun committed
109
static ir_node *gen_ptr_sub(ir_node *node, ir_node *frame, const arm_vals *v)
110
{
111
	dbg_info *dbgi  = get_irn_dbg_info(node);
112
	ir_node  *block = get_nodes_block(node);
Matthias Braun's avatar
Matthias Braun committed
113
114
	ir_node  *ptr   = new_bd_arm_Sub_imm(dbgi, block, frame, v->values[0],
	                                     v->rors[0]);
115
	arch_set_irn_register(ptr, &arm_registers[REG_R12]);
116
117
	sched_add_before(node, ptr);

Matthias Braun's avatar
Matthias Braun committed
118
	for (unsigned cnt = 1; cnt < v->ops; ++cnt) {
119
120
		ir_node *next = new_bd_arm_Sub_imm(dbgi, block, ptr, v->values[cnt],
		                                   v->rors[cnt]);
121
		arch_set_irn_register(next, &arm_registers[REG_R12]);
122
123
124
125
126
127
		sched_add_before(node, next);
		ptr = next;
	}
	return ptr;
}

128
129
130
/** fix frame addresses which are too big */
static void peephole_arm_FrameAddr(ir_node *node)
{
131
132
133
	arm_Address_attr_t *attr   = get_arm_Address_attr(node);
	int                 offset = attr->fp_offset;
	arm_vals            v;
134
135
136
	if (allowed_arm_immediate(offset, &v))
		return;

Matthias Braun's avatar
Matthias Braun committed
137
	ir_node *base = get_irn_n(node, n_arm_FrameAddr_base);
138
	/* TODO: suboptimal */
Matthias Braun's avatar
Matthias Braun committed
139
	ir_node *ptr = gen_ptr_add(node, base, &v);
140

141
142
	attr->fp_offset = 0;
	set_irn_n(node, n_arm_FrameAddr_base, ptr);
143
144
145
}

/**
146
 * Fix stackpointer relative stores if the offset gets too big
147
 */
148
149
150
static void peephole_arm_Str_Ldr(ir_node *node)
{
	arm_load_store_attr_t *attr    = get_arm_load_store_attr(node);
Andreas Zwinkau's avatar
Andreas Zwinkau committed
151
	const int              offset  = attr->offset;
Matthias Braun's avatar
Matthias Braun committed
152
	arm_vals               v;
153
154
	if (allowed_arm_immediate(offset, &v))
		return;
155
156
157
158
159
160

	/* we should only have too big offsets for frame entities */
	if (!attr->is_frame_entity) {
		fprintf(stderr,
		        "POSSIBLE ARM BACKEND PROBLEM: offset in Store too big\n");
	}
Matthias Braun's avatar
Matthias Braun committed
161
	bool use_add = offset >= 0;
162

Matthias Braun's avatar
Matthias Braun committed
163
	ir_node *ptr;
164
165
	if (is_arm_Str(node)) {
		ptr = get_irn_n(node, n_arm_Str_ptr);
166
	} else {
167
168
		assert(is_arm_Ldr(node));
		ptr = get_irn_n(node, n_arm_Ldr_ptr);
169
170
	}

171
172
	if (use_add) {
		ptr = gen_ptr_add(node, ptr, &v);
173
	} else {
174
		ptr = gen_ptr_sub(node, ptr, &v);
175
176
	}

177
178
179
180
181
182
183
184
185
	/* TODO: sub-optimal, the last offset could probably be left inside the
	   store */
	if (is_arm_Str(node)) {
		set_irn_n(node, n_arm_Str_ptr, ptr);
	} else {
		assert(is_arm_Ldr(node));
		set_irn_n(node, n_arm_Ldr_ptr, ptr);
	}
	attr->offset = 0;
186
187
188
189
190
}

/**
 * Register a peephole optimization function.
 */
191
static void register_peephole_optimization(ir_op *op, peephole_opt_func func)
192
{
193
194
195
196
197
	assert(op->ops.generic == NULL);
	op->ops.generic = (op_func)func;
}

/* Perform peephole-optimizations. */
198
void arm_peephole_optimization(ir_graph *irg)
199
200
{
	/* register peephole optimizations */
Matthias Braun's avatar
Matthias Braun committed
201
	ir_clear_opcodes_generic_func();
202
203
204
205
	register_peephole_optimization(op_be_IncSP,      peephole_be_IncSP);
	register_peephole_optimization(op_arm_Str,       peephole_arm_Str_Ldr);
	register_peephole_optimization(op_arm_Ldr,       peephole_arm_Str_Ldr);
	register_peephole_optimization(op_arm_FrameAddr, peephole_arm_FrameAddr);
206

207
	be_peephole_opt(irg);
208
}