Implement 8bit divmod patterns.
[gcc.git] / gcc / config / i386 / i386.md
index 1f7369b59647882327a897fe488621cf6a1463d0..d2afa853da2497cca7085ff07f595750383c9990 100644 (file)
 
 ;; Used in signed and unsigned divisions.
 (define_code_iterator any_div [div udiv])
+(define_code_attr extract_code
+  [(div "SIGN_EXTRACT") (udiv "ZERO_EXTRACT")])
 
 ;; Instruction prefix for signed and unsigned operations.
 (define_code_attr sgnprefix [(sign_extend "i") (zero_extend "")
 \f
 ;; Divide instructions
 
-(define_insn "<u>divqi3"
-  [(set (match_operand:QI 0 "register_operand" "=a")
-       (any_div:QI
-         (match_operand:HI 1 "register_operand" "0")
-         (match_operand:QI 2 "nonimmediate_operand" "qm")))
-   (clobber (reg:CC FLAGS_REG))]
-  "TARGET_QIMODE_MATH"
-  "<sgnprefix>div{b}\t%2"
-  [(set_attr "type" "idiv")
-   (set_attr "mode" "QI")])
-
 ;; The patterns that match these are at the end of this file.
 
 (define_expand "divxf3"
 \f
 ;; Divmod instructions.
 
+(define_expand "<u>divmodqi4"
+  [(parallel [(set (match_operand:QI 0 "register_operand" "")
+                  (any_div:QI
+                    (match_operand:QI 1 "register_operand" "")
+                    (match_operand:QI 2 "nonimmediate_operand" "")))
+             (set (match_operand:QI 3 "register_operand" "")
+                  (mod:QI (match_dup 1) (match_dup 2)))
+             (clobber (reg:CC FLAGS_REG))])]
+  "TARGET_QIMODE_MATH"
+{
+  rtx div, mod, insn;
+  rtx tmp0, tmp1;
+  
+  tmp0 = gen_reg_rtx (HImode);
+  tmp1 = gen_reg_rtx (HImode);
+
+  /* Extend operands[1] to HImode.  Generate 8bit divide.  Result is
+     in AX.  */
+  if (<extract_code> == SIGN_EXTRACT)
+    {
+      emit_insn (gen_extendqihi2 (tmp1, operands[1]));
+      emit_insn (gen_divmodhiqi3 (tmp0, tmp1, operands[2]));
+
+      div = gen_rtx_DIV (QImode, operands[1], operands[2]);
+      mod = gen_rtx_MOD (QImode, operands[1], operands[2]);
+
+      tmp1 = gen_rtx_<extract_code> (QImode, tmp0,
+                                    GEN_INT (8), GEN_INT (8));
+    }
+  else
+    {
+      emit_insn (gen_zero_extendqihi2 (tmp1, operands[1]));
+      emit_insn (gen_udivmodhiqi3 (tmp0, tmp1, operands[2]));
+
+      div = gen_rtx_UDIV (QImode, operands[1], operands[2]);
+      mod = gen_rtx_UMOD (QImode, operands[1], operands[2]);
+
+      tmp1 = gen_rtx_<extract_code> (SImode, tmp0,
+                                    GEN_INT (8), GEN_INT (8));
+      tmp1 = simplify_gen_subreg (QImode, tmp1, SImode, 0);
+    }
+
+  /* Extract remainder from AH.  */
+  insn = emit_move_insn (operands[3], tmp1);
+  set_unique_reg_note (insn, REG_EQUAL, mod);
+
+  /* Extract quotient from AL.  */
+  insn = emit_move_insn (operands[0], gen_lowpart (QImode, tmp0));
+  set_unique_reg_note (insn, REG_EQUAL, div);
+
+  DONE;
+})
+
+;; Divide AX by r/m8, with result stored in
+;; AL <- Quotient
+;; AH <- Remainder
+(define_insn "divmodhiqi3"
+  [(set (match_operand:HI 0 "register_operand" "=a")
+       (ior:HI
+         (ashift:HI
+           (zero_extend:HI
+             (mod:QI (match_operand:HI 1 "register_operand" "0")
+                     (match_operand:QI 2 "nonimmediate_operand" "qm")))
+           (const_int 8))
+         (zero_extend:HI (div:QI (match_dup 1) (match_dup 2)))))
+   (clobber (reg:CC FLAGS_REG))]
+  "TARGET_QIMODE_MATH"
+  "idiv{b}\t%2"
+  [(set_attr "type" "idiv")
+   (set_attr "mode" "QI")])
+
+(define_insn "udivmodhiqi3"
+  [(set (match_operand:HI 0 "register_operand" "=a")
+       (ior:HI
+         (ashift:HI
+           (zero_extend:HI
+             (umod:QI (match_operand:HI 1 "register_operand" "0")
+                      (match_operand:QI 2 "nonimmediate_operand" "qm")))
+           (const_int 8))
+         (zero_extend:HI (udiv:QI (match_dup 1) (match_dup 2)))))
+   (clobber (reg:CC FLAGS_REG))]
+  "TARGET_QIMODE_MATH"
+  "div{b}\t%2"
+  [(set_attr "type" "idiv")
+   (set_attr "mode" "QI")])
+
 (define_expand "divmod<mode>4"
   [(parallel [(set (match_operand:SWIM248 0 "register_operand" "")
                   (div:SWIM248