X-Git-Url: http://nsz.repo.hu/git/?a=blobdiff_plain;f=ir%2Fbe%2Fia32%2Fia32_spec.pl;h=ff82198b793ebb9d26a01e771d996a2925056d62;hb=ef668aa395ab2cb4b3fb4066a8fa4c65c05aabf6;hp=2ad3189e82eb0973c38d195e6f949c48620b9bee;hpb=88ec54f142c4dad80782e865fccb279ed9e30b3e;p=libfirm diff --git a/ir/be/ia32/ia32_spec.pl b/ir/be/ia32/ia32_spec.pl index 2ad3189e8..ff82198b7 100644 --- a/ir/be/ia32/ia32_spec.pl +++ b/ir/be/ia32/ia32_spec.pl @@ -17,7 +17,7 @@ $arch = "ia32"; # # => { # op_flags => "N|L|C|X|I|F|Y|H|c|K", -# irn_flags => "R|N|I|S" +# irn_flags => "R|N" # arity => "0|1|2|3 ... |variable|dynamic|any", # state => "floats|pinned|mem_pinned|exc_pinned", # args => [ @@ -28,12 +28,17 @@ $arch = "ia32"; # 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", +# outs => { "out1", "out2" } # optional, creates pn_op_out1, ... consts +# ins => { "in1", "in2" } # optional, creates n_op_in1, ... consts +# mode => "mode_Iu" # optional, predefines the mode # 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" +# attr => "additional attribute arguments for constructor", +# init_attr => "emit attribute initialization template", +# rd_constructor => "c source code which constructs an ir_node", +# hash_func => "name of the hash function for this operation", # latency => "latency of this operation (can be float)" # attr_type => "name of the attribute struct", +# modified_flags => [ "CF", ... ] # optional, list of modified flags # }, # # ... # (all nodes you need to describe) @@ -52,13 +57,13 @@ $arch = "ia32"; # H irop_flag_highlevel # c irop_flag_constlike # K irop_flag_keep +# NB irop_flag_dump_noblock +# NI irop_flag_dump_noinput # # irn_flags: special node flags, OPTIONAL (default is 0) # following irn_flags are supported: # R rematerializeable # N not spillable -# I ignore for register allocation -# S modifies stack pointer # # state: state of the operation, OPTIONAL (default is "floats") # @@ -73,10 +78,7 @@ $arch = "ia32"; # # outs: if a node defines more than one output, the names of the projections # nodes having outs having automatically the mode mode_T -# One can also annotate some flags for each out, additional to irn_flags. -# They are separated from name with a colon ':', and concatenated by pipe '|' -# Only I and S are available at the moment (same meaning as in irn_flags). -# example: [ "frame:I", "stack:I|S", "M" ] +# example: [ "frame", "stack", "M" ] # # comment: OPTIONAL comment for the node constructor # @@ -96,14 +98,12 @@ $arch = "ia32"; # # NOTE: rd_constructor and args are only optional if and only if arity is 0,1,2 or 3 # -# latency: the latency of the operation, default is 1 -# # register types: # 0 - no special type # 1 - caller save (register must be saved by the caller of a function) # 2 - callee save (register must be saved by the called function) -# 4 - ignore (do not assign this register) +# 4 - ignore (do not automatically 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 @@ -147,14 +147,14 @@ $arch = "ia32"; { 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 => "vf0", type => 1 }, + { name => "vf1", type => 1 }, + { name => "vf2", type => 1 }, + { name => "vf3", type => 1 }, + { name => "vf4", type => 1 }, + { name => "vf5", type => 1 }, + { name => "vf6", type => 1 }, + { name => "vf7", type => 1 }, { 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" } @@ -197,33 +197,33 @@ $arch = "ia32"; S1 => "${arch}_emit_source_register(node, 1);", S2 => "${arch}_emit_source_register(node, 2);", S3 => "${arch}_emit_source_register(node, 3);", + SB0 => "${arch}_emit_8bit_source_register_or_immediate(node, 0);", 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);", + SH0 => "${arch}_emit_8bit_high_source_register(node, 0);", + SS0 => "${arch}_emit_16bit_source_register_or_immediate(node, 0);", 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);", + DS0 => "${arch}_emit_dest_register_size(node, 0);", DB0 => "${arch}_emit_8bit_dest_register(node, 0);", X0 => "${arch}_emit_x87_register(node, 0);", X1 => "${arch}_emit_x87_register(node, 1);", - 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);", + EX => "${arch}_emit_extend_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);", - unop3 => "${arch}_emit_unop(node, 3);", - unop4 => "${arch}_emit_unop(node, 4);", - unop5 => "${arch}_emit_unop(node, 5);", - DAM1 => "${arch}_emit_am_or_dest_register(node, 1);", + unop3 => "${arch}_emit_unop(node, n_ia32_unary_op);", + unop4 => "${arch}_emit_unop(node, n_ia32_binary_right);", binop => "${arch}_emit_binop(node);", x87_binop => "${arch}_emit_x87_binop(node);", CMP0 => "${arch}_emit_cmp_suffix_node(node, 0);", + CMP3 => "${arch}_emit_cmp_suffix_node(node, 3);", ); #--------------------------------------------------# @@ -237,83 +237,99 @@ $arch = "ia32"; # |_| # #--------------------------------------------------# -$default_attr_type = "ia32_attr_t"; -$default_copy_attr = "ia32_copy_attr"; +$default_op_attr_type = "ia32_op_attr_t"; +$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"; + $res .= "\tarch_irn_add_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);"; + if($am eq "source,unary") { + $res .= "\tset_ia32_am_support(res, 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);"; + $res .= "\tset_ia32_am_support(res, ia32_am_binary);"; } elsif($am eq "none") { # nothing to do } else { die("Invalid address mode '$am' specified on op $name"); } + if($am ne "none") { + if($node->{state} ne "exc_pinned" + and $node->{state} ne "pinned") { + die("AM nodes must have pinned or AM pinned state ($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_attributes(res, flags, in_reqs, exec_units, n_res);\n". "\tinit_ia32_x87_attributes(res);". "\tinit_ia32_asm_attributes(res);", + ia32_attr_t => + "\tinit_ia32_attributes(res, flags, in_reqs, exec_units, n_res);", + ia32_call_attr_t => + "\tinit_ia32_attributes(res, flags, in_reqs, exec_units, n_res);\n". + "\tinit_ia32_call_attributes(res, pop, call_tp);", + ia32_condcode_attr_t => + "\tinit_ia32_attributes(res, flags, in_reqs, exec_units, n_res);\n". + "\tinit_ia32_condcode_attributes(res, pnc);", + ia32_copyb_attr_t => + "\tinit_ia32_attributes(res, flags, in_reqs, exec_units, n_res);\n". + "\tinit_ia32_copyb_attributes(res, size);", 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);" + "\tinit_ia32_attributes(res, flags, in_reqs, exec_units, n_res);\n". + "\tinit_ia32_immediate_attributes(res, symconst, symconst_sign, no_pic_adjust, offset);", + ia32_x87_attr_t => + "\tinit_ia32_attributes(res, flags, in_reqs, exec_units, n_res);\n". + "\tinit_ia32_x87_attributes(res);", + ia32_climbframe_attr_t => + "\tinit_ia32_attributes(res, flags, in_reqs, exec_units, n_res);\n". + "\tinit_ia32_climbframe_attributes(res, count);", ); %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", + ia32_attr_t => "ia32_compare_nodes_attr", + ia32_call_attr_t => "ia32_compare_call_attr", + ia32_condcode_attr_t => "ia32_compare_condcode_attr", + ia32_copyb_attr_t => "ia32_compare_copyb_attr", + ia32_immediate_attr_t => "ia32_compare_immediate_attr", + ia32_x87_attr_t => "ia32_compare_x87_attr", + ia32_climbframe_attr_t => "ia32_compare_climbframe_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" ]; +$mode_xmm = "mode_E"; +$mode_gp = "mode_Iu"; +$mode_flags = "mode_Iu"; +$mode_fpcw = "mode_fpcw"; +$status_flags = [ "CF", "PF", "AF", "ZF", "SF", "OF" ]; +$status_flags_wo_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", + reg_req => { out => [ "gp_NOREG:I" ] }, + attr => "ir_entity *symconst, int symconst_sign, int no_pic_adjust, long offset", attr_type => "ia32_immediate_attr_t", + hash_func => "ia32_hash_Immediate", latency => 0, mode => $mode_gp, }, @@ -323,9 +339,14 @@ Asm => { arity => "variable", out_arity => "variable", attr_type => "ia32_asm_attr_t", - latency => 100, + attr => "ident *asm_text, const ia32_asm_reg_t *register_map", + init_attr => "attr->asm_text = asm_text;\n". + "\tattr->register_map = register_map;\n", + latency => 10, + modified_flags => $status_flags, }, +# "allocates" a free register ProduceVal => { op_flags => "c", irn_flags => "R", @@ -352,41 +373,53 @@ ProduceVal => { Add => { irn_flags => "R", - reg_req => { in => [ "gp", "gp", "none", "gp", "gp" ], out => [ "in_r4 in_r5", "none", "flags" ] }, + state => "exc_pinned", + reg_req => { in => [ "gp", "gp", "none", "gp", "gp" ], + out => [ "in_r4 in_r5", "flags", "none" ] }, ins => [ "base", "index", "mem", "left", "right" ], + outs => [ "res", "flags", "M" ], emit => '. add%M %binop', - am => "full,binary", + am => "source,binary", units => [ "GP" ], + latency => 1, mode => $mode_gp, modified_flags => $status_flags }, AddMem => { irn_flags => "R", + state => "exc_pinned", reg_req => { in => [ "gp", "gp", "none", "gp" ], out => [ "none" ] }, ins => [ "base", "index", "mem", "val" ], emit => ". add%M %SI3, %AM", units => [ "GP" ], + latency => 1, mode => "mode_M", modified_flags => $status_flags }, AddMem8Bit => { irn_flags => "R", + state => "exc_pinned", reg_req => { in => [ "gp", "gp", "none", "eax ebx ecx edx" ], out => [ "none" ] }, ins => [ "base", "index", "mem", "val" ], emit => ". add%M %SB3, %AM", units => [ "GP" ], + latency => 1, mode => "mode_M", modified_flags => $status_flags }, Adc => { - reg_req => { in => [ "gp", "gp", "none", "gp", "gp", "flags" ], out => [ "in_r4 in_r5" ] }, + state => "exc_pinned", + reg_req => { in => [ "gp", "gp", "none", "gp", "gp", "flags" ], + out => [ "in_r4 in_r5", "flags", "none" ] }, ins => [ "base", "index", "mem", "left", "right", "eflags" ], + outs => [ "res", "flags", "M" ], emit => '. adc%M %binop', - am => "full,binary", + am => "source,binary", units => [ "GP" ], + latency => 1, mode => $mode_gp, modified_flags => $status_flags }, @@ -404,11 +437,13 @@ l_Adc => { 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" ], + # very strict constraints + state => "exc_pinned", + reg_req => { in => [ "gp", "gp", "none", "eax", "gp" ], + out => [ "eax", "flags", "none", "edx" ] }, + ins => [ "base", "index", "mem", "left", "right" ], emit => '. mul%M %unop4', - outs => [ "EAX", "EDX", "M" ], + outs => [ "res_low", "flags", "M", "res_high" ], am => "source,binary", latency => 10, units => [ "GP" ], @@ -417,18 +452,24 @@ Mul => { l_Mul => { # we should not rematrialize this node. It produces 2 results and has - # very strict constrains + # very strict constraints op_flags => "C", cmp_attr => "return 1;", - outs => [ "EAX", "EDX", "M" ], - arity => 2 + reg_req => { in => [ "none", "none" ], + out => [ "none", "none", "none", "none" ] }, + ins => [ "left", "right" ], + outs => [ "res_low", "flags", "M", "res_high" ], }, IMul => { irn_flags => "R", - reg_req => { in => [ "gp", "gp", "none", "gp", "gp" ], out => [ "in_r4 in_r5" ] }, + state => "exc_pinned", + # TODO: adjust out requirements for the 3 operand form + # (no need for should_be_same then) + reg_req => { in => [ "gp", "gp", "none", "gp", "gp" ], + out => [ "in_r4 in_r5", "flags", "none" ] }, ins => [ "base", "index", "mem", "left", "right" ], - emit => '. imul%M %binop', + outs => [ "res", "flags", "M" ], am => "source,binary", latency => 5, units => [ "GP" ], @@ -438,10 +479,12 @@ IMul => { IMul1OP => { irn_flags => "R", - reg_req => { in => [ "gp", "gp", "none", "eax", "gp" ], out => [ "eax", "edx", "none" ] }, - ins => [ "base", "index", "mem", "val_high", "val_low" ], + state => "exc_pinned", + reg_req => { in => [ "gp", "gp", "none", "eax", "gp" ], + out => [ "eax", "flags", "none", "edx" ] }, + ins => [ "base", "index", "mem", "left", "right" ], emit => '. imul%M %unop4', - outs => [ "EAX", "EDX", "M" ], + outs => [ "res_low", "flags", "M", "res_high" ], am => "source,binary", latency => 5, units => [ "GP" ], @@ -449,103 +492,140 @@ IMul1OP => { }, 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 + reg_req => { in => [ "none", "none" ], + out => [ "none", "none", "none", "none" ] }, + ins => [ "left", "right" ], + outs => [ "res_low", "flags", "M", "res_high" ], }, And => { irn_flags => "R", - reg_req => { in => [ "gp", "gp", "none", "gp", "gp" ], out => [ "in_r4 in_r5" ] }, + state => "exc_pinned", + reg_req => { in => [ "gp", "gp", "none", "gp", "gp" ], + out => [ "in_r4 in_r5", "flags", "none" ] }, ins => [ "base", "index", "mem", "left", "right" ], - am => "full,binary", + outs => [ "res", "flags", "M" ], + op_modes => "commutative | am | immediate | mode_neutral", + am => "source,binary", emit => '. and%M %binop', units => [ "GP" ], + latency => 1, mode => $mode_gp, modified_flags => $status_flags }, AndMem => { irn_flags => "R", + state => "exc_pinned", reg_req => { in => [ "gp", "gp", "none", "gp" ], out => [ "none" ] }, ins => [ "base", "index", "mem", "val" ], emit => '. and%M %SI3, %AM', units => [ "GP" ], + latency => 1, mode => "mode_M", modified_flags => $status_flags }, AndMem8Bit => { irn_flags => "R", + state => "exc_pinned", reg_req => { in => [ "gp", "gp", "none", "eax ebx ecx edx" ], out => [ "none" ] }, ins => [ "base", "index", "mem", "val" ], emit => '. and%M %SB3, %AM', units => [ "GP" ], + latency => 1, mode => "mode_M", modified_flags => $status_flags }, Or => { irn_flags => "R", - reg_req => { in => [ "gp", "gp", "none", "gp", "gp" ], out => [ "in_r4 in_r5" ] }, + state => "exc_pinned", + reg_req => { in => [ "gp", "gp", "none", "gp", "gp" ], + out => [ "in_r4 in_r5", "flags", "none" ] }, ins => [ "base", "index", "mem", "left", "right" ], - am => "full,binary", + outs => [ "res", "flags", "M" ], + am => "source,binary", emit => '. or%M %binop', units => [ "GP" ], + latency => 1, mode => $mode_gp, modified_flags => $status_flags }, OrMem => { irn_flags => "R", + state => "exc_pinned", reg_req => { in => [ "gp", "gp", "none", "gp" ], out => [ "none" ] }, ins => [ "base", "index", "mem", "val" ], emit => '. or%M %SI3, %AM', units => [ "GP" ], + latency => 1, mode => "mode_M", modified_flags => $status_flags }, OrMem8Bit => { irn_flags => "R", + state => "exc_pinned", reg_req => { in => [ "gp", "gp", "none", "eax ebx ecx edx" ], out => [ "none" ] }, ins => [ "base", "index", "mem", "val" ], emit => '. or%M %SB3, %AM', units => [ "GP" ], + latency => 1, mode => "mode_M", modified_flags => $status_flags }, Xor => { irn_flags => "R", - reg_req => { in => [ "gp", "gp", "none", "gp", "gp" ], out => [ "in_r4 in_r5" ] }, + state => "exc_pinned", + reg_req => { in => [ "gp", "gp", "none", "gp", "gp" ], + out => [ "in_r4 in_r5", "flags", "none" ] }, ins => [ "base", "index", "mem", "left", "right" ], - am => "full,binary", + outs => [ "res", "flags", "M" ], + am => "source,binary", emit => '. xor%M %binop', units => [ "GP" ], + latency => 1, + mode => $mode_gp, + modified_flags => $status_flags +}, + +Xor0 => { + op_flags => "c", + irn_flags => "R", + reg_req => { out => [ "gp", "flags" ] }, + outs => [ "res", "flags" ], + emit => ". xor%M %D0, %D0", + units => [ "GP" ], + latency => 1, mode => $mode_gp, modified_flags => $status_flags }, XorMem => { irn_flags => "R", + state => "exc_pinned", reg_req => { in => [ "gp", "gp", "none", "gp" ], out => [ "none" ] }, ins => [ "base", "index", "mem", "val" ], emit => '. xor%M %SI3, %AM', units => [ "GP" ], + latency => 1, mode => "mode_M", modified_flags => $status_flags }, XorMem8Bit => { irn_flags => "R", + state => "exc_pinned", reg_req => { in => [ "gp", "gp", "none", "eax ebx ecx edx" ], out => [ "none" ] }, ins => [ "base", "index", "mem", "val" ], emit => '. xor%M %SB3, %AM', units => [ "GP" ], + latency => 1, mode => "mode_M", modified_flags => $status_flags }, @@ -554,65 +634,87 @@ XorMem8Bit => { 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", + state => "exc_pinned", + reg_req => { in => [ "gp", "gp", "none", "gp", "gp" ], + out => [ "in_r4", "flags", "none" ] }, + ins => [ "base", "index", "mem", "minuend", "subtrahend" ], + outs => [ "res", "flags", "M" ], + am => "source,binary", emit => '. sub%M %binop', units => [ "GP" ], + latency => 1, mode => $mode_gp, modified_flags => $status_flags }, SubMem => { irn_flags => "R", + state => "exc_pinned", reg_req => { in => [ "gp", "gp", "none", "gp" ], out => [ "none" ] }, - ins => [ "base", "index", "mem", "val" ], + ins => [ "base", "index", "mem", "subtrahend" ], emit => '. sub%M %SI3, %AM', units => [ "GP" ], + latency => 1, mode => 'mode_M', modified_flags => $status_flags }, SubMem8Bit => { irn_flags => "R", + state => "exc_pinned", reg_req => { in => [ "gp", "gp", "none", "eax ebx ecx edx" ], out => [ "none" ] }, - ins => [ "base", "index", "mem", "val" ], + ins => [ "base", "index", "mem", "subtrahend" ], emit => '. sub%M %SB3, %AM', units => [ "GP" ], + latency => 1, 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", + state => "exc_pinned", + reg_req => { in => [ "gp", "gp", "none", "gp", "gp", "flags" ], + out => [ "in_r4 !in_r5", "flags", "none" ] }, + ins => [ "base", "index", "mem", "minuend", "subtrahend", "eflags" ], + outs => [ "res", "flags", "M" ], + am => "source,binary", emit => '. sbb%M %binop', units => [ "GP" ], + latency => 1, + mode => $mode_gp, + modified_flags => $status_flags +}, + +Sbb0 => { + irn_flags => "R", + reg_req => { in => [ "flags" ], out => [ "gp", "flags" ] }, + outs => [ "res", "flags" ], + emit => ". sbb%M %D0, %D0", + units => [ "GP" ], + latency => 1, mode => $mode_gp, modified_flags => $status_flags }, l_Sub => { reg_req => { in => [ "none", "none" ], out => [ "none" ] }, - ins => [ "left", "right" ], + ins => [ "minuend", "subtrahend" ], }, l_Sbb => { reg_req => { in => [ "none", "none", "none" ], out => [ "none" ] }, - ins => [ "left", "right", "eflags" ], + ins => [ "minuend", "subtrahend", "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", + reg_req => { in => [ "gp", "gp", "none", "gp", "eax", "edx" ], + out => [ "eax", "flags", "none", "edx", "none" ] }, + ins => [ "base", "index", "mem", "divisor", "dividend_low", "dividend_high" ], + outs => [ "div_res", "flags", "M", "mod_res", "X_exc" ], + am => "source,unary", + emit => ". idiv%M %unop3", latency => 25, units => [ "GP" ], modified_flags => $status_flags @@ -621,13 +723,12 @@ IDiv => { 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", + reg_req => { in => [ "gp", "gp", "none", "gp", "eax", "edx" ], + out => [ "eax", "flags", "none", "edx", "none" ] }, + ins => [ "base", "index", "mem", "divisor", "dividend_low", "dividend_high" ], + outs => [ "div_res", "flags", "M", "mod_res", "X_exc" ], + am => "source,unary", + emit => ". div%M %unop3", latency => 25, units => [ "GP" ], modified_flags => $status_flags @@ -635,49 +736,42 @@ Div => { Shl => { irn_flags => "R", - reg_req => { in => [ "gp", "ecx" ], out => [ "in_r1 !in_r2" ] }, - ins => [ "left", "right" ], - am => "dest,binary", - emit => '. shl %SB1, %S0', + reg_req => { in => [ "gp", "ecx" ], + out => [ "in_r1 !in_r2", "flags" ] }, + ins => [ "val", "count" ], + outs => [ "res", "flags" ], + emit => '. shl%M %SB1, %S0', units => [ "GP" ], + latency => 1, mode => $mode_gp, modified_flags => $status_flags }, ShlMem => { irn_flags => "R", + state => "exc_pinned", reg_req => { in => [ "gp", "gp", "none", "ecx" ], out => [ "none" ] }, ins => [ "base", "index", "mem", "count" ], emit => '. shl%M %SB3, %AM', units => [ "GP" ], + latency => 1, mode => "mode_M", modified_flags => $status_flags }, l_ShlDep => { - cmp_attr => "return 1;", - # value, cnt, dependency - arity => 3 + cmp_attr => "return 1;", + reg_req => { in => [ "none", "none", "none" ], out => [ "none" ] }, + ins => [ "val", "count", "dep" ], }, 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', + irn_flags => "R", + reg_req => { in => [ "gp", "gp", "ecx" ], + out => [ "in_r1 !in_r2 !in_r3", "flags" ] }, + ins => [ "val_high", "val_low", "count" ], + outs => [ "res", "flags" ], + emit => ". shld%M %SB2, %S1, %D0", latency => 6, units => [ "GP" ], mode => $mode_gp, @@ -686,54 +780,48 @@ ShlD => { l_ShlD => { cmp_attr => "return 1;", - arity => 3, + reg_req => { in => [ "none", "none", "none" ], out => [ "none" ] }, + ins => [ "val_high", "val_low", "count" ], }, Shr => { irn_flags => "R", - reg_req => { in => [ "gp", "ecx" ], out => [ "in_r1 !in_r2" ] }, + reg_req => { in => [ "gp", "ecx" ], + out => [ "in_r1 !in_r2", "flags" ] }, ins => [ "val", "count" ], - am => "dest,binary", - emit => '. shr %SB1, %S0', + outs => [ "res", "flags" ], + emit => '. shr%M %SB1, %S0', units => [ "GP" ], mode => $mode_gp, + latency => 1, modified_flags => $status_flags }, ShrMem => { irn_flags => "R", + state => "exc_pinned", reg_req => { in => [ "gp", "gp", "none", "ecx" ], out => [ "none" ] }, ins => [ "base", "index", "mem", "count" ], emit => '. shr%M %SB3, %AM', units => [ "GP" ], mode => "mode_M", + latency => 1, modified_flags => $status_flags }, l_ShrDep => { cmp_attr => "return 1;", - # value, cnt, dependency - arity => 3 + reg_req => { in => [ "none", "none", "none" ], out => [ "none" ] }, + ins => [ "val", "count", "dep" ], }, 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', + irn_flags => "R", + reg_req => { in => [ "gp", "gp", "ecx" ], + out => [ "in_r1 !in_r2 !in_r3", "flags" ] }, + ins => [ "val_high", "val_low", "count" ], + outs => [ "res", "flags" ], + emit => ". shrd%M %SB2, %S1, %D0", latency => 6, units => [ "GP" ], mode => $mode_gp, @@ -742,80 +830,87 @@ ShrD => { l_ShrD => { cmp_attr => "return 1;", - arity => 3 + reg_req => { in => [ "none", "none", "none" ], out => [ "none" ] }, + ins => [ "val_high", "val_low", "count" ], }, Sar => { irn_flags => "R", - reg_req => { in => [ "gp", "ecx" ], out => [ "in_r1 !in_r2" ] }, + reg_req => { in => [ "gp", "ecx" ], + out => [ "in_r1 !in_r2", "flags" ] }, ins => [ "val", "count" ], - am => "dest,binary", - emit => '. sar %SB1, %S0', + outs => [ "res", "flags" ], + emit => '. sar%M %SB1, %S0', units => [ "GP" ], + latency => 1, mode => $mode_gp, modified_flags => $status_flags }, SarMem => { irn_flags => "R", + state => "exc_pinned", reg_req => { in => [ "gp", "gp", "none", "ecx" ], out => [ "none" ] }, ins => [ "base", "index", "mem", "count" ], emit => '. sar%M %SB3, %AM', units => [ "GP" ], + latency => 1, 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 + ins => [ "val", "count", "dep" ], + reg_req => { in => [ "none", "none", "none" ], out => [ "none" ] }, }, Ror => { irn_flags => "R", - reg_req => { in => [ "gp", "ecx" ], out => [ "in_r1 !in_r2" ] }, + reg_req => { in => [ "gp", "ecx" ], + out => [ "in_r1 !in_r2", "flags" ] }, ins => [ "val", "count" ], - am => "dest,binary", - emit => '. ror %SB1, %S0', + outs => [ "res", "flags" ], + emit => '. ror%M %SB1, %S0', units => [ "GP" ], + latency => 1, mode => $mode_gp, modified_flags => $status_flags }, RorMem => { irn_flags => "R", + state => "exc_pinned", reg_req => { in => [ "gp", "gp", "none", "ecx" ], out => [ "none" ] }, ins => [ "base", "index", "mem", "count" ], emit => '. ror%M %SB3, %AM', units => [ "GP" ], + latency => 1, mode => "mode_M", modified_flags => $status_flags }, Rol => { irn_flags => "R", - reg_req => { in => [ "gp", "ecx" ], out => [ "in_r1 !in_r2" ] }, + reg_req => { in => [ "gp", "ecx" ], + out => [ "in_r1 !in_r2", "flags" ] }, ins => [ "val", "count" ], - am => "dest,binary", - emit => '. rol %SB1, %S0', + outs => [ "res", "flags" ], + emit => '. rol%M %SB1, %S0', units => [ "GP" ], + latency => 1, mode => $mode_gp, modified_flags => $status_flags }, RolMem => { irn_flags => "R", + state => "exc_pinned", reg_req => { in => [ "gp", "gp", "none", "ecx" ], out => [ "none" ] }, ins => [ "base", "index", "mem", "count" ], emit => '. rol%M %SB3, %AM', units => [ "GP" ], + latency => 1, mode => "mode_M", modified_flags => $status_flags }, @@ -824,109 +919,145 @@ RolMem => { Neg => { irn_flags => "R", - reg_req => { in => [ "gp" ], out => [ "in_r1" ] }, - emit => '. neg %S0', + reg_req => { in => [ "gp" ], + out => [ "in_r1", "flags" ] }, + emit => '. neg%M %S0', ins => [ "val" ], - am => "dest,unary", + outs => [ "res", "flags" ], units => [ "GP" ], + latency => 1, mode => $mode_gp, modified_flags => $status_flags }, NegMem => { irn_flags => "R", + state => "exc_pinned", reg_req => { in => [ "gp", "gp", "none" ], out => [ "none" ] }, ins => [ "base", "index", "mem" ], emit => '. neg%M %AM', units => [ "GP" ], + latency => 1, mode => "mode_M", modified_flags => $status_flags }, Minus64Bit => { irn_flags => "R", - reg_req => { in => [ "gp", "gp" ], out => [ "in_r1", "gp" ] }, + reg_req => { in => [ "gp", "gp" ], out => [ "in_r1", "in_r2" ] }, outs => [ "low_res", "high_res" ], units => [ "GP" ], + latency => 3, 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', + reg_req => { in => [ "gp" ], + out => [ "in_r1", "flags" ] }, + ins => [ "val" ], + outs => [ "res", "flags" ], + emit => '. inc%M %S0', units => [ "GP" ], mode => $mode_gp, - modified_flags => [ "OF", "SF", "ZF", "AF", "PF" ] + latency => 1, + modified_flags => $status_flags_wo_cf }, IncMem => { irn_flags => "R", + state => "exc_pinned", 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" ] + latency => 1, + modified_flags => $status_flags_wo_cf }, Dec => { irn_flags => "R", - reg_req => { in => [ "gp" ], out => [ "in_r1" ] }, - am => "dest,unary", - emit => '. dec %S0', + reg_req => { in => [ "gp" ], + out => [ "in_r1", "flags" ] }, + ins => [ "val" ], + outs => [ "res", "flags" ], + emit => '. dec%M %S0', units => [ "GP" ], mode => $mode_gp, - modified_flags => [ "OF", "SF", "ZF", "AF", "PF" ] + latency => 1, + modified_flags => $status_flags_wo_cf }, DecMem => { irn_flags => "R", + state => "exc_pinned", 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" ] + latency => 1, + modified_flags => $status_flags_wo_cf }, Not => { irn_flags => "R", - reg_req => { in => [ "gp" ], out => [ "in_r1" ] }, + reg_req => { in => [ "gp" ], + out => [ "in_r1", "flags" ] }, ins => [ "val" ], - am => "dest,unary", - emit => '. not %S0', + outs => [ "res", "flags" ], + emit => '. not%M %S0', units => [ "GP" ], + latency => 1, mode => $mode_gp, + # no flags modified }, NotMem => { irn_flags => "R", + state => "exc_pinned", reg_req => { in => [ "gp", "gp", "none" ], out => [ "none" ] }, ins => [ "base", "index", "mem" ], emit => '. not%M %AM', units => [ "GP" ], + latency => 1, mode => "mode_M", + # no flags modified +}, + +Cmc => { + reg_req => { in => [ "flags" ], out => [ "flags" ] }, + emit => '.cmc', + units => [ "GP" ], + latency => 1, + mode => $mode_flags, + modified_flags => $status_flags +}, + +Stc => { + reg_req => { out => [ "flags" ] }, + emit => '.stc', + units => [ "GP" ], + latency => 1, + mode => $mode_flags, + modified_flags => $status_flags }, # other operations Cmp => { irn_flags => "R", - reg_req => { in => [ "gp", "gp", "none", "gp", "gp" ] , out => [ "flags" ] }, + state => "exc_pinned", + reg_req => { in => [ "gp", "gp", "none", "gp", "gp" ], + out => [ "flags", "none", "none" ] }, ins => [ "base", "index", "mem", "left", "right" ], - outs => [ "eflags" ], + outs => [ "eflags", "unused", "M" ], am => "source,binary", emit => '. cmp%M %binop', - attr => "int flipped, int cmp_unsigned", - init_attr => "attr->data.cmp_flipped = flipped;\n". + attr => "int ins_permuted, int cmp_unsigned", + init_attr => "attr->data.ins_permuted = ins_permuted;\n". "\tattr->data.cmp_unsigned = cmp_unsigned;\n", latency => 1, units => [ "GP" ], @@ -936,13 +1067,15 @@ Cmp => { Cmp8Bit => { irn_flags => "R", - reg_req => { in => [ "gp", "gp", "none", "eax ebx ecx edx", "eax ebx ecx edx" ] , out => [ "flags" ] }, + state => "exc_pinned", + reg_req => { in => [ "gp", "gp", "none", "eax ebx ecx edx", "eax ebx ecx edx" ] , + out => [ "flags", "none", "none" ] }, ins => [ "base", "index", "mem", "left", "right" ], - outs => [ "eflags" ], + outs => [ "eflags", "unused", "M" ], am => "source,binary", emit => '. cmpb %binop', - attr => "int flipped, int cmp_unsigned", - init_attr => "attr->data.cmp_flipped = flipped;\n". + attr => "int ins_permuted, int cmp_unsigned", + init_attr => "attr->data.ins_permuted = ins_permuted;\n". "\tattr->data.cmp_unsigned = cmp_unsigned;\n", latency => 1, units => [ "GP" ], @@ -952,13 +1085,15 @@ Cmp8Bit => { Test => { irn_flags => "R", - reg_req => { in => [ "gp", "gp", "none", "gp", "gp" ] , out => [ "flags" ] }, + state => "exc_pinned", + reg_req => { in => [ "gp", "gp", "none", "gp", "gp" ] , + out => [ "flags", "none", "none" ] }, ins => [ "base", "index", "mem", "left", "right" ], - outs => [ "eflags" ], + outs => [ "eflags", "unused", "M" ], am => "source,binary", emit => '. test%M %binop', - attr => "int flipped, int cmp_unsigned", - init_attr => "attr->data.cmp_flipped = flipped;\n". + attr => "int ins_permuted, int cmp_unsigned", + init_attr => "attr->data.ins_permuted = ins_permuted;\n". "\tattr->data.cmp_unsigned = cmp_unsigned;\n", latency => 1, units => [ "GP" ], @@ -968,13 +1103,15 @@ Test => { Test8Bit => { irn_flags => "R", - reg_req => { in => [ "gp", "gp", "none", "eax ebx ecx edx", "eax ebx ecx edx" ] , out => [ "flags" ] }, + state => "exc_pinned", + reg_req => { in => [ "gp", "gp", "none", "eax ebx ecx edx", "eax ebx ecx edx" ] , + out => [ "flags", "none", "none" ] }, ins => [ "base", "index", "mem", "left", "right" ], - outs => [ "eflags" ], + outs => [ "eflags", "unused", "M" ], am => "source,binary", emit => '. testb %binop', - attr => "int flipped, int cmp_unsigned", - init_attr => "attr->data.cmp_flipped = flipped;\n". + attr => "int ins_permuted, int cmp_unsigned", + init_attr => "attr->data.ins_permuted = ins_permuted;\n". "\tattr->data.cmp_unsigned = cmp_unsigned;\n", latency => 1, units => [ "GP" ], @@ -986,24 +1123,44 @@ 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", + attr_type => "ia32_condcode_attr_t", + attr => "pn_Cmp pnc, int ins_permuted", + init_attr => "attr->attr.data.ins_permuted = ins_permuted;\n". + "\tset_ia32_ls_mode(res, mode_Bu);\n", emit => '. set%CMP0 %DB0', latency => 1, units => [ "GP" ], mode => $mode_gp, }, +SetMem => { + #irn_flags => "R", + state => "exc_pinned", + reg_req => { in => [ "gp", "gp", "none", "eflags" ], out => [ "none" ] }, + ins => [ "base", "index", "mem","eflags" ], + attr_type => "ia32_condcode_attr_t", + attr => "pn_Cmp pnc, int ins_permuted", + init_attr => "attr->attr.data.ins_permuted = ins_permuted;\n". + "\tset_ia32_ls_mode(res, mode_Bu);\n", + emit => '. set%CMP3 %AM', + latency => 1, + units => [ "GP" ], + mode => 'mode_M', +}, + 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" ] }, + state => "exc_pinned", + reg_req => { in => [ "gp", "gp", "none", "gp", "gp", "eflags" ], + out => [ "in_r4 in_r5", "flags", "none" ] }, ins => [ "base", "index", "mem", "val_false", "val_true", "eflags" ], + outs => [ "res", "flags", "M" ], am => "source,binary", - attr => "pn_Cmp pn_code", - init_attr => "attr->pn_code = pn_code;", + attr_type => "ia32_condcode_attr_t", + attr => "int ins_permuted, pn_Cmp pnc", + init_attr => "attr->attr.data.ins_permuted = ins_permuted;", latency => 1, units => [ "GP" ], mode => $mode_gp, @@ -1015,8 +1172,8 @@ Jcc => { reg_req => { in => [ "eflags" ], out => [ "none", "none" ] }, ins => [ "eflags" ], outs => [ "false", "true" ], + attr_type => "ia32_condcode_attr_t", attr => "pn_Cmp pnc", - init_attr => "attr->pn_code = pnc;", latency => 2, units => [ "BRANCH" ], }, @@ -1024,20 +1181,36 @@ Jcc => { SwitchJmp => { state => "pinned", op_flags => "L|X|Y", - reg_req => { in => [ "gp" ], out => [ "none" ] }, + reg_req => { in => [ "gp" ] }, + mode => "mode_T", + attr_type => "ia32_condcode_attr_t", + attr => "long pnc", latency => 3, units => [ "BRANCH" ], - mode => "mode_T", - modified_flags => $status_flags + modified_flags => $status_flags, + init_attr => "info->out_infos = NULL;", # XXX ugly hack for out requirements +}, + +Jmp => { + state => "pinned", + op_flags => "X", + reg_req => { out => [ "none" ] }, + latency => 1, + units => [ "BRANCH" ], + mode => "mode_X", }, IJmp => { state => "pinned", op_flags => "X", - reg_req => { in => [ "gp" ] }, - emit => '. jmp *%S0', + reg_req => { in => [ "gp", "gp", "none", "gp" ] }, + ins => [ "base", "index", "mem", "target" ], + am => "source,unary", + emit => '. jmp *%unop3', + latency => 1, units => [ "BRANCH" ], mode => "mode_X", + init_attr => "info->out_infos = NULL;", # XXX ugly hack for out requirements }, Const => { @@ -1045,80 +1218,87 @@ Const => { irn_flags => "R", reg_req => { out => [ "gp" ] }, units => [ "GP" ], - attr => "ir_entity *symconst, int symconst_sign, long offset", + attr => "ir_entity *symconst, int symconst_sign, int no_pic_adjust, long offset", attr_type => "ia32_immediate_attr_t", + latency => 1, mode => $mode_gp, -# depends on the const and is set in ia32_transform -# modified_flags => $status_flags +}, + +GetEIP => { + op_flags => "c", + reg_req => { out => [ "gp" ] }, + units => [ "GP" ], + latency => 5, + mode => $mode_gp, + modified_flags => $status_flags, }, Unknown_GP => { state => "pinned", - op_flags => "c", - irn_flags => "I", - reg_req => { out => [ "gp_UKNWN" ] }, + op_flags => "c|NB", + reg_req => { out => [ "gp_UKNWN:I" ] }, units => [], emit => "", + latency => 0, mode => $mode_gp }, Unknown_VFP => { state => "pinned", - op_flags => "c", - irn_flags => "I", - reg_req => { out => [ "vfp_UKNWN" ] }, + op_flags => "c|NB", + reg_req => { out => [ "vfp_UKNWN:I" ] }, units => [], emit => "", mode => "mode_E", + latency => 0, attr_type => "ia32_x87_attr_t", }, Unknown_XMM => { state => "pinned", - op_flags => "c", - irn_flags => "I", - reg_req => { out => [ "xmm_UKNWN" ] }, + op_flags => "c|NB", + reg_req => { out => [ "xmm_UKNWN:I" ] }, units => [], emit => "", - mode => "mode_E" + latency => 0, + mode => $mode_xmm }, NoReg_GP => { state => "pinned", - op_flags => "c", - irn_flags => "I", - reg_req => { out => [ "gp_NOREG" ] }, + op_flags => "c|NB|NI", + reg_req => { out => [ "gp_NOREG:I" ] }, units => [], emit => "", + latency => 0, mode => $mode_gp }, NoReg_VFP => { state => "pinned", - op_flags => "c", - irn_flags => "I", - reg_req => { out => [ "vfp_NOREG" ] }, + op_flags => "c|NB|NI", + reg_req => { out => [ "vfp_NOREG:I" ] }, units => [], emit => "", mode => "mode_E", + latency => 0, attr_type => "ia32_x87_attr_t", }, NoReg_XMM => { state => "pinned", - op_flags => "c", - irn_flags => "I", - reg_req => { out => [ "xmm_NOREG" ] }, + op_flags => "c|NB|NI", + reg_req => { out => [ "xmm_NOREG:I" ] }, units => [], emit => "", + latency => 0, mode => "mode_E" }, ChangeCW => { state => "pinned", op_flags => "c", - irn_flags => "I", - reg_req => { out => [ "fp_cw" ] }, + reg_req => { out => [ "fpcw:I" ] }, mode => $mode_fpcw, latency => 3, units => [ "GP" ], @@ -1128,7 +1308,7 @@ ChangeCW => { FldCW => { op_flags => "L|F", state => "pinned", - reg_req => { in => [ "gp", "gp", "none" ], out => [ "fp_cw" ] }, + reg_req => { in => [ "gp", "gp", "none" ], out => [ "fpcw:I" ] }, ins => [ "base", "index", "mem" ], latency => 5, emit => ". fldcw %AM", @@ -1148,11 +1328,22 @@ FnstCW => { units => [ "GP" ], }, +FnstCWNOP => { + op_flags => "L|F", + state => "pinned", + reg_req => { in => [ "fp_cw" ], out => [ "none" ] }, + ins => [ "fpcw" ], + latency => 0, + emit => "", + mode => "mode_M", +}, + Cltd => { # we should not rematrialize this node. It has very strict constraints. reg_req => { in => [ "eax", "edx" ], out => [ "edx" ] }, - ins => [ "val", "globbered" ], + ins => [ "val", "clobbered" ], emit => '. cltd', + latency => 1, mode => $mode_gp, units => [ "GP" ], }, @@ -1165,34 +1356,21 @@ Cltd => { Load => { op_flags => "L|F", state => "exc_pinned", - reg_req => { in => [ "gp", "gp", "none" ], out => [ "gp", "none" ] }, + reg_req => { in => [ "gp", "gp", "none" ], + out => [ "gp", "none", "none", "none" ] }, ins => [ "base", "index", "mem" ], - outs => [ "res", "M" ], + outs => [ "res", "unused", "M", "X_exc" ], latency => 0, - emit => ". mov%SE%ME%.l %AM, %D0", + emit => ". mov%EX%.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" ] }, + reg_req => { in => [ "gp", "gp", "none", "gp" ], out => [ "none", "none" ] }, ins => [ "base", "index", "mem", "val" ], + outs => [ "M", "X_exc" ], emit => '. mov%M %SI3, %AM', latency => 2, units => [ "GP" ], @@ -1202,8 +1380,9 @@ Store => { Store8Bit => { op_flags => "L|F", state => "exc_pinned", - reg_req => { in => [ "gp", "gp", "none", "eax ebx ecx edx" ], out => ["none" ] }, + reg_req => { in => [ "gp", "gp", "none", "eax ebx ecx edx" ], out => ["none", "none" ] }, ins => [ "base", "index", "mem", "val" ], + outs => [ "M", "X_exc" ], emit => '. mov%M %SB3, %AM', latency => 2, units => [ "GP" ], @@ -1218,204 +1397,576 @@ Lea => { 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 +# lea doesn't modify the flags, but setting this seems advantageous since it +# increases chances that the Lea is transformed back to an Add modified_flags => 1, }, Push => { - reg_req => { in => [ "gp", "gp", "none", "gp", "esp" ], out => [ "esp", "none" ] }, + state => "exc_pinned", + reg_req => { in => [ "gp", "gp", "none", "gp", "esp" ], out => [ "esp:I|S", "none" ] }, ins => [ "base", "index", "mem", "val", "stack" ], emit => '. push%M %unop3', - outs => [ "stack:I|S", "M" ], - am => "source,binary", + outs => [ "stack", "M" ], + am => "source,unary", 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" ], + state => "exc_pinned", + reg_req => { in => [ "none", "esp" ], out => [ "gp", "none", "none", "esp:I|S" ] }, + ins => [ "mem", "stack" ], + outs => [ "res", "M", "unused", "stack" ], + emit => '. pop%M %D0', + latency => 3, # Pop is more expensive than Push on Athlon + units => [ "GP" ], +}, + +PopEbp => { + state => "exc_pinned", + reg_req => { in => [ "none", "esp" ], out => [ "ebp:I", "none", "none", "esp:I|S" ] }, + ins => [ "mem", "stack" ], + outs => [ "res", "M", "unused", "stack" ], + emit => '. pop%M %D0', + latency => 3, # Pop is more expensive than Push on Athlon + units => [ "GP" ], +}, + +PopMem => { + state => "exc_pinned", + reg_req => { in => [ "gp", "gp", "none", "esp" ], out => [ "none", "none", "none", "esp:I|S" ] }, ins => [ "base", "index", "mem", "stack" ], - am => "dest,unary", + outs => [ "unused0", "M", "unused1", "stack" ], + emit => '. pop%M %AM', latency => 3, # Pop is more expensive than Push on Athlon units => [ "GP" ], }, Enter => { - reg_req => { in => [ "esp" ], out => [ "ebp", "esp", "none" ] }, + reg_req => { in => [ "esp" ], out => [ "ebp", "esp:I|S", "none" ] }, emit => '. enter', - outs => [ "frame:I", "stack:I|S", "M" ], + outs => [ "frame", "stack", "M" ], latency => 15, units => [ "GP" ], }, Leave => { - reg_req => { in => [ "esp", "ebp" ], out => [ "ebp", "esp" ] }, + reg_req => { in => [ "ebp" ], out => [ "ebp:I", "esp:I|S" ] }, emit => '. leave', - outs => [ "frame:I", "stack:I|S" ], + outs => [ "frame", "stack" ], latency => 3, units => [ "GP" ], }, AddSP => { - irn_flags => "I", state => "pinned", - reg_req => { in => [ "gp", "gp", "none", "esp", "gp" ], out => [ "in_r4", "none" ] }, + reg_req => { in => [ "gp", "gp", "none", "esp", "gp" ], out => [ "esp:I|S", "none" ] }, ins => [ "base", "index", "mem", "stack", "size" ], am => "source,binary", emit => '. addl %binop', - outs => [ "stack:S", "M" ], + latency => 1, + outs => [ "stack", "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" ] }, + reg_req => { in => [ "gp", "gp", "none", "esp", "gp" ], out => [ "esp:I|S", "gp", "none" ] }, ins => [ "base", "index", "mem", "stack", "size" ], am => "source,binary", emit => ". subl %binop\n". ". movl %%esp, %D1", - outs => [ "stack:I|S", "addr", "M" ], + latency => 2, + outs => [ "stack", "addr", "M" ], units => [ "GP" ], modified_flags => $status_flags }, +RepPrefix => { + op_flags => "K", + state => "pinned", + mode => "mode_M", + emit => ". rep", + latency => 0, +}, + LdTls => { irn_flags => "R", reg_req => { out => [ "gp" ] }, units => [ "GP" ], + latency => 1, }, -# the int instruction -int => { - reg_req => { in => [ "gp" ], out => [ "none" ] }, - mode => "mode_M", - emit => '. int %SI0', +# +# BT supports source address mode, but this is unused yet +# +Bt => { + irn_flags => "R", + state => "exc_pinned", + reg_req => { in => [ "gp", "gp" ], out => [ "flags" ] }, + ins => [ "left", "right" ], + emit => '. bt%M %S1, %S0', units => [ "GP" ], - cmp_attr => "return 1;", + latency => 1, + mode => $mode_flags, + modified_flags => $status_flags # only CF is set, but the other flags are undefined }, - -#-----------------------------------------------------------------------------# -# _____ _____ ______ __ _ _ _ # -# / ____/ ____| ____| / _| | | | | | # -# | (___| (___ | |__ | |_| | ___ __ _| |_ _ __ ___ __| | ___ ___ # -# \___ \\___ \| __| | _| |/ _ \ / _` | __| | '_ \ / _ \ / _` |/ _ \/ __| # -# ____) |___) | |____ | | | | (_) | (_| | |_ | | | | (_) | (_| | __/\__ \ # -# |_____/_____/|______| |_| |_|\___/ \__,_|\__| |_| |_|\___/ \__,_|\___||___/ # -#-----------------------------------------------------------------------------# - -xZero => { +Bsf => { irn_flags => "R", - reg_req => { out => [ "xmm" ] }, - emit => '. xorp%XSD %D0, %D0', - latency => 3, - units => [ "SSE" ], - mode => "mode_E", + state => "exc_pinned", + reg_req => { in => [ "gp", "gp", "none", "gp" ], + out => [ "gp", "flags", "none" ] }, + ins => [ "base", "index", "mem", "operand" ], + outs => [ "res", "flags", "M" ], + am => "source,binary", + emit => '. bsf%M %unop3, %D0', + units => [ "GP" ], + latency => 1, + mode => $mode_gp, + modified_flags => $status_flags }, -# commutative operations - -xAdd => { +Bsr => { 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", + state => "exc_pinned", + reg_req => { in => [ "gp", "gp", "none", "gp" ], + out => [ "gp", "flags", "none" ] }, + ins => [ "base", "index", "mem", "operand" ], + outs => [ "res", "flags", "M" ], + am => "source,binary", + emit => '. bsr%M %unop3, %D0', + units => [ "GP" ], + latency => 1, + mode => $mode_gp, + modified_flags => $status_flags +}, + +# +# SSE4.2 or SSE4a popcnt instruction +# +Popcnt => { + irn_flags => "R", + state => "exc_pinned", + reg_req => { in => [ "gp", "gp", "none", "gp" ], + out => [ "gp", "flags", "none" ] }, + ins => [ "base", "index", "mem", "operand" ], + outs => [ "res", "flags", "M" ], + am => "source,binary", + emit => '. popcnt%M %unop3, %D0', + units => [ "GP" ], + latency => 1, + mode => $mode_gp, + modified_flags => $status_flags +}, + +Call => { + state => "exc_pinned", + reg_req => { + in => [ "gp", "gp", "none", "gp", "esp", "fpcw", "eax", "ecx", "edx" ], + out => [ "esp:I|S", "fpcw:I", "none", "eax", "ecx", "edx", "vf0", "vf1", "vf2", "vf3", "vf4", "vf5", "vf6", "vf7", "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5", "xmm6", "xmm7" ] + }, + ins => [ "base", "index", "mem", "addr", "stack", "fpcw", "eax", "ecx", "edx" ], + outs => [ "stack", "fpcw", "M", "eax", "ecx", "edx", "vf0", "vf1", "vf2", "vf3", "vf4", "vf5", "vf6", "vf7", "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5", "xmm6", "xmm7" ], + attr_type => "ia32_call_attr_t", + attr => "unsigned pop, ir_type *call_tp", + am => "source,unary", + units => [ "BRANCH" ], + latency => 4, # random number + modified_flags => $status_flags +}, + +# +# a Helper node for frame-climbing, needed for __builtin_(frame|return)_address +# +# PS: try gcc __builtin_frame_address(100000) :-) +# +ClimbFrame => { + reg_req => { in => [ "gp", "gp", "gp"], out => [ "in_r3" ] }, + ins => [ "frame", "cnt", "tmp" ], + outs => [ "res" ], + latency => 4, # random number + attr_type => "ia32_climbframe_attr_t", + attr => "unsigned count", + units => [ "GP" ], + mode => $mode_gp +}, + +# +# bswap +# +Bswap => { + irn_flags => "R", + reg_req => { in => [ "gp" ], + out => [ "in_r1" ] }, + emit => '. bswap%M %S0', + ins => [ "val" ], + units => [ "GP" ], + latency => 1, + mode => $mode_gp, +}, + +# +# bswap16, use xchg here +# +Bswap16 => { + irn_flags => "R", + reg_req => { in => [ "eax ebx ecx edx" ], + out => [ "in_r1" ] }, + emit => '. xchg %SB0, %SH0', + ins => [ "val" ], + units => [ "GP" ], + latency => 1, + mode => $mode_gp, +}, + +# +# BreakPoint +# +Breakpoint => { + state => "pinned", + reg_req => { in => [ "none" ], out => [ "none" ] }, + ins => [ "mem" ], + latency => 0, + emit => ". int3", + units => [ "GP" ], + mode => mode_M, +}, + +# +# Undefined Instruction on ALL x86 CPU's +# +UD2 => { + state => "pinned", + reg_req => { in => [ "none" ], out => [ "none" ] }, + ins => [ "mem" ], + latency => 0, + emit => ". .value 0x0b0f", + units => [ "GP" ], + mode => mode_M, +}, + +# +# outport +# +Outport => { + irn_flags => "R", + state => "pinned", + reg_req => { in => [ "edx", "eax", "none" ], out => [ "none" ] }, + ins => [ "port", "value", "mem" ], + emit => '. out%M %SS0, %SI1', + units => [ "GP" ], + latency => 1, + mode => mode_M, + modified_flags => $status_flags +}, + +# +# inport +# +Inport => { + irn_flags => "R", + state => "pinned", + reg_req => { in => [ "edx", "none" ], out => [ "eax", "none" ] }, + ins => [ "port", "mem" ], + outs => [ "res", "M" ], + emit => '. in%M %DS0, %SS0', + units => [ "GP" ], + latency => 1, + mode => mode_T, + modified_flags => $status_flags +}, + +# +# Intel style prefetching +# +Prefetch0 => { + op_flags => "L|F", + state => "exc_pinned", + reg_req => { in => [ "gp", "gp", "none" ], out => [ "none" ] }, + ins => [ "base", "index", "mem" ], + outs => [ "M" ], + latency => 0, + emit => ". prefetcht0 %AM", + units => [ "GP" ], +}, + +Prefetch1 => { + op_flags => "L|F", + state => "exc_pinned", + reg_req => { in => [ "gp", "gp", "none" ], out => [ "none" ] }, + ins => [ "base", "index", "mem" ], + outs => [ "M" ], + latency => 0, + emit => ". prefetcht1 %AM", + units => [ "GP" ], +}, + +Prefetch2 => { + op_flags => "L|F", + state => "exc_pinned", + reg_req => { in => [ "gp", "gp", "none" ], out => [ "none" ] }, + ins => [ "base", "index", "mem" ], + outs => [ "M" ], + latency => 0, + emit => ". prefetcht2 %AM", + units => [ "GP" ], +}, + +PrefetchNTA => { + op_flags => "L|F", + state => "exc_pinned", + reg_req => { in => [ "gp", "gp", "none" ], out => [ "none" ] }, + ins => [ "base", "index", "mem" ], + outs => [ "M" ], + latency => 0, + emit => ". prefetchnta %AM", + units => [ "GP" ], +}, + +# +# 3DNow! prefetch instructions +# +Prefetch => { + op_flags => "L|F", + state => "exc_pinned", + reg_req => { in => [ "gp", "gp", "none" ], out => [ "none" ] }, + ins => [ "base", "index", "mem" ], + outs => [ "M" ], + latency => 0, + emit => ". prefetch %AM", + units => [ "GP" ], +}, + +PrefetchW => { + op_flags => "L|F", + state => "exc_pinned", + reg_req => { in => [ "gp", "gp", "none" ], out => [ "none" ] }, + ins => [ "base", "index", "mem" ], + outs => [ "M" ], + latency => 0, + emit => ". prefetchw %AM", + units => [ "GP" ], +}, + +#-----------------------------------------------------------------------------# +# _____ _____ ______ __ _ _ _ # +# / ____/ ____| ____| / _| | | | | | # +# | (___| (___ | |__ | |_| | ___ __ _| |_ _ __ ___ __| | ___ ___ # +# \___ \\___ \| __| | _| |/ _ \ / _` | __| | '_ \ / _ \ / _` |/ _ \/ __| # +# ____) |___) | |____ | | | | (_) | (_| | |_ | | | | (_) | (_| | __/\__ \ # +# |_____/_____/|______| |_| |_|\___/ \__,_|\__| |_| |_|\___/ \__,_|\___||___/ # +#-----------------------------------------------------------------------------# + +# produces a 0/+0.0 +xZero => { + irn_flags => "R", + reg_req => { out => [ "xmm" ] }, + emit => '. xorp%XSD %D0, %D0', + latency => 3, + units => [ "SSE" ], + mode => $mode_xmm +}, + +xPzero => { + irn_flags => "R", + reg_req => { out => [ "xmm" ] }, + emit => '. pxor %D0, %D0', + latency => 3, + units => [ "SSE" ], + mode => $mode_xmm +}, + +# produces all 1 bits +xAllOnes => { + irn_flags => "R", + reg_req => { out => [ "xmm" ] }, + emit => '. pcmpeqb %D0, %D0', + latency => 3, + units => [ "SSE" ], + mode => $mode_xmm +}, + +# integer shift left, dword +xPslld => { + irn_flags => "R", + reg_req => { in => [ "xmm", "xmm" ], out => [ "in_r1 !in_r2" ] }, + emit => '. pslld %SI1, %D0', + latency => 3, + units => [ "SSE" ], + mode => $mode_xmm +}, + +# integer shift left, qword +xPsllq => { + irn_flags => "R", + reg_req => { in => [ "xmm", "xmm" ], out => [ "in_r1 !in_r2" ] }, + emit => '. psllq %SI1, %D0', + latency => 3, + units => [ "SSE" ], + mode => $mode_xmm +}, + +# integer shift right, dword +xPsrld => { + irn_flags => "R", + reg_req => { in => [ "xmm", "xmm" ], out => [ "in_r1 !in_r2" ] }, + emit => '. psrld %SI1, %D0', + latency => 1, + units => [ "SSE" ], + mode => $mode_xmm +}, + +# mov from integer to SSE register +xMovd => { + irn_flags => "R", + reg_req => { in => [ "gp" ], out => [ "xmm" ] }, + emit => '. movd %S0, %D0', + latency => 1, + units => [ "SSE" ], + mode => $mode_xmm +}, + +# commutative operations + +xAdd => { + irn_flags => "R", + state => "exc_pinned", + reg_req => { in => [ "gp", "gp", "none", "xmm", "xmm" ], + out => [ "in_r4 in_r5", "flags", "none" ] }, + ins => [ "base", "index", "mem", "left", "right" ], + outs => [ "res", "flags", "M" ], + am => "source,binary", + emit => '. add%XXM %binop', + latency => 4, + units => [ "SSE" ], + mode => $mode_xmm }, xMul => { irn_flags => "R", - reg_req => { in => [ "gp", "gp", "none", "xmm", "xmm" ], out => [ "in_r4 in_r5" ] }, + state => "exc_pinned", + reg_req => { in => [ "gp", "gp", "none", "xmm", "xmm" ], + out => [ "in_r4 in_r5", "flags", "none" ] }, ins => [ "base", "index", "mem", "left", "right" ], + outs => [ "res", "flags", "M" ], + am => "source,binary", emit => '. mul%XXM %binop', latency => 4, units => [ "SSE" ], - mode => "mode_E", + mode => $mode_xmm }, xMax => { irn_flags => "R", - reg_req => { in => [ "gp", "gp", "none", "xmm", "xmm" ], out => [ "in_r4 in_r5" ] }, + state => "exc_pinned", + reg_req => { in => [ "gp", "gp", "none", "xmm", "xmm" ], + out => [ "in_r4 in_r5", "flags", "none" ] }, ins => [ "base", "index", "mem", "left", "right" ], + outs => [ "res", "flags", "M" ], + am => "source,binary", emit => '. max%XXM %binop', latency => 2, units => [ "SSE" ], - mode => "mode_E", + mode => $mode_xmm }, xMin => { irn_flags => "R", - reg_req => { in => [ "gp", "gp", "none", "xmm", "xmm" ], out => [ "in_r4 in_r5" ] }, + state => "exc_pinned", + reg_req => { in => [ "gp", "gp", "none", "xmm", "xmm" ], + out => [ "in_r4 in_r5", "flags", "none" ] }, ins => [ "base", "index", "mem", "left", "right" ], + outs => [ "res", "flags", "M" ], + am => "source,binary", emit => '. min%XXM %binop', latency => 2, units => [ "SSE" ], - mode => "mode_E", + mode => $mode_xmm }, xAnd => { irn_flags => "R", - reg_req => { in => [ "gp", "gp", "none", "xmm", "xmm" ], out => [ "in_r4 in_r5" ] }, + state => "exc_pinned", + reg_req => { in => [ "gp", "gp", "none", "xmm", "xmm" ], + out => [ "in_r4 in_r5", "flags", "none" ] }, ins => [ "base", "index", "mem", "left", "right" ], + outs => [ "res", "flags", "M" ], + am => "source,binary", emit => '. andp%XSD %binop', latency => 3, units => [ "SSE" ], - mode => "mode_E", + mode => $mode_xmm }, xOr => { irn_flags => "R", - reg_req => { in => [ "gp", "gp", "none", "xmm", "xmm" ], out => [ "in_r4 in_r5" ] }, + state => "exc_pinned", + reg_req => { in => [ "gp", "gp", "none", "xmm", "xmm" ], + out => [ "in_r4 in_r5", "flags", "none" ] }, ins => [ "base", "index", "mem", "left", "right" ], + outs => [ "res", "flags", "M" ], + am => "source,binary", emit => '. orp%XSD %binop', + latency => 3, units => [ "SSE" ], - mode => "mode_E", + mode => $mode_xmm }, xXor => { irn_flags => "R", - reg_req => { in => [ "gp", "gp", "none", "xmm", "xmm" ], out => [ "in_r4 in_r5" ] }, + state => "exc_pinned", + reg_req => { in => [ "gp", "gp", "none", "xmm", "xmm" ], + out => [ "in_r4 in_r5", "flags", "none" ] }, ins => [ "base", "index", "mem", "left", "right" ], + outs => [ "res", "flags", "M" ], + am => "source,binary", emit => '. xorp%XSD %binop', latency => 3, units => [ "SSE" ], - mode => "mode_E", + mode => $mode_xmm }, # not commutative operations xAndNot => { irn_flags => "R", - reg_req => { in => [ "gp", "gp", "none", "xmm", "xmm" ], out => [ "in_r4 !in_r5" ] }, + state => "exc_pinned", + reg_req => { in => [ "gp", "gp", "none", "xmm", "xmm" ], + out => [ "in_r4 !in_r5", "flags", "none" ] }, ins => [ "base", "index", "mem", "left", "right" ], + outs => [ "res", "flags", "M" ], + am => "source,binary", emit => '. andnp%XSD %binop', latency => 3, units => [ "SSE" ], - mode => "mode_E", + mode => $mode_xmm }, xSub => { irn_flags => "R", - reg_req => { in => [ "gp", "gp", "none", "xmm", "xmm" ], out => [ "in_r4" ] }, - ins => [ "base", "index", "mem", "left", "right" ], + state => "exc_pinned", + reg_req => { in => [ "gp", "gp", "none", "xmm", "xmm" ], + out => [ "in_r4", "flags", "none" ] }, + ins => [ "base", "index", "mem", "minuend", "subtrahend" ], + outs => [ "res", "flags", "M" ], + am => "source,binary", emit => '. sub%XXM %binop', latency => 4, units => [ "SSE" ], - mode => "mode_E", + mode => $mode_xmm }, 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" ], + state => "exc_pinned", + reg_req => { in => [ "gp", "gp", "none", "xmm", "xmm" ], + out => [ "in_r4 !in_r5", "flags", "none" ] }, + ins => [ "base", "index", "mem", "dividend", "divisor" ], + outs => [ "res", "flags", "M" ], + am => "source,binary", emit => '. div%XXM %binop', latency => 16, units => [ "SSE" ], @@ -1425,12 +1976,14 @@ xDiv => { Ucomi => { irn_flags => "R", - reg_req => { in => [ "gp", "gp", "none", "xmm", "xmm" ], out => [ "eflags" ] }, + state => "exc_pinned", + 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;", + attr => "int ins_permuted", + init_attr => "attr->data.ins_permuted = ins_permuted;", emit => ' .ucomi%XXM %binop', latency => 3, units => [ "SSE" ], @@ -1443,12 +1996,13 @@ Ucomi => { xLoad => { op_flags => "L|F", state => "exc_pinned", - reg_req => { in => [ "gp", "gp", "none" ], out => [ "xmm", "none" ] }, + reg_req => { in => [ "gp", "gp", "none" ], + out => [ "xmm", "none", "none", "none" ] }, ins => [ "base", "index", "mem" ], + outs => [ "res", "unused", "M", "X_exc" ], emit => '. mov%XXM %AM, %D0', attr => "ir_mode *load_mode", init_attr => "attr->ls_mode = load_mode;", - outs => [ "res", "M" ], latency => 0, units => [ "SSE" ], }, @@ -1456,8 +2010,9 @@ xLoad => { xStore => { op_flags => "L|F", state => "exc_pinned", - reg_req => { in => [ "gp", "gp", "none", "xmm" ] }, + reg_req => { in => [ "gp", "gp", "none", "xmm" ], out => [ "none", "none" ] }, ins => [ "base", "index", "mem", "val" ], + outs => [ "M", "X_exc" ], emit => '. mov%XXM %S3, %AM', latency => 0, units => [ "SSE" ], @@ -1467,8 +2022,9 @@ xStore => { xStoreSimple => { op_flags => "L|F", state => "exc_pinned", - reg_req => { in => [ "gp", "gp", "none", "xmm" ] }, + reg_req => { in => [ "gp", "gp", "none", "xmm" ], out => [ "none" ] }, ins => [ "base", "index", "mem", "val" ], + outs => [ "M" ], emit => '. mov%XXM %S3, %AM', latency => 0, units => [ "SSE" ], @@ -1477,8 +2033,10 @@ xStoreSimple => { CvtSI2SS => { op_flags => "L|F", + state => "exc_pinned", reg_req => { in => [ "gp", "gp", "none", "gp" ], out => [ "xmm" ] }, ins => [ "base", "index", "mem", "val" ], + am => "source,unary", emit => '. cvtsi2ss %unop3, %D0', latency => 2, units => [ "SSE" ], @@ -1487,8 +2045,10 @@ CvtSI2SS => { CvtSI2SD => { op_flags => "L|F", + state => "exc_pinned", reg_req => { in => [ "gp", "gp", "none", "gp" ], out => [ "xmm" ] }, ins => [ "base", "index", "mem", "val" ], + am => "source,unary", emit => '. cvtsi2sd %unop3, %D0', latency => 2, units => [ "SSE" ], @@ -1496,47 +2056,71 @@ CvtSI2SD => { }, -l_X87toSSE => { +l_LLtoFloat => { op_flags => "L|F", cmp_attr => "return 1;", - arity => 3, + ins => [ "val_high", "val_low" ], + reg_req => { in => [ "none", "none" ], out => [ "none" ] } }, -l_SSEtoX87 => { +l_FloattoLL => { op_flags => "L|F", cmp_attr => "return 1;", - arity => 3, + ins => [ "val" ], + outs => [ "res_high", "res_low" ], + reg_req => { in => [ "none" ], out => [ "none", "none" ] } }, # CopyB 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" ], + op_flags => "F|H", + state => "pinned", + reg_req => { in => [ "edi", "esi", "ecx", "none" ], out => [ "edi", "esi", "ecx", "none" ] }, + outs => [ "DST", "SRC", "CNT", "M" ], + attr_type => "ia32_copyb_attr_t", + attr => "unsigned size", + units => [ "GP" ], + latency => 3, # 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", - reg_req => { in => [ "edi", "esi", "none" ], out => [ "edi", "esi", "none" ] }, - outs => [ "DST", "SRC", "M" ], - units => [ "GP" ], + op_flags => "F|H", + state => "pinned", + reg_req => { in => [ "edi", "esi", "none" ], out => [ "edi", "esi", "none" ] }, + outs => [ "DST", "SRC", "M" ], + attr_type => "ia32_copyb_attr_t", + attr => "unsigned size", + units => [ "GP" ], + latency => 3, # we don't care about this flag, so no need to mark this node # modified_flags => [ "DF" ] }, # Conversions +Cwtl => { + state => "exc_pinned", + reg_req => { in => [ "eax" ], out => [ "eax" ] }, + ins => [ "val" ], + outs => [ "res" ], + emit => '. cwtl', + units => [ "GP" ], + latency => 1, + mode => $mode_gp, +}, + Conv_I2I => { state => "exc_pinned", - reg_req => { in => [ "gp", "gp", "none", "gp" ], out => [ "gp", "none" ] }, + reg_req => { in => [ "gp", "gp", "none", "gp" ], + out => [ "gp", "none", "none" ] }, ins => [ "base", "index", "mem", "val" ], + outs => [ "res", "flags", "M" ], + am => "source,unary", units => [ "GP" ], + latency => 1, attr => "ir_mode *smaller_mode", init_attr => "attr->ls_mode = smaller_mode;", mode => $mode_gp, @@ -1544,36 +2128,46 @@ Conv_I2I => { Conv_I2I8Bit => { state => "exc_pinned", - reg_req => { in => [ "gp", "gp", "none", "eax ebx ecx edx" ], out => [ "gp", "none" ] }, + reg_req => { in => [ "gp", "gp", "none", "eax ebx ecx edx" ], + out => [ "gp", "none", "none" ] }, ins => [ "base", "index", "mem", "val" ], + outs => [ "res", "flags", "M" ], + am => "source,unary", units => [ "GP" ], + latency => 1, attr => "ir_mode *smaller_mode", init_attr => "attr->ls_mode = smaller_mode;", mode => $mode_gp, }, Conv_I2FP => { - reg_req => { in => [ "gp", "gp", "none", "gp" ], out => [ "xmm", "none" ] }, - ins => [ "base", "index", "mem", "val" ], - latency => 10, - units => [ "SSE" ], - mode => "mode_E", + state => "exc_pinned", + reg_req => { in => [ "gp", "gp", "none", "gp" ], out => [ "xmm", "none" ] }, + ins => [ "base", "index", "mem", "val" ], + am => "source,unary", + latency => 10, + units => [ "SSE" ], + mode => $mode_xmm, }, Conv_FP2I => { - reg_req => { in => [ "gp", "gp", "none", "xmm" ], out => [ "gp", "none" ] }, - ins => [ "base", "index", "mem", "val" ], - latency => 10, - units => [ "SSE" ], - mode => $mode_gp, + state => "exc_pinned", + reg_req => { in => [ "gp", "gp", "none", "xmm" ], out => [ "gp", "none" ] }, + ins => [ "base", "index", "mem", "val" ], + am => "source,unary", + latency => 10, + units => [ "SSE" ], + mode => $mode_gp, }, Conv_FP2FP => { - reg_req => { in => [ "gp", "gp", "none", "xmm" ], out => [ "xmm", "none" ] }, - ins => [ "base", "index", "mem", "val" ], - latency => 8, - units => [ "SSE" ], - mode => "mode_E", + state => "exc_pinned", + reg_req => { in => [ "gp", "gp", "none", "xmm" ], out => [ "xmm", "none" ] }, + ins => [ "base", "index", "mem", "val" ], + am => "source,unary", + latency => 8, + units => [ "SSE" ], + mode => $mode_xmm, }, #----------------------------------------------------------# @@ -1590,13 +2184,15 @@ Conv_FP2FP => { # |_| |_|\___/ \__,_|\___||___/ # #----------------------------------------------------------# -# spilling disabled for all float nodes for now, because the fpcw handler -# runs before spilling and we might end up with wrong fpcw then +# rematerialisation disabled for all float nodes for now, because the fpcw +# handler runs before spilling and we might end up with wrong fpcw then vfadd => { # irn_flags => "R", + state => "exc_pinned", reg_req => { in => [ "gp", "gp", "none", "vfp", "vfp", "fpcw" ], out => [ "vfp" ] }, ins => [ "base", "index", "mem", "left", "right", "fpcw" ], + am => "source,binary", latency => 4, units => [ "VFP" ], mode => "mode_E", @@ -1605,64 +2201,48 @@ vfadd => { vfmul => { # irn_flags => "R", + state => "exc_pinned", reg_req => { in => [ "gp", "gp", "none", "vfp", "vfp", "fpcw" ], out => [ "vfp" ] }, ins => [ "base", "index", "mem", "left", "right", "fpcw" ], + am => "source,binary", latency => 4, units => [ "VFP" ], mode => "mode_E", attr_type => "ia32_x87_attr_t", }, -l_vfmul => { - op_flags => "C", - cmp_attr => "return 1;", - arity => 2, -}, - vfsub => { # irn_flags => "R", + state => "exc_pinned", reg_req => { in => [ "gp", "gp", "none", "vfp", "vfp", "fpcw" ], out => [ "vfp" ] }, - ins => [ "base", "index", "mem", "left", "right", "fpcw" ], + ins => [ "base", "index", "mem", "minuend", "subtrahend", "fpcw" ], + am => "source,binary", latency => 4, units => [ "VFP" ], mode => "mode_E", attr_type => "ia32_x87_attr_t", }, -l_vfsub => { - cmp_attr => "return 1;", - arity => 2, -}, - vfdiv => { + state => "exc_pinned", reg_req => { in => [ "gp", "gp", "none", "vfp", "vfp", "fpcw" ], out => [ "vfp", "none" ] }, - ins => [ "base", "index", "mem", "left", "right", "fpcw" ], + ins => [ "base", "index", "mem", "dividend", "divisor", "fpcw" ], + am => "source,binary", outs => [ "res", "M" ], latency => 20, units => [ "VFP" ], attr_type => "ia32_x87_attr_t", }, -l_vfdiv => { - cmp_attr => "return 1;", - outs => [ "res", "M" ], - arity => 2, -}, - vfprem => { - reg_req => { in => [ "gp", "gp", "none", "vfp", "vfp", "fpcw" ], out => [ "vfp" ] }, - ins => [ "base", "index", "mem", "left", "right", "fpcw" ], + reg_req => { in => [ "vfp", "vfp", "fpcw" ], out => [ "vfp" ] }, + ins => [ "left", "right", "fpcw" ], latency => 20, units => [ "VFP" ], mode => "mode_E", attr_type => "ia32_x87_attr_t", }, -l_vfprem => { - cmp_attr => "return 1;", - arity => 2, -}, - vfabs => { irn_flags => "R", reg_req => { in => [ "vfp"], out => [ "vfp" ] }, @@ -1686,11 +2266,13 @@ vfchs => { # virtual Load and Store vfld => { + irn_flags => "R", op_flags => "L|F", state => "exc_pinned", - reg_req => { in => [ "gp", "gp", "none" ], out => [ "vfp", "none" ] }, + reg_req => { in => [ "gp", "gp", "none" ], + out => [ "vfp", "none", "none", "none" ] }, ins => [ "base", "index", "mem" ], - outs => [ "res", "M" ], + outs => [ "res", "unused", "M", "X_exc" ], attr => "ir_mode *load_mode", init_attr => "attr->attr.ls_mode = load_mode;", latency => 2, @@ -1699,10 +2281,13 @@ vfld => { }, vfst => { + irn_flags => "R", op_flags => "L|F", state => "exc_pinned", - reg_req => { in => [ "gp", "gp", "none", "vfp" ] }, + reg_req => { in => [ "gp", "gp", "none", "vfp" ], + out => [ "none", "none" ] }, ins => [ "base", "index", "mem", "val" ], + outs => [ "M", "X_exc" ], attr => "ir_mode *store_mode", init_attr => "attr->attr.ls_mode = store_mode;", latency => 2, @@ -1715,35 +2300,35 @@ vfst => { vfild => { state => "exc_pinned", - reg_req => { in => [ "gp", "gp", "none" ], out => [ "vfp", "none" ] }, - outs => [ "res", "M" ], + reg_req => { in => [ "gp", "gp", "none" ], + out => [ "vfp", "none", "none" ] }, + outs => [ "res", "unused", "M" ], ins => [ "base", "index", "mem" ], latency => 4, units => [ "VFP" ], attr_type => "ia32_x87_attr_t", }, -l_vfild => { - cmp_attr => "return 1;", - outs => [ "res", "M" ], - arity => 2, -}, - vfist => { state => "exc_pinned", - reg_req => { in => [ "gp", "gp", "none", "vfp", "fpcw" ] }, + reg_req => { in => [ "gp", "gp", "none", "vfp", "fpcw" ], out => [ "none" ] }, ins => [ "base", "index", "mem", "val", "fpcw" ], + outs => [ "M" ], latency => 4, units => [ "VFP" ], mode => "mode_M", attr_type => "ia32_x87_attr_t", }, -l_vfist => { - cmp_attr => "return 1;", +# SSE3 fisttp instruction +vfisttp => { state => "exc_pinned", - arity => 3, - mode => "mode_M", + reg_req => { in => [ "gp", "gp", "none", "vfp" ], out => [ "in_r4", "none" ]}, + ins => [ "base", "index", "mem", "val" ], + outs => [ "res", "M" ], + latency => 4, + units => [ "VFP" ], + attr_type => "ia32_x87_attr_t", }, @@ -1752,6 +2337,7 @@ l_vfist => { vfldz => { irn_flags => "R", reg_req => { out => [ "vfp" ] }, + outs => [ "res" ], latency => 4, units => [ "VFP" ], mode => "mode_E", @@ -1761,6 +2347,7 @@ vfldz => { vfld1 => { irn_flags => "R", reg_req => { out => [ "vfp" ] }, + outs => [ "res" ], latency => 4, units => [ "VFP" ], mode => "mode_E", @@ -1770,6 +2357,7 @@ vfld1 => { vfldpi => { irn_flags => "R", reg_req => { out => [ "vfp" ] }, + outs => [ "res" ], latency => 4, units => [ "VFP" ], mode => "mode_E", @@ -1779,6 +2367,7 @@ vfldpi => { vfldln2 => { irn_flags => "R", reg_req => { out => [ "vfp" ] }, + outs => [ "res" ], latency => 4, units => [ "VFP" ], mode => "mode_E", @@ -1788,6 +2377,7 @@ vfldln2 => { vfldlg2 => { irn_flags => "R", reg_req => { out => [ "vfp" ] }, + outs => [ "res" ], latency => 4, units => [ "VFP" ], mode => "mode_E", @@ -1797,6 +2387,7 @@ vfldlg2 => { vfldl2t => { irn_flags => "R", reg_req => { out => [ "vfp" ] }, + outs => [ "res" ], latency => 4, units => [ "VFP" ], mode => "mode_E", @@ -1806,6 +2397,7 @@ vfldl2t => { vfldl2e => { irn_flags => "R", reg_req => { out => [ "vfp" ] }, + outs => [ "res" ], latency => 4, units => [ "VFP" ], mode => "mode_E", @@ -1816,13 +2408,13 @@ vfldl2e => { vFucomFnstsw => { # we can't allow to rematerialize this node so we don't have -# accidently produce Phi(Fucom, Fucom(flipped)) +# accidently produce Phi(Fucom, Fucom(ins_permuted)) # irn_flags => "R", reg_req => { in => [ "vfp", "vfp" ], out => [ "eax" ] }, ins => [ "left", "right" ], outs => [ "flags" ], - attr => "int flipped", - init_attr => "attr->attr.data.cmp_flipped = flipped;", + attr => "int ins_permuted", + init_attr => "attr->attr.data.ins_permuted = ins_permuted;", latency => 3, units => [ "VFP" ], attr_type => "ia32_x87_attr_t", @@ -1834,8 +2426,8 @@ vFucomi => { reg_req => { in => [ "vfp", "vfp" ], out => [ "eflags" ] }, ins => [ "left", "right" ], outs => [ "flags" ], - attr => "int flipped", - init_attr => "attr->attr.data.cmp_flipped = flipped;", + attr => "int ins_permuted", + init_attr => "attr->attr.data.ins_permuted = ins_permuted;", latency => 3, units => [ "VFP" ], attr_type => "ia32_x87_attr_t", @@ -1847,8 +2439,8 @@ vFtstFnstsw => { reg_req => { in => [ "vfp" ], out => [ "eax" ] }, ins => [ "left" ], outs => [ "flags" ], - attr => "int flipped", - init_attr => "attr->attr.data.cmp_flipped = flipped;", + attr => "int ins_permuted", + init_attr => "attr->attr.data.ins_permuted = ins_permuted;", latency => 3, units => [ "VFP" ], attr_type => "ia32_x87_attr_t", @@ -1861,6 +2453,7 @@ Sahf => { ins => [ "val" ], outs => [ "flags" ], emit => '. sahf', + latency => 1, units => [ "GP" ], mode => $mode_flags, }, @@ -1877,130 +2470,143 @@ Sahf => { # are swapped, we work this around in the emitter... fadd => { - op_flags => "R", + state => "exc_pinned", rd_constructor => "NONE", reg_req => { }, emit => '. fadd%XM %x87_binop', + latency => 4, attr_type => "ia32_x87_attr_t", }, faddp => { - op_flags => "R", + state => "exc_pinned", rd_constructor => "NONE", reg_req => { }, emit => '. faddp%XM %x87_binop', + latency => 4, attr_type => "ia32_x87_attr_t", }, fmul => { - op_flags => "R", + state => "exc_pinned", rd_constructor => "NONE", reg_req => { }, emit => '. fmul%XM %x87_binop', + latency => 4, attr_type => "ia32_x87_attr_t", }, fmulp => { - op_flags => "R", + state => "exc_pinned", rd_constructor => "NONE", reg_req => { }, emit => '. fmulp%XM %x87_binop',, + latency => 4, attr_type => "ia32_x87_attr_t", }, fsub => { - op_flags => "R", + state => "exc_pinned", rd_constructor => "NONE", reg_req => { }, emit => '. fsub%XM %x87_binop', + latency => 4, attr_type => "ia32_x87_attr_t", }, fsubp => { - op_flags => "R", + state => "exc_pinned", rd_constructor => "NONE", reg_req => { }, # see note about gas bugs emit => '. fsubrp%XM %x87_binop', + latency => 4, attr_type => "ia32_x87_attr_t", }, fsubr => { - op_flags => "R", + state => "exc_pinned", rd_constructor => "NONE", irn_flags => "R", reg_req => { }, emit => '. fsubr%XM %x87_binop', + latency => 4, attr_type => "ia32_x87_attr_t", }, fsubrp => { - op_flags => "R", + state => "exc_pinned", rd_constructor => "NONE", irn_flags => "R", reg_req => { }, # see note about gas bugs emit => '. fsubp%XM %x87_binop', + latency => 4, attr_type => "ia32_x87_attr_t", }, fprem => { - op_flags => "R", rd_constructor => "NONE", reg_req => { }, emit => '. fprem1', + latency => 20, 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", reg_req => { }, - emit => '. fprem1', + emit => '. fprem1\n'. + '. fstp %X0', + latency => 20, attr_type => "ia32_x87_attr_t", }, fdiv => { - op_flags => "R", + state => "exc_pinned", rd_constructor => "NONE", reg_req => { }, emit => '. fdiv%XM %x87_binop', + latency => 20, attr_type => "ia32_x87_attr_t", }, fdivp => { - op_flags => "R", + state => "exc_pinned", rd_constructor => "NONE", reg_req => { }, # see note about gas bugs emit => '. fdivrp%XM %x87_binop', + latency => 20, attr_type => "ia32_x87_attr_t", }, fdivr => { - op_flags => "R", + state => "exc_pinned", rd_constructor => "NONE", reg_req => { }, emit => '. fdivr%XM %x87_binop', + latency => 20, attr_type => "ia32_x87_attr_t", }, fdivrp => { - op_flags => "R", + state => "exc_pinned", rd_constructor => "NONE", reg_req => { }, # see note about gas bugs emit => '. fdivp%XM %x87_binop', + latency => 20, attr_type => "ia32_x87_attr_t", }, fabs => { - op_flags => "R", rd_constructor => "NONE", reg_req => { }, emit => '. fabs', + latency => 4, attr_type => "ia32_x87_attr_t", }, @@ -2009,6 +2615,7 @@ fchs => { rd_constructor => "NONE", reg_req => { }, emit => '. fchs', + latency => 4, attr_type => "ia32_x87_attr_t", }, @@ -2021,6 +2628,7 @@ fld => { reg_req => { }, emit => '. fld%XM %AM', attr_type => "ia32_x87_attr_t", + latency => 2, }, fst => { @@ -2031,6 +2639,7 @@ fst => { emit => '. fst%XM %AM', mode => "mode_M", attr_type => "ia32_x87_attr_t", + latency => 2, }, fstp => { @@ -2041,94 +2650,114 @@ fstp => { emit => '. fstp%XM %AM', mode => "mode_M", attr_type => "ia32_x87_attr_t", + latency => 2, }, # Conversions fild => { - op_flags => "R", + state => "exc_pinned", rd_constructor => "NONE", reg_req => { }, - emit => '. fild%M %AM', + emit => '. fild%XM %AM', attr_type => "ia32_x87_attr_t", + latency => 2, }, fist => { - op_flags => "R", state => "exc_pinned", rd_constructor => "NONE", reg_req => { }, - emit => '. fist%M %AM', + emit => '. fist%XM %AM', mode => "mode_M", attr_type => "ia32_x87_attr_t", + latency => 2, }, fistp => { - op_flags => "R", state => "exc_pinned", rd_constructor => "NONE", reg_req => { }, - emit => '. fistp%M %AM', + emit => '. fistp%XM %AM', mode => "mode_M", attr_type => "ia32_x87_attr_t", + latency => 2, +}, + +# SSE3 fisttp instruction +fisttp => { + state => "exc_pinned", + rd_constructor => "NONE", + reg_req => { }, + emit => '. fisttp%XM %AM', + mode => "mode_M", + attr_type => "ia32_x87_attr_t", + latency => 2, }, # constants fldz => { op_flags => "R|c|K", - irn_flags => "R", - reg_req => { }, + irn_flags => "R", + reg_req => { out => [ "vfp" ] }, emit => '. fldz', attr_type => "ia32_x87_attr_t", + latency => 2, }, fld1 => { op_flags => "R|c|K", - irn_flags => "R", - reg_req => { }, + irn_flags => "R", + reg_req => { out => [ "vfp" ] }, emit => '. fld1', attr_type => "ia32_x87_attr_t", + latency => 2, }, fldpi => { op_flags => "R|c|K", - irn_flags => "R", - reg_req => { }, + irn_flags => "R", + reg_req => { out => [ "vfp" ] }, emit => '. fldpi', attr_type => "ia32_x87_attr_t", + latency => 2, }, fldln2 => { op_flags => "R|c|K", - irn_flags => "R", - reg_req => { }, + irn_flags => "R", + reg_req => { out => [ "vfp" ] }, emit => '. fldln2', attr_type => "ia32_x87_attr_t", + latency => 2, }, fldlg2 => { op_flags => "R|c|K", - irn_flags => "R", - reg_req => { }, + irn_flags => "R", + reg_req => { out => [ "vfp" ] }, emit => '. fldlg2', attr_type => "ia32_x87_attr_t", + latency => 2, }, fldl2t => { op_flags => "R|c|K", - irn_flags => "R", - reg_req => { }, + irn_flags => "R", + reg_req => { out => [ "vfp" ] }, emit => '. fldll2t', attr_type => "ia32_x87_attr_t", + latency => 2, }, fldl2e => { op_flags => "R|c|K", - irn_flags => "R", - reg_req => { }, + irn_flags => "R", + reg_req => { out => [ "vfp" ] }, emit => '. fldl2e', attr_type => "ia32_x87_attr_t", + latency => 2, }, # fxch, fpush, fpop @@ -2137,64 +2766,70 @@ fldl2e => { fxch => { op_flags => "R|K", - reg_req => { }, + reg_req => { out => [ "none" ] }, cmp_attr => "return 1;", emit => '. fxch %X0', attr_type => "ia32_x87_attr_t", mode => "mode_ANY", + latency => 1, }, fpush => { op_flags => "R|K", - reg_req => {}, + reg_req => { out => [ "none" ] }, cmp_attr => "return 1;", emit => '. fld %X0', attr_type => "ia32_x87_attr_t", mode => "mode_ANY", + latency => 1, }, fpushCopy => { - op_flags => "R", reg_req => { in => [ "vfp"], out => [ "vfp" ] }, cmp_attr => "return 1;", emit => '. fld %X0', attr_type => "ia32_x87_attr_t", + latency => 1, }, fpop => { op_flags => "K", - reg_req => { }, + reg_req => { out => [ "none" ] }, cmp_attr => "return 1;", emit => '. fstp %X0', attr_type => "ia32_x87_attr_t", mode => "mode_ANY", + latency => 1, }, ffreep => { op_flags => "K", - reg_req => { }, + reg_req => { out => [ "none" ] }, cmp_attr => "return 1;", emit => '. ffreep %X0', attr_type => "ia32_x87_attr_t", mode => "mode_ANY", + latency => 1, }, emms => { op_flags => "K", - reg_req => { }, + reg_req => { out => [ "none" ] }, cmp_attr => "return 1;", emit => '. emms', attr_type => "ia32_x87_attr_t", mode => "mode_ANY", + latency => 3, }, femms => { op_flags => "K", - reg_req => { }, + reg_req => { out => [ "none" ] }, cmp_attr => "return 1;", emit => '. femms', attr_type => "ia32_x87_attr_t", mode => "mode_ANY", + latency => 3, }, # compare @@ -2202,41 +2837,47 @@ femms => { FucomFnstsw => { reg_req => { }, emit => ". fucom %X1\n". - ". fnstsw", + ". fnstsw %%ax", attr_type => "ia32_x87_attr_t", + latency => 2, }, FucompFnstsw => { reg_req => { }, emit => ". fucomp %X1\n". - ". fnstsw", + ". fnstsw %%ax", attr_type => "ia32_x87_attr_t", + latency => 2, }, FucomppFnstsw => { reg_req => { }, emit => ". fucompp\n". - ". fnstsw", + ". fnstsw %%ax", attr_type => "ia32_x87_attr_t", + latency => 2, }, Fucomi => { reg_req => { }, emit => '. fucomi %X1', attr_type => "ia32_x87_attr_t", + latency => 1, }, Fucompi => { reg_req => { }, emit => '. fucompi %X1', attr_type => "ia32_x87_attr_t", + latency => 1, }, FtstFnstsw => { reg_req => { }, emit => ". ftst\n". - ". fnstsw", + ". fnstsw %%ax", attr_type => "ia32_x87_attr_t", + latency => 2, }, @@ -2259,6 +2900,7 @@ xxLoad => { emit => '. movdqu %D0, %AM', outs => [ "res", "M" ], units => [ "SSE" ], + latency => 1, }, xxStore => { @@ -2268,6 +2910,7 @@ xxStore => { ins => [ "base", "index", "mem", "val" ], emit => '. movdqu %binop', units => [ "SSE" ], + latency => 1, mode => "mode_M", }, @@ -2280,3 +2923,28 @@ unless ($return = do $my_script_name) { warn "couldn't do $my_script_name: $!" unless defined $return; warn "couldn't run $my_script_name" unless $return; } + +# Transform some attributes +foreach my $op (keys(%nodes)) { + my $node = $nodes{$op}; + my $op_attr_init = $node->{op_attr_init}; + + if(defined($op_attr_init)) { + $op_attr_init .= "\n\t"; + } else { + $op_attr_init = ""; + } + + if(!defined($node->{latency})) { + if($op =~ m/^l_/) { + $node->{latency} = 0; + } else { + die("Latency missing for op $op"); + } + } + $op_attr_init .= "attr->latency = ".$node->{latency} . ";"; + + $node->{op_attr_init} = $op_attr_init; +} + +print "";