summarylogtreecommitdiffstats
diff options
context:
space:
mode:
authorJiuyang liu2019-06-25 08:38:31 +0000
committerJiuyang liu2019-06-25 08:38:31 +0000
commitea4c1a3e9a89cd74a1e844f1db9d7b2ee78e9213 (patch)
tree34fc748ac62993dcdbf4c9daee922995b49b7d39
downloadaur-ea4c1a3e9a89cd74a1e844f1db9d7b2ee78e9213.tar.gz
init
-rw-r--r--.SRCINFO28
-rw-r--r--0001-SiFive-CLIC-patches-for-preemptible-and-stack-swappi.patch644
-rw-r--r--0002-Finish-CLIC-support-resolving-patch-merge-error-and-.patch360
-rw-r--r--0003-RISC-V-Add-short-forward-branch-optimization-for-sif.patch284
-rw-r--r--0004-Remove-libgloss.patch17
-rw-r--r--PKGBUILD97
6 files changed, 1430 insertions, 0 deletions
diff --git a/.SRCINFO b/.SRCINFO
new file mode 100644
index 000000000000..3c51de06d195
--- /dev/null
+++ b/.SRCINFO
@@ -0,0 +1,28 @@
+pkgbase = riscv-sifive-elf-gcc-stage1
+ pkgdesc = Cross compiler for 32-bit and 64-bit RISC-V
+ pkgver = 9.1.0
+ pkgrel = 1
+ url = https://gcc.gnu.org/
+ arch = x86_64
+ groups = risc-v
+ license = GPL
+ license = LGPL
+ license = FDL
+ makedepends = python
+ depends = riscv-sifive-elf-binutils
+ depends = libmpc
+ options = !emptydirs
+ options = !strip
+ source = https://gcc.gnu.org/pub/gcc/releases/gcc-9.1.0/gcc-9.1.0.tar.xz
+ source = 0001-SiFive-CLIC-patches-for-preemptible-and-stack-swappi.patch
+ source = 0002-Finish-CLIC-support-resolving-patch-merge-error-and-.patch
+ source = 0003-RISC-V-Add-short-forward-branch-optimization-for-sif.patch
+ source = 0004-Remove-libgloss.patch
+ md5sums = 6069ae3737cf02bf2cb44a391ef0e937
+ md5sums = SKIP
+ md5sums = SKIP
+ md5sums = SKIP
+ md5sums = SKIP
+
+pkgname = riscv-sifive-elf-gcc-stage1
+
diff --git a/0001-SiFive-CLIC-patches-for-preemptible-and-stack-swappi.patch b/0001-SiFive-CLIC-patches-for-preemptible-and-stack-swappi.patch
new file mode 100644
index 000000000000..9be1181eba25
--- /dev/null
+++ b/0001-SiFive-CLIC-patches-for-preemptible-and-stack-swappi.patch
@@ -0,0 +1,644 @@
+From d79fde036c461b5fc410e1ef4fb3bac8a66088ca Mon Sep 17 00:00:00 2001
+From: Jim Wilson <jimw@sifive.com>
+Date: Thu, 21 Feb 2019 19:50:46 -0800
+Subject: [PATCH 1/3] SiFive CLIC patches, for preemptible and stack-swapping
+ interrupt support.
+
+---
+ gcc/config/riscv/constraints.md | 5 +
+ gcc/config/riscv/predicates.md | 4 +
+ gcc/config/riscv/riscv.c | 193 ++++++++++++++++--
+ gcc/config/riscv/riscv.md | 57 ++++++
+ gcc/doc/extend.texi | 25 +++
+ gcc/doc/md.texi | 3 +
+ gcc/testsuite/gcc.target/riscv/interrupt-5.c | 15 ++
+ .../gcc.target/riscv/preemptible-1.c | 11 +
+ .../gcc.target/riscv/preemptible-2.c | 11 +
+ .../gcc.target/riscv/preemptible-3.c | 9 +
+ gcc/testsuite/gcc.target/riscv/stack-swap-1.c | 18 ++
+ 11 files changed, 330 insertions(+), 21 deletions(-)
+ create mode 100644 gcc/testsuite/gcc.target/riscv/preemptible-1.c
+ create mode 100644 gcc/testsuite/gcc.target/riscv/preemptible-2.c
+ create mode 100644 gcc/testsuite/gcc.target/riscv/preemptible-3.c
+ create mode 100644 gcc/testsuite/gcc.target/riscv/stack-swap-1.c
+
+diff --git a/gcc/config/riscv/constraints.md b/gcc/config/riscv/constraints.md
+index b4de83f8324..a736013d9f6 100644
+--- a/gcc/config/riscv/constraints.md
++++ b/gcc/config/riscv/constraints.md
+@@ -49,6 +49,11 @@
+ (and (match_code "const_int")
+ (match_test "IN_RANGE (ival, 0, 31)")))
+
++(define_constraint "C"
++ "A 12-bit unsigned immediate for CSR address."
++ (and (match_code "const_int")
++ (match_test "IN_RANGE (ival, 0, IMM_REACH-1)")))
++
+ ;; Floating-point constant +0.0, used for FCVT-based moves when FMV is
+ ;; not available in RV32.
+ (define_constraint "G"
+diff --git a/gcc/config/riscv/predicates.md b/gcc/config/riscv/predicates.md
+index 83fc4bd663d..83e698793b3 100644
+--- a/gcc/config/riscv/predicates.md
++++ b/gcc/config/riscv/predicates.md
+@@ -35,6 +35,10 @@
+ (ior (match_operand 0 "const_csr_operand")
+ (match_operand 0 "register_operand")))
+
++(define_predicate "csr_address"
++ (and (match_code "const_int")
++ (match_test "IN_RANGE (INTVAL (op), 0, IMM_REACH-1)")))
++
+ (define_predicate "sle_operand"
+ (and (match_code "const_int")
+ (match_test "SMALL_OPERAND (INTVAL (op) + 1)")))
+diff --git a/gcc/config/riscv/riscv.c b/gcc/config/riscv/riscv.c
+index e7440f39095..d90715cca23 100644
+--- a/gcc/config/riscv/riscv.c
++++ b/gcc/config/riscv/riscv.c
+@@ -139,6 +139,12 @@ struct GTY(()) machine_function {
+ bool interrupt_handler_p;
+ /* For an interrupt handler, indicates the privilege level. */
+ enum riscv_privilege_levels interrupt_mode;
++ /* True if current function is an SiFive CLIC preemptible interrupt
++ function. */
++ bool sifive_clic_preemptible_p;
++ /* True if current function is an SiFive CLIC stack swap interrupt
++ function. */
++ bool sifive_clic_stack_swap_p;
+
+ /* True if attributes on current function have been checked. */
+ bool attributes_checked_p;
+@@ -326,7 +332,7 @@ static const struct attribute_spec riscv_attribute_table[] =
+ { "naked", 0, 0, true, false, false, false,
+ riscv_handle_fndecl_attribute, NULL },
+ /* This attribute generates prologue/epilogue for interrupt handlers. */
+- { "interrupt", 0, 1, false, true, true, false,
++ { "interrupt", 0, 2, false, true, true, false,
+ riscv_handle_type_attribute, NULL },
+
+ /* The last attribute spec is set to be NULL. */
+@@ -2813,7 +2819,7 @@ riscv_handle_type_attribute (tree *node ATTRIBUTE_UNUSED, tree name, tree args,
+ /* Check for an argument. */
+ if (is_attribute_p ("interrupt", name))
+ {
+- if (args)
++ while (args != NULL)
+ {
+ tree cst = TREE_VALUE (args);
+ const char *string;
+@@ -2829,14 +2835,18 @@ riscv_handle_type_attribute (tree *node ATTRIBUTE_UNUSED, tree name, tree args,
+
+ string = TREE_STRING_POINTER (cst);
+ if (strcmp (string, "user") && strcmp (string, "supervisor")
+- && strcmp (string, "machine"))
++ && strcmp (string, "machine")
++ && strcmp (string, "SiFive-CLIC-preemptible")
++ && strcmp (string, "SiFive-CLIC-stack-swap"))
+ {
+ warning (OPT_Wattributes,
+- "argument to %qE attribute is not \"user\", \"supervisor\", or \"machine\"",
+- name);
++ "unrecognized argument to %qE attribute", name);
+ *no_add_attrs = true;
+ }
++ args = TREE_CHAIN (args);
+ }
++
++ return NULL_TREE;
+ }
+
+ return NULL_TREE;
+@@ -3147,6 +3157,7 @@ riscv_memmodel_needs_release_fence (enum memmodel model)
+ 'A' Print the atomic operation suffix for memory model OP.
+ 'F' Print a FENCE if the memory model requires a release.
+ 'z' Print x0 if OP is zero, otherwise print OP normally.
++ 'x' Print CONST_INT OP as a CSR register name or as a hex number.
+ 'i' Print i if the operand is not a register. */
+
+ static void
+@@ -3206,6 +3217,35 @@ riscv_print_operand (FILE *file, rtx op, int letter)
+ default:
+ if (letter == 'z' && op == CONST0_RTX (GET_MODE (op)))
+ fputs (reg_names[GP_REG_FIRST], file);
++ else if (letter == 'x' && GET_CODE (op) == CONST_INT)
++ {
++ unsigned HOST_WIDE_INT reg_num = UINTVAL (op);
++ const char *reg_name = NULL;
++
++ switch (reg_num)
++ {
++ case MSTATUS_REGNUM:
++ reg_name = "mstatus";
++ break;
++ case MEPC_REGNUM:
++ reg_name = "mepc";
++ break;
++ case MCAUSE_REGNUM:
++ reg_name = "mcause";
++ break;
++ case MSCRATCHI_REGNUM:
++ reg_name = "mscratchi";
++ break;
++ case MSCRATCHO_REGNUM:
++ reg_name = "mscratcho";
++ break;
++ }
++
++ if (reg_name)
++ asm_fprintf (file, "%s", reg_name);
++ else
++ asm_fprintf (file, "0x%wx", reg_num);
++ }
+ else if (letter && letter != 'z')
+ output_operand_lossage ("invalid use of '%%%c'", letter);
+ else
+@@ -3505,8 +3545,14 @@ riscv_compute_frame_info (void)
+ unsigned x_save_size = RISCV_STACK_ALIGN (num_x_saved * UNITS_PER_WORD);
+ unsigned num_save_restore = 1 + riscv_save_libcall_count (frame->mask);
+
++ /* In an SiFive CLIC preemptible interrupt function, we need extra space
++ for the initial saves of S0 and S1. */
++ if (cfun->machine->sifive_clic_preemptible_p)
++ x_save_size = RISCV_STACK_ALIGN ((num_x_saved + 2) * UNITS_PER_WORD);
++
+ /* Only use save/restore routines if they don't alter the stack size. */
+- if (RISCV_STACK_ALIGN (num_save_restore * UNITS_PER_WORD) == x_save_size)
++ else if (RISCV_STACK_ALIGN (num_save_restore * UNITS_PER_WORD)
++ == x_save_size)
+ {
+ /* Libcall saves/restores 3 registers at once, so we need to
+ allocate 12 bytes for callee-saved register. */
+@@ -3811,6 +3857,7 @@ riscv_expand_prologue (void)
+ {
+ struct riscv_frame_info *frame = &cfun->machine->frame;
+ HOST_WIDE_INT size = frame->total_size;
++ HOST_WIDE_INT interrupt_size = 0;
+ unsigned mask = frame->mask;
+ rtx insn;
+
+@@ -3834,6 +3881,12 @@ riscv_expand_prologue (void)
+ REG_NOTES (insn) = dwarf;
+ }
+
++ /* Swap in the stack pointer from the mscratch register. */
++ if (cfun->machine->sifive_clic_stack_swap_p)
++ emit_insn (gen_riscv_csr_read_write (stack_pointer_rtx,
++ GEN_INT (MSCRATCHI_REGNUM),
++ stack_pointer_rtx));
++
+ /* Save the registers. */
+ if ((frame->mask | frame->fmask) != 0)
+ {
+@@ -3844,7 +3897,34 @@ riscv_expand_prologue (void)
+ GEN_INT (-step1));
+ RTX_FRAME_RELATED_P (emit_insn (insn)) = 1;
+ size -= step1;
+- riscv_for_each_saved_reg (size, riscv_save_reg, false, false);
++
++ if (cfun->machine->sifive_clic_preemptible_p)
++ {
++ /* Save S0 and S1. */
++ riscv_save_restore_reg (word_mode, S0_REGNUM,
++ step1 - (1 * UNITS_PER_WORD),
++ riscv_save_reg);
++ riscv_save_restore_reg (word_mode, S1_REGNUM,
++ step1 - (2 * UNITS_PER_WORD),
++ riscv_save_reg);
++ /* Account for the stack size used by interrupt register saving. */
++ interrupt_size = 2 * UNITS_PER_WORD;
++
++ /* Load cause into s0. */
++ emit_insn (gen_riscv_csr_read (gen_rtx_REG (word_mode, S0_REGNUM),
++ GEN_INT (MCAUSE_REGNUM)));
++ /* Load epc into s1. */
++ emit_insn (gen_riscv_csr_read (gen_rtx_REG (word_mode, S1_REGNUM),
++ GEN_INT (MEPC_REGNUM)));
++ /* Re-enable interrupts. */
++ emit_insn (gen_riscv_csr_read_set_bits (gen_rtx_REG (word_mode,
++ GP_REG_FIRST),
++ GEN_INT (MSTATUS_REGNUM),
++ GEN_INT (MSTATUS_MIE_BIT)));
++ }
++
++ riscv_for_each_saved_reg (size + interrupt_size, riscv_save_reg,
++ false, false);
+ }
+
+ frame->mask = mask; /* Undo the above fib. */
+@@ -3852,6 +3932,10 @@ riscv_expand_prologue (void)
+ /* Set up the frame pointer, if we're using one. */
+ if (frame_pointer_needed)
+ {
++ if (cfun->machine->sifive_clic_preemptible_p)
++ error ("SiFive CLIC preemptible %qs function cannot use a frame pointer",
++ "interrupt");
++
+ insn = gen_add3_insn (hard_frame_pointer_rtx, stack_pointer_rtx,
+ GEN_INT (frame->hard_frame_pointer_offset - size));
+ RTX_FRAME_RELATED_P (emit_insn (insn)) = 1;
+@@ -3921,6 +4005,7 @@ riscv_expand_epilogue (int style)
+ unsigned mask = frame->mask;
+ HOST_WIDE_INT step1 = frame->total_size;
+ HOST_WIDE_INT step2 = 0;
++ HOST_WIDE_INT interrupt_size = 0;
+ bool use_restore_libcall = ((style == NORMAL_RETURN)
+ && riscv_use_save_libcall (frame));
+ rtx ra = gen_rtx_REG (Pmode, RETURN_ADDR_REGNUM);
+@@ -4021,10 +4106,13 @@ riscv_expand_epilogue (int style)
+
+ if (use_restore_libcall)
+ frame->mask = 0; /* Temporarily fib that we need not save GPRs. */
++ else if (cfun->machine->sifive_clic_preemptible_p)
++ interrupt_size = 2 * UNITS_PER_WORD;
+
+ /* Restore the registers. */
+- riscv_for_each_saved_reg (frame->total_size - step2, riscv_restore_reg,
+- true, style == EXCEPTION_RETURN);
++ riscv_for_each_saved_reg (frame->total_size - step2 + interrupt_size,
++ riscv_restore_reg, true,
++ style == EXCEPTION_RETURN);
+
+ if (use_restore_libcall)
+ {
+@@ -4032,6 +4120,29 @@ riscv_expand_epilogue (int style)
+ gcc_assert (step2 >= frame->save_libcall_adjustment);
+ step2 -= frame->save_libcall_adjustment;
+ }
++ else if (cfun->machine->sifive_clic_preemptible_p
++ && (frame->mask | frame->fmask) != 0)
++ {
++ /* Disable interrupts. */
++ emit_insn (gen_riscv_csr_read_clear_bits (gen_rtx_REG (word_mode,
++ GP_REG_FIRST),
++ GEN_INT (MSTATUS_REGNUM),
++ GEN_INT (MSTATUS_MIE_BIT)));
++ /* Save s1 back into mepc. */
++ emit_insn (gen_riscv_csr_write (GEN_INT (MEPC_REGNUM),
++ gen_rtx_REG (word_mode, S1_REGNUM)));
++ /* Save s0 back into mcause. */
++ emit_insn (gen_riscv_csr_write (GEN_INT (MCAUSE_REGNUM),
++ gen_rtx_REG (word_mode, S0_REGNUM)));
++
++ /* Restore S0 and S1. */
++ riscv_save_restore_reg (word_mode, S1_REGNUM,
++ step2 - (2 * UNITS_PER_WORD),
++ riscv_restore_reg);
++ riscv_save_restore_reg (word_mode, S0_REGNUM,
++ step2 - (1 * UNITS_PER_WORD),
++ riscv_restore_reg);
++ }
+
+ if (need_barrier_p)
+ riscv_emit_stack_tie ();
+@@ -4051,6 +4162,12 @@ riscv_expand_epilogue (int style)
+ REG_NOTES (insn) = dwarf;
+ }
+
++ /* Swap out the stack opinter from the mscratch register. */
++ if (cfun->machine->sifive_clic_stack_swap_p)
++ emit_insn (gen_riscv_csr_read_write (stack_pointer_rtx,
++ GEN_INT (MSCRATCHO_REGNUM),
++ stack_pointer_rtx));
++
+ if (use_restore_libcall)
+ {
+ rtx dwarf = riscv_adjust_libcall_cfi_epilogue ();
+@@ -4738,7 +4855,8 @@ riscv_function_ok_for_sibcall (tree decl ATTRIBUTE_UNUSED,
+
+ /* Get the interrupt type, return UNKNOWN_MODE if it's not
+ interrupt function. */
+-static enum riscv_privilege_levels
++/* ??? HACK ??? */
++static void
+ riscv_get_interrupt_type (tree decl)
+ {
+ gcc_assert (decl != NULL_TREE);
+@@ -4751,20 +4869,37 @@ riscv_get_interrupt_type (tree decl)
+ = TREE_VALUE (lookup_attribute ("interrupt",
+ TYPE_ATTRIBUTES (TREE_TYPE (decl))));
+
+- if (attr_args && TREE_CODE (TREE_VALUE (attr_args)) != VOID_TYPE)
++ bool interrupt_mode_set = FALSE;
++
++ /* Interrupt attributes are machine mode by default. */
++ cfun->machine->interrupt_mode = MACHINE_MODE;
++
++ while (attr_args)
+ {
+ const char *string = TREE_STRING_POINTER (TREE_VALUE (attr_args));
+
+- if (!strcmp (string, "user"))
+- return USER_MODE;
+- else if (!strcmp (string, "supervisor"))
+- return SUPERVISOR_MODE;
+- else /* Must be "machine". */
+- return MACHINE_MODE;
++ if (!strcmp (string, "SiFive-CLIC-preemptible"))
++ cfun->machine->sifive_clic_preemptible_p = TRUE;
++ else if (!strcmp (string, "SiFive-CLIC-stack-swap"))
++ cfun->machine->sifive_clic_stack_swap_p = TRUE;
++ else
++ {
++ if (interrupt_mode_set)
++ error ("%qs function cannot have two modes", "interrupt");
++ interrupt_mode_set = TRUE;
++
++ if (!strcmp (string, "user"))
++ cfun->machine->interrupt_mode = USER_MODE;
++ else if (!strcmp (string, "supervisor"))
++ cfun->machine->interrupt_mode = SUPERVISOR_MODE;
++ else if (!strcmp (string, "machine"))
++ cfun->machine->interrupt_mode = MACHINE_MODE;
++ else
++ abort ();
++ }
++
++ attr_args = TREE_CHAIN (attr_args);
+ }
+- else
+- /* Interrupt attributes are machine mode by default. */
+- return MACHINE_MODE;
+ }
+
+ /* Implement `TARGET_SET_CURRENT_FUNCTION'. */
+@@ -4798,7 +4933,17 @@ riscv_set_current_function (tree decl)
+ if (args && TREE_CODE (TREE_VALUE (args)) != VOID_TYPE)
+ error ("%qs function cannot have arguments", "interrupt");
+
+- cfun->machine->interrupt_mode = riscv_get_interrupt_type (decl);
++ riscv_get_interrupt_type (decl);
++
++ if (cfun->machine->interrupt_mode != MACHINE_MODE)
++ {
++ if (cfun->machine->sifive_clic_preemptible_p)
++ error ("SiFive CLIC preemptible %qs function must be machine mode",
++ "interrupt");
++ else if (cfun->machine->sifive_clic_stack_swap_p)
++ error ("SiFive CLIC stack-swap %qs function must be machine mode",
++ "interrupt");
++ }
+
+ gcc_assert (cfun->machine->interrupt_mode != UNKNOWN_MODE);
+ }
+@@ -4807,6 +4952,8 @@ riscv_set_current_function (tree decl)
+ cfun->machine->attributes_checked_p = 1;
+ }
+
++#if 0
++/* ??? HACK ??? */
+ /* Implement TARGET_MERGE_DECL_ATTRIBUTES. */
+ static tree
+ riscv_merge_decl_attributes (tree olddecl, tree newdecl)
+@@ -4830,6 +4977,7 @@ riscv_merge_decl_attributes (tree olddecl, tree newdecl)
+
+ return combined_attrs;
+ }
++#endif
+
+ /* Implement TARGET_CANNOT_COPY_INSN_P. */
+
+@@ -5027,8 +5175,11 @@ riscv_constant_alignment (const_tree exp, HOST_WIDE_INT align)
+ #undef TARGET_CONSTANT_ALIGNMENT
+ #define TARGET_CONSTANT_ALIGNMENT riscv_constant_alignment
+
++#if 0
++/* ??? HACK ??? */
+ #undef TARGET_MERGE_DECL_ATTRIBUTES
+ #define TARGET_MERGE_DECL_ATTRIBUTES riscv_merge_decl_attributes
++#endif
+
+ #undef TARGET_ATTRIBUTE_TABLE
+ #define TARGET_ATTRIBUTE_TABLE riscv_attribute_table
+diff --git a/gcc/config/riscv/riscv.md b/gcc/config/riscv/riscv.md
+index e3799a5bdd8..3b7d4f92c1c 100644
+--- a/gcc/config/riscv/riscv.md
++++ b/gcc/config/riscv/riscv.md
+@@ -56,6 +56,17 @@
+ UNSPECV_FRFLAGS
+ UNSPECV_FSFLAGS
+
++ ;; CSR read
++ UNSPECV_CSR_READ
++ ;; CSR read and set bits
++ UNSPECV_CSR_READ_SET_BITS
++ ;; CSR read and clear bits
++ UNSPECV_CSR_READ_CLEAR_BITS
++ ;; CSR read and write
++ UNSPECV_CSR_READ_WRITE
++ ;; CSR write
++ UNSPECV_CSR_WRITE
++
+ ;; Interrupt handler instructions.
+ UNSPECV_MRET
+ UNSPECV_SRET
+@@ -79,6 +90,14 @@
+ (NORMAL_RETURN 0)
+ (SIBCALL_RETURN 1)
+ (EXCEPTION_RETURN 2)
++
++ (MSTATUS_REGNUM 0x300)
++ (MEPC_REGNUM 0x341)
++ (MCAUSE_REGNUM 0x342)
++ (MSCRATCHI_REGNUM 0x348)
++ (MSCRATCHO_REGNUM 0x349)
++
++ (MSTATUS_MIE_BIT 8)
+ ])
+
+ (include "predicates.md")
+@@ -2400,6 +2419,44 @@
+ "TARGET_HARD_FLOAT"
+ "fsflags\t%0")
+
++(define_insn "riscv_csr_read"
++ [(set (match_operand 0 "register_operand" "=r")
++ (unspec_volatile [(match_operand 1 "csr_address" "C")]
++ UNSPECV_CSR_READ))]
++ ""
++ "csrr\t%0,%x1")
++
++(define_insn "riscv_csr_read_set_bits"
++ [(set (match_operand 0 "register_operand" "=r")
++ (unspec_volatile [(match_operand 1 "csr_address" "C")
++ (match_operand 2 "csr_operand" "rK")]
++ UNSPECV_CSR_READ_SET_BITS))]
++ ""
++ "csrrsi\t%0,%x1,%2")
++
++(define_insn "riscv_csr_read_clear_bits"
++ [(set (match_operand 0 "register_operand" "=r")
++ (unspec_volatile [(match_operand 1 "csr_address" "C")
++ (match_operand 2 "csr_operand" "rK")]
++ UNSPECV_CSR_READ_CLEAR_BITS))]
++ ""
++ "csrrci\t%0,%x1,%2")
++
++(define_insn "riscv_csr_read_write"
++ [(set (match_operand 0 "register_operand" "=r")
++ (unspec_volatile [(match_operand 1 "csr_address" "C")
++ (match_operand 2 "csr_operand" "rK")]
++ UNSPECV_CSR_READ_WRITE))]
++ ""
++ "csrrw\t%0,%x1,%2")
++
++(define_insn "riscv_csr_write"
++ [(unspec_volatile [(match_operand 0 "csr_address" "C")
++ (match_operand 1 "register_operand" "r")]
++ UNSPECV_CSR_WRITE)]
++ ""
++ "csrw\t%x0,%1")
++
+ (define_insn "riscv_mret"
+ [(return)
+ (unspec_volatile [(const_int 0)] UNSPECV_MRET)]
+diff --git a/gcc/doc/extend.texi b/gcc/doc/extend.texi
+index 91679e8b9ba..883db8894db 100644
+--- a/gcc/doc/extend.texi
++++ b/gcc/doc/extend.texi
+@@ -5592,6 +5592,31 @@ void f (void) __attribute__ ((interrupt ("user")));
+ Permissible values for this parameter are @code{user}, @code{supervisor},
+ and @code{machine}. If there is no parameter, then it defaults to
+ @code{machine}.
++
++You can specify an SiFive CLIC preemptible interrupt handler by adding an
++optional parameter to the interrupt attribute like this:
++
++@smallexample
++void f (void) __attribute__ ((interrupt ("SiFive-CLIC-preemptible")));
++@end smallexample
++
++In this type of interrupt handler, in the prologue, the mepc and
++mcause registers are saved, and interrupts are enabled. In the epilogue,
++interrupts are disabled, and the mepc and mcause registers are restored.
++This type of interrupt handler must be @code{machine} mode, and must
++not use the frame pointer.
++
++You can specify an SiFive CLIC stack swapping interrupt handler by adding an
++optional parameter to the interrupt attribute like this:
++
++@smallexample
++void f (void) __attribute__ ((interrupt ("SiFive-CLIC-stack-swap")));
++@end smallexample
++
++In this type of interrupt handler, the stack pointer will be swapped with
++the @code{mscratch} register in the prologue before the first use of the stack
++pointer, and in the epilogue after the last use of the stack pointer. This
++type of interrupt handler must be @code{machine} mode.
+ @end table
+
+ @node RL78 Function Attributes
+diff --git a/gcc/doc/md.texi b/gcc/doc/md.texi
+index 30612a6aecb..3783bb25314 100644
+--- a/gcc/doc/md.texi
++++ b/gcc/doc/md.texi
+@@ -3577,6 +3577,9 @@ Integer zero.
+ @item K
+ A 5-bit unsigned immediate for CSR access instructions.
+
++@item C
++A 12-bit unsigned immediate for CSR register address.
++
+ @item A
+ An address that is held in a general-purpose register.
+
+diff --git a/gcc/testsuite/gcc.target/riscv/interrupt-5.c b/gcc/testsuite/gcc.target/riscv/interrupt-5.c
+index 324954eb1dd..03d8173e5b3 100644
+--- a/gcc/testsuite/gcc.target/riscv/interrupt-5.c
++++ b/gcc/testsuite/gcc.target/riscv/interrupt-5.c
+@@ -19,3 +19,18 @@ void __attribute__ ((interrupt ("hypervisor")))
+ sub3 (void)
+ { /* { dg-warning "argument to" } */
+ }
++
++void __attribute__ ((interrupt ("user", "machine")))
++sub4 (void)
++{ /* { dg-error "cannot have two modes" } */
++}
++
++void __attribute__ ((interrupt ("user", "SiFive-CLIC-preemptible")))
++sub5 (void)
++{ /* { dg-error "must be machine mode" } */
++}
++
++void __attribute__ ((interrupt ("user", "SiFive-CLIC-stack-swap")))
++sub6 (void)
++{ /* { dg-error "must be machine mode" } */
++}
+diff --git a/gcc/testsuite/gcc.target/riscv/preemptible-1.c b/gcc/testsuite/gcc.target/riscv/preemptible-1.c
+new file mode 100644
+index 00000000000..578667f46cd
+--- /dev/null
++++ b/gcc/testsuite/gcc.target/riscv/preemptible-1.c
+@@ -0,0 +1,11 @@
++/* Verify that csr instructions emitted. */
++/* { dg-do compile } */
++/* { dg-options "-O" } */
++extern int interrupt_count;
++
++void __attribute__ ((interrupt ("SiFive-CLIC-preemptible")))
++sub (void)
++{
++ interrupt_count++;
++}
++/* { dg-final { scan-assembler-times "csr" 6 } } */
+diff --git a/gcc/testsuite/gcc.target/riscv/preemptible-2.c b/gcc/testsuite/gcc.target/riscv/preemptible-2.c
+new file mode 100644
+index 00000000000..27cd31de188
+--- /dev/null
++++ b/gcc/testsuite/gcc.target/riscv/preemptible-2.c
+@@ -0,0 +1,11 @@
++/* Verify that all temp regs saved for call. */
++/* { dg-do compile } */
++/* { dg-options "-O" } */
++extern int vector_10 (void);
++
++void __attribute__ ((interrupt ("SiFive-CLIC-preemptible")))
++sub (void)
++{
++ vector_10 ();
++}
++/* { dg-final { scan-assembler-times "s\[wd\]\t\[at\]\[0-7\]" 15 } } */
+diff --git a/gcc/testsuite/gcc.target/riscv/preemptible-3.c b/gcc/testsuite/gcc.target/riscv/preemptible-3.c
+new file mode 100644
+index 00000000000..c01d9ded7d5
+--- /dev/null
++++ b/gcc/testsuite/gcc.target/riscv/preemptible-3.c
+@@ -0,0 +1,9 @@
++/* Verify that csr instructions are not emitted. */
++/* { dg-do compile } */
++/* { dg-options "-O" } */
++
++void __attribute__ ((interrupt ("SiFive-CLIC-preemptible")))
++sub (void)
++{
++}
++/* { dg-final { scan-assembler-not "csr" } } */
+diff --git a/gcc/testsuite/gcc.target/riscv/stack-swap-1.c b/gcc/testsuite/gcc.target/riscv/stack-swap-1.c
+new file mode 100644
+index 00000000000..2e26432cd89
+--- /dev/null
++++ b/gcc/testsuite/gcc.target/riscv/stack-swap-1.c
+@@ -0,0 +1,18 @@
++/* Verify that stack swapping instructions are emitted. */
++/* { dg-do compile } */
++/* { dg-options "-O" } */
++void __attribute__ ((interrupt ("SiFive-CLIC-stack-swap")))
++foo2 (void)
++{
++ extern volatile int INTERRUPT_FLAG;
++ INTERRUPT_FLAG = 0;
++
++ extern volatile int COUNTER;
++#ifdef __riscv_atomic
++ __atomic_fetch_add (&COUNTER, 1, __ATOMIC_RELAXED);
++#else
++ COUNTER++;
++#endif
++}
++/* { dg-final { scan-assembler "mscratchi" } } */
++/* { dg-final { scan-assembler "mscratcho" } } */
+--
+2.21.0
+
diff --git a/0002-Finish-CLIC-support-resolving-patch-merge-error-and-.patch b/0002-Finish-CLIC-support-resolving-patch-merge-error-and-.patch
new file mode 100644
index 000000000000..a0e97bb56d49
--- /dev/null
+++ b/0002-Finish-CLIC-support-resolving-patch-merge-error-and-.patch
@@ -0,0 +1,360 @@
+From 96fded3b45d93f306e86d9529b8ae3ff7f012088 Mon Sep 17 00:00:00 2001
+From: Jim Wilson <jimw@sifive.com>
+Date: Thu, 28 Feb 2019 12:09:52 -0800
+Subject: [PATCH 2/3] Finish CLIC support, resolving patch merge error and
+ adding missing patch.
+
+---
+ gcc/config/riscv/riscv.c | 124 ++++++++++--------
+ gcc/config/riscv/riscv.md | 3 +-
+ .../riscv/interrupt-conflict-mode.c | 2 +-
+ gcc/testsuite/gcc.target/riscv/stack-swap-1.c | 3 +-
+ 4 files changed, 69 insertions(+), 63 deletions(-)
+
+diff --git a/gcc/config/riscv/riscv.c b/gcc/config/riscv/riscv.c
+index d90715cca23..0dcfec1974d 100644
+--- a/gcc/config/riscv/riscv.c
++++ b/gcc/config/riscv/riscv.c
+@@ -96,7 +96,7 @@ enum riscv_address_type {
+ };
+
+ /* Information about a function's frame layout. */
+-struct GTY(()) riscv_frame_info {
++struct GTY(()) riscv_frame_info {
+ /* The size of the frame in bytes. */
+ HOST_WIDE_INT total_size;
+
+@@ -127,7 +127,18 @@ enum riscv_privilege_levels {
+ UNKNOWN_MODE, USER_MODE, SUPERVISOR_MODE, MACHINE_MODE
+ };
+
+-struct GTY(()) machine_function {
++struct GTY(()) riscv_interrupt_flags {
++ /* For an interrupt handler, indicates the privilege level. */
++ enum riscv_privilege_levels interrupt_mode : 2;
++ /* True if current function is an SiFive CLIC preemptible interrupt
++ function. */
++ bool sifive_clic_preemptible_p : 1;
++ /* True if current function is an SiFive CLIC stack swap interrupt
++ function. */
++ bool sifive_clic_stack_swap_p : 1;
++};
++
++struct GTY(()) machine_function {
+ /* The number of extra stack bytes taken up by register varargs.
+ This area is allocated by the callee at the very top of the frame. */
+ int varargs_size;
+@@ -137,14 +148,8 @@ struct GTY(()) machine_function {
+
+ /* True if current function is an interrupt function. */
+ bool interrupt_handler_p;
+- /* For an interrupt handler, indicates the privilege level. */
+- enum riscv_privilege_levels interrupt_mode;
+- /* True if current function is an SiFive CLIC preemptible interrupt
+- function. */
+- bool sifive_clic_preemptible_p;
+- /* True if current function is an SiFive CLIC stack swap interrupt
+- function. */
+- bool sifive_clic_stack_swap_p;
++ /* For an interrupt handler, hold various argument flag bits. */
++ struct riscv_interrupt_flags interrupt_flags;
+
+ /* True if attributes on current function have been checked. */
+ bool attributes_checked_p;
+@@ -3233,11 +3238,8 @@ riscv_print_operand (FILE *file, rtx op, int letter)
+ case MCAUSE_REGNUM:
+ reg_name = "mcause";
+ break;
+- case MSCRATCHI_REGNUM:
+- reg_name = "mscratchi";
+- break;
+- case MSCRATCHO_REGNUM:
+- reg_name = "mscratcho";
++ case MSCRATCHCSW_REGNUM:
++ reg_name = "mscratchcsw";
+ break;
+ }
+
+@@ -3547,7 +3549,7 @@ riscv_compute_frame_info (void)
+
+ /* In an SiFive CLIC preemptible interrupt function, we need extra space
+ for the initial saves of S0 and S1. */
+- if (cfun->machine->sifive_clic_preemptible_p)
++ if (cfun->machine->interrupt_flags.sifive_clic_preemptible_p)
+ x_save_size = RISCV_STACK_ALIGN ((num_x_saved + 2) * UNITS_PER_WORD);
+
+ /* Only use save/restore routines if they don't alter the stack size. */
+@@ -3882,9 +3884,9 @@ riscv_expand_prologue (void)
+ }
+
+ /* Swap in the stack pointer from the mscratch register. */
+- if (cfun->machine->sifive_clic_stack_swap_p)
++ if (cfun->machine->interrupt_flags.sifive_clic_stack_swap_p)
+ emit_insn (gen_riscv_csr_read_write (stack_pointer_rtx,
+- GEN_INT (MSCRATCHI_REGNUM),
++ GEN_INT (MSCRATCHCSW_REGNUM),
+ stack_pointer_rtx));
+
+ /* Save the registers. */
+@@ -3898,7 +3900,7 @@ riscv_expand_prologue (void)
+ RTX_FRAME_RELATED_P (emit_insn (insn)) = 1;
+ size -= step1;
+
+- if (cfun->machine->sifive_clic_preemptible_p)
++ if (cfun->machine->interrupt_flags.sifive_clic_preemptible_p)
+ {
+ /* Save S0 and S1. */
+ riscv_save_restore_reg (word_mode, S0_REGNUM,
+@@ -3932,7 +3934,7 @@ riscv_expand_prologue (void)
+ /* Set up the frame pointer, if we're using one. */
+ if (frame_pointer_needed)
+ {
+- if (cfun->machine->sifive_clic_preemptible_p)
++ if (cfun->machine->interrupt_flags.sifive_clic_preemptible_p)
+ error ("SiFive CLIC preemptible %qs function cannot use a frame pointer",
+ "interrupt");
+
+@@ -4106,7 +4108,7 @@ riscv_expand_epilogue (int style)
+
+ if (use_restore_libcall)
+ frame->mask = 0; /* Temporarily fib that we need not save GPRs. */
+- else if (cfun->machine->sifive_clic_preemptible_p)
++ else if (cfun->machine->interrupt_flags.sifive_clic_preemptible_p)
+ interrupt_size = 2 * UNITS_PER_WORD;
+
+ /* Restore the registers. */
+@@ -4120,7 +4122,7 @@ riscv_expand_epilogue (int style)
+ gcc_assert (step2 >= frame->save_libcall_adjustment);
+ step2 -= frame->save_libcall_adjustment;
+ }
+- else if (cfun->machine->sifive_clic_preemptible_p
++ else if (cfun->machine->interrupt_flags.sifive_clic_preemptible_p
+ && (frame->mask | frame->fmask) != 0)
+ {
+ /* Disable interrupts. */
+@@ -4135,7 +4137,7 @@ riscv_expand_epilogue (int style)
+ emit_insn (gen_riscv_csr_write (GEN_INT (MCAUSE_REGNUM),
+ gen_rtx_REG (word_mode, S0_REGNUM)));
+
+- /* Restore S0 and S1. */
++ /* Restore S0 and S1. */
+ riscv_save_restore_reg (word_mode, S1_REGNUM,
+ step2 - (2 * UNITS_PER_WORD),
+ riscv_restore_reg);
+@@ -4162,10 +4164,10 @@ riscv_expand_epilogue (int style)
+ REG_NOTES (insn) = dwarf;
+ }
+
+- /* Swap out the stack opinter from the mscratch register. */
+- if (cfun->machine->sifive_clic_stack_swap_p)
++ /* Swap out the stack pointer from the mscratch register. */
++ if (cfun->machine->interrupt_flags.sifive_clic_stack_swap_p)
+ emit_insn (gen_riscv_csr_read_write (stack_pointer_rtx,
+- GEN_INT (MSCRATCHO_REGNUM),
++ GEN_INT (MSCRATCHCSW_REGNUM),
+ stack_pointer_rtx));
+
+ if (use_restore_libcall)
+@@ -4187,7 +4189,8 @@ riscv_expand_epilogue (int style)
+ /* Return from interrupt. */
+ if (cfun->machine->interrupt_handler_p)
+ {
+- enum riscv_privilege_levels mode = cfun->machine->interrupt_mode;
++ enum riscv_privilege_levels mode
++ = cfun->machine->interrupt_flags.interrupt_mode;
+
+ gcc_assert (mode != UNKNOWN_MODE);
+
+@@ -4853,35 +4856,41 @@ riscv_function_ok_for_sibcall (tree decl ATTRIBUTE_UNUSED,
+ return true;
+ }
+
+-/* Get the interrupt type, return UNKNOWN_MODE if it's not
++/* Get the interrupt type, return UNKNOWN_MODE if it's not an
+ interrupt function. */
+-/* ??? HACK ??? */
+-static void
++static struct riscv_interrupt_flags
+ riscv_get_interrupt_type (tree decl)
+ {
++ struct riscv_interrupt_flags interrupt_flags;
++ bool interrupt_mode_set;
++
+ gcc_assert (decl != NULL_TREE);
+
+ if ((TREE_CODE(decl) != FUNCTION_DECL)
+ || (!riscv_interrupt_type_p (TREE_TYPE (decl))))
+- return UNKNOWN_MODE;
++ {
++ interrupt_flags.interrupt_mode = UNKNOWN_MODE;
++ return interrupt_flags;
++ }
+
+ tree attr_args
+ = TREE_VALUE (lookup_attribute ("interrupt",
+ TYPE_ATTRIBUTES (TREE_TYPE (decl))));
+
+- bool interrupt_mode_set = FALSE;
+-
+ /* Interrupt attributes are machine mode by default. */
+- cfun->machine->interrupt_mode = MACHINE_MODE;
++ interrupt_flags.interrupt_mode = MACHINE_MODE;
++ interrupt_flags.sifive_clic_preemptible_p = FALSE;
++ interrupt_flags.sifive_clic_stack_swap_p = FALSE;
++ interrupt_mode_set = FALSE;
+
+ while (attr_args)
+ {
+ const char *string = TREE_STRING_POINTER (TREE_VALUE (attr_args));
+
+ if (!strcmp (string, "SiFive-CLIC-preemptible"))
+- cfun->machine->sifive_clic_preemptible_p = TRUE;
++ interrupt_flags.sifive_clic_preemptible_p = TRUE;
+ else if (!strcmp (string, "SiFive-CLIC-stack-swap"))
+- cfun->machine->sifive_clic_stack_swap_p = TRUE;
++ interrupt_flags.sifive_clic_stack_swap_p = TRUE;
+ else
+ {
+ if (interrupt_mode_set)
+@@ -4889,17 +4898,20 @@ riscv_get_interrupt_type (tree decl)
+ interrupt_mode_set = TRUE;
+
+ if (!strcmp (string, "user"))
+- cfun->machine->interrupt_mode = USER_MODE;
++ interrupt_flags.interrupt_mode = USER_MODE;
+ else if (!strcmp (string, "supervisor"))
+- cfun->machine->interrupt_mode = SUPERVISOR_MODE;
++ interrupt_flags.interrupt_mode = SUPERVISOR_MODE;
+ else if (!strcmp (string, "machine"))
+- cfun->machine->interrupt_mode = MACHINE_MODE;
++ interrupt_flags.interrupt_mode = MACHINE_MODE;
+ else
++ /* Unreachable. Checked in riscv_handle_type_attribute. */
+ abort ();
+ }
+
+ attr_args = TREE_CHAIN (attr_args);
+ }
++
++ return interrupt_flags;
+ }
+
+ /* Implement `TARGET_SET_CURRENT_FUNCTION'. */
+@@ -4933,43 +4945,43 @@ riscv_set_current_function (tree decl)
+ if (args && TREE_CODE (TREE_VALUE (args)) != VOID_TYPE)
+ error ("%qs function cannot have arguments", "interrupt");
+
+- riscv_get_interrupt_type (decl);
++ cfun->machine->interrupt_flags = riscv_get_interrupt_type (decl);
+
+- if (cfun->machine->interrupt_mode != MACHINE_MODE)
++ if (cfun->machine->interrupt_flags.interrupt_mode != MACHINE_MODE)
+ {
+- if (cfun->machine->sifive_clic_preemptible_p)
++ if (cfun->machine->interrupt_flags.sifive_clic_preemptible_p)
+ error ("SiFive CLIC preemptible %qs function must be machine mode",
+ "interrupt");
+- else if (cfun->machine->sifive_clic_stack_swap_p)
++ else if (cfun->machine->interrupt_flags.sifive_clic_stack_swap_p)
+ error ("SiFive CLIC stack-swap %qs function must be machine mode",
+ "interrupt");
+ }
+
+- gcc_assert (cfun->machine->interrupt_mode != UNKNOWN_MODE);
++ gcc_assert (cfun->machine->interrupt_flags.interrupt_mode
++ != UNKNOWN_MODE);
+ }
+
+ /* Don't print the above diagnostics more than once. */
+ cfun->machine->attributes_checked_p = 1;
+ }
+
+-#if 0
+-/* ??? HACK ??? */
+-/* Implement TARGET_MERGE_DECL_ATTRIBUTES. */
++/* Implement TARGET_MERGE_DECL_ATTRIBUTES. */
+ static tree
+ riscv_merge_decl_attributes (tree olddecl, tree newdecl)
+ {
+ tree combined_attrs;
+
+- enum riscv_privilege_levels old_interrupt_type
++ struct riscv_interrupt_flags old_interrupt_type
+ = riscv_get_interrupt_type (olddecl);
+- enum riscv_privilege_levels new_interrupt_type
++ struct riscv_interrupt_flags new_interrupt_type
+ = riscv_get_interrupt_type (newdecl);
+
+- /* Check old and new has same interrupt type. */
+- if ((old_interrupt_type != UNKNOWN_MODE)
+- && (new_interrupt_type != UNKNOWN_MODE)
+- && (old_interrupt_type != new_interrupt_type))
+- error ("%qs function cannot have different interrupt type", "interrupt");
++ /* Check old and new have same interrupt type. */
++ if ((old_interrupt_type.interrupt_mode != UNKNOWN_MODE)
++ && (new_interrupt_type.interrupt_mode != UNKNOWN_MODE)
++ && (old_interrupt_type.interrupt_mode
++ != new_interrupt_type.interrupt_mode))
++ error ("%qs function cannot have different interrupt type.", "interrupt");
+
+ /* Create combined attributes. */
+ combined_attrs = merge_attributes (DECL_ATTRIBUTES (olddecl),
+@@ -4977,7 +4989,6 @@ riscv_merge_decl_attributes (tree olddecl, tree newdecl)
+
+ return combined_attrs;
+ }
+-#endif
+
+ /* Implement TARGET_CANNOT_COPY_INSN_P. */
+
+@@ -5175,11 +5186,8 @@ riscv_constant_alignment (const_tree exp, HOST_WIDE_INT align)
+ #undef TARGET_CONSTANT_ALIGNMENT
+ #define TARGET_CONSTANT_ALIGNMENT riscv_constant_alignment
+
+-#if 0
+-/* ??? HACK ??? */
+ #undef TARGET_MERGE_DECL_ATTRIBUTES
+ #define TARGET_MERGE_DECL_ATTRIBUTES riscv_merge_decl_attributes
+-#endif
+
+ #undef TARGET_ATTRIBUTE_TABLE
+ #define TARGET_ATTRIBUTE_TABLE riscv_attribute_table
+diff --git a/gcc/config/riscv/riscv.md b/gcc/config/riscv/riscv.md
+index 3b7d4f92c1c..a27e921d5a9 100644
+--- a/gcc/config/riscv/riscv.md
++++ b/gcc/config/riscv/riscv.md
+@@ -94,8 +94,7 @@
+ (MSTATUS_REGNUM 0x300)
+ (MEPC_REGNUM 0x341)
+ (MCAUSE_REGNUM 0x342)
+- (MSCRATCHI_REGNUM 0x348)
+- (MSCRATCHO_REGNUM 0x349)
++ (MSCRATCHCSW_REGNUM 0x348)
+
+ (MSTATUS_MIE_BIT 8)
+ ])
+diff --git a/gcc/testsuite/gcc.target/riscv/interrupt-conflict-mode.c b/gcc/testsuite/gcc.target/riscv/interrupt-conflict-mode.c
+index e9f145265c0..793397feaf4 100644
+--- a/gcc/testsuite/gcc.target/riscv/interrupt-conflict-mode.c
++++ b/gcc/testsuite/gcc.target/riscv/interrupt-conflict-mode.c
+@@ -6,5 +6,5 @@ foo(void);
+
+ void __attribute__ ((interrupt ("machine")))
+ foo (void)
+-{ /* { dg-error "function cannot have different interrupt type" } */
++{ /* { dg-error "function cannot have different interrupt type." } */
+ }
+diff --git a/gcc/testsuite/gcc.target/riscv/stack-swap-1.c b/gcc/testsuite/gcc.target/riscv/stack-swap-1.c
+index 2e26432cd89..bbc89b58e18 100644
+--- a/gcc/testsuite/gcc.target/riscv/stack-swap-1.c
++++ b/gcc/testsuite/gcc.target/riscv/stack-swap-1.c
+@@ -14,5 +14,4 @@ foo2 (void)
+ COUNTER++;
+ #endif
+ }
+-/* { dg-final { scan-assembler "mscratchi" } } */
+-/* { dg-final { scan-assembler "mscratcho" } } */
++/* { dg-final { scan-assembler-times "mscratchcsw" 2 } } */
+--
+2.21.0
+
diff --git a/0003-RISC-V-Add-short-forward-branch-optimization-for-sif.patch b/0003-RISC-V-Add-short-forward-branch-optimization-for-sif.patch
new file mode 100644
index 000000000000..79b85dd7503b
--- /dev/null
+++ b/0003-RISC-V-Add-short-forward-branch-optimization-for-sif.patch
@@ -0,0 +1,284 @@
+From 17fc91857ce3d7ec5f4755c616aa4598c6daa783 Mon Sep 17 00:00:00 2001
+From: Jim Wilson <jimw@sifive.com>
+Date: Thu, 4 Apr 2019 08:34:32 -0700
+Subject: [PATCH 3/3] RISC-V: Add short-forward-branch optimization for
+ sifive-7 core.
+
+ gcc/
+ * config/riscv/constraints.md (L): New.
+ * config/riscv/predicates.md (lui_operand): New.
+ (sfb_alu_operand): New.
+ * config/riscv/riscv-protos.h (riscv_expand_conditional_move): Declare.
+ * config/riscv/riscv.c (riscv_expand_conditional_move): New.
+ (riscv_print_operand): Add support for 'w' and 'y'. Update comment.
+ * config/riscv/riscv.h (TARGET_SFB_ALU): New.
+ * config/riscv/riscv.md (type): Add sfb_alu.
+ (branch_order<mode>, branch_zero<mode>): Delete.
+ (branch<mode>): New, combined from the two deleted patterns.
+ (mov<mode>cc, mov<GPR:mode><X:mode>cc): New, using TARGET_SFB_ALU.
+ * config/riscv/sifive-7.md: Update bypasses for sfb alu support.
+ (sifive_7_sfb_alu): New.
+---
+ gcc/config/riscv/constraints.md | 5 ++++
+ gcc/config/riscv/predicates.md | 8 +++++
+ gcc/config/riscv/riscv-protos.h | 1 +
+ gcc/config/riscv/riscv.c | 28 +++++++++++++++--
+ gcc/config/riscv/riscv.h | 11 +++++++
+ gcc/config/riscv/riscv.md | 53 +++++++++++++++++++++++----------
+ gcc/config/riscv/sifive-7.md | 12 ++++++--
+ 7 files changed, 97 insertions(+), 21 deletions(-)
+
+diff --git a/gcc/config/riscv/constraints.md b/gcc/config/riscv/constraints.md
+index a736013d9f6..96d09e6a313 100644
+--- a/gcc/config/riscv/constraints.md
++++ b/gcc/config/riscv/constraints.md
+@@ -54,6 +54,11 @@
+ (and (match_code "const_int")
+ (match_test "IN_RANGE (ival, 0, IMM_REACH-1)")))
+
++(define_constraint "L"
++ "A U-type 20-bit signed immediate."
++ (and (match_code "const_int")
++ (match_test "LUI_OPERAND (ival)")))
++
+ ;; Floating-point constant +0.0, used for FCVT-based moves when FMV is
+ ;; not available in RV32.
+ (define_constraint "G"
+diff --git a/gcc/config/riscv/predicates.md b/gcc/config/riscv/predicates.md
+index 83e698793b3..655713bdcbf 100644
+--- a/gcc/config/riscv/predicates.md
++++ b/gcc/config/riscv/predicates.md
+@@ -27,6 +27,14 @@
+ (ior (match_operand 0 "const_arith_operand")
+ (match_operand 0 "register_operand")))
+
++(define_predicate "lui_operand"
++ (and (match_code "const_int")
++ (match_test "LUI_OPERAND (INTVAL (op))")))
++
++(define_predicate "sfb_alu_operand"
++ (ior (match_operand 0 "arith_operand")
++ (match_operand 0 "lui_operand")))
++
+ (define_predicate "const_csr_operand"
+ (and (match_code "const_int")
+ (match_test "IN_RANGE (INTVAL (op), 0, 31)")))
+diff --git a/gcc/config/riscv/riscv-protos.h b/gcc/config/riscv/riscv-protos.h
+index 8b510f87df8..612188f76fb 100644
+--- a/gcc/config/riscv/riscv-protos.h
++++ b/gcc/config/riscv/riscv-protos.h
+@@ -59,6 +59,7 @@ extern const char *riscv_output_return ();
+ extern void riscv_expand_int_scc (rtx, enum rtx_code, rtx, rtx);
+ extern void riscv_expand_float_scc (rtx, enum rtx_code, rtx, rtx);
+ extern void riscv_expand_conditional_branch (rtx, enum rtx_code, rtx, rtx);
++extern void riscv_expand_conditional_move (rtx, rtx, rtx, rtx_code, rtx, rtx);
+ #endif
+ extern rtx riscv_legitimize_call_address (rtx);
+ extern void riscv_set_return_address (rtx, rtx);
+diff --git a/gcc/config/riscv/riscv.c b/gcc/config/riscv/riscv.c
+index 0dcfec1974d..105b42c7264 100644
+--- a/gcc/config/riscv/riscv.c
++++ b/gcc/config/riscv/riscv.c
+@@ -2307,6 +2307,18 @@ riscv_expand_conditional_branch (rtx label, rtx_code code, rtx op0, rtx op1)
+ emit_jump_insn (gen_condjump (condition, label));
+ }
+
++/* If (CODE OP0 OP1) holds, move CONS to DEST; else move ALT to DEST. */
++
++void
++riscv_expand_conditional_move (rtx dest, rtx cons, rtx alt, rtx_code code,
++ rtx op0, rtx op1)
++{
++ riscv_emit_int_compare (&code, &op0, &op1);
++ rtx cond = gen_rtx_fmt_ee (code, GET_MODE (op0), op0, op1);
++ emit_insn (gen_rtx_SET (dest, gen_rtx_IF_THEN_ELSE (GET_MODE (dest), cond,
++ cons, alt)));
++}
++
+ /* Implement TARGET_FUNCTION_ARG_BOUNDARY. Every parameter gets at
+ least PARM_BOUNDARY bits of alignment, but will be given anything up
+ to PREFERRED_STACK_BOUNDARY bits if the type requires it. */
+@@ -3161,6 +3173,8 @@ riscv_memmodel_needs_release_fence (enum memmodel model)
+ 'C' Print the integer branch condition for comparison OP.
+ 'A' Print the atomic operation suffix for memory model OP.
+ 'F' Print a FENCE if the memory model requires a release.
++ 'w' Print nothing if OP is zero, otherwise print OP followed by a comma.
++ 'y' Print 'z' if OP is zero, otherwise print nothing.
+ 'z' Print x0 if OP is zero, otherwise print OP normally.
+ 'x' Print CONST_INT OP as a CSR register name or as a hex number.
+ 'i' Print i if the operand is not a register. */
+@@ -3207,9 +3221,13 @@ riscv_print_operand (FILE *file, rtx op, int letter)
+ switch (code)
+ {
+ case REG:
+- if (letter && letter != 'z')
++ if (letter && letter == 'y')
++ break;
++ else if (letter && letter != 'w' && letter != 'z')
+ output_operand_lossage ("invalid use of '%%%c'", letter);
+ fprintf (file, "%s", reg_names[REGNO (op)]);
++ if (letter == 'w')
++ fputs(",", file);
+ break;
+
+ case MEM:
+@@ -3220,7 +3238,11 @@ riscv_print_operand (FILE *file, rtx op, int letter)
+ break;
+
+ default:
+- if (letter == 'z' && op == CONST0_RTX (GET_MODE (op)))
++ if (letter == 'w')
++ break;
++ else if (letter == 'y' && op == CONST0_RTX (GET_MODE (op)))
++ fputs ("z", file);
++ else if (letter == 'z' && op == CONST0_RTX (GET_MODE (op)))
+ fputs (reg_names[GP_REG_FIRST], file);
+ else if (letter == 'x' && GET_CODE (op) == CONST_INT)
+ {
+@@ -3248,7 +3270,7 @@ riscv_print_operand (FILE *file, rtx op, int letter)
+ else
+ asm_fprintf (file, "0x%wx", reg_num);
+ }
+- else if (letter && letter != 'z')
++ else if (letter && letter != 'y' && letter != 'z')
+ output_operand_lossage ("invalid use of '%%%c'", letter);
+ else
+ output_addr_const (file, riscv_strip_unspec_address (op));
+diff --git a/gcc/config/riscv/riscv.h b/gcc/config/riscv/riscv.h
+index c93743f9549..4edd2a60194 100644
+--- a/gcc/config/riscv/riscv.h
++++ b/gcc/config/riscv/riscv.h
+@@ -662,6 +662,17 @@ typedef struct {
+ #define BRANCH_COST(speed_p, predictable_p) \
+ ((!(speed_p) || (predictable_p)) ? 2 : riscv_branch_cost)
+
++/* True if the target optimizes short forward branches around integer
++ arithmetic instructions into predicated operations, e.g., for
++ conditional-move operations. The macro assumes that all branch
++ instructions (BEQ, BNE, BLT, BLTU, BGE, BGEU, C.BEQZ, and C.BNEZ)
++ support this feature. The macro further assumes that any integer
++ arithmetic and logical operation (ADD[I], SUB, SLL[I], SRL[I], SRA[I],
++ SLT[I][U], AND[I], XOR[I], OR[I], LUI, AUIPC, and their compressed
++ counterparts, including C.MV and C.LI) can be in the branch shadow. */
++
++#define TARGET_SFB_ALU (riscv_microarchitecture == sifive_7)
++
+ #define LOGICAL_OP_NON_SHORT_CIRCUIT 0
+
+ /* Control the assembler format that we output. */
+diff --git a/gcc/config/riscv/riscv.md b/gcc/config/riscv/riscv.md
+index a27e921d5a9..22ede6d8478 100644
+--- a/gcc/config/riscv/riscv.md
++++ b/gcc/config/riscv/riscv.md
+@@ -174,7 +174,7 @@
+ (define_attr "type"
+ "unknown,branch,jump,call,load,fpload,store,fpstore,
+ mtc,mfc,const,arith,logical,shift,slt,imul,idiv,move,fmove,fadd,fmul,
+- fmadd,fdiv,fcmp,fcvt,fsqrt,multi,auipc,nop,ghost"
++ fmadd,fdiv,fcmp,fcvt,fsqrt,multi,auipc,sfb_alu,nop,ghost"
+ (cond [(eq_attr "got" "load") (const_string "load")
+
+ ;; If a doubleword move uses these expensive instructions,
+@@ -1821,31 +1821,52 @@
+
+ ;; Conditional branches
+
+-(define_insn "*branch_order<mode>"
++(define_insn "*branch<mode>"
+ [(set (pc)
+ (if_then_else
+ (match_operator 1 "order_operator"
+ [(match_operand:X 2 "register_operand" "r")
+- (match_operand:X 3 "register_operand" "r")])
++ (match_operand:X 3 "reg_or_0_operand" "rJ")])
+ (label_ref (match_operand 0 "" ""))
+ (pc)))]
+ ""
+- "b%C1\t%2,%3,%0"
++ "b%C1%y3\t%2,%w3%0"
+ [(set_attr "type" "branch")
+ (set_attr "mode" "none")])
+
+-(define_insn "*branch_zero<mode>"
+- [(set (pc)
+- (if_then_else
+- (match_operator 1 "signed_order_operator"
+- [(match_operand:X 2 "register_operand" "r")
+- (const_int 0)])
+- (label_ref (match_operand 0 "" ""))
+- (pc)))]
+- ""
+- "b%C1z\t%2,%0"
+- [(set_attr "type" "branch")
+- (set_attr "mode" "none")])
++;; Patterns for implementations that optimize short forward branches
++
++(define_expand "mov<mode>cc"
++ [(set (match_operand:GPR 0 "register_operand")
++ (if_then_else:GPR (match_operand 1 "comparison_operator")
++ (match_operand:GPR 2 "register_operand")
++ (match_operand:GPR 3 "sfb_alu_operand")))]
++ "TARGET_SFB_ALU"
++{
++ rtx cmp = operands[1];
++ /* We only handle word mode integer compares for now. */
++ if (GET_MODE (XEXP (cmp, 0)) != word_mode)
++ FAIL;
++ riscv_expand_conditional_move (operands[0], operands[2], operands[3],
++ GET_CODE (cmp), XEXP (cmp, 0), XEXP (cmp, 1));
++ DONE;
++})
++
++(define_insn "*mov<GPR:mode><X:mode>cc"
++ [(set (match_operand:GPR 0 "register_operand" "=r,r")
++ (if_then_else:GPR
++ (match_operator 5 "order_operator"
++ [(match_operand:X 1 "register_operand" "r,r")
++ (match_operand:X 2 "reg_or_0_operand" "rJ,rJ")])
++ (match_operand:GPR 3 "register_operand" "0,0")
++ (match_operand:GPR 4 "sfb_alu_operand" "rJ,IL")))]
++ "TARGET_SFB_ALU"
++ "@
++ b%C5%y2 %1, %w2 1f; mv %0, %z4; 1: # movcc
++ b%C5%y2 %1, %w2 1f; li %0, %4; 1: # movcc"
++ [(set_attr "length" "8")
++ (set_attr "type" "sfb_alu")
++ (set_attr "mode" "<GPR:MODE>")])
+
+ ;; Used to implement built-in functions.
+ (define_expand "condjump"
+diff --git a/gcc/config/riscv/sifive-7.md b/gcc/config/riscv/sifive-7.md
+index d58e01f8936..526278e46d4 100644
+--- a/gcc/config/riscv/sifive-7.md
++++ b/gcc/config/riscv/sifive-7.md
+@@ -37,6 +37,11 @@
+ (eq_attr "type" "branch"))
+ "sifive_7_B")
+
++(define_insn_reservation "sifive_7_sfb_alu" 2
++ (and (eq_attr "tune" "sifive_7")
++ (eq_attr "type" "sfb_alu"))
++ "sifive_7_A+sifive_7_B")
++
+ (define_insn_reservation "sifive_7_jump" 1
+ (and (eq_attr "tune" "sifive_7")
+ (eq_attr "type" "jump,call"))
+@@ -101,10 +106,13 @@
+ (eq_attr "type" "mfc"))
+ "sifive_7_A")
+
+-(define_bypass 1 "sifive_7_load,sifive_7_alu,sifive_7_mul,sifive_7_f2i"
++(define_bypass 1 "sifive_7_load,sifive_7_alu,sifive_7_mul,sifive_7_f2i,sifive_7_sfb_alu"
+ "sifive_7_alu,sifive_7_branch")
+
+-(define_bypass 1 "sifive_7_load,sifive_7_alu,sifive_7_mul,sifive_7_f2i"
++(define_bypass 1 "sifive_7_alu,sifive_7_sfb_alu"
++ "sifive_7_sfb_alu")
++
++(define_bypass 1 "sifive_7_load,sifive_7_alu,sifive_7_mul,sifive_7_f2i,sifive_7_sfb_alu"
+ "sifive_7_store" "riscv_store_data_bypass_p")
+
+ (define_bypass 2 "sifive_7_i2f"
+--
+2.21.0
+
diff --git a/0004-Remove-libgloss.patch b/0004-Remove-libgloss.patch
new file mode 100644
index 000000000000..b7febd4e7218
--- /dev/null
+++ b/0004-Remove-libgloss.patch
@@ -0,0 +1,17 @@
+diff --git a/gcc/config/riscv/elf.h b/gcc/config/riscv/elf.h
+index 9be97b866..8a0df0a37 100644
+--- a/gcc/config/riscv/elf.h
++++ b/gcc/config/riscv/elf.h
+@@ -22,10 +22,9 @@ along with GCC; see the file COPYING3. If not see
+ %{mno-relax:--no-relax} \
+ %{shared}"
+
+-/* Link against Newlib libraries, because the ELF backend assumes Newlib.
+- Handle the circular dependence between libc and libgloss. */
++/* remove the dependency of libgloss, no default libc. */
+ #undef LIB_SPEC
+-#define LIB_SPEC "--start-group -lc %{!specs=nosys.specs:-lgloss} --end-group"
++#define LIB_SPEC "--start-group -lgcc -lg -lc --end-group"
+
+ #undef STARTFILE_SPEC
+ #define STARTFILE_SPEC "crt0%O%s crtbegin%O%s"
diff --git a/PKGBUILD b/PKGBUILD
new file mode 100644
index 000000000000..0d5ed468e168
--- /dev/null
+++ b/PKGBUILD
@@ -0,0 +1,97 @@
+# Maintainer: Jiuyang Liu <liujiuyang1994@gmail.com>
+
+# Follow the upstream of https://github.com/sifive/freedom-tools/blob/master/Makefile
+
+_target=riscv-sifive-elf
+pkgname=$_target-gcc-stage1
+pkgver=9.1.0
+pkgrel=1
+pkgdesc='Cross compiler for 32-bit and 64-bit RISC-V'
+arch=('x86_64')
+url='https://gcc.gnu.org/'
+license=('GPL' 'LGPL' 'FDL')
+groups=('risc-v')
+depends=("$_target-binutils" "libmpc")
+options=('!emptydirs' '!strip')
+makedepends=('python')
+source=("https://gcc.gnu.org/pub/gcc/releases/gcc-$pkgver/gcc-$pkgver.tar.xz"
+ "0001-SiFive-CLIC-patches-for-preemptible-and-stack-swappi.patch"
+ "0002-Finish-CLIC-support-resolving-patch-merge-error-and-.patch"
+ "0003-RISC-V-Add-short-forward-branch-optimization-for-sif.patch"
+ "0004-Remove-libgloss.patch")
+md5sums=('6069ae3737cf02bf2cb44a391ef0e937'
+ 'SKIP'
+ 'SKIP'
+ 'SKIP'
+ 'SKIP')
+
+prepare() {
+ # hack! - some configure tests for header files using "$CPP $CPPFLAGS"
+ sed -i "/ac_cpp=/s/\$CPPFLAGS/\$CPPFLAGS -O2/" \
+ "$srcdir/gcc-$pkgver/"{libiberty,gcc}/configure
+
+ rm -rf "$srcdir/gcc-build"
+ mkdir "$srcdir/gcc-build"
+ export GCC_MULTILIB="rv32e-ilp32e--c rv32em-ilp32e--c rv32eac-ilp32e-- rv32emac-ilp32e-- rv32i-ilp32--c rv32im-ilp32--c rv32iac-ilp32-- rv32imac-ilp32-- rv32imaf-ilp32f-- rv32imafc-ilp32f-rv32imafdc- rv32imafdc-ilp32d-- rv64imac-lp64-- rv64imafc-lp64f-rv64imafdc- rv64imafdc-lp64d--"
+ IFS=$' '
+ cd $srcdir/gcc-$pkgver/gcc/config/riscv/
+ ./multilib-generator $GCC_MULTILIB > t-elf-multilib
+ cd $srcdir/gcc-$pkgver
+ echo "patch unmerged work from SiFive."
+ patch --forward --strip=1 --input="${srcdir}/0001-SiFive-CLIC-patches-for-preemptible-and-stack-swappi.patch"
+ patch --forward --strip=1 --input="${srcdir}/0002-Finish-CLIC-support-resolving-patch-merge-error-and-.patch"
+ patch --forward --strip=1 --input="${srcdir}/0003-RISC-V-Add-short-forward-branch-optimization-for-sif.patch"
+ patch --forward --strip=1 --input="${srcdir}/0004-Remove-libgloss.patch"
+}
+
+build() {
+ cd gcc-build
+
+ # https://github.com/sifive/freedom-tools/blob/master/Makefile#L274 include c and c++ support in stage1, I removed this.
+ "$srcdir/gcc-$pkgver/configure" \
+ --disable-libgomp \
+ --disable-libmudflap \
+ --disable-libquadmath \
+ --disable-libssp \
+ --disable-nls \
+ --disable-shared \
+ --disable-threads \
+ --disable-tls \
+ --enable-checking=yes \
+ --enable-languages=c \
+ --enable-multilib \
+ --libexecdir=/usr/lib \
+ --prefix=/usr \
+ --target=$_target \
+ --with-abi="ilp32" \
+ --with-arch="rv32imac" \
+ --with-bugurl='https://bugs.archlinux.org/' \
+ --with-newlib \
+ --with-pkgversion='Arch Repository' \
+ --with-python-dir=share/gcc-riscv-sifive-elf \
+ --with-sysroot=/usr/$_target \
+ --with-system-zlib \
+ CFLAGS="-O2" \
+ CXXFLAGS="-O2" \
+ CFLAGS_FOR_TARGET="-Os -mcmodel=medany" \
+ CXXFLAGS_FOR_TARGET="-Os -mcmodel=medany"
+
+ make
+}
+
+package() {
+ make -C gcc-build DESTDIR="$pkgdir" install-gcc install-target-libgcc
+
+ # Strip target binaries
+ find "$pkgdir/usr/lib/gcc/$_target/" -type f \
+ -and \( -name \*.a -or -name \*.o \) -exec $_target-objcopy \
+ -R .comment -R .note -R .debug_info -R .debug_aranges -R .debug_pubnames \
+ -R .debug_pubtypes -R .debug_abbrev -R .debug_line -R .debug_str \
+ -R .debug_ranges -R .debug_loc '{}' \;
+
+ # Strip host binaries
+ find "$pkgdir/usr/bin/" "$pkgdir/usr/lib/gcc/$_target/" -type f \
+ -and \( -executable \) -exec strip '{}' \;
+ # Remove files that conflict with host gcc package
+ rm -r "$pkgdir/usr/share/"{man/man7,info}
+}