X-Git-Url: http://nsz.repo.hu/git/?a=blobdiff_plain;f=ir%2Fbe%2Fia32%2Fia32_spec.pl;h=dc0c49d8e41c5c6c1f9a6b28b54bef0bbae8a38d;hb=90f2e217df8deecb71f08af6bb28f9decd6795b0;hp=8a4e9cc70f7a3e5457dfcad28932cb11e95dc91b;hpb=511aeabe9b78ea09a5feb0283ec0c70b77953684;p=libfirm diff --git a/ir/be/ia32/ia32_spec.pl b/ir/be/ia32/ia32_spec.pl index 8a4e9cc70..dc0c49d8e 100644 --- a/ir/be/ia32/ia32_spec.pl +++ b/ir/be/ia32/ia32_spec.pl @@ -2,15 +2,13 @@ # $Id$ # This is the specification for the ia32 assembler Firm-operations -# the cpu architecture (ia32, ia64, mips, sparc, ppc, ...) -$arch = "ia32"; +use File::Basename; -# this strings mark the beginning and the end of a comment in emit -$comment_string = "/*"; -$comment_string_end = "*/"; +$new_emit_syntax = 1; +my $myname = $0; -# the number of additional opcodes you want to register -#$additional_opcodes = 0; +# the cpu architecture (ia32, ia64, mips, sparc, ppc, ...) +$arch = "ia32"; # The node description is done as a perl hash initializer with the # following structure: @@ -18,23 +16,24 @@ $comment_string_end = "*/"; # %nodes = ( # # => { -# "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" }, +# 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" }, # ... # ], -# "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)" +# 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)" +# attr_type => "name of the attribute struct", # }, # # ... # (all nodes you need to describe) @@ -107,97 +106,138 @@ $comment_string_end = "*/"; # 4 - ignore (do not assign this register) # 8 - emitter can choose an arbitrary register of this class # 16 - the register is a virtual one +# 32 - register represents a state # NOTE: Last entry of each class is the largest Firm-Mode a register can hold %reg_classes = ( - "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" => "r11", "type" => 1 }, -# { "name" => "r12", "type" => 1 }, -# { "name" => "r13", "type" => 1 }, -# { "name" => "r14", "type" => 1 }, -# { "name" => "r15", "type" => 1 }, -# { "name" => "r16", "type" => 1 }, -# { "name" => "r17", "type" => 1 }, -# { "name" => "r18", "type" => 1 }, -# { "name" => "r19", "type" => 1 }, -# { "name" => "r20", "type" => 1 }, -# { "name" => "r21", "type" => 1 }, -# { "name" => "r22", "type" => 1 }, -# { "name" => "r23", "type" => 1 }, -# { "name" => "r24", "type" => 1 }, -# { "name" => "r25", "type" => 1 }, -# { "name" => "r26", "type" => 1 }, -# { "name" => "r27", "type" => 1 }, -# { "name" => "r28", "type" => 1 }, -# { "name" => "r29", "type" => 1 }, -# { "name" => "r30", "type" => 1 }, -# { "name" => "r31", "type" => 1 }, -# { "name" => "r32", "type" => 1 }, - { "name" => "ebp", "type" => 2 }, - { "name" => "esp", "type" => 4 }, - { "name" => "gp_NOREG", "type" => 2 | 4 | 16 }, # we need a dummy register for NoReg nodes - { "name" => "gp_UKNWN", "type" => 2 | 4 | 8 | 16}, # we need a dummy register for Unknown nodes - { "mode" => "mode_P" } - ], - "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" => 2 | 4 | 16 }, # we need a dummy register for NoReg nodes - { "name" => "xmm_UKNWN", "type" => 2 | 4 | 8 | 16}, # we need a dummy register for Unknown nodes - { "mode" => "mode_D" } - ], - "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" => 2 | 4 | 16 }, # we need a dummy register for NoReg nodes - { "name" => "vfp_UKNWN", "type" => 2 | 4 | 8 | 16}, # we need a dummy register for Unknown nodes - { "mode" => "mode_E" } - ], - "st" => [ - { "name" => "st0", "type" => 1 }, - { "name" => "st1", "type" => 1 }, - { "name" => "st2", "type" => 1 }, - { "name" => "st3", "type" => 1 }, - { "name" => "st4", "type" => 1 }, - { "name" => "st5", "type" => 1 }, - { "name" => "st6", "type" => 1 }, - { "name" => "st7", "type" => 1 }, - { "mode" => "mode_E" } - ] + gp => [ + { name => "edx", type => 1 }, + { name => "ecx", type => 1 }, + { name => "eax", type => 1 }, + { name => "ebx", type => 2 }, + { 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" } + ], + 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", flags => "manual_ra" } + ], + 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 + { mode => "mode_E" } + ], + 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" } + ], + st => [ + { 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 }, + { mode => "mode_E", flags => "manual_ra" } + ], + fp_cw => [ # the floating point control word + { name => "fpcw", type => 4|32 }, + { mode => "mode_fpcw", flags => "manual_ra|state" } + ], + flags => [ + { name => "eflags", type => 0 }, + { mode => "mode_Iu", flags => "manual_ra" } + ], ); # %reg_classes %cpu = ( - "ALU" => [ 1, "ALU1", "ALU2", "ALU3", "ALU4" ], - "MUL" => [ 1, "MUL1", "MUL2" ], - "SSE" => [ 1, "SSE1", "SSE2" ], - "FPU" => [ 1, "FPU1" ], - "MEM" => [ 1, "MEM1", "MEM2" ], - "BRANCH" => [ 1, "BRANCH1", "BRANCH2" ], - "DUMMY" => [ 1, "DUMMY1", "DUMMY2", "DUMMY3", "DUMMY4" ] + 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" ], ); # %cpu %vliw = ( - "bundle_size" => 3, - "bundels_per_cycle" => 2 + bundle_size => 1, + bundels_per_cycle => 1 ); # vliw +%emit_templates = ( + 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));", + ME => "if(get_mode_size_bits(get_ia32_ls_mode(node)) != 32)\n + 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);", +); + #--------------------------------------------------# # _ # # (_) # @@ -209,13 +249,106 @@ $comment_string_end = "*/"; # |_| # #--------------------------------------------------# -$default_cmp_attr = "return ia32_compare_immop_attr(attr_a, attr_b);"; +$default_attr_type = "ia32_attr_t"; +$default_copy_attr = "ia32_copy_attr"; + +sub ia32_custom_init_attr { + my $node = shift; + my $name = shift; + my $res = ""; + if(defined($node->{modified_flags})) { + $res .= "\tset_ia32_flags(res, get_ia32_flags(res) | arch_irn_flags_modify_flags);\n"; + } + 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; + +%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);", + ia32_asm_attr_t => + "\tinit_ia32_attributes(res, flags, in_reqs, out_reqs, exec_units, n_res, latency);\n". + "\tinit_ia32_x87_attributes(res);". + "\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);" +); + +%compare_attr = ( + 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", +); %operands = ( ); +$mode_xmm = "mode_E"; +$mode_gp = "mode_Iu"; +$mode_flags = "mode_Iu"; +$mode_fpcw = "mode_fpcw"; +$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" ]; + %nodes = ( +Immediate => { + state => "pinned", + op_flags => "c", + irn_flags => "I", + reg_req => { out => [ "gp_NOREG" ] }, + attr => "ir_entity *symconst, int symconst_sign, long offset", + attr_type => "ia32_immediate_attr_t", + latency => 0, + mode => $mode_gp, +}, + +Asm => { + mode => "mode_T", + arity => "variable", + out_arity => "variable", + attr_type => "ia32_asm_attr_t", + latency => 100, +}, + +ProduceVal => { + op_flags => "c", + irn_flags => "R", + reg_req => { out => [ "gp" ] }, + emit => "", + units => [ ], + latency => 0, + mode => $mode_gp, + cmp_attr => "return 1;", +}, + #-----------------------------------------------------------------# # _ _ _ # # (_) | | | | # @@ -229,625 +362,956 @@ $default_cmp_attr = "return ia32_compare_immop_attr(attr_a, attr_b);"; # commutative operations -# 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 - -"Add" => { - "irn_flags" => "R", - "comment" => "construct Add: Add(a, b) = Add(b, a) = a + b", - "reg_req" => { "in" => [ "gp", "gp", "gp", "gp", "none" ], "out" => [ "in_r3" ] }, - "emit" => '. add %ia32_emit_binop /* Add(%A3, %A4) -> %D1 */', - "units" => [ "ALU", "MEM" ], -}, - -"AddC" => { - "comment" => "construct Add with Carry: AddC(a, b) = Add(b, a) = a + b + carry", - "reg_req" => { "in" => [ "gp", "gp", "gp", "gp", "none" ], "out" => [ "in_r3" ] }, - "emit" => '. adc %ia32_emit_binop /* AddC(%A3, %A4) -> %D1 */', - "units" => [ "ALU", "MEM" ], -}, - -"Add64Bit" => { - "irn_flags" => "R", - "comment" => "construct 64Bit Add: Add(a_l, a_h, b_l, b_h) = a_l + b_l; a_h + b_h + carry", - "arity" => 4, - "reg_req" => { "in" => [ "gp", "gp", "gp", "gp" ], "out" => [ "!in", "!in" ] }, - "emit" => ' -. mov %D1, %S1 /* mov a_l into assigned l_res register */ -. mov %D2, %S2 /* mov a_h into assigned h_res register */ -. add %D1, %S3 /* a_l + b_l */ -. adc %D2, %S4 /* a_h + b_h + carry */ -', - "outs" => [ "low_res", "high_res" ], - "units" => [ "ALU", "MEM" ], -}, - -"l_Add" => { - "op_flags" => "C", - "irn_flags" => "R", - "cmp_attr" => "return 1;", - "comment" => "construct lowered Add: Add(a, b) = Add(b, a) = a + b", - "arity" => 2, -}, - -"l_AddC" => { - "op_flags" => "C", - "cmp_attr" => "return 1;", - "comment" => "construct lowered Add with Carry: AddC(a, b) = Add(b, a) = a + b + carry", - "arity" => 2, -}, - -"MulS" => { - # we should not rematrialize this node. It produces 2 results and has - # very strict constrains - "comment" => "construct MulS: MulS(a, b) = MulS(b, a) = a * b", - "reg_req" => { "in" => [ "gp", "gp", "eax", "gp", "none" ], "out" => [ "eax", "edx" ] }, - "emit" => '. mul %ia32_emit_unop /* Mul(%A1, %A2) -> %D1 */', - "outs" => [ "EAX", "EDX", "M" ], - "latency" => 10, - "units" => [ "MUL" ], -}, - -"l_MulS" => { - # we should not rematrialize this node. It produces 2 results and has - # very strict constrains - "op_flags" => "C", - "cmp_attr" => "return 1;", - "comment" => "construct lowered MulS: MulS(a, b) = MulS(b, a) = a * b", - "outs" => [ "EAX", "EDX", "M" ], - "arity" => 2 -}, - -"Mul" => { - "irn_flags" => "R", - "comment" => "construct Mul: Mul(a, b) = Mul(b, a) = a * b", - "reg_req" => { "in" => [ "gp", "gp", "gp", "gp", "none" ], "out" => [ "in_r3" ] }, - "emit" => '. imul %ia32_emit_binop /* Mul(%A1, %A2) -> %D1 */', - "latency" => 5, - "units" => [ "MUL" ], -}, - -"l_Mul" => { - "op_flags" => "C", - "cmp_attr" => "return 1;", - "comment" => "construct lowered Mul: Mul(a, b) = Mul(b, a) = a * b", - "arity" => 2 -}, - -# Mulh is an exception from the 4 INs with AM because the target is always EAX:EDX -"Mulh" => { - # we should not rematrialize this node. It produces 2 results and has - # very strict constrains - "comment" => "construct Mul: Mul(a, b) = Mul(b, a) = a * b", - "reg_req" => { "in" => [ "gp", "gp", "eax", "gp", "none" ], "out" => [ "eax", "edx" ] }, - "emit" => '. imul %ia32_emit_unop /* Mulh(%A1, %A2) -> %D1 */', - "outs" => [ "EAX", "EDX", "M" ], - "latency" => 5, - "units" => [ "MUL" ], -}, - -"And" => { - "irn_flags" => "R", - "comment" => "construct And: And(a, b) = And(b, a) = a AND b", - "reg_req" => { "in" => [ "gp", "gp", "gp", "gp", "none" ], "out" => [ "in_r3" ] }, - "emit" => '. and %ia32_emit_binop /* And(%A1, %A2) -> %D1 */', - "units" => [ "ALU" ], -}, - -"Or" => { - "irn_flags" => "R", - "comment" => "construct Or: Or(a, b) = Or(b, a) = a OR b", - "reg_req" => { "in" => [ "gp", "gp", "gp", "gp", "none" ], "out" => [ "in_r3" ] }, - "emit" => '. or %ia32_emit_binop /* Or(%A1, %A2) -> %D1 */', - "units" => [ "ALU" ], -}, - -"Eor" => { - "irn_flags" => "R", - "comment" => "construct Eor: Eor(a, b) = Eor(b, a) = a EOR b", - "reg_req" => { "in" => [ "gp", "gp", "gp", "gp", "none" ], "out" => [ "in_r3" ] }, - "emit" => '. xor %ia32_emit_binop /* Xor(%A1, %A2) -> %D1 */', - "units" => [ "ALU" ], -}, - -"l_Eor" => { - "op_flags" => "C", - "cmp_attr" => "return 1;", - "comment" => "construct lowered Eor: Eor(a, b) = Eor(b, a) = a EOR b", - "arity" => 2 -}, - -"Max" => { - "irn_flags" => "R", - "comment" => "construct Max: Max(a, b) = Max(b, a) = a > b ? a : b", - "reg_req" => { "in" => [ "gp", "gp" ], "out" => [ "in_r1" ] }, - "emit" => -'2. cmp %S1, %S2 /* prepare Max (%S1 - %S2), (%A1, %A2) */ - if (mode_is_signed(get_irn_mode(n))) { -4. cmovl %D1, %S2 /* %S1 is less %S2 */ - } - else { -4. cmovb %D1, %S2 /* %S1 is below %S2 */ - } -', - "latency" => 2, - "units" => [ "ALU" ], -}, - -"Min" => { - "irn_flags" => "R", - "comment" => "construct Min: Min(a, b) = Min(b, a) = a < b ? a : b", - "reg_req" => { "in" => [ "gp", "gp" ], "out" => [ "in_r1" ] }, - "emit" => -'2. cmp %S1, %S2 /* prepare Min (%S1 - %S2), (%A1, %A2) */ - if (mode_is_signed(get_irn_mode(n))) { -2. cmovg %D1, %S2 /* %S1 is greater %S2 */ - } - else { -2. cmova %D1, %S2, %D1 /* %S1 is above %S2 */ - } -', - "latency" => 2, - "units" => [ "ALU" ], +Add => { + irn_flags => "R", + reg_req => { in => [ "gp", "gp", "none", "gp", "gp" ], out => [ "in_r4 in_r5", "none", "flags" ] }, + ins => [ "base", "index", "mem", "left", "right" ], + emit => '. add%M %binop', + am => "full,binary", + units => [ "GP" ], + mode => $mode_gp, + modified_flags => $status_flags +}, + +AddMem => { + irn_flags => "R", + reg_req => { in => [ "gp", "gp", "none", "gp" ], out => [ "none" ] }, + ins => [ "base", "index", "mem", "val" ], + emit => ". add%M %SI3, %AM", + units => [ "GP" ], + mode => "mode_M", + modified_flags => $status_flags +}, + +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 +}, + +Adc => { + reg_req => { in => [ "gp", "gp", "none", "gp", "gp", "flags" ], out => [ "in_r4 in_r5" ] }, + ins => [ "base", "index", "mem", "left", "right", "eflags" ], + emit => '. adc%M %binop', + am => "full,binary", + units => [ "GP" ], + mode => $mode_gp, + modified_flags => $status_flags +}, + +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" ], +}, + +Mul => { + # we should not rematrialize this node. It produces 2 results and has + # very strict constrains + reg_req => { in => [ "gp", "gp", "none", "eax", "gp" ], out => [ "eax", "edx", "none" ] }, + ins => [ "base", "index", "mem", "val_high", "val_low" ], + emit => '. mul%M %unop4', + outs => [ "EAX", "EDX", "M" ], + am => "source,binary", + latency => 10, + units => [ "GP" ], + modified_flags => $status_flags +}, + +l_Mul => { + # 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 +}, + +IMul => { + irn_flags => "R", + reg_req => { in => [ "gp", "gp", "none", "gp", "gp" ], out => [ "in_r4 in_r5" ] }, + ins => [ "base", "index", "mem", "left", "right" ], + emit => '. imul%M %binop', + am => "source,binary", + latency => 5, + units => [ "GP" ], + mode => $mode_gp, + modified_flags => $status_flags +}, + +IMul1OP => { + irn_flags => "R", + reg_req => { in => [ "gp", "gp", "none", "eax", "gp" ], out => [ "eax", "edx", "none" ] }, + ins => [ "base", "index", "mem", "val_high", "val_low" ], + emit => '. imul%M %unop4', + outs => [ "EAX", "EDX", "M" ], + am => "source,binary", + latency => 5, + units => [ "GP" ], + modified_flags => $status_flags +}, + +l_IMul => { + # 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 +}, + +And => { + irn_flags => "R", + reg_req => { in => [ "gp", "gp", "none", "gp", "gp" ], out => [ "in_r4 in_r5" ] }, + ins => [ "base", "index", "mem", "left", "right" ], + am => "full,binary", + emit => '. and%M %binop', + units => [ "GP" ], + mode => $mode_gp, + modified_flags => $status_flags +}, + +AndMem => { + irn_flags => "R", + reg_req => { in => [ "gp", "gp", "none", "gp" ], out => [ "none" ] }, + ins => [ "base", "index", "mem", "val" ], + emit => '. and%M %SI3, %AM', + units => [ "GP" ], + mode => "mode_M", + modified_flags => $status_flags +}, + +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 +}, + +Or => { + irn_flags => "R", + reg_req => { in => [ "gp", "gp", "none", "gp", "gp" ], out => [ "in_r4 in_r5" ] }, + ins => [ "base", "index", "mem", "left", "right" ], + am => "full,binary", + emit => '. or%M %binop', + units => [ "GP" ], + mode => $mode_gp, + modified_flags => $status_flags +}, + +OrMem => { + irn_flags => "R", + reg_req => { in => [ "gp", "gp", "none", "gp" ], out => [ "none" ] }, + ins => [ "base", "index", "mem", "val" ], + emit => '. or%M %SI3, %AM', + units => [ "GP" ], + mode => "mode_M", + modified_flags => $status_flags +}, + +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 +}, + +Xor => { + irn_flags => "R", + reg_req => { in => [ "gp", "gp", "none", "gp", "gp" ], out => [ "in_r4 in_r5" ] }, + ins => [ "base", "index", "mem", "left", "right" ], + am => "full,binary", + emit => '. xor%M %binop', + units => [ "GP" ], + mode => $mode_gp, + modified_flags => $status_flags +}, + +XorMem => { + irn_flags => "R", + reg_req => { in => [ "gp", "gp", "none", "gp" ], out => [ "none" ] }, + ins => [ "base", "index", "mem", "val" ], + emit => '. xor%M %SI3, %AM', + units => [ "GP" ], + mode => "mode_M", + modified_flags => $status_flags +}, + +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 }, # not commutative operations -"Sub" => { - "irn_flags" => "R", - "comment" => "construct Sub: Sub(a, b) = a - b", - "reg_req" => { "in" => [ "gp", "gp", "gp", "gp", "none" ], "out" => [ "in_r3" ] }, - "emit" => '. sub %ia32_emit_binop /* Sub(%A3, %A4) -> %D1 */', - "units" => [ "ALU" ], -}, - -"SubC" => { - "comment" => "construct Sub with Carry: SubC(a, b) = a - b - carry", - "reg_req" => { "in" => [ "gp", "gp", "gp", "gp", "none" ], "out" => [ "in_r3 !in_r4" ] }, - "emit" => '. sbb %ia32_emit_binop /* SubC(%A3, %A4) -> %D1 */', - "units" => [ "ALU" ], -}, - -"Sub64Bit" => { - "irn_flags" => "R", - "comment" => "construct 64Bit Sub: Sub(a_l, a_h, b_l, b_h) = a_l - b_l; a_h - b_h - borrow", - "arity" => 4, - "reg_req" => { "in" => [ "gp", "gp", "gp", "gp" ], "out" => [ "!in", "!in" ] }, - "emit" => ' -. mov %D1, %S1 /* mov a_l into assigned l_res register */ -. mov %D2, %S2 /* mov a_h into assigned h_res register */ -. sub %D1, %S3 /* a_l - b_l */ -. sbb %D2, %S4 /* a_h - b_h - borrow */ -', - "outs" => [ "low_res", "high_res" ], - "units" => [ "ALU" ], -}, - -"l_Sub" => { - "irn_flags" => "R", - "cmp_attr" => "return 1;", - "comment" => "construct lowered Sub: Sub(a, b) = a - b", - "arity" => 2, -}, - -"l_SubC" => { - "cmp_attr" => "return 1;", - "comment" => "construct lowered Sub with Carry: SubC(a, b) = a - b - carry", - "arity" => 2, -}, - -"DivMod" => { - "op_flags" => "F|L", - "state" => "exc_pinned", - "reg_req" => { "in" => [ "eax", "gp", "edx", "none" ], "out" => [ "eax", "edx" ] }, - "attr" => "ia32_op_flavour_t dm_flav", - "init_attr" => " attr->data.op_flav = dm_flav;", - "cmp_attr" => " return attr_a->data.op_flav != attr_b->data.op_flav;\n", - "emit" => -' if (mode_is_signed(get_ia32_res_mode(n))) { -4. idiv %S2 /* signed DivMod(%S1, %S2) -> %D1, (%A1, %A2, %A3) */ - } - else { -4. div %S2 /* unsigned DivMod(%S1, %S2) -> %D1, (%A1, %A2, %A3) */ - } -', - "outs" => [ "div_res", "mod_res", "M" ], - "latency" => 25, - "units" => [ "ALU" ], -}, - -"Shl" => { - "irn_flags" => "R", - "comment" => "construct Shl: Shl(a, b) = a << b", - "reg_req" => { "in" => [ "gp", "gp", "gp", "ecx", "none" ], "out" => [ "in_r3 !in_r4" ] }, - "emit" => '. shl %ia32_emit_binop /* Shl(%A1, %A2) -> %D1 */', - "units" => [ "ALU1", "SSE1" ], -}, - -"l_Shl" => { - "cmp_attr" => "return 1;", - "comment" => "construct lowered Shl: Shl(a, b) = a << b", - "arity" => 2 -}, - -"ShlD" => { - "irn_flags" => "R", - "comment" => "construct ShlD: ShlD(a, b, c) = a, b << count (shift left count bits from b into a)", - # 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" => -' -if (get_ia32_immop_type(n) == ia32_ImmNone) { - if (get_ia32_op_type(n) == ia32_AddrModeD) { -4. shld %ia32_emit_am, %S4, %%cl /* ShlD(%A3, %A4, %A5) -> %D1 */ - } - else { -4. shld %S3, %S4, %%cl /* ShlD(%A3, %A4, %A5) -> %D1 */ - } -} -else { - if (get_ia32_op_type(n) == ia32_AddrModeD) { -4. shld %ia32_emit_am, %S4, %C /* ShlD(%A3, %A4, %A5) -> %D1 */ - } - else { -4. shld %S3, %S4, %C /* ShlD(%A3, %A4, %A5) -> %D1 */ - } -} -', - "latency" => 6, - "units" => [ "ALU1", "SSE1" ], -}, - -"l_ShlD" => { - "cmp_attr" => "return 1;", - "comment" => "construct lowered ShlD: ShlD(a, b, c) = a, b << count (shift left count bits from b into a)", - "arity" => 3 -}, - -"Shr" => { - "irn_flags" => "R", - "comment" => "construct Shr: Shr(a, b) = a >> b", - "reg_req" => { "in" => [ "gp", "gp", "gp", "ecx", "none" ], "out" => [ "in_r3 !in_r4" ] }, - "emit" => '. shr %ia32_emit_binop /* Shr(%A1, %A2) -> %D1 */', - "units" => [ "ALU1", "SSE1" ], -}, - -"l_Shr" => { - "cmp_attr" => "return 1;", - "comment" => "construct lowered Shr: Shr(a, b) = a << b", - "arity" => 2 -}, - -"ShrD" => { - "irn_flags" => "R", - "comment" => "construct ShrD: ShrD(a, b, c) = a, b >> count (shift rigth count bits from a into b)", - # 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" => -' -if (get_ia32_immop_type(n) == ia32_ImmNone) { - if (get_ia32_op_type(n) == ia32_AddrModeD) { -4. shrd %ia32_emit_am, %S4, %%cl /* ShrD(%A3, %A4, %A5) -> %D1 */ - } - else { -4. shrd %S3, %S4, %%cl /* ShrD(%A3, %A4, %A5) -> %D1 */ - } -} -else { - if (get_ia32_op_type(n) == ia32_AddrModeD) { -4. shrd %ia32_emit_am, %S4, %C /* ShrD(%A3, %A4, %A5) -> %D1 */ - } - else { -4. shrd %S3, %S4, %C /* ShrD(%A3, %A4, %A5) -> %D1 */ - } -} -', - "latency" => 6, - "units" => [ "ALU1", "SSE1" ], -}, - -"l_ShrD" => { - "cmp_attr" => "return 1;", - "comment" => "construct lowered ShrD: ShrD(a, b, c) = a, b >> count (shift rigth count bits from a into b)", - "arity" => 3 -}, - -"Shrs" => { - "irn_flags" => "R", - "comment" => "construct Shrs: Shrs(a, b) = a >> b", - "reg_req" => { "in" => [ "gp", "gp", "gp", "ecx", "none" ], "out" => [ "in_r3 !in_r4" ] }, - "emit" => '. sar %ia32_emit_binop /* Shrs(%A1, %A2) -> %D1 */', - "units" => [ "ALU1", "SSE1" ], -}, - -"l_Shrs" => { - "cmp_attr" => "return 1;", - "comment" => "construct lowered Shrs: Shrs(a, b) = a << b", - "arity" => 2 -}, - -"RotR" => { - "irn_flags" => "R", - "comment" => "construct RotR: RotR(a, b) = a ROTR b", - "reg_req" => { "in" => [ "gp", "gp", "gp", "ecx", "none" ], "out" => [ "in_r3 !in_r4" ] }, - "emit" => '. ror %ia32_emit_binop /* RotR(%A1, %A2) -> %D1 */', - "units" => [ "ALU1", "SSE1" ], -}, - -"RotL" => { - "irn_flags" => "R", - "comment" => "construct RotL: RotL(a, b) = a ROTL b", - "reg_req" => { "in" => [ "gp", "gp", "gp", "ecx", "none" ], "out" => [ "in_r3 !in_r4" ] }, - "emit" => '. rol %ia32_emit_binop /* RotL(%A1, %A2) -> %D1 */', - "units" => [ "ALU1", "SSE1" ], +Sub => { + irn_flags => "R", + reg_req => { in => [ "gp", "gp", "none", "gp", "gp" ], out => [ "in_r4", "none", "flags" ] }, + ins => [ "base", "index", "mem", "left", "right" ], + am => "full,binary", + emit => '. sub%M %binop', + units => [ "GP" ], + mode => $mode_gp, + modified_flags => $status_flags +}, + +SubMem => { + irn_flags => "R", + reg_req => { in => [ "gp", "gp", "none", "gp" ], out => [ "none" ] }, + ins => [ "base", "index", "mem", "val" ], + emit => '. sub%M %SI3, %AM', + units => [ "GP" ], + mode => 'mode_M', + modified_flags => $status_flags +}, + +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 +}, + +Sbb => { + reg_req => { in => [ "gp", "gp", "none", "gp", "gp", "flags" ], out => [ "in_r4 !in_r5" ] }, + ins => [ "base", "index", "mem", "left", "right", "eflags" ], + am => "full,binary", + emit => '. sbb%M %binop', + units => [ "GP" ], + mode => $mode_gp, + modified_flags => $status_flags +}, + +l_Sub => { + reg_req => { in => [ "none", "none" ], out => [ "none" ] }, + ins => [ "left", "right" ], +}, + +l_Sbb => { + reg_req => { in => [ "none", "none", "none" ], out => [ "none" ] }, + ins => [ "left", "right", "eflags" ], +}, + +IDiv => { + op_flags => "F|L", + state => "exc_pinned", + reg_req => { in => [ "gp", "gp", "none", "eax", "edx", "gp" ], out => [ "eax", "edx", "none" ] }, + ins => [ "base", "index", "mem", "left_low", "left_high", "right" ], + outs => [ "div_res", "mod_res", "M" ], + attr => "ia32_op_flavour_t dm_flav", + am => "source,ternary", + init_attr => "attr->data.op_flav = dm_flav;", + emit => ". idiv%M %unop5", + latency => 25, + units => [ "GP" ], + modified_flags => $status_flags +}, + +Div => { + op_flags => "F|L", + state => "exc_pinned", + reg_req => { in => [ "gp", "gp", "none", "eax", "edx", "gp" ], out => [ "eax", "edx", "none" ] }, + ins => [ "base", "index", "mem", "left_low", "left_high", "right" ], + outs => [ "div_res", "mod_res", "M" ], + attr => "ia32_op_flavour_t dm_flav", + am => "source,ternary", + init_attr => "attr->data.op_flav = dm_flav;", + emit => ". div%M %unop5", + latency => 25, + units => [ "GP" ], + modified_flags => $status_flags +}, + +Shl => { + irn_flags => "R", + reg_req => { in => [ "gp", "ecx" ], out => [ "in_r1 !in_r2" ] }, + ins => [ "left", "right" ], + am => "dest,binary", + emit => '. shl %SB1, %S0', + units => [ "GP" ], + mode => $mode_gp, + modified_flags => $status_flags +}, + +ShlMem => { + irn_flags => "R", + reg_req => { in => [ "gp", "gp", "none", "ecx" ], out => [ "none" ] }, + ins => [ "base", "index", "mem", "count" ], + emit => '. shl%M %SB3, %AM', + units => [ "GP" ], + mode => "mode_M", + modified_flags => $status_flags +}, + +l_ShlDep => { + cmp_attr => "return 1;", + # value, cnt, dependency + arity => 3 +}, + +ShlD => { + # FIXME: WHY? the right requirement is in_r3 !in_r5, especially this is the same as in Shl + # + # 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" ] }, + + irn_flags => "R", + reg_req => { in => [ "gp", "gp", "ecx" ], out => [ "in_r1 !in_r3" ] }, + ins => [ "left_high", "left_low", "right" ], + am => "dest,ternary", + emit => '. shld%M %SB2, %S1, %S0', + latency => 6, + units => [ "GP" ], + mode => $mode_gp, + modified_flags => $status_flags +}, + +l_ShlD => { + cmp_attr => "return 1;", + arity => 3, +}, + +Shr => { + irn_flags => "R", + reg_req => { in => [ "gp", "ecx" ], out => [ "in_r1 !in_r2" ] }, + ins => [ "val", "count" ], + am => "dest,binary", + emit => '. shr %SB1, %S0', + units => [ "GP" ], + mode => $mode_gp, + modified_flags => $status_flags +}, + +ShrMem => { + irn_flags => "R", + reg_req => { in => [ "gp", "gp", "none", "ecx" ], out => [ "none" ] }, + ins => [ "base", "index", "mem", "count" ], + emit => '. shr%M %SB3, %AM', + units => [ "GP" ], + mode => "mode_M", + modified_flags => $status_flags +}, + +l_ShrDep => { + cmp_attr => "return 1;", + # value, cnt, dependency + arity => 3 +}, + +ShrD => { + # FIXME: WHY? the right requirement is in_r3 !in_r5, especially this is the same as in Shr + # + # 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" ] }, + + irn_flags => "R", + reg_req => { in => [ "gp", "gp", "ecx" ], out => [ "in_r1 !in_r3" ] }, + ins => [ "left_high", "left_low", "right" ], + am => "dest,ternary", + emit => '. shrd%M %SB2, %S1, %S0', + latency => 6, + units => [ "GP" ], + mode => $mode_gp, + modified_flags => $status_flags +}, + +l_ShrD => { + cmp_attr => "return 1;", + arity => 3 +}, + +Sar => { + irn_flags => "R", + reg_req => { in => [ "gp", "ecx" ], out => [ "in_r1 !in_r2" ] }, + ins => [ "val", "count" ], + am => "dest,binary", + emit => '. sar %SB1, %S0', + units => [ "GP" ], + mode => $mode_gp, + modified_flags => $status_flags +}, + +SarMem => { + irn_flags => "R", + reg_req => { in => [ "gp", "gp", "none", "ecx" ], out => [ "none" ] }, + ins => [ "base", "index", "mem", "count" ], + emit => '. sar%M %SB3, %AM', + units => [ "GP" ], + mode => "mode_M", + modified_flags => $status_flags +}, + +l_Sar => { + cmp_attr => "return 1;", + # value, cnt + arity => 2 +}, + +l_SarDep => { + cmp_attr => "return 1;", + # value, cnt, dependency + arity => 3 +}, + +Ror => { + irn_flags => "R", + reg_req => { in => [ "gp", "ecx" ], out => [ "in_r1 !in_r2" ] }, + ins => [ "val", "count" ], + am => "dest,binary", + emit => '. ror %SB1, %S0', + units => [ "GP" ], + mode => $mode_gp, + modified_flags => $status_flags +}, + +RorMem => { + irn_flags => "R", + reg_req => { in => [ "gp", "gp", "none", "ecx" ], out => [ "none" ] }, + ins => [ "base", "index", "mem", "count" ], + emit => '. ror%M %SB3, %AM', + units => [ "GP" ], + mode => "mode_M", + modified_flags => $status_flags +}, + +Rol => { + irn_flags => "R", + reg_req => { in => [ "gp", "ecx" ], out => [ "in_r1 !in_r2" ] }, + ins => [ "val", "count" ], + am => "dest,binary", + emit => '. rol %SB1, %S0', + units => [ "GP" ], + mode => $mode_gp, + modified_flags => $status_flags +}, + +RolMem => { + irn_flags => "R", + reg_req => { in => [ "gp", "gp", "none", "ecx" ], out => [ "none" ] }, + ins => [ "base", "index", "mem", "count" ], + emit => '. rol%M %SB3, %AM', + units => [ "GP" ], + mode => "mode_M", + modified_flags => $status_flags }, # unary operations -"Minus" => { - "irn_flags" => "R", - "comment" => "construct Minus: Minus(a) = -a", - "reg_req" => { "in" => [ "gp", "gp", "gp", "none" ], "out" => [ "in_r3" ] }, - "emit" => '. neg %ia32_emit_unop /* Neg(%A1) -> %D1, (%A1) */', - "units" => [ "ALU" ], -}, - -"Minus64Bit" => { - "irn_flags" => "R", - "comment" => "construct 64Bit Minus: Minus(a_l, a_h, 0) = 0 - a_l; 0 - a_h - borrow", - "arity" => 4, - "reg_req" => { "in" => [ "gp", "gp", "gp" ], "out" => [ "!in", "!in" ] }, - "emit" => ' -. mov %D1, %S1 /* l_res */ -. mov %D2, %S1 /* h_res */ -. sub %D1, %S2 /* 0 - a_l -> low_res */ -. sbb %D2, %S3 /* 0 - a_h - borrow -> high_res */ -', - "outs" => [ "low_res", "high_res" ], - "units" => [ "ALU" ], -}, - - -"l_Minus" => { - "cmp_attr" => "return 1;", - "comment" => "construct lowered Minus: Minus(a) = -a", - "arity" => 1, -}, - -"Inc" => { - "irn_flags" => "R", - "comment" => "construct Increment: Inc(a) = a++", - "reg_req" => { "in" => [ "gp", "gp", "gp", "none" ], "out" => [ "in_r3" ] }, - "emit" => '. inc %ia32_emit_unop /* Inc(%S1) -> %D1, (%A1) */', - "units" => [ "ALU" ], -}, - -"Dec" => { - "irn_flags" => "R", - "comment" => "construct Decrement: Dec(a) = a--", - "reg_req" => { "in" => [ "gp", "gp", "gp", "none" ], "out" => [ "in_r3" ] }, - "emit" => '. dec %ia32_emit_unop /* Dec(%S1) -> %D1, (%A1) */', - "units" => [ "ALU" ], -}, - -"Not" => { - "irn_flags" => "R", - "comment" => "construct Not: Not(a) = !a", - "reg_req" => { "in" => [ "gp", "gp", "gp", "none" ], "out" => [ "in_r3" ] }, - "emit" => '. not %ia32_emit_unop /* Not(%S1) -> %D1, (%A1) */', - "units" => [ "ALU" ], +Neg => { + irn_flags => "R", + reg_req => { in => [ "gp" ], out => [ "in_r1" ] }, + emit => '. neg %S0', + ins => [ "val" ], + am => "dest,unary", + units => [ "GP" ], + mode => $mode_gp, + modified_flags => $status_flags +}, + +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 +}, + +Minus64Bit => { + irn_flags => "R", + reg_req => { in => [ "gp", "gp" ], out => [ "in_r1", "gp" ] }, + outs => [ "low_res", "high_res" ], + units => [ "GP" ], + modified_flags => $status_flags +}, + + +l_Neg => { + cmp_attr => "return 1;", + arity => 1, +}, + +Inc => { + irn_flags => "R", + reg_req => { in => [ "gp" ], out => [ "in_r1" ] }, + am => "dest,unary", + emit => '. inc %S0', + units => [ "GP" ], + mode => $mode_gp, + modified_flags => [ "OF", "SF", "ZF", "AF", "PF" ] +}, + +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" ] +}, + +Dec => { + irn_flags => "R", + reg_req => { in => [ "gp" ], out => [ "in_r1" ] }, + am => "dest,unary", + emit => '. dec %S0', + units => [ "GP" ], + mode => $mode_gp, + modified_flags => [ "OF", "SF", "ZF", "AF", "PF" ] +}, + +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" ] +}, + +Not => { + irn_flags => "R", + reg_req => { in => [ "gp" ], out => [ "in_r1" ] }, + ins => [ "val" ], + am => "dest,unary", + emit => '. not %S0', + units => [ "GP" ], + mode => $mode_gp, +}, + +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", }, # other operations -"CondJmp" => { - "op_flags" => "L|X|Y", - "comment" => "construct conditional jump: CMP A, B && JMPxx LABEL", - "reg_req" => { "in" => [ "gp", "gp", "gp", "gp", "none" ] }, - "outs" => [ "false", "true" ], - "latency" => 3, - "units" => [ "BRANCH" ], -}, - -"TestJmp" => { - "op_flags" => "L|X|Y", - "comment" => "construct conditional jump: TEST A, B && JMPxx LABEL", - "reg_req" => { "in" => [ "gp", "gp" ] }, - "outs" => [ "false", "true" ], - "latency" => 3, - "units" => [ "BRANCH" ], -}, - -"CJmpAM" => { - "op_flags" => "L|X|Y", - "comment" => "construct conditional jump without CMP (replaces CondJmp): JMPxx LABEL", - "reg_req" => { "in" => [ "gp", "gp", "gp", "gp", "none" ], "out" => [ "none", "none" ] }, - "outs" => [ "false", "true" ], - "units" => [ "BRANCH" ], -}, - -"CJmp" => { - "op_flags" => "L|X|Y", - "comment" => "construct conditional jump without CMP (replaces TestJmp): JMPxx LABEL", - "reg_req" => { "in" => [ "gp", "gp" ] }, - "units" => [ "BRANCH" ], -}, - -"SwitchJmp" => { - "op_flags" => "L|X|Y", - "comment" => "construct switch", - "reg_req" => { "in" => [ "gp" ], "out" => [ "none" ] }, - "latency" => 3, - "units" => [ "BRANCH" ], -}, - -"Const" => { - "op_flags" => "c", - "irn_flags" => "R", - "comment" => "represents an integer constant", - "reg_req" => { "out" => [ "gp" ] }, - "units" => [ "ALU" ], -}, - -"Cdq" => { - # we should not rematrialize this node. It produces 2 results and has - # very strict constrains - "comment" => "construct CDQ: sign extend EAX -> EDX:EAX", - "reg_req" => { "in" => [ "gp" ], "out" => [ "eax in_r1", "edx" ] }, - "emit" => '. cdq /* sign extend EAX -> EDX:EAX, (%A1) */', - "outs" => [ "EAX", "EDX" ], - "units" => [ "ALU" ], +Cmp => { + irn_flags => "R", + reg_req => { in => [ "gp", "gp", "none", "gp", "gp" ] , out => [ "flags" ] }, + ins => [ "base", "index", "mem", "left", "right" ], + outs => [ "eflags" ], + am => "source,binary", + 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 +}, + +Cmp8Bit => { + irn_flags => "R", + reg_req => { in => [ "gp", "gp", "none", "eax ebx ecx edx", "eax ebx ecx edx" ] , out => [ "flags" ] }, + ins => [ "base", "index", "mem", "left", "right" ], + outs => [ "eflags" ], + am => "source,binary", + 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 +}, + +Test => { + irn_flags => "R", + reg_req => { in => [ "gp", "gp", "none", "gp", "gp" ] , out => [ "flags" ] }, + ins => [ "base", "index", "mem", "left", "right" ], + outs => [ "eflags" ], + am => "source,binary", + emit => '. test%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 +}, + +Test8Bit => { + irn_flags => "R", + reg_req => { in => [ "gp", "gp", "none", "eax ebx ecx edx", "eax ebx ecx edx" ] , out => [ "flags" ] }, + ins => [ "base", "index", "mem", "left", "right" ], + outs => [ "eflags" ], + am => "source,binary", + emit => '. testb %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 +}, + +Set => { + #irn_flags => "R", + reg_req => { in => [ "eflags" ], out => [ "eax ebx ecx edx" ] }, + ins => [ "eflags" ], + am => "dest,unary", + attr => "pn_Cmp pnc", + init_attr => "attr->pn_code = pnc;\nset_ia32_ls_mode(res, mode_Bu);\n", + emit => '. set%CMP0 %DB0', + latency => 1, + units => [ "GP" ], + mode => $mode_gp, +}, + +CMov => { + #irn_flags => "R", + # (note: leave the false,true order intact to make it compatible with other + # ia32_binary ops) + reg_req => { in => [ "gp", "gp", "none", "gp", "gp", "eflags" ], out => [ "in_r4" ] }, + ins => [ "base", "index", "mem", "val_false", "val_true", "eflags" ], + am => "source,binary", + attr => "pn_Cmp pn_code", + init_attr => "attr->pn_code = pn_code;", + latency => 1, + units => [ "GP" ], + mode => $mode_gp, +}, + +Jcc => { + state => "pinned", + op_flags => "L|X|Y", + reg_req => { in => [ "eflags" ], out => [ "none", "none" ] }, + ins => [ "eflags" ], + outs => [ "false", "true" ], + attr => "pn_Cmp pnc", + init_attr => "attr->pn_code = pnc;", + latency => 2, + units => [ "BRANCH" ], +}, + +SwitchJmp => { + state => "pinned", + op_flags => "L|X|Y", + reg_req => { in => [ "gp" ], out => [ "none" ] }, + latency => 3, + units => [ "BRANCH" ], + mode => "mode_T", + modified_flags => $status_flags +}, + +IJmp => { + state => "pinned", + op_flags => "X", + reg_req => { in => [ "gp" ] }, + emit => '. jmp *%S0', + units => [ "BRANCH" ], + mode => "mode_X", +}, + +Const => { + op_flags => "c", + irn_flags => "R", + reg_req => { out => [ "gp" ] }, + units => [ "GP" ], + attr => "ir_entity *symconst, int symconst_sign, long offset", + attr_type => "ia32_immediate_attr_t", + mode => $mode_gp, +# depends on the const and is set in ia32_transform +# modified_flags => $status_flags +}, + +Unknown_GP => { + state => "pinned", + op_flags => "c", + irn_flags => "I", + reg_req => { out => [ "gp_UKNWN" ] }, + units => [], + emit => "", + mode => $mode_gp +}, + +Unknown_VFP => { + state => "pinned", + op_flags => "c", + irn_flags => "I", + reg_req => { out => [ "vfp_UKNWN" ] }, + units => [], + emit => "", + mode => "mode_E", + attr_type => "ia32_x87_attr_t", +}, + +Unknown_XMM => { + state => "pinned", + op_flags => "c", + irn_flags => "I", + reg_req => { out => [ "xmm_UKNWN" ] }, + units => [], + emit => "", + mode => "mode_E" +}, + +NoReg_GP => { + state => "pinned", + op_flags => "c", + irn_flags => "I", + reg_req => { out => [ "gp_NOREG" ] }, + units => [], + emit => "", + mode => $mode_gp +}, + +NoReg_VFP => { + state => "pinned", + op_flags => "c", + irn_flags => "I", + reg_req => { out => [ "vfp_NOREG" ] }, + units => [], + emit => "", + mode => "mode_E", + attr_type => "ia32_x87_attr_t", +}, + +NoReg_XMM => { + state => "pinned", + op_flags => "c", + irn_flags => "I", + reg_req => { out => [ "xmm_NOREG" ] }, + units => [], + emit => "", + mode => "mode_E" +}, + +ChangeCW => { + state => "pinned", + op_flags => "c", + irn_flags => "I", + reg_req => { out => [ "fp_cw" ] }, + mode => $mode_fpcw, + latency => 3, + units => [ "GP" ], + modified_flags => $fpcw_flags +}, + +FldCW => { + op_flags => "L|F", + state => "pinned", + reg_req => { in => [ "gp", "gp", "none" ], out => [ "fp_cw" ] }, + ins => [ "base", "index", "mem" ], + latency => 5, + emit => ". fldcw %AM", + mode => $mode_fpcw, + units => [ "GP" ], + modified_flags => $fpcw_flags +}, + +FnstCW => { + op_flags => "L|F", + state => "pinned", + reg_req => { in => [ "gp", "gp", "none", "fp_cw" ], out => [ "none" ] }, + ins => [ "base", "index", "mem", "fpcw" ], + latency => 5, + emit => ". fnstcw %AM", + mode => "mode_M", + units => [ "GP" ], +}, + +Cltd => { + # we should not rematrialize this node. It has very strict constraints. + reg_req => { in => [ "eax", "edx" ], out => [ "edx" ] }, + ins => [ "val", "globbered" ], + emit => '. cltd', + mode => $mode_gp, + units => [ "GP" ], }, # Load / Store - -"Load" => { - "op_flags" => "L|F", - "state" => "exc_pinned", - "comment" => "construct Load: Load(ptr, mem) = LD ptr -> reg", - "reg_req" => { "in" => [ "gp", "gp", "none" ], "out" => [ "gp" ] }, - "latency" => 3, - "emit" => -' if (get_mode_size_bits(get_ia32_ls_mode(n)) < 32) { -4. mov%Mx %D1, %ia32_emit_am /* Load((%A1)) -> %D1 */ - } - else { -4. mov %D1, %ia32_emit_am /* Load((%A1)) -> %D1 */ - } -', - "outs" => [ "res", "M" ], - "units" => [ "MEM" ], -}, - -"l_Load" => { - "op_flags" => "L|F", - "cmp_attr" => "return 1;", - "comment" => "construct lowered Load: Load(ptr, mem) = LD ptr -> reg", - "outs" => [ "res", "M" ], - "arity" => 2, -}, - -"l_Store" => { - "op_flags" => "L|F", - "cmp_attr" => "return 1;", - "state" => "exc_pinned", - "comment" => "construct lowered Store: Store(ptr, val, mem) = ST ptr,val", - "arity" => 3, - "mode" => "mode_M", -}, - -"Store" => { - "op_flags" => "L|F", - "state" => "exc_pinned", - "comment" => "construct Store: Store(ptr, val, mem) = ST ptr,val", - "reg_req" => { "in" => [ "gp", "gp", "gp", "none" ] }, - "emit" => '. mov %ia32_emit_binop /* Store(%A3) -> (%A1) */', - "latency" => 3, - "units" => [ "MEM" ], - "mode" => "mode_M", -}, - -"Store8Bit" => { - "op_flags" => "L|F", - "state" => "exc_pinned", - "comment" => "construct 8Bit Store: Store(ptr, val, mem) = ST ptr,val", - "reg_req" => { "in" => [ "gp", "gp", "eax ebx ecx edx", "none" ] }, - "emit" => '. mov %ia32_emit_binop /* Store(%A3) -> (%A1) */', - "latency" => 3, - "units" => [ "MEM" ], - "mode" => "mode_M", -}, - -"Lea" => { - "irn_flags" => "R", - "comment" => "construct Lea: Lea(a,b) = lea [a+b*const+offs] | res = a + b * const + offs with const = 0,1,2,4,8", - "reg_req" => { "in" => [ "gp", "gp" ], "out" => [ "in_r1" ] }, - "emit" => '. lea %D1, %ia32_emit_am /* LEA(%A1, %A2) */', - "latency" => 2, - "units" => [ "ALU" ], -}, - -"Push" => { - "comment" => "push on the stack", - "reg_req" => { "in" => [ "gp", "gp", "gp", "esp", "none" ], "out" => [ "esp" ] }, - "emit" => '. push %ia32_emit_unop /* PUSH(%A1) */', - "outs" => [ "stack:I|S", "M" ], - "latency" => 3, - "units" => [ "MEM" ], -}, - -"Pop" => { - # We don't set class modify stack here (but we will do this on proj 1) - "comment" => "pop a gp register from the stack", - "reg_req" => { "in" => [ "gp", "gp", "esp", "none" ], "out" => [ "gp", "esp" ] }, - "emit" => '. pop %ia32_emit_unop /* POP(%A1) */', - "outs" => [ "res", "stack:I|S", "M" ], - "latency" => 4, - "units" => [ "MEM" ], -}, - -"Enter" => { - "comment" => "create stack frame", - "reg_req" => { "in" => [ "esp" ], "out" => [ "ebp", "esp" ] }, - "emit" => '. enter /* Enter */', - "outs" => [ "frame:I", "stack:I|S", "M" ], - "latency" => 15, - "units" => [ "MEM" ], -}, - -"Leave" => { - "comment" => "destroy stack frame", - "reg_req" => { "in" => [ "esp", "ebp" ], "out" => [ "ebp", "esp" ] }, - "emit" => '. leave /* Leave */', - "outs" => [ "frame:I", "stack:I|S", "M" ], - "latency" => 3, - "units" => [ "MEM" ], -}, - -"AddSP" => { - "irn_flags" => "I", - "comment" => "allocate space on stack", - "reg_req" => { "in" => [ "esp", "gp" ], "out" => [ "esp", "none" ] }, - "outs" => [ "stack:S", "M" ], - "units" => [ "ALU" ], -}, - -"SubSP" => { - "irn_flags" => "I", - "comment" => "free space on stack", - "reg_req" => { "in" => [ "esp", "gp" ], "out" => [ "esp", "none" ] }, - "outs" => [ "stack:S", "M" ], - "units" => [ "ALU" ], -}, - -"LdTls" => { - "irn_flags" => "R", - "comment" => "get the TLS base address", - "reg_req" => { "out" => [ "gp" ] }, - "units" => [ "MEM" ], +# +# Note that we add additional latency values depending on address mode, so a +# lateny of 0 for load is correct + +Load => { + op_flags => "L|F", + state => "exc_pinned", + reg_req => { in => [ "gp", "gp", "none" ], out => [ "gp", "none" ] }, + ins => [ "base", "index", "mem" ], + outs => [ "res", "M" ], + latency => 0, + emit => ". mov%SE%ME%.l %AM, %D0", + units => [ "GP" ], +}, + +l_Load => { + op_flags => "L|F", + cmp_attr => "return 1;", + outs => [ "res", "M" ], + arity => 2, +}, + +l_Store => { + op_flags => "L|F", + cmp_attr => "return 1;", + state => "exc_pinned", + arity => 3, + mode => "mode_M", +}, + +Store => { + op_flags => "L|F", + state => "exc_pinned", + reg_req => { in => [ "gp", "gp", "none", "gp" ], out => [ "none" ] }, + ins => [ "base", "index", "mem", "val" ], + emit => '. mov%M %SI3, %AM', + latency => 2, + units => [ "GP" ], + mode => "mode_M", +}, + +Store8Bit => { + op_flags => "L|F", + state => "exc_pinned", + reg_req => { in => [ "gp", "gp", "none", "eax ebx ecx edx" ], out => ["none" ] }, + ins => [ "base", "index", "mem", "val" ], + emit => '. mov%M %SB3, %AM', + latency => 2, + units => [ "GP" ], + mode => "mode_M", +}, + +Lea => { + irn_flags => "R", + reg_req => { in => [ "gp", "gp" ], out => [ "gp" ] }, + ins => [ "base", "index" ], + emit => '. leal %AM, %D0', + latency => 2, + units => [ "GP" ], + mode => $mode_gp, +# well this isn't true for Lea, but we often transform Lea back to Add, Inc +# or Dec, so we set the flag + modified_flags => 1, +}, + +Push => { + reg_req => { in => [ "gp", "gp", "none", "gp", "esp" ], out => [ "esp", "none" ] }, + ins => [ "base", "index", "mem", "val", "stack" ], + emit => '. push%M %unop3', + outs => [ "stack:I|S", "M" ], + am => "source,binary", + latency => 2, + units => [ "GP" ], +}, + +Pop => { + reg_req => { in => [ "gp", "gp", "none", "esp" ], out => [ "esp", "gp", "none" ] }, + emit => '. pop%M %DAM1', + outs => [ "stack:I|S", "res", "M" ], + ins => [ "base", "index", "mem", "stack" ], + am => "dest,unary", + latency => 3, # Pop is more expensive than Push on Athlon + units => [ "GP" ], +}, + +Enter => { + reg_req => { in => [ "esp" ], out => [ "ebp", "esp", "none" ] }, + emit => '. enter', + outs => [ "frame:I", "stack:I|S", "M" ], + latency => 15, + units => [ "GP" ], +}, + +Leave => { + reg_req => { in => [ "esp", "ebp" ], out => [ "ebp", "esp" ] }, + emit => '. leave', + outs => [ "frame:I", "stack:I|S" ], + latency => 3, + units => [ "GP" ], +}, + +AddSP => { + irn_flags => "I", + state => "pinned", + reg_req => { in => [ "gp", "gp", "none", "esp", "gp" ], out => [ "in_r4", "none" ] }, + ins => [ "base", "index", "mem", "stack", "size" ], + am => "source,binary", + emit => '. addl %binop', + outs => [ "stack:S", "M" ], + units => [ "GP" ], + modified_flags => $status_flags +}, + +SubSP => { +#irn_flags => "I", + state => "pinned", + reg_req => { in => [ "gp", "gp", "none", "esp", "gp" ], out => [ "in_r4", "gp", "none" ] }, + ins => [ "base", "index", "mem", "stack", "size" ], + am => "source,binary", + emit => ". subl %binop\n". + ". movl %%esp, %D1", + outs => [ "stack:I|S", "addr", "M" ], + units => [ "GP" ], + modified_flags => $status_flags +}, + +LdTls => { + irn_flags => "R", + reg_req => { out => [ "gp" ] }, + units => [ "GP" ], +}, + +# the int instruction +int => { + reg_req => { in => [ "gp" ], out => [ "none" ] }, + mode => "mode_M", + emit => '. int %SI0', + units => [ "GP" ], + cmp_attr => "return 1;", }, - #-----------------------------------------------------------------------------# # _____ _____ ______ __ _ _ _ # # / ____/ ____| ____| / _| | | | | | # @@ -857,327 +1321,271 @@ else { # |_____/_____/|______| |_| |_|\___/ \__,_|\__| |_| |_|\___/ \__,_|\___||___/ # #-----------------------------------------------------------------------------# -# commutative operations - -"xAdd" => { - "irn_flags" => "R", - "comment" => "construct SSE Add: Add(a, b) = Add(b, a) = a + b", - "reg_req" => { "in" => [ "gp", "gp", "xmm", "xmm", "none" ], "out" => [ "in_r3" ] }, - "emit" => '. adds%M %ia32_emit_binop /* SSE Add(%A3, %A4) -> %D1 */', - "latency" => 4, - "units" => [ "SSE" ], -}, - -"xMul" => { - "irn_flags" => "R", - "comment" => "construct SSE Mul: Mul(a, b) = Mul(b, a) = a * b", - "reg_req" => { "in" => [ "gp", "gp", "xmm", "xmm", "none" ], "out" => [ "in_r3" ] }, - "emit" => '. muls%M %ia32_emit_binop /* SSE Mul(%A3, %A4) -> %D1 */', - "latency" => 4, - "units" => [ "SSE" ], -}, - -"xMax" => { - "irn_flags" => "R", - "comment" => "construct SSE Max: Max(a, b) = Max(b, a) = a > b ? a : b", - "reg_req" => { "in" => [ "gp", "gp", "xmm", "xmm", "none" ], "out" => [ "in_r3" ] }, - "emit" => '. maxs%M %ia32_emit_binop /* SSE Max(%A3, %A4) -> %D1 */', - "latency" => 2, - "units" => [ "SSE" ], -}, - -"xMin" => { - "irn_flags" => "R", - "comment" => "construct SSE Min: Min(a, b) = Min(b, a) = a < b ? a : b", - "reg_req" => { "in" => [ "gp", "gp", "xmm", "xmm", "none" ], "out" => [ "in_r3" ] }, - "emit" => '. mins%M %ia32_emit_binop /* SSE Min(%A3, %A4) -> %D1 */', - "latency" => 2, - "units" => [ "SSE" ], -}, - -"xAnd" => { - "irn_flags" => "R", - "comment" => "construct SSE And: And(a, b) = a AND b", - "reg_req" => { "in" => [ "gp", "gp", "xmm", "xmm", "none" ], "out" => [ "in_r3" ] }, - "emit" => '. andp%M %ia32_emit_binop /* SSE And(%A3, %A4) -> %D1 */', - "latency" => 3, - "units" => [ "SSE" ], +xZero => { + irn_flags => "R", + reg_req => { out => [ "xmm" ] }, + emit => '. xorp%XSD %D1, %D1', + latency => 3, + units => [ "SSE" ], + mode => "mode_E", }, -"xOr" => { - "irn_flags" => "R", - "comment" => "construct SSE Or: Or(a, b) = a OR b", - "reg_req" => { "in" => [ "gp", "gp", "xmm", "xmm", "none" ], "out" => [ "in_r3" ] }, - "emit" => '. orp%M %ia32_emit_binop /* SSE Or(%A3, %A4) -> %D1 */', - "units" => [ "SSE" ], -}, +# commutative operations -"xEor" => { - "irn_flags" => "R", - "comment" => "construct SSE Eor: Eor(a, b) = a XOR b", - "reg_req" => { "in" => [ "gp", "gp", "xmm", "xmm", "none" ], "out" => [ "in_r3" ] }, - "emit" => '. xorp%M %ia32_emit_binop /* SSE Xor(%A3, %A4) -> %D1 */', - "latency" => 3, - "units" => [ "SSE" ], +xAdd => { + irn_flags => "R", + reg_req => { in => [ "gp", "gp", "none", "xmm", "xmm" ], out => [ "in_r4 in_r5" ] }, + ins => [ "base", "index", "mem", "left", "right" ], + emit => '. add%XXM %binop', + latency => 4, + units => [ "SSE" ], + mode => "mode_E", +}, + +xMul => { + irn_flags => "R", + reg_req => { in => [ "gp", "gp", "none", "xmm", "xmm" ], out => [ "in_r4 in_r5" ] }, + ins => [ "base", "index", "mem", "left", "right" ], + emit => '. mul%XXM %binop', + latency => 4, + units => [ "SSE" ], + mode => "mode_E", +}, + +xMax => { + irn_flags => "R", + reg_req => { in => [ "gp", "gp", "none", "xmm", "xmm" ], out => [ "in_r4 in_r5" ] }, + ins => [ "base", "index", "mem", "left", "right" ], + emit => '. max%XXM %binop', + latency => 2, + units => [ "SSE" ], + mode => "mode_E", +}, + +xMin => { + irn_flags => "R", + reg_req => { in => [ "gp", "gp", "none", "xmm", "xmm" ], out => [ "in_r4 in_r5" ] }, + ins => [ "base", "index", "mem", "left", "right" ], + emit => '. min%XXM %binop', + latency => 2, + units => [ "SSE" ], + mode => "mode_E", +}, + +xAnd => { + irn_flags => "R", + reg_req => { in => [ "gp", "gp", "none", "xmm", "xmm" ], out => [ "in_r4 in_r5" ] }, + ins => [ "base", "index", "mem", "left", "right" ], + emit => '. andp%XSD %binop', + latency => 3, + units => [ "SSE" ], + mode => "mode_E", +}, + +xOr => { + irn_flags => "R", + reg_req => { in => [ "gp", "gp", "none", "xmm", "xmm" ], out => [ "in_r4 in_r5" ] }, + ins => [ "base", "index", "mem", "left", "right" ], + emit => '. orp%XSD %binop', + units => [ "SSE" ], + mode => "mode_E", +}, + +xXor => { + irn_flags => "R", + reg_req => { in => [ "gp", "gp", "none", "xmm", "xmm" ], out => [ "in_r4 in_r5" ] }, + ins => [ "base", "index", "mem", "left", "right" ], + emit => '. xorp%XSD %binop', + latency => 3, + units => [ "SSE" ], + mode => "mode_E", }, # not commutative operations -"xAndNot" => { - "irn_flags" => "R", - "comment" => "construct SSE AndNot: AndNot(a, b) = a AND NOT b", - "reg_req" => { "in" => [ "gp", "gp", "xmm", "xmm", "none" ], "out" => [ "in_r3 !in_r4" ] }, - "emit" => '. andnp%M %ia32_emit_binop /* SSE AndNot(%A3, %A4) -> %D1 */', - "latency" => 3, - "units" => [ "SSE" ], +xAndNot => { + irn_flags => "R", + reg_req => { in => [ "gp", "gp", "none", "xmm", "xmm" ], out => [ "in_r4 !in_r5" ] }, + ins => [ "base", "index", "mem", "left", "right" ], + emit => '. andnp%XSD %binop', + latency => 3, + units => [ "SSE" ], + mode => "mode_E", }, -"xSub" => { - "irn_flags" => "R", - "comment" => "construct SSE Sub: Sub(a, b) = a - b", - "reg_req" => { "in" => [ "gp", "gp", "xmm", "xmm", "none" ], "out" => [ "in_r3" ] }, - "emit" => '. subs%M %ia32_emit_binop /* SSE Sub(%A1, %A2) -> %D1 */', - "latency" => 4, - "units" => [ "SSE" ], +xSub => { + irn_flags => "R", + reg_req => { in => [ "gp", "gp", "none", "xmm", "xmm" ], out => [ "in_r4" ] }, + ins => [ "base", "index", "mem", "left", "right" ], + emit => '. sub%XXM %binop', + latency => 4, + units => [ "SSE" ], + mode => "mode_E", }, -"xDiv" => { - "irn_flags" => "R", - "comment" => "construct SSE Div: Div(a, b) = a / b", - "reg_req" => { "in" => [ "gp", "gp", "xmm", "xmm", "none" ], "out" => [ "in_r3 !in_r4" ] }, - "outs" => [ "res", "M" ], - "emit" => '. divs%M %ia32_emit_binop /* SSE Div(%A1, %A2) -> %D1 */', - "latency" => 16, - "units" => [ "SSE" ], +xDiv => { + irn_flags => "R", + reg_req => { in => [ "gp", "gp", "none", "xmm", "xmm" ], out => [ "in_r4 !in_r5", "none" ] }, + ins => [ "base", "index", "mem", "left", "right" ], + outs => [ "res", "M" ], + emit => '. div%XXM %binop', + latency => 16, + units => [ "SSE" ], }, # other operations -"xCmp" => { - "irn_flags" => "R", - "comment" => "construct SSE Compare: Cmp(a, b) == a = a cmp b", - "reg_req" => { "in" => [ "gp", "gp", "xmm", "xmm", "none" ], "out" => [ "in_r3 !in_r4" ] }, - "latency" => 3, - "units" => [ "SSE" ], -}, - -"xCondJmp" => { - "op_flags" => "L|X|Y", - "comment" => "construct conditional jump: UCOMIS A, B && JMPxx LABEL", - "reg_req" => { "in" => [ "gp", "gp", "xmm", "xmm", "none" ], "out" => [ "none", "none" ] }, - "outs" => [ "false", "true" ], - "latency" => 5, - "units" => [ "SSE" ], -}, - -"xConst" => { - "op_flags" => "c", - "irn_flags" => "R", - "comment" => "represents a SSE constant", - "reg_req" => { "out" => [ "xmm" ] }, - "emit" => '. movs%M %D1, %C /* Load fConst into register */', - "latency" => 2, - "units" => [ "SSE" ], +Ucomi => { + irn_flags => "R", + reg_req => { in => [ "gp", "gp", "none", "xmm", "xmm" ], out => [ "eflags" ] }, + ins => [ "base", "index", "mem", "left", "right" ], + outs => [ "flags" ], + am => "source,binary", + attr => "int flipped", + init_attr => "attr->data.cmp_flipped = flipped;", + emit => ' .ucomi%XXM %binop_nores', + latency => 3, + units => [ "SSE" ], + mode => $mode_flags, + modified_flags => 1, }, # Load / Store -"xLoad" => { - "op_flags" => "L|F", - "state" => "exc_pinned", - "comment" => "construct SSE Load: Load(ptr, mem) = LD ptr", - "reg_req" => { "in" => [ "gp", "gp", "none" ], "out" => [ "xmm" ] }, - "emit" => '. movs%M %D1, %ia32_emit_am /* Load((%A1)) -> %D1 */', - "outs" => [ "res", "M" ], - "latency" => 2, - "units" => [ "SSE" ], -}, - -"xStore" => { - "op_flags" => "L|F", - "state" => "exc_pinned", - "comment" => "construct Store: Store(ptr, val, mem) = ST ptr,val", - "reg_req" => { "in" => [ "gp", "gp", "xmm", "none" ] }, - "emit" => '. movs%M %ia32_emit_binop /* Store(%S3) -> (%A1) */', - "latency" => 2, - "units" => [ "MEM" ], - "mode" => "mode_M", -}, - -"xStoreSimple" => { - "op_flags" => "L|F", - "state" => "exc_pinned", - "comment" => "construct Store without index: Store(ptr, val, mem) = ST ptr,val", - "reg_req" => { "in" => [ "gp", "xmm", "none" ] }, - "emit" => '. movs%M %ia32_emit_am, %S2 /* store XMM0 onto stack */', - "latency" => 2, - "units" => [ "MEM" ], - "mode" => "mode_M", -}, - -"l_X87toSSE" => { - "op_flags" => "L|F", - "comment" => "construct: transfer a value from x87 FPU into a SSE register", - "cmp_attr" => "return 1;", - "arity" => 3, -}, - -"l_SSEtoX87" => { - "op_flags" => "L|F", - "comment" => "construct: transfer a value from SSE register to x87 FPU", - "cmp_attr" => "return 1;", - "arity" => 3, -}, - -"GetST0" => { - "op_flags" => "L|F", - "irn_flags" => "I", - "state" => "exc_pinned", - "comment" => "store ST0 onto stack", - "reg_req" => { "in" => [ "gp", "gp", "none" ] }, - "emit" => '. fstp %ia32_emit_am /* store ST0 onto stack */', - "latency" => 4, - "units" => [ "MEM" ], - "mode" => "mode_M", -}, - -"SetST0" => { - "op_flags" => "L|F", - "irn_flags" => "I", - "state" => "exc_pinned", - "comment" => "load ST0 from stack", - "reg_req" => { "in" => [ "gp", "none" ], "out" => [ "vf0", "none" ] }, - "emit" => '. fld %ia32_emit_am /* load ST0 from stack */', - "outs" => [ "res", "M" ], - "latency" => 2, - "units" => [ "MEM" ], +xLoad => { + op_flags => "L|F", + state => "exc_pinned", + reg_req => { in => [ "gp", "gp", "none" ], out => [ "xmm", "none" ] }, + ins => [ "base", "index", "mem" ], + emit => '. mov%XXM %AM, %D0', + attr => "ir_mode *load_mode", + init_attr => "attr->ls_mode = load_mode;", + outs => [ "res", "M" ], + latency => 0, + units => [ "SSE" ], +}, + +xStore => { + op_flags => "L|F", + state => "exc_pinned", + reg_req => { in => [ "gp", "gp", "none", "xmm" ] }, + ins => [ "base", "index", "mem", "val" ], + emit => '. mov%XXM %S3, %AM', + latency => 0, + units => [ "SSE" ], + mode => "mode_M", +}, + +xStoreSimple => { + op_flags => "L|F", + state => "exc_pinned", + reg_req => { in => [ "gp", "gp", "none", "xmm" ] }, + ins => [ "base", "index", "mem", "val" ], + emit => '. mov%XXM %S3, %AM', + latency => 0, + units => [ "SSE" ], + mode => "mode_M", +}, + +CvtSI2SS => { + op_flags => "L|F", + reg_req => { in => [ "gp", "gp", "none", "gp" ], out => [ "xmm" ] }, + ins => [ "base", "index", "mem", "val" ], + emit => '. cvtsi2ss %D0, %AM', + latency => 2, + units => [ "SSE" ], + mode => $mode_xmm +}, + +CvtSI2SD => { + op_flags => "L|F", + reg_req => { in => [ "gp", "gp", "none", "gp" ], out => [ "xmm" ] }, + ins => [ "base", "index", "mem", "val" ], + emit => '. cvtsi2sd %unop3', + latency => 2, + units => [ "SSE" ], + mode => $mode_xmm +}, + + +l_X87toSSE => { + op_flags => "L|F", + cmp_attr => "return 1;", + arity => 3, +}, + +l_SSEtoX87 => { + op_flags => "L|F", + cmp_attr => "return 1;", + arity => 3, }, # CopyB -"CopyB" => { - "op_flags" => "F|H", - "state" => "pinned", - "comment" => "implements a memcopy: CopyB(dst, src, size, mem) == memcpy(dst, src, size)", - "reg_req" => { "in" => [ "edi", "esi", "ecx", "none" ], "out" => [ "edi", "esi", "ecx", "none" ] }, - "outs" => [ "DST", "SRC", "CNT", "M" ], - "units" => [ "MEM" ], +CopyB => { + op_flags => "F|H", + state => "pinned", + reg_req => { in => [ "edi", "esi", "ecx", "none" ], out => [ "edi", "esi", "ecx", "none" ] }, + outs => [ "DST", "SRC", "CNT", "M" ], + units => [ "GP" ], +# we don't care about this flag, so no need to mark this node +# modified_flags => [ "DF" ] }, -"CopyB_i" => { - "op_flags" => "F|H", - "state" => "pinned", - "comment" => "implements a memcopy: CopyB(dst, src, mem) == memcpy(dst, src, attr(size))", - "reg_req" => { "in" => [ "edi", "esi", "none" ], "out" => [ "edi", "esi", "none" ] }, - "outs" => [ "DST", "SRC", "M" ], - "units" => [ "MEM" ], +CopyB_i => { + op_flags => "F|H", + state => "pinned", + reg_req => { in => [ "edi", "esi", "none" ], out => [ "edi", "esi", "none" ] }, + outs => [ "DST", "SRC", "M" ], + units => [ "GP" ], +# we don't care about this flag, so no need to mark this node +# modified_flags => [ "DF" ] }, # Conversions -"Conv_I2I" => { - "reg_req" => { "in" => [ "gp", "gp", "gp", "none" ], "out" => [ "in_r3", "none" ] }, - "comment" => "construct Conv Int -> Int", - "units" => [ "ALU" ], -}, - -"Conv_I2I8Bit" => { - "reg_req" => { "in" => [ "gp", "gp", "eax ebx ecx edx", "none" ], "out" => [ "in_r3", "none" ] }, - "comment" => "construct Conv Int -> Int", - "units" => [ "ALU" ], -}, - -"Conv_I2FP" => { - "reg_req" => { "in" => [ "gp", "gp", "gp", "none" ], "out" => [ "xmm", "none" ] }, - "comment" => "construct Conv Int -> Floating Point", - "latency" => 10, - "units" => [ "SSE" ], -}, - -"Conv_FP2I" => { - "reg_req" => { "in" => [ "gp", "gp", "xmm", "none" ], "out" => [ "gp", "none" ] }, - "comment" => "construct Conv Floating Point -> Int", - "latency" => 10, - "units" => [ "SSE" ], -}, - -"Conv_FP2FP" => { - "reg_req" => { "in" => [ "gp", "gp", "xmm", "none" ], "out" => [ "xmm", "none" ] }, - "comment" => "construct Conv Floating Point -> Floating Point", - "latency" => 8, - "units" => [ "SSE" ], -}, - -"CmpCMov" => { - "irn_flags" => "R", - "comment" => "construct Conditional Move: CMov(sel, a, b) == sel ? a : b", - "reg_req" => { "in" => [ "gp", "gp", "gp", "gp" ], "out" => [ "in_r4" ] }, - "latency" => 2, - "units" => [ "ALU" ], -}, - -"PsiCondCMov" => { - "irn_flags" => "R", - "comment" => "check if Psi condition tree evaluates to true and move result accordingly", - "reg_req" => { "in" => [ "gp", "gp", "gp" ], "out" => [ "in_r3" ] }, - "latency" => 2, - "units" => [ "ALU" ], -}, - -"xCmpCMov" => { - "irn_flags" => "R", - "comment" => "construct Conditional Move: SSE Compare + int CMov ", - "reg_req" => { "in" => [ "xmm", "xmm", "gp", "gp" ], "out" => [ "in_r4" ] }, - "latency" => 5, - "units" => [ "SSE" ], -}, - -"vfCmpCMov" => { - "irn_flags" => "R", - "comment" => "construct Conditional Move: x87 Compare + int CMov", - "reg_req" => { "in" => [ "vfp", "vfp", "gp", "gp" ], "out" => [ "in_r4" ] }, - "latency" => 10, - "units" => [ "FPU" ], +Conv_I2I => { + state => "exc_pinned", + reg_req => { in => [ "gp", "gp", "none", "gp" ], out => [ "gp", "none" ] }, + ins => [ "base", "index", "mem", "val" ], + units => [ "GP" ], + attr => "ir_mode *smaller_mode", + init_attr => "attr->ls_mode = smaller_mode;", + mode => $mode_gp, }, -"CmpSet" => { - "irn_flags" => "R", - "comment" => "construct Set: Set(sel) == sel ? 1 : 0", - "reg_req" => { "in" => [ "gp", "gp", "gp", "gp", "none" ], "out" => [ "eax ebx ecx edx", "none" ] }, - "latency" => 2, - "units" => [ "ALU" ], +Conv_I2I8Bit => { + state => "exc_pinned", + reg_req => { in => [ "gp", "gp", "none", "eax ebx ecx edx" ], out => [ "gp", "none" ] }, + ins => [ "base", "index", "mem", "val" ], + units => [ "GP" ], + attr => "ir_mode *smaller_mode", + init_attr => "attr->ls_mode = smaller_mode;", + mode => $mode_gp, }, -"PsiCondSet" => { - "irn_flags" => "R", - "comment" => "check if Psi condition tree evaluates to true and set result accordingly", - "reg_req" => { "in" => [ "gp" ], "out" => [ "eax ebx ecx edx" ] }, - "latency" => 2, - "units" => [ "ALU" ], +Conv_I2FP => { + reg_req => { in => [ "gp", "gp", "none", "gp" ], out => [ "xmm", "none" ] }, + ins => [ "base", "index", "mem", "val" ], + latency => 10, + units => [ "SSE" ], + mode => "mode_E", }, -"xCmpSet" => { - "irn_flags" => "R", - "comment" => "construct Set: SSE Compare + int Set", - "reg_req" => { "in" => [ "gp", "gp", "xmm", "xmm", "none" ], "out" => [ "eax ebx ecx edx", "none" ] }, - "latency" => 5, - "units" => [ "SSE" ], +Conv_FP2I => { + reg_req => { in => [ "gp", "gp", "none", "xmm" ], out => [ "gp", "none" ] }, + ins => [ "base", "index", "mem", "val" ], + latency => 10, + units => [ "SSE" ], + mode => $mode_gp, }, -"vfCmpSet" => { - "irn_flags" => "R", - "comment" => "construct Set: x87 Compare + int Set", - "reg_req" => { "in" => [ "gp", "gp", "vfp", "vfp", "none" ], "out" => [ "eax ebx ecx edx", "none" ] }, - "latency" => 10, - "units" => [ "FPU" ], -}, - -"vfCMov" => { - "irn_flags" => "R", - "comment" => "construct x87 Conditional Move: vfCMov(sel, a, b) = sel ? a : b", - "reg_req" => { "in" => [ "vfp", "vfp", "vfp", "vfp" ], "out" => [ "vfp" ] }, - "latency" => 10, - "units" => [ "FPU" ], +Conv_FP2FP => { + reg_req => { in => [ "gp", "gp", "none", "xmm" ], out => [ "xmm", "none" ] }, + ins => [ "base", "index", "mem", "val" ], + latency => 8, + units => [ "SSE" ], + mode => "mode_E", }, #----------------------------------------------------------# @@ -1194,242 +1602,251 @@ else { # |_| |_|\___/ \__,_|\___||___/ # #----------------------------------------------------------# -"vfadd" => { - "irn_flags" => "R", - "comment" => "virtual fp Add: Add(a, b) = Add(b, a) = a + b", - "reg_req" => { "in" => [ "gp", "gp", "vfp", "vfp", "none" ], "out" => [ "vfp" ] }, - "latency" => 4, - "units" => [ "FPU" ], -}, - -"vfmul" => { - "irn_flags" => "R", - "comment" => "virtual fp Mul: Mul(a, b) = Mul(b, a) = a * b", - "reg_req" => { "in" => [ "gp", "gp", "vfp", "vfp", "none" ], "out" => [ "vfp" ] }, - "latency" => 4, - "units" => [ "FPU" ], +vfadd => { + irn_flags => "R", + reg_req => { in => [ "gp", "gp", "none", "vfp", "vfp", "fpcw" ], out => [ "vfp" ] }, + ins => [ "base", "index", "mem", "left", "right", "fpcw" ], + latency => 4, + units => [ "VFP" ], + mode => "mode_E", + attr_type => "ia32_x87_attr_t", }, -"l_vfmul" => { - "op_flags" => "C", - "cmp_attr" => "return 1;", - "comment" => "lowered virtual fp Mul: Mul(a, b) = Mul(b, a) = a * b", - "arity" => 2, +vfmul => { + irn_flags => "R", + reg_req => { in => [ "gp", "gp", "none", "vfp", "vfp", "fpcw" ], out => [ "vfp" ] }, + ins => [ "base", "index", "mem", "left", "right", "fpcw" ], + latency => 4, + units => [ "VFP" ], + mode => "mode_E", + attr_type => "ia32_x87_attr_t", }, -"vfsub" => { - "irn_flags" => "R", - "comment" => "virtual fp Sub: Sub(a, b) = a - b", - "reg_req" => { "in" => [ "gp", "gp", "vfp", "vfp", "none" ], "out" => [ "vfp" ] }, - "latency" => 4, - "units" => [ "FPU" ], +l_vfmul => { + op_flags => "C", + cmp_attr => "return 1;", + arity => 2, }, -"l_vfsub" => { - "cmp_attr" => "return 1;", - "comment" => "lowered virtual fp Sub: Sub(a, b) = a - b", - "arity" => 2, +vfsub => { + irn_flags => "R", + reg_req => { in => [ "gp", "gp", "none", "vfp", "vfp", "fpcw" ], out => [ "vfp" ] }, + ins => [ "base", "index", "mem", "left", "right", "fpcw" ], + latency => 4, + units => [ "VFP" ], + mode => "mode_E", + attr_type => "ia32_x87_attr_t", }, -"vfdiv" => { - "comment" => "virtual fp Div: Div(a, b) = a / b", - "reg_req" => { "in" => [ "gp", "gp", "vfp", "vfp", "none" ], "out" => [ "vfp" ] }, - "outs" => [ "res", "M" ], - "latency" => 20, - "units" => [ "FPU" ], +l_vfsub => { + cmp_attr => "return 1;", + arity => 2, }, -"l_vfdiv" => { - "cmp_attr" => "return 1;", - "comment" => "lowered virtual fp Div: Div(a, b) = a / b", - "arity" => 2, +vfdiv => { + reg_req => { in => [ "gp", "gp", "none", "vfp", "vfp", "fpcw" ], out => [ "vfp", "none" ] }, + ins => [ "base", "index", "mem", "left", "right", "fpcw" ], + outs => [ "res", "M" ], + latency => 20, + units => [ "VFP" ], + attr_type => "ia32_x87_attr_t", }, -"vfprem" => { - "comment" => "virtual fp Rem: Rem(a, b) = a - Q * b (Q is integer)", - "reg_req" => { "in" => [ "gp", "gp", "vfp", "vfp", "none" ], "out" => [ "vfp" ] }, - "latency" => 20, - "units" => [ "FPU" ], +l_vfdiv => { + cmp_attr => "return 1;", + outs => [ "res", "M" ], + arity => 2, }, -"l_vfprem" => { - "cmp_attr" => "return 1;", - "comment" => "lowered virtual fp Rem: Rem(a, b) = a - Q * b (Q is integer)", - "arity" => 2, +vfprem => { + reg_req => { in => [ "gp", "gp", "none", "vfp", "vfp", "fpcw" ], out => [ "vfp" ] }, + ins => [ "base", "index", "mem", "left", "right", "fpcw" ], + latency => 20, + units => [ "VFP" ], + mode => "mode_E", + attr_type => "ia32_x87_attr_t", }, -"vfabs" => { - "irn_flags" => "R", - "comment" => "virtual fp Abs: Abs(a) = |a|", - "reg_req" => { "in" => [ "vfp"], "out" => [ "vfp" ] }, - "latency" => 2, - "units" => [ "FPU" ], +l_vfprem => { + cmp_attr => "return 1;", + arity => 2, }, -"vfchs" => { - "irn_flags" => "R", - "comment" => "virtual fp Chs: Chs(a) = -a", - "reg_req" => { "in" => [ "vfp"], "out" => [ "vfp" ] }, - "latency" => 2, - "units" => [ "FPU" ], +vfabs => { + irn_flags => "R", + reg_req => { in => [ "vfp"], out => [ "vfp" ] }, + ins => [ "value" ], + latency => 2, + units => [ "VFP" ], + mode => "mode_E", + attr_type => "ia32_x87_attr_t", }, -"vfsin" => { - "irn_flags" => "R", - "comment" => "virtual fp Sin: Sin(a) = sin(a)", - "reg_req" => { "in" => [ "vfp"], "out" => [ "vfp" ] }, - "latency" => 150, - "units" => [ "FPU" ], -}, - -"vfcos" => { - "irn_flags" => "R", - "comment" => "virtual fp Cos: Cos(a) = cos(a)", - "reg_req" => { "in" => [ "vfp"], "out" => [ "vfp" ] }, - "latency" => 150, - "units" => [ "FPU" ], -}, - -"vfsqrt" => { - "irn_flags" => "R", - "comment" => "virtual fp Sqrt: Sqrt(a) = a ^ 0.5", - "reg_req" => { "in" => [ "vfp"], "out" => [ "vfp" ] }, - "latency" => 30, - "units" => [ "FPU" ], +vfchs => { + irn_flags => "R", + reg_req => { in => [ "vfp"], out => [ "vfp" ] }, + ins => [ "value" ], + latency => 2, + units => [ "VFP" ], + mode => "mode_E", + attr_type => "ia32_x87_attr_t", }, # virtual Load and Store -"vfld" => { - "op_flags" => "L|F", - "state" => "exc_pinned", - "comment" => "virtual fp Load: Load(ptr, mem) = LD ptr -> reg", - "reg_req" => { "in" => [ "gp", "gp", "none" ], "out" => [ "vfp", "none" ] }, - "outs" => [ "res", "M" ], - "latency" => 2, - "units" => [ "FPU" ], -}, - -"vfst" => { - "op_flags" => "L|F", - "state" => "exc_pinned", - "comment" => "virtual fp Store: Store(ptr, val, mem) = ST ptr,val", - "reg_req" => { "in" => [ "gp", "gp", "vfp", "none" ] }, - "latency" => 2, - "units" => [ "FPU" ], - "mode" => "mode_M", +vfld => { + op_flags => "L|F", + state => "exc_pinned", + reg_req => { in => [ "gp", "gp", "none" ], out => [ "vfp", "none" ] }, + ins => [ "base", "index", "mem" ], + outs => [ "res", "M" ], + attr => "ir_mode *load_mode", + init_attr => "attr->attr.ls_mode = load_mode;", + latency => 2, + units => [ "VFP" ], + attr_type => "ia32_x87_attr_t", +}, + +vfst => { + op_flags => "L|F", + state => "exc_pinned", + reg_req => { in => [ "gp", "gp", "none", "vfp" ] }, + ins => [ "base", "index", "mem", "val" ], + attr => "ir_mode *store_mode", + init_attr => "attr->attr.ls_mode = store_mode;", + latency => 2, + units => [ "VFP" ], + mode => "mode_M", + attr_type => "ia32_x87_attr_t", }, # Conversions -"vfild" => { - "comment" => "virtual fp integer Load: Load(ptr, mem) = iLD ptr -> reg", - "reg_req" => { "in" => [ "gp", "gp", "none" ], "out" => [ "vfp", "none" ] }, - "outs" => [ "res", "M" ], - "latency" => 4, - "units" => [ "FPU" ], +vfild => { + state => "exc_pinned", + reg_req => { in => [ "gp", "gp", "none" ], out => [ "vfp", "none" ] }, + outs => [ "res", "M" ], + ins => [ "base", "index", "mem" ], + latency => 4, + units => [ "VFP" ], + attr_type => "ia32_x87_attr_t", }, -"l_vfild" => { - "cmp_attr" => "return 1;", - "comment" => "lowered virtual fp integer Load: Load(ptr, mem) = iLD ptr -> reg", - "outs" => [ "res", "M" ], - "arity" => 2, +l_vfild => { + cmp_attr => "return 1;", + outs => [ "res", "M" ], + arity => 2, }, -"vfist" => { - "comment" => "virtual fp integer Store: Store(ptr, val, mem) = iST ptr,val", - "reg_req" => { "in" => [ "gp", "gp", "vfp", "none" ] }, - "latency" => 4, - "units" => [ "FPU" ], - "mode" => "mode_M", +vfist => { + state => "exc_pinned", + reg_req => { in => [ "gp", "gp", "none", "vfp", "fpcw" ] }, + ins => [ "base", "index", "mem", "val", "fpcw" ], + latency => 4, + units => [ "VFP" ], + mode => "mode_M", + attr_type => "ia32_x87_attr_t", }, -"l_vfist" => { - "cmp_attr" => "return 1;", - "comment" => "lowered virtual fp integer Store: Store(ptr, val, mem) = iST ptr,val", - "arity" => 3, - "mode" => "mode_M", +l_vfist => { + cmp_attr => "return 1;", + state => "exc_pinned", + arity => 3, + mode => "mode_M", }, # constants -"vfldz" => { - "irn_flags" => "R", - "comment" => "virtual fp Load 0.0: Ld 0.0 -> reg", - "reg_req" => { "out" => [ "vfp" ] }, - "latency" => 4, - "units" => [ "FPU" ], -}, - -"vfld1" => { - "irn_flags" => "R", - "comment" => "virtual fp Load 1.0: Ld 1.0 -> reg", - "reg_req" => { "out" => [ "vfp" ] }, - "latency" => 4, - "units" => [ "FPU" ], -}, - -"vfldpi" => { - "irn_flags" => "R", - "comment" => "virtual fp Load pi: Ld pi -> reg", - "reg_req" => { "out" => [ "vfp" ] }, - "latency" => 4, - "units" => [ "FPU" ], -}, - -"vfldln2" => { - "irn_flags" => "R", - "comment" => "virtual fp Load ln 2: Ld ln 2 -> reg", - "reg_req" => { "out" => [ "vfp" ] }, - "latency" => 4, - "units" => [ "FPU" ], -}, - -"vfldlg2" => { - "irn_flags" => "R", - "comment" => "virtual fp Load lg 2: Ld lg 2 -> reg", - "reg_req" => { "out" => [ "vfp" ] }, - "latency" => 4, - "units" => [ "FPU" ], -}, - -"vfldl2t" => { - "irn_flags" => "R", - "comment" => "virtual fp Load ld 10: Ld ld 10 -> reg", - "reg_req" => { "out" => [ "vfp" ] }, - "latency" => 4, - "units" => [ "FPU" ], -}, - -"vfldl2e" => { - "irn_flags" => "R", - "comment" => "virtual fp Load ld e: Ld ld e -> reg", - "reg_req" => { "out" => [ "vfp" ] }, - "latency" => 4, - "units" => [ "FPU" ], -}, - -"vfConst" => { - "op_flags" => "c", - "irn_flags" => "R", - "init_attr" => " set_ia32_ls_mode(res, mode);", - "comment" => "represents a virtual floating point constant", - "reg_req" => { "out" => [ "vfp" ] }, - "latency" => 3, - "units" => [ "FPU" ], +vfldz => { + irn_flags => "R", + reg_req => { out => [ "vfp" ] }, + latency => 4, + units => [ "VFP" ], + mode => "mode_E", + attr_type => "ia32_x87_attr_t", +}, + +vfld1 => { + irn_flags => "R", + reg_req => { out => [ "vfp" ] }, + latency => 4, + units => [ "VFP" ], + mode => "mode_E", + attr_type => "ia32_x87_attr_t", +}, + +vfldpi => { + irn_flags => "R", + reg_req => { out => [ "vfp" ] }, + latency => 4, + units => [ "VFP" ], + mode => "mode_E", + attr_type => "ia32_x87_attr_t", +}, + +vfldln2 => { + irn_flags => "R", + reg_req => { out => [ "vfp" ] }, + latency => 4, + units => [ "VFP" ], + mode => "mode_E", + attr_type => "ia32_x87_attr_t", +}, + +vfldlg2 => { + irn_flags => "R", + reg_req => { out => [ "vfp" ] }, + latency => 4, + units => [ "VFP" ], + mode => "mode_E", + attr_type => "ia32_x87_attr_t", +}, + +vfldl2t => { + irn_flags => "R", + reg_req => { out => [ "vfp" ] }, + latency => 4, + units => [ "VFP" ], + mode => "mode_E", + attr_type => "ia32_x87_attr_t", +}, + +vfldl2e => { + irn_flags => "R", + reg_req => { out => [ "vfp" ] }, + latency => 4, + units => [ "VFP" ], + mode => "mode_E", + attr_type => "ia32_x87_attr_t", }, # other -"vfCondJmp" => { - "op_flags" => "L|X|Y", - "comment" => "represents a virtual floating point compare", - "reg_req" => { "in" => [ "gp", "gp", "vfp", "vfp", "none" ], "out" => [ "none", "none", "eax" ] }, - "outs" => [ "false", "true", "temp_reg_eax" ], - "latency" => 10, - "units" => [ "FPU" ], +vFucomFnstsw => { +# we can't allow to rematerialize this node so we don't have +# accidently produce Phi(Fucom, Fucom(flipped)) +# irn_flags => "R", + reg_req => { in => [ "vfp", "vfp" ], out => [ "eax" ] }, + ins => [ "left", "right" ], + outs => [ "flags" ], + am => "source,binary", + attr => "int flipped", + init_attr => "attr->attr.data.cmp_flipped = flipped;", + latency => 3, + units => [ "VFP" ], + attr_type => "ia32_x87_attr_t", + mode => $mode_gp +}, + +Sahf => { + irn_flags => "R", + reg_req => { in => [ "eax" ], out => [ "eflags" ] }, + ins => [ "val" ], + outs => [ "flags" ], + emit => '. sahf', + units => [ "GP" ], + mode => $mode_flags, }, #------------------------------------------------------------------------# @@ -1440,360 +1857,388 @@ else { # /_/\_\___//_/ |_| |_|\___/ \__,_|\__| |_| |_|\___/ \__,_|\___||___/ # #------------------------------------------------------------------------# -"fadd" => { - "op_flags" => "R", - "rd_constructor" => "NONE", - "comment" => "x87 Add: Add(a, b) = Add(b, a) = a + b", - "reg_req" => { }, - "emit" => '. fadd %ia32_emit_x87_binop /* x87 fadd(%A3, %A4) -> %D1 */', +# Note: gas is strangely buggy: fdivrp and fdivp as well as fsubrp and fsubp +# are swapped, we work this around in the emitter... + +fadd => { + op_flags => "R", + rd_constructor => "NONE", + reg_req => { }, + emit => '. fadd%XM %x87_binop', + attr_type => "ia32_x87_attr_t", }, -"faddp" => { - "op_flags" => "R", - "rd_constructor" => "NONE", - "comment" => "x87 Add: Add(a, b) = Add(b, a) = a + b", - "reg_req" => { }, - "emit" => '. faddp %ia32_emit_x87_binop /* x87 fadd(%A3, %A4) -> %D1 */', +faddp => { + op_flags => "R", + rd_constructor => "NONE", + reg_req => { }, + emit => '. faddp%XM %x87_binop', + attr_type => "ia32_x87_attr_t", }, -"fmul" => { - "op_flags" => "R", - "rd_constructor" => "NONE", - "comment" => "x87 fp Mul: Mul(a, b) = Mul(b, a) = a + b", - "reg_req" => { }, - "emit" => '. fmul %ia32_emit_x87_binop /* x87 fmul(%A3, %A4) -> %D1 */', +fmul => { + op_flags => "R", + rd_constructor => "NONE", + reg_req => { }, + emit => '. fmul%XM %x87_binop', + attr_type => "ia32_x87_attr_t", }, -"fmulp" => { - "op_flags" => "R", - "rd_constructor" => "NONE", - "comment" => "x87 fp Mul: Mul(a, b) = Mul(b, a) = a + b", - "reg_req" => { }, - "emit" => '. fmulp %ia32_emit_x87_binop /* x87 fmul(%A3, %A4) -> %D1 */',, +fmulp => { + op_flags => "R", + rd_constructor => "NONE", + reg_req => { }, + emit => '. fmulp%XM %x87_binop',, + attr_type => "ia32_x87_attr_t", }, -"fsub" => { - "op_flags" => "R", - "rd_constructor" => "NONE", - "comment" => "x87 fp Sub: Sub(a, b) = a - b", - "reg_req" => { }, - "emit" => '. fsub %ia32_emit_x87_binop /* x87 fsub(%A3, %A4) -> %D1 */', +fsub => { + op_flags => "R", + rd_constructor => "NONE", + reg_req => { }, + emit => '. fsub%XM %x87_binop', + attr_type => "ia32_x87_attr_t", }, -"fsubp" => { - "op_flags" => "R", - "rd_constructor" => "NONE", - "comment" => "x87 fp Sub: Sub(a, b) = a - b", - "reg_req" => { }, - "emit" => '. fsubp %ia32_emit_x87_binop /* x87 fsub(%A3, %A4) -> %D1 */', +fsubp => { + op_flags => "R", + rd_constructor => "NONE", + reg_req => { }, +# see note about gas bugs + emit => '. fsubrp%XM %x87_binop', + attr_type => "ia32_x87_attr_t", }, -"fsubr" => { - "op_flags" => "R", - "rd_constructor" => "NONE", - "irn_flags" => "R", - "comment" => "x87 fp SubR: SubR(a, b) = b - a", - "reg_req" => { }, - "emit" => '. fsubr %ia32_emit_x87_binop /* x87 fsubr(%A3, %A4) -> %D1 */', +fsubr => { + op_flags => "R", + rd_constructor => "NONE", + irn_flags => "R", + reg_req => { }, + emit => '. fsubr%XM %x87_binop', + attr_type => "ia32_x87_attr_t", }, -"fsubrp" => { - "op_flags" => "R", - "rd_constructor" => "NONE", - "irn_flags" => "R", - "comment" => "x87 fp SubR: SubR(a, b) = b - a", - "reg_req" => { }, - "emit" => '. fsubrp %ia32_emit_x87_binop /* x87 fsubr(%A3, %A4) -> %D1 */', +fsubrp => { + op_flags => "R", + rd_constructor => "NONE", + irn_flags => "R", + reg_req => { }, +# see note about gas bugs + emit => '. fsubp%XM %x87_binop', + attr_type => "ia32_x87_attr_t", }, -"fprem" => { - "op_flags" => "R", - "rd_constructor" => "NONE", - "comment" => "x87 fp Rem: Rem(a, b) = a - Q * b (Q is integer)", - "reg_req" => { }, - "emit" => '. fprem1 /* x87 fprem(%A3, %A4) -> %D1 */', +fprem => { + op_flags => "R", + rd_constructor => "NONE", + reg_req => { }, + emit => '. fprem1', + attr_type => "ia32_x87_attr_t", }, # this node is just here, to keep the simulator running # we can omit this when a fprem simulation function exists -"fpremp" => { - "op_flags" => "R", - "rd_constructor" => "NONE", - "comment" => "x87 fp Rem: Rem(a, b) = a - Q * b (Q is integer)", - "reg_req" => { }, - "emit" => '. fprem1 /* x87 fprem(%A3, %A4) -> %D1 WITH POP */', -}, - -"fdiv" => { - "op_flags" => "R", - "rd_constructor" => "NONE", - "comment" => "x87 fp Div: Div(a, b) = a / b", - "reg_req" => { }, - "emit" => '. fdiv %ia32_emit_x87_binop /* x87 fdiv(%A3, %A4) -> %D1 */', -}, - -"fdivp" => { - "op_flags" => "R", - "rd_constructor" => "NONE", - "comment" => "x87 fp Div: Div(a, b) = a / b", - "reg_req" => { }, - "emit" => '. fdivp %ia32_emit_x87_binop /* x87 fdiv(%A3, %A4) -> %D1 */', +fpremp => { + op_flags => "R", + rd_constructor => "NONE", + reg_req => { }, + emit => '. fprem1', + attr_type => "ia32_x87_attr_t", }, -"fdivr" => { - "op_flags" => "R", - "rd_constructor" => "NONE", - "comment" => "x87 fp DivR: DivR(a, b) = b / a", - "reg_req" => { }, - "emit" => '. fdivr %ia32_emit_x87_binop /* x87 fdivr(%A3, %A4) -> %D1 */', +fdiv => { + op_flags => "R", + rd_constructor => "NONE", + reg_req => { }, + emit => '. fdiv%XM %x87_binop', + attr_type => "ia32_x87_attr_t", }, -"fdivrp" => { - "op_flags" => "R", - "rd_constructor" => "NONE", - "comment" => "x87 fp DivR: DivR(a, b) = b / a", - "reg_req" => { }, - "emit" => '. fdivrp %ia32_emit_x87_binop /* x87 fdivr(%A3, %A4) -> %D1 */', +fdivp => { + op_flags => "R", + rd_constructor => "NONE", + reg_req => { }, +# see note about gas bugs + emit => '. fdivrp%XM %x87_binop', + attr_type => "ia32_x87_attr_t", }, -"fabs" => { - "op_flags" => "R", - "rd_constructor" => "NONE", - "comment" => "x87 fp Abs: Abs(a) = |a|", - "reg_req" => { }, - "emit" => '. fabs /* x87 fabs(%A1) -> %D1 */', +fdivr => { + op_flags => "R", + rd_constructor => "NONE", + reg_req => { }, + emit => '. fdivr%XM %x87_binop', + attr_type => "ia32_x87_attr_t", }, -"fchs" => { - "op_flags" => "R", - "rd_constructor" => "NONE", - "comment" => "x87 fp Chs: Chs(a) = -a", - "reg_req" => { }, - "emit" => '. fchs /* x87 fchs(%A1) -> %D1 */', +fdivrp => { + op_flags => "R", + rd_constructor => "NONE", + reg_req => { }, +# see note about gas bugs + emit => '. fdivp%XM %x87_binop', + attr_type => "ia32_x87_attr_t", }, -"fsin" => { - "op_flags" => "R", - "rd_constructor" => "NONE", - "comment" => "x87 fp Sin: Sin(a) = sin(a)", - "reg_req" => { }, - "emit" => '. fsin /* x87 sin(%A1) -> %D1 */', +fabs => { + op_flags => "R", + rd_constructor => "NONE", + reg_req => { }, + emit => '. fabs', + attr_type => "ia32_x87_attr_t", }, -"fcos" => { - "op_flags" => "R", - "rd_constructor" => "NONE", - "comment" => "x87 fp Cos: Cos(a) = cos(a)", - "reg_req" => { }, - "emit" => '. fcos /* x87 cos(%A1) -> %D1 */', -}, - -"fsqrt" => { - "op_flags" => "R", - "rd_constructor" => "NONE", - "comment" => "x87 fp Sqrt: Sqrt(a) = a ^ 0.5", - "reg_req" => { }, - "emit" => '. fsqrt $ /* x87 sqrt(%A1) -> %D1 */', +fchs => { + op_flags => "R|K", + rd_constructor => "NONE", + reg_req => { }, + emit => '. fchs', + attr_type => "ia32_x87_attr_t", }, # x87 Load and Store -"fld" => { - "rd_constructor" => "NONE", - "op_flags" => "R|L|F", - "state" => "exc_pinned", - "comment" => "x87 fp Load: Load(ptr, mem) = LD ptr -> reg", - "reg_req" => { }, - "emit" => '. fld %ia32_emit_am /* Load((%A1)) -> %D1 */', +fld => { + rd_constructor => "NONE", + op_flags => "R|L|F", + state => "exc_pinned", + reg_req => { }, + emit => '. fld%XM %AM', + attr_type => "ia32_x87_attr_t", }, -"fst" => { - "rd_constructor" => "NONE", - "op_flags" => "R|L|F", - "state" => "exc_pinned", - "comment" => "x87 fp Store: Store(ptr, val, mem) = ST ptr,val", - "reg_req" => { }, - "emit" => '. fst %ia32_emit_am /* Store(%A3) -> (%A1) */', - "mode" => "mode_M", +fst => { + rd_constructor => "NONE", + op_flags => "R|L|F", + state => "exc_pinned", + reg_req => { }, + emit => '. fst%XM %AM', + mode => "mode_M", + attr_type => "ia32_x87_attr_t", }, -"fstp" => { - "rd_constructor" => "NONE", - "op_flags" => "R|L|F", - "state" => "exc_pinned", - "comment" => "x87 fp Store: Store(ptr, val, mem) = ST ptr,val", - "reg_req" => { }, - "emit" => '. fstp %ia32_emit_am /* Store(%A3) -> (%A1) and pop */', - "mode" => "mode_M", +fstp => { + rd_constructor => "NONE", + op_flags => "R|L|F", + state => "exc_pinned", + reg_req => { }, + emit => '. fstp%XM %AM', + mode => "mode_M", + attr_type => "ia32_x87_attr_t", }, # Conversions -"fild" => { - "op_flags" => "R", - "rd_constructor" => "NONE", - "comment" => "x87 fp integer Load: Load(ptr, mem) = iLD ptr -> reg", - "reg_req" => { }, - "emit" => '. fild %ia32_emit_am /* integer Load((%A1)) -> %D1 */', +fild => { + op_flags => "R", + rd_constructor => "NONE", + reg_req => { }, + emit => '. fild%M %AM', + attr_type => "ia32_x87_attr_t", }, -"fist" => { - "op_flags" => "R", - "rd_constructor" => "NONE", - "comment" => "x87 fp integer Store: Store(ptr, val, mem) = iST ptr,val", - "reg_req" => { }, - "emit" => '. fist %ia32_emit_am /* integer Store(%A3) -> (%A1) */', - "mode" => "mode_M", +fist => { + op_flags => "R", + state => "exc_pinned", + rd_constructor => "NONE", + reg_req => { }, + emit => '. fist%M %AM', + mode => "mode_M", + attr_type => "ia32_x87_attr_t", }, -"fistp" => { - "op_flags" => "R", - "rd_constructor" => "NONE", - "comment" => "x87 fp integer Store: Store(ptr, val, mem) = iST ptr,val", - "reg_req" => { }, - "emit" => '. fistp %ia32_emit_am /* integer Store(%A3) -> (%A1) and pop */', - "mode" => "mode_M", +fistp => { + op_flags => "R", + state => "exc_pinned", + rd_constructor => "NONE", + reg_req => { }, + emit => '. fistp%M %AM', + mode => "mode_M", + attr_type => "ia32_x87_attr_t", }, # constants -"fldz" => { - "op_flags" => "R|c", - "irn_flags" => "R", - "comment" => "x87 fp Load 0.0: Ld 0.0 -> reg", - "reg_req" => { "out" => [ "vfp" ] }, - "emit" => '. fldz /* x87 0.0 -> %D1 */', -}, - -"fld1" => { - "op_flags" => "R|c", - "irn_flags" => "R", - "comment" => "x87 fp Load 1.0: Ld 1.0 -> reg", - "reg_req" => { "out" => [ "vfp" ] }, - "emit" => '. fld1 /* x87 1.0 -> %D1 */', +fldz => { + op_flags => "R|c|K", + irn_flags => "R", + reg_req => { }, + emit => '. fldz', + attr_type => "ia32_x87_attr_t", }, -"fldpi" => { - "op_flags" => "R|c", - "irn_flags" => "R", - "comment" => "x87 fp Load pi: Ld pi -> reg", - "reg_req" => { "out" => [ "vfp" ] }, - "emit" => '. fldpi /* x87 pi -> %D1 */', +fld1 => { + op_flags => "R|c|K", + irn_flags => "R", + reg_req => { }, + emit => '. fld1', + attr_type => "ia32_x87_attr_t", }, -"fldln2" => { - "op_flags" => "R|c", - "irn_flags" => "R", - "comment" => "x87 fp Load ln 2: Ld ln 2 -> reg", - "reg_req" => { "out" => [ "vfp" ] }, - "emit" => '. fldln2 /* x87 ln(2) -> %D1 */', +fldpi => { + op_flags => "R|c|K", + irn_flags => "R", + reg_req => { }, + emit => '. fldpi', + attr_type => "ia32_x87_attr_t", }, -"fldlg2" => { - "op_flags" => "R|c", - "irn_flags" => "R", - "comment" => "x87 fp Load lg 2: Ld lg 2 -> reg", - "reg_req" => { "out" => [ "vfp" ] }, - "emit" => '. fldlg2 /* x87 log(2) -> %D1 */', +fldln2 => { + op_flags => "R|c|K", + irn_flags => "R", + reg_req => { }, + emit => '. fldln2', + attr_type => "ia32_x87_attr_t", }, -"fldl2t" => { - "op_flags" => "R|c", - "irn_flags" => "R", - "comment" => "x87 fp Load ld 10: Ld ld 10 -> reg", - "reg_req" => { "out" => [ "vfp" ] }, - "emit" => '. fldll2t /* x87 ld(10) -> %D1 */', +fldlg2 => { + op_flags => "R|c|K", + irn_flags => "R", + reg_req => { }, + emit => '. fldlg2', + attr_type => "ia32_x87_attr_t", }, -"fldl2e" => { - "op_flags" => "R|c", - "irn_flags" => "R", - "comment" => "x87 fp Load ld e: Ld ld e -> reg", - "reg_req" => { "out" => [ "vfp" ] }, - "emit" => '. fldl2e /* x87 ld(e) -> %D1 */', +fldl2t => { + op_flags => "R|c|K", + irn_flags => "R", + reg_req => { }, + emit => '. fldll2t', + attr_type => "ia32_x87_attr_t", }, -"fldConst" => { - "op_flags" => "R|c", - "irn_flags" => "R", - "rd_constructor" => "NONE", - "comment" => "represents a x87 constant", - "reg_req" => { "out" => [ "vfp" ] }, - "emit" => '. fld %ia32_emit_adr /* Load fConst into register -> %D1 */', +fldl2e => { + op_flags => "R|c|K", + irn_flags => "R", + reg_req => { }, + emit => '. fldl2e', + attr_type => "ia32_x87_attr_t", }, # fxch, fpush, fpop # Note that it is NEVER allowed to do CSE on these nodes # Moreover, note the virtual register requierements! -"fxch" => { - "op_flags" => "R|K", - "comment" => "x87 stack exchange", - "reg_req" => { }, - "cmp_attr" => "return 1;", - "emit" => '. fxch %X1 /* x87 swap %X1, %X3 */', +fxch => { + op_flags => "R|K", + reg_req => { }, + cmp_attr => "return 1;", + emit => '. fxch %X0', + attr_type => "ia32_x87_attr_t", }, -"fpush" => { - "op_flags" => "R|K", - "comment" => "x87 stack push", - "reg_req" => {}, - "cmp_attr" => "return 1;", - "emit" => '. fld %X1 /* x87 push %X1 */', +fpush => { + op_flags => "R|K", + reg_req => {}, + cmp_attr => "return 1;", + emit => '. fld %X0', + attr_type => "ia32_x87_attr_t", }, -"fpushCopy" => { - "op_flags" => "R", - "comment" => "x87 stack push", - "reg_req" => { "in" => [ "vfp"], "out" => [ "vfp" ] }, - "cmp_attr" => "return 1;", - "emit" => '. fld %X1 /* x87 push %X1 */', +fpushCopy => { + op_flags => "R", + reg_req => { in => [ "vfp"], out => [ "vfp" ] }, + cmp_attr => "return 1;", + emit => '. fld %X0', + attr_type => "ia32_x87_attr_t", }, -"fpop" => { - "op_flags" => "R|K", - "comment" => "x87 stack pop", - "reg_req" => { }, - "cmp_attr" => "return 1;", - "emit" => '. fstp %X1 /* x87 pop %X1 */', +fpop => { + op_flags => "K", + reg_req => { }, + cmp_attr => "return 1;", + emit => '. fstp %X0', + attr_type => "ia32_x87_attr_t", }, -# compare +ffreep => { + op_flags => "K", + reg_req => { }, + cmp_attr => "return 1;", + emit => '. ffreep %X0', + attr_type => "ia32_x87_attr_t", +}, + +emms => { + op_flags => "K", + reg_req => { }, + cmp_attr => "return 1;", + emit => '. emms', + attr_type => "ia32_x87_attr_t", +}, -"fcomJmp" => { - "op_flags" => "L|X|Y", - "comment" => "floating point compare", - "reg_req" => { }, +femms => { + op_flags => "K", + reg_req => { }, + cmp_attr => "return 1;", + emit => '. femms', + attr_type => "ia32_x87_attr_t", }, -"fcompJmp" => { - "op_flags" => "L|X|Y", - "comment" => "floating point compare and pop", - "reg_req" => { }, +# compare + +FucomFnstsw => { + op_flags => "R", + reg_req => { }, + emit => ". fucom %X1\n". + ". fnstsw", + attr_type => "ia32_x87_attr_t", }, -"fcomppJmp" => { - "op_flags" => "L|X|Y", - "comment" => "floating point compare and pop twice", - "reg_req" => { }, +FucompFnstsw => { + op_flags => "R", + reg_req => { }, + emit => ". fucomp %X1\n". + ". fnstsw", + attr_type => "ia32_x87_attr_t", }, -"fcomrJmp" => { - "op_flags" => "L|X|Y", - "comment" => "floating point compare reverse", - "reg_req" => { }, +FucomppFnstsw => { + op_flags => "R", + reg_req => { }, + emit => ". fucompp\n". + ". fnstsw", + attr_type => "ia32_x87_attr_t", }, -"fcomrpJmp" => { - "op_flags" => "L|X|Y", - "comment" => "floating point compare reverse and pop", - "reg_req" => { }, + +# -------------------------------------------------------------------------------- # +# ____ ____ _____ _ _ # +# / ___/ ___|| ____| __ _____ ___| |_ ___ _ __ _ __ ___ __| | ___ ___ # +# \___ \___ \| _| \ \ / / _ \/ __| __/ _ \| '__| | '_ \ / _ \ / _` |/ _ \/ __| # +# ___) |__) | |___ \ V / __/ (__| || (_) | | | | | | (_) | (_| | __/\__ \ # +# |____/____/|_____| \_/ \___|\___|\__\___/|_| |_| |_|\___/ \__,_|\___||___/ # +# # +# -------------------------------------------------------------------------------- # + + +# Spilling and reloading of SSE registers, hardcoded, not generated # + +xxLoad => { + op_flags => "L|F", + state => "exc_pinned", + reg_req => { in => [ "gp", "gp", "none" ], out => [ "xmm", "none" ] }, + emit => '. movdqu %D0, %AM', + outs => [ "res", "M" ], + units => [ "SSE" ], }, -"fcomrppJmp" => { - "op_flags" => "L|X|Y", - "comment" => "floating point compare reverse and pop twice", - "reg_req" => { }, +xxStore => { + op_flags => "L|F", + state => "exc_pinned", + reg_req => { in => [ "gp", "gp", "none", "xmm" ] }, + ins => [ "base", "index", "mem", "val" ], + emit => '. movdqu %binop', + units => [ "SSE" ], + mode => "mode_M", }, ); # end of %nodes + +# Include the generated SIMD node specification written by the SIMD optimization +$my_script_name = dirname($myname) . "/../ia32/ia32_simd_spec.pl"; +unless ($return = do $my_script_name) { + warn "couldn't parse $my_script_name: $@" if $@; + warn "couldn't do $my_script_name: $!" unless defined $return; + warn "couldn't run $my_script_name" unless $return; +}