ia32_spec.pl 60.5 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
	gp => [
		{ name => "edx", type => 1 },
		{ name => "ecx", type => 1 },
115
116
		{ name => "eax", type => 1 },
		{ name => "ebx", type => 2 },
117
118
119
120
121
122
123
		{ 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
	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 },
134
		{ mode => "mode_E", flags => "manual_ra" }
135
	],
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", flags => "manual_ra" }
172
	],
173
	fp_cw => [	# the floating point control word
174
175
		{ name => "fpcw", type => 4|32 },
		{ mode => "mode_fpcw", flags => "manual_ra|state" }
176
	],
177
	flags => [
178
179
		{ name => "eflags", type => 0 },
		{ mode => "mode_Iu", flags => "manual_ra" }
180
	],
181
182
); # %reg_classes

183
%cpu = (
184
185
186
187
	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" ],
188
189
); # %cpu

190
%vliw = (
191
192
	bundle_size       => 1,
	bundels_per_cycle => 1
193
194
); # vliw

195
%emit_templates = (
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
	S0 => "${arch}_emit_source_register(node, 0);",
	S1 => "${arch}_emit_source_register(node, 1);",
	S2 => "${arch}_emit_source_register(node, 2);",
	S3 => "${arch}_emit_source_register(node, 3);",
	S4 => "${arch}_emit_source_register(node, 4);",
	S5 => "${arch}_emit_source_register(node, 5);",
	SB1 => "${arch}_emit_8bit_source_register_or_immediate(node, 1);",
	SB2 => "${arch}_emit_8bit_source_register_or_immediate(node, 2);",
	SB3 => "${arch}_emit_8bit_source_register_or_immediate(node, 3);",
	SI0 => "${arch}_emit_source_register_or_immediate(node, 0);",
	SI1 => "${arch}_emit_source_register_or_immediate(node, 1);",
	SI2 => "${arch}_emit_source_register_or_immediate(node, 2);",
	SI3 => "${arch}_emit_source_register_or_immediate(node, 3);",
	D0 => "${arch}_emit_dest_register(node, 0);",
	D1 => "${arch}_emit_dest_register(node, 1);",
	D2 => "${arch}_emit_dest_register(node, 2);",
	D3 => "${arch}_emit_dest_register(node, 3);",
	D4 => "${arch}_emit_dest_register(node, 4);",
	D5 => "${arch}_emit_dest_register(node, 5);",
	DB0 => "${arch}_emit_8bit_dest_register(node, 0);",
	X0 => "${arch}_emit_x87_register(node, 0);",
	X1 => "${arch}_emit_x87_register(node, 1);",
	X2 => "${arch}_emit_x87_register(node, 2);",
	SE => "${arch}_emit_extend_suffix(get_ia32_ls_mode(node));",
220
	ME => "if(get_mode_size_bits(get_ia32_ls_mode(node)) != 32)\n
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
	           ia32_emit_mode_suffix(node);",
	M  => "${arch}_emit_mode_suffix(node);",
	XM => "${arch}_emit_x87_mode_suffix(node);",
	XXM => "${arch}_emit_xmm_mode_suffix(node);",
	XSD => "${arch}_emit_xmm_mode_suffix_s(node);",
	AM => "${arch}_emit_am(node);",
	unop0 => "${arch}_emit_unop(node, 0);",
	unop1 => "${arch}_emit_unop(node, 1);",
	unop2 => "${arch}_emit_unop(node, 2);",
	unop3 => "${arch}_emit_unop(node, 3);",
	unop4 => "${arch}_emit_unop(node, 4);",
	unop5 => "${arch}_emit_unop(node, 5);",
	DAM0  => "${arch}_emit_am_or_dest_register(node, 0);",
	DAM1  => "${arch}_emit_am_or_dest_register(node, 1);",
	binop => "${arch}_emit_binop(node, 1);",
	binop_nores => "${arch}_emit_binop(node, 0);",
	x87_binop => "${arch}_emit_x87_binop(node);",
	CMP0  => "${arch}_emit_cmp_suffix_node(node, 0);",
239
240
);

241
242
243
244
245
246
247
248
249
250
251
#--------------------------------------------------#
#                        _                         #
#                       (_)                        #
#  _ __   _____      __  _ _ __    ___  _ __  ___  #
# | '_ \ / _ \ \ /\ / / | | '__|  / _ \| '_ \/ __| #
# | | | |  __/\ V  V /  | | |    | (_) | |_) \__ \ #
# |_| |_|\___| \_/\_/   |_|_|     \___/| .__/|___/ #
#                                      | |         #
#                                      |_|         #
#--------------------------------------------------#

252
$default_attr_type = "ia32_attr_t";
253
$default_copy_attr = "ia32_copy_attr";
254

255
256
257
258
259
sub ia32_custom_init_attr {
	my $node = shift;
	my $name = shift;
	my $res = "";
	if(defined($node->{modified_flags})) {
260
		$res .= "\tset_ia32_flags(res, get_ia32_flags(res) | arch_irn_flags_modify_flags);\n";
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
	}
	if(defined($node->{am})) {
		my $am = $node->{am};
		if($am eq "full,binary") {
			$res .= "\tset_ia32_am_support(res, ia32_am_Full, ia32_am_binary);";
		} elsif($am eq "full,unary") {
			$res .= "\tset_ia32_am_support(res, ia32_am_Full, ia32_am_unary);";
		} elsif($am eq "source,binary") {
			$res .= "\tset_ia32_am_support(res, ia32_am_Source, ia32_am_binary);";
		} elsif($am eq "dest,unary") {
			$res .= "\tset_ia32_am_support(res, ia32_am_Dest, ia32_am_unary);";
		} elsif($am eq "dest,binary") {
			$res .= "\tset_ia32_am_support(res, ia32_am_Dest, ia32_am_binary);";
		} elsif($am eq "dest,ternary") {
			$res .= "\tset_ia32_am_support(res, ia32_am_Dest, ia32_am_ternary);";
		} elsif($am eq "source,ternary") {
			$res .= "\tset_ia32_am_support(res, ia32_am_Source, ia32_am_ternary);";
		} elsif($am eq "none") {
			# nothing to do
		} else {
			die("Invalid address mode '$am' specified on op $name");
		}
	}
	return $res;
}
$custom_init_attr_func = \&ia32_custom_init_attr;

288
289
290
291
292
%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);",
293
294
295
	ia32_asm_attr_t =>
		"\tinit_ia32_attributes(res, flags, in_reqs, out_reqs, exec_units, n_res, latency);\n".
		"\tinit_ia32_x87_attributes(res);".
296
297
298
299
		"\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);"
300
301
302
);

%compare_attr = (
303
304
305
306
	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",
307
308
);

Michael Beck's avatar
Michael Beck committed
309
310
311
%operands = (
);

Matthias Braun's avatar
fix    
Matthias Braun committed
312
$mode_xmm     = "mode_E";
313
$mode_gp      = "mode_Iu";
314
$mode_flags   = "mode_Iu";
315
$mode_fpcw    = "mode_fpcw";
316
317
318
319
$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" ];

320
321
%nodes = (

322
323
324
325
326
Immediate => {
	state     => "pinned",
	op_flags  => "c",
	irn_flags => "I",
	reg_req   => { out => [ "gp_NOREG" ] },
327
	attr      => "ir_entity *symconst, int symconst_sign, long offset",
328
	attr_type => "ia32_immediate_attr_t",
329
	latency   => 0,
330
331
	mode      => $mode_gp,
},
332

333
334
335
336
Asm => {
	mode      => "mode_T",
	arity     => "variable",
	out_arity => "variable",
337
	attr_type => "ia32_asm_attr_t",
338
339
340
341
342
343
344
345
346
347
348
	latency   => 100,
},

ProduceVal => {
	op_flags  => "c",
	irn_flags => "R",
	reg_req   => { out => [ "gp" ] },
	emit      => "",
	units     => [ ],
	latency   => 0,
	mode      => $mode_gp,
Matthias Braun's avatar
Matthias Braun committed
349
	cmp_attr  => "return 1;",
350
351
},

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

363
364
# commutative operations

365
Add => {
366
	irn_flags => "R",
367
	reg_req   => { in => [ "gp", "gp", "none", "gp", "gp" ], out => [ "in_r4 in_r5", "none", "flags" ] },
368
	ins       => [ "base", "index", "mem", "left", "right" ],
369
	emit      => '. add%M %binop',
370
	am        => "full,binary",
371
	units     => [ "GP" ],
372
373
	mode      => $mode_gp,
	modified_flags => $status_flags
374
375
},

376
377
AddMem => {
	irn_flags => "R",
378
379
380
	reg_req   => { in => [ "gp", "gp", "none", "gp" ], out => [ "none" ] },
	ins       => [ "base", "index", "mem", "val" ],
	emit      => ". add%M %SI3, %AM",
381
382
383
384
385
	units     => [ "GP" ],
	mode      => "mode_M",
	modified_flags => $status_flags
},

386
387
388
389
390
391
392
393
394
395
AddMem8Bit => {
	irn_flags => "R",
	reg_req   => { in => [ "gp", "gp", "none", "eax ebx ecx edx" ], out => [ "none" ] },
	ins       => [ "base", "index", "mem", "val" ],
	emit      => ". add%M %SB3, %AM",
	units     => [ "GP" ],
	mode      => "mode_M",
	modified_flags => $status_flags
},

396
Adc => {
397
	reg_req   => { in => [ "gp", "gp", "none", "gp", "gp", "flags" ], out => [ "in_r4 in_r5" ] },
398
	ins       => [ "base", "index", "mem", "left", "right", "eflags" ],
399
	emit      => '. adc%M %binop',
400
	am        => "full,binary",
401
	units     => [ "GP" ],
402
403
	mode      => $mode_gp,
	modified_flags => $status_flags
404
405
},

406
407
408
409
410
411
412
413
414
415
416
l_Add => {
	op_flags  => "C",
	reg_req   => { in => [ "none", "none" ], out => [ "none" ] },
	ins       => [ "left", "right" ],
},

l_Adc => {
	reg_req   => { in => [ "none", "none", "none" ], out => [ "none" ] },
	ins       => [ "left", "right", "eflags" ],
},

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

430
l_Mul => {
431
432
433
434
435
436
	# 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
437
438
439
},

IMul => {
440
	irn_flags => "R",
441
	reg_req   => { in => [ "gp", "gp", "none", "gp", "gp" ], out => [ "in_r4 in_r5" ] },
442
	ins       => [ "base", "index", "mem", "left", "right" ],
443
	emit      => '. imul%M %binop',
444
	am        => "source,binary",
445
446
	latency   => 5,
	units     => [ "GP" ],
447
448
	mode      => $mode_gp,
	modified_flags => $status_flags
449
450
451
},

IMul1OP => {
452
	irn_flags => "R",
453
454
455
	reg_req   => { in => [ "gp", "gp", "none", "eax", "gp" ], out => [ "eax", "edx", "none" ] },
	ins       => [ "base", "index", "mem", "val_high", "val_low" ],
	emit      => '. imul%M %unop4',
456
	outs      => [ "EAX", "EDX", "M" ],
457
	am        => "source,binary",
458
459
	latency   => 5,
	units     => [ "GP" ],
460
	modified_flags => $status_flags
461
462
463
},

l_IMul => {
464
465
	# we should not rematrialize this node. It produces 2 results and has
	# very strict constrains
466
467
	op_flags  => "C",
	cmp_attr  => "return 1;",
468
	outs      => [ "EAX", "EDX", "M" ],
469
	arity     => 2
470
471
472
},

And => {
473
	irn_flags => "R",
474
	reg_req   => { in => [ "gp", "gp", "none", "gp", "gp" ], out => [ "in_r4 in_r5" ] },
475
	ins       => [ "base", "index", "mem", "left", "right" ],
476
	am        => "full,binary",
477
	emit      => '. and%M %binop',
478
	units     => [ "GP" ],
479
480
	mode      => $mode_gp,
	modified_flags => $status_flags
481
482
},

483
484
AndMem => {
	irn_flags => "R",
485
486
487
	reg_req   => { in => [ "gp", "gp", "none", "gp" ], out => [ "none" ] },
	ins       => [ "base", "index", "mem", "val" ],
	emit      => '. and%M %SI3, %AM',
488
489
490
491
492
	units     => [ "GP" ],
	mode      => "mode_M",
	modified_flags => $status_flags
},

493
494
495
496
497
498
499
500
501
502
AndMem8Bit => {
	irn_flags => "R",
	reg_req   => { in => [ "gp", "gp", "none",  "eax ebx ecx edx" ], out => [ "none" ] },
	ins       => [ "base", "index", "mem", "val" ],
	emit      => '. and%M %SB3, %AM',
	units     => [ "GP" ],
	mode      => "mode_M",
	modified_flags => $status_flags
},

503
Or => {
504
	irn_flags => "R",
505
	reg_req   => { in => [ "gp", "gp", "none", "gp", "gp" ], out => [ "in_r4 in_r5" ] },
506
	ins       => [ "base", "index", "mem", "left", "right" ],
507
	am        => "full,binary",
Matthias Braun's avatar
Matthias Braun committed
508
	emit      => '. or%M %binop',
509
	units     => [ "GP" ],
510
511
	mode      => $mode_gp,
	modified_flags => $status_flags
512
513
},

514
515
OrMem => {
	irn_flags => "R",
516
517
518
	reg_req   => { in => [ "gp", "gp", "none", "gp" ], out => [ "none" ] },
	ins       => [ "base", "index", "mem", "val" ],
	emit      => '. or%M %SI3, %AM',
519
520
521
522
523
	units     => [ "GP" ],
	mode      => "mode_M",
	modified_flags => $status_flags
},

524
525
526
527
528
529
530
531
532
533
OrMem8Bit => {
	irn_flags => "R",
	reg_req   => { in => [ "gp", "gp", "none", "eax ebx ecx edx" ], out => [ "none" ] },
	ins       => [ "base", "index", "mem", "val" ],
	emit      => '. or%M %SB3, %AM',
	units     => [ "GP" ],
	mode      => "mode_M",
	modified_flags => $status_flags
},

534
Xor => {
535
	irn_flags => "R",
536
	reg_req   => { in => [ "gp", "gp", "none", "gp", "gp" ], out => [ "in_r4 in_r5" ] },
537
	ins       => [ "base", "index", "mem", "left", "right" ],
538
	am        => "full,binary",
539
	emit      => '. xor%M %binop',
540
	units     => [ "GP" ],
541
542
	mode      => $mode_gp,
	modified_flags => $status_flags
543
544
},

545
546
XorMem => {
	irn_flags => "R",
547
548
549
	reg_req   => { in => [ "gp", "gp", "none", "gp" ], out => [ "none" ] },
	ins       => [ "base", "index", "mem", "val" ],
	emit      => '. xor%M %SI3, %AM',
550
551
552
553
554
	units     => [ "GP" ],
	mode      => "mode_M",
	modified_flags => $status_flags
},

555
556
557
558
559
560
561
562
563
564
XorMem8Bit => {
	irn_flags => "R",
	reg_req   => { in => [ "gp", "gp", "none", "eax ebx ecx edx" ], out => [ "none" ] },
	ins       => [ "base", "index", "mem", "val" ],
	emit      => '. xor%M %SB3, %AM',
	units     => [ "GP" ],
	mode      => "mode_M",
	modified_flags => $status_flags
},

565
566
# not commutative operations

567
Sub => {
568
	irn_flags => "R",
569
570
	reg_req   => { in => [ "gp", "gp", "none", "gp", "gp" ], out => [ "in_r4" ] },
	ins       => [ "base", "index", "mem", "left", "right" ],
571
	am        => "full,binary",
572
	emit      => '. sub%M %binop',
573
	units     => [ "GP" ],
574
575
	mode      => $mode_gp,
	modified_flags => $status_flags
576
577
},

578
579
SubMem => {
	irn_flags => "R",
580
581
582
	reg_req   => { in => [ "gp", "gp", "none", "gp" ], out => [ "none" ] },
	ins       => [ "base", "index", "mem", "val" ],
	emit      => '. sub%M %SI3, %AM',
583
584
585
586
587
	units     => [ "GP" ],
	mode      => 'mode_M',
	modified_flags => $status_flags
},

588
589
590
591
592
593
594
595
596
597
SubMem8Bit => {
	irn_flags => "R",
	reg_req   => { in => [ "gp", "gp", "none", "eax ebx ecx edx" ], out => [ "none" ] },
	ins       => [ "base", "index", "mem", "val" ],
	emit      => '. sub%M %SB3, %AM',
	units     => [ "GP" ],
	mode      => 'mode_M',
	modified_flags => $status_flags
},

598
Sbb => {
599
600
	reg_req   => { in => [ "gp", "gp", "none", "gp", "gp" ], out => [ "in_r4 !in_r5" ] },
	ins       => [ "base", "index", "mem", "left", "right" ],
601
	am        => "full,binary",
602
	emit      => '. sbb%M %binop',
603
	units     => [ "GP" ],
604
605
	mode      => $mode_gp,
	modified_flags => $status_flags
606
607
608
},

Sub64Bit => {
609
610
611
612
	irn_flags => "R",
	arity     => 4,
	reg_req   => { in => [ "gp", "gp", "gp", "gp" ], out => [ "!in", "!in" ] },
	emit      => '
613
. movl %S0, %D0
614
. movl %S1, %D1
615
616
. subl %SI2, %D0
. sbbl %SI3, %D1
617
',
618
619
	outs      => [ "low_res", "high_res" ],
	units     => [ "GP" ],
620
	modified_flags => $status_flags
621
622
},

623
IDiv => {
624
625
	op_flags  => "F|L",
	state     => "exc_pinned",
626
627
	reg_req   => { in => [ "gp", "gp", "none", "eax", "edx", "gp" ], out => [ "eax", "edx", "none" ] },
	ins       => [ "base", "index", "mem", "left_low", "left_high", "right" ],
628
	outs      => [ "div_res", "mod_res", "M" ],
629
	attr      => "ia32_op_flavour_t dm_flav",
630
631
	am        => "source,ternary",
	init_attr => "attr->data.op_flav = dm_flav;",
632
	emit      => ". idiv%M %unop5",
633
634
	latency   => 25,
	units     => [ "GP" ],
635
	modified_flags => $status_flags
636
637
},

638
Div => {
639
640
	op_flags  => "F|L",
	state     => "exc_pinned",
641
642
	reg_req   => { in => [ "gp", "gp", "none", "eax", "edx", "gp" ], out => [ "eax", "edx", "none" ] },
	ins       => [ "base", "index", "mem", "left_low", "left_high", "right" ],
643
	outs      => [ "div_res", "mod_res", "M" ],
644
	attr      => "ia32_op_flavour_t dm_flav",
645
646
	am        => "source,ternary",
	init_attr => "attr->data.op_flav = dm_flav;",
647
	emit      => ". div%M %unop5",
648
649
	latency   => 25,
	units     => [ "GP" ],
650
	modified_flags => $status_flags
651
652
},

653
Shl => {
654
	irn_flags => "R",
655
656
	reg_req   => { in => [ "gp", "ecx" ], out => [ "in_r1 !in_r2" ] },
	ins       => [ "left", "right" ],
657
	am        => "dest,binary",
658
	emit      => '. shl %SB1, %S0',
659
	units     => [ "GP" ],
660
661
	mode      => $mode_gp,
	modified_flags => $status_flags
662
663
},

664
665
ShlMem => {
	irn_flags => "R",
666
667
668
	reg_req   => { in => [ "gp", "gp", "none", "ecx" ], out => [ "none" ] },
	ins       => [ "base", "index", "mem", "count" ],
	emit      => '. shl%M %SB3, %AM',
669
670
671
672
673
	units     => [ "GP" ],
	mode      => "mode_M",
	modified_flags => $status_flags
},

674
l_ShlDep => {
675
	cmp_attr  => "return 1;",
676
677
	# value, cnt, dependency
	arity     => 3
678
679
},

680
ShlD => {
681
682
	# FIXME: WHY? the right requirement is in_r3 !in_r5, especially this is the same as in Shl
	#
683
684
685
	# 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
686
687
688
689
690
691
692
693
	# 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" ] },

	irn_flags => "R",
694
695
	reg_req   => { in => [ "gp", "gp", "ecx" ], out => [ "in_r1 !in_r3" ] },
	ins       => [ "left_high", "left_low", "right" ],
696
	am        => "dest,ternary",
697
	emit      => '. shld%M %SB2, %S1, %S0',
698
699
	latency   => 6,
	units     => [ "GP" ],
700
701
	mode      => $mode_gp,
	modified_flags => $status_flags
702
703
},

704
l_ShlD => {
705
706
	cmp_attr  => "return 1;",
	arity     => 3,
707
708
},

709
Shr => {
710
	irn_flags => "R",
711
712
	reg_req   => { in => [ "gp", "ecx" ], out => [ "in_r1 !in_r2" ] },
	ins       => [ "val", "count" ],
713
	am        => "dest,binary",
714
	emit      => '. shr %SB1, %S0',
715
	units     => [ "GP" ],
716
717
	mode      => $mode_gp,
	modified_flags => $status_flags
718
719
},

720
721
ShrMem => {
	irn_flags => "R",
722
723
724
	reg_req   => { in => [ "gp", "gp", "none", "ecx" ], out => [ "none" ] },
	ins       => [ "base", "index", "mem", "count" ],
	emit      => '. shr%M %SB3, %AM',
725
726
727
728
729
	units     => [ "GP" ],
	mode      => "mode_M",
	modified_flags => $status_flags
},

730
l_ShrDep => {
731
	cmp_attr  => "return 1;",
732
733
	# value, cnt, dependency
	arity     => 3
734
735
},

736
ShrD => {
737
738
	# FIXME: WHY? the right requirement is in_r3 !in_r5, especially this is the same as in Shr
	#
739
740
741
742
743
744
745
746
	# 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.
747
748
749
	# reg_req   => { in => [ "gp", "gp", "gp", "gp", "ecx", "none" ], out => [ "!in" ] },

	irn_flags => "R",
750
751
	reg_req   => { in => [ "gp", "gp", "ecx" ], out => [ "in_r1 !in_r3" ] },
	ins       => [ "left_high", "left_low", "right" ],
752
	am        => "dest,ternary",
753
	emit      => '. shrd%M %SB2, %S1, %S0',
754
755
	latency   => 6,
	units     => [ "GP" ],
756
757
	mode      => $mode_gp,
	modified_flags => $status_flags
758
759
},

760
l_ShrD => {
761
762
	cmp_attr  => "return 1;",
	arity     => 3
763
764
},

765
Sar => {
766
	irn_flags => "R",
767
768
	reg_req   => { in => [ "gp", "ecx" ], out => [ "in_r1 !in_r2" ] },
	ins       => [ "val", "count" ],
769
	am        => "dest,binary",
770
	emit      => '. sar %SB1, %S0',
771
	units     => [ "GP" ],
772
773
	mode      => $mode_gp,
	modified_flags => $status_flags
774
775
},

776
777
SarMem => {
	irn_flags => "R",
778
779
780
	reg_req   => { in => [ "gp", "gp", "none", "ecx" ], out => [ "none" ] },
	ins       => [ "base", "index", "mem", "count" ],
	emit      => '. sar%M %SB3, %AM',
781
782
783
784
785
	units     => [ "GP" ],
	mode      => "mode_M",
	modified_flags => $status_flags
},

786
l_Sar => {
787
	cmp_attr  => "return 1;",
788
	# value, cnt
789
	arity     => 2
790
791
},

792
793
794
795
796
797
l_SarDep => {
	cmp_attr  => "return 1;",
	# value, cnt, dependency
	arity     => 3
},

798
Ror => {
799
	irn_flags => "R",
800
801
	reg_req   => { in => [ "gp", "ecx" ], out => [ "in_r1 !in_r2" ] },
	ins       => [ "val", "count" ],
802
	am        => "dest,binary",
803
	emit      => '. ror %SB1, %S0',
804
	units     => [ "GP" ],
805
806
	mode      => $mode_gp,
	modified_flags => $status_flags
807
808
},

809
810
RorMem => {
	irn_flags => "R",
811
812
813
	reg_req   => { in => [ "gp", "gp", "none", "ecx" ], out => [ "none" ] },
	ins       => [ "base", "index", "mem", "count" ],
	emit      => '. ror%M %SB3, %AM',
814
815
816
817
818
	units     => [ "GP" ],
	mode      => "mode_M",
	modified_flags => $status_flags
},

819
Rol => {
820
	irn_flags => "R",
821
822
	reg_req   => { in => [ "gp", "ecx" ], out => [ "in_r1 !in_r2" ] },
	ins       => [ "val", "count" ],
823
	am        => "dest,binary",
824
	emit      => '. rol %SB1, %S0',
825
	units     => [ "GP" ],
826
827
	mode      => $mode_gp,
	modified_flags => $status_flags
828
829
},

830
831
RolMem => {
	irn_flags => "R",
832
833
834
	reg_req   => { in => [ "gp", "gp", "none", "ecx" ], out => [ "none" ] },
	ins       => [ "base", "index", "mem", "count" ],
	emit      => '. rol%M %SB3, %AM',
835
836
837
838
839
	units     => [ "GP" ],
	mode      => "mode_M",
	modified_flags => $status_flags
},

840
# unary operations
Christian Würdig's avatar
Christian Würdig committed
841

842
Neg => {
843
	irn_flags => "R",
844
845
846
	reg_req   => { in => [ "gp" ], out => [ "in_r1" ] },
	emit      => '. neg %S0',
	ins       => [ "val" ],
847
	am        => "dest,unary",
848
	units     => [ "GP" ],
849
850
	mode      => $mode_gp,
	modified_flags => $status_flags
851
852
},

853
854
855
856
857
858
859
860
861
862
NegMem => {
	irn_flags => "R",
	reg_req   => { in => [ "gp", "gp", "none" ], out => [ "none" ] },
	ins       => [ "base", "index", "mem" ],
	emit      => '. neg%M %AM',
	units     => [ "GP" ],
	mode      => "mode_M",
	modified_flags => $status_flags
},

863
Minus64Bit => {
864
	irn_flags => "R",
865
	reg_req   => { in => [ "gp", "gp" ], out => [ "in_r1", "gp" ] },
866
867
	outs      => [ "low_res", "high_res" ],
	units     => [ "GP" ],
868
	modified_flags => $status_flags
869
870
871
},


872
l_Neg => {
873
874
	cmp_attr  => "return 1;",
	arity     => 1,
875
876
},

877
Inc => {
878
	irn_flags => "R",
879
	reg_req   => { in => [ "gp" ], out => [ "in_r1" ] },
880
	am        => "dest,unary",
881
	emit      => '. inc %S0',
882
	units     => [ "GP" ],
883
884
	mode      => $mode_gp,
	modified_flags => [ "OF", "SF", "ZF", "AF", "PF" ]
Christian Würdig's avatar
Christian Würdig committed
885
886
},

887
888
889
890
891
892
893
894
895
896
IncMem => {
	irn_flags => "R",
	reg_req   => { in => [ "gp", "gp", "none" ], out => [ "none" ] },
	ins       => [ "base", "index", "mem" ],
	emit      => '. inc%M %AM',
	units     => [ "GP" ],
	mode      => "mode_M",
	modified_flags => [ "OF", "SF", "ZF", "AF", "PF" ]
},

897
Dec => {
898
	irn_flags => "R",
899
	reg_req   => { in => [ "gp" ], out => [ "in_r1" ] },
900
	am        => "dest,unary",
901
	emit      => '. dec %S0',
902
	units     => [ "GP" ],
903
904
	mode      => $mode_gp,
	modified_flags => [ "OF", "SF", "ZF", "AF", "PF" ]
905
906
},

907
908
909
910
911
912
913
914
915
916
DecMem => {
	irn_flags => "R",
	reg_req   => { in => [ "gp", "gp", "none" ], out => [ "none" ] },
	ins       => [ "base", "index", "mem" ],
	emit      => '. dec%M %AM',
	units     => [ "GP" ],
	mode      => "mode_M",
	modified_flags => [ "OF", "SF", "ZF", "AF", "PF" ]
},

917
Not => {
918
	irn_flags => "R",
919
920
	reg_req   => { in => [ "gp" ], out => [ "in_r1" ] },
	ins       => [ "val" ],
921
	am        => "dest,unary",
922
	emit      => '. not %S0',
923
	units     => [ "GP" ],
924
	mode      => $mode_gp,
Christian Würdig's avatar
Christian Würdig committed
925
926
},

927
928
929
930
931
932
933
934
935
NotMem => {
	irn_flags => "R",
	reg_req   => { in => [ "gp", "gp", "none" ], out => [ "none" ] },
	ins       => [ "base", "index", "mem" ],
	emit      => '. not%M %AM',
	units     => [ "GP" ],
	mode      => "mode_M",
},

Christian Würdig's avatar
Christian Würdig committed
936
937
# other operations

938
939
940
Cmp => {
	irn_flags => "R",
	reg_req   => { in => [ "gp", "gp", "none", "gp", "gp" ] , out => [ "flags" ] },
941
	ins       => [ "base", "index", "mem", "left", "right" ],
942
	outs      => [ "eflags" ],
943
	am        => "source,binary",
944
945
946
947
948
949
950
951
	emit      => '. cmp%M %binop_nores',
	attr      => "int flipped, int cmp_unsigned",
	init_attr => "attr->data.cmp_flipped = flipped;\n".
	             "\tattr->data.cmp_unsigned = cmp_unsigned;\n",
	latency   => 1,
	units     => [ "GP" ],
	mode      => $mode_flags,
	modified_flags => $status_flags
952
953
},

954
955
956
Cmp8Bit => {
	irn_flags => "R",
	reg_req   => { in => [ "gp", "gp", "none", "eax ebx ecx edx", "eax ebx ecx edx" ] , out => [ "flags" ] },
957
	ins       => [ "base", "index", "mem", "left", "right" ],
958
	outs      => [ "eflags" ],
959
	am        => "source,binary",
960
961
962
963
964
965
966
967
	emit      => '. cmpb %binop_nores',
	attr      => "int flipped, int cmp_unsigned",
	init_attr => "attr->data.cmp_flipped = flipped;\n".
	             "\tattr->data.cmp_unsigned = cmp_unsigned;\n",
	latency   => 1,
	units     => [ "GP" ],
	mode      => $mode_flags,
	modified_flags => $status_flags
968
969
},

970
971
972
Test => {
	irn_flags => "R",
	reg_req   => { in => [ "gp", "gp", "none", "gp", "gp" ] , out => [ "flags" ] },
973
	ins       => [ "base", "index", "mem", "left", "right" ],
974
	outs      => [ "eflags" ],
975
	am        => "source,binary",
976
977
978
979
980
981
982
983
984