summaryrefslogtreecommitdiffhomepage
path: root/ir/be/ia32/x86_asm.c
blob: e8ce6efbf9f190ce3c7fa115bf092b4088503612 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
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
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
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
/*
 * This file is part of libFirm.
 * Copyright (C) 2014 University of Karlsruhe.
 */

/**
 * @file
 * @brief  Handling of x86 inline assembly
 * @author Matthias Braun
 * Matching and emitting of inline assembly nodes.
 */
#include "x86_asm.h"

#include "array.h"
#include "be_t.h"
#include "bearch.h"
#include "beasm.h"
#include "betranshlp.h"
#include "gen_ia32_regalloc_if.h"
#include "panic.h"
#include "target_t.h"
#include <assert.h>

static void x86_parse_constraint_letter(void const *const env, be_asm_constraint_t* const c, char const l)
{
	x86_asm_constraint_list_t const *const constraints = (x86_asm_constraint_list_t const*)env;

	unsigned char const u = (unsigned char)l;
	if (u < ARRAY_SIZE(*constraints)) {
		x86_asm_constraint_t const *const constraint = &(*constraints)[u];
		switch (constraint->kind) {
		case MATCH_REG:
			c->cls = constraint->cls;
			if (constraint->limited == 0)
				c->all_registers_allowed = true;
			else
				c->allowed_registers = constraint->limited;
			return;

		case MATCH_MEM:
			/* memory constraint no need to do anything in backend about it
			 * (dependencies are already respected by the memory edge of the
			 *  node) */
			c->memory_possible = true;
			return;

		case MATCH_IMM:
			c->cls            = constraint->cls;
			c->immediate_type = l;
			return;

		case MATCH_ANY:
			c->cls                   = constraint->cls;
			c->immediate_type        = l;
			c->memory_possible       = true;
			c->all_registers_allowed = true;
			return;

		case MATCH_INVALID:
			break;
		}
	}
	panic("Unknown asm constraint '%c'", l);
}

static size_t x86_add_addr_in(be_asm_info_t *const info, ir_node *const in)
{
	ir_node                   *const new_in = be_transform_node(in);
	arch_register_req_t const *const req    = arch_get_irn_register_req(new_in)->cls->class_req;
	return be_asm_append_in(info, new_in, req);
}

ir_node *x86_match_ASM(ir_node const *const node, x86_asm_constraint_list_t const *const constraint_list)
{
	be_asm_info_t info = be_asm_prepare_info(node);

	ir_asm_constraint const *const constraints   = get_ASM_constraints(node);
	size_t                   const n_constraints = get_ASM_n_constraints(node);
	ir_graph                *const irg           = get_irn_irg(node);
	struct obstack          *const obst          = get_irg_obstack(irg);
	x86_asm_operand_t       *const operands      = NEW_ARR_DZ(x86_asm_operand_t, obst, n_constraints);
	for (size_t i = 0; i != n_constraints; ++i) {
		ir_asm_constraint const *const c = &constraints[i];

		be_asm_constraint_t be_constraint;
		be_parse_asm_constraints_internal(&be_constraint, c->constraint, &x86_parse_constraint_letter, constraint_list);

		x86_asm_operand_t *const op = &operands[i];
		op->u.mode = c->mode;

		int const in_pos = c->in_pos;
		if (in_pos >= 0) {
			ir_node *const in  = get_ASM_input(node, in_pos);
			char     const imm = be_constraint.immediate_type;
			if (imm != '\0' && x86_match_immediate(&op->u.imm32, in, imm)) {
				be_asm_add_immediate(&op->op);
			} else if (be_constraint.same_as >= 0) {
				int                        const out_pos = operands[be_constraint.same_as].op.pos;
				arch_register_req_t const *const ireq    = info.out_reqs[out_pos];
				be_asm_add_inout(&info, &op->op, obst, in, ireq, out_pos);
			} else if (be_constraint.cls) {
				arch_register_req_t const *const ireq = be_make_register_req(obst, &be_constraint);
				be_asm_add_inout(&info, &op->op, obst, in, ireq, c->out_pos);
			} else {
				x86_address_t address;
				x86_create_address_mode(&address, in, x86_create_am_normal);

				x86_addr_t *const addr = &op->u.addr;
				*addr = (x86_addr_t){
					.immediate = address.imm,
					.log_scale = address.scale,
					.variant   = address.variant,
				};

				if (x86_addr_variant_has_base(address.variant))
					addr->base_input = x86_add_addr_in(&info, address.base);

				if (x86_addr_variant_has_index(address.variant))
					addr->index_input = x86_add_addr_in(&info, address.index);

				be_set_asm_operand(&op->op, BE_ASM_OPERAND_MEMORY, -1);
			}
		} else {
			be_asm_add_out(&info, &op->op, obst, &be_constraint, c->out_pos);
		}
	}

	return be_make_asm(node, &info, operands);
}

void x86_set_be_asm_constraint_support(const x86_asm_constraint_list_t *constraints)
{
	for (unsigned char c = 0; c < ARRAY_SIZE(*constraints); ++c) {
		const x86_asm_constraint_t *constraint = &(*constraints)[c];
		asm_constraint_flags_t flags;
		switch (constraint->kind) {
		case MATCH_INVALID:
			continue;
		case MATCH_REG:
			flags = ASM_CONSTRAINT_FLAG_SUPPORTS_REGISTER;
			goto fine;
		case MATCH_IMM:
			flags = ASM_CONSTRAINT_FLAG_SUPPORTS_IMMEDIATE;
			goto fine;
		case MATCH_MEM:
			flags = ASM_CONSTRAINT_FLAG_SUPPORTS_MEMOP;
			goto fine;
		case MATCH_ANY:
			flags = ASM_CONSTRAINT_FLAG_SUPPORTS_ANY;
			goto fine;
		}
		panic("invalid constraint");
fine:
		assert(be_asm_constraint_flags[c] == ASM_CONSTRAINT_FLAG_INVALID
		    || be_asm_constraint_flags[c] == ASM_CONSTRAINT_FLAG_NO_SUPPORT);
		be_asm_constraint_flags[c] = flags;
	}
}