gcc/ * gcc/config/riscv/riscv-opts.h (TARGET_LDR): New. (TARGET_LDUR): Likewise. * gcc/config/riscv/riscv.h (INDEX_REG_CLASS): Use TARGET_LDR. (REGNO_OK_FOR_INDEX_P): Use TARGET_LDR. (REG_OK_FOR_INDEX_P): Use REGNO_OK_FOR_INDEX_P. * gcc/config/riscv/riscv.c (riscv_address_type): Add ADDRESS_REG_REG, ADDRESS_REG_UREG. (riscv_address_info): Add shift. (riscv_classify_address_index): New. (riscv_classify_address): Use riscv_classify_address_index. (riscv_legitimize_address_index_p): New. (riscv_output_move_index): New. (riscv_output_move): Add parameter, Use riscv_output_move_index. (riscv_print_operand_address): Use ADDRESS_REG_REG, ADDRESS_REG_UREG. * gcc/config/riscv/riscv-protos.h (riscv_output_move): Update riscv_output_move. * gcc/config/riscv/riscv.md (zero_extendsidi2): Use riscv_output_move. (zero_extendhi<GPR:mode>2): Likewise. (zero_extendqi<SUPERQI:mode>2): Likewise. (extendsidi2): Likewise. (extend<SHORT:mode><SUPERQI:mode>2): Likewise. * gcc/config/riscv/predicates.md (sync_memory_operand): New. * gcc/config/riscv/sync.md (atomic_store<mode>): Use sync_memory_operand. (atomic_<atomic_optab><mode>): Likewise. (atomic_fetch_<atomic_optab><mode>): Likewise. (atomic_exchange<mode>): Likewise. (atomic_cas_value_strong<mode>): Likewise. (atomic_compare_and_swap<mode>): Likewise. (atomic_test_and_set): Likewise.
gcc/testsuite/ * gcc.target/riscv/xthead/riscv-xthead.exp: New. * gcc.target/riscv/xthead/ldr.c: Likewise. --- gcc/config/riscv/predicates.md | 4 + gcc/config/riscv/riscv-opts.h | 3 + gcc/config/riscv/riscv-protos.h | 2 +- gcc/config/riscv/riscv.c | 234 ++++++++++++++++-- gcc/config/riscv/riscv.h | 7 +- gcc/config/riscv/riscv.md | 50 ++-- gcc/config/riscv/sync.md | 14 +- gcc/testsuite/gcc.target/riscv/xthead/ldr.c | 34 +++ .../gcc.target/riscv/xthead/riscv-xthead.exp | 41 +++ 9 files changed, 348 insertions(+), 41 deletions(-) create mode 100644 gcc/testsuite/gcc.target/riscv/xthead/ldr.c create mode 100644 gcc/testsuite/gcc.target/riscv/xthead/riscv-xthead.exp diff --git a/gcc/config/riscv/predicates.md b/gcc/config/riscv/predicates.md index 232115135544..802e7a40e880 100644 --- a/gcc/config/riscv/predicates.md +++ b/gcc/config/riscv/predicates.md @@ -217,3 +217,7 @@ { return riscv_gpr_save_operation_p (op); }) + +(define_predicate "sync_memory_operand" + (and (match_operand 0 "memory_operand") + (match_code "reg" "0"))) diff --git a/gcc/config/riscv/riscv-opts.h b/gcc/config/riscv/riscv-opts.h index a2d84a66f037..d3163cb2377c 100644 --- a/gcc/config/riscv/riscv-opts.h +++ b/gcc/config/riscv/riscv-opts.h @@ -76,4 +76,7 @@ enum stack_protector_guard { #define MASK_XTHEAD_C (1 << 0) #define TARGET_XTHEAD_C ((riscv_x_subext & MASK_XTHEAD_C) != 0) +#define TARGET_LDR (TARGET_XTHEAD_C) +#define TARGET_LDUR (TARGET_XTHEAD_C) + #endif /* ! GCC_RISCV_OPTS_H */ diff --git a/gcc/config/riscv/riscv-protos.h b/gcc/config/riscv/riscv-protos.h index 43d7224d6941..3a218f327c42 100644 --- a/gcc/config/riscv/riscv-protos.h +++ b/gcc/config/riscv/riscv-protos.h @@ -52,9 +52,9 @@ extern bool riscv_legitimize_move (machine_mode, rtx, rtx); extern rtx riscv_subword (rtx, bool); extern bool riscv_split_64bit_move_p (rtx, rtx); extern void riscv_split_doubleword_move (rtx, rtx); -extern const char *riscv_output_move (rtx, rtx); extern const char *riscv_output_return (); #ifdef RTX_CODE +extern const char *riscv_output_move (rtx, rtx, rtx_code outer = UNKNOWN); 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); diff --git a/gcc/config/riscv/riscv.c b/gcc/config/riscv/riscv.c index 576960bb37cb..7d321826f669 100644 --- a/gcc/config/riscv/riscv.c +++ b/gcc/config/riscv/riscv.c @@ -80,6 +80,12 @@ along with GCC; see the file COPYING3. If not see A natural register + offset address. The register satisfies riscv_valid_base_register_p and the offset is a const_arith_operand. + ADDRESS_REG_REG + A base register indexed by (optionally scaled) register. + + ADDRESS_REG_UREG + A base register indexed by (optionally scaled) zero-extended register. + ADDRESS_LO_SUM A LO_SUM rtx. The first operand is a valid base register and the second operand is a symbolic address. @@ -91,6 +97,8 @@ along with GCC; see the file COPYING3. If not see A constant symbolic address. */ enum riscv_address_type { ADDRESS_REG, + ADDRESS_REG_REG, + ADDRESS_REG_UREG, ADDRESS_LO_SUM, ADDRESS_CONST_INT, ADDRESS_SYMBOLIC @@ -175,6 +183,11 @@ struct riscv_arg_info { ADDRESS_REG REG is the base register and OFFSET is the constant offset. + ADDRESS_REG_REG + ADDRESS_REG_UREG + REG is the base register and OFFSET is the indexed register, + and SHIFT is scaled value. + ADDRESS_LO_SUM REG and OFFSET are the operands to the LO_SUM and SYMBOL_TYPE is the type of symbol it references. @@ -186,6 +199,7 @@ struct riscv_address_info { rtx reg; rtx offset; enum riscv_symbol_type symbol_type; + int shift; }; /* One stage in a constant building sequence. These sequences have @@ -821,6 +835,104 @@ riscv_valid_lo_sum_p (enum riscv_symbol_type sym_type, machine_mode mode, return true; } +/* Return true if address offset is a valid index. If it is, fill in INFO + appropriately. STRICT_P is true if REG_OK_STRICT is in effect. */ + +bool +riscv_classify_address_index (struct riscv_address_info *info, rtx x, + machine_mode mode, bool strict_p) +{ + enum riscv_address_type type = ADDRESS_REG_REG;; + rtx index; + int shift = 0; + + if (!TARGET_LDR) + return false; + + if (FLOAT_MODE_P (mode)) + return false; + + /* (reg:P) */ + if ((REG_P (x) || GET_CODE (x) == SUBREG) + && GET_MODE (x) == Pmode) + { + index = x; + shift = 0; + } + /* (zero_extend:DI (reg:SI)) */ + else if (TARGET_LDUR + && GET_CODE (x) == ZERO_EXTEND + && GET_MODE (x) == DImode + && GET_MODE (XEXP (x, 0)) == SImode) + { + type = ADDRESS_REG_UREG; + index = XEXP (x, 0); + shift = 0; + } + /* (mult:DI (zero_extend:DI (reg:SI)) (const_int scale)) */ + else if (TARGET_LDUR + && GET_CODE (x) == MULT + && GET_CODE (XEXP (x, 0)) == ZERO_EXTEND + && GET_MODE (XEXP (x, 0)) == DImode + && GET_MODE (XEXP (XEXP (x, 0), 0)) == SImode + && CONST_INT_P (XEXP (x, 1))) + { + type = ADDRESS_REG_UREG; + index = XEXP (XEXP (x, 0), 0); + shift = exact_log2 (INTVAL (XEXP (x, 1))); + } + /* (ashift:DI (zero_extend:DI (reg:SI)) (const_int shift)) */ + else if (TARGET_LDUR + && GET_CODE (x) == ASHIFT + && GET_CODE (XEXP (x, 0)) == ZERO_EXTEND + && GET_MODE (XEXP (x, 0)) == DImode + && GET_MODE (XEXP (XEXP (x, 0), 0)) == SImode + && CONST_INT_P (XEXP (x, 1))) + { + type = ADDRESS_REG_UREG; + index = XEXP (XEXP (x, 0), 0); + shift = INTVAL (XEXP (x, 1)); + } + /* (mult:P (reg:P) (const_int scale)) */ + else if (GET_CODE (x) == MULT + && GET_MODE (x) == Pmode + && GET_MODE (XEXP (x, 0)) == Pmode + && CONST_INT_P (XEXP (x, 1))) + { + index = XEXP (x, 0); + shift = exact_log2 (INTVAL (XEXP (x, 1))); + } + /* (ashift:P (reg:P) (const_int shift)) */ + else if (GET_CODE (x) == ASHIFT + && GET_MODE (x) == Pmode + && GET_MODE (XEXP (x, 0)) == Pmode + && CONST_INT_P (XEXP (x, 1))) + { + index = XEXP (x, 0); + shift = INTVAL (XEXP (x, 1)); + } + else + return false; + + if (shift != 0 && !IN_RANGE (shift, 1, 3)) + return false; + + if (!strict_p + && GET_CODE (index) == SUBREG + && contains_reg_of_mode[GENERAL_REGS][GET_MODE (SUBREG_REG (index))]) + index = SUBREG_REG (index); + + if (riscv_valid_base_register_p (index, mode, strict_p)) + { + info->type = type; + info->offset = index; + info->shift = shift; + return true; + } + + return false; +} + /* Return true if X is a valid address for machine mode MODE. If it is, fill in INFO appropriately. STRICT_P is true if REG_OK_STRICT is in effect. */ @@ -839,6 +951,18 @@ riscv_classify_address (struct riscv_address_info *info, rtx x, return riscv_valid_base_register_p (info->reg, mode, strict_p); case PLUS: + if (riscv_valid_base_register_p (XEXP (x, 0), mode, strict_p) + && riscv_classify_address_index (info, XEXP (x, 1), mode, strict_p)) + { + info->reg = XEXP (x, 0); + return true; + } + else if (riscv_valid_base_register_p (XEXP (x, 1), mode, strict_p) + && riscv_classify_address_index (info, XEXP (x, 0), mode, strict_p)) + { + info->reg = XEXP (x, 1); + return true; + } info->type = ADDRESS_REG; info->reg = XEXP (x, 0); info->offset = XEXP (x, 1); @@ -2047,11 +2171,70 @@ riscv_split_doubleword_move (rtx dest, rtx src) } } +/* Return TRUE if X is a legitimate address index. */ + +bool +riscv_legitimize_address_index_p (rtx x, machine_mode mode, bool uindex) +{ + struct riscv_address_info addr; + rtx op0, op1; + + if (GET_CODE (x) != PLUS) + return false; + + op0 = XEXP (x, 0); + op1 = XEXP (x, 1); + + return ((riscv_valid_base_register_p (op0, mode, false) + && riscv_classify_address_index (&addr, op1, mode, false)) + || (riscv_valid_base_register_p (op1, mode, false) + && riscv_classify_address_index (&addr, op0, mode, false))) + && (!uindex || addr.type == ADDRESS_REG_UREG); +} + +/* Return the LDR or STR instructions. Assume + that X is MEM operand. */ + +const char * +riscv_output_move_index (rtx x, machine_mode mode, bool ldr, rtx_code outer) +{ + static char buf[128] = {0}; + + int index = exact_log2 (GET_MODE_SIZE (mode)); + if (!IN_RANGE (index, 0, 3)) + return NULL; + + if (!riscv_legitimize_address_index_p (x, mode, false)) + return NULL; + + bool uindex = riscv_legitimize_address_index_p (x, mode, true); + + const char *const insn[][4] = + { + { + "s%srb\t%%z1,%%0", + "s%srh\t%%z1,%%0", + "s%srw\t%%z1,%%0", + "s%srd\t%%z1,%%0" + }, + { + "l%srbu\t%%0,%%1", + "l%srhu\t%%0,%%1", + "l%srw%s\t%%0,%%1", + "l%srd\t%%0,%%1" + } + }; + + snprintf (buf, sizeof (buf), insn[ldr][index], uindex ? "u" : "", outer == ZERO_EXTEND ? "u" : ""); + + return buf; +} + /* Return the appropriate instructions to move SRC into DEST. Assume that SRC is operand 1 and DEST is operand 0. */ const char * -riscv_output_move (rtx dest, rtx src) +riscv_output_move (rtx dest, rtx src, rtx_code outer) { enum rtx_code dest_code, src_code; machine_mode mode; @@ -2071,13 +2254,20 @@ riscv_output_move (rtx dest, rtx src) return dbl_p ? "fmv.x.d\t%0,%1" : "fmv.x.w\t%0,%1"; if (src_code == MEM) - switch (GET_MODE_SIZE (mode)) - { - case 1: return "lbu\t%0,%1"; - case 2: return "lhu\t%0,%1"; - case 4: return "lw\t%0,%1"; - case 8: return "ld\t%0,%1"; - } + { + const char *insn = NULL; + insn = riscv_output_move_index (XEXP (src, 0), GET_MODE (src), true, outer); + if (insn) + return insn; + + switch (GET_MODE_SIZE (GET_MODE (src))) + { + case 1: return "lbu\t%0,%1"; + case 2: return "lhu\t%0,%1"; + case 4: return outer == ZERO_EXTEND ? "lwu\t%0,%1" : "lw\t%0,%1"; + case 8: return "ld\t%0,%1"; + } + } if (src_code == CONST_INT) return "li\t%0,%1"; @@ -2114,13 +2304,20 @@ riscv_output_move (rtx dest, rtx src) } } if (dest_code == MEM) - switch (GET_MODE_SIZE (mode)) - { - case 1: return "sb\t%z1,%0"; - case 2: return "sh\t%z1,%0"; - case 4: return "sw\t%z1,%0"; - case 8: return "sd\t%z1,%0"; - } + { + const char *insn = NULL; + insn = riscv_output_move_index (XEXP (dest, 0), GET_MODE (dest), false, outer); + if (insn) + return insn; + + switch (GET_MODE_SIZE (mode)) + { + case 1: return "sb\t%z1,%0"; + case 2: return "sh\t%z1,%0"; + case 4: return "sw\t%z1,%0"; + case 8: return "sd\t%z1,%0"; + } + } } if (src_code == REG && FP_REG_P (REGNO (src))) { @@ -3504,6 +3701,13 @@ riscv_print_operand_address (FILE *file, machine_mode mode ATTRIBUTE_UNUSED, rtx fprintf (file, "(%s)", reg_names[REGNO (addr.reg)]); return; + case ADDRESS_REG_REG: + case ADDRESS_REG_UREG: + fprintf (file, "%s,%s,%u", reg_names[REGNO (addr.reg)], + reg_names[REGNO (addr.offset)], + addr.shift); + return; + case ADDRESS_LO_SUM: riscv_print_operand_reloc (file, addr.offset, false); fprintf (file, "(%s)", reg_names[REGNO (addr.reg)]); diff --git a/gcc/config/riscv/riscv.h b/gcc/config/riscv/riscv.h index f47d5b40a66a..d54b81270da1 100644 --- a/gcc/config/riscv/riscv.h +++ b/gcc/config/riscv/riscv.h @@ -492,7 +492,7 @@ enum reg_class factor or added to another register (as well as added to a displacement). */ -#define INDEX_REG_CLASS NO_REGS +#define INDEX_REG_CLASS (TARGET_LDR ? GR_REGS : NO_REGS) /* We generally want to put call-clobbered registers ahead of call-saved ones. (IRA expects this.) */ @@ -636,7 +636,8 @@ typedef struct { /* Addressing modes, and classification of registers for them. */ -#define REGNO_OK_FOR_INDEX_P(REGNO) 0 +#define REGNO_OK_FOR_INDEX_P(REGNO) \ + (TARGET_LDR ? riscv_regno_mode_ok_for_base_p (REGNO, VOIDmode, 1) : 0) #define REGNO_MODE_OK_FOR_BASE_P(REGNO, MODE) \ riscv_regno_mode_ok_for_base_p (REGNO, MODE, 1) @@ -659,7 +660,7 @@ typedef struct { riscv_regno_mode_ok_for_base_p (REGNO (X), MODE, 1) #endif -#define REG_OK_FOR_INDEX_P(X) 0 +#define REG_OK_FOR_INDEX_P(X) REGNO_OK_FOR_INDEX_P (REGNO (X)) /* Maximum number of registers that can appear in a valid memory address. */ diff --git a/gcc/config/riscv/riscv.md b/gcc/config/riscv/riscv.md index f88877fd5966..5229b00fb76c 100644 --- a/gcc/config/riscv/riscv.md +++ b/gcc/config/riscv/riscv.md @@ -1307,9 +1307,13 @@ (zero_extend:DI (match_operand:SI 1 "nonimmediate_operand" " r,m")))] "TARGET_64BIT" - "@ - # - lwu\t%0,%1" + { + switch (which_alternative) + { + default: return "#"; + case 1: return riscv_output_move (operands[0], operands[1], ZERO_EXTEND); + } + } "&& reload_completed && REG_P (operands[1]) && !paradoxical_subreg_p (operands[0])" @@ -1326,9 +1330,13 @@ (zero_extend:GPR (match_operand:HI 1 "nonimmediate_operand" " r,m")))] "" - "@ - # - lhu\t%0,%1" + { + switch (which_alternative) + { + default: return "#"; + case 1: return riscv_output_move (operands[0], operands[1]); + } + } "&& reload_completed && REG_P (operands[1]) && !paradoxical_subreg_p (operands[0])" @@ -1348,9 +1356,13 @@ (zero_extend:SUPERQI (match_operand:QI 1 "nonimmediate_operand" " r,m")))] "" - "@ - andi\t%0,%1,0xff - lbu\t%0,%1" + { + switch (which_alternative) + { + default: return "andi\t%0,%1,0xff"; + case 1: return riscv_output_move (operands[0], operands[1]); + } + } [(set_attr "move_type" "andi,load") (set_attr "mode" "<SUPERQI:MODE>")]) @@ -1366,9 +1378,13 @@ (sign_extend:DI (match_operand:SI 1 "nonimmediate_operand" " r,m")))] "TARGET_64BIT" - "@ - sext.w\t%0,%1 - lw\t%0,%1" + { + switch (which_alternative) + { + default: return "sext.w\t%0,%1"; + case 1: return riscv_output_move (operands[0], operands[1]); + } + } [(set_attr "move_type" "move,load") (set_attr "mode" "DI")]) @@ -1377,9 +1393,13 @@ (sign_extend:SUPERQI (match_operand:SHORT 1 "nonimmediate_operand" " r,m")))] "" - "@ - # - l<SHORT:size>\t%0,%1" + { + switch (which_alternative) + { + default: return "#"; + case 1: return riscv_output_move (operands[0], operands[1]); + } + } "&& reload_completed && REG_P (operands[1]) && !paradoxical_subreg_p (operands[0])" diff --git a/gcc/config/riscv/sync.md b/gcc/config/riscv/sync.md index 747a799e2377..5ad1d48a6ce0 100644 --- a/gcc/config/riscv/sync.md +++ b/gcc/config/riscv/sync.md @@ -59,7 +59,7 @@ ;; Implement atomic stores with amoswap. Fall back to fences for atomic loads. (define_insn "atomic_store<mode>" - [(set (match_operand:GPR 0 "memory_operand" "=A") + [(set (match_operand:GPR 0 "sync_memory_operand" "=A") (unspec_volatile:GPR [(match_operand:GPR 1 "reg_or_0_operand" "rJ") (match_operand:SI 2 "const_int_operand")] ;; model @@ -69,7 +69,7 @@ [(set (attr "length") (const_int 8))]) (define_insn "atomic_<atomic_optab><mode>" - [(set (match_operand:GPR 0 "memory_operand" "+A") + [(set (match_operand:GPR 0 "sync_memory_operand" "+A") (unspec_volatile:GPR [(any_atomic:GPR (match_dup 0) (match_operand:GPR 1 "reg_or_0_operand" "rJ")) @@ -81,7 +81,7 @@ (define_insn "atomic_fetch_<atomic_optab><mode>" [(set (match_operand:GPR 0 "register_operand" "=&r") - (match_operand:GPR 1 "memory_operand" "+A")) + (match_operand:GPR 1 "sync_memory_operand" "+A")) (set (match_dup 1) (unspec_volatile:GPR [(any_atomic:GPR (match_dup 1) @@ -95,7 +95,7 @@ (define_insn "atomic_exchange<mode>" [(set (match_operand:GPR 0 "register_operand" "=&r") (unspec_volatile:GPR - [(match_operand:GPR 1 "memory_operand" "+A") + [(match_operand:GPR 1 "sync_memory_operand" "+A") (match_operand:SI 3 "const_int_operand")] ;; model UNSPEC_SYNC_EXCHANGE)) (set (match_dup 1) @@ -106,7 +106,7 @@ (define_insn "atomic_cas_value_strong<mode>" [(set (match_operand:GPR 0 "register_operand" "=&r") - (match_operand:GPR 1 "memory_operand" "+A")) + (match_operand:GPR 1 "sync_memory_operand" "+A")) (set (match_dup 1) (unspec_volatile:GPR [(match_operand:GPR 2 "reg_or_0_operand" "rJ") (match_operand:GPR 3 "reg_or_0_operand" "rJ") @@ -121,7 +121,7 @@ (define_expand "atomic_compare_and_swap<mode>" [(match_operand:SI 0 "register_operand" "") ;; bool output (match_operand:GPR 1 "register_operand" "") ;; val output - (match_operand:GPR 2 "memory_operand" "") ;; memory + (match_operand:GPR 2 "sync_memory_operand" "") ;; memory (match_operand:GPR 3 "reg_or_0_operand" "") ;; expected value (match_operand:GPR 4 "reg_or_0_operand" "") ;; desired value (match_operand:SI 5 "const_int_operand" "") ;; is_weak @@ -154,7 +154,7 @@ (define_expand "atomic_test_and_set" [(match_operand:QI 0 "register_operand" "") ;; bool output - (match_operand:QI 1 "memory_operand" "+A") ;; memory + (match_operand:QI 1 "sync_memory_operand" "+A") ;; memory (match_operand:SI 2 "const_int_operand" "")] ;; model "TARGET_ATOMIC" { diff --git a/gcc/testsuite/gcc.target/riscv/xthead/ldr.c b/gcc/testsuite/gcc.target/riscv/xthead/ldr.c new file mode 100644 index 000000000000..bee469392881 --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/xthead/ldr.c @@ -0,0 +1,34 @@ +/* { dg-do compile } */ +/* { dg-skip-if "test ldr/str insns" { *-*-* } { "*" } { "-march=*xtheadc* -mabi=lp64*" } } */ + +void foo_w(int *dest, int *src, int index) +{ + dest[index] = src[index]; +} + +/* { dg-final { scan-assembler "lrw" } } */ +/* { dg-final { scan-assembler "srw" } } */ + +void foo_d(long *dest, long *src, int index) +{ + dest[index] = src[index]; +} + +/* { dg-final { scan-assembler "lrd" } } */ +/* { dg-final { scan-assembler "srd" } } */ + +void foo_w_ui(int *dest, int *src, unsigned index) +{ + dest[index] = src[index]; +} + +/* { dg-final { scan-assembler "lurw" } } */ +/* { dg-final { scan-assembler "surw" } } */ + +void foo_d_ui(long *dest, long *src, unsigned index) +{ + dest[index] = src[index]; +} + +/* { dg-final { scan-assembler "lurd" } } */ +/* { dg-final { scan-assembler "surd" } } */ diff --git a/gcc/testsuite/gcc.target/riscv/xthead/riscv-xthead.exp b/gcc/testsuite/gcc.target/riscv/xthead/riscv-xthead.exp new file mode 100644 index 000000000000..2b83bf9e5a23 --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/xthead/riscv-xthead.exp @@ -0,0 +1,41 @@ +# Copyright (C) 2017-2021 Free Software Foundation, Inc. + +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with GCC; see the file COPYING3. If not see +# <http://www.gnu.org/licenses/>. + +# GCC testsuite that uses the `dg.exp' driver. + +# Exit immediately if this isn't a RISC-V target. +if ![istarget riscv*-*-*] then { + return +} + +# Load support procs. +load_lib gcc-dg.exp + +# If a testcase doesn't have special options, use these. +global DEFAULT_CFLAGS +if ![info exists DEFAULT_CFLAGS] then { + set DEFAULT_CFLAGS " -ansi -pedantic-errors" +} + +# Initialize `dg'. +dg-init + +# Main loop. +dg-runtest [lsort [glob -nocomplain $srcdir/$subdir/*.\[cS\]]] \ + "" $DEFAULT_CFLAGS + +# All done. +dg-finish -- 2.24.3 (Apple Git-128)