arm_cconv.c 4.58 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
 */

/**
 * @file
 * @brief   calling convention helpers
 * @author  Matthias Braun
 */
#include "arm_cconv.h"
12
#include "beirg.h"
13
14
15
#include "irmode.h"
#include "typerep.h"
#include "xmalloc.h"
Matthias Braun's avatar
Matthias Braun committed
16
#include "panic.h"
17
#include "util.h"
18

19
20
21
22
23
24
25
static const unsigned ignore_regs[] = {
	REG_R12,
	REG_SP,
	REG_PC,
	REG_FL,
};

26
27
28
29
static const arch_register_t* const param_regs[] = {
	&arm_registers[REG_R0],
	&arm_registers[REG_R1],
	&arm_registers[REG_R2],
Matthias Braun's avatar
Matthias Braun committed
30
	&arm_registers[REG_R3],
31
32
33
34
35
36
};

static const arch_register_t* const result_regs[] = {
	&arm_registers[REG_R0],
	&arm_registers[REG_R1],
	&arm_registers[REG_R2],
Matthias Braun's avatar
Matthias Braun committed
37
	&arm_registers[REG_R3],
38
39
40
41
};

static const arch_register_t* const float_result_regs[] = {
	&arm_registers[REG_F0],
Matthias Braun's avatar
Matthias Braun committed
42
	&arm_registers[REG_F1],
43
44
};

Michael Beck's avatar
Michael Beck committed
45
calling_convention_t *arm_decide_calling_convention(const ir_graph *irg,
46
                                                    ir_type *function_type)
47
48
{
	/* determine how parameters are passed */
Matthias Braun's avatar
Matthias Braun committed
49
50
51
52
53
	unsigned            stack_offset = 0;
	size_t const        n_param_regs = ARRAY_SIZE(param_regs);
	size_t const        n_params     = get_method_n_params(function_type);
	size_t              regnum       = 0;
	reg_or_stackslot_t *params       = XMALLOCNZ(reg_or_stackslot_t, n_params);
54

Matthias Braun's avatar
Matthias Braun committed
55
	for (size_t i = 0; i < n_params; ++i) {
56
57
58
59
		ir_type            *param_type = get_method_param_type(function_type,i);
		ir_mode            *mode       = get_type_mode(param_type);
		int                 bits       = get_mode_size_bits(mode);
		reg_or_stackslot_t *param      = &params[i];
60
		param->type = param_type;
61

62
63
64
65
66
67
68
69
70
71
72
73
		/* doubleword modes need to be passed in even registers */
		if (param_type->flags & tf_lowered_dw) {
			if (regnum < n_param_regs) {
				if ((regnum & 1) != 0)
					++regnum;
			} else {
				unsigned misalign = stack_offset % 8;
				if (misalign > 0)
					stack_offset += 8 - misalign;
			}
		}

74
		if (regnum < n_param_regs) {
75
			param->reg0 = param_regs[regnum++];
76
77
78
		} else {
			param->offset = stack_offset;
			/* increase offset 4 bytes so everything is aligned */
Christoph Mallon's avatar
Christoph Mallon committed
79
			stack_offset += MAX(bits / 8, 4);
80
81
82
83
84
85
			continue;
		}

		/* we might need a 2nd 32bit component (for 64bit or double values) */
		if (bits > 32) {
			if (bits > 64)
86
				panic("only 32 and 64bit modes supported");
87
88
89
90
91

			if (regnum < n_param_regs) {
				const arch_register_t *reg = param_regs[regnum++];
				param->reg1 = reg;
			} else {
92
				ir_mode *pmode = param_regs[0]->cls->mode;
93
94
95
96
				ir_type *type  = get_type_for_mode(pmode);
				param->type    = type;
				param->offset  = stack_offset;
				assert(get_mode_size_bits(pmode) == 32);
97
98
99
100
				stack_offset += 4;
			}
		}
	}
Matthias Braun's avatar
Matthias Braun committed
101
102
103
104
105
106
107
108
109
	unsigned const n_param_regs_used = regnum;

	size_t const        n_result_regs= ARRAY_SIZE(result_regs);
	size_t const n_float_result_regs = ARRAY_SIZE(float_result_regs);
	size_t              n_results    = get_method_n_ress(function_type);
	size_t              float_regnum = 0;
	reg_or_stackslot_t *results      = XMALLOCNZ(reg_or_stackslot_t, n_results);
	regnum = 0;
	for (size_t i = 0; i < n_results; ++i) {
110
111
112
113
		ir_type            *result_type = get_method_res_type(function_type, i);
		ir_mode            *result_mode = get_type_mode(result_type);
		reg_or_stackslot_t *result      = &results[i];

114
115
		if (mode_is_float(result_mode)) {
			if (float_regnum >= n_float_result_regs) {
116
				panic("too many float results");
117
118
119
120
			} else {
				const arch_register_t *reg = float_result_regs[float_regnum++];
				result->reg0 = reg;
			}
121
		} else {
122
			if (get_mode_size_bits(result_mode) > 32) {
123
				panic("results with more than 32bits not supported yet");
124
125
126
			}

			if (regnum >= n_result_regs) {
127
				panic("too many results");
128
129
130
131
			} else {
				const arch_register_t *reg = result_regs[regnum++];
				result->reg0 = reg;
			}
132
133
134
		}
	}

Matthias Braun's avatar
Matthias Braun committed
135
	calling_convention_t *cconv = XMALLOCZ(calling_convention_t);
136
	cconv->parameters       = params;
137
	cconv->n_parameters     = n_params;
138
	cconv->param_stack_size = stack_offset;
139
	cconv->n_param_regs     = n_param_regs_used;
140
141
	cconv->results          = results;

142
143
144
145
146
147
148
149
150
	/* setup allocatable registers */
	if (irg != NULL) {
		be_irg_t       *birg      = be_birg_from_irg(irg);
		size_t          n_ignores = ARRAY_SIZE(ignore_regs);
		struct obstack *obst      = &birg->obst;

		assert(birg->allocatable_regs == NULL);
		birg->allocatable_regs = rbitset_obstack_alloc(obst, N_ARM_REGISTERS);
		rbitset_set_all(birg->allocatable_regs, N_ARM_REGISTERS);
Matthias Braun's avatar
Matthias Braun committed
151
		for (size_t r = 0; r < n_ignores; ++r) {
152
153
154
155
			rbitset_clear(birg->allocatable_regs, ignore_regs[r]);
		}
	}

156
157
158
	return cconv;
}

159
void arm_free_calling_convention(calling_convention_t *cconv)
160
161
162
163
164
{
	free(cconv->parameters);
	free(cconv->results);
	free(cconv);
}