*** empty log message ***
authorRichard Stallman <rms@gnu.org>
Sat, 15 Feb 1992 21:27:49 +0000 (21:27 +0000)
committerRichard Stallman <rms@gnu.org>
Sat, 15 Feb 1992 21:27:49 +0000 (21:27 +0000)
From-SVN: r328

gcc/config/i386/i386.md

index 70f2224c8f14aef87065bc64174e56b75472cf30..95b3adbdab28926b45a3bf25d0554d0bf40c09eb 100644 (file)
   "TARGET_80387"
   "")
 
+;; The `ble' and `blt' patterns can reverse a compare, so we must allow
+;; an immediate operand as operand 0 in the recognizers below.
+
 (define_insn ""
   [(set (cc0)
        (compare (match_operand:DF 0 "general_operand" "f")
 
 ;; General case of fullword move.
 
+;; If generating PIC code and operands[1] is a symbolic CONST, emit a
+;; move to get the address of the symbolic object from the GOT.
+
+(define_expand "movsi"
+  [(set (match_operand:SI 0 "general_operand" "")
+       (match_operand:SI 1 "general_operand" ""))]
+  ""
+  "
+{
+  extern int flag_pic;
+
+  if (flag_pic && SYMBOLIC_CONST (operands[1]))
+    emit_pic_move (operands, SImode);
+}")
+
 ;; On i486, incl reg is faster than movl $1,reg.
 
-(define_insn "movsi"
+(define_insn ""
   [(set (match_operand:SI 0 "general_operand" "=g,r")
        (match_operand:SI 1 "general_operand" "ri,m"))]
   ""
 ;; Remainder instructions.
 
 (define_insn "divmodsi4"
-  [(set (match_operand:SI 0 "general_operand" "=a")
-       (div:SI (match_operand:SI 1 "general_operand" "0")
+  [(set (match_operand:SI 0 "register_operand" "=a")
+       (div:SI (match_operand:SI 1 "register_operand" "0")
                (match_operand:SI 2 "general_operand" "rm")))
-   (set (match_operand:SI 3 "general_operand" "=&d")
+   (set (match_operand:SI 3 "register_operand" "=&d")
        (mod:SI (match_dup 1) (match_dup 2)))]
   ""
   "*
 }")
 
 (define_insn "divmodhi4"
-  [(set (match_operand:HI 0 "general_operand" "=a")
-       (div:HI (match_operand:HI 1 "general_operand" "0")
+  [(set (match_operand:HI 0 "register_operand" "=a")
+       (div:HI (match_operand:HI 1 "register_operand" "0")
                (match_operand:HI 2 "general_operand" "rm")))
-   (set (match_operand:HI 3 "general_operand" "=&d")
+   (set (match_operand:HI 3 "register_operand" "=&d")
        (mod:HI (match_dup 1) (match_dup 2)))]
   ""
   "cwtd\;idiv%W0 %2")
 
 ;; ??? Can we make gcc zero extend operand[0]?
 (define_insn "udivmodsi4"
-  [(set (match_operand:SI 0 "general_operand" "=a")
-       (udiv:SI (match_operand:SI 1 "general_operand" "0")
+  [(set (match_operand:SI 0 "register_operand" "=a")
+       (udiv:SI (match_operand:SI 1 "register_operand" "0")
                 (match_operand:SI 2 "general_operand" "rm")))
-   (set (match_operand:SI 3 "general_operand" "=&d")
+   (set (match_operand:SI 3 "register_operand" "=&d")
        (umod:SI (match_dup 1) (match_dup 2)))]
   ""
   "*
 
 ;; ??? Can we make gcc zero extend operand[0]?
 (define_insn "udivmodhi4"
-  [(set (match_operand:HI 0 "general_operand" "=a")
-       (udiv:HI (match_operand:HI 1 "general_operand" "0")
+  [(set (match_operand:HI 0 "register_operand" "=a")
+       (udiv:HI (match_operand:HI 1 "register_operand" "0")
                 (match_operand:HI 2 "general_operand" "rm")))
-   (set (match_operand:HI 3 "general_operand" "=&d")
+   (set (match_operand:HI 3 "register_operand" "=&d")
        (umod:HI (match_dup 1) (match_dup 2)))]
   ""
   "*
 ;;this should be a valid double division which we may want to add
 
 (define_insn ""
-  [(set (match_operand:SI 0 "general_operand" "=a")
-       (udiv:DI (match_operand:DI 1 "general_operand" "a")
-               (match_operand:SI 2 "general_operand" "rm")))
-   (set (match_operand:SI 3 "general_operand" "=d")
+  [(set (match_operand:SI 0 "register_operand" "=a")
+       (udiv:DI (match_operand:DI 1 "register_operand" "a")
+                (match_operand:SI 2 "general_operand" "rm")))
+   (set (match_operand:SI 3 "register_operand" "=d")
        (umod:SI (match_dup 1) (match_dup 2)))]
   ""
   "div%L0 %2,%0")
 ;; bt on the MEM directly.
 
 (define_insn ""
-  [(set (cc0) (zero_extract (match_operand:QI 0 "nonimmediate_operand" "q")
+  [(set (cc0) (zero_extract (match_operand:QI 0 "register_operand" "q")
                            (const_int 1)
                            (match_operand:SI 1 "general_operand" "ri")))]
   ""
   RET;
 }")
 
+(define_insn ""
+  [(set (cc0) (zero_extract (match_operand:QI 0 "memory_operand" "m")
+                           (const_int 1)
+                           (match_operand:SI 1 "general_operand" "ri")))
+   (clobber (match_scratch:SI 2 "=&r"))]
+  ""
+  "*
+{
+  /* Copy memory to scratch register; pretend it was there to start with.  */
+  if (GET_CODE (operands[0]) == MEM)
+    {
+      output_asm_insn (AS2 (mov%L2,%0,%2), operands);
+      operands[0] = operands[2];
+    }
+  if (GET_CODE (operands[1]) == CONST_INT)
+    {
+      operands[1] = gen_rtx (CONST_INT, VOIDmode, 1 << INTVAL (operands[1]));
+      output_asm_insn (AS2 (test%L0,%1,%0), operands);
+    }
+  else
+    {
+      operands[0] = gen_rtx (REG, SImode, REGNO (operands[0]));
+      cc_status.flags |= CC_Z_IN_NOT_C;
+      output_asm_insn (AS2 (bt%L0,%1,%0), operands);
+    }
+  RET;
+}")
+
 (define_insn ""
   [(set (cc0) (zero_extract (match_operand:HI 0 "nonimmediate_operand" "r")
                            (const_int 1)
   ""
   "*
 {
-  if (cc_status.flags & CC_Z_IN_NOT_C)
+  if (cc_prev_status.flags & CC_Z_IN_NOT_C)
     return AS1 (setnb,%0);
   else
     return AS1 (sete,%0);
   ""
   "*
 {
-  if (cc_status.flags & CC_Z_IN_NOT_C)
+  if (cc_prev_status.flags & CC_Z_IN_NOT_C)
     return AS1 (setb,%0);
   else
     return AS1 (setne,%0);
   ""
   "*
 {
-  if (cc_status.flags & CC_Z_IN_NOT_C)
+  if (cc_prev_status.flags & CC_Z_IN_NOT_C)
     return \"jnc %l0\";
   else
     return \"je %l0\";
   ""
   "*
 {
-  if (cc_status.flags & CC_Z_IN_NOT_C)
+  if (cc_prev_status.flags & CC_Z_IN_NOT_C)
     return \"jc %l0\";
   else
     return \"jne %l0\";
   ""
   "*
 {
-  if (cc_status.flags & CC_Z_IN_NOT_C)
+  if (cc_prev_status.flags & CC_Z_IN_NOT_C)
     return \"jc %l0\";
   else
     return \"jne %l0\";
   ""
   "*
 {
-  if (cc_status.flags & CC_Z_IN_NOT_C)
+  if (cc_prev_status.flags & CC_Z_IN_NOT_C)
     return \"jnc %l0\";
   else
     return \"je %l0\";
   "jmp %l0")
 
 (define_insn "indirect_jump"
-  [(set (pc) (match_operand:SI 0 "register_operand" "a"))]
+  [(set (pc) (match_operand:SI 0 "general_operand" "rm"))]
   ""
   "*
 {
   return AS1 (jmp,%*%0);
 }")
 
+;; Implement switch statements when generating PIC code.  Switches are
+;; implemented by `tablejump' when not using -fpic.
+
+;; Emit code here to do the range checking and make the index zero based.
+
+(define_expand "casesi"
+  [(parallel
+    [(set (pc)
+         (if_then_else (leu (minus:SI
+                             (match_operand:SI 0 "general_operand" "")
+                             (match_operand:SI 1 "const_int_operand" ""))
+                            (match_operand:SI 2 "const_int_operand" ""))
+                       (plus:SI (mem:SI (plus:SI (pc)
+                                                 (minus:SI (match_dup 0)
+                                                           (match_dup 1))))
+                                (label_ref (match_operand 3 "" "")))
+                       (pc)))
+     (use (label_ref (match_operand 4 "" "")))
+     (clobber (match_scratch:SI 5 ""))])]
+  "flag_pic"
+  "
+{
+  rtx reg = gen_reg_rtx (SImode);
+
+  current_function_uses_pic_offset_table = 1;
+
+  emit_insn (gen_subsi3 (reg, operands[0], operands[1]));
+  emit_insn (gen_cmpsi (reg, operands[2]));
+  emit_jump_insn (gen_bgtu (operands[4]));
+  operands[0] = reg;
+  operands[1] = CONST0_RTX (SImode);
+}")
+
+;; Implement a casesi insn.
+
+;; Each entry in the "addr_diff_vec" looks like this as the result of the
+;; two rules below:
+;; 
+;;     .long _GLOBAL_OFFSET_TABLE_+[.-.L2]
+;; 
+;; 1. An expression involving an external reference may only use the
+;;    addition operator, and only with an assembly-time constant.
+;;    The example above satisfies this because ".-.L2" is a constant.
+;; 
+;; 2. The symbol _GLOBAL_OFFSET_TABLE_ is magic, and at link time is
+;;    given the value of "GOT - .", where GOT is the actual address of
+;;    the Global Offset Table.  Therefore, the .long above actually
+;;    stores the value "( GOT - . ) + [ . - .L2 ]", or "GOT - .L2".  The
+;;    expression "GOT - .L2" by itself would generate an error from as(1).
+;; 
+;; The pattern below emits code that looks like this:
+;; 
+;;     movl %ebx,reg
+;;     subl TABLE@GOTOFF(%ebx,index,4),reg
+;;     jmp reg
+;; 
+;; The addr_diff_vec contents may be directly referenced with @GOTOFF, since
+;; the addr_diff_vec is known to be part of this module.
+;; 
+;; The subl above calculates "GOT - (( GOT - . ) + [ . - .L2 ])", which
+;; evaluates to just ".L2".
+
+(define_insn ""
+  [(set (pc)
+       (if_then_else (leu (minus:SI
+                           (match_operand:SI 0 "general_operand" "r")
+                           (match_operand:SI 1 "const_int_operand" "i"))
+                          (match_operand:SI 2 "const_int_operand" "i"))
+                     (plus:SI (mem:SI (plus:SI (pc)
+                                               (minus:SI (match_dup 0)
+                                                         (match_dup 1))))
+                              (label_ref (match_operand 3 "" "")))
+                     (pc)))
+   (use (label_ref (match_operand 4 "" "")))
+   (clobber (match_scratch:SI 5 "=&r"))]
+  ""
+  "*
+{
+  rtx xops[4];
+
+  xops[0] = pic_offset_table_rtx;
+  xops[1] = operands[5];
+  xops[2] = operands[3];
+  xops[3] = operands[0];
+
+  output_asm_insn (AS2 (mov%L1,%0,%1), xops);
+  output_asm_insn (\"sub%L1 %l2@GOTOFF(%0,%3,4),%1\", xops);
+  output_asm_insn (AS1 (jmp,%*%1), xops);
+  ASM_OUTPUT_ALIGN_CODE (asm_out_file);
+  RET;
+}")
+
 (define_insn "tablejump"
   [(set (pc) (match_operand:SI 0 "general_operand" "rm"))
    (use (label_ref (match_operand 1 "" "")))]
   return AS1 (jmp,%*%0);
 }")
 
+;; Call insns.
+
+;; If generating PIC code, the predicate indirect_operand will fail
+;; for operands[0] containing symbolic references on all of the named
+;; call* patterns.  Each named pattern is followed by an unnamed pattern
+;; that matches any call to a symbolic CONST (ie, a symbol_ref).  The
+;; unnamed patterns are only used while generating PIC code, because
+;; otherwise the named patterns match.
+
 ;; Call subroutine returning no value.
 
-(define_insn "call_pop"
+(define_expand "call_pop"
+  [(parallel [(call (match_operand:QI 0 "indirect_operand" "")
+                   (match_operand:SI 1 "general_operand" ""))
+             (set (reg:SI 7)
+                  (plus:SI (reg:SI 7)
+                           (match_operand:SI 3 "immediate_operand" "")))])]
+  ""
+  "
+{
+  if (flag_pic)
+    current_function_uses_pic_offset_table = 1;
+}")
+
+(define_insn ""
   [(call (match_operand:QI 0 "indirect_operand" "m")
         (match_operand:SI 1 "general_operand" "g"))
    (set (reg:SI 7) (plus:SI (reg:SI 7)
     return AS1 (call,%P0);
 }")
 
-(define_insn "call"
+(define_insn ""
+  [(call (mem:QI (match_operand:SI 0 "symbolic_operand" ""))
+        (match_operand:SI 1 "general_operand" "g"))
+   (set (reg:SI 7) (plus:SI (reg:SI 7)
+                           (match_operand:SI 3 "immediate_operand" "i")))]
+  ""
+  "call %P0")
+
+(define_expand "call"
+  [(call (match_operand:QI 0 "indirect_operand" "")
+        (match_operand:SI 1 "general_operand" ""))]
+  ;; Operand 1 not used on the i386.
+  ""
+  "
+{
+  if (flag_pic)
+    current_function_uses_pic_offset_table = 1;
+}")
+
+(define_insn ""
   [(call (match_operand:QI 0 "indirect_operand" "m")
         (match_operand:SI 1 "general_operand" "g"))]
   ;; Operand 1 not used on the i386.
     return AS1 (call,%P0);
 }")
 
+(define_insn ""
+  [(call (mem:QI (match_operand:SI 0 "symbolic_operand" ""))
+        (match_operand:SI 1 "general_operand" "g"))]
+  ;; Operand 1 not used on the i386.
+  ""
+  "call %P0")
+
 ;; Call subroutine, returning value in operand 0
 ;; (which must be a hard register).
 
-(define_insn "call_value_pop"
+(define_expand "call_value_pop"
+  [(parallel [(set (match_operand 0 "" "")
+                  (call (match_operand:QI 1 "indirect_operand" "")
+                        (match_operand:SI 2 "general_operand" "")))
+             (set (reg:SI 7)
+                  (plus:SI (reg:SI 7)
+                           (match_operand:SI 4 "immediate_operand" "")))])]
+  ""
+  "
+{
+  if (flag_pic)
+    current_function_uses_pic_offset_table = 1;
+}")
+
+(define_insn ""
   [(set (match_operand 0 "" "=rf")
        (call (match_operand:QI 1 "indirect_operand" "m")
              (match_operand:SI 2 "general_operand" "g")))
   RET;
 }")
 
-(define_insn "call_value"
+(define_insn ""
+  [(set (match_operand 0 "" "=rf")
+       (call (mem:QI (match_operand:SI 1 "symbolic_operand" ""))
+             (match_operand:SI 2 "general_operand" "g")))
+   (set (reg:SI 7) (plus:SI (reg:SI 7)
+                           (match_operand:SI 4 "immediate_operand" "i")))]
+  ""
+  "call %P1")
+
+(define_expand "call_value"
+  [(set (match_operand 0 "" "")
+       (call (match_operand:QI 1 "indirect_operand" "")
+             (match_operand:SI 2 "general_operand" "")))]
+  ;; Operand 2 not used on the i386.
+  ""
+  "
+{
+  if (flag_pic)
+    current_function_uses_pic_offset_table = 1;
+}")
+
+(define_insn ""
   [(set (match_operand 0 "" "=rf")
        (call (match_operand:QI 1 "indirect_operand" "m")
              (match_operand:SI 2 "general_operand" "g")))]
   RET;
 }")
 
+(define_insn ""
+  [(set (match_operand 0 "" "=rf")
+       (call (mem:QI (match_operand:SI 1 "symbolic_operand" ""))
+             (match_operand:SI 2 "general_operand" "g")))]
+  ;; Operand 2 not used on the i386.
+  ""
+  "call %P1")
+
 ;; Insn emitted into the body of a function to return from a function.
 ;; This is only done if the function's epilogue is known to be simple.
 ;; See comments for simple_386_epilogue in i386.c.