bearch_sparc.c 19.3 KB
Newer Older
Hannes Rapp's avatar
Hannes Rapp committed
1
2
/*
 * This file is part of libFirm.
3
 * Copyright (C) 2012 University of Karlsruhe.
Hannes Rapp's avatar
Hannes Rapp committed
4
5
6
7
8
 */

/**
 * @file
 * @brief    The main sparc backend driver file.
Matthias Braun's avatar
Matthias Braun committed
9
 * @author   Hannes Rapp, Matthias Braun
Hannes Rapp's avatar
Hannes Rapp committed
10
11
12
13
14
15
16
17
18
19
 */
#include "lc_opts.h"
#include "lc_opts_enum.h"

#include "irgwalk.h"
#include "irprog.h"
#include "ircons.h"
#include "irgmod.h"
#include "irgopt.h"
#include "iroptimize.h"
20
21
#include "irtools.h"
#include "irdump.h"
22
#include "iropt_t.h"
Hannes Rapp's avatar
Hannes Rapp committed
23
#include "lowering.h"
24
#include "lower_dw.h"
25
#include "lower_alloc.h"
26
#include "lower_builtins.h"
27
#include "lower_calls.h"
28
#include "lower_mode_b.h"
29
#include "lower_softfloat.h"
Hannes Rapp's avatar
Hannes Rapp committed
30
31
#include "debug.h"
#include "array_t.h"
32
#include "error.h"
33
#include "util.h"
34
#include "be_t.h"
35
36
37
38
39
40
41
42
43
#include "bearch.h"
#include "benode.h"
#include "belower.h"
#include "besched.h"
#include "bemodule.h"
#include "begnuas.h"
#include "belistsched.h"
#include "beflags.h"
#include "beutil.h"
Hannes Rapp's avatar
Hannes Rapp committed
44
45
46
47
48
49
50

#include "bearch_sparc_t.h"

#include "sparc_new_nodes.h"
#include "gen_sparc_regalloc_if.h"
#include "sparc_transform.h"
#include "sparc_emitter.h"
51
#include "sparc_cconv.h"
52

Hannes Rapp's avatar
Hannes Rapp committed
53
54
DEBUG_ONLY(static firm_dbg_module_t *dbg = NULL;)

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
extern const arch_isa_if_t sparc_isa_if;
static sparc_isa_t sparc_isa_template = {
	{
		&sparc_isa_if,                       /* isa interface implementation */
		N_SPARC_REGISTERS,
		sparc_registers,
		N_SPARC_CLASSES,
		sparc_reg_classes,
		&sparc_registers[REG_SP],            /* stack pointer register */
		&sparc_registers[REG_FRAME_POINTER], /* base pointer register */
		3,                                   /* power of two stack alignment
		                                        for calls */
		7,                                   /* costs for a spill instruction */
		5,                                   /* costs for a reload instruction */
		true,                                /* custom abi handling */
	},
	NULL,                                  /* constants */
};

typedef enum {
	cpu_generic,
	cpu_v8plus,
	cpu_leon,
	cpu_supersparc,
	cpu_hypersparc,
} sparc_cpu_t;
static const lc_opt_enum_int_items_t cpu_items[] = {
	{ "generic",    cpu_generic    },
	{ "v8",         cpu_generic    },
	{ "v8plus",     cpu_v8plus     },
	{ "leon",       cpu_leon       },
	{ "supersparc", cpu_supersparc },
	{ "hypersparc", cpu_hypersparc },
	{ NULL,         0               },
};

static int cpu;
static lc_opt_enum_int_var_t cpu_var = {
	&cpu, cpu_items
};

sparc_codegen_config_t sparc_cg_config;

typedef enum {
	use_fpu_auto,
	use_fpu_yes,
	use_fpu_no
} sparc_use_fpu_t;
/* fpu set architectures. */
static const lc_opt_enum_int_items_t fpu_items[] = {
	{ "auto",      use_fpu_auto },
	{ "fpu",       use_fpu_yes  },
	{ "softfloat", use_fpu_no   },
	{ NULL,        0 }
};

static int fpu;
static lc_opt_enum_int_var_t arch_fpu_var = {
	&fpu, fpu_items
};

static int use_softfloat;

static const lc_opt_table_entry_t sparc_options[] = {
	LC_OPT_ENT_ENUM_INT("fpunit",     "select the floating point unit", &arch_fpu_var),
	LC_OPT_ENT_ENUM_INT("cpu",        "select architecture variant",    &cpu_var),
	LC_OPT_ENT_BOOL    ("soft-float", "equivalent to fpmath=softfloat", &use_softfloat),
	LC_OPT_LAST
};

125
static ir_entity *sparc_get_frame_entity(const ir_node *node)
Hannes Rapp's avatar
Hannes Rapp committed
126
{
127
128
129
	if (is_sparc_FrameAddr(node)) {
		const sparc_attr_t *attr = get_sparc_attr_const(node);
		return attr->immediate_value_entity;
Hannes Rapp's avatar
Hannes Rapp committed
130
131
	}

132
133
134
	if (sparc_has_load_store_attr(node)) {
		const sparc_load_store_attr_t *load_store_attr
			= get_sparc_load_store_attr_const(node);
Hannes Rapp's avatar
Hannes Rapp committed
135
		if (load_store_attr->is_frame_entity) {
136
			return load_store_attr->base.immediate_value_entity;
Hannes Rapp's avatar
Hannes Rapp committed
137
138
139
		}
	}

Hannes Rapp's avatar
Hannes Rapp committed
140
141
142
143
144
145
146
	return NULL;
}

/**
 * This function is called by the generic backend to correct offsets for
 * nodes accessing the stack.
 */
147
static void sparc_set_frame_offset(ir_node *node, int offset)
Hannes Rapp's avatar
Hannes Rapp committed
148
{
149
150
151
152
153
154
	sparc_attr_t *attr = get_sparc_attr(node);
	attr->immediate_value += offset;

	/* must be a FrameAddr or a load/store node with frame_entity */
	assert(is_sparc_FrameAddr(node) ||
			get_sparc_load_store_attr_const(node)->is_frame_entity);
Hannes Rapp's avatar
Hannes Rapp committed
155
156
}

157
static int sparc_get_sp_bias(const ir_node *node)
Hannes Rapp's avatar
Hannes Rapp committed
158
{
159
	if (is_sparc_Save(node)) {
160
161
162
163
		const sparc_attr_t *attr = get_sparc_attr_const(node);
		if (get_irn_arity(node) == 3)
			panic("no support for _reg variant yet");

164
		return -attr->immediate_value;
165
166
	} else if (is_sparc_RestoreZero(node)) {
		return SP_BIAS_RESET;
167
168
	}
	return 0;
Hannes Rapp's avatar
Hannes Rapp committed
169
170
171
172
}

/* fill register allocator interface */

173
const arch_irn_ops_t sparc_irn_ops = {
Hannes Rapp's avatar
Hannes Rapp committed
174
175
176
177
178
179
180
181
182
183
184
185
	sparc_get_frame_entity,
	sparc_set_frame_offset,
	sparc_get_sp_bias,
	NULL,    /* get_op_estimated_cost   */
	NULL,    /* possible_memory_operand */
	NULL,    /* perform_memory_operand  */
};

/**
 * Transforms the standard firm graph into
 * a SPARC firm graph
 */
186
static void sparc_prepare_graph(ir_graph *irg)
Hannes Rapp's avatar
Hannes Rapp committed
187
{
188
	sparc_transform_graph(irg);
Hannes Rapp's avatar
Hannes Rapp committed
189
190
}

191
192
static bool sparc_modifies_flags(const ir_node *node)
{
193
	be_foreach_out(node, o) {
194
195
196
197
198
		const arch_register_req_t *req = arch_get_irn_register_req_out(node, o);
		if (req->cls == &sparc_reg_classes[CLASS_sparc_flags_class])
			return true;
	}
	return false;
199
200
201
202
}

static bool sparc_modifies_fp_flags(const ir_node *node)
{
203
	be_foreach_out(node, o) {
204
205
206
207
208
		const arch_register_req_t *req = arch_get_irn_register_req_out(node, o);
		if (req->cls == &sparc_reg_classes[CLASS_sparc_fpflags_class])
			return true;
	}
	return false;
209
210
}

211
static void sparc_before_ra(ir_graph *irg)
Hannes Rapp's avatar
Hannes Rapp committed
212
213
{
	/* fixup flags register */
214
	be_sched_fix_flags(irg, &sparc_reg_classes[CLASS_sparc_flags_class],
215
	                   NULL, sparc_modifies_flags);
216
	be_sched_fix_flags(irg, &sparc_reg_classes[CLASS_sparc_fpflags_class],
217
	                   NULL, sparc_modifies_fp_flags);
Hannes Rapp's avatar
Hannes Rapp committed
218
219
}

220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
/**
 * rewrite unsigned->float conversion.
 * Sparc has no instruction for this so instead we do the following:
 *
 *   int    signed_x = unsigned_value_x;
 *   double res      = signed_x;
 *   if (signed_x < 0)
 *       res += 4294967296. ;
 *   return (float) res;
 */
static void rewrite_unsigned_float_Conv(ir_node *node)
{
	ir_graph *irg         = get_irn_irg(node);
	dbg_info *dbgi        = get_irn_dbg_info(node);
	ir_node  *lower_block = get_nodes_block(node);

	part_block(node);

Matthias Braun's avatar
Matthias Braun committed
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
	ir_node   *block       = get_nodes_block(node);
	ir_node   *unsigned_x  = get_Conv_op(node);
	ir_mode   *mode_u      = get_irn_mode(unsigned_x);
	ir_mode   *mode_s      = find_signed_mode(mode_u);
	ir_mode   *mode_d      = mode_D;
	ir_node   *signed_x    = new_rd_Conv(dbgi, block, unsigned_x, mode_s);
	ir_node   *res         = new_rd_Conv(dbgi, block, signed_x, mode_d);
	ir_node   *zero        = new_r_Const(irg, get_mode_null(mode_s));
	ir_node   *cmp         = new_rd_Cmp(dbgi, block, signed_x, zero,
	                                    ir_relation_less);
	ir_node   *cond        = new_rd_Cond(dbgi, block, cmp);
	ir_node   *proj_true   = new_r_Proj(cond, mode_X, pn_Cond_true);
	ir_node   *proj_false  = new_r_Proj(cond, mode_X, pn_Cond_false);
	ir_node   *in_true[1]  = { proj_true };
	ir_node   *in_false[1] = { proj_false };
	ir_node   *true_block  = new_r_Block(irg, ARRAY_SIZE(in_true), in_true);
	ir_node   *false_block = new_r_Block(irg, ARRAY_SIZE(in_false),in_false);
	ir_node   *true_jmp    = new_r_Jmp(true_block);
	ir_node   *false_jmp   = new_r_Jmp(false_block);
	ir_tarval *correction  = new_tarval_from_double(4294967296., mode_d);
	ir_node   *c_const     = new_r_Const(irg, correction);
	ir_node   *fadd        = new_rd_Add(dbgi, true_block, res, c_const, mode_d);

	ir_node  *lower_in[2] = { true_jmp, false_jmp };
	ir_node  *phi_in[2]   = { fadd, res };
	ir_mode  *dest_mode   = get_irn_mode(node);

	set_irn_in(lower_block, ARRAY_SIZE(lower_in), lower_in);
	ir_node *phi = new_r_Phi(lower_block, ARRAY_SIZE(phi_in), phi_in, mode_d);
	assert(get_Block_phis(lower_block) == NULL);
	set_Block_phis(lower_block, phi);
	set_Phi_next(phi, NULL);

	ir_node *res_conv = new_rd_Conv(dbgi, lower_block, phi, dest_mode);
	exchange(node, res_conv);
273
274
}

275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
/**
 * rewrite float->unsigned conversions.
 * Sparc has no instruction for this so instead we do the following:
 *
 * if (x >= 2147483648.) {
 *   converted ^= (int)(x-2147483648.) ^ 0x80000000;
 * } else {
 *   converted = (int)x;
 * }
 * return (unsigned)converted;
 */
static void rewrite_float_unsigned_Conv(ir_node *node)
{
	ir_graph *irg         = get_irn_irg(node);
	dbg_info *dbgi        = get_irn_dbg_info(node);
	ir_node  *lower_block = get_nodes_block(node);

	part_block(node);

Matthias Braun's avatar
Matthias Braun committed
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
	ir_node   *block       = get_nodes_block(node);
	ir_node   *float_x     = get_Conv_op(node);
	ir_mode   *mode_u      = get_irn_mode(node);
	ir_mode   *mode_s      = find_signed_mode(mode_u);
	ir_mode   *mode_f      = get_irn_mode(float_x);
	ir_tarval *limit       = new_tarval_from_double(2147483648., mode_f);
	ir_node   *limitc      = new_r_Const(irg, limit);
	ir_node   *cmp         = new_rd_Cmp(dbgi, block, float_x, limitc,
	                                    ir_relation_greater_equal);
	ir_node   *cond        = new_rd_Cond(dbgi, block, cmp);
	ir_node   *proj_true   = new_r_Proj(cond, mode_X, pn_Cond_true);
	ir_node   *proj_false  = new_r_Proj(cond, mode_X, pn_Cond_false);
	ir_node   *in_true[1]  = { proj_true };
	ir_node   *in_false[1] = { proj_false };
	ir_node   *true_block  = new_r_Block(irg, ARRAY_SIZE(in_true), in_true);
	ir_node   *false_block = new_r_Block(irg, ARRAY_SIZE(in_false),in_false);
	ir_node   *true_jmp    = new_r_Jmp(true_block);
	ir_node   *false_jmp   = new_r_Jmp(false_block);

	ir_tarval *correction  = new_tarval_from_long(0x80000000l, mode_s);
	ir_node   *c_const     = new_r_Const(irg, correction);
	ir_node   *sub         = new_rd_Sub(dbgi, true_block, float_x, limitc,
										mode_f);
	ir_node   *sub_conv    = new_rd_Conv(dbgi, true_block, sub, mode_s);
	ir_node   *xorn        = new_rd_Eor(dbgi, true_block, sub_conv, c_const,
										mode_s);

	ir_node   *converted   = new_rd_Conv(dbgi, false_block, float_x,mode_s);

	ir_node  *lower_in[2] = { true_jmp, false_jmp };
	ir_node  *phi_in[2]   = { xorn, converted };

	set_irn_in(lower_block, ARRAY_SIZE(lower_in), lower_in);
	ir_node *phi = new_r_Phi(lower_block, ARRAY_SIZE(phi_in), phi_in, mode_s);
	assert(get_Block_phis(lower_block) == NULL);
	set_Block_phis(lower_block, phi);
	set_Phi_next(phi, NULL);

	ir_node *res_conv = new_rd_Conv(dbgi, lower_block, phi, mode_u);
	exchange(node, res_conv);
334
335
}

336
337
static int sparc_rewrite_Conv(ir_node *node, void *ctx)
{
Matthias Braun's avatar
Matthias Braun committed
338
	(void) ctx;
339
340
341
342
343
	ir_mode *to_mode   = get_irn_mode(node);
	ir_node *op        = get_Conv_op(node);
	ir_mode *from_mode = get_irn_mode(op);

	if (mode_is_float(to_mode) && mode_is_int(from_mode)
344
345
	    && get_mode_size_bits(from_mode) == 32
	    && !mode_is_signed(from_mode)) {
346
347
348
		rewrite_unsigned_float_Conv(node);
		return 1;
	}
349
	if (mode_is_float(from_mode) && mode_is_int(to_mode)
350
	    && get_mode_size_bits(to_mode) <= 32
351
352
353
354
	    && !mode_is_signed(to_mode)) {
	    rewrite_float_unsigned_Conv(node);
	    return 1;
	}
355
356
357
358

	return 0;
}

359
360
static void sparc_handle_intrinsics(void)
{
Matthias Braun's avatar
Matthias Braun committed
361
	i_record records[3];
362
	size_t n_records = 0;
363

364
	/* we need to rewrite some forms of int->float conversions */
Matthias Braun's avatar
Matthias Braun committed
365
366
367
368
	i_instr_record *map_Conv = &records[n_records++].i_instr;
	map_Conv->kind     = INTRINSIC_INSTR;
	map_Conv->op       = op_Conv;
	map_Conv->i_mapper = sparc_rewrite_Conv;
369
370

	/* SPARC has no signed mod instruction ... */
Matthias Braun's avatar
Matthias Braun committed
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
	ir_type *int_tp = new_type_primitive(mode_Is);
	ir_type *mod_tp = new_type_method(2, 1);
	set_method_param_type(mod_tp, 0, int_tp);
	set_method_param_type(mod_tp, 1, int_tp);
	set_method_res_type(mod_tp, 0, int_tp);

	runtime_rt rt_iMod;
	ident *mod_id = new_id_from_str(".rem");
	rt_iMod.ent             = new_entity(get_glob_type(), mod_id, mod_tp);
	set_entity_ld_ident(rt_iMod.ent, mod_id);
	rt_iMod.mode            = mode_T;
	rt_iMod.res_mode        = mode_Is;
	rt_iMod.mem_proj_nr     = pn_Mod_M;
	rt_iMod.regular_proj_nr = pn_Mod_X_regular;
	rt_iMod.exc_proj_nr     = pn_Mod_X_except;
	rt_iMod.res_proj_nr     = pn_Mod_res;
	set_entity_visibility(rt_iMod.ent, ir_visibility_external);

	i_instr_record *map_imod = &records[n_records++].i_instr;
	map_imod->kind     = INTRINSIC_INSTR;
	map_imod->op       = op_Mod;
	map_imod->i_mapper = (i_mapper_func)i_mapper_RuntimeCall;
	map_imod->ctx      = &rt_iMod;
394

Matthias Braun's avatar
Matthias Braun committed
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
	/* ... nor an unsigned mod. */
	ir_type *umod_tp = new_type_method(2, 1);
	ir_type *uint_tp = new_type_primitive(mode_Iu);
	set_method_param_type(umod_tp, 0, uint_tp);
	set_method_param_type(umod_tp, 1, uint_tp);
	set_method_res_type(umod_tp, 0, uint_tp);

	runtime_rt rt_uMod;
	ident *umod_id = new_id_from_str(".urem");
	rt_uMod.ent             = new_entity(get_glob_type(), umod_id, umod_tp);
	set_entity_ld_ident(rt_uMod.ent, umod_id);
	rt_uMod.mode            = mode_T;
	rt_uMod.res_mode        = mode_Iu;
	rt_uMod.mem_proj_nr     = pn_Mod_M;
	rt_uMod.regular_proj_nr = pn_Mod_X_regular;
	rt_uMod.exc_proj_nr     = pn_Mod_X_except;
	rt_uMod.res_proj_nr     = pn_Mod_res;
	set_entity_visibility(rt_uMod.ent, ir_visibility_external);

	i_instr_record *map_umod = &records[n_records++].i_instr;
	map_umod->kind     = INTRINSIC_INSTR;
	map_umod->op       = op_Mod;
	map_umod->i_mapper = (i_mapper_func)i_mapper_RuntimeCall;
	map_umod->ctx      = &rt_uMod;

	assert(n_records <= ARRAY_SIZE(records));
421
	lower_intrinsics(records, n_records, /*part_block_used=*/ true);
422
423
}

424
425
static void sparc_setup_cg_config(void)
{
426
427
	memset(&sparc_cg_config, 0, sizeof(sparc_cg_config));
	bool has_fpu = false;
428
	switch ((sparc_cpu_t)cpu) {
429
430
431
432
	case cpu_v8plus:
		sparc_cg_config.use_cas = true;
		has_fpu = false;
		break;
433
	case cpu_leon:
434
435
436
		sparc_cg_config.use_cas = true;
		has_fpu = true;
		break;
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
	case cpu_hypersparc:
		has_fpu = true;
		break;
	case cpu_supersparc:
	case cpu_generic:
		has_fpu = false;
		break;
	}

	if (use_softfloat)
		fpu = use_fpu_no;

	if (fpu == use_fpu_auto) {
		sparc_cg_config.use_fpu = has_fpu;
	} else {
		sparc_cg_config.use_fpu = fpu == use_fpu_yes;
	}
}

456
457
static void sparc_init(void)
{
458
	sparc_init_asm_constraints();
459
460
461
	sparc_register_init();
	sparc_create_opcodes(&sparc_irn_ops);
	sparc_cconv_init();
462
	sparc_setup_cg_config();
463
464
}

Matthias Braun's avatar
Matthias Braun committed
465
466
467
468
469
static void sparc_finish(void)
{
	sparc_free_opcodes();
}

470
static arch_env_t *sparc_begin_codegeneration(void)
Hannes Rapp's avatar
Hannes Rapp committed
471
{
472
	sparc_isa_t *isa = XMALLOC(sparc_isa_t);
473
	*isa = sparc_isa_template;
474
	isa->constants = pmap_create();
Hannes Rapp's avatar
Hannes Rapp committed
475

476
477
	be_gas_elf_type_char = '#';
	be_gas_elf_variant   = ELF_VARIANT_SPARC;
478

479
	return &isa->base;
Hannes Rapp's avatar
Hannes Rapp committed
480
481
482
483
484
}

/**
 * Closes the output file and frees the ISA structure.
 */
485
static void sparc_end_codegeneration(void *self)
Hannes Rapp's avatar
Hannes Rapp committed
486
{
487
	sparc_isa_t *isa = (sparc_isa_t*)self;
488
489
	pmap_destroy(isa->constants);
	free(isa);
Hannes Rapp's avatar
Hannes Rapp committed
490
491
}

492
493
static void sparc_lower_for_target(void)
{
494
	lower_calls_with_compounds(LF_RETURN_HIDDEN);
495

Matthias Braun's avatar
Matthias Braun committed
496
	for (size_t i = 0, n_irgs = get_irp_n_irgs(); i < n_irgs; ++i) {
497
498
499
500
501
502
		ir_graph *irg = get_irp_irg(i);
		/* Turn all small CopyBs into loads/stores and all bigger CopyBs into
		 * memcpy calls. */
		lower_CopyB(irg, 31, 32, false);
	}

503
	if (!sparc_cg_config.use_fpu)
504
505
		lower_floating_point();

506
507
508
	ir_builtin_kind supported[8];
	size_t          s = 0;
	supported[s++] = ir_bk_saturating_increment;
509
510
	if (sparc_cg_config.use_cas)
		supported[s++] = ir_bk_compare_swap;
511
512
	assert(s < ARRAY_SIZE(supported));
	lower_builtins(s, supported);
513

Matthias Braun's avatar
Matthias Braun committed
514
515
	ir_mode *mode_gp = sparc_reg_classes[CLASS_sparc_gp].mode;
	for (size_t i = 0, n_irgs = get_irp_n_irgs(); i < n_irgs; ++i) {
516
517
518
519
		ir_graph *irg = get_irp_irg(i);
		lower_switch(irg, 4, 256, mode_gp);
	}

520
521
	sparc_lower_64bit();

Matthias Braun's avatar
Matthias Braun committed
522
	for (size_t i = 0, n_irgs = get_irp_n_irgs(); i < n_irgs; ++i) {
523
		ir_graph *irg = get_irp_irg(i);
524
		ir_lower_mode_b(irg, mode_Iu);
Manuel Mohr's avatar
Manuel Mohr committed
525
526
527
		/* TODO: Pass SPARC_MIN_STACKSIZE as addr_delta as soon as
		 * Alloc nodes are implemented more efficiently. */
		lower_alloc(irg, SPARC_STACK_ALIGNMENT, true, 0);
528
	}
529
530
}

531
532
533
static int sparc_is_mux_allowed(ir_node *sel, ir_node *mux_false,
                                ir_node *mux_true)
{
534
	return ir_is_optimizable_mux(sel, mux_false, mux_true);
535
536
}

Hannes Rapp's avatar
Hannes Rapp committed
537
538
539
/**
 * Returns the libFirm configuration parameter for this backend.
 */
540
541
static const backend_params *sparc_get_backend_params(void)
{
542
543
544
545
546
547
548
549
550
	static const ir_settings_arch_dep_t arch_dep = {
		1,     /* also_use_subs */
		1,     /* maximum_shifts */
		31,    /* highest_shift_amount */
		NULL,  /* evaluate_cost_func */
		1,     /* allow mulhs */
		1,     /* allow mulhu */
		32,    /* max_bits_for_mulh */
	};
Hannes Rapp's avatar
Hannes Rapp committed
551
	static backend_params p = {
552
		1,     /* big endian */
553
554
		1,     /* modulo shift efficient */
		0,     /* non-modulo shift not efficient */
555
		&arch_dep,              /* will be set later */
556
		sparc_is_mux_allowed,   /* parameter for if conversion */
557
		32,    /* machine size */
Hannes Rapp's avatar
Hannes Rapp committed
558
		NULL,  /* float arithmetic mode */
559
560
561
		NULL,  /* long long type */
		NULL,  /* usigned long long type */
		NULL,  /* long double type */
Hannes Rapp's avatar
Hannes Rapp committed
562
563
564
565
566
		0,     /* no trampoline support: size 0 */
		0,     /* no trampoline support: align 0 */
		NULL,  /* no trampoline support: no trampoline builder */
		4      /* alignment of stack parameter: typically 4 (32bit) or 8 (64bit) */
	};
567
568

	ir_mode *mode_long_long
569
		= new_int_mode("long long", irma_twos_complement, 64, 1, 64);
570
571
	ir_type *type_long_long = new_type_primitive(mode_long_long);
	ir_mode *mode_unsigned_long_long
572
		= new_int_mode("unsigned long long", irma_twos_complement, 64, 0, 64);
573
574
575
576
577
	ir_type *type_unsigned_long_long
		= new_type_primitive(mode_unsigned_long_long);

	p.type_long_long          = type_long_long;
	p.type_unsigned_long_long = type_unsigned_long_long;
578

579
580
581
582
583
	ir_type *type_long_double = new_type_primitive(mode_Q);

	set_type_alignment_bytes(type_long_double, 8);
	set_type_size_bytes(type_long_double, 16);
	p.type_long_double = type_long_double;
Hannes Rapp's avatar
Hannes Rapp committed
584
585
586
	return &p;
}

587
588
589
590
591
592
593
594
static ir_node *sparc_new_spill(ir_node *value, ir_node *after)
{
	ir_node  *block = get_block(after);
	ir_graph *irg   = get_irn_irg(value);
	ir_node  *frame = get_irg_frame(irg);
	ir_node  *mem   = get_irg_no_mem(irg);
	ir_mode  *mode  = get_irn_mode(value);

Matthias Braun's avatar
Matthias Braun committed
595
	ir_node  *store;
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
	if (mode_is_float(mode)) {
		store = create_stf(NULL, block, value, frame, mem, mode, NULL, 0, true);
	} else {
		store = new_bd_sparc_St_imm(NULL, block, value, frame, mem, mode, NULL,
		                            0, true);
	}
	sched_add_after(after, store);
	return store;
}

static ir_node *sparc_new_reload(ir_node *value, ir_node *spill,
                                 ir_node *before)
{
	ir_node  *block = get_block(before);
	ir_graph *irg   = get_irn_irg(value);
	ir_node  *frame = get_irg_frame(irg);
	ir_mode  *mode  = get_irn_mode(value);

Matthias Braun's avatar
Matthias Braun committed
614
	ir_node  *load;
615
616
617
618
619
620
621
622
	if (mode_is_float(mode)) {
		load = create_ldf(NULL, block, frame, spill, mode, NULL, 0, true);
	} else {
		load = new_bd_sparc_Ld_imm(NULL, block, frame, spill, mode, NULL, 0,
		                           true);
	}
	sched_add_before(before, load);
	assert((long)pn_sparc_Ld_res == (long)pn_sparc_Ldf_res);
Matthias Braun's avatar
Matthias Braun committed
623
	ir_node *res = new_r_Proj(load, mode, pn_sparc_Ld_res);
624
625
626
627

	return res;
}

Hannes Rapp's avatar
Hannes Rapp committed
628
629
const arch_isa_if_t sparc_isa_if = {
	sparc_init,
Matthias Braun's avatar
Matthias Braun committed
630
	sparc_finish,
631
	sparc_get_backend_params,
632
	sparc_lower_for_target,
633
634
	sparc_is_valid_clobber,

635
636
	sparc_begin_codegeneration,
	sparc_end_codegeneration,
637
	NULL,
638
639
640
641
642
643
644
645
646
	NULL,                /* get call abi */
	NULL,                /* mark remat */
	NULL,                /* get_pic_base */
	sparc_new_spill,
	sparc_new_reload,
	NULL,                /* register_saved_by */

	sparc_handle_intrinsics,
	NULL,                /* before_abi */
647
648
	sparc_prepare_graph,
	sparc_before_ra,
Matthias Braun's avatar
Matthias Braun committed
649
	sparc_finish_graph,
650
	sparc_emit_routine,
Hannes Rapp's avatar
Hannes Rapp committed
651
652
};

653
BE_REGISTER_MODULE_CONSTRUCTOR(be_init_arch_sparc)
Hannes Rapp's avatar
Hannes Rapp committed
654
655
void be_init_arch_sparc(void)
{
656
657
658
659
660
	lc_opt_entry_t *be_grp = lc_opt_get_grp(firm_opt_get_root(), "be");
	lc_opt_entry_t *sparc_grp = lc_opt_get_grp(be_grp, "sparc");

	lc_opt_add_table(sparc_grp, sparc_options);

Hannes Rapp's avatar
Hannes Rapp committed
661
662
663
664
665
	be_register_isa_if("sparc", &sparc_isa_if);
	FIRM_DBG_REGISTER(dbg, "firm.be.sparc.cg");
	sparc_init_transform();
	sparc_init_emitter();
}