- Improved addressmode optimisation for conv nodes
[libfirm] / ir / be / ia32 / ia32_spec.pl
index e23fc0e..f4c6328 100644 (file)
@@ -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" => 6 },  # we need a dummy register for NoReg nodes
-            { "name" => "gp_UKNWN", "type" => },  # 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" => 6 },  # we need a dummy register for NoReg nodes
-            { "name" => "xmm_UKNWN", "type" => },  # 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" => },  # 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,
 },
@@ -979,7 +1000,7 @@ 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,
@@ -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 */',
 },