X-Git-Url: http://nsz.repo.hu/git/?a=blobdiff_plain;f=ir%2Fbe%2Fia32%2Fia32_spec.pl;h=f4c6328aa3561886e896c899d37d1043d40055fd;hb=a1a465eb2b3f54027b29f829423fffd0396937f4;hp=4390e1f7ed1f51d60e7c9163fb550714c509e3a1;hpb=9b583efe55a271e64ca668f5546ed47fe960ab1a;p=libfirm diff --git a/ir/be/ia32/ia32_spec.pl b/ir/be/ia32/ia32_spec.pl index 4390e1f7e..f4c6328aa 100644 --- a/ir/be/ia32/ia32_spec.pl +++ b/ir/be/ia32/ia32_spec.pl @@ -73,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 # @@ -100,6 +104,8 @@ $comment_string = "/*"; # 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" => [ @@ -133,8 +139,8 @@ $comment_string = "/*"; # { "name" => "r32", "type" => 1 }, { "name" => "ebp", "type" => 2 }, { "name" => "esp", "type" => 4 }, - { "name" => "gp_NOREG", "type" => 2 | 4 }, # we need a dummy register for NoReg nodes - { "name" => "gp_UKNWN", "type" => 2 | 4 | 8 }, # 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" => [ @@ -146,21 +152,21 @@ $comment_string = "/*"; { "name" => "xmm5", "type" => 1 }, { "name" => "xmm6", "type" => 1 }, { "name" => "xmm7", "type" => 1 }, - { "name" => "xmm_NOREG", "type" => 2 | 4 }, # we need a dummy register for NoReg nodes - { "name" => "xmm_UKNWN", "type" => 2 | 4 | 8 }, # 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" => 2 | 4 }, # we need a dummy register for NoReg nodes - { "name" => "vfp_UKNWN", "type" => 2 | 4 | 8 }, # 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" => [ @@ -431,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" => [ "!ecx in_r3 !in_r4" ] }, + # 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) { @@ -480,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" => [ "!ecx in_r3 !in_r4" ] }, + # 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) { @@ -635,7 +657,7 @@ 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" => { @@ -716,11 +738,10 @@ else { }, "Push" => { - # We don't set class modify_stack here (but we will do this on proj 0) "comment" => "push on the stack", "reg_req" => { "in" => [ "gp", "gp", "gp", "esp", "none" ], "out" => [ "esp" ] }, "emit" => '. push %ia32_emit_unop /* PUSH(%A1) */', - "outs" => [ "stack", "M" ], + "outs" => [ "stack:I|S", "M" ], "latency" => 3, }, @@ -729,7 +750,7 @@ else { "comment" => "pop a gp register from the stack", "reg_req" => { "in" => [ "gp", "gp", "esp", "none" ], "out" => [ "gp", "esp" ] }, "emit" => '. pop %ia32_emit_unop /* POP(%A1) */', - "outs" => [ "res", "stack", "M" ], + "outs" => [ "res", "stack:I|S", "M" ], "latency" => 4, }, @@ -737,7 +758,7 @@ else { "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, }, @@ -745,7 +766,7 @@ else { "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, }, @@ -753,14 +774,14 @@ else { "irn_flags" => "I", "comment" => "allocate space on stack", "reg_req" => { "in" => [ "esp", "gp" ], "out" => [ "esp", "none" ] }, - "outs" => [ "stack", "M" ], + "outs" => [ "stack:S", "M" ], }, "SubSP" => { "irn_flags" => "I", "comment" => "free space on stack", "reg_req" => { "in" => [ "esp", "gp" ], "out" => [ "esp", "none" ] }, - "outs" => [ "stack", "M" ], + "outs" => [ "stack:S", "M" ], }, "LdTls" => { @@ -907,7 +928,7 @@ 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, }, @@ -1325,7 +1346,7 @@ 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, }, @@ -1547,7 +1568,7 @@ else { "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 */', }, @@ -1555,7 +1576,7 @@ else { "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 */', }, @@ -1563,7 +1584,7 @@ else { "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 */', }, @@ -1571,7 +1592,7 @@ else { "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 */', }, @@ -1579,7 +1600,7 @@ else { "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 */', }, @@ -1587,7 +1608,7 @@ else { "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 */', }, @@ -1595,7 +1616,7 @@ else { "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 */', }, @@ -1605,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 */', }, @@ -1631,7 +1661,7 @@ else { "fpop" => { "op_flags" => "R|K", "comment" => "x87 stack pop", - "reg_req" => { "out" => [ "st" ] }, + "reg_req" => { }, "cmp_attr" => " return 1;\n", "emit" => '. fstp %X1 /* x87 pop %X1 */', },