X-Git-Url: http://nsz.repo.hu/git/?a=blobdiff_plain;f=ir%2Fbe%2Fia32%2Fia32_spec.pl;h=3355198ee4c1defa8b13f50469fcbd829c360e57;hb=b482d88d58ce6517bbb6597aa04ffa86ade5f2c9;hp=fb06c514feacb9bf36a4399bce4540275d8cd8ce;hpb=d57f9cb50b17f54d2a63a190b285467519a2af26;p=libfirm diff --git a/ir/be/ia32/ia32_spec.pl b/ir/be/ia32/ia32_spec.pl index fb06c514f..3355198ee 100644 --- a/ir/be/ia32/ia32_spec.pl +++ b/ir/be/ia32/ia32_spec.pl @@ -1,239 +1,90 @@ -# Creation: 2005/10/19 -# $Id$ # This is the specification for the ia32 assembler Firm-operations -use File::Basename; - -$new_emit_syntax = 1; -my $myname = $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: -# -# %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" }, -# ... -# ], -# 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) -# -# ); # close the %nodes initializer - -# op_flags: flags for the operation, OPTIONAL (default is "N") -# the op_flags correspond to the firm irop_flags: -# N irop_flag_none -# L irop_flag_labeled -# C irop_flag_commutative -# X irop_flag_cfopcode -# I irop_flag_ip_cfopcode -# F irop_flag_fragile -# Y irop_flag_forking -# H irop_flag_highlevel -# c irop_flag_constlike -# K irop_flag_keep -# -# 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") -# -# arity: arity of the operation, MUST NOT BE OMITTED -# -# args: the OPTIONAL arguments of the node constructor (debug, irg and block -# are always the first 3 arguments and are always autmatically -# created) -# If this key is missing the following arguments will be created: -# for i = 1 .. arity: ir_node *op_i -# ir_mode *mode -# -# 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" ] -# -# comment: OPTIONAL comment for the node constructor -# -# rd_constructor: for every operation there will be a -# new_rd__ function with the arguments from above -# which creates the ir_node corresponding to the defined operation -# you can either put the complete source code of this function here -# -# This key is OPTIONAL. If omitted, the following constructor will -# be created: -# if (!op__) assert(0); -# for i = 1 to arity -# set in[i] = op_i -# done -# res = new_ir_node(db, irg, block, op__, mode, arity, in) -# return res -# -# 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 -# +$mode_xmm = "mode_D"; +$mode_mmx = "mode_D"; +$mode_fp87 = "ia32_mode_E"; +$mode_gp = "mode_Iu"; +$mode_flags = "mode_Iu"; +$mode_fpcw = "ia32_mode_fpcw"; # 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) -# 8 - emitter can choose an arbitrary register of this class -# 16 - the register is a virtual one -# 32 - register represents a state +$normal = 0; # no special type +$ignore = 1; # ignore (do not assign this register) +$arbitrary = 2; # emitter can choose an arbitrary register of this class +$virtual = 4; # the register is a virtual one +$state = 8; # 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 => "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" } + { name => "edx" }, + { name => "ecx" }, + { name => "eax" }, + { name => "ebx" }, + { name => "esi" }, + { name => "edi" }, + { name => "ebp" }, + { name => "esp", type => $ignore }, + { name => "gp_NOREG", type => $ignore | $arbitrary | $virtual }, # we need a dummy register for NoReg nodes + { mode => $mode_gp } ], 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" } + { name => "mm0", type => $ignore }, + { name => "mm1", type => $ignore }, + { name => "mm2", type => $ignore }, + { name => "mm3", type => $ignore }, + { name => "mm4", type => $ignore }, + { name => "mm5", type => $ignore }, + { name => "mm6", type => $ignore }, + { name => "mm7", type => $ignore }, + { mode => $mode_mmx, 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" } + { name => "xmm0" }, + { name => "xmm1" }, + { name => "xmm2" }, + { name => "xmm3" }, + { name => "xmm4" }, + { name => "xmm5" }, + { name => "xmm6" }, + { name => "xmm7" }, + { name => "xmm_NOREG", type => $ignore | $virtual }, # we need a dummy register for NoReg nodes + { mode => $mode_xmm } ], 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" } + { name => "vf0" }, + { name => "vf1" }, + { name => "vf2" }, + { name => "vf3" }, + { name => "vf4" }, + { name => "vf5" }, + { name => "vf6" }, + { name => "vf7" }, + { name => "vfp_NOREG", type => $ignore | $arbitrary | $virtual }, # we need a dummy register for NoReg nodes + { mode => $mode_fp87 } ], 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" } + { name => "st0", realname => "st", type => $ignore }, + { name => "st1", realname => "st(1)", type => $ignore }, + { name => "st2", realname => "st(2)", type => $ignore }, + { name => "st3", realname => "st(3)", type => $ignore }, + { name => "st4", realname => "st(4)", type => $ignore }, + { name => "st5", realname => "st(5)", type => $ignore }, + { name => "st6", realname => "st(6)", type => $ignore }, + { name => "st7", realname => "st(7)", type => $ignore }, + { mode => $mode_fp87, flags => "manual_ra" } ], fp_cw => [ # the floating point control word - { name => "fpcw", type => 4 | 32}, - { mode => "mode_fpcw" } + { name => "fpcw", type => $ignore | $state }, + { mode => $mode_fpcw, flags => "manual_ra|state" } ], flags => [ - { name => "eflags", type => 4 }, - { mode => "mode_Iu" } - ], - fp_sw => [ - { name => "fpsw", type => 4 }, - { mode => "mode_Hu" } + { name => "eflags", type => 0 }, + { mode => "mode_Iu", flags => "manual_ra" } ], ); # %reg_classes -%flags = ( - CF => { reg => "eflags", bit => 0 }, - PF => { reg => "eflags", bit => 2 }, - AF => { reg => "eflags", bit => 4 }, - ZF => { reg => "eflags", bit => 6 }, - SF => { reg => "eflags", bit => 7 }, - TF => { reg => "eflags", bit => 8 }, - IF => { reg => "eflags", bit => 9 }, - DF => { reg => "eflags", bit => 10 }, - OF => { reg => "eflags", bit => 11 }, - IOPL0 => { reg => "eflags", bit => 12 }, - IOPL1 => { reg => "eflags", bit => 13 }, - NT => { reg => "eflags", bit => 14 }, - RF => { reg => "eflags", bit => 16 }, - VM => { reg => "eflags", bit => 17 }, - AC => { reg => "eflags", bit => 18 }, - VIF => { reg => "eflags", bit => 19 }, - VIP => { reg => "eflags", bit => 20 }, - ID => { reg => "eflags", bit => 21 }, - - FP_IE => { reg => "fpsw", bit => 0 }, - FP_DE => { reg => "fpsw", bit => 1 }, - FP_ZE => { reg => "fpsw", bit => 2 }, - FP_OE => { reg => "fpsw", bit => 3 }, - FP_UE => { reg => "fpsw", bit => 4 }, - FP_PE => { reg => "fpsw", bit => 5 }, - FP_SF => { reg => "fpsw", bit => 6 }, - FP_ES => { reg => "fpsw", bit => 7 }, - FP_C0 => { reg => "fpsw", bit => 8 }, - FP_C1 => { reg => "fpsw", bit => 9 }, - FP_C2 => { reg => "fpsw", bit => 10 }, - FP_TOP0 => { reg => "fpsw", bit => 11 }, - FP_TOP1 => { reg => "fpsw", bit => 12 }, - FP_TOP2 => { reg => "fpsw", bit => 13 }, - FP_C3 => { reg => "fpsw", bit => 14 }, - FP_B => { reg => "fpsw", bit => 15 }, - - FP_IM => { reg => "fpcw", bit => 0 }, - FP_DM => { reg => "fpcw", bit => 1 }, - FP_ZM => { reg => "fpcw", bit => 2 }, - FP_OM => { reg => "fpcw", bit => 3 }, - FP_UM => { reg => "fpcw", bit => 4 }, - FP_PM => { reg => "fpcw", bit => 5 }, - FP_PC0 => { reg => "fpcw", bit => 8 }, - FP_PC1 => { reg => "fpcw", bit => 9 }, - FP_RC0 => { reg => "fpcw", bit => 10 }, - FP_RC1 => { reg => "fpcw", bit => 11 }, - FP_X => { reg => "fpcw", bit => 12 } -); # %flags - %cpu = ( 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" ], @@ -247,95 +98,137 @@ $arch = "ia32"; ); # vliw %emit_templates = ( - S0 => "${arch}_emit_source_register(env, node, 0);", - S1 => "${arch}_emit_source_register(env, node, 1);", - S2 => "${arch}_emit_source_register(env, node, 2);", - S3 => "${arch}_emit_source_register(env, node, 3);", - S4 => "${arch}_emit_source_register(env, node, 4);", - S5 => "${arch}_emit_source_register(env, node, 5);", - D0 => "${arch}_emit_dest_register(env, node, 0);", - D1 => "${arch}_emit_dest_register(env, node, 1);", - D2 => "${arch}_emit_dest_register(env, node, 2);", - D3 => "${arch}_emit_dest_register(env, node, 3);", - D4 => "${arch}_emit_dest_register(env, node, 4);", - D5 => "${arch}_emit_dest_register(env, node, 5);", - X0 => "${arch}_emit_x87_name(env, node, 0);", - X1 => "${arch}_emit_x87_name(env, node, 1);", - X2 => "${arch}_emit_x87_name(env, node, 2);", - C => "${arch}_emit_immediate(env, node);", - SE => "${arch}_emit_extend_suffix(env, get_ia32_ls_mode(node));", - ME => "if(get_mode_size_bits(get_ia32_ls_mode(node)) != 32)\n - ia32_emit_mode_suffix(env, node);", - M => "${arch}_emit_mode_suffix(env, node);", - XM => "${arch}_emit_x87_mode_suffix(env, node);", - XXM => "${arch}_emit_xmm_mode_suffix(env, node);", - XSD => "${arch}_emit_xmm_mode_suffix_s(env, node);", - AM => "${arch}_emit_am(env, node);", - unop0 => "${arch}_emit_unop(env, node, 0);", - unop1 => "${arch}_emit_unop(env, node, 1);", - unop2 => "${arch}_emit_unop(env, node, 2);", - unop3 => "${arch}_emit_unop(env, node, 3);", - unop4 => "${arch}_emit_unop(env, node, 4);", - DAM0 => "${arch}_emit_am_or_dest_register(env, node, 0);", - DAM1 => "${arch}_emit_am_or_dest_register(env, node, 0);", - binop => "${arch}_emit_binop(env, node);", - x87_binop => "${arch}_emit_x87_binop(env, node);", + 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);", + 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);", + 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);", + 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, 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);", + CMP3 => "${arch}_emit_cmp_suffix_node(node, 3);", ); -#--------------------------------------------------# -# _ # -# (_) # -# _ __ _____ __ _ _ __ ___ _ __ ___ # -# | '_ \ / _ \ \ /\ / / | | '__| / _ \| '_ \/ __| # -# | | | | __/\ V V / | | | | (_) | |_) \__ \ # -# |_| |_|\___| \_/\_/ |_|_| \___/| .__/|___/ # -# | | # -# |_| # -#--------------------------------------------------# -$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 $constr = shift; + my $node = shift; + my $name = shift; + my $res = ""; + + if(defined($node->{modified_flags})) { + $res .= "\tarch_add_irn_flags(res, arch_irn_flags_modify_flags);\n"; + } + if(defined($node->{am})) { + my $am = $node->{am}; + 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_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, irn_flags_, in_reqs, n_res);\n". "\tinit_ia32_x87_attributes(res);". "\tinit_ia32_asm_attributes(res);", + ia32_attr_t => + "\tinit_ia32_attributes(res, irn_flags_, in_reqs, n_res);", + ia32_call_attr_t => + "\tinit_ia32_attributes(res, irn_flags_, in_reqs, n_res);\n". + "\tinit_ia32_call_attributes(res, pop, call_tp);", + ia32_condcode_attr_t => + "\tinit_ia32_attributes(res, irn_flags_, in_reqs, n_res);\n". + "\tinit_ia32_condcode_attributes(res, condition_code);", + ia32_switch_attr_t => + "\tinit_ia32_attributes(res, irn_flags_, in_reqs, n_res);\n". + "\tinit_ia32_switch_attributes(res, switch_table);", + ia32_copyb_attr_t => + "\tinit_ia32_attributes(res, irn_flags_, in_reqs, 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, irn_flags_, in_reqs, n_res);\n". + "\tinit_ia32_immediate_attributes(res, symconst, symconst_sign, no_pic_adjust, offset);", + ia32_x87_attr_t => + "\tinit_ia32_attributes(res, irn_flags_, in_reqs, n_res);\n". + "\tinit_ia32_x87_attributes(res);", + ia32_climbframe_attr_t => + "\tinit_ia32_attributes(res, irn_flags_, in_reqs, 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_asm_attr_t => "ia32_compare_asm_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_switch_attr_t => "ia32_compare_nodes_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_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" ]; +$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", + op_flags => [ "constlike" ], + irn_flags => [ "not_scheduled" ], + 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, }, @@ -344,100 +237,122 @@ Asm => { arity => "variable", out_arity => "variable", attr_type => "ia32_asm_attr_t", + 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, }, -#-----------------------------------------------------------------# -# _ _ _ # -# (_) | | | | # -# _ _ __ | |_ ___ __ _ ___ _ __ _ __ ___ __| | ___ ___ # -# | | '_ \| __/ _ \/ _` |/ _ \ '__| | '_ \ / _ \ / _` |/ _ \/ __| # -# | | | | | || __/ (_| | __/ | | | | | (_) | (_| | __/\__ \ # -# |_|_| |_|\__\___|\__, |\___|_| |_| |_|\___/ \__,_|\___||___/ # -# __/ | # -# |___/ # -#-----------------------------------------------------------------# - -# 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 +# "allocates" a free register +ProduceVal => { + op_flags => [ "constlike", "cse_neutral" ], + irn_flags => [ "rematerializable" ], + reg_req => { out => [ "gp" ] }, + emit => "", + units => [ ], + latency => 0, + mode => $mode_gp, + cmp_attr => "return 1;", +}, Add => { - irn_flags => "R", - reg_req => { in => [ "gp", "gp", "gp", "gp", "none" ], out => [ "in_r3" ] }, - ins => [ "base", "index", "left", "right", "mem" ], + irn_flags => [ "rematerializable" ], + 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 => "source,binary", units => [ "GP" ], + latency => 1, mode => $mode_gp, modified_flags => $status_flags }, -Adc => { - reg_req => { in => [ "gp", "gp", "gp", "gp", "none" ], out => [ "in_r3" ] }, - emit => '. adc%M %binop', +AddMem => { + irn_flags => [ "rematerializable" ], + state => "exc_pinned", + reg_req => { in => [ "gp", "gp", "none", "gp" ], out => [ "none" ] }, + ins => [ "base", "index", "mem", "val" ], + emit => ". add%M %SI3, %AM", units => [ "GP" ], - mode => $mode_gp, + latency => 1, + mode => "mode_M", modified_flags => $status_flags }, -Add64Bit => { - irn_flags => "R", - arity => 4, - reg_req => { in => [ "gp", "gp", "gp", "gp" ], out => [ "!in", "!in" ] }, - emit => ' -. movl %S0, %D0 -. movl %S1, %D1 -. addl %S2, %D0 -. adcl %S3, %D1 -', - outs => [ "low_res", "high_res" ], +AddMem8Bit => { + irn_flags => [ "rematerializable" ], + 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 => { + 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 => "source,binary", + units => [ "GP" ], + latency => 1, + mode => $mode_gp, modified_flags => $status_flags }, l_Add => { - op_flags => "C", - irn_flags => "R", - cmp_attr => "return 1;", - arity => 2, + ins => [ "left", "right" ], + attr_type => "", + dump_func => "NULL", }, l_Adc => { - op_flags => "C", - cmp_attr => "return 1;", - arity => 2, + ins => [ "left", "right", "eflags" ], + attr_type => "", + dump_func => "NULL", }, Mul => { # we should not rematrialize this node. It produces 2 results and has - # very strict constrains - reg_req => { in => [ "gp", "gp", "eax", "gp", "none" ], out => [ "eax", "edx", "none" ] }, - emit => '. mul%M %unop3', - outs => [ "EAX", "EDX", "M" ], - ins => [ "base", "index", "val_high", "val_low", "mem" ], + # 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 => [ "res_low", "flags", "M", "res_high" ], + 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 + ins => [ "left", "right" ], + outs => [ "res_low", "flags", "M", "res_high" ], + attr_type => "", + dump_func => "NULL", }, IMul => { - irn_flags => "R", - reg_req => { in => [ "gp", "gp", "gp", "gp", "none" ], out => [ "in_r3" ] }, - emit => '. imul%M %binop', + irn_flags => [ "rematerializable" ], + 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" ], + outs => [ "res", "flags", "M" ], + am => "source,binary", latency => 5, units => [ "GP" ], mode => $mode_gp, @@ -445,454 +360,786 @@ IMul => { }, IMul1OP => { - irn_flags => "R", - reg_req => { in => [ "gp", "gp", "eax", "gp", "none" ], out => [ "eax", "edx", "none" ] }, - emit => '. imul%M %unop3', - outs => [ "EAX", "EDX", "M" ], - ins => [ "base", "index", "val_high", "val_low", "mem" ], + irn_flags => [ "rematerializable" ], + 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 => [ "res_low", "flags", "M", "res_high" ], + am => "source,binary", latency => 5, units => [ "GP" ], modified_flags => $status_flags }, l_IMul => { - op_flags => "C", - cmp_attr => "return 1;", - arity => 2 + ins => [ "left", "right" ], + outs => [ "res_low", "flags", "M", "res_high" ], + attr_type => "", + dump_func => "NULL", }, And => { - irn_flags => "R", - reg_req => { in => [ "gp", "gp", "gp", "gp", "none" ], out => [ "in_r3" ] }, + irn_flags => [ "rematerializable" ], + 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" ], + am => "source,binary", emit => '. and%M %binop', units => [ "GP" ], + latency => 1, mode => $mode_gp, modified_flags => $status_flags }, +AndMem => { + irn_flags => [ "rematerializable" ], + 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 => [ "rematerializable" ], + 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", "gp", "gp", "none" ], out => [ "in_r3" ] }, + irn_flags => [ "rematerializable" ], + 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" ], + am => "source,binary", emit => '. or%M %binop', units => [ "GP" ], + latency => 1, mode => $mode_gp, modified_flags => $status_flags }, +OrMem => { + irn_flags => [ "rematerializable" ], + 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 => [ "rematerializable" ], + 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", "gp", "gp", "none" ], out => [ "in_r3" ] }, + irn_flags => [ "rematerializable" ], + 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" ], + am => "source,binary", emit => '. xor%M %binop', units => [ "GP" ], + latency => 1, mode => $mode_gp, modified_flags => $status_flags }, -l_Xor => { - op_flags => "C", - cmp_attr => "return 1;", - arity => 2, +Xor0 => { + op_flags => [ "constlike" ], + irn_flags => [ "rematerializable" ], + 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 => [ "rematerializable" ], + 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 }, -# not commutative operations +XorMem8Bit => { + irn_flags => [ "rematerializable" ], + 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 +}, Sub => { - irn_flags => "R", - reg_req => { in => [ "gp", "gp", "gp", "gp", "none" ], out => [ "in_r3" ] }, + irn_flags => [ "rematerializable" ], + 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 => [ "rematerializable" ], + state => "exc_pinned", + reg_req => { in => [ "gp", "gp", "none", "gp" ], out => [ "none" ] }, + ins => [ "base", "index", "mem", "subtrahend" ], + emit => '. sub%M %SI3, %AM', + units => [ "GP" ], + latency => 1, + mode => 'mode_M', + modified_flags => $status_flags +}, + +SubMem8Bit => { + irn_flags => [ "rematerializable" ], + state => "exc_pinned", + reg_req => { in => [ "gp", "gp", "none", "eax ebx ecx edx" ], out => [ "none" ] }, + 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", "gp", "gp", "none" ], out => [ "in_r3 !in_r4" ] }, + state => "exc_pinned", + reg_req => { in => [ "gp", "gp", "none", "gp", "gp", "flags" ], + out => [ "in_r4", "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 }, -Sub64Bit => { - irn_flags => "R", - arity => 4, - reg_req => { in => [ "gp", "gp", "gp", "gp" ], out => [ "!in", "!in" ] }, - emit => ' -. movl %S0, %D0 -. movl %S1, %D1 -. subl %S2, %D0 -. sbbl %S3, %D1 -', - outs => [ "low_res", "high_res" ], +Sbb0 => { + # Spiller currently fails when rematerializing flag consumers + # irn_flags => [ "rematerializable" ], + 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 => { - irn_flags => "R", - cmp_attr => "return 1;", - arity => 2, + ins => [ "minuend", "subtrahend" ], + attr_type => "", + dump_func => "NULL", }, l_Sbb => { - cmp_attr => "return 1;", - arity => 2, + ins => [ "minuend", "subtrahend", "eflags" ], + attr_type => "", + dump_func => "NULL", }, IDiv => { - op_flags => "F|L", + op_flags => [ "fragile", "uses_memory", "labeled" ], state => "exc_pinned", - reg_req => { in => [ "gp", "gp", "eax", "edx", "gp", "none" ], out => [ "eax", "edx", "none" ] }, - attr => "ia32_op_flavour_t dm_flav", - init_attr => "attr->data.op_flav = dm_flav;", - emit => ". idiv%M %unop4", - outs => [ "div_res", "mod_res", "M" ], + reg_req => { in => [ "gp", "gp", "none", "gp", "eax", "edx" ], + out => [ "eax", "flags", "none", "edx", "none", "none" ] }, + ins => [ "base", "index", "mem", "divisor", "dividend_low", "dividend_high" ], + outs => [ "div_res", "flags", "M", "mod_res", "X_regular", "X_except" ], + am => "source,unary", + emit => ". idiv%M %unop3", latency => 25, units => [ "GP" ], modified_flags => $status_flags }, Div => { - op_flags => "F|L", + op_flags => [ "fragile", "uses_memory", "labeled" ], state => "exc_pinned", - reg_req => { in => [ "gp", "gp", "eax", "edx", "gp", "none" ], out => [ "eax", "edx", "none" ] }, - attr => "ia32_op_flavour_t dm_flav", - init_attr => "attr->data.op_flav = dm_flav;", - emit => ". div%M %unop4", - outs => [ "div_res", "mod_res", "M" ], + reg_req => { in => [ "gp", "gp", "none", "gp", "eax", "edx" ], + out => [ "eax", "flags", "none", "edx", "none", "none" ] }, + ins => [ "base", "index", "mem", "divisor", "dividend_low", "dividend_high" ], + outs => [ "div_res", "flags", "M", "mod_res", "X_regular", "X_except" ], + am => "source,unary", + emit => ". div%M %unop3", latency => 25, units => [ "GP" ], modified_flags => $status_flags }, Shl => { - irn_flags => "R", - # "in_r3" would be enough as out requirement, but the register allocator - # does strange things then and doesn't respect the constraint for in4 - # if the same value is attached to in3 and in4 (if you have "i << i" in C) - reg_req => { in => [ "gp", "gp", "gp", "ecx", "none" ], out => [ "in_r3 !in_r4" ] }, - ins => [ "base", "index", "left", "right", "mem" ], - emit => '. shl%M %binop', + irn_flags => [ "rematerializable" ], + 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 }, -l_Shl => { - cmp_attr => "return 1;", - arity => 2 +ShlMem => { + irn_flags => [ "rematerializable" ], + 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 }, ShlD => { - irn_flags => "R", - # Out requirements is: different from all in - # This is because, out must be different from LowPart and ShiftCount. - # We could say "!ecx !in_r4" but it can occur, that all values live through - # this Shift and the only value dying is the ShiftCount. Then there would be - # a register missing, as result must not be ecx and all other registers are - # occupied. What we should write is "!in_r4 !in_r5", but this is not - # supported (and probably never will). So we create artificial interferences - # of the result with all inputs, so the spiller can always assure a free - # register. - reg_req => { in => [ "gp", "gp", "gp", "gp", "ecx", "none" ], out => [ "!in" ] }, - emit => -' -if (get_ia32_immop_type(node) == ia32_ImmNone) { - if (get_ia32_op_type(node) == ia32_AddrModeD) { - . shld%M %%cl, %S3, %AM - } else { - . shld%M %%cl, %S3, %S2 - } -} else { - if (get_ia32_op_type(node) == ia32_AddrModeD) { - . shld%M %C, %S3, %AM - } else { - . shld%M %C, %S3, %S2 - } -} -', + irn_flags => [ "rematerializable" ], + 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, modified_flags => $status_flags }, -l_ShlD => { - cmp_attr => "return 1;", - arity => 3, -}, - Shr => { - irn_flags => "R", - reg_req => { in => [ "gp", "gp", "gp", "ecx", "none" ], out => [ "in_r3 !in_r4" ] }, - emit => '. shr%M %binop', + irn_flags => [ "rematerializable" ], + reg_req => { in => [ "gp", "ecx" ], + out => [ "in_r1 !in_r2", "flags" ] }, + ins => [ "val", "count" ], + outs => [ "res", "flags" ], + emit => '. shr%M %SB1, %S0', units => [ "GP" ], mode => $mode_gp, + latency => 1, modified_flags => $status_flags }, -l_Shr => { - cmp_attr => "return 1;", - arity => 2 +ShrMem => { + irn_flags => [ "rematerializable" ], + 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 }, ShrD => { - irn_flags => "R", - # Out requirements is: different from all in - # This is because, out must be different from LowPart and ShiftCount. - # We could say "!ecx !in_r4" but it can occur, that all values live through - # this Shift and the only value dying is the ShiftCount. Then there would be a - # register missing, as result must not be ecx and all other registers are - # occupied. What we should write is "!in_r4 !in_r5", but this is not supported - # (and probably never will). So we create artificial interferences of the result - # with all inputs, so the spiller can always assure a free register. - reg_req => { in => [ "gp", "gp", "gp", "gp", "ecx", "none" ], out => [ "!in" ] }, - emit => ' -if (get_ia32_immop_type(node) == ia32_ImmNone) { - if (get_ia32_op_type(node) == ia32_AddrModeD) { - . shrd%M %%cl, %S3, %AM - } else { - . shrd%M %%cl, %S3, %S2 - } -} else { - if (get_ia32_op_type(node) == ia32_AddrModeD) { - . shrd%M %C, %S3, %AM - } else { - . shrd%M %C, %S3, %S2 - } -} -', + irn_flags => [ "rematerializable" ], + 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, modified_flags => $status_flags }, -l_ShrD => { - cmp_attr => "return 1;", - arity => 3 -}, - Sar => { - irn_flags => "R", - reg_req => { in => [ "gp", "gp", "gp", "ecx", "none" ], out => [ "in_r3 !in_r4" ] }, - emit => '. sar%M %binop', + irn_flags => [ "rematerializable" ], + reg_req => { in => [ "gp", "ecx" ], + out => [ "in_r1 !in_r2", "flags" ] }, + ins => [ "val", "count" ], + outs => [ "res", "flags" ], + emit => '. sar%M %SB1, %S0', units => [ "GP" ], + latency => 1, mode => $mode_gp, modified_flags => $status_flags }, -l_Sar => { - cmp_attr => "return 1;", - arity => 2 +SarMem => { + irn_flags => [ "rematerializable" ], + 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 }, Ror => { - irn_flags => "R", - reg_req => { in => [ "gp", "gp", "gp", "ecx", "none" ], out => [ "in_r3 !in_r4" ] }, - emit => '. ror%M %binop', + irn_flags => [ "rematerializable" ], + reg_req => { in => [ "gp", "ecx" ], + out => [ "in_r1 !in_r2", "flags" ] }, + ins => [ "val", "count" ], + outs => [ "res", "flags" ], + emit => '. ror%M %SB1, %S0', units => [ "GP" ], + latency => 1, mode => $mode_gp, modified_flags => $status_flags }, +RorMem => { + irn_flags => [ "rematerializable" ], + 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", "gp", "gp", "ecx", "none" ], out => [ "in_r3 !in_r4" ] }, - emit => '. rol%M %binop', + irn_flags => [ "rematerializable" ], + reg_req => { in => [ "gp", "ecx" ], + out => [ "in_r1 !in_r2", "flags" ] }, + ins => [ "val", "count" ], + outs => [ "res", "flags" ], + emit => '. rol%M %SB1, %S0', units => [ "GP" ], + latency => 1, mode => $mode_gp, modified_flags => $status_flags }, -# unary operations +RolMem => { + irn_flags => [ "rematerializable" ], + 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 +}, Neg => { - irn_flags => "R", - reg_req => { in => [ "gp", "gp", "gp", "none" ], out => [ "in_r3" ] }, - emit => '. neg%M %unop2', - ins => [ "base", "index", "val", "mem" ], + irn_flags => [ "rematerializable" ], + reg_req => { in => [ "gp" ], + out => [ "in_r1", "flags" ] }, + emit => '. neg%M %S0', + ins => [ "val" ], + outs => [ "res", "flags" ], units => [ "GP" ], + latency => 1, mode => $mode_gp, modified_flags => $status_flags }, +NegMem => { + irn_flags => [ "rematerializable" ], + 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", "gp" ], out => [ "!in", "!in" ] }, - emit => ' -. movl %S0, %D0 -. movl %S0, %D1 -. subl %S1, %D0 -. sbbl %S2, %D1 -', + irn_flags => [ "rematerializable" ], + 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", "gp", "gp", "none" ], out => [ "in_r3" ] }, - emit => '. inc%M %unop2', + irn_flags => [ "rematerializable" ], + 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 => [ "rematerializable" ], + state => "exc_pinned", + reg_req => { in => [ "gp", "gp", "none" ], out => [ "none" ] }, + ins => [ "base", "index", "mem" ], + emit => '. inc%M %AM', + units => [ "GP" ], + mode => "mode_M", + latency => 1, + modified_flags => $status_flags_wo_cf }, Dec => { - irn_flags => "R", - reg_req => { in => [ "gp", "gp", "gp", "none" ], out => [ "in_r3" ] }, - emit => '. dec%M %unop2', + irn_flags => [ "rematerializable" ], + 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 => [ "rematerializable" ], + state => "exc_pinned", + reg_req => { in => [ "gp", "gp", "none" ], out => [ "none" ] }, + ins => [ "base", "index", "mem" ], + emit => '. dec%M %AM', + units => [ "GP" ], + mode => "mode_M", + latency => 1, + modified_flags => $status_flags_wo_cf }, Not => { - irn_flags => "R", - reg_req => { in => [ "gp", "gp", "gp", "none" ], out => [ "in_r3" ] }, - ins => [ "base", "index", "val", "mem" ], - emit => '. not%M %unop2', + irn_flags => [ "rematerializable" ], + reg_req => { in => [ "gp" ], + out => [ "in_r1" ] }, + ins => [ "val" ], + outs => [ "res" ], + emit => '. not%M %S0', units => [ "GP" ], + latency => 1, mode => $mode_gp, - modified_flags => [] + # no flags modified }, -# other operations - -CondJmp => { - state => "pinned", - op_flags => "L|X|Y", - reg_req => { in => [ "gp", "gp", "gp", "gp", "none" ], - out => [ "none", "none"] }, - ins => [ "base", "index", "left", "right", "mem" ], - outs => [ "false", "true" ], - attr => "long pnc", - init_attr => "attr->pn_code = pnc;", - latency => 3, - units => [ "BRANCH" ], +NotMem => { + irn_flags => [ "rematerializable" ], + 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 }, -TestJmp => { - state => "pinned", - op_flags => "L|X|Y", - reg_req => { in => [ "gp", "gp", "gp", "gp", "none" ], - out => [ "none", "none" ] }, - ins => [ "base", "index", "left", "right", "mem" ], - outs => [ "false", "true" ], - attr => "long pnc", - init_attr => "attr->pn_code = pnc;", - latency => 3, - units => [ "BRANCH" ], +Cmc => { + reg_req => { in => [ "flags" ], out => [ "flags" ] }, + emit => '.cmc', + units => [ "GP" ], + latency => 1, + mode => $mode_flags, + modified_flags => $status_flags }, -CJmpAM => { - state => "pinned", - op_flags => "L|X|Y", - reg_req => { in => [ "gp", "gp", "gp", "gp", "none" ], out => [ "none", "none" ] }, - outs => [ "false", "true" ], - units => [ "BRANCH" ], +Stc => { + reg_req => { out => [ "flags" ] }, + emit => '.stc', + units => [ "GP" ], + latency => 1, + mode => $mode_flags, + modified_flags => $status_flags }, -CJmp => { - state => "pinned", - op_flags => "L|X|Y", - reg_req => { in => [ "gp", "gp" ] }, - units => [ "BRANCH" ], +Cmp => { + irn_flags => [ "rematerializable" ], + state => "exc_pinned", + reg_req => { in => [ "gp", "gp", "none", "gp", "gp" ], + out => [ "flags", "none", "none" ] }, + ins => [ "base", "index", "mem", "left", "right" ], + outs => [ "eflags", "unused", "M" ], + am => "source,binary", + emit => '. cmp%M %binop', + attr => "bool ins_permuted", + init_attr => "attr->data.ins_permuted = ins_permuted;", + latency => 1, + units => [ "GP" ], + mode => $mode_flags, + modified_flags => $status_flags }, -SwitchJmp => { - state => "pinned", - op_flags => "L|X|Y", - reg_req => { in => [ "gp" ], out => [ "none" ] }, - latency => 3, - units => [ "BRANCH" ], - mode => "mode_T", +Cmp8Bit => { + irn_flags => [ "rematerializable" ], + 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", "unused", "M" ], + am => "source,binary", + emit => '. cmpb %binop', + attr => "bool ins_permuted", + init_attr => "attr->data.ins_permuted = ins_permuted;", + latency => 1, + units => [ "GP" ], + mode => $mode_flags, + modified_flags => $status_flags }, -Const => { - op_flags => "c", - irn_flags => "R", - reg_req => { out => [ "gp" ] }, +XorHighLow => { + irn_flags => [ "rematerializable" ], + state => "exc_pinned", + reg_req => { in => [ "eax ebx ecx edx" ], + out => [ "in_r1", "flags" ] }, + emit => '. xorb %SH0, %SB0', + ins => [ "value" ], + outs => [ "res", "flags" ], units => [ "GP" ], + latency => 1, mode => $mode_gp, + modified_flags => $status_flags, }, -Unknown_GP => { - state => "pinned", - op_flags => "c", - irn_flags => "I", - reg_req => { out => [ "gp_UKNWN" ] }, - units => [], - emit => "", - mode => $mode_gp +Test => { + irn_flags => [ "rematerializable" ], + state => "exc_pinned", + reg_req => { in => [ "gp", "gp", "none", "gp", "gp" ] , + out => [ "flags", "none", "none" ] }, + ins => [ "base", "index", "mem", "left", "right" ], + outs => [ "eflags", "unused", "M" ], + am => "source,binary", + emit => '. test%M %binop', + attr => "bool ins_permuted", + init_attr => "attr->data.ins_permuted = ins_permuted;", + latency => 1, + units => [ "GP" ], + mode => $mode_flags, + modified_flags => $status_flags }, -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", +Test8Bit => { + irn_flags => [ "rematerializable" ], + 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", "unused", "M" ], + am => "source,binary", + emit => '. testb %binop', + attr => "bool ins_permuted", + init_attr => "attr->data.ins_permuted = ins_permuted;", + latency => 1, + units => [ "GP" ], + mode => $mode_flags, + modified_flags => $status_flags }, -Unknown_XMM => { - state => "pinned", - op_flags => "c", - irn_flags => "I", - reg_req => { out => [ "xmm_UKNWN" ] }, - units => [], - emit => "", - mode => "mode_E" +Setcc => { + #irn_flags => [ "rematerializable" ], + reg_req => { in => [ "eflags" ], out => [ "eax ebx ecx edx" ] }, + ins => [ "eflags" ], + outs => [ "res" ], + attr_type => "ia32_condcode_attr_t", + attr => "ia32_condition_code_t condition_code", + # The way we handle Setcc with float nodes (potentially) destroys the flags + # (when we emit the setX; setp; orb and the setX;setnp;andb sequences) + init_attr => "set_ia32_ls_mode(res, mode_Bu);\n" + . "\tif (condition_code & ia32_cc_additional_float_cases) {\n" + . "\t\tarch_add_irn_flags(res, arch_irn_flags_modify_flags);\n" + . "\t\t/* attr->latency = 3; */\n" + . "\t}\n", + latency => 1, + units => [ "GP" ], + mode => $mode_gp, }, -NoReg_GP => { - state => "pinned", - op_flags => "c", - irn_flags => "I", - reg_req => { out => [ "gp_NOREG" ] }, - units => [], - emit => "", - mode => $mode_gp +SetccMem => { + #irn_flags => [ "rematerializable" ], + state => "exc_pinned", + reg_req => { in => [ "gp", "gp", "none", "eflags" ], out => [ "none" ] }, + ins => [ "base", "index", "mem","eflags" ], + attr_type => "ia32_condcode_attr_t", + attr => "ia32_condition_code_t condition_code", + init_attr => "set_ia32_ls_mode(res, mode_Bu);\n", + emit => '. set%CMP3 %AM', + latency => 1, + units => [ "GP" ], + mode => 'mode_M', +}, + +CMovcc => { + #irn_flags => [ "rematerializable" ], + state => "exc_pinned", + # (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 in_r5", "flags", "none" ] }, + ins => [ "base", "index", "mem", "val_false", "val_true", "eflags" ], + outs => [ "res", "flags", "M" ], + am => "source,binary", + attr_type => "ia32_condcode_attr_t", + attr => "ia32_condition_code_t condition_code", + latency => 1, + units => [ "GP" ], + mode => $mode_gp, +}, + +Jcc => { + state => "pinned", + op_flags => [ "labeled", "cfopcode", "forking" ], + reg_req => { in => [ "eflags" ], out => [ "none", "none" ] }, + ins => [ "eflags" ], + outs => [ "false", "true" ], + attr_type => "ia32_condcode_attr_t", + attr => "ia32_condition_code_t condition_code", + latency => 2, + units => [ "BRANCH" ], +}, + +SwitchJmp => { + state => "pinned", + op_flags => [ "labeled", "cfopcode", "forking" ], + reg_req => { in => [ "gp", "gp" ] }, + ins => [ "base", "index" ], + out_arity => "variable", + attr_type => "ia32_switch_attr_t", + attr => "const ir_switch_table *switch_table", + latency => 2, + units => [ "BRANCH" ], +}, + +Jmp => { + state => "pinned", + irn_flags => [ "simple_jump" ], + op_flags => [ "cfopcode" ], + reg_req => { out => [ "none" ] }, + latency => 1, + units => [ "BRANCH" ], + mode => "mode_X", +}, + +IJmp => { + state => "pinned", + op_flags => [ "cfopcode", "unknown_jump" ], + 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 => { + op_flags => [ "constlike" ], + irn_flags => [ "rematerializable" ], + reg_req => { out => [ "gp" ] }, + units => [ "GP" ], + attr => "ir_entity *symconst, int symconst_sign, int no_pic_adjust, long offset", + attr_type => "ia32_immediate_attr_t", + latency => 1, + mode => $mode_gp, +}, + +Unknown => { + op_flags => [ "constlike" ], + irn_flags => [ "rematerializable" ], + reg_req => { out => [ "gp" ] }, + latency => 0, + emit => '', + mode => $mode_gp, +}, + +GetEIP => { + op_flags => [ "constlike" ], + reg_req => { out => [ "gp" ] }, + units => [ "GP" ], + latency => 5, + mode => $mode_gp, + modified_flags => $status_flags, +}, + +NoReg_GP => { + state => "pinned", + op_flags => [ "constlike", "dump_noblock", "dump_noinput" ], + irn_flags => [ "not_scheduled" ], + 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 => [ "constlike", "dump_noblock", "dump_noinput" ], + irn_flags => [ "not_scheduled" ], + reg_req => { out => [ "vfp_NOREG:I" ] }, units => [], emit => "", - mode => "mode_E", + mode => $mode_fp87, + 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 => [ "constlike", "dump_noblock", "dump_noinput" ], + irn_flags => [ "not_scheduled" ], + reg_req => { out => [ "xmm_NOREG:I" ] }, units => [], emit => "", - mode => "mode_E" + latency => 0, + mode => $mode_xmm, }, ChangeCW => { state => "pinned", - op_flags => "c", - irn_flags => "I", - reg_req => { out => [ "fp_cw" ] }, + op_flags => [ "constlike" ], + irn_flags => [ "not_scheduled" ], + reg_req => { out => [ "fpcw:I" ] }, mode => $mode_fpcw, latency => 3, units => [ "GP" ], @@ -900,9 +1147,10 @@ ChangeCW => { }, FldCW => { - op_flags => "L|F", + op_flags => [ "labeled" ], 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", mode => $mode_fpcw, @@ -911,21 +1159,32 @@ FldCW => { }, FnstCW => { - op_flags => "L|F", + op_flags => [ "labeled" ], state => "pinned", - reg_req => { in => [ "gp", "gp", "fp_cw", "none" ], out => [ "none" ] }, + 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" ], }, +FnstCWNOP => { + op_flags => [ "labeled" ], + 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 produces 2 results and has - # very strict constrains - reg_req => { in => [ "eax" ], out => [ "edx" ] }, - ins => [ "val" ], + # we should not rematrialize this node. It has very strict constraints. + reg_req => { in => [ "eax", "edx" ], out => [ "edx" ] }, + ins => [ "val", "clobbered" ], emit => '. cltd', + latency => 1, mode => $mode_gp, units => [ "GP" ], }, @@ -936,999 +1195,1381 @@ Cltd => { # lateny of 0 for load is correct Load => { - op_flags => "L|F", + op_flags => [ "uses_memory", "fragile", "labeled" ], state => "exc_pinned", - reg_req => { in => [ "gp", "gp", "none" ], out => [ "gp", "none" ] }, + reg_req => { in => [ "gp", "gp", "none" ], + out => [ "gp", "none", "none", "none", "none" ] }, + ins => [ "base", "index", "mem" ], + outs => [ "res", "unused", "M", "X_regular", "X_except" ], latency => 0, - emit => ". mov%SE%ME%.l %AM, %D0", - outs => [ "res", "M" ], + 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", + op_flags => [ "uses_memory", "fragile", "labeled" ], state => "exc_pinned", - reg_req => { in => [ "gp", "gp", "gp", "none" ], out => [ "none" ] }, - emit => '. mov%M %binop', + reg_req => { in => [ "gp", "gp", "none", "gp" ], + out => [ "none", "none", "none" ] }, + ins => [ "base", "index", "mem", "val" ], + outs => [ "M", "X_regular", "X_except" ], + emit => '. mov%M %SI3, %AM', latency => 2, units => [ "GP" ], - mode => "mode_M", }, Store8Bit => { - op_flags => "L|F", + op_flags => [ "uses_memory", "fragile", "labeled" ], state => "exc_pinned", - reg_req => { in => [ "gp", "gp", "eax ebx ecx edx", "none" ], out => ["none" ] }, - emit => '. mov%M %binop', + reg_req => { in => [ "gp", "gp", "none", "eax ebx ecx edx" ], + out => ["none", "none", "none" ] }, + ins => [ "base", "index", "mem", "val" ], + outs => [ "M", "X_regular", "X_except" ], + emit => '. mov%M %SB3, %AM', latency => 2, units => [ "GP" ], - mode => "mode_M", }, Lea => { - irn_flags => "R", - reg_req => { in => [ "gp", "gp" ], out => [ "in_r1" ] }, + irn_flags => [ "rematerializable" ], + reg_req => { in => [ "gp", "gp" ], out => [ "gp" ] }, + ins => [ "base", "index" ], emit => '. leal %AM, %D0', latency => 2, units => [ "GP" ], mode => $mode_gp, - modified_flags => [], +# 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", "gp", "esp", "none" ], out => [ "esp", "none" ] }, - emit => '. push%M %unop2', - ins => [ "base", "index", "val", "stack", "mem" ], - outs => [ "stack:I|S", "M" ], + 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", "M" ], + am => "source,unary", latency => 2, units => [ "GP" ], - modified_flags => [], +}, + +PushEax => { + state => "exc_pinned", + reg_req => { in => [ "esp" ], out => [ "esp:I|S" ] }, + ins => [ "stack" ], + outs => [ "stack" ], + emit => '. pushl %%eax', + latency => 2, + units => [ "GP" ], + mode => $mode_gp, }, Pop => { - reg_req => { in => [ "gp", "gp", "esp", "none" ], out => [ "esp", "gp", "none" ] }, - emit => '. pop%M %DAM1', - outs => [ "stack:I|S", "res", "M" ], - ins => [ "base", "index", "stack", "mem" ], + 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" ], +}, + +CopyEbpEsp => { + state => "exc_pinned", + reg_req => { in => [ "ebp" ], out => [ "esp:I|S" ] }, + ins => [ "ebp" ], + outs => [ "esp" ], + emit => '. movl %S0, %D0', + latency => 1, + units => [ "GP" ], + mode => $mode_gp, +}, + +PopMem => { + state => "exc_pinned", + reg_req => { in => [ "gp", "gp", "none", "esp" ], out => [ "none", "none", "none", "esp:I|S" ] }, + ins => [ "base", "index", "mem", "stack" ], + outs => [ "unused0", "M", "unused1", "stack" ], + emit => '. pop%M %AM', latency => 3, # Pop is more expensive than Push on Athlon units => [ "GP" ], - modified_flags => [], }, 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" ], + state => "exc_pinned", }, AddSP => { - irn_flags => "I", - reg_req => { in => [ "gp", "gp", "esp", "gp", "none" ], out => [ "in_r3", "none" ] }, + state => "pinned", + 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", - reg_req => { in => [ "gp", "gp", "esp", "gp", "none" ], out => [ "in_r3", "none" ] }, - emit => '. subl %binop', - outs => [ "stack:S", "M" ], + state => "pinned", + 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", + latency => 2, + outs => [ "stack", "addr", "M" ], units => [ "GP" ], modified_flags => $status_flags }, +RepPrefix => { + op_flags => [ "keep" ], + state => "pinned", + mode => "mode_M", + emit => ". rep", + latency => 0, +}, + LdTls => { - irn_flags => "R", + irn_flags => [ "rematerializable" ], reg_req => { out => [ "gp" ] }, units => [ "GP" ], + emit => ". movl %%gs:0, %D0", + mode => $mode_gp, + latency => 1, }, -# the int instruction -int => { +# +# BT supports source address mode, but this is unused yet +# +Bt => { + irn_flags => [ "rematerializable" ], + state => "exc_pinned", + reg_req => { in => [ "gp", "gp" ], out => [ "flags" ] }, + ins => [ "left", "right" ], + emit => '. bt%M %S1, %S0', + units => [ "GP" ], + latency => 1, + mode => $mode_flags, + modified_flags => $status_flags # only CF is set, but the other flags are undefined +}, + +Bsf => { + irn_flags => [ "rematerializable" ], + 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 +}, + +Bsr => { + irn_flags => [ "rematerializable" ], + 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 => [ "rematerializable" ], + 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 => { + op_flags => [ "uses_memory", "fragile" ], + 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", "none", "none" ] + }, + 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", "X_regular", "X_except" ], + 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 => [ "rematerializable" ], + 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 => [ "rematerializable" ], + 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" ] }, - mode => "mode_M", - attr => "tarval *tv", - init_attr => "\tset_ia32_Immop_tarval(res, tv);", - emit => '. int %C', + ins => [ "mem" ], + latency => 0, + emit => ". int3", units => [ "GP" ], - cmp_attr => "return 1;", + 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 => [ "rematerializable" ], + 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 +}, -# commutative operations +# +# inport +# +Inport => { + irn_flags => [ "rematerializable" ], + 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 => [ "labeled" ], + 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 => [ "labeled" ], + 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 => [ "labeled" ], + 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 => [ "labeled" ], + 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 => [ "labeled" ], + 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 => [ "labeled" ], + 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 => [ "rematerializable" ], + reg_req => { out => [ "xmm" ] }, + emit => '. xorp%XSD %D0, %D0', + latency => 3, + units => [ "SSE" ], + mode => $mode_xmm +}, + +xUnknown => { + op_flags => [ "constlike" ], + irn_flags => [ "rematerializable" ], + reg_req => { out => [ "xmm" ] }, + emit => '', + latency => 0, + mode => $mode_xmm +}, + +xPzero => { + irn_flags => [ "rematerializable" ], + reg_req => { out => [ "xmm" ] }, + emit => '. pxor %D0, %D0', + latency => 3, + units => [ "SSE" ], + mode => $mode_xmm +}, + +# produces all 1 bits +xAllOnes => { + irn_flags => [ "rematerializable" ], + reg_req => { out => [ "xmm" ] }, + emit => '. pcmpeqb %D0, %D0', + latency => 3, + units => [ "SSE" ], + mode => $mode_xmm +}, + +# integer shift left, dword +xPslld => { + irn_flags => [ "rematerializable" ], + 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 => [ "rematerializable" ], + 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 => [ "rematerializable" ], + 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 => [ "rematerializable" ], + reg_req => { in => [ "gp" ], out => [ "xmm" ] }, + emit => '. movd %S0, %D0', + latency => 1, + units => [ "SSE" ], + mode => $mode_xmm +}, xAdd => { - irn_flags => "R", - reg_req => { in => [ "gp", "gp", "xmm", "xmm", "none" ], out => [ "in_r3" ] }, + irn_flags => [ "rematerializable" ], + 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_E", + mode => $mode_xmm }, xMul => { - irn_flags => "R", - reg_req => { in => [ "gp", "gp", "xmm", "xmm", "none" ], out => [ "in_r3" ] }, + irn_flags => [ "rematerializable" ], + 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", "xmm", "xmm", "none" ], out => [ "in_r3" ] }, + irn_flags => [ "rematerializable" ], + 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", "xmm", "xmm", "none" ], out => [ "in_r3" ] }, + irn_flags => [ "rematerializable" ], + 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", "xmm", "xmm", "none" ], out => [ "in_r3" ] }, + irn_flags => [ "rematerializable" ], + 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", "xmm", "xmm", "none" ], out => [ "in_r3" ] }, + irn_flags => [ "rematerializable" ], + 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", "xmm", "xmm", "none" ], out => [ "in_r3" ] }, + irn_flags => [ "rematerializable" ], + 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", "xmm", "xmm", "none" ], out => [ "in_r3 !in_r4" ] }, + irn_flags => [ "rematerializable" ], + 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", "xmm", "xmm", "none" ], out => [ "in_r3" ] }, + irn_flags => [ "rematerializable" ], + 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", "xmm", "xmm", "none" ], out => [ "in_r3 !in_r4", "none" ] }, - outs => [ "res", "M" ], + irn_flags => [ "rematerializable" ], + 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" ], }, -# other operations - -xCmp => { - irn_flags => "R", - reg_req => { in => [ "gp", "gp", "xmm", "xmm", "none" ], out => [ "in_r3 !in_r4" ] }, +Ucomi => { + irn_flags => [ "rematerializable" ], + 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 => "bool ins_permuted", + init_attr => "attr->data.ins_permuted = ins_permuted;", + emit => ' .ucomi%XXM %binop', latency => 3, units => [ "SSE" ], - mode => "mode_E", + mode => $mode_flags, + modified_flags => 1, }, -xCondJmp => { - state => "pinned", - op_flags => "L|X|Y", - reg_req => { in => [ "gp", "gp", "xmm", "xmm", "none" ], out => [ "none", "none" ] }, - ins => [ "base", "index", "left", "right", "mem" ], - outs => [ "false", "true" ], - attr => "long pnc", - init_attr => "attr->pn_code = pnc;", - latency => 5, - units => [ "SSE" ], -}, - -xConst => { - op_flags => "c", - irn_flags => "R", - reg_req => { out => [ "xmm" ] }, - emit => '. mov%XXM %C, %D0', - latency => 2, - units => [ "SSE" ], - mode => "mode_E", -}, - -# Load / Store - xLoad => { - op_flags => "L|F", + op_flags => [ "uses_memory", "fragile", "labeled" ], state => "exc_pinned", - reg_req => { in => [ "gp", "gp", "none" ], out => [ "xmm", "none" ] }, + reg_req => { in => [ "gp", "gp", "none" ], + out => [ "xmm", "none", "none", "none", "none" ] }, + ins => [ "base", "index", "mem" ], + outs => [ "res", "unused", "M", "X_regular", "X_except" ], emit => '. mov%XXM %AM, %D0', - outs => [ "res", "M" ], - latency => 2, + attr => "ir_mode *load_mode", + init_attr => "attr->ls_mode = load_mode;", + latency => 0, units => [ "SSE" ], }, xStore => { - op_flags => "L|F", + op_flags => [ "uses_memory", "fragile", "labeled" ], state => "exc_pinned", - reg_req => { in => [ "gp", "gp", "xmm", "none" ] }, - emit => '. mov%XXM %binop', - latency => 2, + reg_req => { in => [ "gp", "gp", "none", "xmm" ], + out => [ "none", "none", "none" ] }, + ins => [ "base", "index", "mem", "val" ], + outs => [ "M", "X_regular", "X_except" ], + emit => '. mov%XXM %S3, %AM', + latency => 0, units => [ "SSE" ], - mode => "mode_M", }, xStoreSimple => { - op_flags => "L|F", + op_flags => [ "uses_memory", "fragile", "labeled" ], state => "exc_pinned", - reg_req => { in => [ "gp", "gp", "xmm", "none" ] }, - ins => [ "base", "index", "val", "mem" ], - emit => '. mov%XXM %S2, %AM', - latency => 2, + reg_req => { in => [ "gp", "gp", "none", "xmm" ], + out => [ "none", "none", "none" ] }, + ins => [ "base", "index", "mem", "val" ], + outs => [ "M", "X_regular", "X_except" ], + emit => '. mov%XXM %S3, %AM', + latency => 0, units => [ "SSE" ], - mode => "mode_M", }, CvtSI2SS => { - op_flags => "L|F", - reg_req => { in => [ "gp", "gp", "gp", "none" ], out => [ "xmm" ] }, - emit => '. cvtsi2ss %D0, %AM', + op_flags => [ "labeled" ], + 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" ], mode => $mode_xmm }, CvtSI2SD => { - op_flags => "L|F", - reg_req => { in => [ "gp", "gp", "gp", "none" ], out => [ "xmm" ] }, - emit => '. cvtsi2sd %unop2', + op_flags => [ "labeled" ], + 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" ], 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, -}, - -GetST0 => { - op_flags => "L|F", - irn_flags => "I", - state => "pinned", - reg_req => { in => [ "gp", "gp", "none" ] }, - emit => '. fstp%XM %AM', - latency => 4, - units => [ "SSE" ], - mode => "mode_M", +l_LLtoFloat => { + ins => [ "val_high", "val_low" ], + attr_type => "", + dump_func => "NULL", }, -SetST0 => { - op_flags => "L|F", - irn_flags => "I", - state => "pinned", - reg_req => { in => [ "gp", "gp", "none" ], out => [ "vf0", "none" ] }, - ins => [ "base", "index", "mem" ], - emit => '. fld%XM %AM', - outs => [ "res", "M" ], - latency => 2, - units => [ "SSE" ], +l_FloattoLL => { + ins => [ "val" ], + outs => [ "res_high", "res_low" ], + attr_type => "", + dump_func => "NULL", }, -# 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" ], - modified_flags => [ "DF" ] + op_flags => [ "uses_memory", "fragile" ], + state => "pinned", + reg_req => { in => [ "edi", "esi", "ecx", "none" ], + out => [ "edi", "esi", "ecx", "none", "none", "none" ] }, + ins => [ "dest", "source", "count", "mem" ], + outs => [ "dest", "source", "count", "M", "X_regular", "X_except" ], + 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" ], - modified_flags => [ "DF" ] -}, - -# Conversions - -Conv_I2I => { - reg_req => { in => [ "gp", "gp", "gp", "none" ], out => [ "in_r3", "none" ] }, - units => [ "GP" ], - ins => [ "base", "index", "val", "mem" ], - mode => $mode_gp, - modified_flags => $status_flags -}, - -Conv_I2I8Bit => { - reg_req => { in => [ "gp", "gp", "eax ebx ecx edx", "none" ], out => [ "in_r3", "none" ] }, - ins => [ "base", "index", "val", "mem" ], - units => [ "GP" ], - mode => $mode_gp, - modified_flags => $status_flags -}, - -Conv_I2FP => { - reg_req => { in => [ "gp", "gp", "gp", "none" ], out => [ "xmm", "none" ] }, - latency => 10, - units => [ "SSE" ], - mode => "mode_E", -}, - -Conv_FP2I => { - reg_req => { in => [ "gp", "gp", "xmm", "none" ], out => [ "gp", "none" ] }, - latency => 10, - units => [ "SSE" ], - mode => $mode_gp, -}, - -Conv_FP2FP => { - reg_req => { in => [ "gp", "gp", "xmm", "none" ], out => [ "xmm", "none" ] }, - latency => 8, - units => [ "SSE" ], - mode => "mode_E", -}, - -CmpCMov => { - irn_flags => "R", - reg_req => { in => [ "gp", "gp", "gp", "gp" ], out => [ "in_r4" ] }, - ins => [ "cmp_left", "cmp_right", "val_true", "val_false" ], - attr => "pn_Cmp pn_code", - init_attr => "attr->pn_code = pn_code;", - latency => 2, + op_flags => [ "uses_memory", "fragile" ], + state => "pinned", + reg_req => { in => [ "edi", "esi", "none" ], + out => [ "edi", "esi", "none", "none", "none" ] }, + ins => [ "dest", "source", "mem" ], + outs => [ "dest", "source", "M", "X_regular", "X_except" ], + attr_type => "ia32_copyb_attr_t", + attr => "unsigned size", units => [ "GP" ], - mode => $mode_gp, + latency => 3, +# we don't care about this flag, so no need to mark this node +# modified_flags => [ "DF" ] }, -xCmpCMov => { - irn_flags => "R", - reg_req => { in => [ "xmm", "xmm", "gp", "gp" ], out => [ "in_r4" ] }, - latency => 5, - units => [ "SSE" ], +Cwtl => { + state => "exc_pinned", + reg_req => { in => [ "eax" ], out => [ "eax" ] }, + ins => [ "val" ], + outs => [ "res" ], + emit => '. cwtl', + units => [ "GP" ], + latency => 1, mode => $mode_gp, }, -vfCmpCMov => { - irn_flags => "R", - reg_req => { in => [ "vfp", "vfp", "gp", "gp" ], out => [ "in_r4" ] }, - latency => 10, - units => [ "VFP" ], +Conv_I2I => { + op_flags => [ "uses_memory", "fragile" ], + state => "exc_pinned", + reg_req => { in => [ "gp", "gp", "none", "gp" ], + out => [ "gp", "none", "none", "none", "none" ] }, + ins => [ "base", "index", "mem", "val" ], + outs => [ "res", "flags", "M", "X_regular", "X_except" ], + am => "source,unary", + units => [ "GP" ], + latency => 1, + attr => "ir_mode *smaller_mode", + init_attr => "attr->ls_mode = smaller_mode;", mode => $mode_gp, - attr_type => "ia32_x87_attr_t", }, -CmpSet => { - irn_flags => "R", - reg_req => { in => [ "gp", "gp", "gp", "gp", "none" ], out => [ "eax ebx ecx edx" ] }, - ins => [ "base", "index", "cmp_left", "cmp_right", "mem" ], - attr => "pn_Cmp pn_code", - init_attr => "attr->pn_code = pn_code;", - latency => 2, +Conv_I2I8Bit => { + op_flags => [ "uses_memory", "fragile" ], + state => "exc_pinned", + reg_req => { in => [ "gp", "gp", "none", "eax ebx ecx edx" ], + out => [ "gp", "none", "none", "none", "none" ] }, + ins => [ "base", "index", "mem", "val" ], + outs => [ "res", "flags", "M", "X_regular", "X_except" ], + am => "source,unary", units => [ "GP" ], + latency => 1, + attr => "ir_mode *smaller_mode", + init_attr => "attr->ls_mode = smaller_mode;", mode => $mode_gp, }, -xCmpSet => { - irn_flags => "R", - reg_req => { in => [ "gp", "gp", "xmm", "xmm", "none" ], out => [ "eax ebx ecx edx" ] }, - latency => 5, +Conv_I2FP => { + 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_gp, + mode => $mode_xmm, }, -vfCmpSet => { - irn_flags => "R", - reg_req => { in => [ "gp", "gp", "vfp", "vfp", "none" ], out => [ "eax ebx ecx edx" ] }, +Conv_FP2I => { + state => "exc_pinned", + reg_req => { in => [ "gp", "gp", "none", "xmm" ], out => [ "gp", "none" ] }, + ins => [ "base", "index", "mem", "val" ], + am => "source,unary", latency => 10, - units => [ "VFP" ], + units => [ "SSE" ], mode => $mode_gp, - attr_type => "ia32_x87_attr_t", }, -vfCMov => { - irn_flags => "R", - reg_req => { in => [ "vfp", "vfp", "vfp", "vfp" ], out => [ "vfp" ] }, - latency => 10, - units => [ "VFP" ], - mode => "mode_E", - attr_type => "ia32_x87_attr_t", +Conv_FP2FP => { + 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, }, -#----------------------------------------------------------# -# _ _ _ __ _ _ # -# (_) | | | | / _| | | | # -# __ ___ _ __| |_ _ _ __ _| | | |_| | ___ __ _| |_ # -# \ \ / / | '__| __| | | |/ _` | | | _| |/ _ \ / _` | __| # -# \ V /| | | | |_| |_| | (_| | | | | | | (_) | (_| | |_ # -# \_/ |_|_| \__|\__,_|\__,_|_| |_| |_|\___/ \__,_|\__| # -# | | # -# _ __ ___ __| | ___ ___ # -# | '_ \ / _ \ / _` |/ _ \/ __| # -# | | | | (_) | (_| | __/\__ \ # -# |_| |_|\___/ \__,_|\___||___/ # -#----------------------------------------------------------# +# 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", - reg_req => { in => [ "gp", "gp", "vfp", "vfp", "none", "fpcw" ], out => [ "vfp" ] }, - ins => [ "base", "index", "left", "right", "mem", "fpcw" ], +# irn_flags => [ "rematerializable" ], + state => "exc_pinned", + reg_req => { in => [ "gp", "gp", "none", "vfp", "vfp", "fpcw" ], + out => [ "vfp", "none", "none" ] }, + ins => [ "base", "index", "mem", "left", "right", "fpcw" ], + outs => [ "res", "dummy", "M" ], + am => "source,binary", latency => 4, units => [ "VFP" ], - mode => "mode_E", + mode => $mode_fp87, attr_type => "ia32_x87_attr_t", }, vfmul => { - irn_flags => "R", - reg_req => { in => [ "gp", "gp", "vfp", "vfp", "none", "fpcw" ], out => [ "vfp" ] }, - ins => [ "base", "index", "left", "right", "mem", "fpcw" ], +# irn_flags => [ "rematerializable" ], + state => "exc_pinned", + reg_req => { in => [ "gp", "gp", "none", "vfp", "vfp", "fpcw" ], + out => [ "vfp", "none", "none" ] }, + ins => [ "base", "index", "mem", "left", "right", "fpcw" ], + outs => [ "res", "dummy", "M" ], + am => "source,binary", latency => 4, units => [ "VFP" ], - mode => "mode_E", + mode => $mode_fp87, attr_type => "ia32_x87_attr_t", }, -l_vfmul => { - op_flags => "C", - cmp_attr => "return 1;", - arity => 2, -}, - vfsub => { - irn_flags => "R", - reg_req => { in => [ "gp", "gp", "vfp", "vfp", "none", "fpcw" ], out => [ "vfp" ] }, - ins => [ "base", "index", "left", "right", "mem", "fpcw" ], +# irn_flags => [ "rematerializable" ], + state => "exc_pinned", + reg_req => { in => [ "gp", "gp", "none", "vfp", "vfp", "fpcw" ], + out => [ "vfp", "none", "none" ] }, + ins => [ "base", "index", "mem", "minuend", "subtrahend", "fpcw" ], + outs => [ "res", "dummy", "M" ], + am => "source,binary", latency => 4, units => [ "VFP" ], - mode => "mode_E", + mode => $mode_fp87, attr_type => "ia32_x87_attr_t", }, -l_vfsub => { - cmp_attr => "return 1;", - arity => 2, -}, - vfdiv => { - reg_req => { in => [ "gp", "gp", "vfp", "vfp", "none", "fpcw" ], out => [ "vfp", "none" ] }, - ins => [ "base", "index", "left", "right", "mem", "fpcw" ], - outs => [ "res", "M" ], + state => "exc_pinned", + reg_req => { in => [ "gp", "gp", "none", "vfp", "vfp", "fpcw" ], + out => [ "vfp", "none", "none" ] }, + ins => [ "base", "index", "mem", "dividend", "divisor", "fpcw" ], + outs => [ "res", "dummy", "M" ], + am => "source,binary", 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", "vfp", "vfp", "none", "fpcw" ], out => [ "vfp" ] }, - ins => [ "base", "index", "left", "right", "mem", "fpcw" ], + reg_req => { in => [ "vfp", "vfp", "fpcw" ], out => [ "vfp" ] }, + ins => [ "left", "right", "fpcw" ], latency => 20, units => [ "VFP" ], - mode => "mode_E", + mode => $mode_fp87, attr_type => "ia32_x87_attr_t", }, -l_vfprem => { - cmp_attr => "return 1;", - arity => 2, -}, - vfabs => { - irn_flags => "R", + irn_flags => [ "rematerializable" ], reg_req => { in => [ "vfp"], out => [ "vfp" ] }, ins => [ "value" ], latency => 2, units => [ "VFP" ], - mode => "mode_E", + mode => $mode_fp87, attr_type => "ia32_x87_attr_t", }, vfchs => { - irn_flags => "R", + irn_flags => [ "rematerializable" ], reg_req => { in => [ "vfp"], out => [ "vfp" ] }, ins => [ "value" ], latency => 2, units => [ "VFP" ], - mode => "mode_E", + mode => $mode_fp87, attr_type => "ia32_x87_attr_t", }, -# virtual Load and Store - vfld => { - op_flags => "L|F", + irn_flags => [ "rematerializable" ], + op_flags => [ "uses_memory", "fragile", "labeled" ], state => "exc_pinned", - reg_req => { in => [ "gp", "gp", "none" ], out => [ "vfp", "none" ] }, + reg_req => { in => [ "gp", "gp", "none" ], + out => [ "vfp", "none", "none", "none", "none" ] }, ins => [ "base", "index", "mem" ], - outs => [ "res", "M" ], - attr => "ir_mode *store_mode", - init_attr => "attr->attr.ls_mode = store_mode;", + outs => [ "res", "unused", "M", "X_regular", "X_except" ], + 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", + irn_flags => [ "rematerializable" ], + op_flags => [ "uses_memory", "fragile", "labeled" ], state => "exc_pinned", - reg_req => { in => [ "gp", "gp", "vfp", "none" ] }, - ins => [ "base", "index", "val", "mem" ], + reg_req => { in => [ "gp", "gp", "none", "vfp" ], + out => [ "none", "none", "none" ] }, + ins => [ "base", "index", "mem", "val" ], + outs => [ "M", "X_regular", "X_except" ], 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 => { 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 => { + op_flags => [ "uses_memory", "fragile" ], state => "exc_pinned", - reg_req => { in => [ "gp", "gp", "vfp", "fpcw", "none" ] }, - ins => [ "base", "index", "val", "fpcw", "mem" ], + reg_req => { in => [ "gp", "gp", "none", "vfp", "fpcw" ], + out => [ "none", "none", "none", "none" ] }, + ins => [ "base", "index", "mem", "val", "fpcw" ], + outs => [ "dummy", "M", "X_regular", "X_except" ], latency => 4, units => [ "VFP" ], - mode => "mode_M", attr_type => "ia32_x87_attr_t", }, -l_vfist => { - cmp_attr => "return 1;", +# SSE3 fisttp instruction +vfisttp => { + op_flags => [ "uses_memory", "fragile" ], state => "exc_pinned", - arity => 3, - mode => "mode_M", + reg_req => { in => [ "gp", "gp", "none", "vfp" ], + out => [ "in_r4", "none", "none", "none" ]}, + ins => [ "base", "index", "mem", "val" ], + outs => [ "res", "M", "X_regular", "X_except" ], + latency => 4, + units => [ "VFP" ], + attr_type => "ia32_x87_attr_t", }, - -# constants - vfldz => { - irn_flags => "R", + irn_flags => [ "rematerializable" ], reg_req => { out => [ "vfp" ] }, + outs => [ "res" ], latency => 4, units => [ "VFP" ], - mode => "mode_E", + mode => $mode_fp87, attr_type => "ia32_x87_attr_t", }, vfld1 => { - irn_flags => "R", + irn_flags => [ "rematerializable" ], reg_req => { out => [ "vfp" ] }, + outs => [ "res" ], latency => 4, units => [ "VFP" ], - mode => "mode_E", + mode => $mode_fp87, attr_type => "ia32_x87_attr_t", }, vfldpi => { - irn_flags => "R", + irn_flags => [ "rematerializable" ], reg_req => { out => [ "vfp" ] }, + outs => [ "res" ], latency => 4, units => [ "VFP" ], - mode => "mode_E", + mode => $mode_fp87, attr_type => "ia32_x87_attr_t", }, vfldln2 => { - irn_flags => "R", + irn_flags => [ "rematerializable" ], reg_req => { out => [ "vfp" ] }, + outs => [ "res" ], latency => 4, units => [ "VFP" ], - mode => "mode_E", + mode => $mode_fp87, attr_type => "ia32_x87_attr_t", }, vfldlg2 => { - irn_flags => "R", + irn_flags => [ "rematerializable" ], reg_req => { out => [ "vfp" ] }, + outs => [ "res" ], latency => 4, units => [ "VFP" ], - mode => "mode_E", + mode => $mode_fp87, attr_type => "ia32_x87_attr_t", }, vfldl2t => { - irn_flags => "R", + irn_flags => [ "rematerializable" ], reg_req => { out => [ "vfp" ] }, + outs => [ "res" ], latency => 4, units => [ "VFP" ], - mode => "mode_E", + mode => $mode_fp87, attr_type => "ia32_x87_attr_t", }, vfldl2e => { - irn_flags => "R", + irn_flags => [ "rematerializable" ], reg_req => { out => [ "vfp" ] }, + outs => [ "res" ], latency => 4, units => [ "VFP" ], - mode => "mode_E", + mode => $mode_fp87, attr_type => "ia32_x87_attr_t", }, -vfConst => { - op_flags => "c", - irn_flags => "R", - reg_req => { out => [ "vfp" ] }, +vFucomFnstsw => { +# we can't allow to rematerialize this node so we don't +# accidently produce Phi(Fucom, Fucom(ins_permuted)) +# irn_flags => [ "rematerializable" ], + reg_req => { in => [ "vfp", "vfp" ], out => [ "eax" ] }, + ins => [ "left", "right" ], + outs => [ "flags" ], + attr => "bool ins_permuted", + init_attr => "attr->attr.data.ins_permuted = ins_permuted;", latency => 3, units => [ "VFP" ], - mode => "mode_E", attr_type => "ia32_x87_attr_t", + mode => $mode_gp }, -# other - -vfCondJmp => { - state => "pinned", - op_flags => "L|X|Y", - reg_req => { in => [ "vfp", "vfp" ], out => [ "none", "none", "eax" ] }, +vFucomi => { + irn_flags => [ "rematerializable" ], + reg_req => { in => [ "vfp", "vfp" ], out => [ "eflags" ] }, ins => [ "left", "right" ], - outs => [ "false", "true", "temp_reg_eax" ], - attr => "long pnc", - init_attr => "attr->attr.pn_code = pnc;", - latency => 10, + outs => [ "flags" ], + attr => "bool ins_permuted", + init_attr => "attr->attr.data.ins_permuted = ins_permuted;", + latency => 3, units => [ "VFP" ], attr_type => "ia32_x87_attr_t", + mode => $mode_gp }, -#------------------------------------------------------------------------# -# ___ _____ __ _ _ _ # -# __ _( _ )___ | / _| | ___ __ _| |_ _ __ ___ __| | ___ ___ # -# \ \/ / _ \ / / | |_| |/ _ \ / _` | __| | '_ \ / _ \ / _` |/ _ \/ __| # -# > < (_) |/ / | _| | (_) | (_| | |_ | | | | (_) | (_| | __/\__ \ # -# /_/\_\___//_/ |_| |_|\___/ \__,_|\__| |_| |_|\___/ \__,_|\___||___/ # -#------------------------------------------------------------------------# +vFtstFnstsw => { +# irn_flags => [ "rematerializable" ], + reg_req => { in => [ "vfp" ], out => [ "eax" ] }, + ins => [ "left" ], + outs => [ "flags" ], + attr => "bool ins_permuted", + init_attr => "attr->attr.data.ins_permuted = ins_permuted;", + latency => 3, + units => [ "VFP" ], + attr_type => "ia32_x87_attr_t", + mode => $mode_gp +}, -# Note: gas is strangely buggy: fdivrp and fdivp as well as fsubrp and fsubp -# are swapped, we work this around in the emitter... +Sahf => { + irn_flags => [ "rematerializable" ], + reg_req => { in => [ "eax" ], out => [ "eflags" ] }, + ins => [ "val" ], + outs => [ "flags" ], + emit => '. sahf', + latency => 1, + units => [ "GP" ], + mode => $mode_flags, +}, fadd => { - op_flags => "R", - rd_constructor => "NONE", - reg_req => { }, + state => "exc_pinned", emit => '. fadd%XM %x87_binop', + latency => 4, attr_type => "ia32_x87_attr_t", + constructors => {}, }, faddp => { - op_flags => "R", - rd_constructor => "NONE", - reg_req => { }, - emit => '. faddp %x87_binop', + state => "exc_pinned", + emit => '. faddp%XM %x87_binop', + latency => 4, attr_type => "ia32_x87_attr_t", + constructors => {}, }, fmul => { - op_flags => "R", - rd_constructor => "NONE", - reg_req => { }, + state => "exc_pinned", emit => '. fmul%XM %x87_binop', + latency => 4, attr_type => "ia32_x87_attr_t", + constructors => {}, }, fmulp => { - op_flags => "R", - rd_constructor => "NONE", - reg_req => { }, - emit => '. fmulp %x87_binop',, + state => "exc_pinned", + emit => '. fmulp%XM %x87_binop',, + latency => 4, attr_type => "ia32_x87_attr_t", + constructors => {}, }, fsub => { - op_flags => "R", - rd_constructor => "NONE", - reg_req => { }, + state => "exc_pinned", emit => '. fsub%XM %x87_binop', + latency => 4, attr_type => "ia32_x87_attr_t", + constructors => {}, }, +# Note: gas is strangely buggy: fdivrp and fdivp as well as fsubrp and fsubp +# are swapped, we work this around in the emitter... + fsubp => { - op_flags => "R", - rd_constructor => "NONE", - reg_req => { }, + state => "exc_pinned", # see note about gas bugs - emit => '. fsubrp %x87_binop', + emit => '. fsubrp%XM %x87_binop', + latency => 4, attr_type => "ia32_x87_attr_t", + constructors => {}, }, fsubr => { - op_flags => "R", - rd_constructor => "NONE", - irn_flags => "R", - reg_req => { }, + state => "exc_pinned", + irn_flags => [ "rematerializable" ], emit => '. fsubr%XM %x87_binop', + latency => 4, attr_type => "ia32_x87_attr_t", + constructors => {}, }, fsubrp => { - op_flags => "R", - rd_constructor => "NONE", - irn_flags => "R", - reg_req => { }, -# see note about gas bugs - emit => '. fsubp %x87_binop', + state => "exc_pinned", + irn_flags => [ "rematerializable" ], +# see note about gas bugs before fsubp + emit => '. fsubp%XM %x87_binop', + latency => 4, attr_type => "ia32_x87_attr_t", + constructors => {}, }, fprem => { - op_flags => "R", - rd_constructor => "NONE", - reg_req => { }, emit => '. fprem1', + latency => 20, attr_type => "ia32_x87_attr_t", + constructors => {}, }, # 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", + constructors => {}, }, fdiv => { - op_flags => "R", - rd_constructor => "NONE", - reg_req => { }, + state => "exc_pinned", emit => '. fdiv%XM %x87_binop', + latency => 20, attr_type => "ia32_x87_attr_t", + constructors => {}, }, fdivp => { - op_flags => "R", - rd_constructor => "NONE", - reg_req => { }, -# see note about gas bugs - emit => '. fdivrp %x87_binop', + state => "exc_pinned", +# see note about gas bugs before fsubp + emit => '. fdivrp%XM %x87_binop', + latency => 20, attr_type => "ia32_x87_attr_t", + constructors => {}, }, fdivr => { - op_flags => "R", - rd_constructor => "NONE", - reg_req => { }, + state => "exc_pinned", emit => '. fdivr%XM %x87_binop', + latency => 20, attr_type => "ia32_x87_attr_t", + constructors => {}, }, fdivrp => { - op_flags => "R", - rd_constructor => "NONE", - reg_req => { }, -# see note about gas bugs - emit => '. fdivp %x87_binop', + state => "exc_pinned", +# see note about gas bugs before fsubp + emit => '. fdivp%XM %x87_binop', + latency => 20, attr_type => "ia32_x87_attr_t", + constructors => {}, }, fabs => { - op_flags => "R", - rd_constructor => "NONE", - reg_req => { }, emit => '. fabs', + latency => 4, attr_type => "ia32_x87_attr_t", + constructors => {}, }, fchs => { - op_flags => "R|K", - rd_constructor => "NONE", - reg_req => { }, + op_flags => [ "keep" ], + irn_flags => [ "rematerializable" ], emit => '. fchs', + latency => 4, attr_type => "ia32_x87_attr_t", + constructors => {}, }, -# x87 Load and Store - fld => { - rd_constructor => "NONE", - op_flags => "R|L|F", + irn_flags => [ "rematerializable" ], + op_flags => [ "labeled" ], state => "exc_pinned", - reg_req => { }, emit => '. fld%XM %AM', attr_type => "ia32_x87_attr_t", + latency => 2, + constructors => {}, }, fst => { - rd_constructor => "NONE", - op_flags => "R|L|F", + irn_flags => [ "rematerializable" ], + op_flags => [ "labeled" ], state => "exc_pinned", - reg_req => { }, emit => '. fst%XM %AM', mode => "mode_M", attr_type => "ia32_x87_attr_t", + latency => 2, + constructors => {}, }, fstp => { - rd_constructor => "NONE", - op_flags => "R|L|F", + irn_flags => [ "rematerializable" ], + op_flags => [ "labeled" ], state => "exc_pinned", - reg_req => { }, emit => '. fstp%XM %AM', mode => "mode_M", attr_type => "ia32_x87_attr_t", + latency => 2, + constructors => {}, }, -# Conversions - fild => { - op_flags => "R", - rd_constructor => "NONE", - reg_req => { }, + state => "exc_pinned", emit => '. fild%XM %AM', attr_type => "ia32_x87_attr_t", + latency => 2, + constructors => {}, }, fist => { - op_flags => "R", state => "exc_pinned", - rd_constructor => "NONE", - reg_req => { }, emit => '. fist%XM %AM', mode => "mode_M", attr_type => "ia32_x87_attr_t", + latency => 2, + constructors => {}, }, fistp => { - op_flags => "R", state => "exc_pinned", - rd_constructor => "NONE", - reg_req => { }, emit => '. fistp%XM %AM', mode => "mode_M", attr_type => "ia32_x87_attr_t", + latency => 2, + constructors => {}, }, -# constants +# SSE3 fisttp instruction +fisttp => { + state => "exc_pinned", + emit => '. fisttp%XM %AM', + mode => "mode_M", + attr_type => "ia32_x87_attr_t", + latency => 2, + constructors => {}, +}, fldz => { - op_flags => "R|c|K", - irn_flags => "R", - reg_req => { }, + op_flags => [ "constlike", "keep" ], + irn_flags => [ "rematerializable" ], + 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 => { }, + op_flags => [ "constlike", "keep" ], + irn_flags => [ "rematerializable" ], + 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 => { }, + op_flags => [ "constlike", "keep" ], + irn_flags => [ "rematerializable" ], + 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 => { }, + op_flags => [ "constlike", "keep" ], + irn_flags => [ "rematerializable" ], + 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 => { }, + op_flags => [ "constlike", "keep" ], + irn_flags => [ "rematerializable" ], + 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 => { }, + op_flags => [ "constlike", "keep" ], + irn_flags => [ "rematerializable" ], + 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 => { }, + op_flags => [ "constlike", "keep" ], + irn_flags => [ "rematerializable" ], + reg_req => { out => [ "vfp" ] }, emit => '. fldl2e', attr_type => "ia32_x87_attr_t", + latency => 2, }, # fxch, fpush, fpop @@ -1936,112 +2577,168 @@ fldl2e => { # Moreover, note the virtual register requierements! fxch => { - op_flags => "R|K", - reg_req => { }, + op_flags => [ "keep" ], + 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 => {}, + op_flags => [ "keep" ], + 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 => "R|K", - reg_req => { }, + op_flags => [ "keep" ], + reg_req => { out => [ "none" ] }, cmp_attr => "return 1;", emit => '. fstp %X0', attr_type => "ia32_x87_attr_t", + mode => "mode_ANY", + latency => 1, }, -# compare +ffreep => { + op_flags => [ "keep" ], + reg_req => { out => [ "none" ] }, + cmp_attr => "return 1;", + emit => '. ffreep %X0', + attr_type => "ia32_x87_attr_t", + mode => "mode_ANY", + latency => 1, +}, -fcomJmp => { - op_flags => "L|X|Y", - reg_req => { }, +emms => { + op_flags => [ "keep" ], + reg_req => { out => [ "none" ] }, + cmp_attr => "return 1;", + emit => '. emms', attr_type => "ia32_x87_attr_t", + mode => "mode_ANY", + latency => 3, }, -fcompJmp => { - op_flags => "L|X|Y", - reg_req => { }, +femms => { + op_flags => [ "keep" ], + reg_req => { out => [ "none" ] }, + cmp_attr => "return 1;", + emit => '. femms', attr_type => "ia32_x87_attr_t", + mode => "mode_ANY", + latency => 3, }, -fcomppJmp => { - op_flags => "L|X|Y", +FucomFnstsw => { reg_req => { }, + emit => ". fucom %X1\n". + ". fnstsw %%ax", attr_type => "ia32_x87_attr_t", + latency => 2, }, -fcomrJmp => { - op_flags => "L|X|Y", +FucompFnstsw => { reg_req => { }, + emit => ". fucomp %X1\n". + ". fnstsw %%ax", attr_type => "ia32_x87_attr_t", + latency => 2, }, -fcomrpJmp => { - op_flags => "L|X|Y", +FucomppFnstsw => { reg_req => { }, + emit => ". fucompp\n". + ". fnstsw %%ax", attr_type => "ia32_x87_attr_t", + latency => 2, }, -fcomrppJmp => { - op_flags => "L|X|Y", +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, +}, -# -------------------------------------------------------------------------------- # -# ____ ____ _____ _ _ # -# / ___/ ___|| ____| __ _____ ___| |_ ___ _ __ _ __ ___ __| | ___ ___ # -# \___ \___ \| _| \ \ / / _ \/ __| __/ _ \| '__| | '_ \ / _ \ / _` |/ _ \/ __| # -# ___) |__) | |___ \ V / __/ (__| || (_) | | | | | | (_) | (_| | __/\__ \ # -# |____/____/|_____| \_/ \___|\___|\__\___/|_| |_| |_|\___/ \__,_|\___||___/ # -# # -# -------------------------------------------------------------------------------- # - +FtstFnstsw => { + reg_req => { }, + emit => ". ftst\n". + ". fnstsw %%ax", + attr_type => "ia32_x87_attr_t", + latency => 2, +}, # Spilling and reloading of SSE registers, hardcoded, not generated # xxLoad => { - op_flags => "L|F", + op_flags => [ "uses_memory", "fragile", "labeled" ], state => "exc_pinned", - reg_req => { in => [ "gp", "gp", "none" ], out => [ "xmm", "none" ] }, + reg_req => { in => [ "gp", "gp", "none" ], + out => [ "xmm", "none", "none", "none" ] }, emit => '. movdqu %D0, %AM', - outs => [ "res", "M" ], + ins => [ "base", "index", "mem" ], + outs => [ "res", "M", "X_regular", "X_except" ], units => [ "SSE" ], + latency => 1, }, xxStore => { - op_flags => "L|F", + op_flags => [ "uses_memory", "fragile", "labeled" ], state => "exc_pinned", - reg_req => { in => [ "gp", "gp", "xmm", "none" ] }, + reg_req => { in => [ "gp", "gp", "none", "xmm" ], + out => [ "none", "none", "none" ] }, + ins => [ "base", "index", "mem", "val" ], + outs => [ "M", "X_regular", "X_except" ], emit => '. movdqu %binop', units => [ "SSE" ], - mode => "mode_M", + latency => 1, }, ); # 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; +# 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 .= "ia32_init_op(op, ".$node->{latency} . ");"; + + $node->{op_attr_init} = $op_attr_init; } + +print "";