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
This commit is contained in:
Stafford Horne 2019-07-21 21:01:59 +00:00 committed by Stafford Horne
parent 1e2e81c1a3
commit 44080af98e
9 changed files with 228 additions and 4 deletions

View File

@ -1,3 +1,30 @@
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.

View File

@ -2579,6 +2579,7 @@ or1k*-*-*)
case ${or1k_multilib} in
mcmov | msext | msfimm | \
mror | mrori | \
mhard-float | mdouble-float | munordered-float | msoft-float | \
mhard-div | mhard-mul | \
msoft-div | msoft-mul )
TM_MULTILIB_CONFIG="${TM_MULTILIB_CONFIG},${or1k_multilib}"

View File

@ -24,6 +24,7 @@
; We use:
; c - sibcall registers
; d - double pair base registers (excludes r0, r30 and r31 which overflow)
; I - constant signed 16-bit
; K - constant unsigned 16-bit
; M - constant signed 16-bit shifted left 16-bits (l.movhi)
@ -32,6 +33,9 @@
(define_register_constraint "c" "SIBCALL_REGS"
"Registers which can hold a sibling call address")
(define_register_constraint "d" "DOUBLE_REGS"
"Registers which can be used for double reg pairs.")
;; Immediates
(define_constraint "I"
"A signed 16-bit immediate in the range -32768 to 32767."

View File

@ -1226,6 +1226,19 @@ or1k_print_operand (FILE *file, rtx x, int code)
output_operand_lossage ("invalid %%H value");
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':
print_reloc (file, x, 0, RKIND_HI);
break;
@ -1435,21 +1448,42 @@ void
or1k_expand_compare (rtx *operands)
{
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
supported unless we have l.sf*i instructions, force them into registers. */
if (!TARGET_SFIMM)
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. */
PUT_MODE (operands[0], BImode);
PUT_CODE (operands[0], cmp_code);
emit_insn (gen_rtx_SET (sr_f, operands[0]));
/* 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[2] = const0_rtx;
}
}
/* Expand the patterns "call", "sibcall", "call_value" and "sibcall_value".
Expands a function call where argument RETVAL is an optional RTX providing

View File

@ -189,6 +189,7 @@ enum reg_class
{
NO_REGS,
SIBCALL_REGS,
DOUBLE_REGS,
GENERAL_REGS,
FLAG_REGS,
ALL_REGS,
@ -200,6 +201,7 @@ enum reg_class
#define REG_CLASS_NAMES { \
"NO_REGS", \
"SIBCALL_REGS", \
"DOUBLE_REGS", \
"GENERAL_REGS", \
"FLAG_REGS", \
"ALL_REGS" }
@ -212,6 +214,7 @@ enum reg_class
#define REG_CLASS_CONTENTS \
{ { 0x00000000, 0x00000000 }, \
{ SIBCALL_REGS_MASK, 0 }, \
{ 0x7f7ffffe, 0x00000000 }, \
{ 0xffffffff, 0x00000003 }, \
{ 0x00000000, 0x00000004 }, \
{ 0xffffffff, 0x00000007 } \

View File

@ -60,7 +60,7 @@
(define_attr "length" "" (const_int 4))
(define_attr "type"
"alu,st,ld,control,multi"
"alu,st,ld,control,multi,fpu"
(const_string "alu"))
(define_attr "insn_support" "class1,sext,sfimm,shftimm,ror,rori" (const_string "class1"))
@ -97,6 +97,10 @@
(define_insn_reservation "control" 1
(eq_attr "type" "control")
"cpu")
(define_insn_reservation "fpu" 2
(eq_attr "type" "fpu")
"cpu")
; Define delay slots for any branch
(define_delay (eq_attr "type" "control")
@ -159,6 +163,47 @@
""
"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
;; -------------------------------------------------------------------------
@ -380,7 +425,7 @@
(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")
(gt "gts") (gtu "gtu") (ge "ges") (le "les")
(geu "geu") (leu "leu") ])
(geu "geu") (leu "leu")])
(define_insn "*sf_insn"
[(set (reg:BI SR_F_REGNUM)
@ -392,6 +437,36 @@
l.sf<insn>i\t%r0, %1"
[(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
;; -------------------------------------------------------------------------
@ -412,6 +487,23 @@
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
;; the atomic insns, wherein the usual usage is to test the success
;; of the compare-and-swap. Representing the operation in this way,
@ -505,6 +597,21 @@
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"
[(set (pc)
(if_then_else

View File

@ -41,6 +41,28 @@ Target RejectNegative Mask(SOFT_MUL).
Enable generation of binaries which use functions from libgcc to perform
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
Target RejectNegative Mask(CMOV)
Enable generation of conditional move (l.cmov) instructions. By default the

View File

@ -90,6 +90,11 @@
(define_predicate "equality_comparison_operator"
(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
;; Return true if the operand is in volatile memory. Note that during the
;; RTL generation phase, memory_operand does not return TRUE for volatile

View File

@ -1034,6 +1034,7 @@ Objective-C and Objective-C++ Dialects}.
@emph{OpenRISC Options}
@gccoptlist{-mboard=@var{name} -mnewlib -mhard-mul -mhard-div @gol
-msoft-mul -msoft-div @gol
-msoft-float -mhard-float -mdouble-float -munordered-float @gol
-mcmov -mror -mrori -msext -msfimm -mshftimm}
@emph{PDP-11 Options}
@ -23666,6 +23667,26 @@ This default is hardware divide.
Select software or hardware multiply (@code{l.mul}, @code{l.muli}) instructions.
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
@opindex mcmov
Enable generation of conditional move (@code{l.cmov}) instructions. By