ia32_spec.pl 52.9 KB
Newer Older
1
2
3
4
# Creation: 2005/10/19
# $Id$
# This is the specification for the ia32 assembler Firm-operations

Andreas Schösser's avatar
Andreas Schösser committed
5
6
use File::Basename;

7
$new_emit_syntax = 1;
Andreas Schösser's avatar
Andreas Schösser committed
8
my $myname = $0;
9

10
11
12
13
14
15
16
17
18
# the cpu architecture (ia32, ia64, mips, sparc, ppc, ...)
$arch = "ia32";

# The node description is done as a perl hash initializer with the
# following structure:
#
# %nodes = (
#
# <op-name> => {
19
20
21
22
23
24
25
#   op_flags  => "N|L|C|X|I|F|Y|H|c|K",
#   irn_flags => "R|N|I|S"
#   arity     => "0|1|2|3 ... |variable|dynamic|any",
#   state     => "floats|pinned|mem_pinned|exc_pinned",
#   args      => [
#                    { type => "type 1", name => "name 1" },
#                    { type => "type 2", name => "name 2" },
26
27
#                    ...
#                  ],
28
29
30
31
32
33
34
35
#   comment   => "any comment for constructor",
#   reg_req   => { in => [ "reg_class|register" ], out => [ "reg_class|register|in_rX" ] },
#   cmp_attr  => "c source code for comparing node attributes",
#   emit      => "emit code with templates",
#   attr      => "attitional attribute arguments for constructor"
#   init_attr => "emit attribute initialization template"
#   rd_constructor => "c source code which constructs an ir_node"
#   latency   => "latency of this operation (can be float)"
Michael Beck's avatar
Michael Beck committed
36
#   attr_type => "name of the attribute struct",
37
38
39
40
41
42
# },
#
# ... # (all nodes you need to describe)
#
# ); # close the %nodes initializer

43
# op_flags: flags for the operation, OPTIONAL (default is "N")
44
45
46
47
48
49
50
51
52
53
# the op_flags correspond to the firm irop_flags:
#   N   irop_flag_none
#   L   irop_flag_labeled
#   C   irop_flag_commutative
#   X   irop_flag_cfopcode
#   I   irop_flag_ip_cfopcode
#   F   irop_flag_fragile
#   Y   irop_flag_forking
#   H   irop_flag_highlevel
#   c   irop_flag_constlike
Michael Beck's avatar
Michael Beck committed
54
#   K   irop_flag_keep
55
#
56
57
58
59
60
# irn_flags: special node flags, OPTIONAL (default is 0)
# following irn_flags are supported:
#   R   rematerializeable
#   N   not spillable
#   I   ignore for register allocation
61
#   S   modifies stack pointer
Christian Würdig's avatar
Christian Würdig committed
62
#
Christian Würdig's avatar
Christian Würdig committed
63
# state: state of the operation, OPTIONAL (default is "floats")
Christian Würdig's avatar
Christian Würdig committed
64
65
66
67
#
# arity: arity of the operation, MUST NOT BE OMITTED
#
# args:  the OPTIONAL arguments of the node constructor (debug, irg and block
68
69
#        are always the first 3 arguments and are always autmatically
#        created)
Christian Würdig's avatar
Christian Würdig committed
70
#        If this key is missing the following arguments will be created:
71
72
#        for i = 1 .. arity: ir_node *op_i
#        ir_mode *mode
Christian Würdig's avatar
Christian Würdig committed
73
#
Michael Beck's avatar
Michael Beck committed
74
75
# outs:  if a node defines more than one output, the names of the projections
#        nodes having outs having automatically the mode mode_T
76
77
78
79
#        One can also annotate some flags for each out, additional to irn_flags.
#        They are separated from name with a colon ':', and concatenated by pipe '|'
#        Only I and S are available at the moment (same meaning as in irn_flags).
#        example: [ "frame:I", "stack:I|S", "M" ]
Michael Beck's avatar
Michael Beck committed
80
#
Christian Würdig's avatar
Christian Würdig committed
81
82
# comment: OPTIONAL comment for the node constructor
#
83
84
85
86
87
# rd_constructor: for every operation there will be a
#      new_rd_<arch>_<op-name> function with the arguments from above
#      which creates the ir_node corresponding to the defined operation
#      you can either put the complete source code of this function here
#
Christian Würdig's avatar
Christian Würdig committed
88
89
#      This key is OPTIONAL. If omitted, the following constructor will
#      be created:
90
91
92
93
#      if (!op_<arch>_<op-name>) assert(0);
#      for i = 1 to arity
#         set in[i] = op_i
#      done
Christian Würdig's avatar
Christian Würdig committed
94
#      res = new_ir_node(db, irg, block, op_<arch>_<op-name>, mode, arity, in)
95
96
#      return res
#
Christian Würdig's avatar
Christian Würdig committed
97
# NOTE: rd_constructor and args are only optional if and only if arity is 0,1,2 or 3
Christian Würdig's avatar
Christian Würdig committed
98
99
100
#
# latency: the latency of the operation, default is 1
#
101

Christian Würdig's avatar
Christian Würdig committed
102
103
# register types:
#   0 - no special type
104
105
#   1 - caller save (register must be saved by the caller of a function)
#   2 - callee save (register must be saved by the called function)
Christian Würdig's avatar
Christian Würdig committed
106
#   4 - ignore (do not assign this register)
107
108
#   8 - emitter can choose an arbitrary register of this class
#  16 - the register is a virtual one
109
#  32 - register represents a state
Christian Würdig's avatar
Christian Würdig committed
110
# NOTE: Last entry of each class is the largest Firm-Mode a register can hold
111
%reg_classes = (
112
113
114
115
116
117
118
119
120
121
122
123
	gp => [
		{ name => "eax", type => 1 },
		{ name => "edx", type => 1 },
		{ name => "ebx", type => 2 },
		{ name => "ecx", type => 1 },
		{ name => "esi", type => 2 },
		{ name => "edi", type => 2 },
		{ name => "ebp", type => 2 },
		{ name => "esp", type => 4 },
		{ name => "gp_NOREG", type => 4 | 8 | 16 }, # we need a dummy register for NoReg nodes
		{ name => "gp_UKNWN", type => 4 | 8 | 16 },  # we need a dummy register for Unknown nodes
		{ mode => "mode_Iu" }
124
	],
125
126
127
128
129
130
131
132
133
134
135
	mmx => [
		{ name => "mm0", type => 4 },
		{ name => "mm1", type => 4 },
		{ name => "mm2", type => 4 },
		{ name => "mm3", type => 4 },
		{ name => "mm4", type => 4 },
		{ name => "mm5", type => 4 },
		{ name => "mm6", type => 4 },
		{ name => "mm7", type => 4 },
		{ mode => "mode_E" }
	],
136
137
138
139
140
141
142
143
144
145
146
	xmm => [
		{ name => "xmm0", type => 1 },
		{ name => "xmm1", type => 1 },
		{ name => "xmm2", type => 1 },
		{ name => "xmm3", type => 1 },
		{ name => "xmm4", type => 1 },
		{ name => "xmm5", type => 1 },
		{ name => "xmm6", type => 1 },
		{ name => "xmm7", type => 1 },
		{ name => "xmm_NOREG", type => 4 | 16 },     # we need a dummy register for NoReg nodes
		{ name => "xmm_UKNWN", type => 4 | 8 | 16},  # we need a dummy register for Unknown nodes
147
		{ mode => "mode_E" }
148
	],
149
150
151
152
153
154
155
156
157
158
159
160
	vfp => [
		{ name => "vf0", type => 1 | 16 },
		{ name => "vf1", type => 1 | 16 },
		{ name => "vf2", type => 1 | 16 },
		{ name => "vf3", type => 1 | 16 },
		{ name => "vf4", type => 1 | 16 },
		{ name => "vf5", type => 1 | 16 },
		{ name => "vf6", type => 1 | 16 },
		{ name => "vf7", type => 1 | 16 },
		{ name => "vfp_NOREG", type => 4 | 8 | 16 }, # we need a dummy register for NoReg nodes
		{ name => "vfp_UKNWN", type => 4 | 8 | 16 },  # we need a dummy register for Unknown nodes
		{ mode => "mode_E" }
161
	],
162
	st => [
163
164
165
166
167
168
169
170
		{ name => "st0", realname => "st",    type => 4 },
		{ name => "st1", realname => "st(1)", type => 4 },
		{ name => "st2", realname => "st(2)", type => 4 },
		{ name => "st3", realname => "st(3)", type => 4 },
		{ name => "st4", realname => "st(4)", type => 4 },
		{ name => "st5", realname => "st(5)", type => 4 },
		{ name => "st6", realname => "st(6)", type => 4 },
		{ name => "st7", realname => "st(7)", type => 4 },
171
		{ mode => "mode_E" }
172
	],
173
	fp_cw => [	# the floating point control word
174
		{ name => "fpcw", type => 4 | 32},
175
		{ mode => "mode_fpcw" }
176
	],
177
178
179
180
181
182
183
184
	flags => [
		{ name => "eflags", type => 4 },
		{ mode => "mode_Iu" }
	],
	fp_sw => [
		{ name => "fpsw", type => 4 },
		{ mode => "mode_Hu" }
	],
185
186
); # %reg_classes

187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
%flags = (
	CF  => { reg => "eflags", bit => 0 },
	PF  => { reg => "eflags", bit => 2 },
	AF  => { reg => "eflags", bit => 4 },
	ZF  => { reg => "eflags", bit => 6 },
	SF  => { reg => "eflags", bit => 7 },
	TF  => { reg => "eflags", bit => 8 },
	IF  => { reg => "eflags", bit => 9 },
	DF  => { reg => "eflags", bit => 10 },
	OF  => { reg => "eflags", bit => 11 },
	IOPL0 => { reg => "eflags", bit => 12 },
	IOPL1 => { reg => "eflags", bit => 13 },
	NT  => { reg => "eflags", bit => 14 },
	RF  => { reg => "eflags", bit => 16 },
	VM  => { reg => "eflags", bit => 17 },
	AC  => { reg => "eflags", bit => 18 },
	VIF => { reg => "eflags", bit => 19 },
	VIP => { reg => "eflags", bit => 20 },
	ID  => { reg => "eflags", bit => 21 },

	FP_IE => { reg => "fpsw", bit => 0 },
	FP_DE => { reg => "fpsw", bit => 1 },
	FP_ZE => { reg => "fpsw", bit => 2 },
	FP_OE => { reg => "fpsw", bit => 3 },
	FP_UE => { reg => "fpsw", bit => 4 },
	FP_PE => { reg => "fpsw", bit => 5 },
	FP_SF => { reg => "fpsw", bit => 6 },
	FP_ES => { reg => "fpsw", bit => 7 },
	FP_C0 => { reg => "fpsw", bit => 8 },
	FP_C1 => { reg => "fpsw", bit => 9 },
	FP_C2 => { reg => "fpsw", bit => 10 },
	FP_TOP0 => { reg => "fpsw", bit => 11 },
	FP_TOP1 => { reg => "fpsw", bit => 12 },
	FP_TOP2 => { reg => "fpsw", bit => 13 },
	FP_C3 => { reg => "fpsw", bit => 14 },
	FP_B  => { reg => "fpsw", bit => 15 },

	FP_IM => { reg => "fpcw", bit => 0 },
	FP_DM => { reg => "fpcw", bit => 1 },
	FP_ZM => { reg => "fpcw", bit => 2 },
	FP_OM => { reg => "fpcw", bit => 3 },
	FP_UM => { reg => "fpcw", bit => 4 },
	FP_PM => { reg => "fpcw", bit => 5 },
	FP_PC0 => { reg => "fpcw", bit => 8 },
	FP_PC1 => { reg => "fpcw", bit => 9 },
	FP_RC0 => { reg => "fpcw", bit => 10 },
	FP_RC1 => { reg => "fpcw", bit => 11 },
	FP_X  => { reg => "fpcw", bit => 12 }
); # %flags

237
%cpu = (
238
239
240
241
	GP     => [ 1, "GP_EAX", "GP_EBX", "GP_ECX", "GP_EDX", "GP_ESI", "GP_EDI", "GP_EBP" ],
	SSE    => [ 1, "SSE_XMM0", "SSE_XMM1", "SSE_XMM2", "SSE_XMM3", "SSE_XMM4", "SSE_XMM5", "SSE_XMM6", "SSE_XMM7" ],
	VFP    => [ 1, "VFP_VF0", "VFP_VF1", "VFP_VF2", "VFP_VF3", "VFP_VF4", "VFP_VF5", "VFP_VF6", "VFP_VF7" ],
	BRANCH => [ 1, "BRANCH1", "BRANCH2" ],
242
243
); # %cpu

244
%vliw = (
245
246
	bundle_size       => 1,
	bundels_per_cycle => 1
247
248
); # vliw

249
%emit_templates = (
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
	S0 => "${arch}_emit_source_register(env, node, 0);",
	S1 => "${arch}_emit_source_register(env, node, 1);",
	S2 => "${arch}_emit_source_register(env, node, 2);",
	S3 => "${arch}_emit_source_register(env, node, 3);",
	S4 => "${arch}_emit_source_register(env, node, 4);",
	S5 => "${arch}_emit_source_register(env, node, 5);",
	D0 => "${arch}_emit_dest_register(env, node, 0);",
	D1 => "${arch}_emit_dest_register(env, node, 1);",
	D2 => "${arch}_emit_dest_register(env, node, 2);",
	D3 => "${arch}_emit_dest_register(env, node, 3);",
	D4 => "${arch}_emit_dest_register(env, node, 4);",
	D5 => "${arch}_emit_dest_register(env, node, 5);",
	X0 => "${arch}_emit_x87_name(env, node, 0);",
	X1 => "${arch}_emit_x87_name(env, node, 1);",
	X2 => "${arch}_emit_x87_name(env, node, 2);",
265
266
267
	C  => "${arch}_emit_immediate(env, node);",
	SE => "${arch}_emit_extend_suffix(env, get_ia32_ls_mode(node));",
	ME => "if(get_mode_size_bits(get_ia32_ls_mode(node)) != 32)\n
Matthias Braun's avatar
Matthias Braun committed
268
269
	           ia32_emit_mode_suffix(env, node);",
	M  => "${arch}_emit_mode_suffix(env, node);",
270
	XM => "${arch}_emit_x87_mode_suffix(env, node);",
271
272
273
	XXM => "${arch}_emit_xmm_mode_suffix(env, node);",
	XSD => "${arch}_emit_xmm_mode_suffix_s(env, node);",
	AM => "${arch}_emit_am(env, node);",
274
275
276
277
278
279
280
	unop0 => "${arch}_emit_unop(env, node, 0);",
	unop1 => "${arch}_emit_unop(env, node, 1);",
	unop2 => "${arch}_emit_unop(env, node, 2);",
	unop3 => "${arch}_emit_unop(env, node, 3);",
	unop4 => "${arch}_emit_unop(env, node, 4);",
	DAM0  => "${arch}_emit_am_or_dest_register(env, node, 0);",
	DAM1  => "${arch}_emit_am_or_dest_register(env, node, 0);",
281
282
	binop => "${arch}_emit_binop(env, node);",
	x87_binop => "${arch}_emit_x87_binop(env, node);",
283
284
);

285
286
287
288
289
290
291
292
293
294
295
#--------------------------------------------------#
#                        _                         #
#                       (_)                        #
#  _ __   _____      __  _ _ __    ___  _ __  ___  #
# | '_ \ / _ \ \ /\ / / | | '__|  / _ \| '_ \/ __| #
# | | | |  __/\ V  V /  | | |    | (_) | |_) \__ \ #
# |_| |_|\___| \_/\_/   |_|_|     \___/| .__/|___/ #
#                                      | |         #
#                                      |_|         #
#--------------------------------------------------#

296
$default_attr_type = "ia32_attr_t";
297
$default_copy_attr = "ia32_copy_attr";
298

299
300
301
302
303
%init_attr = (
	ia32_attr_t     => "\tinit_ia32_attributes(res, flags, in_reqs, out_reqs, exec_units, n_res, latency);",
	ia32_x87_attr_t =>
		"\tinit_ia32_attributes(res, flags, in_reqs, out_reqs, exec_units, n_res, latency);\n".
		"\tinit_ia32_x87_attributes(res);",
304
305
306
	ia32_asm_attr_t =>
		"\tinit_ia32_attributes(res, flags, in_reqs, out_reqs, exec_units, n_res, latency);\n".
		"\tinit_ia32_x87_attributes(res);".
307
308
309
310
		"\tinit_ia32_asm_attributes(res);",
	ia32_immediate_attr_t =>
		"\tinit_ia32_attributes(res, flags, in_reqs, out_reqs, exec_units, n_res, latency);\n".
		"\tinit_ia32_immediate_attributes(res, symconst, symconst_sign, offset);"
311
312
313
);

%compare_attr = (
314
315
316
317
	ia32_attr_t           => "ia32_compare_nodes_attr",
	ia32_x87_attr_t       => "ia32_compare_x87_attr",
	ia32_asm_attr_t       => "ia32_compare_asm_attr",
	ia32_immediate_attr_t => "ia32_compare_immediate_attr",
318
319
);

Michael Beck's avatar
Michael Beck committed
320
321
322
%operands = (
);

Matthias Braun's avatar
fix    
Matthias Braun committed
323
$mode_xmm     = "mode_E";
324
$mode_gp      = "mode_Iu";
325
$mode_fpcw    = "mode_fpcw";
326
327
328
329
$status_flags = [ "CF", "PF", "AF", "ZF", "SF", "OF" ];
$fpcw_flags   = [ "FP_IM", "FP_DM", "FP_ZM", "FP_OM", "FP_UM", "FP_PM",
                  "FP_PC0", "FP_PC1", "FP_RC0", "FP_RC1", "FP_X" ];

330
331
%nodes = (

332
333
334
335
336
Immediate => {
	state     => "pinned",
	op_flags  => "c",
	irn_flags => "I",
	reg_req   => { out => [ "gp_NOREG" ] },
337
	attr      => "ir_entity *symconst, int symconst_sign, long offset",
338
	attr_type => "ia32_immediate_attr_t",
339
340
	mode      => $mode_gp,
},
341

342
343
344
345
Asm => {
	mode      => "mode_T",
	arity     => "variable",
	out_arity => "variable",
346
	attr_type => "ia32_asm_attr_t",
347
348
},

Christian Würdig's avatar
Christian Würdig committed
349
350
351
352
353
354
355
356
357
358
#-----------------------------------------------------------------#
#  _       _                                         _            #
# (_)     | |                                       | |           #
#  _ _ __ | |_ ___  __ _  ___ _ __   _ __   ___   __| | ___  ___  #
# | | '_ \| __/ _ \/ _` |/ _ \ '__| | '_ \ / _ \ / _` |/ _ \/ __| #
# | | | | | ||  __/ (_| |  __/ |    | | | | (_) | (_| |  __/\__ \ #
# |_|_| |_|\__\___|\__, |\___|_|    |_| |_|\___/ \__,_|\___||___/ #
#                   __/ |                                         #
#                  |___/                                          #
#-----------------------------------------------------------------#
Christian Würdig's avatar
Christian Würdig committed
359

360
361
# commutative operations

362
363
364
365
366
367
368
# NOTE:
# All nodes supporting Addressmode have 5 INs:
# 1 - base    r1 == NoReg in case of no AM or no base
# 2 - index   r2 == NoReg in case of no AM or no index
# 3 - op1     r3 == always present
# 4 - op2     r4 == NoReg in case of immediate operation
# 5 - mem     NoMem in case of no AM otherwise it takes the mem from the Load
369

370
Add => {
371
372
	irn_flags => "R",
	reg_req   => { in => [ "gp", "gp", "gp", "gp", "none" ], out => [ "in_r3" ] },
373
	ins       => [ "base", "index", "left", "right", "mem" ],
374
	emit      => '. add%M %binop',
375
	units     => [ "GP" ],
376
377
	mode      => $mode_gp,
	modified_flags => $status_flags
378
379
380
},

Adc => {
381
	reg_req   => { in => [ "gp", "gp", "gp", "gp", "none" ], out => [ "in_r3" ] },
382
	emit      => '. adc%M %binop',
383
	units     => [ "GP" ],
384
385
	mode      => $mode_gp,
	modified_flags => $status_flags
386
387
388
},

Add64Bit => {
389
390
391
392
	irn_flags => "R",
	arity     => 4,
	reg_req   => { in => [ "gp", "gp", "gp", "gp" ], out => [ "!in", "!in" ] },
	emit      => '
393
. movl %S0, %D0
394
. movl %S1, %D1
395
396
. addl %S2, %D0
. adcl %S3, %D1
397
',
398
399
	outs      => [ "low_res", "high_res" ],
	units     => [ "GP" ],
400
	modified_flags => $status_flags
401
402
},

403
l_Add => {
404
405
406
407
	op_flags  => "C",
	irn_flags => "R",
	cmp_attr  => "return 1;",
	arity     => 2,
408
409
},

410
l_Adc => {
411
412
413
	op_flags  => "C",
	cmp_attr  => "return 1;",
	arity     => 2,
414
415
},

416
Mul => {
417
418
419
	# we should not rematrialize this node. It produces 2 results and has
	# very strict constrains
	reg_req   => { in => [ "gp", "gp", "eax", "gp", "none" ], out => [ "eax", "edx", "none" ] },
420
	emit      => '. mul%M %unop3',
421
	outs      => [ "EAX", "EDX", "M" ],
422
	ins       => [ "base", "index", "val_high", "val_low", "mem" ],
423
424
	latency   => 10,
	units     => [ "GP" ],
425
	modified_flags => $status_flags
426
427
},

428
l_Mul => {
429
430
431
432
433
434
	# we should not rematrialize this node. It produces 2 results and has
	# very strict constrains
	op_flags  => "C",
	cmp_attr  => "return 1;",
	outs      => [ "EAX", "EDX", "M" ],
	arity     => 2
435
436
437
},

IMul => {
438
439
	irn_flags => "R",
	reg_req   => { in => [ "gp", "gp", "gp", "gp", "none" ], out => [ "in_r3" ] },
440
	emit      => '. imul%M %binop',
441
442
	latency   => 5,
	units     => [ "GP" ],
443
444
	mode      => $mode_gp,
	modified_flags => $status_flags
445
446
447
},

IMul1OP => {
448
449
	irn_flags => "R",
	reg_req   => { in => [ "gp", "gp", "eax", "gp", "none" ], out => [ "eax", "edx", "none" ] },
450
	emit      => '. imul%M %unop3',
451
	outs      => [ "EAX", "EDX", "M" ],
452
	ins       => [ "base", "index", "val_high", "val_low", "mem" ],
453
454
	latency   => 5,
	units     => [ "GP" ],
455
	modified_flags => $status_flags
456
457
458
},

l_IMul => {
459
460
461
	op_flags  => "C",
	cmp_attr  => "return 1;",
	arity     => 2
462
463
464
},

And => {
465
466
	irn_flags => "R",
	reg_req   => { in => [ "gp", "gp", "gp", "gp", "none" ], out => [ "in_r3" ] },
467
	emit      => '. and%M %binop',
468
	units     => [ "GP" ],
469
470
	mode      => $mode_gp,
	modified_flags => $status_flags
471
472
473
},

Or => {
474
475
	irn_flags => "R",
	reg_req   => { in => [ "gp", "gp", "gp", "gp", "none" ], out => [ "in_r3" ] },
Matthias Braun's avatar
Matthias Braun committed
476
	emit      => '. or%M %binop',
477
	units     => [ "GP" ],
478
479
	mode      => $mode_gp,
	modified_flags => $status_flags
480
481
482
},

Xor => {
483
484
	irn_flags => "R",
	reg_req   => { in => [ "gp", "gp", "gp", "gp", "none" ], out => [ "in_r3" ] },
485
	emit      => '. xor%M %binop',
486
	units     => [ "GP" ],
487
488
	mode      => $mode_gp,
	modified_flags => $status_flags
489
490
491
},

l_Xor => {
492
493
	op_flags  => "C",
	cmp_attr  => "return 1;",
494
495
	arity     => 2,
	modified_flags => $status_flags
496
497
},

498
499
# not commutative operations

500
Sub => {
501
502
	irn_flags => "R",
	reg_req   => { in => [ "gp", "gp", "gp", "gp", "none" ], out => [ "in_r3" ] },
503
	emit      => '. sub%M %binop',
504
	units     => [ "GP" ],
505
506
	mode      => $mode_gp,
	modified_flags => $status_flags
507
508
509
},

Sbb => {
510
	reg_req   => { in => [ "gp", "gp", "gp", "gp", "none" ], out => [ "in_r3 !in_r4" ] },
511
	emit      => '. sbb%M %binop',
512
	units     => [ "GP" ],
513
514
	mode      => $mode_gp,
	modified_flags => $status_flags
515
516
517
},

Sub64Bit => {
518
519
520
521
	irn_flags => "R",
	arity     => 4,
	reg_req   => { in => [ "gp", "gp", "gp", "gp" ], out => [ "!in", "!in" ] },
	emit      => '
522
. movl %S0, %D0
523
. movl %S1, %D1
524
525
. subl %S2, %D0
. sbbl %S3, %D1
526
',
527
528
	outs      => [ "low_res", "high_res" ],
	units     => [ "GP" ],
529
	modified_flags => $status_flags
530
531
},

532
l_Sub => {
533
534
535
	irn_flags => "R",
	cmp_attr  => "return 1;",
	arity     => 2,
536
537
},

538
l_Sbb => {
539
540
	cmp_attr  => "return 1;",
	arity     => 2,
541
542
},

543
IDiv => {
544
545
546
547
548
	op_flags  => "F|L",
	state     => "exc_pinned",
	reg_req   => { in => [ "gp", "gp", "eax", "edx", "gp", "none" ], out => [ "eax", "edx", "none" ] },
	attr      => "ia32_op_flavour_t dm_flav",
	init_attr => "attr->data.op_flav = dm_flav;",
549
	emit      => ". idiv%M %unop4",
550
551
552
	outs      => [ "div_res", "mod_res", "M" ],
	latency   => 25,
	units     => [ "GP" ],
553
	modified_flags => $status_flags
554
555
},

556
Div => {
557
558
559
560
561
	op_flags  => "F|L",
	state     => "exc_pinned",
	reg_req   => { in => [ "gp", "gp", "eax", "edx", "gp", "none" ], out => [ "eax", "edx", "none" ] },
	attr      => "ia32_op_flavour_t dm_flav",
	init_attr => "attr->data.op_flav = dm_flav;",
562
	emit      => ". div%M %unop4",
563
564
565
	outs      => [ "div_res", "mod_res", "M" ],
	latency   => 25,
	units     => [ "GP" ],
566
	modified_flags => $status_flags
567
568
},

569
Shl => {
570
	irn_flags => "R",
571
572
573
	# "in_r3" would be enough as out requirement, but the register allocator
	# does strange things then and doesn't respect the constraint for in4
	# if the same value is attached to in3 and in4 (if you have "i << i" in C)
574
	reg_req   => { in => [ "gp", "gp", "gp", "ecx", "none" ], out => [ "in_r3 !in_r4" ] },
575
	ins       => [ "base", "index", "left", "right", "mem" ],
576
	emit      => '. shl%M %binop',
577
	units     => [ "GP" ],
578
579
	mode      => $mode_gp,
	modified_flags => $status_flags
580
581
},

582
l_Shl => {
583
584
	cmp_attr  => "return 1;",
	arity     => 2
585
586
},

587
ShlD => {
588
589
590
591
	irn_flags => "R",
	# Out requirements is: different from all in
	# This is because, out must be different from LowPart and ShiftCount.
	# We could say "!ecx !in_r4" but it can occur, that all values live through
592
593
594
595
596
597
	# this Shift and the only value dying is the ShiftCount. Then there would be
	# a register missing, as result must not be ecx and all other registers are
	# occupied. What we should write is "!in_r4 !in_r5", but this is not
	# supported (and probably never will). So we create artificial interferences
	# of the result with all inputs, so the spiller can always assure a free
	# register.
598
599
	reg_req   => { in => [ "gp", "gp", "gp", "gp", "ecx", "none" ], out => [ "!in" ] },
	emit      =>
600
'
601
602
if (get_ia32_immop_type(node) == ia32_ImmNone) {
	if (get_ia32_op_type(node) == ia32_AddrModeD) {
603
		. shld%M %%cl, %S3, %AM
604
	} else {
605
		. shld%M %%cl, %S3, %S2
606
607
608
	}
} else {
	if (get_ia32_op_type(node) == ia32_AddrModeD) {
609
		. shld%M %C, %S3, %AM
610
	} else {
611
		. shld%M %C, %S3, %S2
612
	}
613
614
}
',
615
616
	latency   => 6,
	units     => [ "GP" ],
617
618
	mode      => $mode_gp,
	modified_flags => $status_flags
619
620
},

621
l_ShlD => {
622
623
	cmp_attr  => "return 1;",
	arity     => 3,
624
625
},

626
Shr => {
627
628
	irn_flags => "R",
	reg_req   => { in => [ "gp", "gp", "gp", "ecx", "none" ], out => [ "in_r3 !in_r4" ] },
629
	emit      => '. shr%M %binop',
630
	units     => [ "GP" ],
631
632
	mode      => $mode_gp,
	modified_flags => $status_flags
633
634
},

635
l_Shr => {
636
637
	cmp_attr  => "return 1;",
	arity     => 2
638
639
},

640
ShrD => {
641
642
643
644
645
646
647
648
649
650
651
	irn_flags => "R",
	# Out requirements is: different from all in
	# This is because, out must be different from LowPart and ShiftCount.
	# We could say "!ecx !in_r4" but it can occur, that all values live through
	# this Shift and the only value dying is the ShiftCount. Then there would be a
	# register missing, as result must not be ecx and all other registers are
	# occupied. What we should write is "!in_r4 !in_r5", but this is not supported
	# (and probably never will). So we create artificial interferences of the result
	# with all inputs, so the spiller can always assure a free register.
	reg_req   => { in => [ "gp", "gp", "gp", "gp", "ecx", "none" ], out => [ "!in" ] },
	emit      => '
652
653
if (get_ia32_immop_type(node) == ia32_ImmNone) {
	if (get_ia32_op_type(node) == ia32_AddrModeD) {
654
		. shrd%M %%cl, %S3, %AM
655
	} else {
656
		. shrd%M %%cl, %S3, %S2
657
658
659
	}
} else {
	if (get_ia32_op_type(node) == ia32_AddrModeD) {
660
		. shrd%M %C, %S3, %AM
661
	} else {
662
		. shrd%M %C, %S3, %S2
663
	}
664
665
}
',
666
667
	latency   => 6,
	units     => [ "GP" ],
668
669
	mode      => $mode_gp,
	modified_flags => $status_flags
670
671
},

672
l_ShrD => {
673
674
	cmp_attr  => "return 1;",
	arity     => 3
675
676
},

677
Sar => {
678
679
	irn_flags => "R",
	reg_req   => { in => [ "gp", "gp", "gp", "ecx", "none" ], out => [ "in_r3 !in_r4" ] },
680
	emit      => '. sar%M %binop',
681
	units     => [ "GP" ],
682
683
	mode      => $mode_gp,
	modified_flags => $status_flags
684
685
},

686
l_Sar => {
687
688
	cmp_attr  => "return 1;",
	arity     => 2
689
690
},

691
Ror => {
692
693
	irn_flags => "R",
	reg_req   => { in => [ "gp", "gp", "gp", "ecx", "none" ], out => [ "in_r3 !in_r4" ] },
694
	emit      => '. ror%M %binop',
695
	units     => [ "GP" ],
696
697
	mode      => $mode_gp,
	modified_flags => $status_flags
698
699
},

700
Rol => {
701
702
	irn_flags => "R",
	reg_req   => { in => [ "gp", "gp", "gp", "ecx", "none" ], out => [ "in_r3 !in_r4" ] },
703
	emit      => '. rol%M %binop',
704
	units     => [ "GP" ],
705
706
	mode      => $mode_gp,
	modified_flags => $status_flags
707
708
},

709
# unary operations
Christian Würdig's avatar
Christian Würdig committed
710

711
Neg => {
712
713
	irn_flags => "R",
	reg_req   => { in => [ "gp", "gp", "gp", "none" ], out => [ "in_r3" ] },
714
715
	emit      => '. neg%M %unop2',
	ins       => [ "base", "index", "val", "mem" ],
716
	units     => [ "GP" ],
717
718
	mode      => $mode_gp,
	modified_flags => $status_flags
719
720
721
},

Minus64Bit => {
722
723
724
	irn_flags => "R",
	reg_req   => { in => [ "gp", "gp", "gp" ], out => [ "!in", "!in" ] },
	emit      => '
725
726
727
728
. movl %S0, %D0
. movl %S0, %D1
. subl %S1, %D0
. sbbl %S2, %D1
729
',
730
731
	outs      => [ "low_res", "high_res" ],
	units     => [ "GP" ],
732
	modified_flags => $status_flags
733
734
735
},


736
l_Neg => {
737
738
	cmp_attr  => "return 1;",
	arity     => 1,
739
740
},

741
Inc => {
742
743
	irn_flags => "R",
	reg_req   => { in => [ "gp", "gp", "gp", "none" ], out => [ "in_r3" ] },
744
	emit      => '. inc%M %unop2',
745
	units     => [ "GP" ],
746
747
	mode      => $mode_gp,
	modified_flags => [ "OF", "SF", "ZF", "AF", "PF" ]
Christian Würdig's avatar
Christian Würdig committed
748
749
},

750
Dec => {
751
752
	irn_flags => "R",
	reg_req   => { in => [ "gp", "gp", "gp", "none" ], out => [ "in_r3" ] },
753
	emit      => '. dec%M %unop2',
754
	units     => [ "GP" ],
755
756
	mode      => $mode_gp,
	modified_flags => [ "OF", "SF", "ZF", "AF", "PF" ]
757
758
},

759
Not => {
760
761
	irn_flags => "R",
	reg_req   => { in => [ "gp", "gp", "gp", "none" ], out => [ "in_r3" ] },
762
	ins       => [ "base", "index", "val", "mem" ],
763
	emit      => '. not%M %unop2',
764
	units     => [ "GP" ],
765
766
	mode      => $mode_gp,
	modified_flags => []
Christian Würdig's avatar
Christian Würdig committed
767
768
},

Christian Würdig's avatar
Christian Würdig committed
769
770
# other operations

771
CondJmp => {
772
	state     => "pinned",
773
	op_flags  => "L|X|Y",
774
775
776
	reg_req   => { in  => [ "gp", "gp", "gp", "gp", "none" ],
	               out => [ "none", "none"] },
	ins       => [ "base", "index", "left", "right", "mem" ],
777
	outs      => [ "false", "true" ],
778
779
	attr      => "long pnc",
	init_attr => "attr->pn_code = pnc;",
780
781
	latency   => 3,
	units     => [ "BRANCH" ],
782
783
784
},

TestJmp => {
785
	state     => "pinned",
786
	op_flags  => "L|X|Y",
787
788
789
	reg_req   => { in  => [ "gp", "gp", "gp", "gp", "none" ],
	               out => [ "none", "none" ] },
	ins       => [ "base", "index", "left", "right", "mem" ],
790
	outs      => [ "false", "true" ],
791
792
	attr      => "long pnc",
	init_attr => "attr->pn_code = pnc;",
793
794
	latency   => 3,
	units     => [ "BRANCH" ],
795
796
797
},

SwitchJmp => {
798
	state     => "pinned",
799
800
801
802
	op_flags  => "L|X|Y",
	reg_req   => { in => [ "gp" ], out => [ "none" ] },
	latency   => 3,
	units     => [ "BRANCH" ],
803
	mode      => "mode_T",
804
805
806
},

Const => {
807
808
809
810
	op_flags  => "c",
	irn_flags => "R",
	reg_req   => { out => [ "gp" ] },
	units     => [ "GP" ],
811
	mode      => $mode_gp,
812
813
814
},

Unknown_GP => {
815
	state     => "pinned",
816
817
818
819
820
	op_flags  => "c",
	irn_flags => "I",
	reg_req   => { out => [ "gp_UKNWN" ] },
	units     => [],
	emit      => "",
821
	mode      => $mode_gp
822
823
824
},

Unknown_VFP => {
825
	state     => "pinned",
826
827
828
829
830
	op_flags  => "c",
	irn_flags => "I",
	reg_req   => { out => [ "vfp_UKNWN" ] },
	units     => [],
	emit      => "",
831
832
	mode      => "mode_E",
	attr_type => "ia32_x87_attr_t",
833
834
835
},

Unknown_XMM => {
836
	state     => "pinned",
837
838
839
840
841
842
	op_flags  => "c",
	irn_flags => "I",
	reg_req   => { out => [ "xmm_UKNWN" ] },
	units     => [],
	emit      => "",
	mode      => "mode_E"
843
844
845
},

NoReg_GP => {
846
	state     => "pinned",
847
848
849
850
851
	op_flags  => "c",
	irn_flags => "I",
	reg_req   => { out => [ "gp_NOREG" ] },
	units     => [],
	emit      => "",
852
	mode      => $mode_gp
853
854
855
},

NoReg_VFP => {
856
	state     => "pinned",
857
858
859
860
861
	op_flags  => "c",
	irn_flags => "I",
	reg_req   => { out => [ "vfp_NOREG" ] },
	units     => [],
	emit      => "",
862
863
	mode      => "mode_E",
	attr_type => "ia32_x87_attr_t",
864
865
866
},

NoReg_XMM => {
867
	state     => "pinned",
868
869
870
871
872
873
	op_flags  => "c",
	irn_flags => "I",
	reg_req   => { out => [ "xmm_NOREG" ] },
	units     => [],
	emit      => "",
	mode      => "mode_E"
874
875
876
},

ChangeCW => {
877
878
879
	state     => "pinned",
	op_flags  => "c",
	irn_flags => "I",
880
	reg_req   => { out => [ "fp_cw" ] },
881
	mode      => $mode_fpcw,
882
883
	latency   => 3,
	units     => [ "GP" ],
884
	modified_flags => $fpcw_flags
885
886
887
},

FldCW => {
888
	op_flags  => "L|F",
Matthias Braun's avatar
Matthias Braun committed
889
	state     => "pinned",
890
891
892
	reg_req   => { in => [ "gp", "gp", "none" ], out => [ "fp_cw" ] },
	latency   => 5,
	emit      => ". fldcw %AM",
893
	mode      => $mode_fpcw,
894
	units     => [ "GP" ],
895
	modified_flags => $fpcw_flags
896
897
},

898
FnstCW => {
899
	op_flags  => "L|F",
Matthias Braun's avatar
Matthias Braun committed
900
	state     => "pinned",
901
	reg_req   => { in => [ "gp", "gp", "fp_cw", "none" ], out => [ "none" ] },
902
	latency   => 5,
903
	emit      => ". fnstcw %AM",
904
905
	mode      => "mode_M",
	units     => [ "GP" ],
906
907
908
},

Cltd => {
909
910
	# we should not rematrialize this node. It produces 2 results and has
	# very strict constrains
911
912
	reg_req   => { in => [ "eax" ], out => [ "edx" ] },
	ins       => [ "val" ],
913
	emit      => '. cltd',
914
	mode      => $mode_gp,
915
	units     => [ "GP" ],
916
917
},

Christian Würdig's avatar
Christian Würdig committed
918
# Load / Store
919
920
921
#
# Note that we add additional latency values depending on address mode, so a
# lateny of 0 for load is correct
Christian Würdig's avatar
Christian Würdig committed
922

923
Load => {
924
925
926
	op_flags  => "L|F",
	state     => "exc_pinned",
	reg_req   => { in => [ "gp", "gp", "none" ], out => [ "gp", "none" ] },
927
928
	ins       => [ "base", "index", "mem" ],
	outs      => [ "res", "M" ],
929
	latency   => 0,
930
	emit      => ". mov%SE%ME%.l %AM, %D0",
931
	units     => [ "GP" ],
932
933
934
},

l_Load => {
935
936
937
938
	op_flags  => "L|F",
	cmp_attr  => "return 1;",
	outs      => [ "res", "M" ],
	arity     => 2,
939
940
941
},

l_Store => {
942
943
944
945
946
	op_flags  => "L|F",
	cmp_attr  => "return 1;",
	state     => "exc_pinned",
	arity     => 3,
	mode      => "mode_M",
947
948
949
},

Store => {
950
951
952
	op_flags  => "L|F",
	state     => "exc_pinned",
	reg_req   => { in => [ "gp", "gp", "gp", "none" ], out => [ "none" ] },
953
	ins       => [ "base", "index", "val", "mem" ],
954
	emit      => '. mov%M %binop',
955
	latency   => 2,
956
957
	units     => [ "GP" ],
	mode      => "mode_M",
958
959
960
},

Store8Bit => {
961
962
963
964
	op_flags  => "L|F",
	state     => "exc_pinned",
	reg_req   => { in => [ "gp", "gp", "eax ebx ecx edx", "none" ], out => ["none" ] },
	emit      => '. mov%M %binop',
965
	latency   => 2,