3 # This is the specification for the ia32 assembler Firm-operations
7 # the cpu architecture (ia32, ia64, mips, sparc, ppc, ...)
10 # The node description is done as a perl hash initializer with the
11 # following structure:
16 # "op_flags" => "N|L|C|X|I|F|Y|H|c|K",
17 # "irn_flags" => "R|N|I|S"
18 # "arity" => "0|1|2|3 ... |variable|dynamic|any",
19 # "state" => "floats|pinned|mem_pinned|exc_pinned",
21 # { "type" => "type 1", "name" => "name 1" },
22 # { "type" => "type 2", "name" => "name 2" },
25 # "comment" => "any comment for constructor",
26 # "reg_req" => { "in" => [ "reg_class|register" ], "out" => [ "reg_class|register|in_rX" ] },
27 # "cmp_attr" => "c source code for comparing node attributes",
28 # "emit" => "emit code with templates",
29 # "attr" => "attitional attribute arguments for constructor"
30 # "init_attr" => "emit attribute initialization template"
31 # "rd_constructor" => "c source code which constructs an ir_node"
32 # "latency" => "latency of this operation (can be float)"
35 # ... # (all nodes you need to describe)
37 # ); # close the %nodes initializer
39 # op_flags: flags for the operation, OPTIONAL (default is "N")
40 # the op_flags correspond to the firm irop_flags:
43 # C irop_flag_commutative
44 # X irop_flag_cfopcode
45 # I irop_flag_ip_cfopcode
48 # H irop_flag_highlevel
49 # c irop_flag_constlike
52 # irn_flags: special node flags, OPTIONAL (default is 0)
53 # following irn_flags are supported:
56 # I ignore for register allocation
57 # S modifies stack pointer
59 # state: state of the operation, OPTIONAL (default is "floats")
61 # arity: arity of the operation, MUST NOT BE OMITTED
63 # args: the OPTIONAL arguments of the node constructor (debug, irg and block
64 # are always the first 3 arguments and are always autmatically
66 # If this key is missing the following arguments will be created:
67 # for i = 1 .. arity: ir_node *op_i
70 # outs: if a node defines more than one output, the names of the projections
71 # nodes having outs having automatically the mode mode_T
72 # One can also annotate some flags for each out, additional to irn_flags.
73 # They are separated from name with a colon ':', and concatenated by pipe '|'
74 # Only I and S are available at the moment (same meaning as in irn_flags).
75 # example: [ "frame:I", "stack:I|S", "M" ]
77 # comment: OPTIONAL comment for the node constructor
79 # rd_constructor: for every operation there will be a
80 # new_rd_<arch>_<op-name> function with the arguments from above
81 # which creates the ir_node corresponding to the defined operation
82 # you can either put the complete source code of this function here
84 # This key is OPTIONAL. If omitted, the following constructor will
86 # if (!op_<arch>_<op-name>) assert(0);
90 # res = new_ir_node(db, irg, block, op_<arch>_<op-name>, mode, arity, in)
93 # NOTE: rd_constructor and args are only optional if and only if arity is 0,1,2 or 3
95 # latency: the latency of the operation, default is 1
100 # 1 - caller save (register must be saved by the caller of a function)
101 # 2 - callee save (register must be saved by the called function)
102 # 4 - ignore (do not assign this register)
103 # 8 - emitter can choose an arbitrary register of this class
104 # 16 - the register is a virtual one
105 # NOTE: Last entry of each class is the largest Firm-Mode a register can hold
108 { "name" => "eax", "type" => 1 },
109 { "name" => "edx", "type" => 1 },
110 { "name" => "ebx", "type" => 2 },
111 { "name" => "ecx", "type" => 1 },
112 { "name" => "esi", "type" => 2 },
113 { "name" => "edi", "type" => 2 },
114 { "name" => "ebp", "type" => 2 },
115 { "name" => "esp", "type" => 4 },
116 { "name" => "gp_NOREG", "type" => 4 | 8 | 16 }, # we need a dummy register for NoReg nodes
117 { "name" => "gp_UKNWN", "type" => 4 | 8 | 16 }, # we need a dummy register for Unknown nodes
118 { "mode" => "mode_Iu" }
121 { "name" => "xmm0", "type" => 1 },
122 { "name" => "xmm1", "type" => 1 },
123 { "name" => "xmm2", "type" => 1 },
124 { "name" => "xmm3", "type" => 1 },
125 { "name" => "xmm4", "type" => 1 },
126 { "name" => "xmm5", "type" => 1 },
127 { "name" => "xmm6", "type" => 1 },
128 { "name" => "xmm7", "type" => 1 },
129 { "name" => "xmm_NOREG", "type" => 4 | 8 | 16 }, # we need a dummy register for NoReg nodes
130 { "name" => "xmm_UKNWN", "type" => 4 | 8 | 16 }, # we need a dummy register for Unknown nodes
131 { "mode" => "mode_E" }
134 { "name" => "vf0", "type" => 1 | 16 },
135 { "name" => "vf1", "type" => 1 | 16 },
136 { "name" => "vf2", "type" => 1 | 16 },
137 { "name" => "vf3", "type" => 1 | 16 },
138 { "name" => "vf4", "type" => 1 | 16 },
139 { "name" => "vf5", "type" => 1 | 16 },
140 { "name" => "vf6", "type" => 1 | 16 },
141 { "name" => "vf7", "type" => 1 | 16 },
142 { "name" => "vfp_NOREG", "type" => 4 | 8 | 16 }, # we need a dummy register for NoReg nodes
143 { "name" => "vfp_UKNWN", "type" => 4 | 8 | 16 }, # we need a dummy register for Unknown nodes
144 { "mode" => "mode_E" }
147 { "name" => "st0", "type" => 1 },
148 { "name" => "st1", "type" => 1 },
149 { "name" => "st2", "type" => 1 },
150 { "name" => "st3", "type" => 1 },
151 { "name" => "st4", "type" => 1 },
152 { "name" => "st5", "type" => 1 },
153 { "name" => "st6", "type" => 1 },
154 { "name" => "st7", "type" => 1 },
155 { "mode" => "mode_E" }
157 "fp_cw" => [ # the floating point control word
158 { "name" => "fpcw", "type" => 0 },
159 { "mode" => "mode_Hu" },
164 "GP" => [ 1, "GP_EAX", "GP_EBX", "GP_ECX", "GP_EDX", "GP_ESI", "GP_EDI", "GP_EBP" ],
165 "SSE" => [ 1, "SSE_XMM0", "SSE_XMM1", "SSE_XMM2", "SSE_XMM3", "SSE_XMM4", "SSE_XMM5", "SSE_XMM6", "SSE_XMM7" ],
166 "VFP" => [ 1, "VFP_VF0", "VFP_VF1", "VFP_VF2", "VFP_VF3", "VFP_VF4", "VFP_VF5", "VFP_VF6", "VFP_VF7" ],
167 "BRANCH" => [ 1, "BRANCH1", "BRANCH2" ],
172 "bundels_per_cycle" => 1
176 "S1" => "${arch}_emit_source_register(env, node, 0);",
177 "S2" => "${arch}_emit_source_register(env, node, 1);",
178 "S3" => "${arch}_emit_source_register(env, node, 2);",
179 "S4" => "${arch}_emit_source_register(env, node, 3);",
180 "S5" => "${arch}_emit_source_register(env, node, 4);",
181 "S6" => "${arch}_emit_source_register(env, node, 5);",
182 "D1" => "${arch}_emit_dest_register(env, node, 0);",
183 "D2" => "${arch}_emit_dest_register(env, node, 1);",
184 "D3" => "${arch}_emit_dest_register(env, node, 2);",
185 "D4" => "${arch}_emit_dest_register(env, node, 3);",
186 "D5" => "${arch}_emit_dest_register(env, node, 4);",
187 "D6" => "${arch}_emit_dest_register(env, node, 5);",
188 "A1" => "${arch}_emit_in_node_name(env, node, 0);",
189 "A2" => "${arch}_emit_in_node_name(env, node, 1);",
190 "A3" => "${arch}_emit_in_node_name(env, node, 2);",
191 "A4" => "${arch}_emit_in_node_name(env, node, 3);",
192 "A5" => "${arch}_emit_in_node_name(env, node, 4);",
193 "A6" => "${arch}_emit_in_node_name(env, node, 5);",
194 "X1" => "${arch}_emit_x87_name(env, node, 0);",
195 "X2" => "${arch}_emit_x87_name(env, node, 1);",
196 "X3" => "${arch}_emit_x87_name(env, node, 2);",
197 "C" => "${arch}_emit_immediate(env, node);",
198 "SE" => "${arch}_emit_extend_suffix(env, get_ia32_ls_mode(node));",
199 "ME" => "if(get_mode_size_bits(get_ia32_ls_mode(node)) != 32)\n
200 ${arch}_emit_mode_suffix(env, get_ia32_ls_mode(node));",
201 "M" => "${arch}_emit_mode_suffix(env, get_ia32_ls_mode(node));",
202 "XM" => "${arch}_emit_x87_mode_suffix(env, node);",
203 "XXM" => "${arch}_emit_xmm_mode_suffix(env, node);",
204 "AM" => "${arch}_emit_am(env, node);",
205 "unop" => "${arch}_emit_unop(env, node);",
206 "binop" => "${arch}_emit_binop(env, node);",
207 "x87_binop" => "${arch}_emit_x87_binop(env, node);",
210 #--------------------------------------------------#
213 # _ __ _____ __ _ _ __ ___ _ __ ___ #
214 # | '_ \ / _ \ \ /\ / / | | '__| / _ \| '_ \/ __| #
215 # | | | | __/\ V V / | | | | (_) | |_) \__ \ #
216 # |_| |_|\___| \_/\_/ |_|_| \___/| .__/|___/ #
219 #--------------------------------------------------#
221 $default_cmp_attr = "return ia32_compare_attr(attr_a, attr_b);";
228 #-----------------------------------------------------------------#
231 # _ _ __ | |_ ___ __ _ ___ _ __ _ __ ___ __| | ___ ___ #
232 # | | '_ \| __/ _ \/ _` |/ _ \ '__| | '_ \ / _ \ / _` |/ _ \/ __| #
233 # | | | | | || __/ (_| | __/ | | | | | (_) | (_| | __/\__ \ #
234 # |_|_| |_|\__\___|\__, |\___|_| |_| |_|\___/ \__,_|\___||___/ #
237 #-----------------------------------------------------------------#
239 # commutative operations
242 # All nodes supporting Addressmode have 5 INs:
243 # 1 - base r1 == NoReg in case of no AM or no base
244 # 2 - index r2 == NoReg in case of no AM or no index
245 # 3 - op1 r3 == always present
246 # 4 - op2 r4 == NoReg in case of immediate operation
247 # 5 - mem NoMem in case of no AM otherwise it takes the mem from the Load
251 "comment" => "construct Add: Add(a, b) = Add(b, a) = a + b",
252 "reg_req" => { "in" => [ "gp", "gp", "gp", "gp", "none" ], "out" => [ "in_r3" ] },
253 "emit" => '. addl %binop',
259 "comment" => "construct Add with Carry: Adc(a, b) = Add(b, a) = a + b + carry",
260 "reg_req" => { "in" => [ "gp", "gp", "gp", "gp", "none" ], "out" => [ "in_r3" ] },
261 "emit" => '. adcl %binop',
268 "comment" => "construct 64Bit Add: Add(a_l, a_h, b_l, b_h) = a_l + b_l; a_h + b_h + carry",
270 "reg_req" => { "in" => [ "gp", "gp", "gp", "gp" ], "out" => [ "!in", "!in" ] },
277 "outs" => [ "low_res", "high_res" ],
284 "cmp_attr" => "return 1;",
285 "comment" => "construct lowered Add: Add(a, b) = Add(b, a) = a + b",
291 "cmp_attr" => "return 1;",
292 "comment" => "construct lowered Add with Carry: Adc(a, b) = Adc(b, a) = a + b + carry",
297 # we should not rematrialize this node. It produces 2 results and has
298 # very strict constrains
299 "comment" => "construct MulS: MulS(a, b) = MulS(b, a) = a * b",
300 "reg_req" => { "in" => [ "gp", "gp", "eax", "gp", "none" ], "out" => [ "eax", "edx", "none" ] },
301 "emit" => '. mull %unop',
302 "outs" => [ "EAX", "EDX", "M" ],
308 # we should not rematrialize this node. It produces 2 results and has
309 # very strict constrains
311 "cmp_attr" => "return 1;",
312 "comment" => "construct lowered MulS: Mul(a, b) = Mul(b, a) = a * b",
313 "outs" => [ "EAX", "EDX", "M" ],
319 "comment" => "construct Mul: Mul(a, b) = Mul(b, a) = a * b",
320 "reg_req" => { "in" => [ "gp", "gp", "gp", "gp", "none" ], "out" => [ "in_r3" ] },
321 "emit" => '. imull %binop',
329 "comment" => "construct Mul (1 operand format): Mul(a, b) = Mul(b, a) = a * b",
330 "reg_req" => { "in" => [ "gp", "gp", "eax", "gp", "none" ], "out" => [ "eax", "edx", "none" ] },
331 "emit" => '. imull %unop',
332 "outs" => [ "EAX", "EDX", "M" ],
339 "cmp_attr" => "return 1;",
340 "comment" => "construct lowered IMul: IMul(a, b) = IMul(b, a) = a * b",
346 "comment" => "construct And: And(a, b) = And(b, a) = a AND b",
347 "reg_req" => { "in" => [ "gp", "gp", "gp", "gp", "none" ], "out" => [ "in_r3" ] },
348 "emit" => '. andl %binop',
355 "comment" => "construct Or: Or(a, b) = Or(b, a) = a OR b",
356 "reg_req" => { "in" => [ "gp", "gp", "gp", "gp", "none" ], "out" => [ "in_r3" ] },
357 "emit" => '. orl %binop',
364 "comment" => "construct Xor: Xor(a, b) = Xor(b, a) = a EOR b",
365 "reg_req" => { "in" => [ "gp", "gp", "gp", "gp", "none" ], "out" => [ "in_r3" ] },
366 "emit" => '. xorl %binop',
373 "cmp_attr" => "return 1;",
374 "comment" => "construct lowered Xor: Xor(a, b) = Xor(b, a) = a XOR b",
378 # not commutative operations
382 "comment" => "construct Sub: Sub(a, b) = a - b",
383 "reg_req" => { "in" => [ "gp", "gp", "gp", "gp", "none" ], "out" => [ "in_r3" ] },
384 "emit" => '. subl %binop',
390 "comment" => "construct Sub with Carry: SubC(a, b) = a - b - carry",
391 "reg_req" => { "in" => [ "gp", "gp", "gp", "gp", "none" ], "out" => [ "in_r3 !in_r4" ] },
392 "emit" => '. sbbl %binop',
399 "comment" => "construct 64Bit Sub: Sub(a_l, a_h, b_l, b_h) = a_l - b_l; a_h - b_h - borrow",
401 "reg_req" => { "in" => [ "gp", "gp", "gp", "gp" ], "out" => [ "!in", "!in" ] },
408 "outs" => [ "low_res", "high_res" ],
414 "cmp_attr" => "return 1;",
415 "comment" => "construct lowered Sub: Sub(a, b) = a - b",
420 "cmp_attr" => "return 1;",
421 "comment" => "construct lowered Sub with Carry: SubC(a, b) = a - b - carry",
427 "state" => "exc_pinned",
428 "reg_req" => { "in" => [ "gp", "gp", "eax", "edx", "gp", "none" ], "out" => [ "eax", "edx", "none" ] },
429 "attr" => "ia32_op_flavour_t dm_flav",
430 "init_attr" => "attr->data.op_flav = dm_flav;",
431 "emit" => ". idivl %unop",
432 "outs" => [ "div_res", "mod_res", "M" ],
439 "state" => "exc_pinned",
440 "reg_req" => { "in" => [ "gp", "gp", "eax", "edx", "gp", "none" ], "out" => [ "eax", "edx", "none" ] },
441 "attr" => "ia32_op_flavour_t dm_flav",
442 "init_attr" => "attr->data.op_flav = dm_flav;",
443 "emit" => ". divl %unop",
444 "outs" => [ "div_res", "mod_res", "M" ],
451 "comment" => "construct Shl: Shl(a, b) = a << b",
452 "reg_req" => { "in" => [ "gp", "gp", "gp", "ecx", "none" ], "out" => [ "in_r3 !in_r4" ] },
453 "emit" => '. shll %binop',
459 "cmp_attr" => "return 1;",
460 "comment" => "construct lowered Shl: Shl(a, b) = a << b",
466 "comment" => "construct ShlD: ShlD(a, b, c) = a, b << count (shift left count bits from b into a)",
467 # Out requirements is: different from all in
468 # This is because, out must be different from LowPart and ShiftCount.
469 # We could say "!ecx !in_r4" but it can occur, that all values live through
470 # this Shift and the only value dying is the ShiftCount. Then there would be a
471 # register missing, as result must not be ecx and all other registers are
472 # occupied. What we should write is "!in_r4 !in_r5", but this is not supported
473 # (and probably never will). So we create artificial interferences of the result
474 # with all inputs, so the spiller can always assure a free register.
475 "reg_req" => { "in" => [ "gp", "gp", "gp", "gp", "ecx", "none" ], "out" => [ "!in" ] },
478 if (get_ia32_immop_type(node) == ia32_ImmNone) {
479 if (get_ia32_op_type(node) == ia32_AddrModeD) {
480 . shldl %%cl, %S4, %AM
482 . shldl %%cl, %S4, %S3
485 if (get_ia32_op_type(node) == ia32_AddrModeD) {
486 . shldl $%C, %S4, %AM
488 . shldl $%C, %S4, %S3
498 "cmp_attr" => "return 1;",
499 "comment" => "construct lowered ShlD: ShlD(a, b, c) = a, b << count (shift left count bits from b into a)",
505 "comment" => "construct Shr: Shr(a, b) = a >> b",
506 "reg_req" => { "in" => [ "gp", "gp", "gp", "ecx", "none" ], "out" => [ "in_r3 !in_r4" ] },
507 "emit" => '. shrl %binop',
513 "cmp_attr" => "return 1;",
514 "comment" => "construct lowered Shr: Shr(a, b) = a << b",
520 "comment" => "construct ShrD: ShrD(a, b, c) = a, b >> count (shift rigth count bits from a into b)",
521 # Out requirements is: different from all in
522 # This is because, out must be different from LowPart and ShiftCount.
523 # We could say "!ecx !in_r4" but it can occur, that all values live through
524 # this Shift and the only value dying is the ShiftCount. Then there would be a
525 # register missing, as result must not be ecx and all other registers are
526 # occupied. What we should write is "!in_r4 !in_r5", but this is not supported
527 # (and probably never will). So we create artificial interferences of the result
528 # with all inputs, so the spiller can always assure a free register.
529 "reg_req" => { "in" => [ "gp", "gp", "gp", "gp", "ecx", "none" ], "out" => [ "!in" ] },
531 if (get_ia32_immop_type(node) == ia32_ImmNone) {
532 if (get_ia32_op_type(node) == ia32_AddrModeD) {
533 . shrdl %%cl, %S4, %AM
535 . shrdl %%cl, %S4, %S3
538 if (get_ia32_op_type(node) == ia32_AddrModeD) {
539 . shrdl $%C, %S4, %AM
541 . shrdl $%C, %S4, %S3
551 "cmp_attr" => "return 1;",
552 "comment" => "construct lowered ShrD: ShrD(a, b, c) = a, b >> count (shift rigth count bits from a into b)",
558 "comment" => "construct Shrs: Shrs(a, b) = a >> b",
559 "reg_req" => { "in" => [ "gp", "gp", "gp", "ecx", "none" ], "out" => [ "in_r3 !in_r4" ] },
560 "emit" => '. sarl %binop',
566 "cmp_attr" => "return 1;",
567 "comment" => "construct lowered Sar: Sar(a, b) = a << b",
573 "comment" => "construct Ror: Ror(a, b) = a ROR b",
574 "reg_req" => { "in" => [ "gp", "gp", "gp", "ecx", "none" ], "out" => [ "in_r3 !in_r4" ] },
575 "emit" => '. rorl %binop',
582 "comment" => "construct Rol: Rol(a, b) = a ROL b",
583 "reg_req" => { "in" => [ "gp", "gp", "gp", "ecx", "none" ], "out" => [ "in_r3 !in_r4" ] },
584 "emit" => '. roll %binop',
593 "comment" => "construct Minus: Minus(a) = -a",
594 "reg_req" => { "in" => [ "gp", "gp", "gp", "none" ], "out" => [ "in_r3" ] },
595 "emit" => '. negl %unop',
602 "comment" => "construct 64Bit Minus: Minus(a_l, a_h, 0) = 0 - a_l; 0 - a_h - borrow",
604 "reg_req" => { "in" => [ "gp", "gp", "gp" ], "out" => [ "!in", "!in" ] },
611 "outs" => [ "low_res", "high_res" ],
617 "cmp_attr" => "return 1;",
618 "comment" => "construct lowered Minus: Minus(a) = -a",
624 "comment" => "construct Increment: Inc(a) = a++",
625 "reg_req" => { "in" => [ "gp", "gp", "gp", "none" ], "out" => [ "in_r3" ] },
626 "emit" => '. incl %unop',
633 "comment" => "construct Decrement: Dec(a) = a--",
634 "reg_req" => { "in" => [ "gp", "gp", "gp", "none" ], "out" => [ "in_r3" ] },
635 "emit" => '. decl %unop',
642 "comment" => "construct Not: Not(a) = !a",
643 "reg_req" => { "in" => [ "gp", "gp", "gp", "none" ], "out" => [ "in_r3" ] },
644 "emit" => '. notl %unop',
652 "op_flags" => "L|X|Y",
653 "comment" => "construct conditional jump: CMP A, B && JMPxx LABEL",
654 "reg_req" => { "in" => [ "gp", "gp", "gp", "gp", "none" ] },
655 "outs" => [ "false", "true" ],
657 "units" => [ "BRANCH" ],
661 "op_flags" => "L|X|Y",
662 "comment" => "construct conditional jump: TEST A, B && JMPxx LABEL",
663 "reg_req" => { "in" => [ "gp", "gp" ] },
664 "outs" => [ "false", "true" ],
666 "units" => [ "BRANCH" ],
670 "op_flags" => "L|X|Y",
671 "comment" => "construct conditional jump without CMP (replaces CondJmp): JMPxx LABEL",
672 "reg_req" => { "in" => [ "gp", "gp", "gp", "gp", "none" ], "out" => [ "none", "none" ] },
673 "outs" => [ "false", "true" ],
674 "units" => [ "BRANCH" ],
678 "op_flags" => "L|X|Y",
679 "comment" => "construct conditional jump without CMP (replaces TestJmp): JMPxx LABEL",
680 "reg_req" => { "in" => [ "gp", "gp" ] },
681 "units" => [ "BRANCH" ],
685 "op_flags" => "L|X|Y",
686 "comment" => "construct switch",
687 "reg_req" => { "in" => [ "gp" ], "out" => [ "none" ] },
689 "units" => [ "BRANCH" ],
695 "comment" => "represents an integer constant",
696 "reg_req" => { "out" => [ "gp" ] },
704 "comment" => "unknown value",
705 "reg_req" => { "out" => [ "gp_UKNWN" ] },
714 "comment" => "unknown value",
715 "reg_req" => { "out" => [ "vfp_UKNWN" ] },
724 "comment" => "unknown value",
725 "reg_req" => { "out" => [ "xmm_UKNWN" ] },
734 "comment" => "unknown GP value",
735 "reg_req" => { "out" => [ "gp_NOREG" ] },
744 "comment" => "unknown VFP value",
745 "reg_req" => { "out" => [ "vfp_NOREG" ] },
754 "comment" => "unknown XMM value",
755 "reg_req" => { "out" => [ "xmm_NOREG" ] },
763 "comment" => "change floating point control word",
764 "reg_req" => { "out" => [ "fp_cw" ] },
772 "state" => "exc_pinned",
773 "comment" => "load floating point control word FldCW(ptr, mem) = LD ptr -> reg",
774 "reg_req" => { "in" => [ "gp", "gp", "none" ], "out" => [ "fp_cw" ] },
776 "emit" => ". fldcw %AM",
783 "state" => "exc_pinned",
784 "comment" => "store floating point control word: FstCW(ptr, mem) = ST ptr -> reg",
785 "reg_req" => { "in" => [ "gp", "gp", "fp_cw", "none" ] },
787 "emit" => ". fstcw %AM",
793 # we should not rematrialize this node. It produces 2 results and has
794 # very strict constrains
795 "comment" => "construct CDQ: sign extend EAX -> EDX:EAX",
796 "reg_req" => { "in" => [ "gp" ], "out" => [ "eax in_r1", "edx" ] },
798 "outs" => [ "EAX", "EDX" ],
806 "state" => "exc_pinned",
807 "comment" => "construct Load: Load(ptr, mem) = LD ptr -> reg",
808 "reg_req" => { "in" => [ "gp", "gp", "none" ], "out" => [ "gp", "none" ] },
810 "emit" => ". mov%SE%ME%.l %AM, %D1",
811 "outs" => [ "res", "M" ],
817 "cmp_attr" => "return 1;",
818 "comment" => "construct lowered Load: Load(ptr, mem) = LD ptr -> reg",
819 "outs" => [ "res", "M" ],
825 "cmp_attr" => "return 1;",
826 "state" => "exc_pinned",
827 "comment" => "construct lowered Store: Store(ptr, val, mem) = ST ptr,val",
834 "state" => "exc_pinned",
835 "comment" => "construct Store: Store(ptr, val, mem) = ST ptr,val",
836 "reg_req" => { "in" => [ "gp", "gp", "gp", "none" ] },
837 "emit" => '. mov%M %binop',
845 "state" => "exc_pinned",
846 "comment" => "construct 8Bit Store: Store(ptr, val, mem) = ST ptr,val",
847 "reg_req" => { "in" => [ "gp", "gp", "eax ebx ecx edx", "none" ] },
848 "emit" => '. mov%M %binop',
856 "comment" => "construct Lea: Lea(a,b) = lea [a+b*const+offs] | res = a + b * const + offs with const = 0,1,2,4,8",
857 "reg_req" => { "in" => [ "gp", "gp" ], "out" => [ "in_r1" ] },
858 "emit" => '. leal %AM, %D1',
865 "comment" => "push on the stack",
866 "reg_req" => { "in" => [ "gp", "gp", "gp", "esp", "none" ], "out" => [ "esp", "none" ] },
867 "emit" => '. pushl %unop',
868 "outs" => [ "stack:I|S", "M" ],
874 "comment" => "pop a gp register from the stack",
875 "reg_req" => { "in" => [ "gp", "gp", "esp", "none" ], "out" => [ "esp", "gp", "none" ] },
876 "emit" => '. popl %unop',
877 "outs" => [ "stack:I|S", "res", "M" ],
883 "comment" => "create stack frame",
884 "reg_req" => { "in" => [ "esp" ], "out" => [ "ebp", "esp" ] },
886 "outs" => [ "frame:I", "stack:I|S", "M" ],
892 "comment" => "destroy stack frame",
893 "reg_req" => { "in" => [ "esp", "ebp" ], "out" => [ "ebp", "esp" ] },
895 "outs" => [ "frame:I", "stack:I|S" ],
902 "comment" => "allocate space on stack",
903 "reg_req" => { "in" => [ "gp", "gp", "esp", "gp", "none" ], "out" => [ "in_r3", "none" ] },
904 "emit" => '. addl %binop',
905 "outs" => [ "stack:S", "M" ],
911 "comment" => "free space on stack",
912 "reg_req" => { "in" => [ "gp", "gp", "esp", "gp", "none" ], "out" => [ "in_r3", "none" ] },
913 "emit" => '. subl %binop',
914 "outs" => [ "stack:S", "M" ],
920 "comment" => "get the TLS base address",
921 "reg_req" => { "out" => [ "gp" ] },
927 #-----------------------------------------------------------------------------#
928 # _____ _____ ______ __ _ _ _ #
929 # / ____/ ____| ____| / _| | | | | | #
930 # | (___| (___ | |__ | |_| | ___ __ _| |_ _ __ ___ __| | ___ ___ #
931 # \___ \\___ \| __| | _| |/ _ \ / _` | __| | '_ \ / _ \ / _` |/ _ \/ __| #
932 # ____) |___) | |____ | | | | (_) | (_| | |_ | | | | (_) | (_| | __/\__ \ #
933 # |_____/_____/|______| |_| |_|\___/ \__,_|\__| |_| |_|\___/ \__,_|\___||___/ #
934 #-----------------------------------------------------------------------------#
936 # commutative operations
940 "comment" => "construct SSE Add: Add(a, b) = Add(b, a) = a + b",
941 "reg_req" => { "in" => [ "gp", "gp", "xmm", "xmm", "none" ], "out" => [ "in_r3" ] },
942 "emit" => '. add%XXM %binop',
944 "units" => [ "SSE" ],
950 "comment" => "construct SSE Mul: Mul(a, b) = Mul(b, a) = a * b",
951 "reg_req" => { "in" => [ "gp", "gp", "xmm", "xmm", "none" ], "out" => [ "in_r3" ] },
952 "emit" => '. mul%XXM %binop',
954 "units" => [ "SSE" ],
960 "comment" => "construct SSE Max: Max(a, b) = Max(b, a) = a > b ? a : b",
961 "reg_req" => { "in" => [ "gp", "gp", "xmm", "xmm", "none" ], "out" => [ "in_r3" ] },
962 "emit" => '. max%XXM %binop',
964 "units" => [ "SSE" ],
970 "comment" => "construct SSE Min: Min(a, b) = Min(b, a) = a < b ? a : b",
971 "reg_req" => { "in" => [ "gp", "gp", "xmm", "xmm", "none" ], "out" => [ "in_r3" ] },
972 "emit" => '. min%XXM %binop',
974 "units" => [ "SSE" ],
980 "comment" => "construct SSE And: And(a, b) = a AND b",
981 "reg_req" => { "in" => [ "gp", "gp", "xmm", "xmm", "none" ], "out" => [ "in_r3" ] },
982 "emit" => '. andp%XXM %binop',
984 "units" => [ "SSE" ],
990 "comment" => "construct SSE Or: Or(a, b) = a OR b",
991 "reg_req" => { "in" => [ "gp", "gp", "xmm", "xmm", "none" ], "out" => [ "in_r3" ] },
992 "emit" => '. orp%XXM %binop',
993 "units" => [ "SSE" ],
999 "comment" => "construct SSE Xor: Xor(a, b) = a XOR b",
1000 "reg_req" => { "in" => [ "gp", "gp", "xmm", "xmm", "none" ], "out" => [ "in_r3" ] },
1001 "emit" => '. xorp%XXM %binop',
1003 "units" => [ "SSE" ],
1007 # not commutative operations
1011 "comment" => "construct SSE AndNot: AndNot(a, b) = a AND NOT b",
1012 "reg_req" => { "in" => [ "gp", "gp", "xmm", "xmm", "none" ], "out" => [ "in_r3 !in_r4" ] },
1013 "emit" => '. andnp%XXM %binop',
1015 "units" => [ "SSE" ],
1021 "comment" => "construct SSE Sub: Sub(a, b) = a - b",
1022 "reg_req" => { "in" => [ "gp", "gp", "xmm", "xmm", "none" ], "out" => [ "in_r3" ] },
1023 "emit" => '. sub%XXM %binop',
1025 "units" => [ "SSE" ],
1031 "comment" => "construct SSE Div: Div(a, b) = a / b",
1032 "reg_req" => { "in" => [ "gp", "gp", "xmm", "xmm", "none" ], "out" => [ "in_r3 !in_r4" ] },
1033 "outs" => [ "res", "M" ],
1034 "emit" => '. div%XXM %binop',
1036 "units" => [ "SSE" ],
1043 "comment" => "construct SSE Compare: Cmp(a, b) == a = a cmp b",
1044 "reg_req" => { "in" => [ "gp", "gp", "xmm", "xmm", "none" ], "out" => [ "in_r3 !in_r4" ] },
1046 "units" => [ "SSE" ],
1051 "op_flags" => "L|X|Y",
1052 "comment" => "construct conditional jump: UCOMIS A, B && JMPxx LABEL",
1053 "reg_req" => { "in" => [ "gp", "gp", "xmm", "xmm", "none" ], "out" => [ "none", "none" ] },
1054 "outs" => [ "false", "true" ],
1056 "units" => [ "SSE" ],
1062 "comment" => "represents a SSE constant",
1063 "reg_req" => { "out" => [ "xmm" ] },
1064 "emit" => '. mov%XXM $%C, %D1',
1066 "units" => [ "SSE" ],
1073 "op_flags" => "L|F",
1074 "state" => "exc_pinned",
1075 "comment" => "construct SSE Load: Load(ptr, mem) = LD ptr",
1076 "reg_req" => { "in" => [ "gp", "gp", "none" ], "out" => [ "xmm", "none" ] },
1077 "emit" => '. mov%XXM %AM, %D1',
1078 "outs" => [ "res", "M" ],
1080 "units" => [ "SSE" ],
1084 "op_flags" => "L|F",
1085 "state" => "exc_pinned",
1086 "comment" => "construct Store: Store(ptr, val, mem) = ST ptr,val",
1087 "reg_req" => { "in" => [ "gp", "gp", "xmm", "none" ] },
1088 "emit" => '. mov%XXM %binop',
1090 "units" => [ "SSE" ],
1095 "op_flags" => "L|F",
1096 "state" => "exc_pinned",
1097 "comment" => "construct Store without index: Store(ptr, val, mem) = ST ptr,val",
1098 "reg_req" => { "in" => [ "gp", "xmm", "none" ] },
1099 "emit" => '. mov%XXM %S2, %AM',
1101 "units" => [ "SSE" ],
1106 "op_flags" => "L|F",
1107 "comment" => "construct: transfer a value from x87 FPU into a SSE register",
1108 "cmp_attr" => "return 1;",
1113 "op_flags" => "L|F",
1114 "comment" => "construct: transfer a value from SSE register to x87 FPU",
1115 "cmp_attr" => "return 1;",
1120 "op_flags" => "L|F",
1122 "state" => "exc_pinned",
1123 "comment" => "store ST0 onto stack",
1124 "reg_req" => { "in" => [ "gp", "gp", "none" ] },
1125 "emit" => '. fstp%XM %AM',
1127 "units" => [ "SSE" ],
1132 "op_flags" => "L|F",
1134 "state" => "exc_pinned",
1135 "comment" => "load ST0 from stack",
1136 "reg_req" => { "in" => [ "gp", "none" ], "out" => [ "vf0", "none" ] },
1137 "emit" => '. fld%M %AM',
1138 "outs" => [ "res", "M" ],
1140 "units" => [ "SSE" ],
1146 "op_flags" => "F|H",
1147 "state" => "pinned",
1148 "comment" => "implements a memcopy: CopyB(dst, src, size, mem) == memcpy(dst, src, size)",
1149 "reg_req" => { "in" => [ "edi", "esi", "ecx", "none" ], "out" => [ "edi", "esi", "ecx", "none" ] },
1150 "outs" => [ "DST", "SRC", "CNT", "M" ],
1151 "units" => [ "GP" ],
1155 "op_flags" => "F|H",
1156 "state" => "pinned",
1157 "comment" => "implements a memcopy: CopyB(dst, src, mem) == memcpy(dst, src, attr(size))",
1158 "reg_req" => { "in" => [ "edi", "esi", "none" ], "out" => [ "edi", "esi", "none" ] },
1159 "outs" => [ "DST", "SRC", "M" ],
1160 "units" => [ "GP" ],
1166 "reg_req" => { "in" => [ "gp", "gp", "gp", "none" ], "out" => [ "in_r3", "none" ] },
1167 "comment" => "construct Conv Int -> Int",
1168 "units" => [ "GP" ],
1169 "mode" => "mode_Iu",
1173 "reg_req" => { "in" => [ "gp", "gp", "eax ebx ecx edx", "none" ], "out" => [ "in_r3", "none" ] },
1174 "comment" => "construct Conv Int -> Int",
1175 "units" => [ "GP" ],
1176 "mode" => "mode_Iu",
1180 "reg_req" => { "in" => [ "gp", "gp", "gp", "none" ], "out" => [ "xmm", "none" ] },
1181 "comment" => "construct Conv Int -> Floating Point",
1183 "units" => [ "SSE" ],
1188 "reg_req" => { "in" => [ "gp", "gp", "xmm", "none" ], "out" => [ "gp", "none" ] },
1189 "comment" => "construct Conv Floating Point -> Int",
1191 "units" => [ "SSE" ],
1192 "mode" => "mode_Iu",
1196 "reg_req" => { "in" => [ "gp", "gp", "xmm", "none" ], "out" => [ "xmm", "none" ] },
1197 "comment" => "construct Conv Floating Point -> Floating Point",
1199 "units" => [ "SSE" ],
1205 "comment" => "construct Conditional Move: CMov(sel, a, b) == sel ? a : b",
1206 "reg_req" => { "in" => [ "gp", "gp", "gp", "gp" ], "out" => [ "in_r4" ] },
1208 "units" => [ "GP" ],
1209 "mode" => "mode_Iu",
1214 "comment" => "check if Psi condition tree evaluates to true and move result accordingly",
1215 "reg_req" => { "in" => [ "gp", "gp", "gp" ], "out" => [ "in_r3" ] },
1217 "units" => [ "GP" ],
1218 "mode" => "mode_Iu",
1223 "comment" => "construct Conditional Move: SSE Compare + int CMov ",
1224 "reg_req" => { "in" => [ "xmm", "xmm", "gp", "gp" ], "out" => [ "in_r4" ] },
1226 "units" => [ "SSE" ],
1227 "mode" => "mode_Iu",
1232 "comment" => "construct Conditional Move: x87 Compare + int CMov",
1233 "reg_req" => { "in" => [ "vfp", "vfp", "gp", "gp" ], "out" => [ "in_r4" ] },
1235 "units" => [ "VFP" ],
1236 "mode" => "mode_Iu",
1241 "comment" => "construct Set: Set(sel) == sel ? 1 : 0",
1242 "reg_req" => { "in" => [ "gp", "gp", "gp", "gp", "none" ], "out" => [ "eax ebx ecx edx" ] },
1244 "units" => [ "GP" ],
1245 "mode" => "mode_Iu",
1250 "comment" => "check if Psi condition tree evaluates to true and set result accordingly",
1251 "reg_req" => { "in" => [ "gp" ], "out" => [ "eax ebx ecx edx" ] },
1253 "units" => [ "GP" ],
1254 "mode" => "mode_Iu",
1259 "comment" => "construct Set: SSE Compare + int Set",
1260 "reg_req" => { "in" => [ "gp", "gp", "xmm", "xmm", "none" ], "out" => [ "eax ebx ecx edx" ] },
1262 "units" => [ "SSE" ],
1263 "mode" => "mode_Iu",
1268 "comment" => "construct Set: x87 Compare + int Set",
1269 "reg_req" => { "in" => [ "gp", "gp", "vfp", "vfp", "none" ], "out" => [ "eax ebx ecx edx" ] },
1271 "units" => [ "VFP" ],
1272 "mode" => "mode_Iu",
1277 "comment" => "construct x87 Conditional Move: vfCMov(sel, a, b) = sel ? a : b",
1278 "reg_req" => { "in" => [ "vfp", "vfp", "vfp", "vfp" ], "out" => [ "vfp" ] },
1280 "units" => [ "VFP" ],
1284 #----------------------------------------------------------#
1286 # (_) | | | | / _| | | | #
1287 # __ ___ _ __| |_ _ _ __ _| | | |_| | ___ __ _| |_ #
1288 # \ \ / / | '__| __| | | |/ _` | | | _| |/ _ \ / _` | __| #
1289 # \ V /| | | | |_| |_| | (_| | | | | | | (_) | (_| | |_ #
1290 # \_/ |_|_| \__|\__,_|\__,_|_| |_| |_|\___/ \__,_|\__| #
1292 # _ __ ___ __| | ___ ___ #
1293 # | '_ \ / _ \ / _` |/ _ \/ __| #
1294 # | | | | (_) | (_| | __/\__ \ #
1295 # |_| |_|\___/ \__,_|\___||___/ #
1296 #----------------------------------------------------------#
1300 "comment" => "virtual fp Add: Add(a, b) = Add(b, a) = a + b",
1301 "reg_req" => { "in" => [ "gp", "gp", "vfp", "vfp", "none" ], "out" => [ "vfp" ] },
1303 "units" => [ "VFP" ],
1309 "comment" => "virtual fp Mul: Mul(a, b) = Mul(b, a) = a * b",
1310 "reg_req" => { "in" => [ "gp", "gp", "vfp", "vfp", "none" ], "out" => [ "vfp" ] },
1312 "units" => [ "VFP" ],
1318 "cmp_attr" => "return 1;",
1319 "comment" => "lowered virtual fp Mul: Mul(a, b) = Mul(b, a) = a * b",
1325 "comment" => "virtual fp Sub: Sub(a, b) = a - b",
1326 "reg_req" => { "in" => [ "gp", "gp", "vfp", "vfp", "none" ], "out" => [ "vfp" ] },
1328 "units" => [ "VFP" ],
1333 "cmp_attr" => "return 1;",
1334 "comment" => "lowered virtual fp Sub: Sub(a, b) = a - b",
1339 "comment" => "virtual fp Div: Div(a, b) = a / b",
1340 "reg_req" => { "in" => [ "gp", "gp", "vfp", "vfp", "none" ], "out" => [ "vfp" ] },
1341 "outs" => [ "res", "M" ],
1343 "units" => [ "VFP" ],
1347 "cmp_attr" => "return 1;",
1348 "comment" => "lowered virtual fp Div: Div(a, b) = a / b",
1349 "outs" => [ "res", "M" ],
1354 "comment" => "virtual fp Rem: Rem(a, b) = a - Q * b (Q is integer)",
1355 "reg_req" => { "in" => [ "gp", "gp", "vfp", "vfp", "none" ], "out" => [ "vfp" ] },
1357 "units" => [ "VFP" ],
1362 "cmp_attr" => "return 1;",
1363 "comment" => "lowered virtual fp Rem: Rem(a, b) = a - Q * b (Q is integer)",
1369 "comment" => "virtual fp Abs: Abs(a) = |a|",
1370 "reg_req" => { "in" => [ "vfp"], "out" => [ "vfp" ] },
1372 "units" => [ "VFP" ],
1378 "comment" => "virtual fp Chs: Chs(a) = -a",
1379 "reg_req" => { "in" => [ "vfp"], "out" => [ "vfp" ] },
1381 "units" => [ "VFP" ],
1387 "comment" => "virtual fp Sin: Sin(a) = sin(a)",
1388 "reg_req" => { "in" => [ "vfp"], "out" => [ "vfp" ] },
1390 "units" => [ "VFP" ],
1396 "comment" => "virtual fp Cos: Cos(a) = cos(a)",
1397 "reg_req" => { "in" => [ "vfp"], "out" => [ "vfp" ] },
1399 "units" => [ "VFP" ],
1405 "comment" => "virtual fp Sqrt: Sqrt(a) = a ^ 0.5",
1406 "reg_req" => { "in" => [ "vfp"], "out" => [ "vfp" ] },
1408 "units" => [ "VFP" ],
1412 # virtual Load and Store
1415 "op_flags" => "L|F",
1416 "state" => "exc_pinned",
1417 "comment" => "virtual fp Load: Load(ptr, mem) = LD ptr -> reg",
1418 "reg_req" => { "in" => [ "gp", "gp", "none" ], "out" => [ "vfp", "none" ] },
1419 "outs" => [ "res", "M" ],
1421 "units" => [ "VFP" ],
1425 "op_flags" => "L|F",
1426 "state" => "exc_pinned",
1427 "comment" => "virtual fp Store: Store(ptr, val, mem) = ST ptr,val",
1428 "reg_req" => { "in" => [ "gp", "gp", "vfp", "none" ] },
1430 "units" => [ "VFP" ],
1437 "comment" => "virtual fp integer Load: Load(ptr, mem) = iLD ptr -> reg",
1438 "reg_req" => { "in" => [ "gp", "gp", "none" ], "out" => [ "vfp", "none" ] },
1439 "outs" => [ "res", "M" ],
1441 "units" => [ "VFP" ],
1445 "cmp_attr" => "return 1;",
1446 "comment" => "lowered virtual fp integer Load: Load(ptr, mem) = iLD ptr -> reg",
1447 "outs" => [ "res", "M" ],
1452 "comment" => "virtual fp integer Store: Store(ptr, val, mem) = iST ptr,val",
1453 "reg_req" => { "in" => [ "gp", "gp", "vfp", "none" ] },
1455 "units" => [ "VFP" ],
1460 "cmp_attr" => "return 1;",
1461 "comment" => "lowered virtual fp integer Store: Store(ptr, val, mem) = iST ptr,val",
1471 "comment" => "virtual fp Load 0.0: Ld 0.0 -> reg",
1472 "reg_req" => { "out" => [ "vfp" ] },
1474 "units" => [ "VFP" ],
1480 "comment" => "virtual fp Load 1.0: Ld 1.0 -> reg",
1481 "reg_req" => { "out" => [ "vfp" ] },
1483 "units" => [ "VFP" ],
1489 "comment" => "virtual fp Load pi: Ld pi -> reg",
1490 "reg_req" => { "out" => [ "vfp" ] },
1492 "units" => [ "VFP" ],
1498 "comment" => "virtual fp Load ln 2: Ld ln 2 -> reg",
1499 "reg_req" => { "out" => [ "vfp" ] },
1501 "units" => [ "VFP" ],
1507 "comment" => "virtual fp Load lg 2: Ld lg 2 -> reg",
1508 "reg_req" => { "out" => [ "vfp" ] },
1510 "units" => [ "VFP" ],
1516 "comment" => "virtual fp Load ld 10: Ld ld 10 -> reg",
1517 "reg_req" => { "out" => [ "vfp" ] },
1519 "units" => [ "VFP" ],
1525 "comment" => "virtual fp Load ld e: Ld ld e -> reg",
1526 "reg_req" => { "out" => [ "vfp" ] },
1528 "units" => [ "VFP" ],
1535 # "init_attr" => " set_ia32_ls_mode(res, mode);",
1536 "comment" => "represents a virtual floating point constant",
1537 "reg_req" => { "out" => [ "vfp" ] },
1539 "units" => [ "VFP" ],
1546 "op_flags" => "L|X|Y",
1547 "comment" => "represents a virtual floating point compare",
1548 "reg_req" => { "in" => [ "gp", "gp", "vfp", "vfp", "none" ], "out" => [ "none", "none", "eax" ] },
1549 "outs" => [ "false", "true", "temp_reg_eax" ],
1551 "units" => [ "VFP" ],
1554 #------------------------------------------------------------------------#
1555 # ___ _____ __ _ _ _ #
1556 # __ _( _ )___ | / _| | ___ __ _| |_ _ __ ___ __| | ___ ___ #
1557 # \ \/ / _ \ / / | |_| |/ _ \ / _` | __| | '_ \ / _ \ / _` |/ _ \/ __| #
1558 # > < (_) |/ / | _| | (_) | (_| | |_ | | | | (_) | (_| | __/\__ \ #
1559 # /_/\_\___//_/ |_| |_|\___/ \__,_|\__| |_| |_|\___/ \__,_|\___||___/ #
1560 #------------------------------------------------------------------------#
1564 "rd_constructor" => "NONE",
1565 "comment" => "x87 Add: Add(a, b) = Add(b, a) = a + b",
1567 "emit" => '. fadd%XM %x87_binop',
1572 "rd_constructor" => "NONE",
1573 "comment" => "x87 Add: Add(a, b) = Add(b, a) = a + b",
1575 "emit" => '. faddp %x87_binop',
1580 "rd_constructor" => "NONE",
1581 "comment" => "x87 fp Mul: Mul(a, b) = Mul(b, a) = a + b",
1583 "emit" => '. fmul%XM %x87_binop',
1588 "rd_constructor" => "NONE",
1589 "comment" => "x87 fp Mul: Mul(a, b) = Mul(b, a) = a + b",
1591 "emit" => '. fmulp %x87_binop',,
1596 "rd_constructor" => "NONE",
1597 "comment" => "x87 fp Sub: Sub(a, b) = a - b",
1599 "emit" => '. fsub%XM %x87_binop',
1604 "rd_constructor" => "NONE",
1605 "comment" => "x87 fp Sub: Sub(a, b) = a - b",
1607 "emit" => '. fsubp %x87_binop',
1612 "rd_constructor" => "NONE",
1614 "comment" => "x87 fp SubR: SubR(a, b) = b - a",
1616 "emit" => '. fsubr%XM %x87_binop',
1621 "rd_constructor" => "NONE",
1623 "comment" => "x87 fp SubR: SubR(a, b) = b - a",
1625 "emit" => '. fsubrp %x87_binop',
1630 "rd_constructor" => "NONE",
1631 "comment" => "x87 fp Rem: Rem(a, b) = a - Q * b (Q is integer)",
1633 "emit" => '. fprem1',
1636 # this node is just here, to keep the simulator running
1637 # we can omit this when a fprem simulation function exists
1640 "rd_constructor" => "NONE",
1641 "comment" => "x87 fp Rem: Rem(a, b) = a - Q * b (Q is integer)",
1643 "emit" => '. fprem1',
1648 "rd_constructor" => "NONE",
1649 "comment" => "x87 fp Div: Div(a, b) = a / b",
1651 "emit" => '. fdiv%XM %x87_binop',
1656 "rd_constructor" => "NONE",
1657 "comment" => "x87 fp Div: Div(a, b) = a / b",
1659 "emit" => '. fdivp %x87_binop',
1664 "rd_constructor" => "NONE",
1665 "comment" => "x87 fp DivR: DivR(a, b) = b / a",
1667 "emit" => '. fdivr%XM %x87_binop',
1672 "rd_constructor" => "NONE",
1673 "comment" => "x87 fp DivR: DivR(a, b) = b / a",
1675 "emit" => '. fdivrp %x87_binop',
1680 "rd_constructor" => "NONE",
1681 "comment" => "x87 fp Abs: Abs(a) = |a|",
1688 "rd_constructor" => "NONE",
1689 "comment" => "x87 fp Chs: Chs(a) = -a",
1696 "rd_constructor" => "NONE",
1697 "comment" => "x87 fp Sin: Sin(a) = sin(a)",
1704 "rd_constructor" => "NONE",
1705 "comment" => "x87 fp Cos: Cos(a) = cos(a)",
1712 "rd_constructor" => "NONE",
1713 "comment" => "x87 fp Sqrt: Sqrt(a) = a ^ 0.5",
1715 "emit" => '. fsqrt $',
1718 # x87 Load and Store
1721 "rd_constructor" => "NONE",
1722 "op_flags" => "R|L|F",
1723 "state" => "exc_pinned",
1724 "comment" => "x87 fp Load: Load(ptr, mem) = LD ptr -> reg",
1726 "emit" => '. fld%XM %AM',
1730 "rd_constructor" => "NONE",
1731 "op_flags" => "R|L|F",
1732 "state" => "exc_pinned",
1733 "comment" => "x87 fp Store: Store(ptr, val, mem) = ST ptr,val",
1735 "emit" => '. fst%XM %AM',
1740 "rd_constructor" => "NONE",
1741 "op_flags" => "R|L|F",
1742 "state" => "exc_pinned",
1743 "comment" => "x87 fp Store: Store(ptr, val, mem) = ST ptr,val",
1745 "emit" => '. fstp%XM %AM',
1753 "rd_constructor" => "NONE",
1754 "comment" => "x87 fp integer Load: Load(ptr, mem) = iLD ptr -> reg",
1756 "emit" => '. fild%XM %AM',
1761 "rd_constructor" => "NONE",
1762 "comment" => "x87 fp integer Store: Store(ptr, val, mem) = iST ptr,val",
1764 "emit" => '. fist%M %AM',
1770 "rd_constructor" => "NONE",
1771 "comment" => "x87 fp integer Store: Store(ptr, val, mem) = iST ptr,val",
1773 "emit" => '. fistp%M %AM',
1780 "op_flags" => "R|c",
1782 "comment" => "x87 fp Load 0.0: Ld 0.0 -> reg",
1783 "reg_req" => { "out" => [ "vfp" ] },
1788 "op_flags" => "R|c",
1790 "comment" => "x87 fp Load 1.0: Ld 1.0 -> reg",
1791 "reg_req" => { "out" => [ "vfp" ] },
1796 "op_flags" => "R|c",
1798 "comment" => "x87 fp Load pi: Ld pi -> reg",
1799 "reg_req" => { "out" => [ "vfp" ] },
1800 "emit" => '. fldpi',
1804 "op_flags" => "R|c",
1806 "comment" => "x87 fp Load ln 2: Ld ln 2 -> reg",
1807 "reg_req" => { "out" => [ "vfp" ] },
1808 "emit" => '. fldln2',
1812 "op_flags" => "R|c",
1814 "comment" => "x87 fp Load lg 2: Ld lg 2 -> reg",
1815 "reg_req" => { "out" => [ "vfp" ] },
1816 "emit" => '. fldlg2',
1820 "op_flags" => "R|c",
1822 "comment" => "x87 fp Load ld 10: Ld ld 10 -> reg",
1823 "reg_req" => { "out" => [ "vfp" ] },
1824 "emit" => '. fldll2t',
1828 "op_flags" => "R|c",
1830 "comment" => "x87 fp Load ld e: Ld ld e -> reg",
1831 "reg_req" => { "out" => [ "vfp" ] },
1832 "emit" => '. fldl2e',
1836 "op_flags" => "R|c",
1838 "rd_constructor" => "NONE",
1839 "comment" => "represents a x87 constant",
1840 "reg_req" => { "out" => [ "vfp" ] },
1841 "emit" => '. fld $%C',
1845 # Note that it is NEVER allowed to do CSE on these nodes
1846 # Moreover, note the virtual register requierements!
1849 "op_flags" => "R|K",
1850 "comment" => "x87 stack exchange",
1852 "cmp_attr" => "return 1;",
1853 "emit" => '. fxch %X1',
1857 "op_flags" => "R|K",
1858 "comment" => "x87 stack push",
1860 "cmp_attr" => "return 1;",
1861 "emit" => '. fld %X1',
1866 "comment" => "x87 stack push",
1867 "reg_req" => { "in" => [ "vfp"], "out" => [ "vfp" ] },
1868 "cmp_attr" => "return 1;",
1869 "emit" => '. fld %X1',
1873 "op_flags" => "R|K",
1874 "comment" => "x87 stack pop",
1876 "cmp_attr" => "return 1;",
1877 "emit" => '. fstp %X1',
1883 "op_flags" => "L|X|Y",
1884 "comment" => "floating point compare",
1889 "op_flags" => "L|X|Y",
1890 "comment" => "floating point compare and pop",
1895 "op_flags" => "L|X|Y",
1896 "comment" => "floating point compare and pop twice",
1901 "op_flags" => "L|X|Y",
1902 "comment" => "floating point compare reverse",
1907 "op_flags" => "L|X|Y",
1908 "comment" => "floating point compare reverse and pop",
1913 "op_flags" => "L|X|Y",
1914 "comment" => "floating point compare reverse and pop twice",