Commit 44080af9 by Stafford Horne Committed by Stafford Horne

or1k: Initial support for FPU

This adds support for OpenRISC hardware floating point instructions.
This is enabled with the -mhard-float option.

Double-prevision floating point operations work using register pairing as
specified in: https://openrisc.io/proposals/orfpx64a32.  This has just been
added in the OpenRISC architecture specification 1.3.
This is enabled with the -mdouble-float option.

Not all architectures support unordered comparisons so an option,
-munordered-float is added.

Currently OpenRISC does not support sf/df or df/sf conversions, but this has
also just been added in architecture specification 1.3.

gcc/ChangeLog:

	* config.gcc (or1k*-*-*): Add mhard-float, mdouble-float, msoft-float
	and munordered-float validations.
	* config/or1k/constraints.md (d): New register constraint.
	* config/or1k/predicates.md (fp_comparison_operator): New.
	* config/or1k/or1k.c (or1k_print_operand): Add support for printing 'd'
	operands.
	(or1k_expand_compare): Normalize unordered comparisons.
	* config/or1k/or1k.h (reg_class): Define DOUBLE_REGS.
	(REG_CLASS_NAMES): Add "DOUBLE_REGS".
	(REG_CLASS_CONTENTS): Add contents for DOUBLE_REGS.
	* config/or1k/or1k.md (type): Add fpu.
	(fpu): New instruction reservation.
	(F, f, fr, fi, FI, FOP, fop): New.
	(<fop><F:mode>3): New ALU instruction definition.
	(float<fi><F:mode>2): New conversion instruction definition.
	(fix_trunc<F:mode><fi>2): New conversion instruction definition.
	(fpcmpcc): New code iterator.
	(*sf_fp_insn): New instruction definition.
	(cstore<F:mode>4): New expand definition.
	(cbranch<F:mode>4): New expand definition.
	* config/or1k/or1k.opt (msoft-float, mhard-float, mdouble-float,
	munordered-float): New options.
	* doc/invoke.texi: Document msoft-float, mhard-float, mdouble-float and
	munordered-float.

From-SVN: r273650
parent 1e2e81c1
2019-07-22 Stafford Horne <shorne@gmail.com> 2019-07-22 Stafford Horne <shorne@gmail.com>
* config.gcc (or1k*-*-*): Add mhard-float, mdouble-float, msoft-float
and munordered-float validations.
* config/or1k/constraints.md (d): New register constraint.
* config/or1k/predicates.md (fp_comparison_operator): New.
* config/or1k/or1k.c (or1k_print_operand): Add support for printing 'd'
operands.
(or1k_expand_compare): Normalize unordered comparisons.
* config/or1k/or1k.h (reg_class): Define DOUBLE_REGS.
(REG_CLASS_NAMES): Add "DOUBLE_REGS".
(REG_CLASS_CONTENTS): Add contents for DOUBLE_REGS.
* config/or1k/or1k.md (type): Add fpu.
(fpu): New instruction reservation.
(F, f, fr, fi, FI, FOP, fop): New.
(<fop><F:mode>3): New ALU instruction definition.
(float<fi><F:mode>2): New conversion instruction definition.
(fix_trunc<F:mode><fi>2): New conversion instruction definition.
(fpcmpcc): New code iterator.
(*sf_fp_insn): New instruction definition.
(cstore<F:mode>4): New expand definition.
(cbranch<F:mode>4): New expand definition.
* config/or1k/or1k.opt (msoft-float, mhard-float, mdouble-float,
munordered-float): New options.
* doc/invoke.texi: Document msoft-float, mhard-float, mdouble-float and
munordered-float.
2019-07-22 Stafford Horne <shorne@gmail.com>
* config.gcc (or1k*-*-*): Add mrori and mror to validation. * config.gcc (or1k*-*-*): Add mrori and mror to validation.
* doc/invoke.texi (OpenRISC Options): Add mrori option, rewrite all * doc/invoke.texi (OpenRISC Options): Add mrori option, rewrite all
documenation to be more clear. documenation to be more clear.
......
...@@ -2579,6 +2579,7 @@ or1k*-*-*) ...@@ -2579,6 +2579,7 @@ or1k*-*-*)
case ${or1k_multilib} in case ${or1k_multilib} in
mcmov | msext | msfimm | \ mcmov | msext | msfimm | \
mror | mrori | \ mror | mrori | \
mhard-float | mdouble-float | munordered-float | msoft-float | \
mhard-div | mhard-mul | \ mhard-div | mhard-mul | \
msoft-div | msoft-mul ) msoft-div | msoft-mul )
TM_MULTILIB_CONFIG="${TM_MULTILIB_CONFIG},${or1k_multilib}" TM_MULTILIB_CONFIG="${TM_MULTILIB_CONFIG},${or1k_multilib}"
......
...@@ -24,6 +24,7 @@ ...@@ -24,6 +24,7 @@
; We use: ; We use:
; c - sibcall registers ; c - sibcall registers
; d - double pair base registers (excludes r0, r30 and r31 which overflow)
; I - constant signed 16-bit ; I - constant signed 16-bit
; K - constant unsigned 16-bit ; K - constant unsigned 16-bit
; M - constant signed 16-bit shifted left 16-bits (l.movhi) ; M - constant signed 16-bit shifted left 16-bits (l.movhi)
...@@ -32,6 +33,9 @@ ...@@ -32,6 +33,9 @@
(define_register_constraint "c" "SIBCALL_REGS" (define_register_constraint "c" "SIBCALL_REGS"
"Registers which can hold a sibling call address") "Registers which can hold a sibling call address")
(define_register_constraint "d" "DOUBLE_REGS"
"Registers which can be used for double reg pairs.")
;; Immediates ;; Immediates
(define_constraint "I" (define_constraint "I"
"A signed 16-bit immediate in the range -32768 to 32767." "A signed 16-bit immediate in the range -32768 to 32767."
......
...@@ -1226,6 +1226,19 @@ or1k_print_operand (FILE *file, rtx x, int code) ...@@ -1226,6 +1226,19 @@ or1k_print_operand (FILE *file, rtx x, int code)
output_operand_lossage ("invalid %%H value"); output_operand_lossage ("invalid %%H value");
break; break;
case 'd':
if (REG_P (x))
{
if (GET_MODE (x) == DFmode || GET_MODE (x) == DImode)
fprintf (file, "%s,%s", reg_names[REGNO (operand)],
reg_names[REGNO (operand) + 1]);
else
fprintf (file, "%s", reg_names[REGNO (operand)]);
}
else
output_operand_lossage ("invalid %%d value");
break;
case 'h': case 'h':
print_reloc (file, x, 0, RKIND_HI); print_reloc (file, x, 0, RKIND_HI);
break; break;
...@@ -1435,21 +1448,42 @@ void ...@@ -1435,21 +1448,42 @@ void
or1k_expand_compare (rtx *operands) or1k_expand_compare (rtx *operands)
{ {
rtx sr_f = gen_rtx_REG (BImode, SR_F_REGNUM); rtx sr_f = gen_rtx_REG (BImode, SR_F_REGNUM);
rtx_code cmp_code = GET_CODE (operands[0]);
bool flag_check_ne = true;
/* The RTL may receive an immediate in argument 1 of the compare, this is not /* The RTL may receive an immediate in argument 1 of the compare, this is not
supported unless we have l.sf*i instructions, force them into registers. */ supported unless we have l.sf*i instructions, force them into registers. */
if (!TARGET_SFIMM) if (!TARGET_SFIMM)
XEXP (operands[0], 1) = force_reg (SImode, XEXP (operands[0], 1)); XEXP (operands[0], 1) = force_reg (SImode, XEXP (operands[0], 1));
/* Normalize comparison operators to ones OpenRISC support. */
switch (cmp_code)
{
case LTGT:
cmp_code = UNEQ;
flag_check_ne = false;
break;
case ORDERED:
cmp_code = UNORDERED;
flag_check_ne = false;
break;
default:
break;
}
/* Emit the given comparison into the Flag bit. */ /* Emit the given comparison into the Flag bit. */
PUT_MODE (operands[0], BImode); PUT_MODE (operands[0], BImode);
PUT_CODE (operands[0], cmp_code);
emit_insn (gen_rtx_SET (sr_f, operands[0])); emit_insn (gen_rtx_SET (sr_f, operands[0]));
/* Adjust the operands for use in the caller. */ /* Adjust the operands for use in the caller. */
operands[0] = gen_rtx_NE (VOIDmode, sr_f, const0_rtx); operands[0] = flag_check_ne ? gen_rtx_NE (VOIDmode, sr_f, const0_rtx)
: gen_rtx_EQ (VOIDmode, sr_f, const0_rtx);
operands[1] = sr_f; operands[1] = sr_f;
operands[2] = const0_rtx; operands[2] = const0_rtx;
} }
/* Expand the patterns "call", "sibcall", "call_value" and "sibcall_value". /* Expand the patterns "call", "sibcall", "call_value" and "sibcall_value".
Expands a function call where argument RETVAL is an optional RTX providing Expands a function call where argument RETVAL is an optional RTX providing
......
...@@ -189,6 +189,7 @@ enum reg_class ...@@ -189,6 +189,7 @@ enum reg_class
{ {
NO_REGS, NO_REGS,
SIBCALL_REGS, SIBCALL_REGS,
DOUBLE_REGS,
GENERAL_REGS, GENERAL_REGS,
FLAG_REGS, FLAG_REGS,
ALL_REGS, ALL_REGS,
...@@ -200,6 +201,7 @@ enum reg_class ...@@ -200,6 +201,7 @@ enum reg_class
#define REG_CLASS_NAMES { \ #define REG_CLASS_NAMES { \
"NO_REGS", \ "NO_REGS", \
"SIBCALL_REGS", \ "SIBCALL_REGS", \
"DOUBLE_REGS", \
"GENERAL_REGS", \ "GENERAL_REGS", \
"FLAG_REGS", \ "FLAG_REGS", \
"ALL_REGS" } "ALL_REGS" }
...@@ -212,6 +214,7 @@ enum reg_class ...@@ -212,6 +214,7 @@ enum reg_class
#define REG_CLASS_CONTENTS \ #define REG_CLASS_CONTENTS \
{ { 0x00000000, 0x00000000 }, \ { { 0x00000000, 0x00000000 }, \
{ SIBCALL_REGS_MASK, 0 }, \ { SIBCALL_REGS_MASK, 0 }, \
{ 0x7f7ffffe, 0x00000000 }, \
{ 0xffffffff, 0x00000003 }, \ { 0xffffffff, 0x00000003 }, \
{ 0x00000000, 0x00000004 }, \ { 0x00000000, 0x00000004 }, \
{ 0xffffffff, 0x00000007 } \ { 0xffffffff, 0x00000007 } \
......
...@@ -60,7 +60,7 @@ ...@@ -60,7 +60,7 @@
(define_attr "length" "" (const_int 4)) (define_attr "length" "" (const_int 4))
(define_attr "type" (define_attr "type"
"alu,st,ld,control,multi" "alu,st,ld,control,multi,fpu"
(const_string "alu")) (const_string "alu"))
(define_attr "insn_support" "class1,sext,sfimm,shftimm,ror,rori" (const_string "class1")) (define_attr "insn_support" "class1,sext,sfimm,shftimm,ror,rori" (const_string "class1"))
...@@ -97,6 +97,10 @@ ...@@ -97,6 +97,10 @@
(define_insn_reservation "control" 1 (define_insn_reservation "control" 1
(eq_attr "type" "control") (eq_attr "type" "control")
"cpu") "cpu")
(define_insn_reservation "fpu" 2
(eq_attr "type" "fpu")
"cpu")
; Define delay slots for any branch ; Define delay slots for any branch
(define_delay (eq_attr "type" "control") (define_delay (eq_attr "type" "control")
...@@ -160,6 +164,47 @@ ...@@ -160,6 +164,47 @@
"l.sub\t%0, %r1, %2") "l.sub\t%0, %r1, %2")
;; ------------------------------------------------------------------------- ;; -------------------------------------------------------------------------
;; Floating Point Arithmetic instructions
;; -------------------------------------------------------------------------
;; Mode iterator for single/double float
(define_mode_iterator F [(SF "TARGET_HARD_FLOAT")
(DF "TARGET_DOUBLE_FLOAT")])
(define_mode_attr f [(SF "s") (DF "d")])
(define_mode_attr fr [(SF "r") (DF "d")])
(define_mode_attr fi [(SF "si") (DF "di")])
(define_mode_attr FI [(SF "SI") (DF "DI")])
;; Basic arithmetic instructions
(define_code_iterator FOP [plus minus mult div])
(define_code_attr fop [(plus "add") (minus "sub") (mult "mul") (div "div")])
(define_insn "<fop><F:mode>3"
[(set (match_operand:F 0 "register_operand" "=<fr>")
(FOP:F (match_operand:F 1 "register_operand" "<fr>")
(match_operand:F 2 "register_operand" "<fr>")))]
"TARGET_HARD_FLOAT"
"lf.<fop>.<f>\t%d0, %d1, %d2"
[(set_attr "type" "fpu")])
;; Basic float<->int conversion
(define_insn "float<fi><F:mode>2"
[(set (match_operand:F 0 "register_operand" "=<fr>")
(float:F
(match_operand:<FI> 1 "register_operand" "<fr>")))]
"TARGET_HARD_FLOAT"
"lf.itof.<f>\t%d0, %d1"
[(set_attr "type" "fpu")])
(define_insn "fix_trunc<F:mode><fi>2"
[(set (match_operand:<FI> 0 "register_operand" "=<fr>")
(fix:<FI>
(match_operand:F 1 "register_operand" "<fr>")))]
"TARGET_HARD_FLOAT"
"lf.ftoi.<f>\t%d0, %d1"
[(set_attr "type" "fpu")])
;; -------------------------------------------------------------------------
;; Logical operators ;; Logical operators
;; ------------------------------------------------------------------------- ;; -------------------------------------------------------------------------
...@@ -380,7 +425,7 @@ ...@@ -380,7 +425,7 @@
(define_code_iterator intcmpcc [ne eq lt ltu gt gtu ge le geu leu]) (define_code_iterator intcmpcc [ne eq lt ltu gt gtu ge le geu leu])
(define_code_attr insn [(ne "ne") (eq "eq") (lt "lts") (ltu "ltu") (define_code_attr insn [(ne "ne") (eq "eq") (lt "lts") (ltu "ltu")
(gt "gts") (gtu "gtu") (ge "ges") (le "les") (gt "gts") (gtu "gtu") (ge "ges") (le "les")
(geu "geu") (leu "leu") ]) (geu "geu") (leu "leu")])
(define_insn "*sf_insn" (define_insn "*sf_insn"
[(set (reg:BI SR_F_REGNUM) [(set (reg:BI SR_F_REGNUM)
...@@ -392,6 +437,36 @@ ...@@ -392,6 +437,36 @@
l.sf<insn>i\t%r0, %1" l.sf<insn>i\t%r0, %1"
[(set_attr "insn_support" "*,sfimm")]) [(set_attr "insn_support" "*,sfimm")])
;; Support FP comparisons too
;; The OpenRISC FPU supports these comparisons:
;;
;; lf.sfeq.{d,s} - equality, r r, double or single precision
;; lf.sfge.{d,s} - greater than or equal, r r, double or single precision
;; lf.sfgt.{d,s} - greater than, r r, double or single precision
;; lf.sfle.{d,s} - less than or equal, r r, double or single precision
;; lf.sflt.{d,s} - less than, r r, double or single precision
;; lf.sfne.{d,s} - not equal, r r, double or single precision
;;
;; Double precision is only supported on some hardware. Only register/register
;; comparisons are supported. All comparisons are signed.
(define_code_iterator fpcmpcc [ne eq lt gt ge le uneq unle unlt ungt unge
unordered])
(define_code_attr fpcmpinsn [(ne "ne") (eq "eq") (lt "lt") (gt "gt") (ge "ge")
(le "le") (uneq "ueq") (unle "ule") (unlt "ult")
(ungt "ugt") (unge "uge") (unordered "un")])
(define_insn "*sf_fp_insn"
[(set (reg:BI SR_F_REGNUM)
(fpcmpcc:BI (match_operand:F 0 "register_operand" "<fr>")
(match_operand:F 1 "register_operand" "<fr>")))]
"TARGET_HARD_FLOAT"
"lf.sf<fpcmpinsn>.<f>\t%d0, %d1"
[(set_attr "type" "fpu")])
;; ------------------------------------------------------------------------- ;; -------------------------------------------------------------------------
;; Conditional Store instructions ;; Conditional Store instructions
;; ------------------------------------------------------------------------- ;; -------------------------------------------------------------------------
...@@ -412,6 +487,23 @@ ...@@ -412,6 +487,23 @@
DONE; DONE;
}) })
;; Support FP cstores too
(define_expand "cstore<F:mode>4"
[(set (match_operand:SI 0 "register_operand" "")
(if_then_else:F
(match_operator 1 "fp_comparison_operator"
[(match_operand:F 2 "register_operand" "")
(match_operand:F 3 "register_operand" "")])
(match_dup 0)
(const_int 0)))]
"TARGET_HARD_FLOAT"
{
or1k_expand_compare (operands + 1);
PUT_MODE (operands[1], SImode);
emit_insn (gen_rtx_SET (operands[0], operands[1]));
DONE;
})
;; Being able to "copy" SR_F to a general register is helpful for ;; Being able to "copy" SR_F to a general register is helpful for
;; the atomic insns, wherein the usual usage is to test the success ;; the atomic insns, wherein the usual usage is to test the success
;; of the compare-and-swap. Representing the operation in this way, ;; of the compare-and-swap. Representing the operation in this way,
...@@ -505,6 +597,21 @@ ...@@ -505,6 +597,21 @@
or1k_expand_compare (operands); or1k_expand_compare (operands);
}) })
;; Support FP branching
(define_expand "cbranch<F:mode>4"
[(set (pc)
(if_then_else
(match_operator 0 "fp_comparison_operator"
[(match_operand:F 1 "register_operand" "")
(match_operand:F 2 "register_operand" "")])
(label_ref (match_operand 3 "" ""))
(pc)))]
"TARGET_HARD_FLOAT"
{
or1k_expand_compare (operands);
})
(define_insn "*cbranch" (define_insn "*cbranch"
[(set (pc) [(set (pc)
(if_then_else (if_then_else
......
...@@ -41,6 +41,28 @@ Target RejectNegative Mask(SOFT_MUL). ...@@ -41,6 +41,28 @@ Target RejectNegative Mask(SOFT_MUL).
Enable generation of binaries which use functions from libgcc to perform Enable generation of binaries which use functions from libgcc to perform
multiply operations. The default is -mhard-mul. multiply operations. The default is -mhard-mul.
msoft-float
Target RejectNegative InverseMask(HARD_FLOAT)
Enable generation of binaries which use functions from libgcc to perform
floating point operations. This is the default; use -mhard-float to override.
mhard-float
Target RejectNegative Mask(HARD_FLOAT)
Enable generation of hardware floating point instructions. The default is
-msoft-float.
mdouble-float
Target Mask(DOUBLE_FLOAT)
When -mhard-float is selected, enables generation of double-precision floating
point instructions. By default functions from libgcc are used to perform
double-precision floating point operations.
munordered-float
Target RejectNegative Mask(FP_UNORDERED)
When -mhard-float is selected, enables generation of unordered floating point
compare and set flag (lf.sfun*) instructions. By default functions from libgcc
are used to perform unordered floating point compare and set flag operations.
mcmov mcmov
Target RejectNegative Mask(CMOV) Target RejectNegative Mask(CMOV)
Enable generation of conditional move (l.cmov) instructions. By default the Enable generation of conditional move (l.cmov) instructions. By default the
......
...@@ -90,6 +90,11 @@ ...@@ -90,6 +90,11 @@
(define_predicate "equality_comparison_operator" (define_predicate "equality_comparison_operator"
(match_code "ne,eq")) (match_code "ne,eq"))
(define_predicate "fp_comparison_operator"
(if_then_else (match_test "TARGET_FP_UNORDERED")
(match_operand 0 "comparison_operator")
(match_operand 0 "ordered_comparison_operator")))
;; Borrowed from rs6000 ;; Borrowed from rs6000
;; Return true if the operand is in volatile memory. Note that during the ;; Return true if the operand is in volatile memory. Note that during the
;; RTL generation phase, memory_operand does not return TRUE for volatile ;; RTL generation phase, memory_operand does not return TRUE for volatile
......
...@@ -1034,6 +1034,7 @@ Objective-C and Objective-C++ Dialects}. ...@@ -1034,6 +1034,7 @@ Objective-C and Objective-C++ Dialects}.
@emph{OpenRISC Options} @emph{OpenRISC Options}
@gccoptlist{-mboard=@var{name} -mnewlib -mhard-mul -mhard-div @gol @gccoptlist{-mboard=@var{name} -mnewlib -mhard-mul -mhard-div @gol
-msoft-mul -msoft-div @gol -msoft-mul -msoft-div @gol
-msoft-float -mhard-float -mdouble-float -munordered-float @gol
-mcmov -mror -mrori -msext -msfimm -mshftimm} -mcmov -mror -mrori -msext -msfimm -mshftimm}
@emph{PDP-11 Options} @emph{PDP-11 Options}
...@@ -23666,6 +23667,26 @@ This default is hardware divide. ...@@ -23666,6 +23667,26 @@ This default is hardware divide.
Select software or hardware multiply (@code{l.mul}, @code{l.muli}) instructions. Select software or hardware multiply (@code{l.mul}, @code{l.muli}) instructions.
This default is hardware multiply. This default is hardware multiply.
@item -msoft-float
@itemx -mhard-float
@opindex msoft-float
@opindex mhard-float
Select software or hardware for floating point operations.
The default is software.
@item -mdouble-float
@opindex mdouble-float
When @option{-mhard-float} is selected, enables generation of double-precision
floating point instructions. By default functions from @file{libgcc} are used
to perform double-precision floating point operations.
@item -munordered-float
@opindex munordered-float
When @option{-mhard-float} is selected, enables generation of unordered
floating point compare and set flag (@code{lf.sfun*}) instructions. By default
functions from @file{libgcc} are used to perform unordered floating point
compare and set flag operations.
@item -mcmov @item -mcmov
@opindex mcmov @opindex mcmov
Enable generation of conditional move (@code{l.cmov}) instructions. By Enable generation of conditional move (@code{l.cmov}) instructions. By
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment