diff options
author | Stafford Horne <shorne@gmail.com> | 2019-07-21 21:01:59 +0000 |
---|---|---|
committer | Stafford Horne <shorne@gcc.gnu.org> | 2019-07-21 21:01:59 +0000 |
commit | 44080af98edf7d8a59a94dd803f60cf0505fba34 (patch) | |
tree | 4ad7a9f769f0596da8bb827b2b3e4b2e11c71002 /gcc/config/or1k | |
parent | 1e2e81c1a36a51f4660d30a0278366a8a0727a9d (diff) | |
download | gcc-44080af98edf7d8a59a94dd803f60cf0505fba34.zip gcc-44080af98edf7d8a59a94dd803f60cf0505fba34.tar.gz gcc-44080af98edf7d8a59a94dd803f60cf0505fba34.tar.bz2 |
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
Diffstat (limited to 'gcc/config/or1k')
-rw-r--r-- | gcc/config/or1k/constraints.md | 4 | ||||
-rw-r--r-- | gcc/config/or1k/or1k.c | 38 | ||||
-rw-r--r-- | gcc/config/or1k/or1k.h | 3 | ||||
-rw-r--r-- | gcc/config/or1k/or1k.md | 111 | ||||
-rw-r--r-- | gcc/config/or1k/or1k.opt | 22 | ||||
-rw-r--r-- | gcc/config/or1k/predicates.md | 5 |
6 files changed, 179 insertions, 4 deletions
diff --git a/gcc/config/or1k/constraints.md b/gcc/config/or1k/constraints.md index 93da8c0..8cac7eb 100644 --- a/gcc/config/or1k/constraints.md +++ b/gcc/config/or1k/constraints.md @@ -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." diff --git a/gcc/config/or1k/or1k.c b/gcc/config/or1k/or1k.c index 54c9e80..1eea84f 100644 --- a/gcc/config/or1k/or1k.c +++ b/gcc/config/or1k/or1k.c @@ -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 diff --git a/gcc/config/or1k/or1k.h b/gcc/config/or1k/or1k.h index 6dda230..2b29e62 100644 --- a/gcc/config/or1k/or1k.h +++ b/gcc/config/or1k/or1k.h @@ -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 } \ diff --git a/gcc/config/or1k/or1k.md b/gcc/config/or1k/or1k.md index 0faa0fa..cee11d0 100644 --- a/gcc/config/or1k/or1k.md +++ b/gcc/config/or1k/or1k.md @@ -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") @@ -160,6 +164,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 diff --git a/gcc/config/or1k/or1k.opt b/gcc/config/or1k/or1k.opt index c2f64c5..15085fa 100644 --- a/gcc/config/or1k/or1k.opt +++ b/gcc/config/or1k/or1k.opt @@ -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 diff --git a/gcc/config/or1k/predicates.md b/gcc/config/or1k/predicates.md index 5e97bf4..3aa6ca3 100644 --- a/gcc/config/or1k/predicates.md +++ b/gcc/config/or1k/predicates.md @@ -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 |