lower_builtins.c 6.46 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
13
14
 */

/**
 * @file
 * @brief   Lowering of builtins to compiler-lib calls
 * @author  Matthias Braun
 */
#include "lower_builtins.h"
#include <stdbool.h>
#include <stdlib.h>
#include "adt/pmap.h"
15
#include "be.h"
16
17
18
19
#include "irnode_t.h"
#include "ircons_t.h"
#include "irgmod.h"
#include "irgwalk.h"
20
#include "iroptimize.h"
Matthias Braun's avatar
Matthias Braun committed
21
#include "panic.h"
22
#include "irprog_t.h"
23
#include "util.h"
24

Christoph Mallon's avatar
Christoph Mallon committed
25
static bool dont_lower[ir_bk_last + 1];
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42

static const char *get_builtin_name(ir_builtin_kind kind)
{
	switch (kind) {
	case ir_bk_ffs:      return "ffs";
	case ir_bk_clz:      return "clz";
	case ir_bk_ctz:      return "ctz";
	case ir_bk_popcount: return "popcount";
	case ir_bk_parity:   return "parity";
	case ir_bk_bswap:    return "bswap";
	case ir_bk_prefetch:
	case ir_bk_trap:
	case ir_bk_debugbreak:
	case ir_bk_return_address:
	case ir_bk_frame_address:
	case ir_bk_inport:
	case ir_bk_outport:
43
	case ir_bk_saturating_increment:
44
	case ir_bk_compare_swap:
Matthias Braun's avatar
Matthias Braun committed
45
	case ir_bk_may_alias:
46
47
	case ir_bk_va_start:
	case ir_bk_va_arg:
48
49
50
51
52
53
54
55
		break;
	}
	abort();
}

static const char *get_gcc_machmode(ir_type *type)
{
	assert(is_Primitive_type(type));
56
	switch (get_type_size(type)) {
57
58
59
60
61
62
63
	case 4: return "si";
	case 8: return "di";
	default:
		panic("couldn't determine gcc machmode for type %+F", type);
	}
}

64
65
66
67
68
69
70
71
72
73
/*
 * The 64-bit version of libgcc does not contain some builtin
 * functions for 32-bit values (__<builtin>si2) anymore.
 */
static void widen_builtin(ir_node *node)
{
	ir_type *mtp  = get_Builtin_type(node);
	ir_type *arg1 = get_method_param_type(mtp, 0);

	// Nothing to do, if argument size is at least machine size.
74
	if (8 * get_type_size(arg1) >= be_get_machine_size()) {
75
76
77
78
79
80
81
82
83
84
85
86
87
		return;
	}

	// Only touch builtins with no 32-bit version.
	ir_builtin_kind kind = get_Builtin_kind(node);
	if (kind != ir_bk_clz    &&
	    kind != ir_bk_ctz    &&
	    kind != ir_bk_ffs    &&
	    kind != ir_bk_parity &&
	    kind != ir_bk_popcount) {
		return;
	}

88
	ir_mode  *target_mode = get_reference_offset_mode(mode_P);
89
90
91
92
93
94
95
96
97
	dbg_info *dbgi        = get_irn_dbg_info(node);
	ir_node  *block       = get_nodes_block(node);
	ir_node  *op          = get_irn_n(node, n_Builtin_max + 1);

	ir_node *conv = new_rd_Conv(dbgi, block, op, target_mode);
	set_irn_n(node, n_Builtin_max + 1, conv);

	ir_type *new_arg1   = get_type_for_mode(target_mode);
	ir_type *new_result = get_method_res_type(mtp, 0);
98
	ir_type *new_type   = new_type_method(1, 1, false, cc_cdecl_set, mtp_no_property);
99
100
101
102
103
	set_method_param_type(new_type, 0, new_arg1);
	set_method_res_type(new_type, 0, new_result);
	set_Builtin_type(node, new_type);
}

104
105
static void replace_with_call(ir_node *node)
{
106
107
	widen_builtin(node);

Christoph Mallon's avatar
Christoph Mallon committed
108
109
110
111
112
113
	ir_type        *const mtp      = get_Builtin_type(node);
	ir_builtin_kind const kind     = get_Builtin_kind(node);
	char     const *const name     = get_builtin_name(kind);
	ir_type        *const arg1     = get_method_param_type(mtp, 0);
	char     const *const machmode = get_gcc_machmode(arg1);
	ident          *const id       = new_id_fmt("__%s%s2", name, machmode);
114
	ir_entity      *const entity   = create_compilerlib_entity(id, mtp);
115

Christoph Mallon's avatar
Christoph Mallon committed
116
117
118
119
120
121
122
123
124
125
126
127
128
	dbg_info *const dbgi      = get_irn_dbg_info(node);
	ir_node  *const block     = get_nodes_block(node);
	ir_node  *const mem       = get_Builtin_mem(node);
	ir_graph *const irg       = get_irn_irg(node);
	ir_node  *const callee    = new_r_Address(irg, entity);
	int       const n_params  = get_Builtin_n_params(node);
	ir_node **const params    = get_Builtin_param_arr(node);
	ir_node  *const call      = new_rd_Call(dbgi, block, mem, callee, n_params, params, mtp);
	ir_node  *const call_mem  = new_r_Proj(call, mode_M, pn_Call_M);
	ir_node  *const call_ress = new_r_Proj(call, mode_T, pn_Call_T_result);
	ir_type  *const res_type  = get_method_res_type(mtp, 0);
	ir_mode  *const res_mode  = get_type_mode(res_type);
	ir_node  *const call_res  = new_r_Proj(call_ress, res_mode, 0);
129

130
131
132
133
134
	ir_node *const in[] = {
		[pn_Builtin_M]       = call_mem,
		[pn_Builtin_max + 1] = call_res,
	};
	turn_into_tuple(node, ARRAY_SIZE(in), in);
135
136
}

Matthias Braun's avatar
Matthias Braun committed
137
138
139
140
141
142
143
144
145
146
static void replace_may_alias(ir_node *node)
{
	ir_node *in0   = get_Builtin_param(node, 0);
	ir_node *in1   = get_Builtin_param(node, 1);
	ir_type *type  = get_Builtin_type(node);
	ir_type *type0 = get_pointer_points_to_type(get_method_param_type(type, 0));
	ir_type *type1 = get_pointer_points_to_type(get_method_param_type(type, 1));
	ir_type *rtype = get_method_res_type(type, 0);
	ir_mode *rmode = get_type_mode(rtype);

Matthias Braun's avatar
Matthias Braun committed
147
	ir_alias_relation alias = get_alias_relation(in0, type0, 1, in1, type1, 1);
Matthias Braun's avatar
Matthias Braun committed
148

149
150
151
	ir_graph *const irg    = get_irn_irg(node);
	ir_node  *const result = (alias != ir_no_alias ? new_r_Const_one : new_r_Const_null)(irg, rmode);
	ir_node  *const in[]   = {
Matthias Braun's avatar
Matthias Braun committed
152
153
154
155
156
157
		[pn_Builtin_M]     = get_Builtin_mem(node),
		[pn_Builtin_max+1] = result,
	};
	turn_into_tuple(node, ARRAY_SIZE(in), in);
}

158
159
static void lower_builtin(ir_node *node, void *env)
{
160
	bool *changed = (bool*)env;
161
162
163
	if (!is_Builtin(node))
		return;

Christoph Mallon's avatar
Christoph Mallon committed
164
	ir_builtin_kind const kind = get_Builtin_kind(node);
165
166
167
168
169
170
171
	if (dont_lower[kind])
		return;

	switch (kind) {
	case ir_bk_prefetch: {
		/* just remove it */
		ir_node *mem = get_Builtin_mem(node);
172
173
		ir_node *const in[] = { mem };
		turn_into_tuple(node, ARRAY_SIZE(in), in);
Christoph Mallon's avatar
Christoph Mallon committed
174
		goto changed;
175
	}
176

177
178
179
180
181
182
183
184
	case ir_bk_ffs:
	case ir_bk_clz:
	case ir_bk_ctz:
	case ir_bk_popcount:
	case ir_bk_parity:
	case ir_bk_bswap:
		/* replace with a call */
		replace_with_call(node);
Christoph Mallon's avatar
Christoph Mallon committed
185
		goto changed;
186

Matthias Braun's avatar
Matthias Braun committed
187
188
	case ir_bk_may_alias:
		replace_may_alias(node);
Christoph Mallon's avatar
Christoph Mallon committed
189
changed:
190
		*changed = true;
Matthias Braun's avatar
Matthias Braun committed
191
192
		return;

193
194
195
196
	case ir_bk_va_arg:
		be_get_backend_param()->vararg.lower_va_arg(node);
		return;

197
198
199
200
201
202
	case ir_bk_trap:
	case ir_bk_debugbreak:
	case ir_bk_return_address:
	case ir_bk_frame_address:
	case ir_bk_inport:
	case ir_bk_outport:
203
	case ir_bk_saturating_increment:
204
	case ir_bk_compare_swap:
205
	case ir_bk_va_start:
206
		/* can't do anything about these, backend will probably fail now */
207
208
		panic("builtin kind %s not supported (for this target)",
		      get_builtin_kind_name(kind));
209
	}
210
	panic("unexpected builtin %+F", node);
211
212
213
214
215
}

void lower_builtins(size_t n_exceptions, ir_builtin_kind *exceptions)
{
	memset(dont_lower, 0, sizeof(dont_lower));
216
	for (size_t i = 0; i < n_exceptions; ++i) {
217
218
219
		dont_lower[exceptions[i]] = true;
	}

220
	foreach_irp_irg(i, irg) {
221
		bool changed = false;
222
		assure_irg_properties(irg, IR_GRAPH_PROPERTY_CONSISTENT_OUT_EDGES);
223
224
225
		irg_walk_graph(irg, NULL, lower_builtin, &changed);
		confirm_irg_properties(irg, changed ? IR_GRAPH_PROPERTIES_CONTROL_FLOW
		                                    : IR_GRAPH_PROPERTIES_ALL);
226
227
	}
}