X-Git-Url: http://nsz.repo.hu/git/?a=blobdiff_plain;f=ir%2Fbe%2Fia32%2Fia32_spec.pl;h=f4c6328aa3561886e896c899d37d1043d40055fd;hb=a1a465eb2b3f54027b29f829423fffd0396937f4;hp=61ed661e625ecf119479b70298668a93ffac63ea;hpb=7e0f6e526505c5de950c07572ac1514c7f9c0b36;p=libfirm diff --git a/ir/be/ia32/ia32_spec.pl b/ir/be/ia32/ia32_spec.pl index 61ed661e6..f4c6328aa 100644 --- a/ir/be/ia32/ia32_spec.pl +++ b/ir/be/ia32/ia32_spec.pl @@ -18,7 +18,7 @@ $comment_string = "/*"; # # => { # "op_flags" => "N|L|C|X|I|F|Y|H|c|K", -# "irn_flags" => "R|N|I" +# "irn_flags" => "R|N|I|S" # "arity" => "0|1|2|3 ... |variable|dynamic|any", # "state" => "floats|pinned|mem_pinned|exc_pinned", # "args" => [ @@ -33,6 +33,7 @@ $comment_string = "/*"; # "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)" # }, # # ... # (all nodes you need to describe) @@ -57,6 +58,7 @@ $comment_string = "/*"; # R rematerializeable # N not spillable # I ignore for register allocation +# S modifies stack pointer # # state: state of the operation, OPTIONAL (default is "floats") # @@ -71,6 +73,10 @@ $comment_string = "/*"; # # 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 # @@ -89,12 +95,17 @@ $comment_string = "/*"; # 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 +# # 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 # NOTE: Last entry of each class is the largest Firm-Mode a register can hold %reg_classes = ( "gp" => [ @@ -128,8 +139,8 @@ $comment_string = "/*"; # { "name" => "r32", "type" => 1 }, { "name" => "ebp", "type" => 2 }, { "name" => "esp", "type" => 4 }, - { "name" => "gp_NOREG", "type" => 6 }, # we need a dummy register for NoReg nodes - { "name" => "gp_UKNWN", "type" => 6 }, # we need a dummy register for Unknown nodes + { "name" => "gp_NOREG", "type" => 2 | 4 | 16 }, # we need a dummy register for NoReg nodes + { "name" => "gp_UKNWN", "type" => 2 | 4 | 8 | 16}, # we need a dummy register for Unknown nodes { "mode" => "mode_P" } ], "xmm" => [ @@ -141,21 +152,21 @@ $comment_string = "/*"; { "name" => "xmm5", "type" => 1 }, { "name" => "xmm6", "type" => 1 }, { "name" => "xmm7", "type" => 1 }, - { "name" => "xmm_NOREG", "type" => 6 }, # we need a dummy register for NoReg nodes - { "name" => "xmm_UKNWN", "type" => 6 }, # we need a dummy register for Unknown nodes + { "name" => "xmm_NOREG", "type" => 2 | 4 | 16 }, # we need a dummy register for NoReg nodes + { "name" => "xmm_UKNWN", "type" => 2 | 4 | 8 | 16}, # we need a dummy register for Unknown nodes { "mode" => "mode_D" } ], "vfp" => [ - { "name" => "vf0", "type" => 1 }, - { "name" => "vf1", "type" => 1 }, - { "name" => "vf2", "type" => 1 }, - { "name" => "vf3", "type" => 1 }, - { "name" => "vf4", "type" => 1 }, - { "name" => "vf5", "type" => 1 }, - { "name" => "vf6", "type" => 1 }, - { "name" => "vf7", "type" => 1 }, - { "name" => "vfp_NOREG", "type" => 6 }, # we need a dummy register for NoReg nodes - { "name" => "vfp_UKNWN", "type" => 6 }, # we need a dummy register for Unknown nodes + { "name" => "vf0", "type" => 1 | 16 }, + { "name" => "vf1", "type" => 1 | 16 }, + { "name" => "vf2", "type" => 1 | 16 }, + { "name" => "vf3", "type" => 1 | 16 }, + { "name" => "vf4", "type" => 1 | 16 }, + { "name" => "vf5", "type" => 1 | 16 }, + { "name" => "vf6", "type" => 1 | 16 }, + { "name" => "vf7", "type" => 1 | 16 }, + { "name" => "vfp_NOREG", "type" => 2 | 4 | 16 }, # we need a dummy register for NoReg nodes + { "name" => "vfp_UKNWN", "type" => 2 | 4 | 8 | 16}, # we need a dummy register for Unknown nodes { "mode" => "mode_E" } ], "st" => [ @@ -241,14 +252,19 @@ $comment_string = "/*"; }, "MulS" => { + # we should not rematrialize this node. It produces 2 results and has + # very strict constrains "comment" => "construct MulS: MulS(a, b) = MulS(b, a) = a * b", "cmp_attr" => " return ia32_compare_immop_attr(attr_a, attr_b);\n", - "reg_req" => { "in" => [ "gp", "gp", "gp", "gp", "none" ], "out" => [ "eax in_r3", "edx" ] }, + "reg_req" => { "in" => [ "gp", "gp", "eax", "gp", "none" ], "out" => [ "eax", "edx" ] }, "emit" => '. mul %ia32_emit_unop /* Mul(%A1, %A2) -> %D1 */', "outs" => [ "EAX", "EDX", "M" ], + "latency" => 10, }, "l_MulS" => { + # we should not rematrialize this node. It produces 2 results and has + # very strict constrains "op_flags" => "C", "cmp_attr" => " return 1;\n", "comment" => "construct lowered MulS: MulS(a, b) = MulS(b, a) = a * b", @@ -263,6 +279,7 @@ $comment_string = "/*"; "reg_req" => { "in" => [ "gp", "gp", "gp", "gp", "none" ], "out" => [ "in_r3" ] }, "emit" => '. imul %ia32_emit_binop /* Mul(%A1, %A2) -> %D1 */', "outs" => [ "res", "M" ], + "latency" => 5, }, "l_Mul" => { @@ -274,11 +291,14 @@ $comment_string = "/*"; # Mulh is an exception from the 4 INs with AM because the target is always EAX:EDX "Mulh" => { + # we should not rematrialize this node. It produces 2 results and has + # very strict constrains "comment" => "construct Mul: Mul(a, b) = Mul(b, a) = a * b", "cmp_attr" => " return ia32_compare_immop_attr(attr_a, attr_b);\n", - "reg_req" => { "in" => [ "gp", "gp", "gp", "gp", "none" ], "out" => [ "eax in_r3", "edx" ] }, + "reg_req" => { "in" => [ "gp", "gp", "eax", "gp", "none" ], "out" => [ "eax", "edx" ] }, "emit" => '. imul %ia32_emit_unop /* Mulh(%A1, %A2) -> %D1 */', "outs" => [ "EAX", "EDX", "M" ], + "latency" => 5, }, "And" => { @@ -327,7 +347,8 @@ $comment_string = "/*"; else { 4. cmovb %D1, %S2 /* %S1 is below %S2 */ } -' +', + "latency" => 2, }, "Min" => { @@ -342,7 +363,8 @@ $comment_string = "/*"; else { 2. cmova %D1, %S2, %D1 /* %S1 is above %S2 */ } -' +', + "latency" => 2, }, # not commutative operations @@ -359,7 +381,7 @@ $comment_string = "/*"; "SubC" => { "comment" => "construct Sub with Carry: SubC(a, b) = a - b - carry", "cmp_attr" => " return ia32_compare_immop_attr(attr_a, attr_b);\n", - "reg_req" => { "in" => [ "gp", "gp", "gp", "gp", "none" ], "out" => [ "in_r3" ] }, + "reg_req" => { "in" => [ "gp", "gp", "gp", "gp", "none" ], "out" => [ "in_r3 !in_r4" ] }, "emit" => '. sbb %ia32_emit_binop /* SubC(%A3, %A4) -> %D1 */', "outs" => [ "res", "M" ], }, @@ -380,7 +402,7 @@ $comment_string = "/*"; "DivMod" => { "op_flags" => "F|L", "state" => "exc_pinned", - "reg_req" => { "in" => [ "gp", "gp", "gp", "none" ], "out" => [ "eax in_r1", "edx in_r3" ] }, + "reg_req" => { "in" => [ "eax", "gp", "edx", "none" ], "out" => [ "eax", "edx" ] }, "attr" => "ia32_op_flavour_t dm_flav", "init_attr" => " attr->data.op_flav = dm_flav;", "cmp_attr" => " return attr_a->data.op_flav != attr_b->data.op_flav;\n", @@ -393,13 +415,14 @@ $comment_string = "/*"; } ', "outs" => [ "div_res", "mod_res", "M" ], + "latency" => 25, }, "Shl" => { "irn_flags" => "R", "comment" => "construct Shl: Shl(a, b) = a << b", "cmp_attr" => " return ia32_compare_immop_attr(attr_a, attr_b);\n", - "reg_req" => { "in" => [ "gp", "gp", "gp", "ecx", "none" ], "out" => [ "in_r3 !in_r4" ] }, + "reg_req" => { "in" => [ "gp", "gp", "gp", "ecx gp_NOREG", "none" ], "out" => [ "in_r3 !in_r4" ] }, "emit" => '. shl %ia32_emit_binop /* Shl(%A1, %A2) -> %D1 */', "outs" => [ "res", "M" ], }, @@ -414,7 +437,15 @@ $comment_string = "/*"; "irn_flags" => "R", "comment" => "construct ShlD: ShlD(a, b, c) = a, b << count (shift left count bits from b into a)", "cmp_attr" => " return ia32_compare_immop_attr(attr_a, attr_b);\n", - "reg_req" => { "in" => [ "gp", "gp", "gp", "gp", "ecx", "none" ], "out" => [ "in_r3 !in_r5" ] }, + # Out requirements is: different from all in + # This is because, out must be different from LowPart and ShiftCount. + # We could say "!ecx !in_r4" but it can occur, that all values live through + # this Shift and the only value dying is the ShiftCount. Then there would be a + # register missing, as result must not be ecx and all other registers are + # occupied. What we should write is "!in_r4 !in_r5", but this is not supported + # (and probably never will). So we create artificial interferences of the result + # with all inputs, so the spiller can always assure a free register. + "reg_req" => { "in" => [ "gp", "gp", "gp", "gp", "ecx", "none" ], "out" => [ "!in" ] }, "emit" => ' if (get_ia32_immop_type(n) == ia32_ImmNone) { @@ -435,6 +466,7 @@ else { } ', "outs" => [ "res", "M" ], + "latency" => 6, }, "l_ShlD" => { @@ -447,7 +479,7 @@ else { "irn_flags" => "R", "comment" => "construct Shr: Shr(a, b) = a >> b", "cmp_attr" => " return ia32_compare_immop_attr(attr_a, attr_b);\n", - "reg_req" => { "in" => [ "gp", "gp", "gp", "ecx", "none" ], "out" => [ "in_r3 !in_r4" ] }, + "reg_req" => { "in" => [ "gp", "gp", "gp", "ecx gp_NOREG", "none" ], "out" => [ "in_r3 !in_r4" ] }, "emit" => '. shr %ia32_emit_binop /* Shr(%A1, %A2) -> %D1 */', "outs" => [ "res", "M" ], }, @@ -462,7 +494,15 @@ else { "irn_flags" => "R", "comment" => "construct ShrD: ShrD(a, b, c) = a, b >> count (shift rigth count bits from a into b)", "cmp_attr" => " return ia32_compare_immop_attr(attr_a, attr_b);\n", - "reg_req" => { "in" => [ "gp", "gp", "gp", "gp", "ecx", "none" ], "out" => [ "in_r3 !in_r5" ] }, + # Out requirements is: different from all in + # This is because, out must be different from LowPart and ShiftCount. + # We could say "!ecx !in_r4" but it can occur, that all values live through + # this Shift and the only value dying is the ShiftCount. Then there would be a + # register missing, as result must not be ecx and all other registers are + # occupied. What we should write is "!in_r4 !in_r5", but this is not supported + # (and probably never will). So we create artificial interferences of the result + # with all inputs, so the spiller can always assure a free register. + "reg_req" => { "in" => [ "gp", "gp", "gp", "gp", "ecx", "none" ], "out" => [ "!in" ] }, "emit" => ' if (get_ia32_immop_type(n) == ia32_ImmNone) { @@ -483,6 +523,7 @@ else { } ', "outs" => [ "res", "M" ], + "latency" => 6, }, "l_ShrD" => { @@ -495,7 +536,7 @@ else { "irn_flags" => "R", "comment" => "construct Shrs: Shrs(a, b) = a >> b", "cmp_attr" => " return ia32_compare_immop_attr(attr_a, attr_b);\n", - "reg_req" => { "in" => [ "gp", "gp", "gp", "ecx", "none" ], "out" => [ "in_r3 !in_r4" ] }, + "reg_req" => { "in" => [ "gp", "gp", "gp", "ecx gp_NOREG", "none" ], "out" => [ "in_r3 !in_r4" ] }, "emit" => '. sar %ia32_emit_binop /* Shrs(%A1, %A2) -> %D1 */', "outs" => [ "res", "M" ], }, @@ -576,6 +617,7 @@ else { "cmp_attr" => " return ia32_compare_immop_attr(attr_a, attr_b);\n", "reg_req" => { "in" => [ "gp", "gp", "gp", "gp", "none" ] }, "outs" => [ "false", "true" ], + "latency" => 3, }, "TestJmp" => { @@ -584,6 +626,7 @@ else { "reg_req" => { "in" => [ "gp", "gp" ] }, "cmp_attr" => " return ia32_compare_immop_attr(attr_a, attr_b);\n", "outs" => [ "false", "true" ], + "latency" => 3, }, "CJmpAM" => { @@ -606,6 +649,7 @@ else { "comment" => "construct switch", "cmp_attr" => " return ia32_compare_immop_attr(attr_a, attr_b);\n", "reg_req" => { "in" => [ "gp" ], "out" => [ "none" ] }, + "latency" => 3, }, "Const" => { @@ -613,11 +657,12 @@ else { "irn_flags" => "R", "comment" => "represents an integer constant", "cmp_attr" => " return ia32_compare_immop_attr(attr_a, attr_b);\n", - "reg_req" => { "in" => [ "none" ], "out" => [ "gp" ] }, + "reg_req" => { "out" => [ "gp" ] }, }, "Cdq" => { - "irn_flags" => "R", + # we should not rematrialize this node. It produces 2 results and has + # very strict constrains "comment" => "construct CDQ: sign extend EAX -> EDX:EAX", "reg_req" => { "in" => [ "gp" ], "out" => [ "eax in_r1", "edx" ] }, "emit" => '. cdq /* sign extend EAX -> EDX:EAX, (%A1) */', @@ -628,11 +673,11 @@ else { "Load" => { "op_flags" => "L|F", - "irn_flags" => "R", "state" => "exc_pinned", "comment" => "construct Load: Load(ptr, mem) = LD ptr -> reg", "cmp_attr" => " return ia32_compare_immop_attr(attr_a, attr_b);\n", "reg_req" => { "in" => [ "gp", "gp", "none" ], "out" => [ "gp" ] }, + "latency" => 3, "emit" => ' if (get_mode_size_bits(get_ia32_ls_mode(n)) < 32) { 4. mov%Mx %D1, %ia32_emit_am /* Load((%A1)) -> %D1 */ @@ -669,6 +714,7 @@ else { "reg_req" => { "in" => [ "gp", "gp", "gp", "none" ] }, "emit" => '. mov %ia32_emit_binop /* Store(%A3) -> (%A1) */', "outs" => [ "M" ], + "latency" => 3, }, "Store8Bit" => { @@ -676,9 +722,10 @@ else { "state" => "exc_pinned", "comment" => "construct 8Bit Store: Store(ptr, val, mem) = ST ptr,val", "cmp_attr" => " return ia32_compare_immop_attr(attr_a, attr_b);\n", - "reg_req" => { "in" => [ "gp", "gp", "eax ebx ecx edx", "none" ] }, + "reg_req" => { "in" => [ "gp", "gp", "eax ebx ecx edx gp_NOREG", "none" ] }, "emit" => '. mov %ia32_emit_binop /* Store(%A3) -> (%A1) */', "outs" => [ "M" ], + "latency" => 3, }, "Lea" => { @@ -686,48 +733,65 @@ else { "comment" => "construct Lea: Lea(a,b) = lea [a+b*const+offs] | res = a + b * const + offs with const = 0,1,2,4,8", "cmp_attr" => " return ia32_compare_immop_attr(attr_a, attr_b);\n", "reg_req" => { "in" => [ "gp", "gp" ], "out" => [ "in_r1" ] }, - "emit" => '. lea %D1, %ia32_emit_am /* LEA(%A1, %A2) */' + "emit" => '. lea %D1, %ia32_emit_am /* LEA(%A1, %A2) */', + "latency" => 2, }, "Push" => { - "comment" => "push a gp register on the stack", - "reg_req" => { "in" => [ "esp", "gp", "none" ], "out" => [ "esp" ] }, - "emit" => ' -if (get_ia32_id_cnst(n)) { - if (get_ia32_immop_type(n) == ia32_ImmConst) { -. push %C /* Push(%A2) */ - } else { -. push OFFSET FLAT:%C /* Push(%A2) */ - } -} -else { -. push %S2 /* Push(%A2) */ -} -', - "outs" => [ "stack", "M" ], + "comment" => "push on the stack", + "reg_req" => { "in" => [ "gp", "gp", "gp", "esp", "none" ], "out" => [ "esp" ] }, + "emit" => '. push %ia32_emit_unop /* PUSH(%A1) */', + "outs" => [ "stack:I|S", "M" ], + "latency" => 3, }, "Pop" => { + # We don't set class modify stack here (but we will do this on proj 1) "comment" => "pop a gp register from the stack", - "reg_req" => { "in" => [ "esp", "none" ], "out" => [ "gp", "esp" ] }, - "emit" => '. pop %D1 /* Pop -> %D1 */', - "outs" => [ "res", "stack", "M" ], + "reg_req" => { "in" => [ "gp", "gp", "esp", "none" ], "out" => [ "gp", "esp" ] }, + "emit" => '. pop %ia32_emit_unop /* POP(%A1) */', + "outs" => [ "res", "stack:I|S", "M" ], + "latency" => 4, }, "Enter" => { "comment" => "create stack frame", "reg_req" => { "in" => [ "esp" ], "out" => [ "ebp", "esp" ] }, "emit" => '. enter /* Enter */', - "outs" => [ "frame", "stack", "M" ], + "outs" => [ "frame:I", "stack:I|S", "M" ], + "latency" => 15, }, "Leave" => { "comment" => "destroy stack frame", "reg_req" => { "in" => [ "esp", "ebp" ], "out" => [ "ebp", "esp" ] }, "emit" => '. leave /* Leave */', - "outs" => [ "frame", "stack", "M" ], + "outs" => [ "frame:I", "stack:I|S", "M" ], + "latency" => 3, +}, + +"AddSP" => { + "irn_flags" => "I", + "comment" => "allocate space on stack", + "reg_req" => { "in" => [ "esp", "gp" ], "out" => [ "esp", "none" ] }, + "outs" => [ "stack:S", "M" ], +}, + +"SubSP" => { + "irn_flags" => "I", + "comment" => "free space on stack", + "reg_req" => { "in" => [ "esp", "gp" ], "out" => [ "esp", "none" ] }, + "outs" => [ "stack:S", "M" ], +}, + +"LdTls" => { + "irn_flags" => "R", + "comment" => "get the TLS base address", + "reg_req" => { "out" => [ "gp" ] }, }, + + #-----------------------------------------------------------------------------# # _____ _____ ______ __ _ _ _ # # / ____/ ____| ____| / _| | | | | | # @@ -746,6 +810,7 @@ else { "reg_req" => { "in" => [ "gp", "gp", "xmm", "xmm", "none" ], "out" => [ "in_r3" ] }, "emit" => '. adds%M %ia32_emit_binop /* SSE Add(%A3, %A4) -> %D1 */', "outs" => [ "res", "M" ], + "latency" => 4, }, "xMul" => { @@ -755,6 +820,7 @@ else { "reg_req" => { "in" => [ "gp", "gp", "xmm", "xmm", "none" ], "out" => [ "in_r3" ] }, "emit" => '. muls%M %ia32_emit_binop /* SSE Mul(%A3, %A4) -> %D1 */', "outs" => [ "res", "M" ], + "latency" => 4, }, "xMax" => { @@ -764,6 +830,7 @@ else { "reg_req" => { "in" => [ "gp", "gp", "xmm", "xmm", "none" ], "out" => [ "in_r3" ] }, "emit" => '. maxs%M %ia32_emit_binop /* SSE Max(%A3, %A4) -> %D1 */', "outs" => [ "res", "M" ], + "latency" => 2, }, "xMin" => { @@ -773,6 +840,7 @@ else { "reg_req" => { "in" => [ "gp", "gp", "xmm", "xmm", "none" ], "out" => [ "in_r3" ] }, "emit" => '. mins%M %ia32_emit_binop /* SSE Min(%A3, %A4) -> %D1 */', "outs" => [ "res", "M" ], + "latency" => 2, }, "xAnd" => { @@ -782,6 +850,7 @@ else { "reg_req" => { "in" => [ "gp", "gp", "xmm", "xmm", "none" ], "out" => [ "in_r3" ] }, "emit" => '. andp%M %ia32_emit_binop /* SSE And(%A3, %A4) -> %D1 */', "outs" => [ "res", "M" ], + "latency" => 3, }, "xOr" => { @@ -800,6 +869,7 @@ else { "reg_req" => { "in" => [ "gp", "gp", "xmm", "xmm", "none" ], "out" => [ "in_r3" ] }, "emit" => '. xorp%M %ia32_emit_binop /* SSE Xor(%A3, %A4) -> %D1 */', "outs" => [ "res", "M" ], + "latency" => 3, }, # not commutative operations @@ -811,6 +881,7 @@ else { "reg_req" => { "in" => [ "gp", "gp", "xmm", "xmm", "none" ], "out" => [ "in_r3 !in_r4" ] }, "emit" => '. andnp%M %ia32_emit_binop /* SSE AndNot(%A3, %A4) -> %D1 */', "outs" => [ "res", "M" ], + "latency" => 3, }, "xSub" => { @@ -820,6 +891,7 @@ else { "reg_req" => { "in" => [ "gp", "gp", "xmm", "xmm", "none" ], "out" => [ "in_r3" ] }, "emit" => '. subs%M %ia32_emit_binop /* SSE Sub(%A1, %A2) -> %D1 */', "outs" => [ "res", "M" ], + "latency" => 4, }, "xDiv" => { @@ -829,6 +901,7 @@ else { "reg_req" => { "in" => [ "gp", "gp", "xmm", "xmm", "none" ], "out" => [ "in_r3 !in_r4" ] }, "emit" => '. divs%M %ia32_emit_binop /* SSE Div(%A1, %A2) -> %D1 */', "outs" => [ "res", "M" ], + "latency" => 16, }, # other operations @@ -838,6 +911,7 @@ else { "comment" => "construct SSE Compare: Cmp(a, b) == a = a cmp b", "reg_req" => { "in" => [ "gp", "gp", "xmm", "xmm", "none" ], "out" => [ "in_r3 !in_r4" ] }, "outs" => [ "res", "M" ], + "latency" => 3, }, "xCondJmp" => { @@ -846,6 +920,7 @@ else { "cmp_attr" => " return ia32_compare_immop_attr(attr_a, attr_b);\n", "reg_req" => { "in" => [ "gp", "gp", "xmm", "xmm", "none" ], "out" => [ "none", "none" ] }, "outs" => [ "false", "true" ], + "latency" => 5, }, "xConst" => { @@ -853,21 +928,22 @@ else { "irn_flags" => "R", "comment" => "represents a SSE constant", "cmp_attr" => " return ia32_compare_immop_attr(attr_a, attr_b);\n", - "reg_req" => { "in" => [ "none" ], "out" => [ "xmm" ] }, + "reg_req" => { "out" => [ "xmm" ] }, "emit" => '. movs%M %D1, %C /* Load fConst into register */', + "latency" => 2, }, # Load / Store "xLoad" => { "op_flags" => "L|F", - "irn_flags" => "R", "state" => "exc_pinned", "comment" => "construct SSE Load: Load(ptr, mem) = LD ptr", "cmp_attr" => " return ia32_compare_immop_attr(attr_a, attr_b);\n", "reg_req" => { "in" => [ "gp", "gp", "none" ], "out" => [ "xmm" ] }, "emit" => '. movs%M %D1, %ia32_emit_am /* Load((%A1)) -> %D1 */', "outs" => [ "res", "M" ], + "latency" => 2, }, "xStore" => { @@ -878,6 +954,18 @@ else { "reg_req" => { "in" => [ "gp", "gp", "xmm", "none" ] }, "emit" => '. movs%M %ia32_emit_binop /* Store(%S3) -> (%A1) */', "outs" => [ "M" ], + "latency" => 2, +}, + +"xStoreSimple" => { + "op_flags" => "L|F", + "state" => "exc_pinned", + "comment" => "construct Store without index: Store(ptr, val, mem) = ST ptr,val", + "cmp_attr" => " return ia32_compare_immop_attr(attr_a, attr_b);\n", + "reg_req" => { "in" => [ "gp", "xmm", "none" ] }, + "emit" => '. movs%M %ia32_emit_am, %S2 /* store XMM0 onto stack */', + "outs" => [ "M" ], + "latency" => 2, }, "l_X87toSSE" => { @@ -903,6 +991,7 @@ else { "reg_req" => { "in" => [ "gp", "none" ] }, "emit" => '. fstp %ia32_emit_am /* store ST0 onto stack */', "outs" => [ "M" ], + "latency" => 4, }, "SetST0" => { @@ -911,9 +1000,10 @@ else { "state" => "exc_pinned", "comment" => "load ST0 from stack", "cmp_attr" => " return ia32_compare_immop_attr(attr_a, attr_b);\n", - "reg_req" => { "in" => [ "gp", "none" ], "out" => [ "st0", "none" ] }, + "reg_req" => { "in" => [ "gp", "none" ], "out" => [ "vf0", "none" ] }, "emit" => '. fld %ia32_emit_am /* load ST0 from stack */', "outs" => [ "res", "M" ], + "latency" => 2, }, # CopyB @@ -922,7 +1012,7 @@ else { "op_flags" => "F|H", "state" => "pinned", "comment" => "implements a memcopy: CopyB(dst, src, size, mem) == memcpy(dst, src, size)", - "reg_req" => { "in" => [ "gp", "gp", "gp", "none" ], "out" => [ "edi in_r1", "esi in_r2", "ecx in_r3", "none" ] }, + "reg_req" => { "in" => [ "edi", "esi", "ecx", "none" ], "out" => [ "edi", "esi", "ecx", "none" ] }, "outs" => [ "DST", "SRC", "CNT", "M" ], }, @@ -930,8 +1020,8 @@ else { "op_flags" => "F|H", "state" => "pinned", "comment" => "implements a memcopy: CopyB(dst, src, mem) == memcpy(dst, src, attr(size))", - "cmp_attr" => " return ia32_compare_immop_attr(attr_a, attr_b);\n", - "reg_req" => { "in" => [ "gp", "gp", "none" ], "out" => [ "edi in_r1", "esi in_r2", "none" ] }, + "cmp_attr" => " return ia32_compare_immop_attr(attr_a, attr_b);\n", + "reg_req" => { "in" => [ "edi", "esi", "none" ], "out" => [ "edi", "esi", "none" ] }, "outs" => [ "DST", "SRC", "M" ], }, @@ -939,61 +1029,68 @@ else { "Conv_I2I" => { "reg_req" => { "in" => [ "gp", "gp", "gp", "none" ], "out" => [ "in_r3", "none" ] }, - "cmp_attr" => " return ia32_compare_conv_attr(attr_a, attr_b);\n", + "cmp_attr" => " return ia32_compare_conv_attr(attr_a, attr_b);\n", "comment" => "construct Conv Int -> Int", - "outs" => [ "res", "M" ], + "outs" => [ "res", "M" ], }, "Conv_I2I8Bit" => { "reg_req" => { "in" => [ "gp", "gp", "eax ebx ecx edx", "none" ], "out" => [ "in_r3", "none" ] }, - "cmp_attr" => " return ia32_compare_conv_attr(attr_a, attr_b);\n", + "cmp_attr" => " return ia32_compare_conv_attr(attr_a, attr_b);\n", "comment" => "construct Conv Int -> Int", - "outs" => [ "res", "M" ], + "outs" => [ "res", "M" ], }, "Conv_I2FP" => { "reg_req" => { "in" => [ "gp", "gp", "gp", "none" ], "out" => [ "xmm", "none" ] }, - "cmp_attr" => " return ia32_compare_conv_attr(attr_a, attr_b);\n", + "cmp_attr" => " return ia32_compare_conv_attr(attr_a, attr_b);\n", "comment" => "construct Conv Int -> Floating Point", - "outs" => [ "res", "M" ], + "outs" => [ "res", "M" ], + "latency" => 10, }, "Conv_FP2I" => { "reg_req" => { "in" => [ "gp", "gp", "xmm", "none" ], "out" => [ "gp", "none" ] }, - "cmp_attr" => " return ia32_compare_conv_attr(attr_a, attr_b);\n", + "cmp_attr" => " return ia32_compare_conv_attr(attr_a, attr_b);\n", "comment" => "construct Conv Floating Point -> Int", - "outs" => [ "res", "M" ], + "outs" => [ "res", "M" ], + "latency" => 10, }, "Conv_FP2FP" => { "reg_req" => { "in" => [ "gp", "gp", "xmm", "none" ], "out" => [ "xmm", "none" ] }, - "cmp_attr" => " return ia32_compare_conv_attr(attr_a, attr_b);\n", + "cmp_attr" => " return ia32_compare_conv_attr(attr_a, attr_b);\n", "comment" => "construct Conv Floating Point -> Floating Point", - "outs" => [ "res", "M" ], + "outs" => [ "res", "M" ], + "latency" => 8, }, "CmpCMov" => { "irn_flags" => "R", "comment" => "construct Conditional Move: CMov(sel, a, b) == sel ? a : b", - "reg_req" => { "in" => [ "gp", "gp", "gp", "gp" ], "out" => [ "in_r4" ] } + "reg_req" => { "in" => [ "gp", "gp", "gp", "gp" ], "out" => [ "in_r4" ] }, + "latency" => 2, }, "PsiCondCMov" => { "irn_flags" => "R", "comment" => "check if Psi condition tree evaluates to true and move result accordingly", - "reg_req" => { "in" => [ "gp", "gp", "gp" ], "out" => [ "in_r3" ] } + "reg_req" => { "in" => [ "gp", "gp", "gp" ], "out" => [ "in_r3" ] }, + "latency" => 2, }, "xCmpCMov" => { "irn_flags" => "R", "comment" => "construct Conditional Move: SSE Compare + int CMov ", - "reg_req" => { "in" => [ "xmm", "xmm", "gp", "gp" ], "out" => [ "in_r4" ] } + "reg_req" => { "in" => [ "xmm", "xmm", "gp", "gp" ], "out" => [ "in_r4" ] }, + "latency" => 5, }, "vfCmpCMov" => { "irn_flags" => "R", "comment" => "construct Conditional Move: x87 Compare + int CMov", - "reg_req" => { "in" => [ "vfp", "vfp", "gp", "gp" ], "out" => [ "in_r4" ] } + "reg_req" => { "in" => [ "vfp", "vfp", "gp", "gp" ], "out" => [ "in_r4" ] }, + "latency" => 10, }, "CmpSet" => { @@ -1001,12 +1098,14 @@ else { "comment" => "construct Set: Set(sel) == sel ? 1 : 0", "reg_req" => { "in" => [ "gp", "gp", "gp", "gp", "none" ], "out" => [ "eax ebx ecx edx", "none" ] }, "outs" => [ "res", "M" ], + "latency" => 2, }, "PsiCondSet" => { "irn_flags" => "R", "comment" => "check if Psi condition tree evaluates to true and set result accordingly", "reg_req" => { "in" => [ "gp" ], "out" => [ "eax ebx ecx edx" ] }, + "latency" => 2, }, "xCmpSet" => { @@ -1014,6 +1113,7 @@ else { "comment" => "construct Set: SSE Compare + int Set", "reg_req" => { "in" => [ "gp", "gp", "xmm", "xmm", "none" ], "out" => [ "eax ebx ecx edx", "none" ] }, "outs" => [ "res", "M" ], + "latency" => 5, }, "vfCmpSet" => { @@ -1021,12 +1121,14 @@ else { "comment" => "construct Set: x87 Compare + int Set", "reg_req" => { "in" => [ "gp", "gp", "vfp", "vfp", "none" ], "out" => [ "eax ebx ecx edx", "none" ] }, "outs" => [ "res", "M" ], + "latency" => 10, }, "vfCMov" => { "irn_flags" => "R", "comment" => "construct x87 Conditional Move: vfCMov(sel, a, b) = sel ? a : b", - "reg_req" => { "in" => [ "vfp", "vfp", "vfp", "vfp" ], "out" => [ "vfp" ] } + "reg_req" => { "in" => [ "vfp", "vfp", "vfp", "vfp" ], "out" => [ "vfp" ] }, + "latency" => 10, }, #----------------------------------------------------------# @@ -1049,6 +1151,7 @@ else { "cmp_attr" => " return ia32_compare_immop_attr(attr_a, attr_b);\n", "reg_req" => { "in" => [ "gp", "gp", "vfp", "vfp", "none" ], "out" => [ "vfp" ] }, "outs" => [ "res", "M" ], + "latency" => 4, }, "vfmul" => { @@ -1057,6 +1160,7 @@ else { "cmp_attr" => " return ia32_compare_immop_attr(attr_a, attr_b);\n", "reg_req" => { "in" => [ "gp", "gp", "vfp", "vfp", "none" ], "out" => [ "vfp" ] }, "outs" => [ "res", "M" ], + "latency" => 4, }, "l_vfmul" => { @@ -1072,6 +1176,7 @@ else { "cmp_attr" => " return ia32_compare_immop_attr(attr_a, attr_b);\n", "reg_req" => { "in" => [ "gp", "gp", "vfp", "vfp", "none" ], "out" => [ "vfp" ] }, "outs" => [ "res", "M" ], + "latency" => 4, }, "l_vfsub" => { @@ -1085,6 +1190,7 @@ else { "cmp_attr" => " return ia32_compare_immop_attr(attr_a, attr_b);\n", "reg_req" => { "in" => [ "gp", "gp", "vfp", "vfp", "none" ], "out" => [ "vfp" ] }, "outs" => [ "res", "M" ], + "latency" => 20, }, "l_vfdiv" => { @@ -1097,42 +1203,47 @@ else { "irn_flags" => "R", "comment" => "virtual fp Abs: Abs(a) = |a|", "reg_req" => { "in" => [ "vfp"], "out" => [ "vfp" ] }, + "latency" => 2, }, "vfchs" => { "irn_flags" => "R", "comment" => "virtual fp Chs: Chs(a) = -a", "reg_req" => { "in" => [ "vfp"], "out" => [ "vfp" ] }, + "latency" => 2, }, "vfsin" => { "irn_flags" => "R", "comment" => "virtual fp Sin: Sin(a) = sin(a)", "reg_req" => { "in" => [ "vfp"], "out" => [ "vfp" ] }, + "latency" => 150, }, "vfcos" => { "irn_flags" => "R", "comment" => "virtual fp Cos: Cos(a) = cos(a)", "reg_req" => { "in" => [ "vfp"], "out" => [ "vfp" ] }, + "latency" => 150, }, "vfsqrt" => { "irn_flags" => "R", "comment" => "virtual fp Sqrt: Sqrt(a) = a ^ 0.5", "reg_req" => { "in" => [ "vfp"], "out" => [ "vfp" ] }, + "latency" => 30, }, # virtual Load and Store "vfld" => { "op_flags" => "L|F", - "irn_flags" => "R", "state" => "exc_pinned", "comment" => "virtual fp Load: Load(ptr, mem) = LD ptr -> reg", "cmp_attr" => " return ia32_compare_immop_attr(attr_a, attr_b);\n", "reg_req" => { "in" => [ "gp", "gp", "none" ], "out" => [ "vfp", "none" ] }, "outs" => [ "res", "M" ], + "latency" => 2, }, "vfst" => { @@ -1142,16 +1253,17 @@ else { "cmp_attr" => " return ia32_compare_immop_attr(attr_a, attr_b);\n", "reg_req" => { "in" => [ "gp", "gp", "vfp", "none" ] }, "outs" => [ "M" ], + "latency" => 2, }, # Conversions "vfild" => { - "irn_flags" => "R", "comment" => "virtual fp integer Load: Load(ptr, mem) = iLD ptr -> reg", "cmp_attr" => " return ia32_compare_immop_attr(attr_a, attr_b);\n", "reg_req" => { "in" => [ "gp", "gp", "none" ], "out" => [ "vfp", "none" ] }, "outs" => [ "res", "M" ], + "latency" => 4, }, "l_vfild" => { @@ -1166,6 +1278,7 @@ else { "cmp_attr" => " return ia32_compare_immop_attr(attr_a, attr_b);\n", "reg_req" => { "in" => [ "gp", "gp", "vfp", "none" ] }, "outs" => [ "M" ], + "latency" => 4, }, "l_vfist" => { @@ -1182,42 +1295,49 @@ else { "irn_flags" => "R", "comment" => "virtual fp Load 0.0: Ld 0.0 -> reg", "reg_req" => { "out" => [ "vfp" ] }, + "latency" => 4, }, "vfld1" => { "irn_flags" => "R", "comment" => "virtual fp Load 1.0: Ld 1.0 -> reg", "reg_req" => { "out" => [ "vfp" ] }, + "latency" => 4, }, "vfldpi" => { "irn_flags" => "R", "comment" => "virtual fp Load pi: Ld pi -> reg", "reg_req" => { "out" => [ "vfp" ] }, + "latency" => 4, }, "vfldln2" => { "irn_flags" => "R", "comment" => "virtual fp Load ln 2: Ld ln 2 -> reg", "reg_req" => { "out" => [ "vfp" ] }, + "latency" => 4, }, "vfldlg2" => { "irn_flags" => "R", "comment" => "virtual fp Load lg 2: Ld lg 2 -> reg", "reg_req" => { "out" => [ "vfp" ] }, + "latency" => 4, }, "vfldl2t" => { "irn_flags" => "R", "comment" => "virtual fp Load ld 10: Ld ld 10 -> reg", "reg_req" => { "out" => [ "vfp" ] }, + "latency" => 4, }, "vfldl2e" => { "irn_flags" => "R", "comment" => "virtual fp Load ld e: Ld ld e -> reg", "reg_req" => { "out" => [ "vfp" ] }, + "latency" => 4, }, "vfConst" => { @@ -1226,7 +1346,8 @@ else { "init_attr" => " set_ia32_ls_mode(res, mode);", "comment" => "represents a virtual floating point constant", "cmp_attr" => " return ia32_compare_immop_attr(attr_a, attr_b);\n", - "reg_req" => { "in" => [ "none" ], "out" => [ "vfp" ] }, + "reg_req" => { "out" => [ "vfp" ] }, + "latency" => 3, }, # other @@ -1237,6 +1358,7 @@ else { "cmp_attr" => " return ia32_compare_immop_attr(attr_a, attr_b);\n", "reg_req" => { "in" => [ "gp", "gp", "vfp", "vfp", "none" ], "out" => [ "none", "none", "eax" ] }, "outs" => [ "false", "true", "temp_reg_eax" ], + "latency" => 10, }, #------------------------------------------------------------------------# @@ -1252,7 +1374,7 @@ else { "rd_constructor" => "NONE", "comment" => "x87 Add: Add(a, b) = Add(b, a) = a + b", "reg_req" => { }, - "emit" => '. fadd %ia32_emit_x87_binop /* x87 fadd(%A1, %A2) -> %D1 */', + "emit" => '. fadd %ia32_emit_x87_binop /* x87 fadd(%A3, %A4) -> %D1 */', }, "faddp" => { @@ -1260,7 +1382,7 @@ else { "rd_constructor" => "NONE", "comment" => "x87 Add: Add(a, b) = Add(b, a) = a + b", "reg_req" => { }, - "emit" => '. faddp %ia32_emit_x87_binop /* x87 fadd(%A1, %A2) -> %D1 */', + "emit" => '. faddp %ia32_emit_x87_binop /* x87 fadd(%A3, %A4) -> %D1 */', }, "fmul" => { @@ -1268,7 +1390,7 @@ else { "rd_constructor" => "NONE", "comment" => "x87 fp Mul: Mul(a, b) = Mul(b, a) = a + b", "reg_req" => { }, - "emit" => '. fmul %ia32_emit_x87_binop /* x87 fmul(%A1, %A2) -> %D1 */', + "emit" => '. fmul %ia32_emit_x87_binop /* x87 fmul(%A3, %A4) -> %D1 */', }, "fmulp" => { @@ -1276,7 +1398,7 @@ else { "rd_constructor" => "NONE", "comment" => "x87 fp Mul: Mul(a, b) = Mul(b, a) = a + b", "reg_req" => { }, - "emit" => '. fmulp %ia32_emit_x87_binop /* x87 fmul(%A1, %A2) -> %D1 */',, + "emit" => '. fmulp %ia32_emit_x87_binop /* x87 fmul(%A3, %A4) -> %D1 */',, }, "fsub" => { @@ -1284,7 +1406,7 @@ else { "rd_constructor" => "NONE", "comment" => "x87 fp Sub: Sub(a, b) = a - b", "reg_req" => { }, - "emit" => '. fsub %ia32_emit_x87_binop /* x87 fsub(%A1, %A2) -> %D1 */', + "emit" => '. fsub %ia32_emit_x87_binop /* x87 fsub(%A3, %A4) -> %D1 */', }, "fsubp" => { @@ -1292,7 +1414,7 @@ else { "rd_constructor" => "NONE", "comment" => "x87 fp Sub: Sub(a, b) = a - b", "reg_req" => { }, - "emit" => '. fsubp %ia32_emit_x87_binop /* x87 fsub(%A1, %A2) -> %D1 */', + "emit" => '. fsubp %ia32_emit_x87_binop /* x87 fsub(%A3, %A4) -> %D1 */', }, "fsubr" => { @@ -1301,7 +1423,7 @@ else { "irn_flags" => "R", "comment" => "x87 fp SubR: SubR(a, b) = b - a", "reg_req" => { }, - "emit" => '. fsubr %ia32_emit_x87_binop /* x87 fsubr(%A1, %A2) -> %D1 */', + "emit" => '. fsubr %ia32_emit_x87_binop /* x87 fsubr(%A3, %A4) -> %D1 */', }, "fsubrp" => { @@ -1310,7 +1432,7 @@ else { "irn_flags" => "R", "comment" => "x87 fp SubR: SubR(a, b) = b - a", "reg_req" => { }, - "emit" => '. fsubrp %ia32_emit_x87_binop /* x87 fsubr(%A1, %A2) -> %D1 */', + "emit" => '. fsubrp %ia32_emit_x87_binop /* x87 fsubr(%A3, %A4) -> %D1 */', }, "fdiv" => { @@ -1318,7 +1440,7 @@ else { "rd_constructor" => "NONE", "comment" => "x87 fp Div: Div(a, b) = a / b", "reg_req" => { }, - "emit" => '. fdiv %ia32_emit_x87_binop /* x87 fdiv(%A1, %A2) -> %D1 */', + "emit" => '. fdiv %ia32_emit_x87_binop /* x87 fdiv(%A3, %A4) -> %D1 */', }, "fdivp" => { @@ -1326,7 +1448,7 @@ else { "rd_constructor" => "NONE", "comment" => "x87 fp Div: Div(a, b) = a / b", "reg_req" => { }, - "emit" => '. fdivp %ia32_emit_x87_binop /* x87 fdiv(%A1, %A2) -> %D1 */', + "emit" => '. fdivp %ia32_emit_x87_binop /* x87 fdiv(%A3, %A4) -> %D1 */', }, "fdivr" => { @@ -1334,7 +1456,7 @@ else { "rd_constructor" => "NONE", "comment" => "x87 fp DivR: DivR(a, b) = b / a", "reg_req" => { }, - "emit" => '. fdivr %ia32_emit_x87_binop /* x87 fdivr(%A1, %A2) -> %D1 */', + "emit" => '. fdivr %ia32_emit_x87_binop /* x87 fdivr(%A3, %A4) -> %D1 */', }, "fdivrp" => { @@ -1342,7 +1464,7 @@ else { "rd_constructor" => "NONE", "comment" => "x87 fp DivR: DivR(a, b) = b / a", "reg_req" => { }, - "emit" => '. fdivrp %ia32_emit_x87_binop /* x87 fdivr(%A1, %A2) -> %D1 */', + "emit" => '. fdivrp %ia32_emit_x87_binop /* x87 fdivr(%A3, %A4) -> %D1 */', }, "fabs" => { @@ -1350,7 +1472,7 @@ else { "rd_constructor" => "NONE", "comment" => "x87 fp Abs: Abs(a) = |a|", "reg_req" => { }, - "emit" => '. fabs /* x87 fabs(%S1) -> %D1 */', + "emit" => '. fabs /* x87 fabs(%A1) -> %D1 */', }, "fchs" => { @@ -1358,7 +1480,7 @@ else { "rd_constructor" => "NONE", "comment" => "x87 fp Chs: Chs(a) = -a", "reg_req" => { }, - "emit" => '. fchs /* x87 fchs(%S1) -> %D1 */', + "emit" => '. fchs /* x87 fchs(%A1) -> %D1 */', }, "fsin" => { @@ -1366,7 +1488,7 @@ else { "rd_constructor" => "NONE", "comment" => "x87 fp Sin: Sin(a) = sin(a)", "reg_req" => { }, - "emit" => '. fsin /* x87 sin(%S1) -> %D1 */', + "emit" => '. fsin /* x87 sin(%A1) -> %D1 */', }, "fcos" => { @@ -1374,7 +1496,7 @@ else { "rd_constructor" => "NONE", "comment" => "x87 fp Cos: Cos(a) = cos(a)", "reg_req" => { }, - "emit" => '. fcos /* x87 cos(%S1) -> %D1 */', + "emit" => '. fcos /* x87 cos(%A1) -> %D1 */', }, "fsqrt" => { @@ -1382,7 +1504,7 @@ else { "rd_constructor" => "NONE", "comment" => "x87 fp Sqrt: Sqrt(a) = a ^ 0.5", "reg_req" => { }, - "emit" => '. fsqrt $ /* x87 sqrt(%S1) -> %D1 */', + "emit" => '. fsqrt $ /* x87 sqrt(%A1) -> %D1 */', }, # x87 Load and Store @@ -1418,7 +1540,6 @@ else { "fild" => { "op_flags" => "R", - "irn_flags" => "R", "rd_constructor" => "NONE", "comment" => "x87 fp integer Load: Load(ptr, mem) = iLD ptr -> reg", "reg_req" => { }, @@ -1444,58 +1565,58 @@ else { # constants "fldz" => { - "op_flags" => "R", - "rd_constructor" => "NONE", + "op_flags" => "R|c", + "irn_flags" => "R", "comment" => "x87 fp Load 0.0: Ld 0.0 -> reg", - "reg_req" => { }, + "reg_req" => { "out" => [ "vfp" ] }, "emit" => '. fldz /* x87 0.0 -> %D1 */', }, "fld1" => { - "op_flags" => "R", - "rd_constructor" => "NONE", + "op_flags" => "R|c", + "irn_flags" => "R", "comment" => "x87 fp Load 1.0: Ld 1.0 -> reg", - "reg_req" => { }, + "reg_req" => { "out" => [ "vfp" ] }, "emit" => '. fld1 /* x87 1.0 -> %D1 */', }, "fldpi" => { - "op_flags" => "R", - "rd_constructor" => "NONE", + "op_flags" => "R|c", + "irn_flags" => "R", "comment" => "x87 fp Load pi: Ld pi -> reg", - "reg_req" => { }, + "reg_req" => { "out" => [ "vfp" ] }, "emit" => '. fldpi /* x87 pi -> %D1 */', }, "fldln2" => { - "op_flags" => "R", - "rd_constructor" => "NONE", + "op_flags" => "R|c", + "irn_flags" => "R", "comment" => "x87 fp Load ln 2: Ld ln 2 -> reg", - "reg_req" => { }, + "reg_req" => { "out" => [ "vfp" ] }, "emit" => '. fldln2 /* x87 ln(2) -> %D1 */', }, "fldlg2" => { - "op_flags" => "R", - "rd_constructor" => "NONE", + "op_flags" => "R|c", + "irn_flags" => "R", "comment" => "x87 fp Load lg 2: Ld lg 2 -> reg", - "reg_req" => { }, + "reg_req" => { "out" => [ "vfp" ] }, "emit" => '. fldlg2 /* x87 log(2) -> %D1 */', }, "fldl2t" => { - "op_flags" => "R", - "rd_constructor" => "NONE", + "op_flags" => "R|c", + "irn_flags" => "R", "comment" => "x87 fp Load ld 10: Ld ld 10 -> reg", - "reg_req" => { }, + "reg_req" => { "out" => [ "vfp" ] }, "emit" => '. fldll2t /* x87 ld(10) -> %D1 */', }, "fldl2e" => { - "op_flags" => "R", - "rd_constructor" => "NONE", + "op_flags" => "R|c", + "irn_flags" => "R", "comment" => "x87 fp Load ld e: Ld ld e -> reg", - "reg_req" => { }, + "reg_req" => { "out" => [ "vfp" ] }, "emit" => '. fldl2e /* x87 ld(e) -> %D1 */', }, @@ -1505,25 +1626,34 @@ else { "rd_constructor" => "NONE", "comment" => "represents a x87 constant", "cmp_attr" => " return ia32_compare_immop_attr(attr_a, attr_b);\n", - "reg_req" => { "out" => [ "st" ] }, + "reg_req" => { "out" => [ "vfp" ] }, "emit" => '. fld %ia32_emit_adr /* Load fConst into register -> %D1 */', }, # fxch, fpush, fpop # Note that it is NEVER allowed to do CSE on these nodes +# Moreover, note the virtual register requierements! "fxch" => { "op_flags" => "R|K", "comment" => "x87 stack exchange", - "reg_req" => { "in" => [ "st"], "out" => [ "st" ] }, + "reg_req" => { }, "cmp_attr" => " return 1;\n", "emit" => '. fxch %X1 /* x87 swap %X1, %X3 */', }, "fpush" => { + "op_flags" => "R|K", + "comment" => "x87 stack push", + "reg_req" => {}, + "cmp_attr" => " return 1;\n", + "emit" => '. fld %X1 /* x87 push %X1 */', +}, + +"fpushCopy" => { "op_flags" => "R", "comment" => "x87 stack push", - "reg_req" => { "in" => [ "st"], "out" => [ "st" ] }, + "reg_req" => { "in" => [ "vfp"], "out" => [ "vfp" ] }, "cmp_attr" => " return 1;\n", "emit" => '. fld %X1 /* x87 push %X1 */', }, @@ -1531,7 +1661,7 @@ else { "fpop" => { "op_flags" => "R|K", "comment" => "x87 stack pop", - "reg_req" => { "in" => [ "st"], "out" => [ "st" ] }, + "reg_req" => { }, "cmp_attr" => " return 1;\n", "emit" => '. fstp %X1 /* x87 pop %X1 */', },