From 181f753dc4afa9866d6125904cf050d5eb437a86 Mon Sep 17 00:00:00 2001 From: David Malcolm Date: Tue, 30 Jan 2024 08:17:47 -0500 Subject: analyzer: add SARIF property bag to -Wanalyzer-allocation-size This is useful for debugging the analyzer. gcc/analyzer/ChangeLog: * region-model.cc (dubious_allocation_size::dubious_allocation_size): Add "capacity_sval" param. Drop unused ctor. (dubious_allocation_size::maybe_add_sarif_properties): New. (dubious_allocation_size::m_capacity_sval): New field. (region_model::check_region_size): Pass capacity svalue to dubious_allocation_size ctor. Signed-off-by: David Malcolm --- gcc/analyzer/region-model.cc | 31 +++++++++++++++++++++---------- 1 file changed, 21 insertions(+), 10 deletions(-) (limited to 'gcc') diff --git a/gcc/analyzer/region-model.cc b/gcc/analyzer/region-model.cc index dbb2149..ba82f46 100644 --- a/gcc/analyzer/region-model.cc +++ b/gcc/analyzer/region-model.cc @@ -3113,16 +3113,15 @@ class dubious_allocation_size { public: dubious_allocation_size (const region *lhs, const region *rhs, + const svalue *capacity_sval, tree expr, const gimple *stmt) - : m_lhs (lhs), m_rhs (rhs), m_expr (NULL_TREE), m_stmt (stmt), + : m_lhs (lhs), m_rhs (rhs), + m_capacity_sval (capacity_sval), m_expr (expr), + m_stmt (stmt), m_has_allocation_event (false) - {} - - dubious_allocation_size (const region *lhs, const region *rhs, - tree expr, const gimple *stmt) - : m_lhs (lhs), m_rhs (rhs), m_expr (expr), m_stmt (stmt), - m_has_allocation_event (false) - {} + { + gcc_assert (m_capacity_sval); + } const char *get_kind () const final override { @@ -3196,9 +3195,21 @@ public: interest->add_region_creation (m_rhs); } + void maybe_add_sarif_properties (sarif_object &result_obj) + const final override + { + sarif_property_bag &props = result_obj.get_or_create_properties (); +#define PROPERTY_PREFIX "gcc/analyzer/dubious_allocation_size/" + props.set (PROPERTY_PREFIX "lhs", m_lhs->to_json ()); + props.set (PROPERTY_PREFIX "rhs", m_rhs->to_json ()); + props.set (PROPERTY_PREFIX "capacity_sval", m_capacity_sval->to_json ()); +#undef PROPERTY_PREFIX + } + private: const region *m_lhs; const region *m_rhs; + const svalue *m_capacity_sval; const tree m_expr; const gimple *m_stmt; bool m_has_allocation_event; @@ -3437,7 +3448,7 @@ region_model::check_region_size (const region *lhs_reg, const svalue *rhs_sval, && !capacity_compatible_with_type (cst_cap, pointee_size_tree, is_struct)) ctxt->warn (make_unique (lhs_reg, rhs_reg, - cst_cap, + capacity, cst_cap, ctxt->get_stmt ())); } break; @@ -3451,7 +3462,7 @@ region_model::check_region_size (const region *lhs_reg, const svalue *rhs_sval, tree expr = get_representative_tree (capacity); ctxt->warn (make_unique (lhs_reg, rhs_reg, - expr, + capacity, expr, ctxt->get_stmt ())); } } -- cgit v1.1 From 9f382376660069e49290fdb51861abdec63519c7 Mon Sep 17 00:00:00 2001 From: David Malcolm Date: Tue, 30 Jan 2024 08:17:47 -0500 Subject: analyzer: fix -Wanalyzer-allocation-size false +ve on Linux kernel's round_up macro [PR113654] gcc/analyzer/ChangeLog: PR analyzer/113654 * region-model.cc (is_round_up): New. (is_multiple_p): New. (is_dubious_capacity): New. (region_model::check_region_size): Move usage of size_visitor into is_dubious_capacity. gcc/testsuite/ChangeLog: PR analyzer/113654 * c-c++-common/analyzer/allocation-size-pr113654-1.c: New test. Signed-off-by: David Malcolm --- gcc/analyzer/region-model.cc | 75 +++++++++++++++++++++- .../analyzer/allocation-size-pr113654-1.c | 52 +++++++++++++++ 2 files changed, 125 insertions(+), 2 deletions(-) create mode 100644 gcc/testsuite/c-c++-common/analyzer/allocation-size-pr113654-1.c (limited to 'gcc') diff --git a/gcc/analyzer/region-model.cc b/gcc/analyzer/region-model.cc index ba82f46..082972f 100644 --- a/gcc/analyzer/region-model.cc +++ b/gcc/analyzer/region-model.cc @@ -3349,6 +3349,76 @@ private: svalue_set result_set; /* Used as a mapping of svalue*->bool. */ }; +/* Return true if SIZE_CST is a power of 2, and we have + CAPACITY_SVAL == ((X | (Y - 1) ) + 1), since it is then a multiple + of SIZE_CST, as used by Linux kernel's round_up macro. */ + +static bool +is_round_up (tree size_cst, + const svalue *capacity_sval) +{ + if (!integer_pow2p (size_cst)) + return false; + const binop_svalue *binop_sval = capacity_sval->dyn_cast_binop_svalue (); + if (!binop_sval) + return false; + if (binop_sval->get_op () != PLUS_EXPR) + return false; + tree rhs_cst = binop_sval->get_arg1 ()->maybe_get_constant (); + if (!rhs_cst) + return false; + if (!integer_onep (rhs_cst)) + return false; + + /* We have CAPACITY_SVAL == (LHS + 1) for some LHS expression. */ + + const binop_svalue *lhs_binop_sval + = binop_sval->get_arg0 ()->dyn_cast_binop_svalue (); + if (!lhs_binop_sval) + return false; + if (lhs_binop_sval->get_op () != BIT_IOR_EXPR) + return false; + + tree inner_rhs_cst = lhs_binop_sval->get_arg1 ()->maybe_get_constant (); + if (!inner_rhs_cst) + return false; + + if (wi::to_widest (inner_rhs_cst) + 1 != wi::to_widest (size_cst)) + return false; + return true; +} + +/* Return true if CAPACITY_SVAL is known to be a multiple of SIZE_CST. */ + +static bool +is_multiple_p (tree size_cst, + const svalue *capacity_sval) +{ + if (const svalue *sval = capacity_sval->maybe_undo_cast ()) + return is_multiple_p (size_cst, sval); + + if (is_round_up (size_cst, capacity_sval)) + return true; + + return false; +} + +/* Return true if we should emit a dubious_allocation_size warning + on assigning a region of capacity CAPACITY_SVAL bytes to a pointer + of type with size SIZE_CST, where CM expresses known constraints. */ + +static bool +is_dubious_capacity (tree size_cst, + const svalue *capacity_sval, + constraint_manager *cm) +{ + if (is_multiple_p (size_cst, capacity_sval)) + return false; + size_visitor v (size_cst, capacity_sval, cm); + return v.is_dubious_capacity (); +} + + /* Return true if a struct or union either uses the inheritance pattern, where the first field is a base struct, or the flexible array member pattern, where the last field is an array without a specified size. */ @@ -3456,8 +3526,9 @@ region_model::check_region_size (const region *lhs_reg, const svalue *rhs_sval, { if (!is_struct) { - size_visitor v (pointee_size_tree, capacity, m_constraints); - if (v.is_dubious_capacity ()) + if (is_dubious_capacity (pointee_size_tree, + capacity, + m_constraints)) { tree expr = get_representative_tree (capacity); ctxt->warn (make_unique (lhs_reg, diff --git a/gcc/testsuite/c-c++-common/analyzer/allocation-size-pr113654-1.c b/gcc/testsuite/c-c++-common/analyzer/allocation-size-pr113654-1.c new file mode 100644 index 0000000..b7bfc5f --- /dev/null +++ b/gcc/testsuite/c-c++-common/analyzer/allocation-size-pr113654-1.c @@ -0,0 +1,52 @@ +/* Adapted from include/linux/math.h */ +#define __round_mask(x, y) ((__typeof__(x))((y)-1)) +#define round_up(x, y) ((((x)-1) | __round_mask(x, y))+1) + +/* Reduced from Linux kernel's drivers/gpu/drm/i915/display/intel_bios.c */ +typedef unsigned short u16; +typedef unsigned int u32; +typedef unsigned long __kernel_size_t; +typedef __kernel_size_t size_t; + +extern __attribute__((__alloc_size__(1))) __attribute__((__malloc__)) +void* kzalloc(size_t size); + +typedef struct +{ + u32 reg; +} i915_reg_t; +struct intel_uncore; +struct intel_uncore_funcs +{ + u32 (*mmio_readl)(struct intel_uncore* uncore, i915_reg_t r); +}; +struct intel_uncore +{ + void* regs; + struct intel_uncore_funcs funcs; +}; +static inline __attribute__((__gnu_inline__)) __attribute__((__unused__)) +__attribute__((no_instrument_function)) u32 +intel_uncore_read(struct intel_uncore* uncore, i915_reg_t reg) +{ + return uncore->funcs.mmio_readl(uncore, reg); +} +struct drm_i915_private +{ + struct intel_uncore uncore; +}; +struct vbt_header* +spi_oprom_get_vbt(struct drm_i915_private* i915) +{ + u16 vbt_size; + u32* vbt; + vbt_size = + intel_uncore_read(&i915->uncore, ((const i915_reg_t){ .reg = (0x102040) })); + vbt_size &= 0xffff; + vbt = (u32*)kzalloc(round_up (vbt_size, 4)); /* { dg-bogus "allocated buffer size is not a multiple of the pointee's size" "PR analyzer/113654" } */ + if (!vbt) + goto err_not_found; + return (struct vbt_header*)vbt; +err_not_found: + return ((struct vbt_header*)0); +} -- cgit v1.1 From 7bfea0aedbce3f33a783bbb47f39724a58d19f73 Mon Sep 17 00:00:00 2001 From: Pan Li Date: Tue, 30 Jan 2024 15:42:06 +0800 Subject: RISC-V: Bugfix for vls mode aggregated in GPR calling convention According to the issue as below. https://hub.fgit.cf/riscv-non-isa/riscv-elf-psabi-doc/pull/416 When the mode size of vls integer mode is less than 2 * XLEN, we will take the gpr for both the args and the return values. Instead of the reference. For example the below code: typedef short v8hi __attribute__ ((vector_size (16))); v8hi __attribute__((noinline)) add (v8hi a, v8hi b) { v8hi r = a + b; return r; } Before this patch: add: vsetivli zero,8,e16,m1,ta,ma vle16.v v1,0(a1) <== arg by reference vle16.v v2,0(a2) <== arg by reference vadd.vv v1,v1,v2 vse16.v v1,0(a0) <== return by reference ret After this patch: add: addi sp,sp,-32 sd a0,0(sp) <== arg by register a0 - a3 sd a1,8(sp) sd a2,16(sp) sd a3,24(sp) addi a5,sp,16 vsetivli zero,8,e16,m1,ta,ma vle16.v v2,0(sp) vle16.v v1,0(a5) vadd.vv v1,v1,v2 vse16.v v1,0(sp) ld a0,0(sp) <== return by a0 - a1. ld a1,8(sp) addi sp,sp,32 jr ra For vls floating point, we take the same rules as integer and passed by the gpr or reference. The riscv regression passed for this patch. gcc/ChangeLog: * config/riscv/riscv.cc (riscv_v_vls_mode_aggregate_gpr_count): New function to calculate the gpr count required by vls mode. (riscv_v_vls_to_gpr_mode): New function convert vls mode to gpr mode. (riscv_pass_vls_aggregate_in_gpr): New function to return the rtx of gpr for vls mode. (riscv_get_arg_info): Add vls mode handling. (riscv_pass_by_reference): Return false if arg info has no zero gpr count. gcc/testsuite/ChangeLog: * gcc.target/riscv/rvv/autovec/vls/def.h: Add new helper macro. * gcc.target/riscv/rvv/autovec/vls/calling-convention-1.c: New test. * gcc.target/riscv/rvv/autovec/vls/calling-convention-10.c: New test. * gcc.target/riscv/rvv/autovec/vls/calling-convention-2.c: New test. * gcc.target/riscv/rvv/autovec/vls/calling-convention-3.c: New test. * gcc.target/riscv/rvv/autovec/vls/calling-convention-4.c: New test. * gcc.target/riscv/rvv/autovec/vls/calling-convention-5.c: New test. * gcc.target/riscv/rvv/autovec/vls/calling-convention-6.c: New test. * gcc.target/riscv/rvv/autovec/vls/calling-convention-7.c: New test. * gcc.target/riscv/rvv/autovec/vls/calling-convention-8.c: New test. * gcc.target/riscv/rvv/autovec/vls/calling-convention-9.c: New test. * gcc.target/riscv/rvv/autovec/vls/calling-convention-run-1.c: New test. * gcc.target/riscv/rvv/autovec/vls/calling-convention-run-2.c: New test. * gcc.target/riscv/rvv/autovec/vls/calling-convention-run-3.c: New test. * gcc.target/riscv/rvv/autovec/vls/calling-convention-run-4.c: New test. * gcc.target/riscv/rvv/autovec/vls/calling-convention-run-5.c: New test. * gcc.target/riscv/rvv/autovec/vls/calling-convention-run-6.c: New test. Signed-off-by: Pan Li --- gcc/config/riscv/riscv.cc | 78 +++++++++++ .../riscv/rvv/autovec/vls/calling-convention-1.c | 154 +++++++++++++++++++++ .../riscv/rvv/autovec/vls/calling-convention-10.c | 51 +++++++ .../riscv/rvv/autovec/vls/calling-convention-2.c | 142 +++++++++++++++++++ .../riscv/rvv/autovec/vls/calling-convention-3.c | 130 +++++++++++++++++ .../riscv/rvv/autovec/vls/calling-convention-4.c | 118 ++++++++++++++++ .../riscv/rvv/autovec/vls/calling-convention-5.c | 141 +++++++++++++++++++ .../riscv/rvv/autovec/vls/calling-convention-6.c | 129 +++++++++++++++++ .../riscv/rvv/autovec/vls/calling-convention-7.c | 118 ++++++++++++++++ .../riscv/rvv/autovec/vls/calling-convention-8.c | 43 ++++++ .../riscv/rvv/autovec/vls/calling-convention-9.c | 51 +++++++ .../rvv/autovec/vls/calling-convention-run-1.c | 55 ++++++++ .../rvv/autovec/vls/calling-convention-run-2.c | 55 ++++++++ .../rvv/autovec/vls/calling-convention-run-3.c | 55 ++++++++ .../rvv/autovec/vls/calling-convention-run-4.c | 55 ++++++++ .../rvv/autovec/vls/calling-convention-run-5.c | 55 ++++++++ .../rvv/autovec/vls/calling-convention-run-6.c | 55 ++++++++ .../gcc.target/riscv/rvv/autovec/vls/def.h | 74 ++++++++++ 18 files changed, 1559 insertions(+) create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/autovec/vls/calling-convention-1.c create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/autovec/vls/calling-convention-10.c create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/autovec/vls/calling-convention-2.c create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/autovec/vls/calling-convention-3.c create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/autovec/vls/calling-convention-4.c create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/autovec/vls/calling-convention-5.c create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/autovec/vls/calling-convention-6.c create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/autovec/vls/calling-convention-7.c create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/autovec/vls/calling-convention-8.c create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/autovec/vls/calling-convention-9.c create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/autovec/vls/calling-convention-run-1.c create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/autovec/vls/calling-convention-run-2.c create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/autovec/vls/calling-convention-run-3.c create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/autovec/vls/calling-convention-run-4.c create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/autovec/vls/calling-convention-run-5.c create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/autovec/vls/calling-convention-run-6.c (limited to 'gcc') diff --git a/gcc/config/riscv/riscv.cc b/gcc/config/riscv/riscv.cc index 7b6111a..529ef5e 100644 --- a/gcc/config/riscv/riscv.cc +++ b/gcc/config/riscv/riscv.cc @@ -1382,6 +1382,41 @@ riscv_v_ext_mode_p (machine_mode mode) || riscv_v_ext_vls_mode_p (mode); } +static unsigned +riscv_v_vls_mode_aggregate_gpr_count (unsigned vls_unit_size, + unsigned scalar_unit_size) +{ + gcc_assert (vls_unit_size != 0 && scalar_unit_size != 0); + + if (vls_unit_size < scalar_unit_size) + return 1; + + /* Ensure the vls mode is exact_div by scalar_unit_size. */ + gcc_assert ((vls_unit_size % scalar_unit_size) == 0); + + return vls_unit_size / scalar_unit_size; +} + +static machine_mode +riscv_v_vls_to_gpr_mode (unsigned vls_mode_size) +{ + switch (vls_mode_size) + { + case 16: + return TImode; + case 8: + return DImode; + case 4: + return SImode; + case 2: + return HImode; + case 1: + return QImode; + default: + gcc_unreachable (); + } +} + /* Call from ADJUST_NUNITS in riscv-modes.def. Return the correct NUNITS size for corresponding machine_mode. */ @@ -4868,6 +4903,41 @@ riscv_pass_fpr_pair (machine_mode mode, unsigned regno1, GEN_INT (offset2)))); } +static rtx +riscv_pass_vls_aggregate_in_gpr (struct riscv_arg_info *info, machine_mode mode, + unsigned gpr_base) +{ + gcc_assert (riscv_v_ext_vls_mode_p (mode)); + + unsigned count = 0; + unsigned regnum = 0; + machine_mode gpr_mode = VOIDmode; + unsigned vls_size = GET_MODE_SIZE (mode).to_constant (); + unsigned gpr_size = GET_MODE_SIZE (Xmode); + + if (IN_RANGE (vls_size, 0, gpr_size * 2)) + { + count = riscv_v_vls_mode_aggregate_gpr_count (vls_size, gpr_size); + + if (count + info->gpr_offset <= MAX_ARGS_IN_REGISTERS) + { + regnum = gpr_base + info->gpr_offset; + info->num_gprs = count; + gpr_mode = riscv_v_vls_to_gpr_mode (vls_size); + } + } + + if (!regnum) + return NULL_RTX; /* Return NULL_RTX if we cannot find a suitable reg. */ + + gcc_assert (gpr_mode != VOIDmode); + + rtx reg = gen_rtx_REG (gpr_mode, regnum); + rtx x = gen_rtx_EXPR_LIST (VOIDmode, reg, CONST0_RTX (gpr_mode)); + + return gen_rtx_PARALLEL (mode, gen_rtvec (1, x)); +} + /* Initialize a variable CUM of type CUMULATIVE_ARGS for a call to a function whose data type is FNTYPE. For a library call, FNTYPE is 0. */ @@ -5067,6 +5137,10 @@ riscv_get_arg_info (struct riscv_arg_info *info, const CUMULATIVE_ARGS *cum, /* For scalable vector argument. */ if (riscv_vector_type_p (type) && riscv_v_ext_mode_p (mode)) return riscv_get_vector_arg (info, cum, mode, return_p); + + /* For vls mode aggregated in gpr. */ + if (riscv_v_ext_vls_mode_p (mode)) + return riscv_pass_vls_aggregate_in_gpr (info, mode, gpr_base); } /* Work out the size of the argument. */ @@ -5196,6 +5270,10 @@ riscv_pass_by_reference (cumulative_args_t cum_v, const function_arg_info &arg) if (info.num_fprs) return false; + /* Don't pass by reference if we can use general register(s) for vls. */ + if (info.num_gprs && riscv_v_ext_vls_mode_p (arg.mode)) + return false; + /* Don't pass by reference if we can use vector register groups. */ if (info.num_vrs > 0 || info.num_mrs > 0) return false; diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/vls/calling-convention-1.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vls/calling-convention-1.c new file mode 100644 index 0000000..41e31c2 --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vls/calling-convention-1.c @@ -0,0 +1,154 @@ +/* { dg-do compile } */ +/* { dg-options "-march=rv64gcv_zvl4096b --param riscv-autovec-preference=scalable -mabi=lp64d -O3" } */ + +#include "def.h" + +DEF_RET1_ARG0 (v1qi) +DEF_RET1_ARG0 (v2qi) +DEF_RET1_ARG0 (v4qi) +DEF_RET1_ARG0 (v8qi) +DEF_RET1_ARG0 (v16qi) +DEF_RET1_ARG0 (v32qi) +DEF_RET1_ARG0 (v64qi) +DEF_RET1_ARG0 (v128qi) +DEF_RET1_ARG0 (v256qi) +DEF_RET1_ARG0 (v512qi) +DEF_RET1_ARG0 (v1024qi) +DEF_RET1_ARG0 (v2048qi) +DEF_RET1_ARG0 (v4096qi) + +DEF_RET1_ARG1 (v1qi) +DEF_RET1_ARG1 (v2qi) +DEF_RET1_ARG1 (v4qi) +DEF_RET1_ARG1 (v8qi) +DEF_RET1_ARG1 (v16qi) +DEF_RET1_ARG1 (v32qi) +DEF_RET1_ARG1 (v64qi) +DEF_RET1_ARG1 (v128qi) +DEF_RET1_ARG1 (v256qi) +DEF_RET1_ARG1 (v512qi) +DEF_RET1_ARG1 (v1024qi) +DEF_RET1_ARG1 (v2048qi) +DEF_RET1_ARG1 (v4096qi) + +DEF_RET1_ARG2 (v1qi) +DEF_RET1_ARG2 (v2qi) +DEF_RET1_ARG2 (v4qi) +DEF_RET1_ARG2 (v8qi) +DEF_RET1_ARG2 (v16qi) +DEF_RET1_ARG2 (v32qi) +DEF_RET1_ARG2 (v64qi) +DEF_RET1_ARG2 (v128qi) +DEF_RET1_ARG2 (v256qi) +DEF_RET1_ARG2 (v512qi) +DEF_RET1_ARG2 (v1024qi) +DEF_RET1_ARG2 (v2048qi) +DEF_RET1_ARG2 (v4096qi) + +DEF_RET1_ARG3 (v1qi) +DEF_RET1_ARG3 (v2qi) +DEF_RET1_ARG3 (v4qi) +DEF_RET1_ARG3 (v8qi) +DEF_RET1_ARG3 (v16qi) +DEF_RET1_ARG3 (v32qi) +DEF_RET1_ARG3 (v64qi) +DEF_RET1_ARG3 (v128qi) +DEF_RET1_ARG3 (v256qi) +DEF_RET1_ARG3 (v512qi) +DEF_RET1_ARG3 (v1024qi) +DEF_RET1_ARG3 (v2048qi) +DEF_RET1_ARG3 (v4096qi) + +DEF_RET1_ARG4 (v1qi) +DEF_RET1_ARG4 (v2qi) +DEF_RET1_ARG4 (v4qi) +DEF_RET1_ARG4 (v8qi) +DEF_RET1_ARG4 (v16qi) +DEF_RET1_ARG4 (v32qi) +DEF_RET1_ARG4 (v64qi) +DEF_RET1_ARG4 (v128qi) +DEF_RET1_ARG4 (v256qi) +DEF_RET1_ARG4 (v512qi) +DEF_RET1_ARG4 (v1024qi) +DEF_RET1_ARG4 (v2048qi) +DEF_RET1_ARG4 (v4096qi) + +DEF_RET1_ARG5 (v1qi) +DEF_RET1_ARG5 (v2qi) +DEF_RET1_ARG5 (v4qi) +DEF_RET1_ARG5 (v8qi) +DEF_RET1_ARG5 (v16qi) +DEF_RET1_ARG5 (v32qi) +DEF_RET1_ARG5 (v64qi) +DEF_RET1_ARG5 (v128qi) +DEF_RET1_ARG5 (v256qi) +DEF_RET1_ARG5 (v512qi) +DEF_RET1_ARG5 (v1024qi) +DEF_RET1_ARG5 (v2048qi) +DEF_RET1_ARG5 (v4096qi) + +DEF_RET1_ARG6 (v1qi) +DEF_RET1_ARG6 (v2qi) +DEF_RET1_ARG6 (v4qi) +DEF_RET1_ARG6 (v8qi) +DEF_RET1_ARG6 (v16qi) +DEF_RET1_ARG6 (v32qi) +DEF_RET1_ARG6 (v64qi) +DEF_RET1_ARG6 (v128qi) +DEF_RET1_ARG6 (v256qi) +DEF_RET1_ARG6 (v512qi) +DEF_RET1_ARG6 (v1024qi) +DEF_RET1_ARG6 (v2048qi) +DEF_RET1_ARG6 (v4096qi) + +DEF_RET1_ARG7 (v1qi) +DEF_RET1_ARG7 (v2qi) +DEF_RET1_ARG7 (v4qi) +DEF_RET1_ARG7 (v8qi) +DEF_RET1_ARG7 (v16qi) +DEF_RET1_ARG7 (v32qi) +DEF_RET1_ARG7 (v64qi) +DEF_RET1_ARG7 (v128qi) +DEF_RET1_ARG7 (v256qi) +DEF_RET1_ARG7 (v512qi) +DEF_RET1_ARG7 (v1024qi) +DEF_RET1_ARG7 (v2048qi) +DEF_RET1_ARG7 (v4096qi) + +DEF_RET1_ARG8 (v1qi) +DEF_RET1_ARG8 (v2qi) +DEF_RET1_ARG8 (v4qi) +DEF_RET1_ARG8 (v8qi) +DEF_RET1_ARG8 (v16qi) +DEF_RET1_ARG8 (v32qi) +DEF_RET1_ARG8 (v64qi) +DEF_RET1_ARG8 (v128qi) +DEF_RET1_ARG8 (v256qi) +DEF_RET1_ARG8 (v512qi) +DEF_RET1_ARG8 (v1024qi) +DEF_RET1_ARG8 (v2048qi) +DEF_RET1_ARG8 (v4096qi) + +DEF_RET1_ARG9 (v1qi) +DEF_RET1_ARG9 (v2qi) +DEF_RET1_ARG9 (v4qi) +DEF_RET1_ARG9 (v8qi) +DEF_RET1_ARG9 (v16qi) +DEF_RET1_ARG9 (v32qi) +DEF_RET1_ARG9 (v64qi) +DEF_RET1_ARG9 (v128qi) +DEF_RET1_ARG9 (v256qi) +DEF_RET1_ARG9 (v512qi) +DEF_RET1_ARG9 (v1024qi) +DEF_RET1_ARG9 (v2048qi) +DEF_RET1_ARG9 (v4096qi) + +/* { dg-final { scan-assembler-times {li\s+a[0-1],\s*0} 9 } } */ +/* { dg-final { scan-assembler-times {lbu\s+a0,\s*[0-9]+\(sp\)} 8 } } */ +/* { dg-final { scan-assembler-times {lhu\s+a0,\s*[0-9]+\(sp\)} 8 } } */ +/* { dg-final { scan-assembler-times {lw\s+a0,\s*[0-9]+\(sp\)} 8 } } */ +/* { dg-final { scan-assembler-times {ld\s+a[0-1],\s*[0-9]+\(sp\)} 35 } } */ +/* { dg-final { scan-assembler-times {sb\s+a[0-7],\s*[0-9]+\(sp\)} 43 } } */ +/* { dg-final { scan-assembler-times {sh\s+a[0-7],\s*[0-9]+\(sp\)} 43 } } */ +/* { dg-final { scan-assembler-times {sw\s+a[0-7],\s*[0-9]+\(sp\)} 43 } } */ +/* { dg-final { scan-assembler-times {sd\s+a[0-7],\s*[0-9]+\(sp\)} 103 } } */ diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/vls/calling-convention-10.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vls/calling-convention-10.c new file mode 100644 index 0000000..0abc6cf --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vls/calling-convention-10.c @@ -0,0 +1,51 @@ +/* { dg-do compile } */ +/* { dg-options "-march=rv64gcv_zvfh_zvl4096b -mabi=lp64 --param riscv-autovec-preference=scalable -O3 -fno-schedule-insns -fno-schedule-insns2" } */ +/* { dg-final { check-function-bodies "**" "" } } */ + +#include "def.h" + +/* +** v4hf_RET1_ARG1: +** ret +*/ +DEF_RET1_ARG1 (v4hf) + +/* +** v2sf_RET1_ARG2: +** addi\s+sp,\s*sp,\s*-16 +** sd\s+a0,\s*0\(sp\) +** sd\s+a1,\s*8\(sp\) +** ... +** ld\s+a0,\s*0\(sp\) +** addi\s+sp,\s*sp,\s*16 +** jr\s+ra +*/ +DEF_RET1_ARG2 (v2sf) + +/* +** v4sf_RET1_ARG2: +** addi\s+sp,\s*sp,\s*-32 +** sd\s+a0,\s*0\(sp\) +** sd\s+a1,\s*8\(sp\) +** sd\s+a2,\s*16\(sp\) +** sd\s+a3,\s*24\(sp\) +** ... +** ld\s+a0,\s*0\(sp\) +** ld\s+a1,\s*8\(sp\) +** addi\s+sp,\s*sp,\s*32 +** jr\s+ra +*/ +DEF_RET1_ARG2 (v4sf) + +/* +** v1df_RET1_ARG3: +** addi\s+sp,\s*sp,\s*-32 +** sd\s+a0,\s*8\(sp\) +** sd\s+a1,\s*16\(sp\) +** sd\s+a2,\s*24\(sp\) +** ... +** ld\s+a0,\s*8\(sp\) +** addi\s+sp,\s*sp,\s*32 +** jr\s+ra +*/ +DEF_RET1_ARG3 (v1df) diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/vls/calling-convention-2.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vls/calling-convention-2.c new file mode 100644 index 0000000..8544f16 --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vls/calling-convention-2.c @@ -0,0 +1,142 @@ +/* { dg-do compile } */ +/* { dg-options "-march=rv64gcv_zvl4096b --param riscv-autovec-preference=scalable -mabi=lp64d -O3" } */ + +#include "def.h" + +DEF_RET1_ARG0 (v1hi) +DEF_RET1_ARG0 (v2hi) +DEF_RET1_ARG0 (v4hi) +DEF_RET1_ARG0 (v8hi) +DEF_RET1_ARG0 (v16hi) +DEF_RET1_ARG0 (v32hi) +DEF_RET1_ARG0 (v64hi) +DEF_RET1_ARG0 (v128hi) +DEF_RET1_ARG0 (v256hi) +DEF_RET1_ARG0 (v512hi) +DEF_RET1_ARG0 (v1024hi) +DEF_RET1_ARG0 (v2048hi) + +DEF_RET1_ARG1 (v1hi) +DEF_RET1_ARG1 (v2hi) +DEF_RET1_ARG1 (v4hi) +DEF_RET1_ARG1 (v8hi) +DEF_RET1_ARG1 (v16hi) +DEF_RET1_ARG1 (v32hi) +DEF_RET1_ARG1 (v64hi) +DEF_RET1_ARG1 (v128hi) +DEF_RET1_ARG1 (v256hi) +DEF_RET1_ARG1 (v512hi) +DEF_RET1_ARG1 (v1024hi) +DEF_RET1_ARG1 (v2048hi) + +DEF_RET1_ARG2 (v1hi) +DEF_RET1_ARG2 (v2hi) +DEF_RET1_ARG2 (v4hi) +DEF_RET1_ARG2 (v8hi) +DEF_RET1_ARG2 (v16hi) +DEF_RET1_ARG2 (v32hi) +DEF_RET1_ARG2 (v64hi) +DEF_RET1_ARG2 (v128hi) +DEF_RET1_ARG2 (v256hi) +DEF_RET1_ARG2 (v512hi) +DEF_RET1_ARG2 (v1024hi) +DEF_RET1_ARG2 (v2048hi) + +DEF_RET1_ARG3 (v1hi) +DEF_RET1_ARG3 (v2hi) +DEF_RET1_ARG3 (v4hi) +DEF_RET1_ARG3 (v8hi) +DEF_RET1_ARG3 (v16hi) +DEF_RET1_ARG3 (v32hi) +DEF_RET1_ARG3 (v64hi) +DEF_RET1_ARG3 (v128hi) +DEF_RET1_ARG3 (v256hi) +DEF_RET1_ARG3 (v512hi) +DEF_RET1_ARG3 (v1024hi) +DEF_RET1_ARG3 (v2048hi) + +DEF_RET1_ARG4 (v1hi) +DEF_RET1_ARG4 (v2hi) +DEF_RET1_ARG4 (v4hi) +DEF_RET1_ARG4 (v8hi) +DEF_RET1_ARG4 (v16hi) +DEF_RET1_ARG4 (v32hi) +DEF_RET1_ARG4 (v64hi) +DEF_RET1_ARG4 (v128hi) +DEF_RET1_ARG4 (v256hi) +DEF_RET1_ARG4 (v512hi) +DEF_RET1_ARG4 (v1024hi) +DEF_RET1_ARG4 (v2048hi) + +DEF_RET1_ARG5 (v1hi) +DEF_RET1_ARG5 (v2hi) +DEF_RET1_ARG5 (v4hi) +DEF_RET1_ARG5 (v8hi) +DEF_RET1_ARG5 (v16hi) +DEF_RET1_ARG5 (v32hi) +DEF_RET1_ARG5 (v64hi) +DEF_RET1_ARG5 (v128hi) +DEF_RET1_ARG5 (v256hi) +DEF_RET1_ARG5 (v512hi) +DEF_RET1_ARG5 (v1024hi) +DEF_RET1_ARG5 (v2048hi) + +DEF_RET1_ARG6 (v1hi) +DEF_RET1_ARG6 (v2hi) +DEF_RET1_ARG6 (v4hi) +DEF_RET1_ARG6 (v8hi) +DEF_RET1_ARG6 (v16hi) +DEF_RET1_ARG6 (v32hi) +DEF_RET1_ARG6 (v64hi) +DEF_RET1_ARG6 (v128hi) +DEF_RET1_ARG6 (v256hi) +DEF_RET1_ARG6 (v512hi) +DEF_RET1_ARG6 (v1024hi) +DEF_RET1_ARG6 (v2048hi) + +DEF_RET1_ARG7 (v1hi) +DEF_RET1_ARG7 (v2hi) +DEF_RET1_ARG7 (v4hi) +DEF_RET1_ARG7 (v8hi) +DEF_RET1_ARG7 (v16hi) +DEF_RET1_ARG7 (v32hi) +DEF_RET1_ARG7 (v64hi) +DEF_RET1_ARG7 (v128hi) +DEF_RET1_ARG7 (v256hi) +DEF_RET1_ARG7 (v512hi) +DEF_RET1_ARG7 (v1024hi) +DEF_RET1_ARG7 (v2048hi) + +DEF_RET1_ARG8 (v1hi) +DEF_RET1_ARG8 (v2hi) +DEF_RET1_ARG8 (v4hi) +DEF_RET1_ARG8 (v8hi) +DEF_RET1_ARG8 (v16hi) +DEF_RET1_ARG8 (v32hi) +DEF_RET1_ARG8 (v64hi) +DEF_RET1_ARG8 (v128hi) +DEF_RET1_ARG8 (v256hi) +DEF_RET1_ARG8 (v512hi) +DEF_RET1_ARG8 (v1024hi) +DEF_RET1_ARG8 (v2048hi) + +DEF_RET1_ARG9 (v1hi) +DEF_RET1_ARG9 (v2hi) +DEF_RET1_ARG9 (v4hi) +DEF_RET1_ARG9 (v8hi) +DEF_RET1_ARG9 (v16hi) +DEF_RET1_ARG9 (v32hi) +DEF_RET1_ARG9 (v64hi) +DEF_RET1_ARG9 (v128hi) +DEF_RET1_ARG9 (v256hi) +DEF_RET1_ARG9 (v512hi) +DEF_RET1_ARG9 (v1024hi) +DEF_RET1_ARG9 (v2048hi) + +/* { dg-final { scan-assembler-times {li\s+a[0-1],\s*0} 8 } } */ +/* { dg-final { scan-assembler-times {lhu\s+a0,\s*[0-9]+\(sp\)} 8 } } */ +/* { dg-final { scan-assembler-times {lw\s+a0,\s*[0-9]+\(sp\)} 8 } } */ +/* { dg-final { scan-assembler-times {ld\s+a[0-1],\s*[0-9]+\(sp\)} 33 } } */ +/* { dg-final { scan-assembler-times {sh\s+a[0-7],\s*[0-9]+\(sp\)} 43 } } */ +/* { dg-final { scan-assembler-times {sw\s+a[0-7],\s*[0-9]+\(sp\)} 43 } } */ +/* { dg-final { scan-assembler-times {sd\s+a[0-7],\s*[0-9]+\(sp\)} 103 } } */ diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/vls/calling-convention-3.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vls/calling-convention-3.c new file mode 100644 index 0000000..17b0693 --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vls/calling-convention-3.c @@ -0,0 +1,130 @@ +/* { dg-do compile } */ +/* { dg-options "-march=rv64gcv_zvl4096b --param riscv-autovec-preference=scalable -mabi=lp64d -O3" } */ + +#include "def.h" + +DEF_RET1_ARG0 (v1si) +DEF_RET1_ARG0 (v2si) +DEF_RET1_ARG0 (v4si) +DEF_RET1_ARG0 (v8si) +DEF_RET1_ARG0 (v16si) +DEF_RET1_ARG0 (v32si) +DEF_RET1_ARG0 (v64si) +DEF_RET1_ARG0 (v128si) +DEF_RET1_ARG0 (v256si) +DEF_RET1_ARG0 (v512si) +DEF_RET1_ARG0 (v1024si) + +DEF_RET1_ARG1 (v1si) +DEF_RET1_ARG1 (v2si) +DEF_RET1_ARG1 (v4si) +DEF_RET1_ARG1 (v8si) +DEF_RET1_ARG1 (v16si) +DEF_RET1_ARG1 (v32si) +DEF_RET1_ARG1 (v64si) +DEF_RET1_ARG1 (v128si) +DEF_RET1_ARG1 (v256si) +DEF_RET1_ARG1 (v512si) +DEF_RET1_ARG1 (v1024si) + +DEF_RET1_ARG2 (v1si) +DEF_RET1_ARG2 (v2si) +DEF_RET1_ARG2 (v4si) +DEF_RET1_ARG2 (v8si) +DEF_RET1_ARG2 (v16si) +DEF_RET1_ARG2 (v32si) +DEF_RET1_ARG2 (v64si) +DEF_RET1_ARG2 (v128si) +DEF_RET1_ARG2 (v256si) +DEF_RET1_ARG2 (v512si) +DEF_RET1_ARG2 (v1024si) + +DEF_RET1_ARG3 (v1si) +DEF_RET1_ARG3 (v2si) +DEF_RET1_ARG3 (v4si) +DEF_RET1_ARG3 (v8si) +DEF_RET1_ARG3 (v16si) +DEF_RET1_ARG3 (v32si) +DEF_RET1_ARG3 (v64si) +DEF_RET1_ARG3 (v128si) +DEF_RET1_ARG3 (v256si) +DEF_RET1_ARG3 (v512si) +DEF_RET1_ARG3 (v1024si) + +DEF_RET1_ARG4 (v1si) +DEF_RET1_ARG4 (v2si) +DEF_RET1_ARG4 (v4si) +DEF_RET1_ARG4 (v8si) +DEF_RET1_ARG4 (v16si) +DEF_RET1_ARG4 (v32si) +DEF_RET1_ARG4 (v64si) +DEF_RET1_ARG4 (v128si) +DEF_RET1_ARG4 (v256si) +DEF_RET1_ARG4 (v512si) +DEF_RET1_ARG4 (v1024si) + +DEF_RET1_ARG5 (v1si) +DEF_RET1_ARG5 (v2si) +DEF_RET1_ARG5 (v4si) +DEF_RET1_ARG5 (v8si) +DEF_RET1_ARG5 (v16si) +DEF_RET1_ARG5 (v32si) +DEF_RET1_ARG5 (v64si) +DEF_RET1_ARG5 (v128si) +DEF_RET1_ARG5 (v256si) +DEF_RET1_ARG5 (v512si) +DEF_RET1_ARG5 (v1024si) + +DEF_RET1_ARG6 (v1si) +DEF_RET1_ARG6 (v2si) +DEF_RET1_ARG6 (v4si) +DEF_RET1_ARG6 (v8si) +DEF_RET1_ARG6 (v16si) +DEF_RET1_ARG6 (v32si) +DEF_RET1_ARG6 (v64si) +DEF_RET1_ARG6 (v128si) +DEF_RET1_ARG6 (v256si) +DEF_RET1_ARG6 (v512si) +DEF_RET1_ARG6 (v1024si) + +DEF_RET1_ARG7 (v1si) +DEF_RET1_ARG7 (v2si) +DEF_RET1_ARG7 (v4si) +DEF_RET1_ARG7 (v8si) +DEF_RET1_ARG7 (v16si) +DEF_RET1_ARG7 (v32si) +DEF_RET1_ARG7 (v64si) +DEF_RET1_ARG7 (v128si) +DEF_RET1_ARG7 (v256si) +DEF_RET1_ARG7 (v512si) +DEF_RET1_ARG7 (v1024si) + +DEF_RET1_ARG8 (v1si) +DEF_RET1_ARG8 (v2si) +DEF_RET1_ARG8 (v4si) +DEF_RET1_ARG8 (v8si) +DEF_RET1_ARG8 (v16si) +DEF_RET1_ARG8 (v32si) +DEF_RET1_ARG8 (v64si) +DEF_RET1_ARG8 (v128si) +DEF_RET1_ARG8 (v256si) +DEF_RET1_ARG8 (v512si) +DEF_RET1_ARG8 (v1024si) + +DEF_RET1_ARG9 (v1si) +DEF_RET1_ARG9 (v2si) +DEF_RET1_ARG9 (v4si) +DEF_RET1_ARG9 (v8si) +DEF_RET1_ARG9 (v16si) +DEF_RET1_ARG9 (v32si) +DEF_RET1_ARG9 (v64si) +DEF_RET1_ARG9 (v128si) +DEF_RET1_ARG9 (v256si) +DEF_RET1_ARG9 (v512si) +DEF_RET1_ARG9 (v1024si) + +/* { dg-final { scan-assembler-times {li\s+a[0-1],\s*0} 7 } } */ +/* { dg-final { scan-assembler-times {lw\s+a0,\s*[0-9]+\(sp\)} 8 } } */ +/* { dg-final { scan-assembler-times {ld\s+a[0-1],\s*[0-9]+\(sp\)} 31 } } */ +/* { dg-final { scan-assembler-times {sw\s+a[0-7],\s*[0-9]+\(sp\)} 43 } } */ +/* { dg-final { scan-assembler-times {sd\s+a[0-7],\s*[0-9]+\(sp\)} 103 } } */ diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/vls/calling-convention-4.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vls/calling-convention-4.c new file mode 100644 index 0000000..8c3f6ba --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vls/calling-convention-4.c @@ -0,0 +1,118 @@ +/* { dg-do compile } */ +/* { dg-options "-march=rv64gcv_zvl4096b --param riscv-autovec-preference=scalable -mabi=lp64d -O3" } */ + +#include "def.h" + +DEF_RET1_ARG0 (v1di) +DEF_RET1_ARG0 (v2di) +DEF_RET1_ARG0 (v4di) +DEF_RET1_ARG0 (v8di) +DEF_RET1_ARG0 (v16di) +DEF_RET1_ARG0 (v32di) +DEF_RET1_ARG0 (v64di) +DEF_RET1_ARG0 (v128di) +DEF_RET1_ARG0 (v256di) +DEF_RET1_ARG0 (v512di) + +DEF_RET1_ARG1 (v1di) +DEF_RET1_ARG1 (v2di) +DEF_RET1_ARG1 (v4di) +DEF_RET1_ARG1 (v8di) +DEF_RET1_ARG1 (v16di) +DEF_RET1_ARG1 (v32di) +DEF_RET1_ARG1 (v64di) +DEF_RET1_ARG1 (v128di) +DEF_RET1_ARG1 (v256di) +DEF_RET1_ARG1 (v512di) + +DEF_RET1_ARG2 (v1di) +DEF_RET1_ARG2 (v2di) +DEF_RET1_ARG2 (v4di) +DEF_RET1_ARG2 (v8di) +DEF_RET1_ARG2 (v16di) +DEF_RET1_ARG2 (v32di) +DEF_RET1_ARG2 (v64di) +DEF_RET1_ARG2 (v128di) +DEF_RET1_ARG2 (v256di) +DEF_RET1_ARG2 (v512di) + +DEF_RET1_ARG3 (v1di) +DEF_RET1_ARG3 (v2di) +DEF_RET1_ARG3 (v4di) +DEF_RET1_ARG3 (v8di) +DEF_RET1_ARG3 (v16di) +DEF_RET1_ARG3 (v32di) +DEF_RET1_ARG3 (v64di) +DEF_RET1_ARG3 (v128di) +DEF_RET1_ARG3 (v256di) +DEF_RET1_ARG3 (v512di) + +DEF_RET1_ARG4 (v1di) +DEF_RET1_ARG4 (v2di) +DEF_RET1_ARG4 (v4di) +DEF_RET1_ARG4 (v8di) +DEF_RET1_ARG4 (v16di) +DEF_RET1_ARG4 (v32di) +DEF_RET1_ARG4 (v64di) +DEF_RET1_ARG4 (v128di) +DEF_RET1_ARG4 (v256di) +DEF_RET1_ARG4 (v512di) + +DEF_RET1_ARG5 (v1di) +DEF_RET1_ARG5 (v2di) +DEF_RET1_ARG5 (v4di) +DEF_RET1_ARG5 (v8di) +DEF_RET1_ARG5 (v16di) +DEF_RET1_ARG5 (v32di) +DEF_RET1_ARG5 (v64di) +DEF_RET1_ARG5 (v128di) +DEF_RET1_ARG5 (v256di) +DEF_RET1_ARG5 (v512di) + +DEF_RET1_ARG6 (v1di) +DEF_RET1_ARG6 (v2di) +DEF_RET1_ARG6 (v4di) +DEF_RET1_ARG6 (v8di) +DEF_RET1_ARG6 (v16di) +DEF_RET1_ARG6 (v32di) +DEF_RET1_ARG6 (v64di) +DEF_RET1_ARG6 (v128di) +DEF_RET1_ARG6 (v256di) +DEF_RET1_ARG6 (v512di) + +DEF_RET1_ARG7 (v1di) +DEF_RET1_ARG7 (v2di) +DEF_RET1_ARG7 (v4di) +DEF_RET1_ARG7 (v8di) +DEF_RET1_ARG7 (v16di) +DEF_RET1_ARG7 (v32di) +DEF_RET1_ARG7 (v64di) +DEF_RET1_ARG7 (v128di) +DEF_RET1_ARG7 (v256di) +DEF_RET1_ARG7 (v512di) + +DEF_RET1_ARG8 (v1di) +DEF_RET1_ARG8 (v2di) +DEF_RET1_ARG8 (v4di) +DEF_RET1_ARG8 (v8di) +DEF_RET1_ARG8 (v16di) +DEF_RET1_ARG8 (v32di) +DEF_RET1_ARG8 (v64di) +DEF_RET1_ARG8 (v128di) +DEF_RET1_ARG8 (v256di) +DEF_RET1_ARG8 (v512di) + +DEF_RET1_ARG9 (v1di) +DEF_RET1_ARG9 (v2di) +DEF_RET1_ARG9 (v4di) +DEF_RET1_ARG9 (v8di) +DEF_RET1_ARG9 (v16di) +DEF_RET1_ARG9 (v32di) +DEF_RET1_ARG9 (v64di) +DEF_RET1_ARG9 (v128di) +DEF_RET1_ARG9 (v256di) +DEF_RET1_ARG9 (v512di) + +/* { dg-final { scan-assembler-times {li\s+a[0-1],\s*0} 6 } } */ +/* { dg-final { scan-assembler-times {ld\s+a[0-1],\s*[0-9]+\(sp\)} 29 } } */ +/* { dg-final { scan-assembler-times {sd\s+a[0-7],\s*[0-9]+\(sp\)} 103 } } */ diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/vls/calling-convention-5.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vls/calling-convention-5.c new file mode 100644 index 0000000..a0208d8 --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vls/calling-convention-5.c @@ -0,0 +1,141 @@ +/* { dg-do compile } */ +/* { dg-options "-march=rv64gcv_zvfh_zvl4096b --param riscv-autovec-preference=scalable -mabi=lp64d -O3" } */ + +#include "def.h" + +DEF_RET1_ARG0 (v1hf) +DEF_RET1_ARG0 (v2hf) +DEF_RET1_ARG0 (v4hf) +DEF_RET1_ARG0 (v8hf) +DEF_RET1_ARG0 (v16hf) +DEF_RET1_ARG0 (v32hf) +DEF_RET1_ARG0 (v64hf) +DEF_RET1_ARG0 (v128hf) +DEF_RET1_ARG0 (v256hf) +DEF_RET1_ARG0 (v512hf) +DEF_RET1_ARG0 (v1024hf) +DEF_RET1_ARG0 (v2048hf) + +DEF_RET1_ARG1 (v1hf) +DEF_RET1_ARG1 (v2hf) +DEF_RET1_ARG1 (v4hf) +DEF_RET1_ARG1 (v8hf) +DEF_RET1_ARG1 (v16hf) +DEF_RET1_ARG1 (v32hf) +DEF_RET1_ARG1 (v64hf) +DEF_RET1_ARG1 (v128hf) +DEF_RET1_ARG1 (v256hf) +DEF_RET1_ARG1 (v512hf) +DEF_RET1_ARG1 (v1024hf) +DEF_RET1_ARG1 (v2048hf) + +DEF_RET1_ARG2 (v1hf) +DEF_RET1_ARG2 (v2hf) +DEF_RET1_ARG2 (v4hf) +DEF_RET1_ARG2 (v8hf) +DEF_RET1_ARG2 (v16hf) +DEF_RET1_ARG2 (v32hf) +DEF_RET1_ARG2 (v64hf) +DEF_RET1_ARG2 (v128hf) +DEF_RET1_ARG2 (v256hf) +DEF_RET1_ARG2 (v512hf) +DEF_RET1_ARG2 (v1024hf) +DEF_RET1_ARG2 (v2048hf) + +DEF_RET1_ARG3 (v1hf) +DEF_RET1_ARG3 (v2hf) +DEF_RET1_ARG3 (v4hf) +DEF_RET1_ARG3 (v8hf) +DEF_RET1_ARG3 (v16hf) +DEF_RET1_ARG3 (v32hf) +DEF_RET1_ARG3 (v64hf) +DEF_RET1_ARG3 (v128hf) +DEF_RET1_ARG3 (v256hf) +DEF_RET1_ARG3 (v512hf) +DEF_RET1_ARG3 (v1024hf) +DEF_RET1_ARG3 (v2048hf) + +DEF_RET1_ARG4 (v1hf) +DEF_RET1_ARG4 (v2hf) +DEF_RET1_ARG4 (v4hf) +DEF_RET1_ARG4 (v8hf) +DEF_RET1_ARG4 (v16hf) +DEF_RET1_ARG4 (v32hf) +DEF_RET1_ARG4 (v64hf) +DEF_RET1_ARG4 (v128hf) +DEF_RET1_ARG4 (v256hf) +DEF_RET1_ARG4 (v512hf) +DEF_RET1_ARG4 (v1024hf) +DEF_RET1_ARG4 (v2048hf) + +DEF_RET1_ARG5 (v1hf) +DEF_RET1_ARG5 (v2hf) +DEF_RET1_ARG5 (v4hf) +DEF_RET1_ARG5 (v8hf) +DEF_RET1_ARG5 (v16hf) +DEF_RET1_ARG5 (v32hf) +DEF_RET1_ARG5 (v64hf) +DEF_RET1_ARG5 (v128hf) +DEF_RET1_ARG5 (v256hf) +DEF_RET1_ARG5 (v512hf) +DEF_RET1_ARG5 (v1024hf) +DEF_RET1_ARG5 (v2048hf) + +DEF_RET1_ARG6 (v1hf) +DEF_RET1_ARG6 (v2hf) +DEF_RET1_ARG6 (v4hf) +DEF_RET1_ARG6 (v8hf) +DEF_RET1_ARG6 (v16hf) +DEF_RET1_ARG6 (v32hf) +DEF_RET1_ARG6 (v64hf) +DEF_RET1_ARG6 (v128hf) +DEF_RET1_ARG6 (v256hf) +DEF_RET1_ARG6 (v512hf) +DEF_RET1_ARG6 (v1024hf) +DEF_RET1_ARG6 (v2048hf) + +DEF_RET1_ARG7 (v1hf) +DEF_RET1_ARG7 (v2hf) +DEF_RET1_ARG7 (v4hf) +DEF_RET1_ARG7 (v8hf) +DEF_RET1_ARG7 (v16hf) +DEF_RET1_ARG7 (v32hf) +DEF_RET1_ARG7 (v64hf) +DEF_RET1_ARG7 (v128hf) +DEF_RET1_ARG7 (v256hf) +DEF_RET1_ARG7 (v512hf) +DEF_RET1_ARG7 (v1024hf) +DEF_RET1_ARG7 (v2048hf) + +DEF_RET1_ARG8 (v1hf) +DEF_RET1_ARG8 (v2hf) +DEF_RET1_ARG8 (v4hf) +DEF_RET1_ARG8 (v8hf) +DEF_RET1_ARG8 (v16hf) +DEF_RET1_ARG8 (v32hf) +DEF_RET1_ARG8 (v64hf) +DEF_RET1_ARG8 (v128hf) +DEF_RET1_ARG8 (v256hf) +DEF_RET1_ARG8 (v512hf) +DEF_RET1_ARG8 (v1024hf) +DEF_RET1_ARG8 (v2048hf) + +DEF_RET1_ARG9 (v1hf) +DEF_RET1_ARG9 (v2hf) +DEF_RET1_ARG9 (v4hf) +DEF_RET1_ARG9 (v8hf) +DEF_RET1_ARG9 (v16hf) +DEF_RET1_ARG9 (v32hf) +DEF_RET1_ARG9 (v64hf) +DEF_RET1_ARG9 (v128hf) +DEF_RET1_ARG9 (v256hf) +DEF_RET1_ARG9 (v512hf) +DEF_RET1_ARG9 (v1024hf) +DEF_RET1_ARG9 (v2048hf) + +/* { dg-final { scan-assembler-times {li\s+a[0-1],\s*0} 8 } } */ +/* { dg-final { scan-assembler-times {lhu\s+a[0-1],\s*[0-9]+\(sp\)} 8 } } */ +/* { dg-final { scan-assembler-times {lw\s+a[0-1],\s*[0-9]+\(sp\)} 8 } } */ +/* { dg-final { scan-assembler-times {sh\s+a[0-7],\s*[0-9]+\(sp\)} 43 } } */ +/* { dg-final { scan-assembler-times {sw\s+a[0-7],\s*[0-9]+\(sp\)} 43 } } */ +/* { dg-final { scan-assembler-times {sd\s+a[0-7],\s*[0-9]+\(sp\)} 103 } } */ diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/vls/calling-convention-6.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vls/calling-convention-6.c new file mode 100644 index 0000000..58ef8bf --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vls/calling-convention-6.c @@ -0,0 +1,129 @@ +/* { dg-do compile } */ +/* { dg-options "-march=rv64gcv_zvl4096b --param riscv-autovec-preference=scalable -mabi=lp64d -O3" } */ + +#include "def.h" + +DEF_RET1_ARG0 (v1sf) +DEF_RET1_ARG0 (v2sf) +DEF_RET1_ARG0 (v4sf) +DEF_RET1_ARG0 (v8sf) +DEF_RET1_ARG0 (v16sf) +DEF_RET1_ARG0 (v32sf) +DEF_RET1_ARG0 (v64sf) +DEF_RET1_ARG0 (v128sf) +DEF_RET1_ARG0 (v256sf) +DEF_RET1_ARG0 (v512sf) +DEF_RET1_ARG0 (v1024sf) + +DEF_RET1_ARG1 (v1sf) +DEF_RET1_ARG1 (v2sf) +DEF_RET1_ARG1 (v4sf) +DEF_RET1_ARG1 (v8sf) +DEF_RET1_ARG1 (v16sf) +DEF_RET1_ARG1 (v32sf) +DEF_RET1_ARG1 (v64sf) +DEF_RET1_ARG1 (v128sf) +DEF_RET1_ARG1 (v256sf) +DEF_RET1_ARG1 (v512sf) +DEF_RET1_ARG1 (v1024sf) + +DEF_RET1_ARG2 (v1sf) +DEF_RET1_ARG2 (v2sf) +DEF_RET1_ARG2 (v4sf) +DEF_RET1_ARG2 (v8sf) +DEF_RET1_ARG2 (v16sf) +DEF_RET1_ARG2 (v32sf) +DEF_RET1_ARG2 (v64sf) +DEF_RET1_ARG2 (v128sf) +DEF_RET1_ARG2 (v256sf) +DEF_RET1_ARG2 (v512sf) +DEF_RET1_ARG2 (v1024sf) + +DEF_RET1_ARG3 (v1sf) +DEF_RET1_ARG3 (v2sf) +DEF_RET1_ARG3 (v4sf) +DEF_RET1_ARG3 (v8sf) +DEF_RET1_ARG3 (v16sf) +DEF_RET1_ARG3 (v32sf) +DEF_RET1_ARG3 (v64sf) +DEF_RET1_ARG3 (v128sf) +DEF_RET1_ARG3 (v256sf) +DEF_RET1_ARG3 (v512sf) +DEF_RET1_ARG3 (v1024sf) + +DEF_RET1_ARG4 (v1sf) +DEF_RET1_ARG4 (v2sf) +DEF_RET1_ARG4 (v4sf) +DEF_RET1_ARG4 (v8sf) +DEF_RET1_ARG4 (v16sf) +DEF_RET1_ARG4 (v32sf) +DEF_RET1_ARG4 (v64sf) +DEF_RET1_ARG4 (v128sf) +DEF_RET1_ARG4 (v256sf) +DEF_RET1_ARG4 (v512sf) +DEF_RET1_ARG4 (v1024sf) + +DEF_RET1_ARG5 (v1sf) +DEF_RET1_ARG5 (v2sf) +DEF_RET1_ARG5 (v4sf) +DEF_RET1_ARG5 (v8sf) +DEF_RET1_ARG5 (v16sf) +DEF_RET1_ARG5 (v32sf) +DEF_RET1_ARG5 (v64sf) +DEF_RET1_ARG5 (v128sf) +DEF_RET1_ARG5 (v256sf) +DEF_RET1_ARG5 (v512sf) +DEF_RET1_ARG5 (v1024sf) + +DEF_RET1_ARG6 (v1sf) +DEF_RET1_ARG6 (v2sf) +DEF_RET1_ARG6 (v4sf) +DEF_RET1_ARG6 (v8sf) +DEF_RET1_ARG6 (v16sf) +DEF_RET1_ARG6 (v32sf) +DEF_RET1_ARG6 (v64sf) +DEF_RET1_ARG6 (v128sf) +DEF_RET1_ARG6 (v256sf) +DEF_RET1_ARG6 (v512sf) +DEF_RET1_ARG6 (v1024sf) + +DEF_RET1_ARG7 (v1sf) +DEF_RET1_ARG7 (v2sf) +DEF_RET1_ARG7 (v4sf) +DEF_RET1_ARG7 (v8sf) +DEF_RET1_ARG7 (v16sf) +DEF_RET1_ARG7 (v32sf) +DEF_RET1_ARG7 (v64sf) +DEF_RET1_ARG7 (v128sf) +DEF_RET1_ARG7 (v256sf) +DEF_RET1_ARG7 (v512sf) +DEF_RET1_ARG7 (v1024sf) + +DEF_RET1_ARG8 (v1sf) +DEF_RET1_ARG8 (v2sf) +DEF_RET1_ARG8 (v4sf) +DEF_RET1_ARG8 (v8sf) +DEF_RET1_ARG8 (v16sf) +DEF_RET1_ARG8 (v32sf) +DEF_RET1_ARG8 (v64sf) +DEF_RET1_ARG8 (v128sf) +DEF_RET1_ARG8 (v256sf) +DEF_RET1_ARG8 (v512sf) +DEF_RET1_ARG8 (v1024sf) + +DEF_RET1_ARG9 (v1sf) +DEF_RET1_ARG9 (v2sf) +DEF_RET1_ARG9 (v4sf) +DEF_RET1_ARG9 (v8sf) +DEF_RET1_ARG9 (v16sf) +DEF_RET1_ARG9 (v32sf) +DEF_RET1_ARG9 (v64sf) +DEF_RET1_ARG9 (v128sf) +DEF_RET1_ARG9 (v256sf) +DEF_RET1_ARG9 (v512sf) +DEF_RET1_ARG9 (v1024sf) + +/* { dg-final { scan-assembler-times {li\s+a[0-1],\s*0} 7 } } */ +/* { dg-final { scan-assembler-times {lw\s+a[0-1],\s*[0-9]+\(sp\)} 8 } } */ +/* { dg-final { scan-assembler-times {sw\s+a[0-7],\s*[0-9]+\(sp\)} 43 } } */ +/* { dg-final { scan-assembler-times {sd\s+a[0-7],\s*[0-9]+\(sp\)} 103 } } */ diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/vls/calling-convention-7.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vls/calling-convention-7.c new file mode 100644 index 0000000..e35ccd5 --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vls/calling-convention-7.c @@ -0,0 +1,118 @@ +/* { dg-do compile } */ +/* { dg-options "-march=rv64gcv_zvl4096b --param riscv-autovec-preference=scalable -mabi=lp64d -O3" } */ + +#include "def.h" + +DEF_RET1_ARG0 (v1df) +DEF_RET1_ARG0 (v2df) +DEF_RET1_ARG0 (v4df) +DEF_RET1_ARG0 (v8df) +DEF_RET1_ARG0 (v16df) +DEF_RET1_ARG0 (v32df) +DEF_RET1_ARG0 (v64df) +DEF_RET1_ARG0 (v128df) +DEF_RET1_ARG0 (v256df) +DEF_RET1_ARG0 (v512df) + +DEF_RET1_ARG1 (v1df) +DEF_RET1_ARG1 (v2df) +DEF_RET1_ARG1 (v4df) +DEF_RET1_ARG1 (v8df) +DEF_RET1_ARG1 (v16df) +DEF_RET1_ARG1 (v32df) +DEF_RET1_ARG1 (v64df) +DEF_RET1_ARG1 (v128df) +DEF_RET1_ARG1 (v256df) +DEF_RET1_ARG1 (v512df) + +DEF_RET1_ARG2 (v1df) +DEF_RET1_ARG2 (v2df) +DEF_RET1_ARG2 (v4df) +DEF_RET1_ARG2 (v8df) +DEF_RET1_ARG2 (v16df) +DEF_RET1_ARG2 (v32df) +DEF_RET1_ARG2 (v64df) +DEF_RET1_ARG2 (v128df) +DEF_RET1_ARG2 (v256df) +DEF_RET1_ARG2 (v512df) + +DEF_RET1_ARG3 (v1df) +DEF_RET1_ARG3 (v2df) +DEF_RET1_ARG3 (v4df) +DEF_RET1_ARG3 (v8df) +DEF_RET1_ARG3 (v16df) +DEF_RET1_ARG3 (v32df) +DEF_RET1_ARG3 (v64df) +DEF_RET1_ARG3 (v128df) +DEF_RET1_ARG3 (v256df) +DEF_RET1_ARG3 (v512df) + +DEF_RET1_ARG4 (v1df) +DEF_RET1_ARG4 (v2df) +DEF_RET1_ARG4 (v4df) +DEF_RET1_ARG4 (v8df) +DEF_RET1_ARG4 (v16df) +DEF_RET1_ARG4 (v32df) +DEF_RET1_ARG4 (v64df) +DEF_RET1_ARG4 (v128df) +DEF_RET1_ARG4 (v256df) +DEF_RET1_ARG4 (v512df) + +DEF_RET1_ARG5 (v1df) +DEF_RET1_ARG5 (v2df) +DEF_RET1_ARG5 (v4df) +DEF_RET1_ARG5 (v8df) +DEF_RET1_ARG5 (v16df) +DEF_RET1_ARG5 (v32df) +DEF_RET1_ARG5 (v64df) +DEF_RET1_ARG5 (v128df) +DEF_RET1_ARG5 (v256df) +DEF_RET1_ARG5 (v512df) + +DEF_RET1_ARG6 (v1df) +DEF_RET1_ARG6 (v2df) +DEF_RET1_ARG6 (v4df) +DEF_RET1_ARG6 (v8df) +DEF_RET1_ARG6 (v16df) +DEF_RET1_ARG6 (v32df) +DEF_RET1_ARG6 (v64df) +DEF_RET1_ARG6 (v128df) +DEF_RET1_ARG6 (v256df) +DEF_RET1_ARG6 (v512df) + +DEF_RET1_ARG7 (v1df) +DEF_RET1_ARG7 (v2df) +DEF_RET1_ARG7 (v4df) +DEF_RET1_ARG7 (v8df) +DEF_RET1_ARG7 (v16df) +DEF_RET1_ARG7 (v32df) +DEF_RET1_ARG7 (v64df) +DEF_RET1_ARG7 (v128df) +DEF_RET1_ARG7 (v256df) +DEF_RET1_ARG7 (v512df) + +DEF_RET1_ARG8 (v1df) +DEF_RET1_ARG8 (v2df) +DEF_RET1_ARG8 (v4df) +DEF_RET1_ARG8 (v8df) +DEF_RET1_ARG8 (v16df) +DEF_RET1_ARG8 (v32df) +DEF_RET1_ARG8 (v64df) +DEF_RET1_ARG8 (v128df) +DEF_RET1_ARG8 (v256df) +DEF_RET1_ARG8 (v512df) + +DEF_RET1_ARG9 (v1df) +DEF_RET1_ARG9 (v2df) +DEF_RET1_ARG9 (v4df) +DEF_RET1_ARG9 (v8df) +DEF_RET1_ARG9 (v16df) +DEF_RET1_ARG9 (v32df) +DEF_RET1_ARG9 (v64df) +DEF_RET1_ARG9 (v128df) +DEF_RET1_ARG9 (v256df) +DEF_RET1_ARG9 (v512df) + +/* { dg-final { scan-assembler-times {li\s+a[0-1],\s*0} 6 } } */ +/* { dg-final { scan-assembler-times {ld\s+a[0-1],\s*[0-9]+\(sp\)} 29 } } */ +/* { dg-final { scan-assembler-times {sd\s+a[0-7],\s*[0-9]+\(sp\)} 103 } } */ diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/vls/calling-convention-8.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vls/calling-convention-8.c new file mode 100644 index 0000000..ed66a2c --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vls/calling-convention-8.c @@ -0,0 +1,43 @@ +/* { dg-do compile } */ +/* { dg-options "-march=rv64gcv_zvl4096b -mabi=lp64d --param riscv-autovec-preference=scalable -O3 -fno-schedule-insns -fno-schedule-insns2" } */ +/* { dg-final { check-function-bodies "**" "" } } */ + +#include "def.h" + +/* +** v8qi_RET1_ARG0: +** li\s+a0,\s*0 +** ret +*/ +DEF_RET1_ARG0 (v8qi) + +/* +** v4hi_RET1_ARG1: +** ret +*/ +DEF_RET1_ARG1 (v4hi) + +/* +** v2si_RET1_ARG2: +** addi\s+sp,\s*sp,\s*-16 +** sd\s+a0,\s*0\(sp\) +** sd\s+a1,\s*8\(sp\) +** ... +** ld\s+a0,\s*0\(sp\) +** addi\s+sp,\s*sp,\s*16 +** jr\s+ra +*/ +DEF_RET1_ARG2 (v2si) + +/* +** v1di_RET1_ARG3: +** addi\s+sp,\s*sp,\s*-32 +** sd\s+a0,\s*8\(sp\) +** sd\s+a1,\s*16\(sp\) +** sd\s+a2,\s*24\(sp\) +** ... +** ld\s+a0,\s*8\(sp\) +** addi\s+sp,\s*sp,\s*32 +** jr\s+ra +*/ +DEF_RET1_ARG3 (v1di) diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/vls/calling-convention-9.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vls/calling-convention-9.c new file mode 100644 index 0000000..ab8e79c --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vls/calling-convention-9.c @@ -0,0 +1,51 @@ +/* { dg-do compile } */ +/* { dg-options "-march=rv64gcv_zvfh_zvl4096b -mabi=lp64d --param riscv-autovec-preference=scalable -O3 -fno-schedule-insns -fno-schedule-insns2" } */ +/* { dg-final { check-function-bodies "**" "" } } */ + +#include "def.h" + +/* +** v4hf_RET1_ARG1: +** ret +*/ +DEF_RET1_ARG1 (v4hf) + +/* +** v2sf_RET1_ARG2: +** addi\s+sp,\s*sp,\s*-16 +** sd\s+a0,\s*0\(sp\) +** sd\s+a1,\s*8\(sp\) +** ... +** ld\s+a0,\s*0\(sp\) +** addi\s+sp,\s*sp,\s*16 +** jr\s+ra +*/ +DEF_RET1_ARG2 (v2sf) + +/* +** v4sf_RET1_ARG2: +** addi\s+sp,\s*sp,\s*-32 +** sd\s+a0,\s*0\(sp\) +** sd\s+a1,\s*8\(sp\) +** sd\s+a2,\s*16\(sp\) +** sd\s+a3,\s*24\(sp\) +** ... +** ld\s+a0,\s*0\(sp\) +** ld\s+a1,\s*8\(sp\) +** addi\s+sp,\s*sp,\s*32 +** jr\s+ra +*/ +DEF_RET1_ARG2 (v4sf) + +/* +** v1df_RET1_ARG3: +** addi\s+sp,\s*sp,\s*-32 +** sd\s+a0,\s*8\(sp\) +** sd\s+a1,\s*16\(sp\) +** sd\s+a2,\s*24\(sp\) +** ... +** ld\s+a0,\s*8\(sp\) +** addi\s+sp,\s*sp,\s*32 +** jr\s+ra +*/ +DEF_RET1_ARG3 (v1df) diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/vls/calling-convention-run-1.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vls/calling-convention-run-1.c new file mode 100644 index 0000000..d8aa5c5 --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vls/calling-convention-run-1.c @@ -0,0 +1,55 @@ +/* { dg-do run { target { riscv_v } } } */ +/* { dg-additional-options "-std=c99 -fno-vect-cost-model --param=riscv-autovec-preference=scalable" } */ + +typedef char v16qi __attribute__ ((vector_size (16))); + +v16qi +add (v16qi a1, v16qi a2, v16qi a3, v16qi a4, v16qi a5, v16qi a6, v16qi a7, + v16qi a8, v16qi a9) +{ + return a1 + a2 + a3 + a4 + a5 + a6 + a7 + a8 + a9; +} + +int +main () +{ + v16qi a1 = { + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + }; + v16qi a2 = { + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + }; + v16qi a3 = { + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + }; + v16qi a4 = { + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + }; + v16qi a5 = { + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + }; + v16qi a6 = { + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + }; + v16qi a7 = { + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + }; + v16qi a8 = { + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + }; + v16qi a9 = { + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + }; + v16qi expected = { + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + }; + v16qi result = add (a1, a2, a3, a4, a5, a6, a7, a8, a9); + + unsigned i; + + for (i = 0; i < 16; i++) + if (result[i] != expected[i]) + __builtin_abort (); + + return 0; +} diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/vls/calling-convention-run-2.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vls/calling-convention-run-2.c new file mode 100644 index 0000000..57376a3 --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vls/calling-convention-run-2.c @@ -0,0 +1,55 @@ +/* { dg-do run { target { riscv_v } } } */ +/* { dg-additional-options "-std=c99 -fno-vect-cost-model --param=riscv-autovec-preference=scalable" } */ + +typedef short v8hi __attribute__ ((vector_size (16))); + +v8hi +add (v8hi a1, v8hi a2, v8hi a3, v8hi a4, v8hi a5, v8hi a6, v8hi a7, + v8hi a8, v8hi a9) +{ + return a1 + a2 + a3 + a4 + a5 + a6 + a7 + a8 + a9; +} + +int +main () +{ + v8hi a1 = { + 1, 1, 1, 1, 1, 1, 1, 1, + }; + v8hi a2 = { + 1, 1, 1, 1, 1, 1, 1, 1, + }; + v8hi a3 = { + 1, 1, 1, 1, 1, 1, 1, 1, + }; + v8hi a4 = { + 1, 1, 1, 1, 1, 1, 1, 1, + }; + v8hi a5 = { + 1, 1, 1, 1, 1, 1, 1, 1, + }; + v8hi a6 = { + 1, 1, 1, 1, 1, 1, 1, 1, + }; + v8hi a7 = { + 1, 1, 1, 1, 1, 1, 1, 1, + }; + v8hi a8 = { + 1, 1, 1, 1, 1, 1, 1, 1, + }; + v8hi a9 = { + 1, 1, 1, 1, 1, 1, 1, 1, + }; + v8hi expected = { + 9, 9, 9, 9, 9, 9, 9, 9, + }; + v8hi result = add (a1, a2, a3, a4, a5, a6, a7, a8, a9); + + unsigned i; + + for (i = 0; i < 8; i++) + if (result[i] != expected[i]) + __builtin_abort (); + + return 0; +} diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/vls/calling-convention-run-3.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vls/calling-convention-run-3.c new file mode 100644 index 0000000..b37cd56 --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vls/calling-convention-run-3.c @@ -0,0 +1,55 @@ +/* { dg-do run { target { riscv_v } } } */ +/* { dg-additional-options "-std=c99 -fno-vect-cost-model --param=riscv-autovec-preference=scalable" } */ + +typedef int v4si __attribute__ ((vector_size (16))); + +v4si +add (v4si a1, v4si a2, v4si a3, v4si a4, v4si a5, v4si a6, v4si a7, + v4si a8, v4si a9) +{ + return a1 + a2 + a3 + a4 + a5 + a6 + a7 + a8 + a9; +} + +int +main () +{ + v4si a1 = { + 1, 1, 1, 1, + }; + v4si a2 = { + 1, 1, 1, 1, + }; + v4si a3 = { + 1, 1, 1, 1, + }; + v4si a4 = { + 1, 1, 1, 1, + }; + v4si a5 = { + 1, 1, 1, 1, + }; + v4si a6 = { + 1, 1, 1, 1, + }; + v4si a7 = { + 1, 1, 1, 1, + }; + v4si a8 = { + 1, 1, 1, 1, + }; + v4si a9 = { + 1, 1, 1, 1, + }; + v4si expected = { + 9, 9, 9, 9, + }; + v4si result = add (a1, a2, a3, a4, a5, a6, a7, a8, a9); + + unsigned i; + + for (i = 0; i < 4; i++) + if (result[i] != expected[i]) + __builtin_abort (); + + return 0; +} diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/vls/calling-convention-run-4.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vls/calling-convention-run-4.c new file mode 100644 index 0000000..0788447 --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vls/calling-convention-run-4.c @@ -0,0 +1,55 @@ +/* { dg-do run { target { riscv_v } } } */ +/* { dg-additional-options "-std=c99 -fno-vect-cost-model --param=riscv-autovec-preference=scalable" } */ + +typedef long long v2di __attribute__ ((vector_size (16))); + +v2di +add (v2di a1, v2di a2, v2di a3, v2di a4, v2di a5, v2di a6, v2di a7, + v2di a8, v2di a9) +{ + return a1 + a2 + a3 + a4 + a5 + a6 + a7 + a8 + a9; +} + +int +main () +{ + v2di a1 = { + 1, 1, + }; + v2di a2 = { + 1, 1, + }; + v2di a3 = { + 1, 1, + }; + v2di a4 = { + 1, 1, + }; + v2di a5 = { + 1, 1, + }; + v2di a6 = { + 1, 1, + }; + v2di a7 = { + 1, 1, + }; + v2di a8 = { + 1, 1, + }; + v2di a9 = { + 1, 1, + }; + v2di expected = { + 9, 9, + }; + v2di result = add (a1, a2, a3, a4, a5, a6, a7, a8, a9); + + unsigned i; + + for (i = 0; i < 2; i++) + if (result[i] != expected[i]) + __builtin_abort (); + + return 0; +} diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/vls/calling-convention-run-5.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vls/calling-convention-run-5.c new file mode 100644 index 0000000..ec8658d --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vls/calling-convention-run-5.c @@ -0,0 +1,55 @@ +/* { dg-do run { target { riscv_v } } } */ +/* { dg-additional-options "-std=c99 -fno-vect-cost-model --param=riscv-autovec-preference=scalable" } */ + +typedef float v4sf __attribute__ ((vector_size (16))); + +v4sf +add (v4sf a1, v4sf a2, v4sf a3, v4sf a4, v4sf a5, v4sf a6, v4sf a7, + v4sf a8, v4sf a9) +{ + return a1 + a2 + a3 + a4 + a5 + a6 + a7 + a8 + a9; +} + +int +main () +{ + v4sf a1 = { + 1.0, 1.0, 1.0, 1.0, + }; + v4sf a2 = { + 1.0, 1.0, 1.0, 1.0, + }; + v4sf a3 = { + 1.0, 1.0, 1.0, 1.0, + }; + v4sf a4 = { + 1.0, 1.0, 1.0, 1.0, + }; + v4sf a5 = { + 1.0, 1.0, 1.0, 1.0, + }; + v4sf a6 = { + 1.0, 1.0, 1.0, 1.0, + }; + v4sf a7 = { + 1.0, 1.0, 1.0, 1.0, + }; + v4sf a8 = { + 1.0, 1.0, 1.0, 1.0, + }; + v4sf a9 = { + 1.0, 1.0, 1.0, 1.0, + }; + v4sf expected = { + 9.0, 9.0, 9.0, 9.0, + }; + v4sf result = add (a1, a2, a3, a4, a5, a6, a7, a8, a9); + + unsigned i; + + for (i = 0; i < 4; i++) + if (result[i] != expected[i]) + __builtin_abort (); + + return 0; +} diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/vls/calling-convention-run-6.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vls/calling-convention-run-6.c new file mode 100644 index 0000000..bbb53a1 --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vls/calling-convention-run-6.c @@ -0,0 +1,55 @@ +/* { dg-do run { target { riscv_v } } } */ +/* { dg-additional-options "-std=c99 -fno-vect-cost-model --param=riscv-autovec-preference=scalable" } */ + +typedef long long v2df __attribute__ ((vector_size (16))); + +v2df +add (v2df a1, v2df a2, v2df a3, v2df a4, v2df a5, v2df a6, v2df a7, + v2df a8, v2df a9) +{ + return a1 + a2 + a3 + a4 + a5 + a6 + a7 + a8 + a9; +} + +int +main () +{ + v2df a1 = { + 1.0, 1.0, + }; + v2df a2 = { + 1.0, 1.0, + }; + v2df a3 = { + 1.0, 1.0, + }; + v2df a4 = { + 1.0, 1.0, + }; + v2df a5 = { + 1.0, 1.0, + }; + v2df a6 = { + 1.0, 1.0, + }; + v2df a7 = { + 1.0, 1.0, + }; + v2df a8 = { + 1.0, 1.0, + }; + v2df a9 = { + 1.0, 1.0, + }; + v2df expected = { + 9.0, 9.0, + }; + v2df result = add (a1, a2, a3, a4, a5, a6, a7, a8, a9); + + unsigned i; + + for (i = 0; i < 2; i++) + if (result[i] != expected[i]) + __builtin_abort (); + + return 0; +} diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/vls/def.h b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vls/def.h index cb7a1c9..ef55c4d 100644 --- a/gcc/testsuite/gcc.target/riscv/rvv/autovec/vls/def.h +++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vls/def.h @@ -860,3 +860,77 @@ typedef double v512df __attribute__ ((vector_size (4096))); TYPE1 v = {__VA_ARGS__}; \ *(TYPE1 *) out = v; \ } + +#define DEF_RET1_ARG0(TYPE) \ + TYPE __attribute__((noinline)) \ + TYPE##_RET1_ARG0 () \ + { \ + TYPE r = {}; \ + return r; \ + } + +#define DEF_RET1_ARG1(TYPE) \ + TYPE __attribute__((noinline)) \ + TYPE##_RET1_ARG1 (TYPE a1) \ + { \ + return a1; \ + } + +#define DEF_RET1_ARG2(TYPE) \ + TYPE __attribute__((noinline)) \ + TYPE##_RET1_ARG2 (TYPE a1, TYPE a2) \ + { \ + return a1 + a2; \ + } + +#define DEF_RET1_ARG3(TYPE) \ + TYPE __attribute__((noinline)) \ + TYPE##_RET1_ARG3 (TYPE a1, TYPE a2, TYPE a3) \ + { \ + return a1 + a2 + a3; \ + } + +#define DEF_RET1_ARG4(TYPE) \ + TYPE __attribute__((noinline)) \ + TYPE##_RET1_ARG4 (TYPE a1, TYPE a2, TYPE a3, TYPE a4) \ + { \ + return a1 + a2 + a3 + a4; \ + } + +#define DEF_RET1_ARG5(TYPE) \ + TYPE __attribute__((noinline)) \ + TYPE##_RET1_ARG5 (TYPE a1, TYPE a2, TYPE a3, TYPE a4, TYPE a5) \ + { \ + return a1 + a2 + a3 + a4 + a5; \ + } + +#define DEF_RET1_ARG6(TYPE) \ + TYPE __attribute__((noinline)) \ + TYPE##_RET1_ARG6 (TYPE a1, TYPE a2, TYPE a3, TYPE a4, TYPE a5, TYPE a6) \ + { \ + return a1 + a2 + a3 + a4 + a5 + a6; \ + } + +#define DEF_RET1_ARG7(TYPE) \ + TYPE __attribute__((noinline)) \ + TYPE##_RET1_ARG7 (TYPE a1, TYPE a2, TYPE a3, TYPE a4, TYPE a5, TYPE a6, \ + TYPE a7) \ + { \ + return a1 + a2 + a3 + a4 + a5 + a6 + a7; \ + } + +#define DEF_RET1_ARG8(TYPE) \ + TYPE __attribute__((noinline)) \ + TYPE##_RET1_ARG8 (TYPE a1, TYPE a2, TYPE a3, TYPE a4, TYPE a5, TYPE a6, \ + TYPE a7, TYPE a8) \ + { \ + return a1 + a2 + a3 + a4 + a5 + a6 + a7 + a8; \ + } + +#define DEF_RET1_ARG9(TYPE) \ + TYPE __attribute__((noinline)) \ + TYPE##_RET1_ARG9 (TYPE a1, TYPE a2, TYPE a3, TYPE a4, TYPE a5, TYPE a6, \ + TYPE a7, TYPE a8, TYPE a9) \ + { \ + return a1 + a2 + a3 + a4 + a5 + a6 + a7 + a8 + a9; \ + } -- cgit v1.1 From af37bef86199e50368cbfbc97befe0622a07f12f Mon Sep 17 00:00:00 2001 From: Patrick Palka Date: Tue, 30 Jan 2024 10:13:41 -0500 Subject: c++: unifying integer parm with type-dep arg [PR113644] Here when trying to unify P=42 A=T::value we ICE due to the latter's empty type, which same_type_p dislikes. PR c++/113644 gcc/cp/ChangeLog: * pt.cc (unify) : Handle NULL_TREE type. gcc/testsuite/ChangeLog: * g++.dg/template/nontype30.C: New test. --- gcc/cp/pt.cc | 3 ++- gcc/testsuite/g++.dg/template/nontype30.C | 13 +++++++++++++ 2 files changed, 15 insertions(+), 1 deletion(-) create mode 100644 gcc/testsuite/g++.dg/template/nontype30.C (limited to 'gcc') diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc index fb2448a..5871cb6 100644 --- a/gcc/cp/pt.cc +++ b/gcc/cp/pt.cc @@ -24949,7 +24949,8 @@ unify (tree tparms, tree targs, tree parm, tree arg, int strict, /* Type INTEGER_CST can come from ordinary constant template args. */ case INTEGER_CST: case REAL_CST: - if (!same_type_p (TREE_TYPE (parm), TREE_TYPE (arg))) + if (TREE_TYPE (arg) == NULL_TREE + || !same_type_p (TREE_TYPE (parm), TREE_TYPE (arg))) return unify_template_argument_mismatch (explain_p, parm, arg); while (CONVERT_EXPR_P (arg)) arg = TREE_OPERAND (arg, 0); diff --git a/gcc/testsuite/g++.dg/template/nontype30.C b/gcc/testsuite/g++.dg/template/nontype30.C new file mode 100644 index 0000000..926a772 --- /dev/null +++ b/gcc/testsuite/g++.dg/template/nontype30.C @@ -0,0 +1,13 @@ +// PR c++/113644 + +template struct A { }; + +template void f(A<42>); +template void f(A); + +struct B { static const int value = 42; }; + +int main() { + A<42> a; + f(a); // { dg-error "ambiguous" } +} -- cgit v1.1 From 0857a00fe3226db8801384743b6d44353dcac9da Mon Sep 17 00:00:00 2001 From: Patrick Palka Date: Tue, 30 Jan 2024 10:44:56 -0500 Subject: c++: duplicated side effects of xobj arg [PR113640] We miscompile the below testcase because keep_unused_object_arg thinks the object argument of an xobj member function is unused, and so it ends up duplicating the argument's side effects. PR c++/113640 gcc/cp/ChangeLog: * call.cc (keep_unused_object_arg): Punt for an xobj member function. gcc/testsuite/ChangeLog: * g++.dg/cpp23/explicit-obj-lambda14.C: New test. Reviewed-by: Jason Merrill --- gcc/cp/call.cc | 2 +- gcc/testsuite/g++.dg/cpp23/explicit-obj-lambda14.C | 27 ++++++++++++++++++++++ 2 files changed, 28 insertions(+), 1 deletion(-) create mode 100644 gcc/testsuite/g++.dg/cpp23/explicit-obj-lambda14.C (limited to 'gcc') diff --git a/gcc/cp/call.cc b/gcc/cp/call.cc index 9de0d77..451a189 100644 --- a/gcc/cp/call.cc +++ b/gcc/cp/call.cc @@ -5256,7 +5256,7 @@ keep_unused_object_arg (tree result, tree obj, tree fn) { if (result == NULL_TREE || result == error_mark_node - || TREE_CODE (TREE_TYPE (fn)) == METHOD_TYPE + || DECL_OBJECT_MEMBER_FUNCTION_P (fn) || !TREE_SIDE_EFFECTS (obj)) return result; diff --git a/gcc/testsuite/g++.dg/cpp23/explicit-obj-lambda14.C b/gcc/testsuite/g++.dg/cpp23/explicit-obj-lambda14.C new file mode 100644 index 0000000..5c1d566 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp23/explicit-obj-lambda14.C @@ -0,0 +1,27 @@ +// PR c++/113640 +// { dg-do run { target c++23 } } + +static int total; + +struct A { + A f(this auto self, int n) { + total += n; + return self; + } +}; + +int main() { + A a; + a.f(1).f(42).f(100); + if (total != 143) + __builtin_abort(); + + auto l = [](this auto self, int n) { + total += n; + return self; + }; + total = 0; + l(1)(42)(100); + if (total != 143) + __builtin_abort(); +} -- cgit v1.1 From dd7aa986fd12fc24e9d2efb8a8b267acb2bf19ea Mon Sep 17 00:00:00 2001 From: Jason Merrill Date: Tue, 30 Jan 2024 11:36:53 -0500 Subject: testsuite: mangle-reparm1a options [PR113451] When I added -fabi-compat-version=8 to avoid mangling aliases it also suppressed the -Wabi warning. PR c++/113451 gcc/testsuite/ChangeLog: * g++.dg/abi/mangle-regparm1a.C: Use -Wabi=0. --- gcc/testsuite/g++.dg/abi/mangle-regparm1a.C | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'gcc') diff --git a/gcc/testsuite/g++.dg/abi/mangle-regparm1a.C b/gcc/testsuite/g++.dg/abi/mangle-regparm1a.C index 60ac51e..885c760 100644 --- a/gcc/testsuite/g++.dg/abi/mangle-regparm1a.C +++ b/gcc/testsuite/g++.dg/abi/mangle-regparm1a.C @@ -1,5 +1,5 @@ // { dg-do run { target { { i?86-*-* x86_64-*-* } && ia32 } } } -// { dg-options "-fabi-version=8 -fabi-compat-version=8 -Wabi -save-temps" } +// { dg-options "-fabi-version=8 -fabi-compat-version=8 -Wabi=0 -save-temps" } // { dg-final { scan-assembler "_Z18IndirectExternCallIPFviiEiEvT_T0_S3_" } } template -- cgit v1.1 From 209fc1e5f6c67e55e579b69f617b0b678b1bfdf0 Mon Sep 17 00:00:00 2001 From: Jason Merrill Date: Tue, 30 Jan 2024 12:07:21 -0500 Subject: testsuite: fix anon6 mangling [PR112846] As with r14-6796-g2fa122cae50cd8, avoid mangling compatibility aliases in mangling tests, and test the new mangling. PR c++/112846 gcc/testsuite/ChangeLog: * g++.dg/abi/anon6.C: Specify ABI v18. * g++.dg/abi/anon6a.C: New test for ABI v19. --- gcc/testsuite/g++.dg/abi/anon6.C | 1 + gcc/testsuite/g++.dg/abi/anon6a.C | 20 ++++++++++++++++++++ 2 files changed, 21 insertions(+) create mode 100644 gcc/testsuite/g++.dg/abi/anon6a.C (limited to 'gcc') diff --git a/gcc/testsuite/g++.dg/abi/anon6.C b/gcc/testsuite/g++.dg/abi/anon6.C index 7be0b0b..fd76610 100644 --- a/gcc/testsuite/g++.dg/abi/anon6.C +++ b/gcc/testsuite/g++.dg/abi/anon6.C @@ -1,5 +1,6 @@ // PR c++/108566 // { dg-do compile { target c++20 } } +// { dg-additional-options "-fabi-version=18 -fabi-compat-version=18" } template struct wrapper1 { diff --git a/gcc/testsuite/g++.dg/abi/anon6a.C b/gcc/testsuite/g++.dg/abi/anon6a.C new file mode 100644 index 0000000..69c9adb --- /dev/null +++ b/gcc/testsuite/g++.dg/abi/anon6a.C @@ -0,0 +1,20 @@ +// PR c++/108566 +// { dg-do compile { target c++20 } } +// { dg-additional-options "-fabi-compat-version=0" } + +template +struct wrapper1 { + union { + union { + T RightName; + }; + }; +}; + +template void dummy(){} + +void uses() { + dummy{123.0}>(); +} + +// { dg-final { scan-assembler "_Z5dummyITnDaXtl8wrapper1IdEtlNS1_Ut_Edi9RightNametlNS2_Ut_Edi9RightNameLd405ec00000000000EEEEEEvv" } } -- cgit v1.1 From 1a4c47e10e8ba06f04de2d41a040ba1494843a01 Mon Sep 17 00:00:00 2001 From: Patrick Palka Date: Tue, 30 Jan 2024 12:30:32 -0500 Subject: c++: add original testcase [PR67898] The original testcase from this PR (fixed by r14-8291) seems rather different from the others, so let's add it to the testsuite. PR c++/67898 gcc/testsuite/ChangeLog: * g++.dg/cpp0x/temp_default8.C: New test. --- gcc/testsuite/g++.dg/cpp0x/temp_default8.C | 14 ++++++++++++++ 1 file changed, 14 insertions(+) create mode 100644 gcc/testsuite/g++.dg/cpp0x/temp_default8.C (limited to 'gcc') diff --git a/gcc/testsuite/g++.dg/cpp0x/temp_default8.C b/gcc/testsuite/g++.dg/cpp0x/temp_default8.C new file mode 100644 index 0000000..505c67d --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp0x/temp_default8.C @@ -0,0 +1,14 @@ +// PR c++/67898 +// { dg-do compile { target c++11 } } + +void f(int); +void f(float); + +template struct X { }; + +template +void test() { + X(); +} + +template void test(); -- cgit v1.1 From 24d5e0bf19f27a89a13f64b4b8750dbde89bdaa0 Mon Sep 17 00:00:00 2001 From: Takayuki 'January June' Suwa Date: Mon, 8 May 2023 22:38:51 +0900 Subject: xtensa: Make full transition to LRA gcc/ChangeLog: * config/xtensa/constraints.md (R, T, U): Change define_constraint to define_memory_constraint. * config/xtensa/predicates.md (move_operand): Don't check that a constant pool operand size is a multiple of UNITS_PER_WORD. * config/xtensa/xtensa.cc (xtensa_lra_p, TARGET_LRA_P): Remove. (xtensa_emit_move_sequence): Remove "if (reload_in_progress)" clause as it can no longer be true. (fixup_subreg_mem): Drop function. (xtensa_output_integer_literal_parts): Consider 16-bit wide constants. (xtensa_legitimate_constant_p): Add short-circuit path for integer load instructions. Don't check that mode size is at least UNITS_PER_WORD. * config/xtensa/xtensa.md (movsf): Use can_create_pseudo_p() rather reload_in_progress and reload_completed. (doloop_end): Drop operand 2. (movhi_internal): Add alternative loading constant from a literal pool. (define_split for DI register_operand): Don't limit to !TARGET_AUTO_LITPOOLS. * config/xtensa/xtensa.opt (mlra): Change to no effect. --- gcc/config/xtensa/constraints.md | 26 +++++++---------------- gcc/config/xtensa/predicates.md | 7 ++---- gcc/config/xtensa/xtensa.cc | 46 ++++++---------------------------------- gcc/config/xtensa/xtensa.md | 17 +++++++-------- gcc/config/xtensa/xtensa.opt | 4 ++-- 5 files changed, 26 insertions(+), 74 deletions(-) (limited to 'gcc') diff --git a/gcc/config/xtensa/constraints.md b/gcc/config/xtensa/constraints.md index 27fd496..d855fb8 100644 --- a/gcc/config/xtensa/constraints.md +++ b/gcc/config/xtensa/constraints.md @@ -123,29 +123,19 @@ (and (match_code "const_int") (match_test "! xtensa_split1_finished_p ()")))) -;; Memory constraints. Do not use define_memory_constraint here. Doing so -;; causes reload to force some constants into the constant pool, but since -;; the Xtensa constant pool can only be accessed with L32R instructions, it -;; is always better to just copy a constant into a register. Instead, use -;; regular constraints but add a check to allow pseudos during reload. +;; Memory constraints. -(define_constraint "R" +(define_memory_constraint "R" "Memory that can be accessed with a 4-bit unsigned offset from a register." - (ior (and (match_code "mem") - (match_test "smalloffset_mem_p (op)")) - (and (match_code "reg") - (match_test "reload_in_progress - && REGNO (op) >= FIRST_PSEUDO_REGISTER")))) + (and (match_code "mem") + (match_test "smalloffset_mem_p (op)"))) -(define_constraint "T" +(define_memory_constraint "T" "Memory in a literal pool (addressable with an L32R instruction)." (and (match_code "mem") (match_test "!TARGET_CONST16 && constantpool_mem_p (op)"))) -(define_constraint "U" +(define_memory_constraint "U" "Memory that is not in a literal pool." - (ior (and (match_code "mem") - (match_test "! constantpool_mem_p (op)")) - (and (match_code "reg") - (match_test "reload_in_progress - && REGNO (op) >= FIRST_PSEUDO_REGISTER")))) + (and (match_code "mem") + (match_test "! constantpool_mem_p (op)"))) diff --git a/gcc/config/xtensa/predicates.md b/gcc/config/xtensa/predicates.md index a3dd1a9..a296c7e 100644 --- a/gcc/config/xtensa/predicates.md +++ b/gcc/config/xtensa/predicates.md @@ -143,17 +143,14 @@ (define_predicate "move_operand" (ior (ior (match_operand 0 "register_operand") - (and (match_operand 0 "memory_operand") - (match_test "!constantpool_mem_p (op) - || GET_MODE_SIZE (mode) % UNITS_PER_WORD == 0"))) + (match_operand 0 "memory_operand")) (ior (and (match_code "const_int") (match_test "(GET_MODE_CLASS (mode) == MODE_INT && xtensa_simm12b (INTVAL (op))) || ! xtensa_split1_finished_p ()")) (and (match_code "const_int,const_double,const,symbol_ref,label_ref") (match_test "(TARGET_CONST16 || TARGET_AUTO_LITPOOLS) - && CONSTANT_P (op) - && GET_MODE_SIZE (mode) % UNITS_PER_WORD == 0"))))) + && CONSTANT_P (op)"))))) ;; Accept the floating point constant 1 in the appropriate mode. (define_predicate "const_float_1_operand" diff --git a/gcc/config/xtensa/xtensa.cc b/gcc/config/xtensa/xtensa.cc index 12677af..9beac93 100644 --- a/gcc/config/xtensa/xtensa.cc +++ b/gcc/config/xtensa/xtensa.cc @@ -115,7 +115,6 @@ static enum internal_test map_test_to_internal_test (enum rtx_code); static rtx gen_int_relational (enum rtx_code, rtx, rtx); static rtx gen_float_relational (enum rtx_code, rtx, rtx); static rtx gen_conditional_move (enum rtx_code, machine_mode, rtx, rtx); -static rtx fixup_subreg_mem (rtx); static struct machine_function * xtensa_init_machine_status (void); static rtx xtensa_legitimize_tls_address (rtx); static rtx xtensa_legitimize_address (rtx, rtx, machine_mode); @@ -192,7 +191,6 @@ static void xtensa_output_mi_thunk (FILE *file, tree thunk ATTRIBUTE_UNUSED, HOST_WIDE_INT delta, HOST_WIDE_INT vcall_offset, tree function); -static bool xtensa_lra_p (void); static rtx xtensa_delegitimize_address (rtx); @@ -286,9 +284,6 @@ static rtx xtensa_delegitimize_address (rtx); #undef TARGET_CANNOT_FORCE_CONST_MEM #define TARGET_CANNOT_FORCE_CONST_MEM xtensa_cannot_force_const_mem -#undef TARGET_LRA_P -#define TARGET_LRA_P xtensa_lra_p - #undef TARGET_LEGITIMATE_ADDRESS_P #define TARGET_LEGITIMATE_ADDRESS_P xtensa_legitimate_address_p @@ -1333,35 +1328,10 @@ xtensa_emit_move_sequence (rtx *operands, machine_mode mode) operands[1] = xtensa_copy_incoming_a7 (operands[1]); - /* During reload we don't want to emit (subreg:X (mem:Y)) since that - instruction won't be recognized after reload, so we remove the - subreg and adjust mem accordingly. */ - if (reload_in_progress) - { - operands[0] = fixup_subreg_mem (operands[0]); - operands[1] = fixup_subreg_mem (operands[1]); - } return 0; } -static rtx -fixup_subreg_mem (rtx x) -{ - if (GET_CODE (x) == SUBREG - && GET_CODE (SUBREG_REG (x)) == REG - && REGNO (SUBREG_REG (x)) >= FIRST_PSEUDO_REGISTER) - { - rtx temp = - gen_rtx_SUBREG (GET_MODE (x), - reg_equiv_mem (REGNO (SUBREG_REG (x))), - SUBREG_BYTE (x)); - x = alter_subreg (&temp, true); - } - return x; -} - - /* Check if an incoming argument in a7 is expected to be used soon and if OPND is a register or register pair that includes a7. If so, create a new pseudo and copy a7 into that pseudo at the very @@ -2355,7 +2325,7 @@ xtensa_legitimate_address_p (machine_mode mode, rtx addr, bool strict, code_helper) { /* Allow constant pool addresses. */ - if (mode != BLKmode && GET_MODE_SIZE (mode) >= UNITS_PER_WORD + if (mode != BLKmode && ! TARGET_CONST16 && constantpool_address_p (addr) && ! xtensa_tls_referenced_p (addr)) return true; @@ -3280,7 +3250,7 @@ xtensa_output_integer_literal_parts (FILE *file, rtx x, int size) fputs (", ", file); xtensa_output_integer_literal_parts (file, second, size / 2); } - else if (size == 4) + else if (size == 4 || size == 2) { output_addr_const (file, x); } @@ -4952,6 +4922,10 @@ xtensa_trampoline_init (rtx m_tramp, tree fndecl, rtx chain) static bool xtensa_legitimate_constant_p (machine_mode mode ATTRIBUTE_UNUSED, rtx x) { + if (CONST_INT_P (x)) + return TARGET_AUTO_LITPOOLS || TARGET_CONST16 + || xtensa_simm12b (INTVAL (x)); + return !xtensa_tls_referenced_p (x); } @@ -5393,12 +5367,4 @@ xtensa_delegitimize_address (rtx op) return op; } -/* Implement TARGET_LRA_P. */ - -static bool -xtensa_lra_p (void) -{ - return TARGET_LRA; -} - #include "gt-xtensa.h" diff --git a/gcc/config/xtensa/xtensa.md b/gcc/config/xtensa/xtensa.md index c848e4e..f3953aa 100644 --- a/gcc/config/xtensa/xtensa.md +++ b/gcc/config/xtensa/xtensa.md @@ -1244,7 +1244,7 @@ (define_split [(set (match_operand:DI 0 "register_operand") (match_operand:DI 1 "const_int_operand"))] - "!TARGET_CONST16 && !TARGET_AUTO_LITPOOLS + "!TARGET_CONST16 && ! xtensa_split1_finished_p ()" [(set (match_dup 0) (match_dup 1)) @@ -1328,8 +1328,8 @@ }) (define_insn "movhi_internal" - [(set (match_operand:HI 0 "nonimmed_operand" "=D,D,a,a,a,a,U,*a,*A") - (match_operand:HI 1 "move_operand" "M,d,r,I,Y,U,r,*A,*r"))] + [(set (match_operand:HI 0 "nonimmed_operand" "=D,D,a,a,a,a,a,U,*a,*A") + (match_operand:HI 1 "move_operand" "M,d,r,I,Y,T,U,r,*A,*r"))] "xtensa_valid_move (HImode, operands)" "@ movi.n\t%0, %x1 @@ -1337,13 +1337,14 @@ mov\t%0, %1 movi\t%0, %x1 movi\t%0, %1 + %v1l32r\t%0, %1 %v1l16ui\t%0, %1 %v0s16i\t%1, %0 rsr\t%0, ACCLO wsr\t%1, ACCLO" - [(set_attr "type" "move,move,move,move,move,load,store,rsr,wsr") + [(set_attr "type" "move,move,move,move,move,load,load,store,rsr,wsr") (set_attr "mode" "HI") - (set_attr "length" "2,2,3,3,3,3,3,3,3")]) + (set_attr "length" "2,2,3,3,3,3,3,3,3,3")]) ;; 8-bit Integer moves @@ -1420,7 +1421,7 @@ if ((!register_operand (operands[0], SFmode) && !register_operand (operands[1], SFmode)) || (FP_REG_P (xt_true_regnum (operands[0])) - && !(reload_in_progress | reload_completed) + && can_create_pseudo_p () && (constantpool_mem_p (operands[1]) || CONSTANT_P (operands[1])))) operands[1] = force_reg (SFmode, operands[1]); @@ -2368,14 +2369,12 @@ (set (match_dup 0) (plus:SI (match_dup 0) (const_int -1))) - (unspec [(const_int 0)] UNSPEC_LSETUP_END) - (clobber (match_dup 2))])] ; match_scratch + (unspec [(const_int 0)] UNSPEC_LSETUP_END)])] "TARGET_LOOPS && optimize" { /* The loop optimizer doesn't check the predicates... */ if (GET_MODE (operands[0]) != SImode) FAIL; - operands[2] = gen_rtx_SCRATCH (SImode); }) diff --git a/gcc/config/xtensa/xtensa.opt b/gcc/config/xtensa/xtensa.opt index a953f0b..b653e99 100644 --- a/gcc/config/xtensa/xtensa.opt +++ b/gcc/config/xtensa/xtensa.opt @@ -38,8 +38,8 @@ Target RejectNegative Joined UInteger Var(xtensa_extra_l32r_costs) Init(0) Set extra memory access cost for L32R instruction, in clock-cycle units. mlra -Target Mask(LRA) -Use LRA instead of reload (transitional). +Target Ignore +Does nothing. Preserved for backward compatibility. mtarget-align Target -- cgit v1.1 From f2061b2a9641c2228d4e2d86f19532ad7e93d627 Mon Sep 17 00:00:00 2001 From: Marek Polacek Date: Thu, 25 Jan 2024 12:08:14 -0500 Subject: c++: avoid -Wdangling-reference for std::span-like classes [PR110358] Real-world experience shows that -Wdangling-reference triggers for user-defined std::span-like classes a lot. We can easily avoid that by considering classes like template struct Span { T* data_; std::size len_; }; to be std::span-like, and not warning for them. Unlike the previous patch, this one considers a non-union class template that has a pointer data member and a trivial destructor as std::span-like. PR c++/110358 PR c++/109640 gcc/cp/ChangeLog: * call.cc (reference_like_class_p): Don't warn for std::span-like classes. gcc/ChangeLog: * doc/invoke.texi: Update -Wdangling-reference description. gcc/testsuite/ChangeLog: * g++.dg/warn/Wdangling-reference18.C: New test. * g++.dg/warn/Wdangling-reference19.C: New test. * g++.dg/warn/Wdangling-reference20.C: New test. --- gcc/cp/call.cc | 18 ++++++++++ gcc/doc/invoke.texi | 14 ++++++++ gcc/testsuite/g++.dg/warn/Wdangling-reference18.C | 24 +++++++++++++ gcc/testsuite/g++.dg/warn/Wdangling-reference19.C | 25 +++++++++++++ gcc/testsuite/g++.dg/warn/Wdangling-reference20.C | 44 +++++++++++++++++++++++ 5 files changed, 125 insertions(+) create mode 100644 gcc/testsuite/g++.dg/warn/Wdangling-reference18.C create mode 100644 gcc/testsuite/g++.dg/warn/Wdangling-reference19.C create mode 100644 gcc/testsuite/g++.dg/warn/Wdangling-reference20.C (limited to 'gcc') diff --git a/gcc/cp/call.cc b/gcc/cp/call.cc index 451a189..42cbd0d 100644 --- a/gcc/cp/call.cc +++ b/gcc/cp/call.cc @@ -14082,6 +14082,24 @@ reference_like_class_p (tree ctype) return true; } + /* Avoid warning if CTYPE looks like std::span: it's a class template, + has a T* member, and a trivial destructor. For example, + + template + struct Span { + T* data_; + std::size len_; + }; + + is considered std::span-like. */ + if (NON_UNION_CLASS_TYPE_P (ctype) + && CLASSTYPE_TEMPLATE_INSTANTIATION (ctype) + && TYPE_HAS_TRIVIAL_DESTRUCTOR (ctype)) + for (tree field = next_aggregate_field (TYPE_FIELDS (ctype)); + field; field = next_aggregate_field (DECL_CHAIN (field))) + if (TYPE_PTR_P (TREE_TYPE (field))) + return true; + /* Some classes, such as std::tuple, have the reference member in its (non-direct) base class. */ if (dfs_walk_once (TYPE_BINFO (ctype), class_has_reference_member_p_r, diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi index 819a75d..eb931b9 100644 --- a/gcc/doc/invoke.texi +++ b/gcc/doc/invoke.texi @@ -3916,6 +3916,20 @@ where @code{std::minmax} returns @code{std::pair}, and both references dangle after the end of the full expression that contains the call to @code{std::minmax}. +The warning does not warn for @code{std::span}-like classes. We consider +classes of the form: + +@smallexample +template +struct Span @{ + T* data_; + std::size len_; +@}; +@end smallexample + +as @code{std::span}-like; that is, the class is a non-union class template +that has a pointer data member and a trivial destructor. + This warning is enabled by @option{-Wall}. @opindex Wdelete-non-virtual-dtor diff --git a/gcc/testsuite/g++.dg/warn/Wdangling-reference18.C b/gcc/testsuite/g++.dg/warn/Wdangling-reference18.C new file mode 100644 index 0000000..e088c17 --- /dev/null +++ b/gcc/testsuite/g++.dg/warn/Wdangling-reference18.C @@ -0,0 +1,24 @@ +// PR c++/110358 +// { dg-do compile { target c++11 } } +// { dg-options "-Wdangling-reference" } +// Don't warn for std::span-like classes. + +template +struct Span { + T* data_; + int len_; + + [[nodiscard]] constexpr auto operator[](int n) const noexcept -> T& { return data_[n]; } + [[nodiscard]] constexpr auto front() const noexcept -> T& { return data_[0]; } + [[nodiscard]] constexpr auto back() const noexcept -> T& { return data_[len_ - 1]; } +}; + +auto get() -> Span; + +auto f() -> int { + int const& a = get().front(); // { dg-bogus "dangling reference" } + int const& b = get().back(); // { dg-bogus "dangling reference" } + int const& c = get()[0]; // { dg-bogus "dangling reference" } + + return a + b + c; +} diff --git a/gcc/testsuite/g++.dg/warn/Wdangling-reference19.C b/gcc/testsuite/g++.dg/warn/Wdangling-reference19.C new file mode 100644 index 0000000..053467d --- /dev/null +++ b/gcc/testsuite/g++.dg/warn/Wdangling-reference19.C @@ -0,0 +1,25 @@ +// PR c++/110358 +// { dg-do compile { target c++11 } } +// { dg-options "-Wdangling-reference" } +// Like Wdangling-reference18.C but not actually a span-like class. + +template +struct Span { + T* data_; + int len_; + ~Span (); + + [[nodiscard]] constexpr auto operator[](int n) const noexcept -> T& { return data_[n]; } + [[nodiscard]] constexpr auto front() const noexcept -> T& { return data_[0]; } + [[nodiscard]] constexpr auto back() const noexcept -> T& { return data_[len_ - 1]; } +}; + +auto get() -> Span; + +auto f() -> int { + int const& a = get().front(); // { dg-warning "dangling reference" } + int const& b = get().back(); // { dg-warning "dangling reference" } + int const& c = get()[0]; // { dg-warning "dangling reference" } + + return a + b + c; +} diff --git a/gcc/testsuite/g++.dg/warn/Wdangling-reference20.C b/gcc/testsuite/g++.dg/warn/Wdangling-reference20.C new file mode 100644 index 0000000..84138f0 --- /dev/null +++ b/gcc/testsuite/g++.dg/warn/Wdangling-reference20.C @@ -0,0 +1,44 @@ +// PR c++/109640 +// { dg-do compile { target c++20 } } +// { dg-options "-Wdangling-reference" } +// Don't warn for std::span-like classes. + +#include +#include + +template +struct MySpan +{ + MySpan(T* data, std::size_t size) : + data_(data), + size_(size) + {} + + T& operator[](std::size_t idx) { return data_[idx]; } + +private: + T* data_; + std::size_t size_; +}; + +template +MySpan make_my_span(T const(&x)[n]) +{ + return MySpan(std::begin(x), n); +} + +template +std::span make_span(T const(&x)[n]) +{ + return std::span(std::begin(x), n); +} + +int main() +{ + int x[10]{}; + [[maybe_unused]] int const& y1{make_my_span(x)[0]}; + [[maybe_unused]] int const& y2{make_span(x)[0]}; + using T = int[10]; + [[maybe_unused]] int const& y3{make_my_span(T{})[0]}; // { dg-warning "dangling reference" } + [[maybe_unused]] int const& y4{make_span(T{})[0]}; // { dg-warning "dangling reference" } +} -- cgit v1.1 From d7250100381b817114447d91fff4748526d4fb21 Mon Sep 17 00:00:00 2001 From: Fangrui Song Date: Thu, 11 Jan 2024 10:24:25 -0800 Subject: i386: Add "Ws" constraint for symbolic address/label reference [PR105576] Printing the raw symbol is useful in inline asm (e.g. in C++ to get the mangled name). Similar constraints are available in other targets (e.g. "S" for aarch64/riscv, "Cs" for m68k). There isn't a good way for x86 yet, e.g. "i" doesn't work for PIC/-mcmodel=large. This patch adds "Ws". Here are possible use cases: ``` namespace ns { extern int var; } asm (".pushsection .xxx,\"aw\"; .dc.a %0; .popsection" :: "Ws"(&var)); asm (".reloc ., BFD_RELOC_NONE, %0" :: "Ws"(&var)); ``` gcc/ChangeLog: PR target/105576 * config/i386/constraints.md: Define constraint "Ws". * doc/md.texi: Document it. gcc/testsuite/ChangeLog: PR target/105576 * gcc.target/i386/asm-raw-symbol.c: New testcase. --- gcc/config/i386/constraints.md | 4 ++++ gcc/doc/md.texi | 4 ++++ gcc/testsuite/gcc.target/i386/asm-raw-symbol.c | 13 +++++++++++++ 3 files changed, 21 insertions(+) create mode 100644 gcc/testsuite/gcc.target/i386/asm-raw-symbol.c (limited to 'gcc') diff --git a/gcc/config/i386/constraints.md b/gcc/config/i386/constraints.md index 0c6e662..280e4c8 100644 --- a/gcc/config/i386/constraints.md +++ b/gcc/config/i386/constraints.md @@ -348,6 +348,10 @@ to double word size." (match_operand 0 "x86_64_dwzext_immediate_operand")) +(define_constraint "Ws" + "A symbolic reference or label reference." + (match_code "const,symbol_ref,label_ref")) + (define_constraint "Z" "32-bit unsigned integer constant, or a symbolic reference known to fit that range (for immediate operands in zero-extending x86-64 diff --git a/gcc/doc/md.texi b/gcc/doc/md.texi index 47a87d6..b0c6192 100644 --- a/gcc/doc/md.texi +++ b/gcc/doc/md.texi @@ -4275,6 +4275,10 @@ require non-@code{VOIDmode} immediate operands). 128-bit integer constant where both the high and low 64-bit word satisfy the @code{e} constraint. +@item Ws +A symbolic reference or label reference. +You can use the @code{%p} modifier to print the raw symbol. + @item Z 32-bit unsigned integer constant, or a symbolic reference known to fit that range (for immediate operands in zero-extending x86-64 diff --git a/gcc/testsuite/gcc.target/i386/asm-raw-symbol.c b/gcc/testsuite/gcc.target/i386/asm-raw-symbol.c new file mode 100644 index 0000000..b785456 --- /dev/null +++ b/gcc/testsuite/gcc.target/i386/asm-raw-symbol.c @@ -0,0 +1,13 @@ +/* { dg-do compile } */ + +extern int var; + +void +func (void) +{ + __asm__ ("@ %p0" : : "Ws" (func)); + __asm__ ("@ %p0" : : "Ws" (&var + 1)); +} + +/* { dg-final { scan-assembler "@ func" } } */ +/* { dg-final { scan-assembler "@ var\\+4" } } */ -- cgit v1.1 From 097ddd552d6de783a0de7b3b2c4d8ed3bf601002 Mon Sep 17 00:00:00 2001 From: GCC Administrator Date: Wed, 31 Jan 2024 00:19:27 +0000 Subject: Daily bump. --- gcc/ChangeLog | 99 ++++++ gcc/DATESTAMP | 2 +- gcc/analyzer/ChangeLog | 19 ++ gcc/cp/ChangeLog | 23 ++ gcc/rust/ChangeLog | 839 ++++++++++++++++++++++++++++++++++++++++++++++++ gcc/testsuite/ChangeLog | 255 +++++++++++++++ 6 files changed, 1236 insertions(+), 1 deletion(-) (limited to 'gcc') diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 60e2d87..2f7d6ff 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,102 @@ +2024-01-30 Fangrui Song + + PR target/105576 + * config/i386/constraints.md: Define constraint "Ws". + * doc/md.texi: Document it. + +2024-01-30 Marek Polacek + + PR c++/110358 + PR c++/109640 + * doc/invoke.texi: Update -Wdangling-reference description. + +2024-01-30 Takayuki 'January June' Suwa + + * config/xtensa/constraints.md (R, T, U): + Change define_constraint to define_memory_constraint. + * config/xtensa/predicates.md (move_operand): Don't check that a + constant pool operand size is a multiple of UNITS_PER_WORD. + * config/xtensa/xtensa.cc + (xtensa_lra_p, TARGET_LRA_P): Remove. + (xtensa_emit_move_sequence): Remove "if (reload_in_progress)" + clause as it can no longer be true. + (fixup_subreg_mem): Drop function. + (xtensa_output_integer_literal_parts): Consider 16-bit wide + constants. + (xtensa_legitimate_constant_p): Add short-circuit path for + integer load instructions. Don't check that mode size is + at least UNITS_PER_WORD. + * config/xtensa/xtensa.md (movsf): Use can_create_pseudo_p() + rather reload_in_progress and reload_completed. + (doloop_end): Drop operand 2. + (movhi_internal): Add alternative loading constant from a + literal pool. + (define_split for DI register_operand): Don't limit to + !TARGET_AUTO_LITPOOLS. + * config/xtensa/xtensa.opt (mlra): Change to no effect. + +2024-01-30 Pan Li + + * config/riscv/riscv.cc (riscv_v_vls_mode_aggregate_gpr_count): New function to + calculate the gpr count required by vls mode. + (riscv_v_vls_to_gpr_mode): New function convert vls mode to gpr mode. + (riscv_pass_vls_aggregate_in_gpr): New function to return the rtx of gpr + for vls mode. + (riscv_get_arg_info): Add vls mode handling. + (riscv_pass_by_reference): Return false if arg info has no zero gpr count. + +2024-01-30 Richard Biener + + PR tree-optimization/113659 + * tree-vect-loop-manip.cc (slpeel_tree_duplicate_loop_to_edge_cfg): + Handle main exit without virtual use. + +2024-01-30 Christoph Müllner + + * config/riscv/riscv.md: Move UNSPEC_XTHEADFMV* to unspec enum. + +2024-01-30 Iain Sandoe + + PR libgcc/113403 + * config/darwin.h (DARWIN_SHARED_WEAK_ADDS, DARWIN_WEAK_CRTS): New. + (REAL_LIBGCC_SPEC): Move weak CRT handling to separate spec. + * config/i386/darwin.h (DARWIN_HEAP_T_LIB): New. + * config/i386/darwin32-biarch.h (DARWIN_HEAP_T_LIB): New. + * config/i386/darwin64-biarch.h (DARWIN_HEAP_T_LIB): New. + * config/rs6000/darwin.h (DARWIN_HEAP_T_LIB): New. + +2024-01-30 Richard Sandiford + + PR target/113623 + * config/aarch64/aarch64-early-ra.cc (early_ra::preprocess_insns): + Mark all registers that occur in addresses as needing a GPR. + +2024-01-30 Richard Sandiford + + PR target/113636 + * config/aarch64/aarch64-early-ra.cc (early_ra::replace_regs): Take + the containing insn as an extra parameter. Reset debug instructions + if they reference a register that is no longer used by real insns. + (early_ra::apply_allocation): Update calls accordingly. + +2024-01-30 Jakub Jelinek + + PR tree-optimization/113603 + * tree-ssa-strlen.cc (strlen_pass::handle_store): After + count_nonzero_bytes call refetch si using get_strinfo in case it + has been unshared in the meantime. + +2024-01-30 Jakub Jelinek + + PR middle-end/101195 + * except.cc (expand_builtin_eh_return_data_regno): If which doesn't + fit into unsigned HOST_WIDE_INT, return constm1_rtx. + +2024-01-30 Jin Ma + + * config/riscv/thead.cc (th_print_operand_address): Change %ld + to %lld. + 2024-01-29 Manos Anagnostakis Manolis Tsamis Philipp Tomsich diff --git a/gcc/DATESTAMP b/gcc/DATESTAMP index d984aca..e288d0c 100644 --- a/gcc/DATESTAMP +++ b/gcc/DATESTAMP @@ -1 +1 @@ -20240130 +20240131 diff --git a/gcc/analyzer/ChangeLog b/gcc/analyzer/ChangeLog index 338a782..ce599b1 100644 --- a/gcc/analyzer/ChangeLog +++ b/gcc/analyzer/ChangeLog @@ -1,3 +1,22 @@ +2024-01-30 David Malcolm + + PR analyzer/113654 + * region-model.cc (is_round_up): New. + (is_multiple_p): New. + (is_dubious_capacity): New. + (region_model::check_region_size): Move usage of size_visitor into + is_dubious_capacity. + +2024-01-30 David Malcolm + + * region-model.cc + (dubious_allocation_size::dubious_allocation_size): Add + "capacity_sval" param. Drop unused ctor. + (dubious_allocation_size::maybe_add_sarif_properties): New. + (dubious_allocation_size::m_capacity_sval): New field. + (region_model::check_region_size): Pass capacity svalue to + dubious_allocation_size ctor. + 2024-01-25 David Malcolm PR analyzer/112969 diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index 2d64d86..4198641 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,3 +1,26 @@ +2024-01-30 Marek Polacek + + PR c++/110358 + PR c++/109640 + * call.cc (reference_like_class_p): Don't warn for std::span-like + classes. + +2024-01-30 Patrick Palka + + PR c++/113640 + * call.cc (keep_unused_object_arg): Punt for an xobj member + function. + +2024-01-30 Patrick Palka + + PR c++/113644 + * pt.cc (unify) : Handle NULL_TREE type. + +2024-01-30 Nathaniel Shead + + PR c++/107594 + * module.cc (get_module): Bail on empty name. + 2024-01-29 Jason Merrill PR c++/113544 diff --git a/gcc/rust/ChangeLog b/gcc/rust/ChangeLog index a834a8f..f1220b0 100644 --- a/gcc/rust/ChangeLog +++ b/gcc/rust/ChangeLog @@ -1,3 +1,842 @@ +2024-01-30 Owen Avery + + * ast/rust-ast-full-decls.h + (class TraitImplItem): Remove forward declaration. + (class AssociatedItem): Add forward declaration. + * ast/rust-ast.h + (class TraitImplItem): Remove. + (class TraitItem): Inherit from AssociatedItem. + (SingleASTNode::take_trait_impl_item): + Return std::unique_ptr instead of + std::unique_ptr. + * ast/rust-item.h + (class Function): Inherit from AssociatedItem instead of + TraitImplItem. + (class TypeAlias): Likewise. + (class ConstantItem): Likewise. + (class TraitImpl): Store items as AssociatedItem. + * expand/rust-derive-clone.cc + (DeriveClone::clone_fn): Return std::unique_ptr. + (DeriveClone::clone_impl): Take std::unique_ptr. + * expand/rust-derive-clone.h + (DeriveClone::clone_fn): Return std::unique_ptr. + (DeriveClone::clone_impl): Take std::unique_ptr. + * expand/rust-expand-visitor.cc + (ExpandVisitor::visit): Handle changes to + SingleASTNode::take_trait_impl_item. + * parse/rust-parse-impl.h + (Parser::parse_impl): Parse TraitImpl as containing AssociatedItem. + (Parser::parse_trait_impl_item): Return + std::unique_ptr. + (Parser::parse_trait_impl_function_or_method): Likewise. + * parse/rust-parse.h + (Parser::parse_trait_impl_item): Return + std::unique_ptr. + (Parser::parse_trait_impl_function_or_method): Likewise. + +2024-01-30 Robert Goss + + * typecheck/rust-hir-type-check-expr.cc (TypeCheckExpr::visit) Add additional check + * typecheck/rust-hir-type-check-struct-field.h: A helper method to make error added + * typecheck/rust-hir-type-check-struct.cc (TypeCheckStructExpr::resolve) Update message + +2024-01-30 Jakub Dupak + + * hir/rust-ast-lower-type.cc (ASTLoweringTypeBounds::visit): fix for lifetimes + (ASTLowerWhereClauseItem::visit): fix for lifetimes + +2024-01-30 Jakub Dupak + + * parse/rust-parse-impl.h (Parser::parse_where_clause): fix parsing + (Parser::parse_where_clause_item): fix parsing + (Parser::parse_type_bound_where_clause_item): fix parsing + (Parser::parse_trait_bound): fix parsing + * parse/rust-parse.h: fix parsing + +2024-01-30 Kushal Pal + + * lex/rust-lex.cc (Lexer::dump_and_skip): + Changed " " to '\n' + +2024-01-30 Owen Avery + + * ast/rust-ast-fragment.cc + (Fragment::assert_single_fragment): Update. + * ast/rust-ast.h + (class TraitImplItem): Move definition before that of TraitItem. + (class TraitItem): + Inherit from TraitImplItem instead of AssociatedItem. + (class SingleASTNode): Unify handling of associated items. + (SingleASTNode::take_assoc_item): Move from... + (SingleASTNode::take_impl_item): ...here, but leave stub calling + take_assoc_item behind. + (SingleASTNode::take_trait_item): + Cast associated item to TraitItem. + (SingleASTNode::take_trait_impl_item): + Cast associated item to TraitImplItem. + * ast/rust-ast.cc + (SingleASTNode::SingleASTNode): + Unify handling of associated items. + (SingleASTNode::operator=): Likewise. + (SingleASTNode::accept_vis): Likewise. + (SingleASTNode::is_error): Likewise. + (SingleASTNode::as_string): Likewise. + * ast/rust-item.h + (class Function): Remove direct inheritence from AssociatedItem. + (class ConstantItem): Likewise. + * ast/rust-macro.h + (class MacroInvocation): + Remove direct inheritence from AssociatedItem and TraitImplItem. + +2024-01-30 Robert Goss + + * typecheck/rust-hir-type-check-struct-field.h: Allow visit to return a bool + * typecheck/rust-hir-type-check-struct.cc: Improve check of repeat fields + +2024-01-30 Kushal Pal + + * parse/rust-parse-impl.h (Parser::parse_inherent_impl_item): + Added switch-case for ASYNC token. + +2024-01-30 Kushal Pal + + * checks/errors/rust-ast-validation.cc (ASTValidation::visit): + Enclose const in single quotes. + +2024-01-30 Kushal Pal + + * checks/errors/rust-ast-validation.cc (ASTValidation::visit): + Added check for `async` functions inside trait. + * parse/rust-parse-impl.h (Parser::parse_trait_item): + Added switch-case for ASYNC token. + +2024-01-30 Nirmal Patel + + * lex/rust-lex.cc (Lexer::parse_byte_string): Handle newline + while parsing byte strings + (Lexer::parse_string): Handle newline while parsing strings + +2024-01-30 Jakub Dupak + + * backend/rust-compile-expr.cc (CompileExpr::visit): Use new API. + * typecheck/rust-tyty-call.cc (TypeCheckCallExpr::visit): Use new API. + * typecheck/rust-tyty-cmp.h: Remove old API. + * typecheck/rust-tyty.cc (FnPtr::is_equal): Use new API. + * typecheck/rust-tyty.h: Remove old API. + * typecheck/rust-unify.cc (UnifyRules::expect_fnptr): Use new API. + +2024-01-30 Jakub Dupak + + * hir/rust-ast-lower-type.cc (ASTLoweringType::visit): For lifetimes. + +2024-01-30 Jakub Dupak + + * hir/rust-ast-lower-base.cc (ASTLoweringBase::lower_lifetime): Propagate static + requirement. + * hir/rust-ast-lower-base.h: Propagate static requirement. + * hir/rust-ast-lower-implitem.h: Propagate static requirement. + * hir/rust-ast-lower-item.cc (ASTLoweringItem::visit): Propagate static requirement. + * hir/rust-ast-lower-type.cc (ASTLoweringType::translate): Propagate static requirement. + (ASTLoweringType::visit): Propagate static requirement. + * hir/rust-ast-lower-type.h: Propagate static requirement. + +2024-01-30 Jakub Dupak + + * parse/rust-parse-impl.h (Parser::parse_generic_param): Lifetime elision control. + (Parser::parse_lifetime_where_clause_item): Lifetime elision control. + (Parser::parse_type_param_bound): Lifetime elision control. + (Parser::parse_lifetime_bounds): Lifetime elision control. + (Parser::parse_lifetime): Lifetime elision control. + (Parser::parse_path_generic_args): Lifetime elision control. + (Parser::parse_self_param): Lifetime elision control. + (Parser::parse_break_expr): Lifetime elision control. + (Parser::parse_continue_expr): Lifetime elision control. + (Parser::parse_reference_type_inner): Lifetime elision control. + * parse/rust-parse.h: Lifetime elision control. + +2024-01-30 Jakub Dupak + + * ast/rust-ast.h: Elided lifetime static constructor + * ast/rust-type.h: Default lifetime to elided. + * parse/rust-parse-impl.h (Parser::parse_lifetime_param): Use elided lifetime. + (Parser::parse_lifetime): Use elided lifetime/ + (Parser::lifetime_from_token): Use elided lifetime. + (Parser::parse_self_param): Use elided lifetime. + (Parser::parse_reference_type_inner): Use elided lifetime. + +2024-01-30 Jakub Dupak + + * parse/rust-parse-impl.h (Parser::lifetime_from_token): Fix matched pattern. + +2024-01-30 Kushal Pal + + * checks/errors/rust-ast-validation.cc (ASTValidation::visit): + Added check for `async` function inside trait. + +2024-01-30 Kushal Pal + + * parse/rust-parse-impl.h (Parser::parse_trait_impl_item): + Handled `async` items + +2024-01-30 Raiki Tamura + + * Make-lang.in: Add .o files + * backend/rust-mangle.cc (struct V0Path): moved to splitted files + (v0_path): Likewise. + (legacy_mangle_name): Likewise. + (legacy_mangle_canonical_path): Likewise. + (legacy_hash): Likewise. + (v0_tuple_prefix): Likewise. + (v0_numeric_prefix): Likewise. + (v0_simple_type_prefix): Likewise. + (v0_complex_type_prefix): Likewise. + (v0_integer_62): Likewise. + (v0_opt_integer_62): Likewise. + (v0_disambiguator): Likewise. + (v0_type_prefix): Likewise. + (v0_generic_args): Likewise. + (v0_identifier): Likewise. + (v0_type_path): Likewise. + (v0_function_path): Likewise. + (v0_scope_path): Likewise. + (v0_crate_path): Likewise. + (v0_inherent_or_trait_impl_path): Likewise. + (v0_closure): Likewise. + (legacy_mangle_item): Likewise. + (v0_mangle_item): Likewise. + * backend/rust-mangle.h (legacy_mangle_item): Likewise. + (v0_mangle_item): Likewise. + * backend/rust-mangle-legacy.cc: New file. + * backend/rust-mangle-v0.cc: New file. + +2024-01-30 Jakub Dupak + + * checks/errors/borrowck/rust-bir-place.h: Cleanup. + * checks/errors/borrowck/rust-borrow-checker.h: Cleanup. + +2024-01-30 Jakub Dupak + + * typecheck/rust-tyty.h (BaseType::is): Cast API. + (SubstitutionRef>): Cast API. + (BaseType::as): Cast API. + (BaseType::try_as): Cast API. + +2024-01-30 Jakub Dupak + + * typecheck/rust-tyty.h (class ClosureType): Inherit interface. + (class FnPtr): Inherit interface. + (class FnType): Inherit interface. + (class CallableTypeInterface): New interface. + (BaseType::is): Detect interface members API. + +2024-01-30 Jakub Dupak + + * typecheck/rust-hir-type-check-type.cc (TypeCheckType::resolve_root_path): Refactor. + +2024-01-30 Jakub Dupak + + * checks/errors/borrowck/rust-bir-builder-internal.h: Replace nodiscard. + * checks/errors/borrowck/rust-bir-place.h: Replace nodiscard. + +2024-01-30 Jakub Dupak + + * typecheck/rust-tyty.h: Fix nodiscard to warn unused. + +2024-01-30 Jakub Dupak + + * hir/tree/rust-hir-item.h: Ad lifetime getter. + * hir/tree/rust-hir-path.h: Make getter const ref. + * hir/tree/rust-hir.h: Const ref and new getter. + +2024-01-30 Arthur Cohen + + * Make-lang.in (GRS_OBJS): Add rust-attribs.o. + * backend/rust-builtins.cc (builtin_const, builtin_noreturn) + (builtin_novops): Remove. + (BuiltinsContext::lookup_simple_builtin): Adjust. + (BuiltinsContext::setup_overflow_fns): Remove. + (BuiltinsContext::define_function_type): Set builtin type to + errormark so the builtin is considered unavailable. + (BuiltinsContext::setup_math_fns): Remove. + (BuiltinsContext::setup_atomic_fns): Remove. + (build_c_type_nodes): Refactor based on D frontend. + (BuiltinsContext::define_builtin_types): Likewise. + (DEF_PRIMITIVE_TYPE): New. + (DEF_FUNCTION_TYPE_0): New. + (DEF_FUNCTION_TYPE_1): New. + (DEF_FUNCTION_TYPE_2): New. + (DEF_FUNCTION_TYPE_3): New. + (DEF_FUNCTION_TYPE_4): New. + (DEF_FUNCTION_TYPE_5): New. + (DEF_FUNCTION_TYPE_6): New. + (DEF_FUNCTION_TYPE_7): New. + (DEF_FUNCTION_TYPE_8): New. + (DEF_FUNCTION_TYPE_9): New. + (DEF_FUNCTION_TYPE_10): New. + (DEF_FUNCTION_TYPE_11): New. + (DEF_FUNCTION_TYPE_VAR_0): New. + (DEF_FUNCTION_TYPE_VAR_1): New. + (DEF_FUNCTION_TYPE_VAR_2): New. + (DEF_FUNCTION_TYPE_VAR_3): New. + (DEF_FUNCTION_TYPE_VAR_4): New. + (DEF_FUNCTION_TYPE_VAR_5): New. + (DEF_FUNCTION_TYPE_VAR_6): New. + (DEF_FUNCTION_TYPE_VAR_7): New. + (DEF_FUNCTION_TYPE_VAR_11): New. + (DEF_POINTER_TYPE): New. + (BuiltinsContext::setup): Adjust. + (BuiltinsContext::define_builtin_attributes): New. + (DEF_ATTR_NULL_TREE): New. + (DEF_ATTR_INT): New. + (DEF_ATTR_STRING): New. + (DEF_ATTR_IDENT): New. + (DEF_ATTR_TREE_LIST): New. + (handle_flags): Remove. + (BuiltinsContext::define_builtins): New. + (DEF_BUILTIN): New. + (BuiltinsContext::define_builtin): Remove. + (BuiltinsContext::register_rust_mappings): New. Add all missing + builtins. + (BuiltinsContext::lookup_gcc_builtin): Adjust. + * backend/rust-builtins.h (DEF_PRIMITIVE_TYPE): New. + (DEF_FUNCTION_TYPE_0): New. + (DEF_FUNCTION_TYPE_1): New. + (DEF_FUNCTION_TYPE_2): New. + (DEF_FUNCTION_TYPE_3): New. + (DEF_FUNCTION_TYPE_4): New. + (DEF_FUNCTION_TYPE_5): New. + (DEF_FUNCTION_TYPE_6): New. + (DEF_FUNCTION_TYPE_7): New. + (DEF_FUNCTION_TYPE_8): New. + (DEF_FUNCTION_TYPE_9): New. + (DEF_FUNCTION_TYPE_10): New. + (DEF_FUNCTION_TYPE_11): New. + (DEF_FUNCTION_TYPE_VAR_0): New. + (DEF_FUNCTION_TYPE_VAR_1): New. + (DEF_FUNCTION_TYPE_VAR_2): New. + (DEF_FUNCTION_TYPE_VAR_3): New. + (DEF_FUNCTION_TYPE_VAR_4): New. + (DEF_FUNCTION_TYPE_VAR_5): New. + (DEF_FUNCTION_TYPE_VAR_6): New. + (DEF_FUNCTION_TYPE_VAR_7): New. + (DEF_FUNCTION_TYPE_VAR_11): New. + (DEF_POINTER_TYPE): New. + (DEF_ATTR_NULL_TREE): New. + (DEF_ATTR_INT): New. + (DEF_ATTR_STRING): New. + (DEF_ATTR_IDENT): New. + (DEF_ATTR_TREE_LIST): New. + * backend/rust-compile-intrinsic.cc (Intrinsics::compile): Add + comment. + (op_with_overflow_inner): Adjust. + (copy_handler_inner): Adjust. + (prefetch_data_handler): Adjust. + (build_atomic_builtin_name): Adjust. + (atomic_load_handler_inner): Adjust. + (uninit_handler): Adjust. + (move_val_init_handler): Adjust. + (expect_handler_inner): Adjust. + * rust-gcc.cc (fetch_overflow_builtins): Adjust. + * rust-lang.cc (rust_localize_identifier): Adjust. + (LANG_HOOKS_COMMON_ATTRIBUTE_TABLE): New. + * rust-attribs.cc: New file. + +2024-01-30 Pierre-Emmanuel Patry + + * expand/rust-cfg-strip.cc (CfgStrip::visit): Change calls from visitor + to default visitor. + (CfgStrip::go): Add call to visit crate. + * expand/rust-cfg-strip.h (class CfgStrip): Update prototypes and + remove empty ones. + * ast/rust-ast-visitor.cc: add WhereClause condition check. + +2024-01-30 Pierre-Emmanuel Patry + + * expand/rust-expand-visitor.cc (ExpandVisitor::go): Add call to visit + on the crate. + (ExpandVisitor::visit): Remove some visit functions in favor of their + default visitor counterpart. + * expand/rust-expand-visitor.h (class ExpandVisitor): Inherit from + default visitor and remove now useless function prototypes. + +2024-01-30 Pierre-Emmanuel Patry + + * resolve/rust-default-resolver.cc (DefaultResolver::visit): Remove + duplicated functions. + * resolve/rust-default-resolver.h (class DefaultResolver): Make the + default resolver inherit from the default visitor. + +2024-01-30 Owen Avery + + * checks/errors/rust-feature.cc + (Feature::name_hash_map): + Add entries for Name::LANG_ITEMS and Name::NO_CORE. + * checks/errors/rust-feature.h + (Feature::Name::LANG_ITEMS): New. + (Feature::Name::NO_CORE): New. + +2024-01-30 Kushal Pal + + * backend/rust-compile-base.cc (HIRCompileBase::setup_abi_options): + Renamed `WIN64` to `WIN_64` + * util/rust-abi.cc (get_abi_from_string): Likewise + (get_string_from_abi): Likewise + * util/rust-abi.h (enum ABI): Likewise + +2024-01-30 Nobel Singh + + * checks/errors/rust-ast-validation.cc (ASTValidation::visit): Add + check for const funtion. + +2024-01-30 Pierre-Emmanuel Patry + + * checks/errors/rust-ast-validation.cc (ASTValidation::visit): Add + a validation check and emit an error depending on the context. + +2024-01-30 Pierre-Emmanuel Patry + + * ast/rust-ast-collector.cc (TokenCollector::visit): Adapt defintion + getter. + * ast/rust-ast-visitor.cc (DefaultASTVisitor::visit): Likewise. + * expand/rust-cfg-strip.cc (CfgStrip::visit): Likewise. + * expand/rust-expand-visitor.cc (ExpandVisitor::visit): Likewise. + * hir/rust-ast-lower-implitem.h: Likewise. + * hir/rust-ast-lower-item.cc (ASTLoweringItem::visit): Likewise. + * resolve/rust-ast-resolve-item.cc (ResolveItem::visit): Likewise. + * resolve/rust-ast-resolve-stmt.h: Likewise. + * resolve/rust-default-resolver.cc (DefaultResolver::visit): Likewise. + * util/rust-attributes.cc (AttributeChecker::visit): Likewise. + * parse/rust-parse-impl.h: Allow empty function body during parsing. + * ast/rust-ast.cc (Function::Function): Constructor now take an + optional for the body. + (Function::operator=): Adapt to new optional member. + (Function::as_string): Likewise. + * ast/rust-item.h (class Function): Make body optional and do not + rely on nullptr anymore. + +2024-01-30 Pierre-Emmanuel Patry + + * resolve/rust-early-name-resolver.cc (EarlyNameResolver::resolve_generic_args): + Move function. + (EarlyNameResolver::resolve_qualified_path_type): Likewise. + (EarlyNameResolver::visit): Add a top level visit function for crate + and remove duplicated code. + * resolve/rust-early-name-resolver.h (class EarlyNameResolver): Update + overriden function list. + +2024-01-30 Pierre-Emmanuel Patry + + * util/rust-attributes.cc (AttributeChecker::visit): Add visit function + for crates. + * util/rust-attributes.h (class AttributeChecker): Update function + prototypes. + +2024-01-30 Pierre-Emmanuel Patry + + * checks/errors/rust-feature-gate.cc (FeatureGate::visit): Add a visit + function for the crate level. + (FeatureGate::check): Add call to crate visit. + * checks/errors/rust-feature-gate.h (class FeatureGate): Remove now + useless visit functions (traversal only). + +2024-01-30 Pierre-Emmanuel Patry + + * checks/errors/rust-ast-validation.cc (ASTValidation::visit): Add + const check. + * checks/errors/rust-ast-validation.h: Add visit function prototype. + +2024-01-30 Pierre-Emmanuel Patry + + * checks/errors/rust-ast-validation.cc (ASTValidation::visit): Add + async const check. + +2024-01-30 Pierre-Emmanuel Patry + + * parse/rust-parse-impl.h (Parser::parse_vis_item): Allow parsing async + items in const. + (Parser::parse_async_item): Account for const offset during async + lookahead. + +2024-01-30 Pierre-Emmanuel Patry + + * ast/rust-ast-builder.cc (AstBuilder::fn_qualifiers): Change + constructor to match the new arguments. + * ast/rust-ast-collector.cc (TokenCollector::visit): Change behavior + to handle both const and async specifiers at the same time. + * ast/rust-ast.cc (FunctionQualifiers::as_string): Likewise. + * ast/rust-item.h (class FunctionQualifiers): Remove AsyncConstStatus + and replace it with both Async and Const status. Also change the safety + arguments to use an enum instead of a boolean. + * hir/rust-ast-lower-base.cc (ASTLoweringBase::lower_qualifiers): + Update constructor call. + * hir/tree/rust-hir-item.h: Add Const and Async status, remove + AsyncConstStatus, update the constructor. + * hir/tree/rust-hir.cc (FunctionQualifiers::as_string): Update with + the new status. + * parse/rust-parse-impl.h (Parser::parse_function_qualifiers): Update + constructor call. + * util/rust-common.h (enum Mutability): Make an enum class. + (enum class): Add Async and Const enum class to avoid booleans. + (enum Unsafety): Change to an enum class. + +2024-01-30 Owen Avery + + * ast/rust-ast-full-decls.h + (class InherentImplItem): Remove. + * ast/rust-ast.h + (class InherentImplItem): Remove. + (class SingleASTNode): + Store pointer to AssociatedItem instead of InherentImplItem. + * ast/rust-ast.cc + (SingleASTNode::SingleASTNode): + Use clone_associated_item instead of clone_inherent_impl_item. + (SingleASTNode::operator=): Likewise. + * ast/rust-item.h + (class InherentImpl): + Use AssociatedItem rather than InherentImplItem. + (class Function): Likewise. + (class ConstantItem): Likewise. + * ast/rust-macro.h + (class MacroInvocation): Likewise. + * expand/rust-expand-visitor.cc + (ExpandVisitor::visit): Likewise. + * parse/rust-parse-impl.h + (Parser::parse_impl): Likewise. + (Parser::parse_inherent_impl_item): Likewise. + (Parser::parse_inherent_impl_function_or_method): Likewise. + * parse/rust-parse.h + (Parser::parse_inherent_impl_item): Likewise. + (Parser::parse_inherent_impl_function_or_method): Likewise. + +2024-01-30 Philip Herron + + * backend/rust-compile-base.cc (HIRCompileBase::compile_locals_for_block): removed + * backend/rust-compile-base.h: update header + * backend/rust-compile-block.cc (CompileBlock::visit): remove old logic + * backend/rust-compile-expr.cc (CompileExpr::generate_closure_function): likewise + * backend/rust-compile-stmt.cc (CompileStmt::visit): likewise + * backend/rust-compile-var-decl.h: ensure we setup tuple bindings correctly + +2024-01-30 Pierre-Emmanuel Patry + + * ast/rust-item.h: Add safety getter to modules. + * checks/errors/rust-ast-validation.cc (ASTValidation::visit): Check + a module's safety and emit an error when meeting an unsafe module. + * checks/errors/rust-ast-validation.h: Add function prototype. + * parse/rust-parse-impl.h (Parser::parse_module): Move the module locus + to the first token instead of the mod keyword. + +2024-01-30 Pierre-Emmanuel Patry + + * parse/rust-parse-impl.h (Parser::parse_vis_item): Dispatch to parse + module when meeting an unsafe module. + (Parser::parse_module): Set unsafe status when the parser encounter an + unsafe keyword. + +2024-01-30 Pierre-Emmanuel Patry + + * ast/rust-item.h: Add safety status to Modules in the AST. + * parse/rust-parse-impl.h (Parser::parse_module): Adapt constructors. + +2024-01-30 Owen Avery + + * hir/tree/rust-hir-pattern.h + (class TupleItems): New. + (class TupleStructItems): Inherit from TupleItems. + (class TuplePatternItems): Likewise. + +2024-01-30 Arthur Cohen + + * resolve/rust-toplevel-name-resolver-2.0.cc + (TopLevel::insert_or_error_out): New functions. + (TopLevel::handle_use_dec): New function. + (flatten_rebind): Likewise. + (flatten_list): Likewise. + (flatten_glob): Likewise. + (flatten): Likewise. + (TopLevel::visit): Visit various `use` declaration nodes. + * resolve/rust-toplevel-name-resolver-2.0.h: Declare functions and + visitors. + +2024-01-30 Arthur Cohen + + * resolve/rust-early-name-resolver-2.0.cc + (Early::visit): Remove visitors. + * resolve/rust-early-name-resolver-2.0.h: Likewise. + +2024-01-30 Arthur Cohen + + * ast/rust-item.h (class UseTree): Add `node_id` member. + +2024-01-30 Arthur Cohen + + * resolve/rust-toplevel-name-resolver-2.0.cc + (TopLevel::insert_or_error_out): Add documentation comment. + (TopLevel::go): Likewise. + +2024-01-30 Arthur Cohen + + * resolve/rust-early-name-resolver-2.0.cc + (Early::insert_once): New function. + (Early::visit): Likewise. + * resolve/rust-early-name-resolver-2.0.h: Likewise. + +2024-01-30 Arthur Cohen + + * resolve/rust-late-name-resolver-2.0.cc (Late::visit): Store mappings + after having resolved them. + * resolve/rust-late-name-resolver-2.0.h: Add `TypePath` visitor. + +2024-01-30 Arthur Cohen + + * resolve/rust-late-name-resolver-2.0.cc + (Late::setup_builtin_types): New function. + (Late::go): Setup builtin types. + * resolve/rust-late-name-resolver-2.0.h: + * resolve/rust-name-resolution-context.cc + (NameResolutionContext::map_usage): New function. + * resolve/rust-name-resolution-context.h: Likewise. + +2024-01-30 Arthur Cohen + + * resolve/rust-name-resolution-context.h: Store a reference to the + mappings. + * resolve/rust-name-resolution-context.cc + (NameResolutionContext::NameResolutionContext): Likewise. + +2024-01-30 Arthur Cohen + + * resolve/rust-toplevel-name-resolver-2.0.cc (TopLevel::visit): Use + the DefaultResolver in the toplevel visitor. + +2024-01-30 Arthur Cohen + + * Make-lang.in: Compile late name resolver. + * resolve/rust-late-name-resolver-2.0.cc: New file. + * resolve/rust-late-name-resolver-2.0.h: New file. + +2024-01-30 Arthur Cohen + + * resolve/rust-name-resolution-context.h: Add a Labels stack. + +2024-01-30 M V V S Manoj Kumar + + * parse/rust-parse-impl.h (Parser::parse_item): Likewise. + (Parser::parse_vis_item): Likewise. + (Parser::parse_async_item): Likewise. + * parse/rust-parse.h: Made declaration for parse_async_item. + +2024-01-30 Pierre-Emmanuel Patry + + * lex/rust-lex.cc (Lexer::classify_keyword): Update keyword map name. + * lex/rust-token.h (enum PrimitiveCoreType): Remove some deprecated + comments. + * util/rust-keyword-values.cc (get_keywords): Update the keyword map + name. + (RS_TOKEN): Define as empty + (RS_TOKEN_KEYWORD_2015): Add the emission value. + (RS_TOKEN_KEYWORD_2018): Likewise. + * util/rust-keyword-values.h (RS_KEYWORD_LIST): Introduce the keyword + list. + (RS_TOKEN_KEYWORD_2018): Define multiple new keywords. + +2024-01-30 Pierre-Emmanuel Patry + + * ast/rust-ast-collector.cc (TokenCollector::visit): Replace raw value. + * parse/rust-parse-impl.h (Parser::is_macro_rules_def): Likewise. + (Parser::parse_item): Likewise. + (Parser::parse_vis_item): Likewise. + (Parser::parse_macro_rules_def): Likewise. + (Parser::parse_union): Likewise. + (Parser::parse_trait_impl_item): Likewise. + (Parser::parse_stmt): Likewise. + (Parser::parse_stmt_or_expr): Likewise. + +2024-01-30 Pierre-Emmanuel Patry + + * util/rust-keyword-values.h (class WeakKeywords): Add new class with + weak keyword constexpr. + +2024-01-30 Pierre-Emmanuel Patry + + * ast/rust-ast-collector.cc (TokenCollector::visit): Replace raw value + with keyword call. + * ast/rust-ast.h: Likewise. + * parse/rust-parse-impl.h (Parser::parse_path_ident_segment): Likewise. + (Parser::parse_macro_match_fragment): Likewise. + (Parser::parse_extern_crate): Likewise. + (Parser::parse_use_tree): Likewise. + (Parser::parse_const_item): Likewise. + (Parser::parse_literal_expr): Likewise. + (Parser::parse_maybe_named_param): Likewise. + (Parser::parse_pattern_no_alt): Likewise. + (Parser::left_denotation): Likewise. + (Parser::parse_path_in_expression_pratt): Likewise. + +2024-01-30 Pierre-Emmanuel Patry + + * lex/rust-token.h (enum PrimitiveCoreType): Add await keyword + definition. + +2024-01-30 Pierre-Emmanuel Patry + + * lex/rust-token.h (enum PrimitiveCoreType): Change macro for + underscore in token list. + +2024-01-30 Pierre-Emmanuel Patry + + * lex/rust-token.h (enum PrimitiveCoreType): Change enum macro calls. + (RS_TOKEN_KEYWORD): Remove generic token keyword macro. + (RS_TOKEN_KEYWORD_2015): Introduce keywords for edition 2015. + (RS_TOKEN_KEYWORD_2018): Likewise with edition 2018. + * lex/rust-token.cc (RS_TOKEN_KEYWORD): Remove old macro definition. + (RS_TOKEN_KEYWORD_2015): Replace with 2015 definition... + (RS_TOKEN_KEYWORD_2018): ... and 2018 definition. + * util/rust-keyword-values.cc (RS_TOKEN_KEYWORD): Likewise. + (RS_TOKEN_KEYWORD_2015): Likewise. + (RS_TOKEN_KEYWORD_2018): Likewise. + * util/rust-keyword-values.h (RS_TOKEN_KEYWORD): Likewise. + (RS_TOKEN_KEYWORD_2015): Likewise. + (RS_TOKEN_KEYWORD_2018): Likewise. + +2024-01-30 Pierre-Emmanuel Patry + + * lex/rust-token.h (enum PrimitiveCoreType): Change keyword suffix from + tok to kw. + * ast/rust-ast-collector.cc (TokenCollector::visit): Update suffix to + match the new declaration. + * lex/rust-lex.cc (Lexer::parse_raw_identifier): Likewise. + * parse/rust-parse-impl.h (can_tok_start_type): Likewise. + (Parser::parse_item): Likewise. + (Parser::parse_vis_item): Likewise. + (Parser::parse_extern_crate): Likewise. + (Parser::parse_function): Likewise. + (Parser::parse_function_qualifiers): Likewise. + (Parser::parse_struct): Likewise. + (Parser::parse_enum): Likewise. + (Parser::parse_static_item): Likewise. + (Parser::parse_trait_item): Likewise. + (Parser::parse_inherent_impl_item): Likewise. + (Parser::parse_trait_impl_item): Likewise. + (Parser::parse_extern_block): Likewise. + (Parser::parse_external_item): Likewise. + (Parser::parse_stmt): Likewise. + (Parser::parse_return_expr): Likewise. + (Parser::parse_match_expr): Likewise. + (Parser::parse_type): Likewise. + (Parser::parse_for_prefixed_type): Likewise. + (Parser::parse_type_no_bounds): Likewise. + (Parser::parse_stmt_or_expr): Likewise. + * parse/rust-parse.cc (peculiar_fragment_match_compatible): Likewie. + * util/rust-token-converter.cc (convert): Likewise. + +2024-01-30 Pierre-Emmanuel Patry + + * checks/errors/rust-ast-validation.cc (ASTValidation::visit): Add + zero field check during ast validation pass. + * checks/errors/rust-ast-validation.h: Add union visit function + prototype. + +2024-01-30 Pierre-Emmanuel Patry + + * checks/errors/rust-ast-validation.cc (ASTValidation::visit): Add + ast validation pass to reject variadic arguments on regular functions. + +2024-01-30 Pierre-Emmanuel Patry + + * checks/errors/rust-ast-validation.cc (ASTValidation::visit): Add auto + trait associated item check in AST validation pass. + * parse/rust-parse-impl.h: Remove old error emission done during + parsing pass. + +2024-01-30 Pierre-Emmanuel Patry + + * checks/errors/rust-ast-validation.cc (ASTValidation::visit): Reject + auto traits with super traits. + +2024-01-30 Pierre-Emmanuel Patry + + * checks/errors/rust-ast-validation.cc (ASTValidation::visit): Add + check for generics on auto traits. + * checks/errors/rust-ast-validation.h: Add visit function prototype. + +2024-01-30 Arthur Cohen + + * resolve/rust-forever-stack.hxx: Remove debug log. + +2024-01-30 Arthur Cohen + + * resolve/rust-ast-resolve-path.cc (ResolvePath::resolve_path): Format. + +2024-01-30 Arthur Cohen + + * resolve/rust-forever-stack.h: New method. + * resolve/rust-forever-stack.hxx: Likewise. + +2024-01-30 Arthur Cohen + + * resolve/rust-forever-stack.h: New method. + * resolve/rust-forever-stack.hxx: Likewise. + +2024-01-30 Arthur Cohen + + * resolve/rust-forever-stack.hxx: Do not copy segment when + dereferencing iterator in `find_starting_point`. + +2024-01-30 Arthur Cohen + + * resolve/rust-forever-stack.h: Fix `ForeverStack::resolve_path` + signature. + * resolve/rust-forever-stack.hxx: Likewise. + * resolve/rust-early-name-resolver-2.0.cc (Early::visit): Use new API. + (Early::visit_attributes): Likewise. + +2024-01-30 Arthur Cohen + + * resolve/rust-forever-stack.hxx: Add specific behavior for + `ForeverStack::get` when dealing with labels. + +2024-01-30 Arthur Cohen + + * resolve/rust-forever-stack.h: Improve resolve_path API. + * resolve/rust-forever-stack.hxx: Likewise and fix implementation. + +2024-01-30 Arthur Cohen + + * resolve/rust-rib.h: Add Namespace enum. + +2024-01-30 Arthur Cohen + + * ast/rust-ast.h: Change Path API to be more consistent. + * ast/rust-path.h: Likewise. + * ast/rust-ast-collector.cc (TokenCollector::visit): Use new API. + * resolve/rust-ast-resolve-item.cc (ResolveItem::visit): Likewise. + * resolve/rust-ast-resolve-path.cc (ResolvePath::resolve_path): Likewise. + * resolve/rust-forever-stack.hxx: Likewise. + +2024-01-30 Pierre-Emmanuel Patry + + * parse/rust-parse-impl.h (Parser::parse_function): Early return on + unrecoverable errors. + (Parser::parse_trait_item): Likewise. + (Parser::parse_self_param): Update return type. + * parse/rust-parse.h (enum ParseSelfError): Add enumeration to describe + different self parameter parsing errors. + +2024-01-30 Pierre-Emmanuel Patry + + * parse/rust-parse-impl.h (Parser::parse_self_param): Fix the loop + exit condition. + +2024-01-30 Pierre-Emmanuel Patry + + * ast/rust-item.h (struct Visibility): Move Visibility from here... + * ast/rust-ast.h (struct Visibility): ...to here. + * parse/rust-parse-impl.h (Parser::parse_trait_item): Parse visibility + before giving it back to the item parsing function. + (Parser::parse_trait_type): Add visibility modifier. + * parse/rust-parse.h (RUST_PARSE_H): Change function prototype. + 2024-01-18 Arthur Cohen * backend/rust-compile-base.cc (HIRCompileBase::resolve_method_address): diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index 512d3ce..532d623 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,258 @@ +2024-01-30 Fangrui Song + + PR target/105576 + * gcc.target/i386/asm-raw-symbol.c: New testcase. + +2024-01-30 Marek Polacek + + PR c++/110358 + PR c++/109640 + * g++.dg/warn/Wdangling-reference18.C: New test. + * g++.dg/warn/Wdangling-reference19.C: New test. + * g++.dg/warn/Wdangling-reference20.C: New test. + +2024-01-30 Patrick Palka + + PR c++/67898 + * g++.dg/cpp0x/temp_default8.C: New test. + +2024-01-30 Jason Merrill + + PR c++/112846 + * g++.dg/abi/anon6.C: Specify ABI v18. + * g++.dg/abi/anon6a.C: New test for ABI v19. + +2024-01-30 Jason Merrill + + PR c++/113451 + * g++.dg/abi/mangle-regparm1a.C: Use -Wabi=0. + +2024-01-30 Patrick Palka + + PR c++/113640 + * g++.dg/cpp23/explicit-obj-lambda14.C: New test. + +2024-01-30 Patrick Palka + + PR c++/113644 + * g++.dg/template/nontype30.C: New test. + +2024-01-30 Pan Li + + * gcc.target/riscv/rvv/autovec/vls/def.h: Add new helper macro. + * gcc.target/riscv/rvv/autovec/vls/calling-convention-1.c: New test. + * gcc.target/riscv/rvv/autovec/vls/calling-convention-10.c: New test. + * gcc.target/riscv/rvv/autovec/vls/calling-convention-2.c: New test. + * gcc.target/riscv/rvv/autovec/vls/calling-convention-3.c: New test. + * gcc.target/riscv/rvv/autovec/vls/calling-convention-4.c: New test. + * gcc.target/riscv/rvv/autovec/vls/calling-convention-5.c: New test. + * gcc.target/riscv/rvv/autovec/vls/calling-convention-6.c: New test. + * gcc.target/riscv/rvv/autovec/vls/calling-convention-7.c: New test. + * gcc.target/riscv/rvv/autovec/vls/calling-convention-8.c: New test. + * gcc.target/riscv/rvv/autovec/vls/calling-convention-9.c: New test. + * gcc.target/riscv/rvv/autovec/vls/calling-convention-run-1.c: New test. + * gcc.target/riscv/rvv/autovec/vls/calling-convention-run-2.c: New test. + * gcc.target/riscv/rvv/autovec/vls/calling-convention-run-3.c: New test. + * gcc.target/riscv/rvv/autovec/vls/calling-convention-run-4.c: New test. + * gcc.target/riscv/rvv/autovec/vls/calling-convention-run-5.c: New test. + * gcc.target/riscv/rvv/autovec/vls/calling-convention-run-6.c: New test. + +2024-01-30 David Malcolm + + PR analyzer/113654 + * c-c++-common/analyzer/allocation-size-pr113654-1.c: New test. + +2024-01-30 Arthur Cohen + + * rust/execute/torture/builtin_macros1.rs: Fix output pattern. + * rust/execute/torture/coercion3.rs: Likewise. + * rust/execute/torture/issue-2080.rs: Likewise. + * rust/execute/torture/issue-2179.rs: Likewise. + * rust/execute/torture/issue-2180.rs: Likewise. + * rust/execute/torture/iter1.rs: Likewise. + +2024-01-30 Robert Goss + + * rust/compile/missing_constructor_fields.rs: Added case with no initializers + +2024-01-30 Jakub Dupak + + * rust/compile/for_lifetimes.rs: New test. + +2024-01-30 Jakub Dupak + + * rust/compile/torture/utf8_identifiers.rs: add mising lifetime + +2024-01-30 Robert Goss + + * rust/compile/repeated_constructor_fields.rs: Added case with constructor field repeated + +2024-01-30 Kushal Pal + + * rust/compile/issue-2788.rs: New test. + +2024-01-30 Kushal Pal + + * rust/compile/const_trait_fn.rs: + Enclose const in single quotes. + +2024-01-30 Kushal Pal + + * rust/compile/issue-2785.rs: New test. + +2024-01-30 Nirmal Patel + + * rust/compile/issue-2187.rs: New file. + * rust/execute/torture/issue-2187.rs: New file. + +2024-01-30 Kushal Pal + + * rust/compile/issue-2767.rs: New test. + +2024-01-30 Arthur Cohen + + * rust/compile/torture/intrinsics-4.rs: Adjust. + * rust/compile/torture/intrinsics-math.rs: Adjust. + * rust/execute/torture/atomic_load.rs: Adjust. + * rust/execute/torture/atomic_store.rs: Adjust. + * rust/compile/torture/intrinsics-1.rs: Removed. + * rust/compile/torture/builtin_abort.rs: New test. + * rust/execute/torture/builtin_abort.rs: New test. + +2024-01-30 Owen Avery + + * rust/compile/sized-stub.rs: New test. + +2024-01-30 Nobel Singh + + * rust/compile/issue-2040.rs: New test. + +2024-01-30 Pierre-Emmanuel Patry + + * rust/compile/functions_without_body.rs: New test. + +2024-01-30 Pierre-Emmanuel Patry + + * rust/execute/torture/name_resolution.rs: New test. + +2024-01-30 Pierre-Emmanuel Patry + + * rust/compile/name_resolution11.rs: New test. + * rust/compile/name_resolution12.rs: New test. + * rust/compile/name_resolution13.rs: New test. + +2024-01-30 Pierre-Emmanuel Patry + + * rust/compile/const_trait_fn.rs: New test. + +2024-01-30 Pierre-Emmanuel Patry + + * rust/compile/const_async_function.rs: New test. + +2024-01-30 Pierre-Emmanuel Patry + + * rust/compile/unsafe_module.rs: New test. + +2024-01-30 M V V S Manoj Kumar + + * rust/compile/issue-2650-1.rs: New test.(edition=2018) + * rust/compile/issue-2650-2.rs: New test.(edition=2015) + +2024-01-30 Pierre-Emmanuel Patry + + * rust/compile/const_generics_8.rs: Fill the union with dummy values. + * rust/compile/empty_union.rs: New test. + +2024-01-30 Pierre-Emmanuel Patry + + * rust/compile/non_foreign_variadic_function.rs: New test. + +2024-01-30 Pierre-Emmanuel Patry + + * rust/compile/auto_trait_invalid.rs: Update old test with updated + error message. + +2024-01-30 Pierre-Emmanuel Patry + + * rust/compile/auto_trait_super_trait.rs: New test. + +2024-01-30 Pierre-Emmanuel Patry + + * rust/compile/generic_auto_trait.rs: New test. + +2024-01-30 Pierre-Emmanuel Patry + + * rust/compile/self_const_ptr.rs: New test. + * rust/compile/self_mut_ptr.rs: New test. + * rust/compile/self_ptr.rs: New test. + +2024-01-30 Pierre-Emmanuel Patry + + * rust/compile/trait_pub_type.rs: New test. + +2024-01-30 Richard Biener + + PR tree-optimization/113659 + * gcc.dg/pr113659.c: New testcase. + +2024-01-30 Iain Sandoe + + PR target/112861 + * lib/gdc.exp: Decide on whether to present -B or -L to reference + the paths to uninstalled libphobos and libstdc++ and use that to + generate the link flags. + +2024-01-30 Richard Sandiford + + PR target/113623 + * gcc.c-torture/compile/pr113623.c: New test. + +2024-01-30 Richard Sandiford + + PR target/113636 + * go.dg/pr113636.go: New test. + +2024-01-30 Jakub Jelinek + + PR tree-optimization/113603 + * gcc.c-torture/compile/pr113603.c: New test. + +2024-01-30 Jakub Jelinek + + PR middle-end/101195 + * gcc.dg/pr101195.c: New test. + +2024-01-30 Jakub Jelinek + + PR middle-end/113622 + * gcc.target/i386/pr113622-2.c: Use -msse2 instead of -msse in + dg-options. + * gcc.target/i386/pr113622-3.c: Likewise. + +2024-01-30 Alexandre Oliva + + Revert: + 2023-12-26 David Edelsohn + + * c-c++-common/strub-unsupported-2.c: Require strub. + * c-c++-common/strub-unsupported-3.c: Same. + * c-c++-common/strub-unsupported.c: Same. + * lib/target-supports.exp (check_effective_target_strub): Return 0 + for AIX. + +2024-01-30 H.J. Lu <(no_default)> + + * gcc.target/i386/libcall-1.c: Limit to lp64 target. + * gcc.target/i386/pr107057.c: Likewise. + +2024-01-30 Juzhe-Zhong + + * gcc.target/riscv/rvv/autovec/binop/shift-rv32gcv.c: Adapt test. + * gcc.target/riscv/rvv/autovec/binop/shift-rv64gcv.c: Ditto. + * gcc.target/riscv/rvv/autovec/vls/mod-1.c: Ditto. + * gcc.target/riscv/rvv/autovec/vls/shift-1.c: Ditto. + * gcc.target/riscv/rvv/autovec/vls/shift-2.c: Ditto. + 2024-01-29 Alexandre Oliva * lib/target-supports.exp (check_effective_target_shared): -- cgit v1.1 From 9dd10de15b183f7b662905e1383fdc3a08755f2e Mon Sep 17 00:00:00 2001 From: Juzhe-Zhong Date: Mon, 29 Jan 2024 19:32:02 +0800 Subject: RISC-V: Fix VSETLV PASS compile-time issue The compile time issue was discovered in SPEC 2017 wrf: Use time and -ftime-report to analyze the profile data of SPEC 2017 wrf compilation . Before this patch (Lazy vsetvl): scheduling : 121.89 ( 15%) 0.53 ( 11%) 122.72 ( 15%) 13M ( 1%) machine dep reorg : 424.61 ( 53%) 1.84 ( 37%) 427.44 ( 53%) 5290k ( 0%) real 13m27.074s user 13m19.539s sys 0m5.180s Simple vsetvl: machine dep reorg : 0.10 ( 0%) 0.00 ( 0%) 0.11 ( 0%) 4138k ( 0%) real 6m5.780s user 6m2.396s sys 0m2.373s The machine dep reorg is the compile time of VSETVL PASS (424 seconds) which counts 53% of the compilation time, spends much more time than scheduling. After investigation, the critical patch of VSETVL pass is compute_lcm_local_properties which is called every iteration of phase 2 (earliest fusion) and phase 3 (global lcm). This patch optimized the codes of compute_lcm_local_properties to reduce the compilation time. After this patch: scheduling : 117.51 ( 27%) 0.21 ( 6%) 118.04 ( 27%) 13M ( 1%) machine dep reorg : 80.13 ( 18%) 0.91 ( 26%) 81.26 ( 18%) 5290k ( 0%) real 7m25.374s user 7m20.116s sys 0m3.795s The optimization of this patch is very obvious, lazy VSETVL PASS: 424s (53%) -> 80s (18%) which spend less time than scheduling. Tested on both RV32 and RV64 no regression. Ok for trunk ? PR target/113495 gcc/ChangeLog: * config/riscv/riscv-vsetvl.cc (extract_single_source): Remove. (pre_vsetvl::compute_vsetvl_def_data): Fix compile time issue. (pre_vsetvl::compute_transparent): New function. (pre_vsetvl::compute_lcm_local_properties): Fix compile time time issue. --- gcc/config/riscv/riscv-vsetvl.cc | 184 +++++++++++++-------------------------- 1 file changed, 60 insertions(+), 124 deletions(-) (limited to 'gcc') diff --git a/gcc/config/riscv/riscv-vsetvl.cc b/gcc/config/riscv/riscv-vsetvl.cc index d7b40a5..cec8623 100644 --- a/gcc/config/riscv/riscv-vsetvl.cc +++ b/gcc/config/riscv/riscv-vsetvl.cc @@ -599,14 +599,6 @@ extract_single_source (set_info *set) return first_insn; } -static insn_info * -extract_single_source (def_info *def) -{ - if (!def) - return nullptr; - return extract_single_source (dyn_cast (def)); -} - static bool same_equiv_note_p (set_info *set1, set_info *set2) { @@ -2374,6 +2366,7 @@ public: } void compute_vsetvl_def_data (); + void compute_transparent (const bb_info *); void compute_lcm_local_properties (); void fuse_local_vsetvl_info (); @@ -2452,20 +2445,16 @@ pre_vsetvl::compute_vsetvl_def_data () { for (unsigned i = 0; i < m_vsetvl_def_exprs.length (); i += 1) { - const vsetvl_info &info = *m_vsetvl_def_exprs[i]; - if (!info.has_nonvlmax_reg_avl ()) - continue; - unsigned int regno; - sbitmap_iterator sbi; - EXECUTE_IF_SET_IN_BITMAP (m_reg_def_loc[bb->index ()], 0, regno, - sbi) - if (regno == REGNO (info.get_avl ())) - { - bitmap_set_bit (m_kill[bb->index ()], i); - bitmap_set_bit (def_loc[bb->index ()], - get_expr_index (m_vsetvl_def_exprs, - m_unknow_info)); - } + auto *info = m_vsetvl_def_exprs[i]; + if (info->has_nonvlmax_reg_avl () + && bitmap_bit_p (m_reg_def_loc[bb->index ()], + REGNO (info->get_avl ()))) + { + bitmap_set_bit (m_kill[bb->index ()], i); + bitmap_set_bit (def_loc[bb->index ()], + get_expr_index (m_vsetvl_def_exprs, + m_unknow_info)); + } } continue; } @@ -2516,6 +2505,36 @@ pre_vsetvl::compute_vsetvl_def_data () sbitmap_vector_free (m_kill); } +/* Subroutine of compute_lcm_local_properties which Compute local transparent + BB. Note that the compile time is very sensitive to compute_transparent and + compute_lcm_local_properties, any change of these 2 functions should be + aware of the compile time changing of the program which has a large number of + blocks, e.g SPEC 2017 wrf. + + Current compile time profile of SPEC 2017 wrf: + + 1. scheduling - 27% + 2. machine dep reorg (VSETVL PASS) - 18% + + VSETVL pass should not spend more time than scheduling in compilation. */ +void +pre_vsetvl::compute_transparent (const bb_info *bb) +{ + int num_exprs = m_exprs.length (); + unsigned bb_index = bb->index (); + for (int i = 0; i < num_exprs; i++) + { + auto *info = m_exprs[i]; + if (info->has_nonvlmax_reg_avl () + && bitmap_bit_p (m_reg_def_loc[bb_index], REGNO (info->get_avl ()))) + bitmap_clear_bit (m_transp[bb_index], i); + else if (info->has_vl () + && bitmap_bit_p (m_reg_def_loc[bb_index], + REGNO (info->get_vl ()))) + bitmap_clear_bit (m_transp[bb_index], i); + } +} + /* Compute the local properties of each recorded expression. Local properties are those that are defined by the block, irrespective of @@ -2572,7 +2591,7 @@ pre_vsetvl::compute_lcm_local_properties () bitmap_vector_clear (m_avloc, last_basic_block_for_fn (cfun)); bitmap_vector_clear (m_antloc, last_basic_block_for_fn (cfun)); - bitmap_vector_clear (m_transp, last_basic_block_for_fn (cfun)); + bitmap_vector_ones (m_transp, last_basic_block_for_fn (cfun)); /* - If T is locally available at the end of a block, then T' must be available at the end of the same block. Since some optimization has @@ -2598,117 +2617,34 @@ pre_vsetvl::compute_lcm_local_properties () /* Compute m_transp */ if (block_info.empty_p ()) + compute_transparent (bb); + else { - bitmap_ones (m_transp[bb_index]); - for (int i = 0; i < num_exprs; i += 1) - { - const vsetvl_info &info = *m_exprs[i]; - if (!info.has_nonvlmax_reg_avl () && !info.has_vl ()) - continue; - - if (info.has_nonvlmax_reg_avl ()) - { - unsigned int regno; - sbitmap_iterator sbi; - EXECUTE_IF_SET_IN_BITMAP (m_reg_def_loc[bb->index ()], 0, - regno, sbi) - { - if (regno == REGNO (info.get_avl ())) - bitmap_clear_bit (m_transp[bb->index ()], i); - } - } - - for (insn_info *insn : bb->real_nondebug_insns ()) - { - if (info.has_nonvlmax_reg_avl () - && find_access (insn->defs (), REGNO (info.get_avl ()))) - { - bitmap_clear_bit (m_transp[bb_index], i); - break; - } - - if (info.has_vl () - && reg_mentioned_p (info.get_vl (), insn->rtl ())) - { - if (find_access (insn->defs (), REGNO (info.get_vl ()))) - /* We can't fuse vsetvl into the blocks that modify the - VL operand since successors of such blocks will need - the value of those blocks are defining. - - bb 4: def a5 - / \ - bb 5:use a5 bb 6:vsetvl a5, 5 - - The example above shows that we can't fuse vsetvl - from bb 6 into bb 4 since the successor bb 5 is using - the value defined in bb 4. */ - ; - else - { - /* We can't fuse vsetvl into the blocks that use the - VL operand which has different value from the - vsetvl info. - - bb 4: def a5 - | - bb 5: use a5 - | - bb 6: def a5 - | - bb 7: use a5 - - The example above shows that we can't fuse vsetvl - from bb 6 into bb 5 since their value is different. - */ - resource_info resource - = full_register (REGNO (info.get_vl ())); - def_lookup dl = crtl->ssa->find_def (resource, insn); - def_info *def - = dl.matching_set_or_last_def_of_prev_group (); - insn_info *def_insn = extract_single_source (def); - if (def_insn && vsetvl_insn_p (def_insn->rtl ())) - { - vsetvl_info def_info = vsetvl_info (def_insn); - if (m_dem.compatible_p (def_info, info)) - continue; - } - } + bitmap_clear (m_transp[bb_index]); + vsetvl_info &header_info = block_info.get_entry_info (); + vsetvl_info &footer_info = block_info.get_exit_info (); - bitmap_clear_bit (m_transp[bb_index], i); - break; - } - } - } + if (header_info.valid_p () && anticipated_exp_p (header_info)) + bitmap_set_bit (m_antloc[bb_index], + get_expr_index (m_exprs, header_info)); - continue; + if (footer_info.valid_p ()) + for (int i = 0; i < num_exprs; i += 1) + { + const vsetvl_info &info = *m_exprs[i]; + if (!info.valid_p ()) + continue; + if (available_exp_p (footer_info, info)) + bitmap_set_bit (m_avloc[bb_index], i); + } } - vsetvl_info &header_info = block_info.get_entry_info (); - vsetvl_info &footer_info = block_info.get_exit_info (); - - if (header_info.valid_p () && anticipated_exp_p (header_info)) - bitmap_set_bit (m_antloc[bb_index], - get_expr_index (m_exprs, header_info)); - - if (footer_info.valid_p ()) - for (int i = 0; i < num_exprs; i += 1) - { - const vsetvl_info &info = *m_exprs[i]; - if (!info.valid_p ()) - continue; - if (available_exp_p (footer_info, info)) - bitmap_set_bit (m_avloc[bb_index], i); - } - } - - for (const bb_info *bb : crtl->ssa->bbs ()) - { - unsigned bb_index = bb->index (); if (invalid_opt_bb_p (bb->cfg_bb ())) { bitmap_clear (m_antloc[bb_index]); bitmap_clear (m_transp[bb_index]); } + /* Compute ae_kill for each basic block using: ~(TRANSP | COMP) -- cgit v1.1 From 18aabe7d203aa1276e6cbacfb3ffc8d8fcb14966 Mon Sep 17 00:00:00 2001 From: David Malcolm Date: Tue, 30 Jan 2024 20:06:31 -0500 Subject: analyzer: handle null "var" in state_change_event::get_desc [PR113509] Avoid ICE with -fanalyzer-verbose-state-changes when region_model::get_representative_tree returns nullptr in state_change_event::get_desc. gcc/analyzer/ChangeLog: PR analyzer/113509 * checker-event.cc (state_change_event::get_desc): Don't assume "var" is non-NULL. gcc/testsuite/ChangeLog: PR analyzer/113509 * c-c++-common/analyzer/stdarg-pr113509.c: New test. Signed-off-by: David Malcolm --- gcc/analyzer/checker-event.cc | 59 +++++++++++++++------- .../c-c++-common/analyzer/stdarg-pr113509.c | 8 +++ 2 files changed, 49 insertions(+), 18 deletions(-) create mode 100644 gcc/testsuite/c-c++-common/analyzer/stdarg-pr113509.c (limited to 'gcc') diff --git a/gcc/analyzer/checker-event.cc b/gcc/analyzer/checker-event.cc index 3ff3aea..b64c58e 100644 --- a/gcc/analyzer/checker-event.cc +++ b/gcc/analyzer/checker-event.cc @@ -443,25 +443,48 @@ state_change_event::get_desc (bool can_colorize) const meaning.dump_to_pp (&meaning_pp); /* Append debug version. */ - if (m_origin) - return make_label_text - (can_colorize, - "%s (state of %qE: %qs -> %qs, origin: %qE, meaning: %s)", - custom_desc.get (), - var, - m_from->get_name (), - m_to->get_name (), - origin, - pp_formatted_text (&meaning_pp)); + if (var) + { + if (m_origin) + return make_label_text + (can_colorize, + "%s (state of %qE: %qs -> %qs, origin: %qE, meaning: %s)", + custom_desc.get (), + var, + m_from->get_name (), + m_to->get_name (), + origin, + pp_formatted_text (&meaning_pp)); + else + return make_label_text + (can_colorize, + "%s (state of %qE: %qs -> %qs, NULL origin, meaning: %s)", + custom_desc.get (), + var, + m_from->get_name (), + m_to->get_name (), + pp_formatted_text (&meaning_pp)); + } else - return make_label_text - (can_colorize, - "%s (state of %qE: %qs -> %qs, NULL origin, meaning: %s)", - custom_desc.get (), - var, - m_from->get_name (), - m_to->get_name (), - pp_formatted_text (&meaning_pp)); + { + if (m_origin) + return make_label_text + (can_colorize, + "%s (state: %qs -> %qs, origin: %qE, meaning: %s)", + custom_desc.get (), + m_from->get_name (), + m_to->get_name (), + origin, + pp_formatted_text (&meaning_pp)); + else + return make_label_text + (can_colorize, + "%s (state: %qs -> %qs, NULL origin, meaning: %s)", + custom_desc.get (), + m_from->get_name (), + m_to->get_name (), + pp_formatted_text (&meaning_pp)); + } } else return custom_desc; diff --git a/gcc/testsuite/c-c++-common/analyzer/stdarg-pr113509.c b/gcc/testsuite/c-c++-common/analyzer/stdarg-pr113509.c new file mode 100644 index 0000000..5534808 --- /dev/null +++ b/gcc/testsuite/c-c++-common/analyzer/stdarg-pr113509.c @@ -0,0 +1,8 @@ +/* Regression test for ICE with -fanalyzer-verbose-state-changes. */ + +/* { dg-additional-options " -fanalyzer-verbose-state-changes" } */ + +__builtin_va_list FOO_showfatal_ap; +void FOO_showfatal(char fmta, ...) { + __builtin_va_start(FOO_showfatal_ap, fmta); /* { dg-message "'va_start' called here" } */ +} /* { dg-warning "missing call to 'va_end'" } */ -- cgit v1.1 From 35de88e2ed0aa78f6e3306c8560cd6bb15ce0ffe Mon Sep 17 00:00:00 2001 From: Joseph Myers Date: Wed, 31 Jan 2024 01:24:21 +0000 Subject: c: Fix ICEs casting expressions with integer constant operands to bool [PR111059, PR111911] C front-end bugs 111059 and 111911 both report ICEs with conversions to boolean of expressions with integer constant operands that can appear in an integer constant expression as long as they are not evaluated (such as division by zero). The issue is a nested C_MAYBE_CONST_EXPR, with the inner one generated in build_binary_op to indicate that a subexpression has been fully folded and should not be folded again, and the outer one in build_c_cast to indicate that the expression has integer constant operands. To avoid the inner one from build_binary_op, c_objc_common_truthvalue_conversion should be given an argument properly marked as having integer constant operands rather than that information having been removed by the caller - but because c_convert would then also wrap a C_MAYBE_CONST_EXPR with a NOP_EXPR converting to boolean, it seems most convenient to have c_objc_common_truthvalue_conversion produce the NE_EXPR directly in the desired type (boolean in this case), before generating any C_MAYBE_CONST_EXPR there, rather than it always producing a comparison in integer_type_node and doing a conversion to boolean in the caller. The same issue as in those PRs also applies for conversion to enums with a boolean fixed underlying type; that case is also fixed and tests added for it. Note that not all the tests added failed before the patch (in particular, the issue was specific to casts and did not apply for implicit conversions, but some tests of those are added as well). Bootstrapped with no regressions for x86_64-pc-linux-gnu. PR c/111059 PR c/111911 gcc/c/ * c-tree.h (c_objc_common_truthvalue_conversion): Add third argument. * c-convert.cc (c_convert): For conversions to boolean, pass third argument to c_objc_common_truthvalue_conversion rather than converting here. * c-typeck.cc (build_c_cast): Ensure arguments with integer operands are marked as such for conversion to boolean. (c_objc_common_truthvalue_conversion): Add third argument TYPE. gcc/testsuite/ * gcc.c-torture/compile/pr111059-1.c, gcc.c-torture/compile/pr111059-2.c, gcc.c-torture/compile/pr111059-3.c, gcc.c-torture/compile/pr111059-4.c, gcc.c-torture/compile/pr111059-5.c, gcc.c-torture/compile/pr111059-6.c, gcc.c-torture/compile/pr111059-7.c, gcc.c-torture/compile/pr111059-8.c, gcc.c-torture/compile/pr111059-9.c, gcc.c-torture/compile/pr111059-10.c, gcc.c-torture/compile/pr111059-11.c, gcc.c-torture/compile/pr111059-12.c, gcc.c-torture/compile/pr111911-1.c, gcc.c-torture/compile/pr111911-2.c: New tests. --- gcc/c/c-convert.cc | 3 +-- gcc/c/c-tree.h | 3 ++- gcc/c/c-typeck.cc | 31 ++++++++++++++++++----- gcc/testsuite/gcc.c-torture/compile/pr111059-1.c | 5 ++++ gcc/testsuite/gcc.c-torture/compile/pr111059-10.c | 9 +++++++ gcc/testsuite/gcc.c-torture/compile/pr111059-11.c | 9 +++++++ gcc/testsuite/gcc.c-torture/compile/pr111059-12.c | 9 +++++++ gcc/testsuite/gcc.c-torture/compile/pr111059-2.c | 5 ++++ gcc/testsuite/gcc.c-torture/compile/pr111059-3.c | 5 ++++ gcc/testsuite/gcc.c-torture/compile/pr111059-4.c | 5 ++++ gcc/testsuite/gcc.c-torture/compile/pr111059-5.c | 5 ++++ gcc/testsuite/gcc.c-torture/compile/pr111059-6.c | 5 ++++ gcc/testsuite/gcc.c-torture/compile/pr111059-7.c | 9 +++++++ gcc/testsuite/gcc.c-torture/compile/pr111059-8.c | 9 +++++++ gcc/testsuite/gcc.c-torture/compile/pr111059-9.c | 9 +++++++ gcc/testsuite/gcc.c-torture/compile/pr111911-1.c | 7 +++++ gcc/testsuite/gcc.c-torture/compile/pr111911-2.c | 11 ++++++++ 17 files changed, 130 insertions(+), 9 deletions(-) create mode 100644 gcc/testsuite/gcc.c-torture/compile/pr111059-1.c create mode 100644 gcc/testsuite/gcc.c-torture/compile/pr111059-10.c create mode 100644 gcc/testsuite/gcc.c-torture/compile/pr111059-11.c create mode 100644 gcc/testsuite/gcc.c-torture/compile/pr111059-12.c create mode 100644 gcc/testsuite/gcc.c-torture/compile/pr111059-2.c create mode 100644 gcc/testsuite/gcc.c-torture/compile/pr111059-3.c create mode 100644 gcc/testsuite/gcc.c-torture/compile/pr111059-4.c create mode 100644 gcc/testsuite/gcc.c-torture/compile/pr111059-5.c create mode 100644 gcc/testsuite/gcc.c-torture/compile/pr111059-6.c create mode 100644 gcc/testsuite/gcc.c-torture/compile/pr111059-7.c create mode 100644 gcc/testsuite/gcc.c-torture/compile/pr111059-8.c create mode 100644 gcc/testsuite/gcc.c-torture/compile/pr111059-9.c create mode 100644 gcc/testsuite/gcc.c-torture/compile/pr111911-1.c create mode 100644 gcc/testsuite/gcc.c-torture/compile/pr111911-2.c (limited to 'gcc') diff --git a/gcc/c/c-convert.cc b/gcc/c/c-convert.cc index 3e52926..7c1064c 100644 --- a/gcc/c/c-convert.cc +++ b/gcc/c/c-convert.cc @@ -150,8 +150,7 @@ c_convert (tree type, tree expr, bool init_const) case BOOLEAN_TYPE: convert_to_boolean: - return fold_convert_loc - (loc, type, c_objc_common_truthvalue_conversion (input_location, expr)); + return c_objc_common_truthvalue_conversion (input_location, expr, type); case POINTER_TYPE: /* The type nullptr_t may be converted to a pointer type. The result is diff --git a/gcc/c/c-tree.h b/gcc/c/c-tree.h index cf29534..1fba9c8 100644 --- a/gcc/c/c-tree.h +++ b/gcc/c/c-tree.h @@ -755,7 +755,8 @@ bool c_type_variably_modified_p (tree t) extern bool char_type_p (tree); -extern tree c_objc_common_truthvalue_conversion (location_t, tree); +extern tree c_objc_common_truthvalue_conversion (location_t, tree, + tree = integer_type_node); extern tree require_complete_type (location_t, tree); extern bool same_translation_unit_p (const_tree, const_tree); extern int comptypes (tree, tree); diff --git a/gcc/c/c-typeck.cc b/gcc/c/c-typeck.cc index 66c6abc..12d1a5a 100644 --- a/gcc/c/c-typeck.cc +++ b/gcc/c/c-typeck.cc @@ -6363,6 +6363,22 @@ build_c_cast (location_t loc, tree type, tree expr) " from %qT to %qT", otype, type); ovalue = value; + /* If converting to boolean a value with integer operands that + is not itself represented as an INTEGER_CST, the call below + to note_integer_operands may insert a C_MAYBE_CONST_EXPR, but + build_binary_op as called by c_common_truthvalue_conversion + may also insert a C_MAYBE_CONST_EXPR to indicate that a + subexpression has been fully folded. To avoid nested + C_MAYBE_CONST_EXPR, ensure that + c_objc_common_truthvalue_conversion receives an argument + properly marked as having integer operands in that case. */ + if (int_operands + && TREE_CODE (value) != INTEGER_CST + && (TREE_CODE (type) == BOOLEAN_TYPE + || (TREE_CODE (type) == ENUMERAL_TYPE + && ENUM_UNDERLYING_TYPE (type) != NULL_TREE + && TREE_CODE (ENUM_UNDERLYING_TYPE (type)) == BOOLEAN_TYPE))) + value = note_integer_operands (value); value = convert (type, value); /* Ignore any integer overflow caused by the cast. */ @@ -13509,11 +13525,11 @@ build_binary_op (location_t location, enum tree_code code, } -/* Convert EXPR to be a truth-value, validating its type for this +/* Convert EXPR to be a truth-value (type TYPE), validating its type for this purpose. LOCATION is the source location for the expression. */ tree -c_objc_common_truthvalue_conversion (location_t location, tree expr) +c_objc_common_truthvalue_conversion (location_t location, tree expr, tree type) { bool int_const, int_operands; @@ -13556,14 +13572,17 @@ c_objc_common_truthvalue_conversion (location_t location, tree expr) if (int_operands && TREE_CODE (expr) != INTEGER_CST) { expr = remove_c_maybe_const_expr (expr); - expr = build2 (NE_EXPR, integer_type_node, expr, + expr = build2 (NE_EXPR, type, expr, convert (TREE_TYPE (expr), integer_zero_node)); expr = note_integer_operands (expr); } else - /* ??? Should we also give an error for vectors rather than leaving - those to give errors later? */ - expr = c_common_truthvalue_conversion (location, expr); + { + /* ??? Should we also give an error for vectors rather than leaving + those to give errors later? */ + expr = c_common_truthvalue_conversion (location, expr); + expr = fold_convert_loc (location, type, expr); + } if (TREE_CODE (expr) == INTEGER_CST && int_operands && !int_const) { diff --git a/gcc/testsuite/gcc.c-torture/compile/pr111059-1.c b/gcc/testsuite/gcc.c-torture/compile/pr111059-1.c new file mode 100644 index 0000000..5788cb4 --- /dev/null +++ b/gcc/testsuite/gcc.c-torture/compile/pr111059-1.c @@ -0,0 +1,5 @@ +void +f () +{ + (_Bool) (1 << -1); +} diff --git a/gcc/testsuite/gcc.c-torture/compile/pr111059-10.c b/gcc/testsuite/gcc.c-torture/compile/pr111059-10.c new file mode 100644 index 0000000..fdd9a29 --- /dev/null +++ b/gcc/testsuite/gcc.c-torture/compile/pr111059-10.c @@ -0,0 +1,9 @@ +/* { dg-options "-std=gnu23 -Wno-div-by-zero" } */ + +enum e : bool { X }; + +enum e +f () +{ + return 0 / 0; +} diff --git a/gcc/testsuite/gcc.c-torture/compile/pr111059-11.c b/gcc/testsuite/gcc.c-torture/compile/pr111059-11.c new file mode 100644 index 0000000..8126034 --- /dev/null +++ b/gcc/testsuite/gcc.c-torture/compile/pr111059-11.c @@ -0,0 +1,9 @@ +/* { dg-options "-std=gnu23 -Wno-overflow" } */ + +enum e : bool { X }; + +void +f () +{ + (enum e) (__INT_MAX__ + 1); +} diff --git a/gcc/testsuite/gcc.c-torture/compile/pr111059-12.c b/gcc/testsuite/gcc.c-torture/compile/pr111059-12.c new file mode 100644 index 0000000..d11fcf6 --- /dev/null +++ b/gcc/testsuite/gcc.c-torture/compile/pr111059-12.c @@ -0,0 +1,9 @@ +/* { dg-options "-std=gnu23 -Wno-overflow" } */ + +enum e : bool { X }; + +enum e +f () +{ + return __INT_MAX__ + 1; +} diff --git a/gcc/testsuite/gcc.c-torture/compile/pr111059-2.c b/gcc/testsuite/gcc.c-torture/compile/pr111059-2.c new file mode 100644 index 0000000..785e291 --- /dev/null +++ b/gcc/testsuite/gcc.c-torture/compile/pr111059-2.c @@ -0,0 +1,5 @@ +void +f () +{ + (_Bool) (0 / 0); +} diff --git a/gcc/testsuite/gcc.c-torture/compile/pr111059-3.c b/gcc/testsuite/gcc.c-torture/compile/pr111059-3.c new file mode 100644 index 0000000..21099bc --- /dev/null +++ b/gcc/testsuite/gcc.c-torture/compile/pr111059-3.c @@ -0,0 +1,5 @@ +_Bool +f () +{ + return 1 << -1; +} diff --git a/gcc/testsuite/gcc.c-torture/compile/pr111059-4.c b/gcc/testsuite/gcc.c-torture/compile/pr111059-4.c new file mode 100644 index 0000000..95c68e5 --- /dev/null +++ b/gcc/testsuite/gcc.c-torture/compile/pr111059-4.c @@ -0,0 +1,5 @@ +_Bool +f () +{ + return 0 / 0; +} diff --git a/gcc/testsuite/gcc.c-torture/compile/pr111059-5.c b/gcc/testsuite/gcc.c-torture/compile/pr111059-5.c new file mode 100644 index 0000000..1047355 --- /dev/null +++ b/gcc/testsuite/gcc.c-torture/compile/pr111059-5.c @@ -0,0 +1,5 @@ +void +f () +{ + (_Bool) (__INT_MAX__ + 1); +} diff --git a/gcc/testsuite/gcc.c-torture/compile/pr111059-6.c b/gcc/testsuite/gcc.c-torture/compile/pr111059-6.c new file mode 100644 index 0000000..213f79b --- /dev/null +++ b/gcc/testsuite/gcc.c-torture/compile/pr111059-6.c @@ -0,0 +1,5 @@ +_Bool +f () +{ + return __INT_MAX__ + 1; +} diff --git a/gcc/testsuite/gcc.c-torture/compile/pr111059-7.c b/gcc/testsuite/gcc.c-torture/compile/pr111059-7.c new file mode 100644 index 0000000..466f45f --- /dev/null +++ b/gcc/testsuite/gcc.c-torture/compile/pr111059-7.c @@ -0,0 +1,9 @@ +/* { dg-options "-std=gnu23 -Wno-shift-count-negative" } */ + +enum e : bool { X }; + +void +f () +{ + (enum e) (1 << -1); +} diff --git a/gcc/testsuite/gcc.c-torture/compile/pr111059-8.c b/gcc/testsuite/gcc.c-torture/compile/pr111059-8.c new file mode 100644 index 0000000..67f3395 --- /dev/null +++ b/gcc/testsuite/gcc.c-torture/compile/pr111059-8.c @@ -0,0 +1,9 @@ +/* { dg-options "-std=gnu23 -Wno-div-by-zero" } */ + +enum e : bool { X }; + +void +f () +{ + (enum e) (0 / 0); +} diff --git a/gcc/testsuite/gcc.c-torture/compile/pr111059-9.c b/gcc/testsuite/gcc.c-torture/compile/pr111059-9.c new file mode 100644 index 0000000..f88096d --- /dev/null +++ b/gcc/testsuite/gcc.c-torture/compile/pr111059-9.c @@ -0,0 +1,9 @@ +/* { dg-options "-std=gnu23 -Wno-shift-count-negative" } */ + +enum e : bool { X }; + +enum e +f () +{ + return 1 << -1; +} diff --git a/gcc/testsuite/gcc.c-torture/compile/pr111911-1.c b/gcc/testsuite/gcc.c-torture/compile/pr111911-1.c new file mode 100644 index 0000000..350f4cc --- /dev/null +++ b/gcc/testsuite/gcc.c-torture/compile/pr111911-1.c @@ -0,0 +1,7 @@ +int +main (void) +{ + if (!(_Bool)(__INT_MAX__ + 1) / !(_Bool)(__INT_MAX__ + 1)) + ; + return 1; +} diff --git a/gcc/testsuite/gcc.c-torture/compile/pr111911-2.c b/gcc/testsuite/gcc.c-torture/compile/pr111911-2.c new file mode 100644 index 0000000..28b69c4 --- /dev/null +++ b/gcc/testsuite/gcc.c-torture/compile/pr111911-2.c @@ -0,0 +1,11 @@ +/* { dg-options "-std=gnu23 -Wno-overflow -Wno-div-by-zero" } */ + +enum e : bool { X }; + +int +main (void) +{ + if (!(enum e)(__INT_MAX__ + 1) / !(enum e)(__INT_MAX__ + 1)) + ; + return 1; +} -- cgit v1.1 From 320fb976e933e8892af905e68de65492568f2a49 Mon Sep 17 00:00:00 2001 From: Alexandre Oliva Date: Wed, 31 Jan 2024 00:13:36 -0300 Subject: 0From: Alexandre Oliva strub: introduce STACK_ADDRESS_OFFSET Since STACK_POINTER_OFFSET is not necessarily at the boundary between caller- and callee-owned stack, as desired by __builtin_stack_address(), and using it as if it were or not causes problems, introduce a new macro so that ports can define it suitably, without modifying STACK_POINTER_OFFSET. for gcc/ChangeLog PR middle-end/112917 PR middle-end/113100 * builtins.cc (expand_builtin_stack_address): Use STACK_ADDRESS_OFFSET. * doc/extend.texi (__builtin_stack_address): Adjust. * config/sparc/sparc.h (STACK_ADDRESS_OFFSET): Define. * doc/tm.texi.in (STACK_ADDRESS_OFFSET): Document. * doc/tm.texi: Rebuilt. --- gcc/builtins.cc | 5 ++--- gcc/config/sparc/sparc.h | 7 +++++++ gcc/doc/extend.texi | 2 +- gcc/doc/tm.texi | 29 +++++++++++++++++++++++++++++ gcc/doc/tm.texi.in | 29 +++++++++++++++++++++++++++++ 5 files changed, 68 insertions(+), 4 deletions(-) (limited to 'gcc') diff --git a/gcc/builtins.cc b/gcc/builtins.cc index a0bd82c..1d54ea0 100644 --- a/gcc/builtins.cc +++ b/gcc/builtins.cc @@ -5450,7 +5450,7 @@ expand_builtin_stack_address () rtx ret = convert_to_mode (ptr_mode, copy_to_reg (stack_pointer_rtx), STACK_UNSIGNED); -#ifdef SPARC_STACK_BOUNDARY_HACK +#ifdef STACK_ADDRESS_OFFSET /* Unbias the stack pointer, bringing it to the boundary between the stack area claimed by the active function calling this builtin, and stack ranges that could get clobbered if it called another @@ -5477,8 +5477,7 @@ expand_builtin_stack_address () (caller) function's active area as well, whereas those pushed or allocated temporarily for a call are regarded as part of the callee's stack range, rather than the caller's. */ - if (SPARC_STACK_BOUNDARY_HACK) - ret = plus_constant (ptr_mode, ret, STACK_POINTER_OFFSET); + ret = plus_constant (ptr_mode, ret, STACK_ADDRESS_OFFSET); #endif return force_reg (ptr_mode, ret); diff --git a/gcc/config/sparc/sparc.h b/gcc/config/sparc/sparc.h index fc064a9..fb07480 100644 --- a/gcc/config/sparc/sparc.h +++ b/gcc/config/sparc/sparc.h @@ -734,6 +734,13 @@ along with GCC; see the file COPYING3. If not see parameter regs. */ #define STACK_POINTER_OFFSET (FIRST_PARM_OFFSET(0) + SPARC_STACK_BIAS) +/* Unbias the stack pointer if needed, and move past the register save area, + that is never in use while a function is active, so that it is regarded as a + callee save area rather than as part of the function's own stack area. This + enables __strub_leave() to do a better job of clearing the stack frame of a + previously-called sibling. */ +#define STACK_ADDRESS_OFFSET STACK_POINTER_OFFSET + /* Base register for access to local variables of the function. */ #define HARD_FRAME_POINTER_REGNUM 30 diff --git a/gcc/doc/extend.texi b/gcc/doc/extend.texi index f0d02c9..142e41a 100644 --- a/gcc/doc/extend.texi +++ b/gcc/doc/extend.texi @@ -12799,7 +12799,7 @@ situations. @deftypefn {Built-in Function} {void *} __builtin_stack_address () This function returns the stack pointer register, offset by -@code{STACK_POINTER_OFFSET}. +@code{STACK_ADDRESS_OFFSET} if that's defined. Conceptually, the returned address returned by this built-in function is the boundary between the stack area allocated for use by its caller, and diff --git a/gcc/doc/tm.texi b/gcc/doc/tm.texi index 69ae63c..c8b8b12 100644 --- a/gcc/doc/tm.texi +++ b/gcc/doc/tm.texi @@ -3456,6 +3456,35 @@ or type, otherwise return false. The default implementation always returns true. @end deftypefn +@defmac STACK_ADDRESS_OFFSET +Offset from the stack pointer register to the boundary address between +the stack area claimed by an active function, and stack ranges that +could get clobbered if it called another function. It should NOT +encompass any stack red zone, that is used in leaf functions. + +This value is added to the stack pointer register to compute the address +returned by @code{__builtin_stack_address}, and this is its only use. +If this macro is not defined, no offset is added. Defining it like +@code{STACK_POINTER_OFFSET} may be appropriate for many machines, but +not all. + +On SPARC, for example, the register save area is *not* considered active +or used by the active function, but rather as akin to the area in which +call-preserved registers are saved by callees, so the stack address is +above that area, even though the (unbiased) stack pointer points below +it. This enables @code{__strub_leave} to clear what would otherwise +overlap with its own register save area. + +On PowerPC, @code{STACK_POINTER_OFFSET} also reserves space for a save +area, but that area is used by the caller rather than the callee, so the +boundary address is below it. + +If the address is computed too high or too low, parts of a stack range +that should be scrubbed may be left unscrubbed, scrubbing may corrupt +active portions of the stack frame, and stack ranges may be +doubly-scrubbed by caller and callee. +@end defmac + @defmac TARGET_STRUB_USE_DYNAMIC_ARRAY If defined to nonzero, @code{__strub_leave} will allocate a dynamic array covering the stack range that needs scrubbing before clearing it. diff --git a/gcc/doc/tm.texi.in b/gcc/doc/tm.texi.in index 21343d4..658e1e6 100644 --- a/gcc/doc/tm.texi.in +++ b/gcc/doc/tm.texi.in @@ -2688,6 +2688,35 @@ may reduce the size of debug information on some ports. @hook TARGET_HAVE_STRUB_SUPPORT_FOR +@defmac STACK_ADDRESS_OFFSET +Offset from the stack pointer register to the boundary address between +the stack area claimed by an active function, and stack ranges that +could get clobbered if it called another function. It should NOT +encompass any stack red zone, that is used in leaf functions. + +This value is added to the stack pointer register to compute the address +returned by @code{__builtin_stack_address}, and this is its only use. +If this macro is not defined, no offset is added. Defining it like +@code{STACK_POINTER_OFFSET} may be appropriate for many machines, but +not all. + +On SPARC, for example, the register save area is *not* considered active +or used by the active function, but rather as akin to the area in which +call-preserved registers are saved by callees, so the stack address is +above that area, even though the (unbiased) stack pointer points below +it. This enables @code{__strub_leave} to clear what would otherwise +overlap with its own register save area. + +On PowerPC, @code{STACK_POINTER_OFFSET} also reserves space for a save +area, but that area is used by the caller rather than the callee, so the +boundary address is below it. + +If the address is computed too high or too low, parts of a stack range +that should be scrubbed may be left unscrubbed, scrubbing may corrupt +active portions of the stack frame, and stack ranges may be +doubly-scrubbed by caller and callee. +@end defmac + @defmac TARGET_STRUB_USE_DYNAMIC_ARRAY If defined to nonzero, @code{__strub_leave} will allocate a dynamic array covering the stack range that needs scrubbing before clearing it. -- cgit v1.1 From d826596acb02edf41ac4f76af2aed5efa3b8c698 Mon Sep 17 00:00:00 2001 From: Alexandre Oliva Date: Wed, 31 Jan 2024 00:13:27 -0300 Subject: strub: drop nonaliased parm from build_ref_type_for [PR113394] Variant type copies can't have their own alias sets any more, and it's not like setting them affected the pointed-to objects anyway. for gcc/ChangeLog PR debug/113394 * ipa-strub.cc (build_ref_type_for): Drop nonaliased. Adjust caller. for gcc/testsuite/ChangeLog PR debug/113394 * gcc.dg/strub-internal-pr113394.c: New. --- gcc/ipa-strub.cc | 31 +++++--------------------- gcc/testsuite/gcc.dg/strub-internal-pr113394.c | 6 +++++ 2 files changed, 11 insertions(+), 26 deletions(-) create mode 100644 gcc/testsuite/gcc.dg/strub-internal-pr113394.c (limited to 'gcc') diff --git a/gcc/ipa-strub.cc b/gcc/ipa-strub.cc index e1b0701..0ee063c 100644 --- a/gcc/ipa-strub.cc +++ b/gcc/ipa-strub.cc @@ -2052,36 +2052,17 @@ walk_regimplify_phi (gphi *stmt) return needs_commit; } -/* Create a reference type to use for PARM when turning it into a reference. - NONALIASED causes the reference type to gain its own separate alias set, so - that accessing the indirectly-passed parm won'will not add aliasing - noise. */ +/* Create a reference type to use for PARM when turning it into a + reference. */ static tree -build_ref_type_for (tree parm, bool nonaliased = true) +build_ref_type_for (tree parm) { gcc_checking_assert (TREE_CODE (parm) == PARM_DECL); tree ref_type = build_reference_type (TREE_TYPE (parm)); - if (!nonaliased) - return ref_type; - - /* Each PARM turned indirect still points to the distinct memory area at the - wrapper, and the reference in unchanging, so we might qualify it, but... - const is not really important, since we're only using default defs for the - reference parm anyway, and not introducing any defs, and restrict seems to - cause trouble. E.g., libgnat/s-concat3.adb:str_concat_3 has memmoves that, - if it's wrapped, the memmoves are deleted in dse1. Using a distinct alias - set seems to not run afoul of this problem, and it hopefully enables the - compiler to tell the pointers do point to objects that are not otherwise - aliased. */ - tree qref_type = build_variant_type_copy (ref_type); - - TYPE_ALIAS_SET (qref_type) = new_alias_set (); - record_alias_subset (TYPE_ALIAS_SET (qref_type), get_alias_set (ref_type)); - - return qref_type; + return ref_type; } /* Add cgraph edges from current_function_decl to callees in SEQ with frequency @@ -2909,9 +2890,7 @@ pass_ipa_strub::execute (function *) if with transparent reference, and the wrapper doesn't take any extra parms that could point into wrapper's parms. So we can probably drop the TREE_ADDRESSABLE and keep the TRUE. */ - tree ref_type = build_ref_type_for (nparm, - true - || !TREE_ADDRESSABLE (parm)); + tree ref_type = build_ref_type_for (nparm); DECL_ARG_TYPE (nparm) = TREE_TYPE (nparm) = ref_type; relayout_decl (nparm); diff --git a/gcc/testsuite/gcc.dg/strub-internal-pr113394.c b/gcc/testsuite/gcc.dg/strub-internal-pr113394.c new file mode 100644 index 0000000..d21c209 --- /dev/null +++ b/gcc/testsuite/gcc.dg/strub-internal-pr113394.c @@ -0,0 +1,6 @@ +/* { dg-do compile } */ +/* { dg-options "-fstrub=internal -g" } */ + +/* gcc.c-torture/compile/20020210-1.c */ +/* PR c/5615 */ +void f(int a, struct {int b[a];} c) {} /* { dg-warning "anonymous struct" } */ -- cgit v1.1 From e7964bf623c6df3cb415eeafd458b0b8394e6ea4 Mon Sep 17 00:00:00 2001 From: Georg-Johann Lay Date: Wed, 31 Jan 2024 09:33:37 +0100 Subject: AVR: Add AVR64DU and some older devices. gcc/ * config/avr/avr-mcus.def: Add AVR64DU28, AVR64DU32, ATA5787, ATA5835, ATtiny64AUTO, ATA5700M322. * doc/avr-mmcu.texi: Rebuild. --- gcc/config/avr/avr-mcus.def | 8 +++++++- gcc/doc/avr-mmcu.texi | 6 +++--- 2 files changed, 10 insertions(+), 4 deletions(-) (limited to 'gcc') diff --git a/gcc/config/avr/avr-mcus.def b/gcc/config/avr/avr-mcus.def index 5ffab4d..7ddfba0 100644 --- a/gcc/config/avr/avr-mcus.def +++ b/gcc/config/avr/avr-mcus.def @@ -165,13 +165,16 @@ AVR_MCU ("at90pwm3b", ARCH_AVR4, AVR_ISA_NONE, "__AVR_AT90PWM3B__", AVR_MCU ("at90pwm81", ARCH_AVR4, AVR_ISA_NONE, "__AVR_AT90PWM81__", 0x0100, 0x0, 0x2000, 0) /* Enhanced, > 8K, <= 64K. */ AVR_MCU ("avr5", ARCH_AVR5, AVR_ISA_NONE, NULL, 0x0060, 0x0, 0x4000, 0) -AVR_MCU ("ata5702m322", ARCH_AVR5, AVR_ISA_NONE, "__AVR_ATA5702M322__", 0x0200, 0x0, 0x10000, 0) +AVR_MCU ("ata5700m322", ARCH_AVR5, AVR_ISA_NONE, "__AVR_ATA5700M322__", 0x0200, 0x8000, 0x10000, 0) +AVR_MCU ("ata5702m322", ARCH_AVR5, AVR_ISA_NONE, "__AVR_ATA5702M322__", 0x0200, 0x8000, 0x10000, 0) AVR_MCU ("ata5782", ARCH_AVR5, AVR_ISA_NONE, "__AVR_ATA5782__", 0x0200, 0x8000, 0xd000, 0) +AVR_MCU ("ata5787", ARCH_AVR5, AVR_ISA_NONE, "__AVR_ATA5787__", 0x0200, 0x8000, 0xd200, 0) AVR_MCU ("ata5790", ARCH_AVR5, AVR_ISA_NONE, "__AVR_ATA5790__", 0x0100, 0x0, 0x4000, 0) AVR_MCU ("ata5790n", ARCH_AVR5, AVR_ISA_NONE, "__AVR_ATA5790N__", 0x0100, 0x0, 0x4000, 0) AVR_MCU ("ata5791", ARCH_AVR5, AVR_ISA_NONE, "__AVR_ATA5791__", 0x0100, 0x0, 0x4000, 0) AVR_MCU ("ata5795", ARCH_AVR5, AVR_ISA_NONE, "__AVR_ATA5795__", 0x0100, 0x0, 0x2000, 0) AVR_MCU ("ata5831", ARCH_AVR5, AVR_ISA_NONE, "__AVR_ATA5831__", 0x0200, 0x8000, 0xd000, 0) +AVR_MCU ("ata5835", ARCH_AVR5, AVR_ISA_NONE, "__AVR_ATA5835__", 0x0200, 0x8000, 0xd200, 0) AVR_MCU ("ata6613c", ARCH_AVR5, AVR_ISA_NONE, "__AVR_ATA6613C__", 0x0100, 0x0, 0x4000, 0) AVR_MCU ("ata6614q", ARCH_AVR5, AVR_ISA_NONE, "__AVR_ATA6614Q__", 0x0100, 0x0, 0x8000, 0) AVR_MCU ("ata8210", ARCH_AVR5, AVR_ISA_NONE, "__AVR_ATA8210__", 0x0200, 0x8000, 0xd000, 0) @@ -318,6 +321,8 @@ AVR_MCU ("avr64dd14", ARCH_AVRXMEGA2, AVR_ISA_FLMAP, "__AVR_AVR64DD14__", AVR_MCU ("avr64dd20", ARCH_AVRXMEGA2, AVR_ISA_FLMAP, "__AVR_AVR64DD20__", 0x6000, 0x0, 0x10000, 0) AVR_MCU ("avr64dd28", ARCH_AVRXMEGA2, AVR_ISA_FLMAP, "__AVR_AVR64DD28__", 0x6000, 0x0, 0x10000, 0) AVR_MCU ("avr64dd32", ARCH_AVRXMEGA2, AVR_ISA_FLMAP, "__AVR_AVR64DD32__", 0x6000, 0x0, 0x10000, 0) +AVR_MCU ("avr64du28", ARCH_AVRXMEGA2, AVR_ISA_FLMAP, "__AVR_AVR64DU28__", 0x6000, 0x0, 0x10000, 0) +AVR_MCU ("avr64du32", ARCH_AVRXMEGA2, AVR_ISA_FLMAP, "__AVR_AVR64DU32__", 0x6000, 0x0, 0x10000, 0) AVR_MCU ("avr64ea28", ARCH_AVRXMEGA2, AVR_ISA_FLMAP, "__AVR_AVR64EA28__", 0x6800, 0x0, 0x10000, 0) AVR_MCU ("avr64ea32", ARCH_AVRXMEGA2, AVR_ISA_FLMAP, "__AVR_AVR64EA32__", 0x6800, 0x0, 0x10000, 0) AVR_MCU ("avr64ea48", ARCH_AVRXMEGA2, AVR_ISA_FLMAP, "__AVR_AVR64EA48__", 0x6800, 0x0, 0x10000, 0) @@ -339,6 +344,7 @@ AVR_MCU ("attiny214", ARCH_AVRXMEGA3, AVR_ISA_RCALL, "__AVR_ATtiny214__", AVR_MCU ("attiny412", ARCH_AVRXMEGA3, AVR_ISA_RCALL, "__AVR_ATtiny412__", 0x3f00, 0x0, 0x1000, 0x8000) AVR_MCU ("attiny414", ARCH_AVRXMEGA3, AVR_ISA_RCALL, "__AVR_ATtiny414__", 0x3f00, 0x0, 0x1000, 0x8000) AVR_MCU ("attiny416", ARCH_AVRXMEGA3, AVR_ISA_RCALL, "__AVR_ATtiny416__", 0x3f00, 0x0, 0x1000, 0x8000) +AVR_MCU ("attiny416auto", ARCH_AVRXMEGA3, AVR_ISA_RCALL, "__AVR_ATtiny416AUTO__", 0x3f00, 0x0, 0x1000, 0x8000) AVR_MCU ("attiny417", ARCH_AVRXMEGA3, AVR_ISA_RCALL, "__AVR_ATtiny417__", 0x3f00, 0x0, 0x1000, 0x8000) AVR_MCU ("attiny814", ARCH_AVRXMEGA3, AVR_ISA_RCALL, "__AVR_ATtiny814__", 0x3e00, 0x0, 0x2000, 0x8000) AVR_MCU ("attiny816", ARCH_AVRXMEGA3, AVR_ISA_RCALL, "__AVR_ATtiny816__", 0x3e00, 0x0, 0x2000, 0x8000) diff --git a/gcc/doc/avr-mmcu.texi b/gcc/doc/avr-mmcu.texi index 1a2c688..f38a0e0 100644 --- a/gcc/doc/avr-mmcu.texi +++ b/gcc/doc/avr-mmcu.texi @@ -38,7 +38,7 @@ @item @anchor{avr5}avr5 ``Enhanced'' devices with 16@tie{}KiB up to 64@tie{}KiB of program memory. -@*@var{mcu}@tie{}= @code{atmega16}, @code{atmega16a}, @code{atmega16hva}, @code{atmega16hva2}, @code{atmega16hvb}, @code{atmega16hvbrevb}, @code{atmega16m1}, @code{atmega16u4}, @code{atmega161}, @code{atmega162}, @code{atmega163}, @code{atmega164a}, @code{atmega164p}, @code{atmega164pa}, @code{atmega165}, @code{atmega165a}, @code{atmega165p}, @code{atmega165pa}, @code{atmega168}, @code{atmega168a}, @code{atmega168p}, @code{atmega168pa}, @code{atmega168pb}, @code{atmega169}, @code{atmega169a}, @code{atmega169p}, @code{atmega169pa}, @code{atmega32}, @code{atmega32a}, @code{atmega32c1}, @code{atmega32hvb}, @code{atmega32hvbrevb}, @code{atmega32m1}, @code{atmega32u4}, @code{atmega32u6}, @code{atmega323}, @code{atmega324a}, @code{atmega324p}, @code{atmega324pa}, @code{atmega324pb}, @code{atmega325}, @code{atmega325a}, @code{atmega325p}, @code{atmega325pa}, @code{atmega328}, @code{atmega328p}, @code{atmega328pb}, @code{atmega329}, @code{atmega329a}, @code{atmega329p}, @code{atmega329pa}, @code{atmega3250}, @code{atmega3250a}, @code{atmega3250p}, @code{atmega3250pa}, @code{atmega3290}, @code{atmega3290a}, @code{atmega3290p}, @code{atmega3290pa}, @code{atmega406}, @code{atmega64}, @code{atmega64a}, @code{atmega64c1}, @code{atmega64hve}, @code{atmega64hve2}, @code{atmega64m1}, @code{atmega64rfr2}, @code{atmega640}, @code{atmega644}, @code{atmega644a}, @code{atmega644p}, @code{atmega644pa}, @code{atmega644rfr2}, @code{atmega645}, @code{atmega645a}, @code{atmega645p}, @code{atmega649}, @code{atmega649a}, @code{atmega649p}, @code{atmega6450}, @code{atmega6450a}, @code{atmega6450p}, @code{atmega6490}, @code{atmega6490a}, @code{atmega6490p}, @code{ata5795}, @code{ata5790}, @code{ata5790n}, @code{ata5791}, @code{ata6613c}, @code{ata6614q}, @code{ata5782}, @code{ata5831}, @code{ata8210}, @code{ata8510}, @code{ata5702m322}, @code{at90pwm161}, @code{at90pwm216}, @code{at90pwm316}, @code{at90can32}, @code{at90can64}, @code{at90scr100}, @code{at90usb646}, @code{at90usb647}, @code{at94k}, @code{m3000}. +@*@var{mcu}@tie{}= @code{atmega16}, @code{atmega16a}, @code{atmega16hva}, @code{atmega16hva2}, @code{atmega16hvb}, @code{atmega16hvbrevb}, @code{atmega16m1}, @code{atmega16u4}, @code{atmega161}, @code{atmega162}, @code{atmega163}, @code{atmega164a}, @code{atmega164p}, @code{atmega164pa}, @code{atmega165}, @code{atmega165a}, @code{atmega165p}, @code{atmega165pa}, @code{atmega168}, @code{atmega168a}, @code{atmega168p}, @code{atmega168pa}, @code{atmega168pb}, @code{atmega169}, @code{atmega169a}, @code{atmega169p}, @code{atmega169pa}, @code{atmega32}, @code{atmega32a}, @code{atmega32c1}, @code{atmega32hvb}, @code{atmega32hvbrevb}, @code{atmega32m1}, @code{atmega32u4}, @code{atmega32u6}, @code{atmega323}, @code{atmega324a}, @code{atmega324p}, @code{atmega324pa}, @code{atmega324pb}, @code{atmega325}, @code{atmega325a}, @code{atmega325p}, @code{atmega325pa}, @code{atmega328}, @code{atmega328p}, @code{atmega328pb}, @code{atmega329}, @code{atmega329a}, @code{atmega329p}, @code{atmega329pa}, @code{atmega3250}, @code{atmega3250a}, @code{atmega3250p}, @code{atmega3250pa}, @code{atmega3290}, @code{atmega3290a}, @code{atmega3290p}, @code{atmega3290pa}, @code{atmega406}, @code{atmega64}, @code{atmega64a}, @code{atmega64c1}, @code{atmega64hve}, @code{atmega64hve2}, @code{atmega64m1}, @code{atmega64rfr2}, @code{atmega640}, @code{atmega644}, @code{atmega644a}, @code{atmega644p}, @code{atmega644pa}, @code{atmega644rfr2}, @code{atmega645}, @code{atmega645a}, @code{atmega645p}, @code{atmega649}, @code{atmega649a}, @code{atmega649p}, @code{atmega6450}, @code{atmega6450a}, @code{atmega6450p}, @code{atmega6490}, @code{atmega6490a}, @code{atmega6490p}, @code{ata5795}, @code{ata5790}, @code{ata5790n}, @code{ata5791}, @code{ata6613c}, @code{ata6614q}, @code{ata5782}, @code{ata5831}, @code{ata8210}, @code{ata8510}, @code{ata5787}, @code{ata5835}, @code{ata5700m322}, @code{ata5702m322}, @code{at90pwm161}, @code{at90pwm216}, @code{at90pwm316}, @code{at90can32}, @code{at90can64}, @code{at90scr100}, @code{at90usb646}, @code{at90usb647}, @code{at94k}, @code{m3000}. @item @anchor{avr51}avr51 ``Enhanced'' devices with 128@tie{}KiB of program memory. @@ -50,11 +50,11 @@ @item @anchor{avrxmega2}avrxmega2 ``XMEGA'' devices with more than 8@tie{}KiB and up to 64@tie{}KiB of program memory. -@*@var{mcu}@tie{}= @code{atxmega8e5}, @code{atxmega16a4}, @code{atxmega16a4u}, @code{atxmega16c4}, @code{atxmega16d4}, @code{atxmega16e5}, @code{atxmega32a4}, @code{atxmega32a4u}, @code{atxmega32c3}, @code{atxmega32c4}, @code{atxmega32d3}, @code{atxmega32d4}, @code{atxmega32e5}, @code{avr64da28}, @code{avr64da32}, @code{avr64da48}, @code{avr64da64}, @code{avr64db28}, @code{avr64db32}, @code{avr64db48}, @code{avr64db64}, @code{avr64dd14}, @code{avr64dd20}, @code{avr64dd28}, @code{avr64dd32}, @code{avr64ea28}, @code{avr64ea32}, @code{avr64ea48}. +@*@var{mcu}@tie{}= @code{atxmega8e5}, @code{atxmega16a4}, @code{atxmega16a4u}, @code{atxmega16c4}, @code{atxmega16d4}, @code{atxmega16e5}, @code{atxmega32a4}, @code{atxmega32a4u}, @code{atxmega32c3}, @code{atxmega32c4}, @code{atxmega32d3}, @code{atxmega32d4}, @code{atxmega32e5}, @code{avr64da28}, @code{avr64da32}, @code{avr64da48}, @code{avr64da64}, @code{avr64db28}, @code{avr64db32}, @code{avr64db48}, @code{avr64db64}, @code{avr64dd14}, @code{avr64dd20}, @code{avr64dd28}, @code{avr64dd32}, @code{avr64du28}, @code{avr64du32}, @code{avr64ea28}, @code{avr64ea32}, @code{avr64ea48}. @item @anchor{avrxmega3}avrxmega3 ``XMEGA'' devices with up to 64@tie{}KiB of combined program memory and RAM, and with program memory visible in the RAM address space. -@*@var{mcu}@tie{}= @code{attiny202}, @code{attiny204}, @code{attiny212}, @code{attiny214}, @code{attiny402}, @code{attiny404}, @code{attiny406}, @code{attiny412}, @code{attiny414}, @code{attiny416}, @code{attiny417}, @code{attiny424}, @code{attiny426}, @code{attiny427}, @code{attiny804}, @code{attiny806}, @code{attiny807}, @code{attiny814}, @code{attiny816}, @code{attiny817}, @code{attiny824}, @code{attiny826}, @code{attiny827}, @code{attiny1604}, @code{attiny1606}, @code{attiny1607}, @code{attiny1614}, @code{attiny1616}, @code{attiny1617}, @code{attiny1624}, @code{attiny1626}, @code{attiny1627}, @code{attiny3214}, @code{attiny3216}, @code{attiny3217}, @code{attiny3224}, @code{attiny3226}, @code{attiny3227}, @code{atmega808}, @code{atmega809}, @code{atmega1608}, @code{atmega1609}, @code{atmega3208}, @code{atmega3209}, @code{atmega4808}, @code{atmega4809}, @code{avr16dd14}, @code{avr16dd20}, @code{avr16dd28}, @code{avr16dd32}, @code{avr16ea28}, @code{avr16ea32}, @code{avr16ea48}, @code{avr16eb14}, @code{avr16eb20}, @code{avr16eb28}, @code{avr16eb32}, @code{avr32da28}, @code{avr32da32}, @code{avr32da48}, @code{avr32db28}, @code{avr32db32}, @code{avr32db48}, @code{avr32dd14}, @code{avr32dd20}, @code{avr32dd28}, @code{avr32dd32}, @code{avr32ea28}, @code{avr32ea32}, @code{avr32ea48}. +@*@var{mcu}@tie{}= @code{attiny202}, @code{attiny204}, @code{attiny212}, @code{attiny214}, @code{attiny402}, @code{attiny404}, @code{attiny406}, @code{attiny412}, @code{attiny414}, @code{attiny416}, @code{attiny416auto}, @code{attiny417}, @code{attiny424}, @code{attiny426}, @code{attiny427}, @code{attiny804}, @code{attiny806}, @code{attiny807}, @code{attiny814}, @code{attiny816}, @code{attiny817}, @code{attiny824}, @code{attiny826}, @code{attiny827}, @code{attiny1604}, @code{attiny1606}, @code{attiny1607}, @code{attiny1614}, @code{attiny1616}, @code{attiny1617}, @code{attiny1624}, @code{attiny1626}, @code{attiny1627}, @code{attiny3214}, @code{attiny3216}, @code{attiny3217}, @code{attiny3224}, @code{attiny3226}, @code{attiny3227}, @code{atmega808}, @code{atmega809}, @code{atmega1608}, @code{atmega1609}, @code{atmega3208}, @code{atmega3209}, @code{atmega4808}, @code{atmega4809}, @code{avr16dd14}, @code{avr16dd20}, @code{avr16dd28}, @code{avr16dd32}, @code{avr16ea28}, @code{avr16ea32}, @code{avr16ea48}, @code{avr16eb14}, @code{avr16eb20}, @code{avr16eb28}, @code{avr16eb32}, @code{avr32da28}, @code{avr32da32}, @code{avr32da48}, @code{avr32db28}, @code{avr32db32}, @code{avr32db48}, @code{avr32dd14}, @code{avr32dd20}, @code{avr32dd28}, @code{avr32dd32}, @code{avr32ea28}, @code{avr32ea32}, @code{avr32ea48}. @item @anchor{avrxmega4}avrxmega4 ``XMEGA'' devices with more than 64@tie{}KiB and up to 128@tie{}KiB of program memory. -- cgit v1.1 From 924137b9012cee5603482242de08fbf0b2030f6a Mon Sep 17 00:00:00 2001 From: Richard Biener Date: Wed, 31 Jan 2024 09:09:50 +0100 Subject: tree-optimization/113670 - gather/scatter to/from hard registers The following makes sure we're not taking the address of hard registers when vectorizing appearant gathers or scatters to/from them. PR tree-optimization/113670 * tree-vect-data-refs.cc (vect_check_gather_scatter): Make sure we can take the address of the reference base. * gcc.target/i386/pr113670.c: New testcase. --- gcc/testsuite/gcc.target/i386/pr113670.c | 16 ++++++++++++++++ gcc/tree-vect-data-refs.cc | 5 +++++ 2 files changed, 21 insertions(+) create mode 100644 gcc/testsuite/gcc.target/i386/pr113670.c (limited to 'gcc') diff --git a/gcc/testsuite/gcc.target/i386/pr113670.c b/gcc/testsuite/gcc.target/i386/pr113670.c new file mode 100644 index 0000000..8b9d374 --- /dev/null +++ b/gcc/testsuite/gcc.target/i386/pr113670.c @@ -0,0 +1,16 @@ +/* { dg-do compile } */ +/* { dg-options "-msse2 -O2 -fno-vect-cost-model" } */ + +typedef float __attribute__ ((vector_size (16))) vec; +typedef int __attribute__ ((vector_size (16))) ivec; +ivec x; + +void +test (void) +{ + register vec a asm("xmm3"), b asm("xmm4"); + register ivec c asm("xmm5"); + for (int i = 0; i < 4; i++) + c[i] = a[i] < b[i] ? -1 : 1; + x = c; +} diff --git a/gcc/tree-vect-data-refs.cc b/gcc/tree-vect-data-refs.cc index f592aeb..e6a3035 100644 --- a/gcc/tree-vect-data-refs.cc +++ b/gcc/tree-vect-data-refs.cc @@ -4325,6 +4325,11 @@ vect_check_gather_scatter (stmt_vec_info stmt_info, loop_vec_info loop_vinfo, if (!multiple_p (pbitpos, BITS_PER_UNIT)) return false; + /* We need to be able to form an address to the base which for example + isn't possible for hard registers. */ + if (may_be_nonaddressable_p (base)) + return false; + poly_int64 pbytepos = exact_div (pbitpos, BITS_PER_UNIT); if (TREE_CODE (base) == MEM_REF) -- cgit v1.1 From 90ac839a470d61ffcd9eee0d7d37ca9c385dfefb Mon Sep 17 00:00:00 2001 From: Jakub Jelinek Date: Wed, 31 Jan 2024 10:50:33 +0100 Subject: lower-bitint: Fix up VIEW_CONVERT_EXPR handling in handle_operand_addr [PR113639] Yet another spot where we need to treat VIEW_CONVERT_EXPR differently from NOP_EXPR/CONVERT_EXPR. 2024-01-31 Jakub Jelinek PR tree-optimization/113639 * gimple-lower-bitint.cc (bitint_large_huge::handle_operand_addr): For VIEW_CONVERT_EXPR set rhs1 to its operand. * gcc.dg/bitint-79.c: New test. --- gcc/gimple-lower-bitint.cc | 2 ++ gcc/testsuite/gcc.dg/bitint-79.c | 16 ++++++++++++++++ 2 files changed, 18 insertions(+) create mode 100644 gcc/testsuite/gcc.dg/bitint-79.c (limited to 'gcc') diff --git a/gcc/gimple-lower-bitint.cc b/gcc/gimple-lower-bitint.cc index af16745..a3802c6 100644 --- a/gcc/gimple-lower-bitint.cc +++ b/gcc/gimple-lower-bitint.cc @@ -2159,6 +2159,8 @@ bitint_large_huge::handle_operand_addr (tree op, gimple *stmt, gcc_assert (gimple_assign_cast_p (g)); tree rhs1 = gimple_assign_rhs1 (g); bitint_prec_kind kind = bitint_prec_small; + if (TREE_CODE (rhs1) == VIEW_CONVERT_EXPR) + rhs1 = TREE_OPERAND (rhs1, 0); gcc_assert (INTEGRAL_TYPE_P (TREE_TYPE (rhs1))); if (TREE_CODE (TREE_TYPE (rhs1)) == BITINT_TYPE) kind = bitint_precision_kind (TREE_TYPE (rhs1)); diff --git a/gcc/testsuite/gcc.dg/bitint-79.c b/gcc/testsuite/gcc.dg/bitint-79.c new file mode 100644 index 0000000..e7422c0 --- /dev/null +++ b/gcc/testsuite/gcc.dg/bitint-79.c @@ -0,0 +1,16 @@ +/* PR tree-optimization/113639 */ +/* { dg-do compile { target bitint } } */ +/* { dg-options "-O2 -std=c23" } */ + +int j, k; +#if __BITINT_MAXWIDTH__ >= 162 +struct S { _BitInt(162) n; }; +void bar (_BitInt(162) x); + +void +foo (struct S s) +{ + bar (s.n * j); + (void) (s.n * k); +} +#endif -- cgit v1.1 From 457d2b59b58e5998e1e6967316d4e3e8f24edeed Mon Sep 17 00:00:00 2001 From: Jakub Jelinek Date: Wed, 31 Jan 2024 10:56:15 +0100 Subject: dwarf2out: Fix ICE on large _BitInt in loc_list_from_tree_1 [PR113637] This spot uses SCALAR_INT_TYPE_MODE which obviously ICEs for large/huge BITINT_TYPE types which have BLKmode. But such large BITINT_TYPEs certainly don't fit into DWARF2_ADDR_SIZE either, so we can just assume it would be false if type has BLKmode. 2024-01-31 Jakub Jelinek PR debug/113637 * dwarf2out.cc (loc_list_from_tree_1): Assume integral types with BLKmode are larger than DWARF2_ADDR_SIZE. * gcc.dg/bitint-80.c: New test. --- gcc/dwarf2out.cc | 1 + gcc/testsuite/gcc.dg/bitint-80.c | 15 +++++++++++++++ 2 files changed, 16 insertions(+) create mode 100644 gcc/testsuite/gcc.dg/bitint-80.c (limited to 'gcc') diff --git a/gcc/dwarf2out.cc b/gcc/dwarf2out.cc index 2b72321..4b09c35 100644 --- a/gcc/dwarf2out.cc +++ b/gcc/dwarf2out.cc @@ -19027,6 +19027,7 @@ loc_list_from_tree_1 (tree loc, int want_address, && ! DECL_IGNORED_P (loc) && (INTEGRAL_TYPE_P (TREE_TYPE (loc)) || POINTER_TYPE_P (TREE_TYPE (loc))) + && TYPE_MODE (TREE_TYPE (loc)) != BLKmode && (GET_MODE_SIZE (SCALAR_INT_TYPE_MODE (TREE_TYPE (loc))) <= DWARF2_ADDR_SIZE)) { diff --git a/gcc/testsuite/gcc.dg/bitint-80.c b/gcc/testsuite/gcc.dg/bitint-80.c new file mode 100644 index 0000000..0ad0935 --- /dev/null +++ b/gcc/testsuite/gcc.dg/bitint-80.c @@ -0,0 +1,15 @@ +/* PR debug/113637 */ +/* { dg-do compile { target bitint } } */ +/* { dg-options "-g -std=c23" } */ + +#if __BITINT_MAXWIDTH__ >= 639 +typedef _BitInt(639) B; +#else +typedef _BitInt(63) B; +#endif + +void +foo (B n) +{ + extern void bar (int [][n]); +} -- cgit v1.1 From b59775b642bb2b1ecd2e6d52c988b9c432117bc8 Mon Sep 17 00:00:00 2001 From: Jakub Jelinek Date: Wed, 31 Jan 2024 10:56:56 +0100 Subject: simplify-rtx: Fix up last argument to simplify_gen_unary [PR113656] When simplifying e.g. (float_truncate:SF (float_truncate:DF (reg:XF)) or (float_truncate:SF (float_extend:XF (reg:DF)) etc. into (float_truncate:SF (reg:XF)) or (float_truncate:SF (reg:DF)) we call simplify_gen_unary with incorrect op_mode argument, it should be the argument's mode, but we call it with the outer mode instead. As these are all floating point operations, the argument always has non-VOIDmode and so we can just use that mode (as done in similar simplifications a few lines later), but neither FLOAT_TRUNCATE nor FLOAT_EXTEND are operations that should have the same modes of operand and result. This bug hasn't been a problem for years because normally op_mode is used only if the mode of op is VOIDmode, otherwise it is redundant, but r10-2139 added an assertion in some spots that op_mode is right even in such cases. 2024-01-31 Jakub Jelinek PR rtl-optimization/113656 * simplify-rtx.cc (simplify_context::simplify_unary_operation_1) : Fix up last argument to simplify_gen_unary. * gcc.target/i386/pr113656.c: New test. --- gcc/simplify-rtx.cc | 2 +- gcc/testsuite/gcc.target/i386/pr113656.c | 12 ++++++++++++ 2 files changed, 13 insertions(+), 1 deletion(-) create mode 100644 gcc/testsuite/gcc.target/i386/pr113656.c (limited to 'gcc') diff --git a/gcc/simplify-rtx.cc b/gcc/simplify-rtx.cc index c7215cf..36dd522 100644 --- a/gcc/simplify-rtx.cc +++ b/gcc/simplify-rtx.cc @@ -1305,7 +1305,7 @@ simplify_context::simplify_unary_operation_1 (rtx_code code, machine_mode mode, > GET_MODE_UNIT_SIZE (mode) ? FLOAT_TRUNCATE : FLOAT_EXTEND, mode, - XEXP (op, 0), mode); + XEXP (op, 0), GET_MODE (XEXP (op, 0))); /* (float_truncate (float x)) is (float x) */ if ((GET_CODE (op) == FLOAT || GET_CODE (op) == UNSIGNED_FLOAT) diff --git a/gcc/testsuite/gcc.target/i386/pr113656.c b/gcc/testsuite/gcc.target/i386/pr113656.c new file mode 100644 index 0000000..fa57a56 --- /dev/null +++ b/gcc/testsuite/gcc.target/i386/pr113656.c @@ -0,0 +1,12 @@ +/* PR rtl-optimization/113656 */ +/* { dg-do compile } */ +/* { dg-options "-O3 -frounding-math -funsafe-math-optimizations -mavx512fp16 -mavx512vl" } */ + +_Float16 a[8]; + +void +foo () +{ + for (int i = 0; i < 8; i++) + a[i] = i - 8.4; +} -- cgit v1.1 From 724b64304ff5c8ac08a913509afd6fde38d7b767 Mon Sep 17 00:00:00 2001 From: Richard Biener Date: Wed, 31 Jan 2024 11:28:50 +0100 Subject: tree-optimization/113630 - invalid code hoisting The following avoids code hoisting (but also PRE insertion) of expressions that got value-numbered to another one that are not a valid replacement (but still compute the same value). This time because the access path ends in a structure with different size, meaning we consider a related access as not trapping because of the size of the base of the access. PR tree-optimization/113630 * tree-ssa-pre.cc (compute_avail): Avoid registering a reference with a representation with not matching base access size. * gcc.dg/torture/pr113630.c: New testcase. --- gcc/testsuite/gcc.dg/torture/pr113630.c | 4 ++++ gcc/tree-ssa-pre.cc | 14 ++++++++++++++ 2 files changed, 18 insertions(+) create mode 100644 gcc/testsuite/gcc.dg/torture/pr113630.c (limited to 'gcc') diff --git a/gcc/testsuite/gcc.dg/torture/pr113630.c b/gcc/testsuite/gcc.dg/torture/pr113630.c new file mode 100644 index 0000000..72ebdef --- /dev/null +++ b/gcc/testsuite/gcc.dg/torture/pr113630.c @@ -0,0 +1,4 @@ +/* { dg-do run { target { { *-*-linux* *-*-gnu* *-*-uclinux* } && mmap } } } */ +/* { dg-additional-options "-fno-strict-aliasing" } */ + +#include "pr110799.c" diff --git a/gcc/tree-ssa-pre.cc b/gcc/tree-ssa-pre.cc index e72592d..d29214d 100644 --- a/gcc/tree-ssa-pre.cc +++ b/gcc/tree-ssa-pre.cc @@ -4281,6 +4281,20 @@ compute_avail (function *fun) = wide_int_to_tree (ptr_type_node, wi::to_wide (ref1->op2)); } + /* We also need to make sure that the access path + ends in an access of the same size as otherwise + we might assume an access may not trap while in + fact it might. That's independent of whether + TBAA is in effect. */ + if (TYPE_SIZE (ref1->type) != TYPE_SIZE (ref2->type) + && (! TYPE_SIZE (ref1->type) + || ! TYPE_SIZE (ref2->type) + || ! operand_equal_p (TYPE_SIZE (ref1->type), + TYPE_SIZE (ref2->type)))) + { + operands.release (); + continue; + } operands.release (); result = get_or_alloc_expr_for_reference -- cgit v1.1 From ccd8da149f5b77ecbf8586b17c6ba79edf2bc745 Mon Sep 17 00:00:00 2001 From: Rainer Orth Date: Wed, 31 Jan 2024 13:34:07 +0100 Subject: testsuite: Require ucn in g++.dg/cpp0x/udlit-extended-id-1.C g++.dg/cpp0x/udlit-extended-id-1.C FAILs on Solaris/SPARC and x86 with the native assembler: UNRESOLVED: g++.dg/cpp0x/udlit-extended-id-1.C -std=c++14 compilation failed to produce executable FAIL: g++.dg/cpp0x/udlit-extended-id-1.C -std=c++17 (test for excess errors) UNRESOLVED: g++.dg/cpp0x/udlit-extended-id-1.C -std=c++17 compilation failed to produce executable FAIL: g++.dg/cpp0x/udlit-extended-id-1.C -std=c++20 (test for excess errors) UNRESOLVED: g++.dg/cpp0x/udlit-extended-id-1.C -std=c++20 compilation failed to produce executable /bin/as doesn't support UCN identifiers: /usr/ccs/bin/as: "/var/tmp//ccCl_9fa.s", line 4: error: invalid character (0xcf) /usr/ccs/bin/as: "/var/tmp//ccCl_9fa.s", line 4: error: invalid character (0x80) /usr/ccs/bin/as: "/var/tmp//ccCl_9fa.s", line 4: error: statement syntax /usr/ccs/bin/as: "/var/tmp//ccCl_9fa.s", line 4: error: statement syntax [...] To avoid this, this patch requires ucn support. Tested on i386-pc-solaris2.11 (as and gas), sparc-sun-solaris2.11 (as and gas), and i686-pc-linux-gnu. 2024-01-30 Rainer Orth gcc/testsuite: * g++.dg/cpp0x/udlit-extended-id-1.C: Require ucn support. --- gcc/testsuite/g++.dg/cpp0x/udlit-extended-id-1.C | 1 + 1 file changed, 1 insertion(+) (limited to 'gcc') diff --git a/gcc/testsuite/g++.dg/cpp0x/udlit-extended-id-1.C b/gcc/testsuite/g++.dg/cpp0x/udlit-extended-id-1.C index c7091e9..94c0cd4 100644 --- a/gcc/testsuite/g++.dg/cpp0x/udlit-extended-id-1.C +++ b/gcc/testsuite/g++.dg/cpp0x/udlit-extended-id-1.C @@ -1,5 +1,6 @@ // { dg-do run { target c++11 } } // { dg-additional-options "-Wno-error=normalized" } +// { dg-require-effective-target ucn } #include #include using namespace std; -- cgit v1.1 From cfb3f666562fb4ab896a05c234a697afb63627a4 Mon Sep 17 00:00:00 2001 From: Richard Biener Date: Wed, 31 Jan 2024 10:42:48 +0100 Subject: tree-optimization/111444 - avoid insertions when skipping defs The following avoids inserting expressions for IPA CP discovered equivalences into the VN hashtables when we are optimistically skipping may-defs in the attempt to prove it's redundant. PR tree-optimization/111444 * tree-ssa-sccvn.cc (vn_reference_lookup_3): Do not use vn_reference_lookup_2 when optimistically skipping may-defs. * gcc.dg/torture/pr111444.c: New testcase. --- gcc/testsuite/gcc.dg/torture/pr111444.c | 26 ++++++++++++++++++++++++++ gcc/tree-ssa-sccvn.cc | 22 +++++++++++++--------- 2 files changed, 39 insertions(+), 9 deletions(-) create mode 100644 gcc/testsuite/gcc.dg/torture/pr111444.c (limited to 'gcc') diff --git a/gcc/testsuite/gcc.dg/torture/pr111444.c b/gcc/testsuite/gcc.dg/torture/pr111444.c new file mode 100644 index 0000000..e613f25 --- /dev/null +++ b/gcc/testsuite/gcc.dg/torture/pr111444.c @@ -0,0 +1,26 @@ +/* { dg-do run } */ + +int a = 3, d, e; +int *b = &a; +char c; +short f; +const int **g; +static long h(int **i, int **j) +{ + const int *k[46]; + const int **l = &k[5]; + *j = &e; + g = l; + for (; d; d = d + 1) + ; + **i = 0; + return f; +} +int main() +{ + int *m = &a; + h(&m, &m); + c = *b; + if (c != 3) + __builtin_abort (); +} diff --git a/gcc/tree-ssa-sccvn.cc b/gcc/tree-ssa-sccvn.cc index f0fa718..9bed9b3 100644 --- a/gcc/tree-ssa-sccvn.cc +++ b/gcc/tree-ssa-sccvn.cc @@ -2790,25 +2790,29 @@ vn_reference_lookup_3 (ao_ref *ref, tree vuse, void *data_, } else { - tree *saved_last_vuse_ptr = data->last_vuse_ptr; - /* Do not update last_vuse_ptr in vn_reference_lookup_2. */ - data->last_vuse_ptr = NULL; tree saved_vuse = vr->vuse; hashval_t saved_hashcode = vr->hashcode; - void *res = vn_reference_lookup_2 (ref, gimple_vuse (def_stmt), - data); + if (vr->vuse) + vr->hashcode = vr->hashcode - SSA_NAME_VERSION (vr->vuse); + vr->vuse = vuse_ssa_val (gimple_vuse (def_stmt)); + if (vr->vuse) + vr->hashcode = vr->hashcode + SSA_NAME_VERSION (vr->vuse); + vn_reference_t vnresult = NULL; + /* Do not use vn_reference_lookup_2 since that might perform + expression hashtable insertion but this lookup crosses + a possible may-alias making such insertion conditionally + invalid. */ + vn_reference_lookup_1 (vr, &vnresult); /* Need to restore vr->vuse and vr->hashcode. */ vr->vuse = saved_vuse; vr->hashcode = saved_hashcode; - data->last_vuse_ptr = saved_last_vuse_ptr; - if (res && res != (void *)-1) + if (vnresult) { - vn_reference_t vnresult = (vn_reference_t) res; if (TREE_CODE (rhs) == SSA_NAME) rhs = SSA_VAL (rhs); if (vnresult->result && operand_equal_p (vnresult->result, rhs, 0)) - return res; + return vnresult; } } } -- cgit v1.1 From df2a6143dc7d98680b03d50b3645e538946b3c2e Mon Sep 17 00:00:00 2001 From: Rainer Orth Date: Wed, 31 Jan 2024 14:49:22 +0100 Subject: testsuite: i386: Disable .eh_frame in gcc.target/i386/auto-init-5.c etc. The gcc.target/i386/auto-init-5.c and gcc.target/i386/auto-init-6.c tests FAIL on 64-bit Solaris/x86 with the native assembler: FAIL: gcc.target/i386/auto-init-5.c scan-assembler-times \\\\.long\\t0 14 FAIL: gcc.target/i386/auto-init-6.c scan-assembler-times long\\t0 8 /bin/as doesn't fully support the CFI directives, so the .eh_frame sections are emitted directly and contain .long. Since .eh_frame doesn't matter for those tests, this patch disables its generation in the first place. Tested on i386-pc-solaris2.11 (as and gas) and i686-pc-linux-gnu. 2024-01-30 Rainer Orth gcc/testsuite: * gcc.target/i386/auto-init-5.c: Add -fno-asynchronous-unwind-tables to dg-options. * gcc.target/i386/auto-init-6.c: Likewise. --- gcc/testsuite/gcc.target/i386/auto-init-5.c | 2 +- gcc/testsuite/gcc.target/i386/auto-init-6.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'gcc') diff --git a/gcc/testsuite/gcc.target/i386/auto-init-5.c b/gcc/testsuite/gcc.target/i386/auto-init-5.c index 0e9d74f..fdccd40 100644 --- a/gcc/testsuite/gcc.target/i386/auto-init-5.c +++ b/gcc/testsuite/gcc.target/i386/auto-init-5.c @@ -1,6 +1,6 @@ /* Verify zero initialization for complex type automatic variables. */ /* { dg-do compile } */ -/* { dg-options "-ftrivial-auto-var-init=zero" } */ +/* { dg-options "-ftrivial-auto-var-init=zero -fno-asynchronous-unwind-tables" } */ _Complex long double result; diff --git a/gcc/testsuite/gcc.target/i386/auto-init-6.c b/gcc/testsuite/gcc.target/i386/auto-init-6.c index e53385f..4b0ce39 100644 --- a/gcc/testsuite/gcc.target/i386/auto-init-6.c +++ b/gcc/testsuite/gcc.target/i386/auto-init-6.c @@ -2,7 +2,7 @@ /* Note, _Complex long double is initialized to zeroes due to the current implemenation limitation. */ /* { dg-do compile } */ -/* { dg-options "-ftrivial-auto-var-init=pattern -march=x86-64 -mtune=generic -msse" } */ +/* { dg-options "-ftrivial-auto-var-init=pattern -march=x86-64 -mtune=generic -msse -fno-asynchronous-unwind-tables" } */ _Complex long double result; -- cgit v1.1 From 0529ba8168c89f24314e8750237d77bb132bea9c Mon Sep 17 00:00:00 2001 From: Alex Coplan Date: Tue, 30 Jan 2024 10:22:48 +0000 Subject: aarch64: Avoid out-of-range shrink-wrapped saves [PR111677] The PR shows us ICEing due to an unrecognizable TFmode save emitted by aarch64_process_components. The problem is that for T{I,F,D}mode we conservatively require mems to be in range for x-register ldp/stp. That is because (at least for TImode) it can be allocated to both GPRs and FPRs, and in the GPR case that is an x-reg ldp/stp, and the FPR case is a q-register load/store. As Richard pointed out in the PR, aarch64_get_separate_components already checks that the offsets are suitable for a single load, so we just need to choose a mode in aarch64_reg_save_mode that gives the full q-register range. In this patch, we choose V16QImode as an alternative 16-byte "bag-of-bits" mode that doesn't have the artificial range restrictions imposed on T{I,F,D}mode. For T{F,D}mode in GCC 15 I think we could consider relaxing the restriction imposed in aarch64_classify_address, as typically T{F,D}mode should be allocated to FPRs. But such a change seems too invasive to consider for GCC 14 at this stage (let alone backports). Fortunately the new flexible load/store pair patterns in GCC 14 allow this mode change to work without further changes. The backports are more involved as we need to adjust the load/store pair handling to cater for V16QImode in a few places. Note that for the testcase we are relying on the torture options to add -funroll-loops at -O3 which is necessary to trigger the ICE on trunk (but not on the 13 branch). gcc/ChangeLog: PR target/111677 * config/aarch64/aarch64.cc (aarch64_reg_save_mode): Use V16QImode for the full 16-byte FPR saves in the vector PCS case. gcc/testsuite/ChangeLog: PR target/111677 * gcc.target/aarch64/torture/pr111677.c: New test. --- gcc/config/aarch64/aarch64.cc | 2 +- .../gcc.target/aarch64/torture/pr111677.c | 28 ++++++++++++++++++++++ 2 files changed, 29 insertions(+), 1 deletion(-) create mode 100644 gcc/testsuite/gcc.target/aarch64/torture/pr111677.c (limited to 'gcc') diff --git a/gcc/config/aarch64/aarch64.cc b/gcc/config/aarch64/aarch64.cc index a37d47b..4556b8d 100644 --- a/gcc/config/aarch64/aarch64.cc +++ b/gcc/config/aarch64/aarch64.cc @@ -2361,7 +2361,7 @@ aarch64_reg_save_mode (unsigned int regno) case ARM_PCS_SIMD: /* The vector PCS saves the low 128 bits (which is the full register on non-SVE targets). */ - return TFmode; + return V16QImode; case ARM_PCS_SVE: /* Use vectors of DImode for registers that need frame diff --git a/gcc/testsuite/gcc.target/aarch64/torture/pr111677.c b/gcc/testsuite/gcc.target/aarch64/torture/pr111677.c new file mode 100644 index 0000000..6bb640c --- /dev/null +++ b/gcc/testsuite/gcc.target/aarch64/torture/pr111677.c @@ -0,0 +1,28 @@ +/* { dg-do compile } */ +/* { dg-require-effective-target fopenmp } */ +/* { dg-options "-ffast-math -fstack-protector-strong -fopenmp" } */ +typedef struct { + long size_z; + int width; +} dt_bilateral_t; +typedef float dt_aligned_pixel_t[4]; +#pragma omp declare simd +void dt_bilateral_splat(dt_bilateral_t *b) { + float *buf; + long offsets[8]; + for (; b;) { + int firstrow; + for (int j = firstrow; j; j++) + for (int i; i < b->width; i++) { + dt_aligned_pixel_t contrib; + for (int k = 0; k < 4; k++) + buf[offsets[k]] += contrib[k]; + } + float *dest; + for (int j = (long)b; j; j++) { + float *src = (float *)b->size_z; + for (int i = 0; i < (long)b; i++) + dest[i] += src[i]; + } + } +} -- cgit v1.1 From 22dbfbe8767ff4c1d93e39f68ec7c2d5b1358beb Mon Sep 17 00:00:00 2001 From: Richard Biener Date: Wed, 31 Jan 2024 14:40:24 +0100 Subject: middle-end/110176 - wrong zext (bool) <= (int) 4294967295u folding The following fixes a wrong pattern that didn't match the behavior of the original fold_widened_comparison in that get_unwidened returned a constant always in the wider type. But here we're using (int) 4294967295u without the conversion applied. Fixed by doing as earlier in the pattern - matching constants only if the conversion was actually applied. PR middle-end/110176 * match.pd (zext (bool) <= (int) 4294967295u): Make sure to match INTEGER_CST only without outstanding conversion. * gcc.dg/torture/pr110176.c: New testcase. --- gcc/match.pd | 12 ++++----- gcc/testsuite/gcc.dg/torture/pr110176.c | 46 +++++++++++++++++++++++++++++++++ 2 files changed, 52 insertions(+), 6 deletions(-) create mode 100644 gcc/testsuite/gcc.dg/torture/pr110176.c (limited to 'gcc') diff --git a/gcc/match.pd b/gcc/match.pd index e42ecaf..a82bb08 100644 --- a/gcc/match.pd +++ b/gcc/match.pd @@ -6754,19 +6754,19 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT) >= TYPE_PRECISION (TREE_TYPE (@10))) && (TYPE_UNSIGNED (TREE_TYPE (@00)) == TYPE_UNSIGNED (TREE_TYPE (@10)))) - || (TREE_CODE (@10) == INTEGER_CST + || (TREE_CODE (@1) == INTEGER_CST && INTEGRAL_TYPE_P (TREE_TYPE (@00)) - && int_fits_type_p (@10, TREE_TYPE (@00))))) + && int_fits_type_p (@1, TREE_TYPE (@00))))) (cmp @00 (convert @10)) - (if (TREE_CODE (@10) == INTEGER_CST + (if (TREE_CODE (@1) == INTEGER_CST && INTEGRAL_TYPE_P (TREE_TYPE (@00)) - && !int_fits_type_p (@10, TREE_TYPE (@00))) + && !int_fits_type_p (@1, TREE_TYPE (@00))) (with { tree min = lower_bound_in_type (TREE_TYPE (@10), TREE_TYPE (@00)); tree max = upper_bound_in_type (TREE_TYPE (@10), TREE_TYPE (@00)); - bool above = integer_nonzerop (const_binop (LT_EXPR, type, max, @10)); - bool below = integer_nonzerop (const_binop (LT_EXPR, type, @10, min)); + bool above = integer_nonzerop (const_binop (LT_EXPR, type, max, @1)); + bool below = integer_nonzerop (const_binop (LT_EXPR, type, @1, min)); } (if (above || below) (if (cmp == EQ_EXPR || cmp == NE_EXPR) diff --git a/gcc/testsuite/gcc.dg/torture/pr110176.c b/gcc/testsuite/gcc.dg/torture/pr110176.c new file mode 100644 index 0000000..e41e3a0 --- /dev/null +++ b/gcc/testsuite/gcc.dg/torture/pr110176.c @@ -0,0 +1,46 @@ +/* { dg-do run } */ + +int f(_Bool t) +{ + int tt = t; + unsigned x = -1; + int xx = x; + return xx <= tt; +} + +int a, b; +void c() {} +__attribute__((noipa)) +void h() {__builtin_abort();} +int d() { + unsigned f[1]; + int i; + if (a) + goto h; + f[0] = -1; + while (1) { + c(); + for (; a < 1; a++) { + if (0) { + j: + continue; + } + i = f[0]; + if (a) + break; + b = i >= (b == 0); + } + if (!b) { + if (0) { + h: + goto j; + } + return 0; + } + h(); + } +} +int main() { + d(); + return 0; +} -- cgit v1.1 From 0debaceb11dee9781f9a8b320cb5893836324878 Mon Sep 17 00:00:00 2001 From: Tamar Christina Date: Wed, 31 Jan 2024 14:50:33 +0000 Subject: hwasan: instrument new memory and string functions [PR112644] Recent libhwasan updates[1] intercept various string and memory functions. These functions have checking in them, which means there's no need to inline the checking. This patch marks said functions as intercepted, and adjusts a testcase to handle the difference. It also looks for HWASAN in a check in expand_builtin. This check originally is there to avoid using expand to inline the behaviour of builtins like memset which are intercepted by ASAN and hence which we rely on the function call staying as a function call. With the new reliance on function calls in HWASAN we need to do the same thing for HWASAN too. HWASAN and ASAN don't seem to however instrument the same functions. Looking into libsanitizer/sanitizer_common/sanitizer_common_interceptors_memintrinsics.inc it looks like the common ones are memset, memmove and memcpy. The rest of the routines for asan seem to be defined in compiler-rt/lib/asan/asan_interceptors.h however compiler-rt/lib/hwasan/ does not have such a file but it does have compiler-rt/lib/hwasan/hwasan_platform_interceptors.h which it looks like is forcing off everything but memset, memmove, memcpy, memcmp and bcmp. As such I've taken those as the final list that hwasan currently supports. This also means that on future updates this list should be cross checked. [1] https://discourse.llvm.org/t/hwasan-question-about-the-recent-interceptors-being-added/75351 gcc/ChangeLog: PR sanitizer/112644 * asan.h (asan_intercepted_p): Incercept memset, memmove, memcpy and memcmp. * builtins.cc (expand_builtin): Include HWASAN when checking for builtin inlining. gcc/testsuite/ChangeLog: PR sanitizer/112644 * c-c++-common/hwasan/builtin-special-handling.c: Update testcase. Co-Authored-By: Matthew Malcomson --- gcc/asan.h | 7 ++++++- gcc/builtins.cc | 3 ++- .../c-c++-common/hwasan/builtin-special-handling.c | 18 +++++++++--------- 3 files changed, 17 insertions(+), 11 deletions(-) (limited to 'gcc') diff --git a/gcc/asan.h b/gcc/asan.h index 82811bd..d1bf8b1 100644 --- a/gcc/asan.h +++ b/gcc/asan.h @@ -185,8 +185,13 @@ extern hash_set *asan_handled_variables; inline bool asan_intercepted_p (enum built_in_function fcode) { + /* This list should be kept up-to-date with upstream's version at + compiler-rt/lib/hwasan/hwasan_platform_interceptors.h. */ if (hwasan_sanitize_p ()) - return false; + return fcode == BUILT_IN_MEMCMP + || fcode == BUILT_IN_MEMCPY + || fcode == BUILT_IN_MEMMOVE + || fcode == BUILT_IN_MEMSET; return fcode == BUILT_IN_INDEX || fcode == BUILT_IN_MEMCHR diff --git a/gcc/builtins.cc b/gcc/builtins.cc index 1d54ea0..4c04ae0 100644 --- a/gcc/builtins.cc +++ b/gcc/builtins.cc @@ -7791,7 +7791,8 @@ expand_builtin (tree exp, rtx target, rtx subtarget, machine_mode mode, default: break; } - if (sanitize_flags_p (SANITIZE_ADDRESS) && asan_intercepted_p (fcode)) + if (sanitize_flags_p (SANITIZE_ADDRESS | SANITIZE_HWADDRESS) + && asan_intercepted_p (fcode)) return expand_call (exp, target, ignore); /* When not optimizing, generate calls to library functions for a certain diff --git a/gcc/testsuite/c-c++-common/hwasan/builtin-special-handling.c b/gcc/testsuite/c-c++-common/hwasan/builtin-special-handling.c index a7a6d91..f975baa 100644 --- a/gcc/testsuite/c-c++-common/hwasan/builtin-special-handling.c +++ b/gcc/testsuite/c-c++-common/hwasan/builtin-special-handling.c @@ -8,24 +8,24 @@ /* { dg-skip-if "" { *-*-* } { "-flto" } { "-flto-partition=none" } } */ typedef __SIZE_TYPE__ size_t; -/* Functions to observe that HWASAN instruments memory builtins in the expected - manner. */ +/* HWASAN used to instrument calls to memset, memcpy, and memmove. It no + longer does this. Many other string and memory builtins are intercepted by + the runtime (and hence the codegen need not do anything). */ void * __attribute__((noinline)) memset_builtin (void *dest, int value, size_t len) { return __builtin_memset (dest, value, len); } -/* HWASAN avoids strlen because it doesn't know the size of the memory access - until *after* the function call. */ size_t __attribute__ ((noinline)) strlen_builtin (char *element) { return __builtin_strlen (element); } -/* First test ensures that the HWASAN_CHECK was emitted before the - memset. Second test ensures there was only HWASAN_CHECK (which demonstrates - that strlen was not instrumented). */ -/* { dg-final { scan-tree-dump-times "HWASAN_CHECK.*memset" 1 "asan1" } } */ -/* { dg-final { scan-tree-dump-times "HWASAN_CHECK" 1 "asan1" } } */ +/* First check here ensures there is no inline instrumentation generated for + these builtins. Second checks that we end up calling memset (i.e. that it's + not optimised into an inline operation, which would happen without the + instrumentation). */ +/* { dg-final { scan-tree-dump-not "HWASAN_CHECK" "asan1" } } */ +/* { dg-final { scan-assembler-times "\tmemset\\M" 1 } } */ -- cgit v1.1 From 0a640455928a050315f6addd88ace5d945eba130 Mon Sep 17 00:00:00 2001 From: Tamar Christina Date: Wed, 31 Jan 2024 14:51:36 +0000 Subject: hwasan: Remove testsuite check for a complaint message [PR112644] With recent updates to hwasan runtime libraries, the error reporting for this particular check is has been reworked. I would question why it has lost this message. To me it looks strange that num_descriptions_printed is incremented whenever we call PrintHeapOrGlobalCandidate whether that function prints anything or not. (See PrintAddressDescription in libsanitizer/hwasan/hwasan_report.cpp). The message is no longer printed because we increment this num_descriptions_printed variable indicating that we have found some description. I would like to question this upstream, but it doesn't look that much of a problem and if pressed for time we should just change our testsuite. Bootstrapped Regtested on aarch64-none-linux-gnu and no issues. gcc/testsuite/ChangeLog: PR sanitizer/112644 * c-c++-common/hwasan/hwasan-thread-clears-stack.c: Update testcase. --- gcc/testsuite/c-c++-common/hwasan/hwasan-thread-clears-stack.c | 1 - 1 file changed, 1 deletion(-) (limited to 'gcc') diff --git a/gcc/testsuite/c-c++-common/hwasan/hwasan-thread-clears-stack.c b/gcc/testsuite/c-c++-common/hwasan/hwasan-thread-clears-stack.c index 09c72a5..6c70684 100644 --- a/gcc/testsuite/c-c++-common/hwasan/hwasan-thread-clears-stack.c +++ b/gcc/testsuite/c-c++-common/hwasan/hwasan-thread-clears-stack.c @@ -52,5 +52,4 @@ main (int argc, char **argv) /* { dg-output "HWAddressSanitizer: tag-mismatch on address 0x\[0-9a-f\]*.*" } */ /* { dg-output "READ of size 4 at 0x\[0-9a-f\]* tags: \[\[:xdigit:\]\]\[\[:xdigit:\]\]/00 \\(ptr/mem\\) in thread T0.*" } */ -/* { dg-output "HWAddressSanitizer can not describe address in more detail\..*" } */ /* { dg-output "SUMMARY: HWAddressSanitizer: tag-mismatch \[^\n\]*.*" } */ -- cgit v1.1 From f7935beef7b02fbba0adf33fb2ba5c0a27d7e9ff Mon Sep 17 00:00:00 2001 From: Tamar Christina Date: Wed, 31 Jan 2024 14:52:59 +0000 Subject: AArch64: relax cbranch tests to accepted inverted branches [PR113502] Recently something in the midend had started inverting the branches by inverting the condition and the branches. While this is fine, it makes it hard to actually test. In RTL I disable scheduling and BB reordering to prevent this. But in GIMPLE there seems to be nothing I can do. __builtin_expect seems to have no impact on the change since I suspect this is happening during expand where conditions can be flipped regardless of probability during compare_and_branch. Since the mid-end has plenty of correctness tests, this weakens the backend tests to just check that a correct looking sequence is emitted. gcc/testsuite/ChangeLog: PR testsuite/113502 * gcc.target/aarch64/sve/vect-early-break-cbranch.c: Ignore exact branch. * gcc.target/aarch64/vect-early-break-cbranch.c: Likewise. --- .../gcc.target/aarch64/sve/vect-early-break-cbranch.c | 12 ++++++------ gcc/testsuite/gcc.target/aarch64/vect-early-break-cbranch.c | 12 ++++++------ 2 files changed, 12 insertions(+), 12 deletions(-) (limited to 'gcc') diff --git a/gcc/testsuite/gcc.target/aarch64/sve/vect-early-break-cbranch.c b/gcc/testsuite/gcc.target/aarch64/sve/vect-early-break-cbranch.c index d150535..d7cef11 100644 --- a/gcc/testsuite/gcc.target/aarch64/sve/vect-early-break-cbranch.c +++ b/gcc/testsuite/gcc.target/aarch64/sve/vect-early-break-cbranch.c @@ -9,7 +9,7 @@ int b[N] = {0}; ** ... ** cmpgt p[0-9]+.s, p[0-9]+/z, z[0-9]+.s, #0 ** ptest p[0-9]+, p[0-9]+.b -** b.any \.L[0-9]+ +** b.(any|none) \.L[0-9]+ ** ... */ void f1 () @@ -26,7 +26,7 @@ void f1 () ** ... ** cmpge p[0-9]+.s, p[0-9]+/z, z[0-9]+.s, #0 ** ptest p[0-9]+, p[0-9]+.b -** b.any \.L[0-9]+ +** b.(any|none) \.L[0-9]+ ** ... */ void f2 () @@ -43,7 +43,7 @@ void f2 () ** ... ** cmpeq p[0-9]+.s, p[0-9]+/z, z[0-9]+.s, #0 ** ptest p[0-9]+, p[0-9]+.b -** b.any \.L[0-9]+ +** b.(any|none) \.L[0-9]+ ** ... */ void f3 () @@ -60,7 +60,7 @@ void f3 () ** ... ** cmpne p[0-9]+.s, p[0-9]+/z, z[0-9]+.s, #0 ** ptest p[0-9]+, p[0-9]+.b -** b.any \.L[0-9]+ +** b.(any|none) \.L[0-9]+ ** ... */ void f4 () @@ -77,7 +77,7 @@ void f4 () ** ... ** cmplt p[0-9]+.s, p7/z, z[0-9]+.s, #0 ** ptest p[0-9]+, p[0-9]+.b -** b.any .L[0-9]+ +** b.(any|none) .L[0-9]+ ** ... */ void f5 () @@ -94,7 +94,7 @@ void f5 () ** ... ** cmple p[0-9]+.s, p[0-9]+/z, z[0-9]+.s, #0 ** ptest p[0-9]+, p[0-9]+.b -** b.any \.L[0-9]+ +** b.(any|none) \.L[0-9]+ ** ... */ void f6 () diff --git a/gcc/testsuite/gcc.target/aarch64/vect-early-break-cbranch.c b/gcc/testsuite/gcc.target/aarch64/vect-early-break-cbranch.c index a5e7b94..673b781 100644 --- a/gcc/testsuite/gcc.target/aarch64/vect-early-break-cbranch.c +++ b/gcc/testsuite/gcc.target/aarch64/vect-early-break-cbranch.c @@ -15,7 +15,7 @@ int b[N] = {0}; ** cmgt v[0-9]+.4s, v[0-9]+.4s, #0 ** umaxp v[0-9]+.4s, v[0-9]+.4s, v[0-9]+.4s ** fmov x[0-9]+, d[0-9]+ -** cbnz x[0-9]+, \.L[0-9]+ +** cbn?z x[0-9]+, \.L[0-9]+ ** ... */ void f1 () @@ -34,7 +34,7 @@ void f1 () ** cmge v[0-9]+.4s, v[0-9]+.4s, #0 ** umaxp v[0-9]+.4s, v[0-9]+.4s, v[0-9]+.4s ** fmov x[0-9]+, d[0-9]+ -** cbnz x[0-9]+, \.L[0-9]+ +** cbn?z x[0-9]+, \.L[0-9]+ ** ... */ void f2 () @@ -53,7 +53,7 @@ void f2 () ** cmeq v[0-9]+.4s, v[0-9]+.4s, #0 ** umaxp v[0-9]+.4s, v[0-9]+.4s, v[0-9]+.4s ** fmov x[0-9]+, d[0-9]+ -** cbnz x[0-9]+, \.L[0-9]+ +** cbn?z x[0-9]+, \.L[0-9]+ ** ... */ void f3 () @@ -72,7 +72,7 @@ void f3 () ** cmtst v[0-9]+.4s, v[0-9]+.4s, v[0-9]+.4s ** umaxp v[0-9]+.4s, v[0-9]+.4s, v[0-9]+.4s ** fmov x[0-9]+, d[0-9]+ -** cbnz x[0-9]+, \.L[0-9]+ +** cbn?z x[0-9]+, \.L[0-9]+ ** ... */ void f4 () @@ -91,7 +91,7 @@ void f4 () ** cmlt v[0-9]+.4s, v[0-9]+.4s, #0 ** umaxp v[0-9]+.4s, v[0-9]+.4s, v[0-9]+.4s ** fmov x[0-9]+, d[0-9]+ -** cbnz x[0-9]+, \.L[0-9]+ +** cbn?z x[0-9]+, \.L[0-9]+ ** ... */ void f5 () @@ -110,7 +110,7 @@ void f5 () ** cmle v[0-9]+.4s, v[0-9]+.4s, #0 ** umaxp v[0-9]+.4s, v[0-9]+.4s, v[0-9]+.4s ** fmov x[0-9]+, d[0-9]+ -** cbnz x[0-9]+, \.L[0-9]+ +** cbn?z x[0-9]+, \.L[0-9]+ ** ... */ void f6 () -- cgit v1.1 From 4fd094835a8997cdcc3d18d7d297debe1527202d Mon Sep 17 00:00:00 2001 From: Gaius Mulley Date: Wed, 31 Jan 2024 15:44:32 +0000 Subject: PR modula2/111627 Excess test fails with a case-preserving-case-insensitive source tree This patch renames gm2 testsuite modules whose names conflict with library modules. The conflict is not seen on case preserving case sensitive file systems. gcc/testsuite/ChangeLog: PR modula2/111627 * gm2/pim/pass/stdio.mod: Moved to... * gm2/pim/pass/teststdio.mod: ...here. * gm2/pim/run/pass/builtins.mod: Moved to... * gm2/pim/run/pass/testbuiltins.mod: ...here. * gm2/pim/run/pass/math.mod: Moved to... * gm2/pim/run/pass/testmath.mod: ...here. * gm2/pim/run/pass/math2.mod: Moved to... * gm2/pim/run/pass/testmath2.mod: ...here. Signed-off-by: Gaius Mulley --- gcc/testsuite/gm2/pim/pass/stdio.mod | 53 ----------------- gcc/testsuite/gm2/pim/pass/teststdio.mod | 53 +++++++++++++++++ gcc/testsuite/gm2/pim/run/pass/builtins.mod | 79 ------------------------- gcc/testsuite/gm2/pim/run/pass/math.mod | 44 -------------- gcc/testsuite/gm2/pim/run/pass/math2.mod | 44 -------------- gcc/testsuite/gm2/pim/run/pass/testbuiltins.mod | 79 +++++++++++++++++++++++++ gcc/testsuite/gm2/pim/run/pass/testmath.mod | 44 ++++++++++++++ gcc/testsuite/gm2/pim/run/pass/testmath2.mod | 44 ++++++++++++++ 8 files changed, 220 insertions(+), 220 deletions(-) delete mode 100644 gcc/testsuite/gm2/pim/pass/stdio.mod create mode 100644 gcc/testsuite/gm2/pim/pass/teststdio.mod delete mode 100644 gcc/testsuite/gm2/pim/run/pass/builtins.mod delete mode 100644 gcc/testsuite/gm2/pim/run/pass/math.mod delete mode 100644 gcc/testsuite/gm2/pim/run/pass/math2.mod create mode 100644 gcc/testsuite/gm2/pim/run/pass/testbuiltins.mod create mode 100644 gcc/testsuite/gm2/pim/run/pass/testmath.mod create mode 100644 gcc/testsuite/gm2/pim/run/pass/testmath2.mod (limited to 'gcc') diff --git a/gcc/testsuite/gm2/pim/pass/stdio.mod b/gcc/testsuite/gm2/pim/pass/stdio.mod deleted file mode 100644 index f121a8c..0000000 --- a/gcc/testsuite/gm2/pim/pass/stdio.mod +++ /dev/null @@ -1,53 +0,0 @@ -(* Copyright (C) 2015 Free Software Foundation, Inc. *) -(* This file is part of GNU Modula-2. - -GNU Modula-2 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, or (at your option) any later -version. - -GNU Modula-2 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 gm2; see the file COPYING. If not, write to the Free Software -Foundation, 51 Franklin Street, Fifth Floor, -Boston, MA 02110-1301, USA. *) - -MODULE stdio ; (*!m2pim*) - -CONST - MaxStack = 40 ; - -TYPE - ProcWrite = PROCEDURE (CHAR) ; - -VAR - StackW : ARRAY [0..MaxStack] OF ProcWrite ; - StackWPtr: CARDINAL ; - - -PROCEDURE write (ch: CHAR) ; -BEGIN - -END write ; - - -PROCEDURE PushOutput (p: ProcWrite) ; -BEGIN - IF StackWPtr=MaxStack - THEN - HALT - ELSE - INC(StackWPtr) ; - StackW[StackWPtr] := p - END -END PushOutput ; - - -BEGIN - StackWPtr := 0 ; - PushOutput(write) -END stdio. diff --git a/gcc/testsuite/gm2/pim/pass/teststdio.mod b/gcc/testsuite/gm2/pim/pass/teststdio.mod new file mode 100644 index 0000000..f67b1c7 --- /dev/null +++ b/gcc/testsuite/gm2/pim/pass/teststdio.mod @@ -0,0 +1,53 @@ +(* Copyright (C) 2015 Free Software Foundation, Inc. *) +(* This file is part of GNU Modula-2. + +GNU Modula-2 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, or (at your option) any later +version. + +GNU Modula-2 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 gm2; see the file COPYING. If not, write to the Free Software +Foundation, 51 Franklin Street, Fifth Floor, +Boston, MA 02110-1301, USA. *) + +MODULE teststdio ; (*!m2pim*) + +CONST + MaxStack = 40 ; + +TYPE + ProcWrite = PROCEDURE (CHAR) ; + +VAR + StackW : ARRAY [0..MaxStack] OF ProcWrite ; + StackWPtr: CARDINAL ; + + +PROCEDURE write (ch: CHAR) ; +BEGIN + +END write ; + + +PROCEDURE PushOutput (p: ProcWrite) ; +BEGIN + IF StackWPtr=MaxStack + THEN + HALT + ELSE + INC(StackWPtr) ; + StackW[StackWPtr] := p + END +END PushOutput ; + + +BEGIN + StackWPtr := 0 ; + PushOutput(write) +END teststdio. diff --git a/gcc/testsuite/gm2/pim/run/pass/builtins.mod b/gcc/testsuite/gm2/pim/run/pass/builtins.mod deleted file mode 100644 index 1cf9fb7..0000000 --- a/gcc/testsuite/gm2/pim/run/pass/builtins.mod +++ /dev/null @@ -1,79 +0,0 @@ -MODULE builtins ; (*!m2pim+gm2*) - -FROM Builtins IMPORT log10l ; -FROM libc IMPORT printf, exit ; -FROM libm IMPORT powl ; - - -(* - doPowerOfTen - safely returns the exponent of a LONGREAL as an INTEGER. -*) - -PROCEDURE doPowerOfTen (r: LONGREAL) : INTEGER ; -VAR - i : INTEGER ; - c, d: LONGREAL ; -BEGIN - IF r=0.0 - THEN - RETURN( 0 ) - ELSE - IF r<0.0 - THEN - c := -r - ELSE - c := r - END ; - IF c>=1.0 - THEN - RETURN( VAL(INTEGER, log10l (c)) ) - ELSE - i := 0 ; - LOOP - d := c*powl(10.0, VAL(LONGREAL, i)) ; - IF d>=1.0 - THEN - RETURN( -i ) - ELSE - INC(i) - END - END - END - END -END doPowerOfTen ; - - -PROCEDURE test ; -BEGIN - Assert (doPowerOfTen (1.0), 0) ; - Assert (doPowerOfTen (10.0), 1) ; - Assert (doPowerOfTen (100.0), 2) ; - Assert (doPowerOfTen (-1.0), 0) ; - Assert (doPowerOfTen (-10.0), 1) ; - Assert (doPowerOfTen (-100.0), 2) -END test ; - - -(* - Assert - -*) - -PROCEDURE Assert (func, actual: INTEGER) ; -BEGIN - IF func = actual - THEN - printf ("success: computed %d = actual %d\n", func, actual) - ELSE - printf ("failure: computed %d # actual %d\n", func, actual) ; - code := 1 - END -END Assert ; - - -VAR - code: INTEGER ; -BEGIN - code := 0 ; - test ; - exit (code) -END builtins. diff --git a/gcc/testsuite/gm2/pim/run/pass/math.mod b/gcc/testsuite/gm2/pim/run/pass/math.mod deleted file mode 100644 index 8eab79d..0000000 --- a/gcc/testsuite/gm2/pim/run/pass/math.mod +++ /dev/null @@ -1,44 +0,0 @@ -(* Copyright (C) 2008 Free Software Foundation, Inc. *) -(* This file is part of GNU Modula-2. - -GNU Modula-2 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 2, or (at your option) any later -version. - -GNU Modula-2 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 gm2; see the file COPYING. If not, write to the Free Software -Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. *) - -MODULE math ; - -IMPORT MathLib0, SMathLib0 ; -FROM libc IMPORT printf, exit ; - - -PROCEDURE Assert (b: BOOLEAN; f: ARRAY OF CHAR; l: CARDINAL) ; -BEGIN - IF NOT b - THEN - printf("%s:%d: assert failed\n", f, l) ; - exit(1) - END -END Assert ; - - -VAR - r: REAL ; - s: SHORTREAL ; -BEGIN - r := 2.3 ; - printf("value of entier (10.0 + r) = %d (should be 12)\n", MathLib0.entier (10.0 + r)) ; - Assert(MathLib0.entier (10.0 + r) = 12, __FILE__, __LINE__) ; - s := 5.9 ; - printf("value of SMathLib0.entier (10.0 + s) = %d (should be 15)\n", SMathLib0.entier (10.0 + s)) ; - Assert(SMathLib0.entier (10.0 + s) = 15, __FILE__, __LINE__) ; -END math. diff --git a/gcc/testsuite/gm2/pim/run/pass/math2.mod b/gcc/testsuite/gm2/pim/run/pass/math2.mod deleted file mode 100644 index 3dd2709..0000000 --- a/gcc/testsuite/gm2/pim/run/pass/math2.mod +++ /dev/null @@ -1,44 +0,0 @@ -(* Copyright (C) 2008 Free Software Foundation, Inc. *) -(* This file is part of GNU Modula-2. - -GNU Modula-2 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 2, or (at your option) any later -version. - -GNU Modula-2 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 gm2; see the file COPYING. If not, write to the Free Software -Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. *) - -MODULE math2 ; - -IMPORT MathLib0, SMathLib0 ; -FROM libc IMPORT printf, exit ; - - -PROCEDURE Assert (b: BOOLEAN; f: ARRAY OF CHAR; l: CARDINAL) ; -BEGIN - IF NOT b - THEN - printf("%s:%d: assert failed\n", f, l) ; - exit(1) - END -END Assert ; - - -VAR - r: REAL ; - s: SHORTREAL ; -BEGIN - r := 2.3 ; - printf("value of entier (10.0 + r) = %d (should be 12)\n", MathLib0.entier (10.0 + r)) ; - Assert(MathLib0.entier (r + 10.0) = 12, __FILE__, __LINE__) ; - s := 5.9 ; - printf("value of SMathLib0.entier (10.0 + s) = %d (should be 15)\n", SMathLib0.entier (10.0 + s)) ; - Assert(SMathLib0.entier (s + 10.0) = 15, __FILE__, __LINE__) ; -END math2. diff --git a/gcc/testsuite/gm2/pim/run/pass/testbuiltins.mod b/gcc/testsuite/gm2/pim/run/pass/testbuiltins.mod new file mode 100644 index 0000000..2fbea37 --- /dev/null +++ b/gcc/testsuite/gm2/pim/run/pass/testbuiltins.mod @@ -0,0 +1,79 @@ +MODULE testbuiltins ; (*!m2pim+gm2*) + +FROM Builtins IMPORT log10l ; +FROM libc IMPORT printf, exit ; +FROM libm IMPORT powl ; + + +(* + doPowerOfTen - safely returns the exponent of a LONGREAL as an INTEGER. +*) + +PROCEDURE doPowerOfTen (r: LONGREAL) : INTEGER ; +VAR + i : INTEGER ; + c, d: LONGREAL ; +BEGIN + IF r=0.0 + THEN + RETURN( 0 ) + ELSE + IF r<0.0 + THEN + c := -r + ELSE + c := r + END ; + IF c>=1.0 + THEN + RETURN( VAL(INTEGER, log10l (c)) ) + ELSE + i := 0 ; + LOOP + d := c*powl(10.0, VAL(LONGREAL, i)) ; + IF d>=1.0 + THEN + RETURN( -i ) + ELSE + INC(i) + END + END + END + END +END doPowerOfTen ; + + +PROCEDURE test ; +BEGIN + Assert (doPowerOfTen (1.0), 0) ; + Assert (doPowerOfTen (10.0), 1) ; + Assert (doPowerOfTen (100.0), 2) ; + Assert (doPowerOfTen (-1.0), 0) ; + Assert (doPowerOfTen (-10.0), 1) ; + Assert (doPowerOfTen (-100.0), 2) +END test ; + + +(* + Assert - +*) + +PROCEDURE Assert (func, actual: INTEGER) ; +BEGIN + IF func = actual + THEN + printf ("success: computed %d = actual %d\n", func, actual) + ELSE + printf ("failure: computed %d # actual %d\n", func, actual) ; + code := 1 + END +END Assert ; + + +VAR + code: INTEGER ; +BEGIN + code := 0 ; + test ; + exit (code) +END testbuiltins. diff --git a/gcc/testsuite/gm2/pim/run/pass/testmath.mod b/gcc/testsuite/gm2/pim/run/pass/testmath.mod new file mode 100644 index 0000000..19caf57 --- /dev/null +++ b/gcc/testsuite/gm2/pim/run/pass/testmath.mod @@ -0,0 +1,44 @@ +(* Copyright (C) 2008 Free Software Foundation, Inc. *) +(* This file is part of GNU Modula-2. + +GNU Modula-2 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 2, or (at your option) any later +version. + +GNU Modula-2 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 gm2; see the file COPYING. If not, write to the Free Software +Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. *) + +MODULE testmath ; + +IMPORT MathLib0, SMathLib0 ; +FROM libc IMPORT printf, exit ; + + +PROCEDURE Assert (b: BOOLEAN; f: ARRAY OF CHAR; l: CARDINAL) ; +BEGIN + IF NOT b + THEN + printf("%s:%d: assert failed\n", f, l) ; + exit(1) + END +END Assert ; + + +VAR + r: REAL ; + s: SHORTREAL ; +BEGIN + r := 2.3 ; + printf("value of entier (10.0 + r) = %d (should be 12)\n", MathLib0.entier (10.0 + r)) ; + Assert(MathLib0.entier (10.0 + r) = 12, __FILE__, __LINE__) ; + s := 5.9 ; + printf("value of SMathLib0.entier (10.0 + s) = %d (should be 15)\n", SMathLib0.entier (10.0 + s)) ; + Assert(SMathLib0.entier (10.0 + s) = 15, __FILE__, __LINE__) ; +END testmath. diff --git a/gcc/testsuite/gm2/pim/run/pass/testmath2.mod b/gcc/testsuite/gm2/pim/run/pass/testmath2.mod new file mode 100644 index 0000000..483372d --- /dev/null +++ b/gcc/testsuite/gm2/pim/run/pass/testmath2.mod @@ -0,0 +1,44 @@ +(* Copyright (C) 2008 Free Software Foundation, Inc. *) +(* This file is part of GNU Modula-2. + +GNU Modula-2 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 2, or (at your option) any later +version. + +GNU Modula-2 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 gm2; see the file COPYING. If not, write to the Free Software +Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. *) + +MODULE testmath2 ; + +IMPORT MathLib0, SMathLib0 ; +FROM libc IMPORT printf, exit ; + + +PROCEDURE Assert (b: BOOLEAN; f: ARRAY OF CHAR; l: CARDINAL) ; +BEGIN + IF NOT b + THEN + printf("%s:%d: assert failed\n", f, l) ; + exit(1) + END +END Assert ; + + +VAR + r: REAL ; + s: SHORTREAL ; +BEGIN + r := 2.3 ; + printf("value of entier (10.0 + r) = %d (should be 12)\n", MathLib0.entier (10.0 + r)) ; + Assert(MathLib0.entier (r + 10.0) = 12, __FILE__, __LINE__) ; + s := 5.9 ; + printf("value of SMathLib0.entier (10.0 + s) = %d (should be 15)\n", SMathLib0.entier (10.0 + s)) ; + Assert(SMathLib0.entier (s + 10.0) = 15, __FILE__, __LINE__) ; +END testmath2. -- cgit v1.1 From dcf579cb61bc2eb474fd824c19003d2dc17ec24f Mon Sep 17 00:00:00 2001 From: Gaius Mulley Date: Wed, 31 Jan 2024 15:51:49 +0000 Subject: modula2: tidyup patch This patch improves a comment and also adds the location tokenno to possibly exported idents as they are encountered. gcc/m2/ChangeLog: * gm2-compiler/M2Comp.mod (Pass0CheckMod): Tidy up comment. * gm2-compiler/P1Build.bnf (PossiblyExportIdent): Replace PushTF with PushTFtok. Signed-off-by: Gaius Mulley --- gcc/m2/gm2-compiler/M2Comp.mod | 4 ++-- gcc/m2/gm2-compiler/P1Build.bnf | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) (limited to 'gcc') diff --git a/gcc/m2/gm2-compiler/M2Comp.mod b/gcc/m2/gm2-compiler/M2Comp.mod index 48ea7b7..a97f0ed 100644 --- a/gcc/m2/gm2-compiler/M2Comp.mod +++ b/gcc/m2/gm2-compiler/M2Comp.mod @@ -872,8 +872,8 @@ BEGIN IF NOT IsDefinitionForC (sym) THEN (* The implementation module is only useful if -fgen-module-list= is - used (to gather all dependencies) although we do not insist upon finding the - implementation module. *) + used (to gather all dependencies). Note that we do not insist + upon finding the implementation module. *) LibName := NIL ; IF FindSourceModFile (SymName, FileName, LibName) THEN diff --git a/gcc/m2/gm2-compiler/P1Build.bnf b/gcc/m2/gm2-compiler/P1Build.bnf index 5d7254f..a3534fc 100644 --- a/gcc/m2/gm2-compiler/P1Build.bnf +++ b/gcc/m2/gm2-compiler/P1Build.bnf @@ -374,7 +374,7 @@ VAR nothing: CARDINAL ; BEGIN AddNameToScope(makekey(currentstring)) ; - PushTF(makekey(currentstring), identtok) ; + PushTFtok(makekey(currentstring), identtok, GetTokenNo()) ; CheckExplicitExported ; IF NOT IsAutoPushOn() THEN -- cgit v1.1 From 3fed1609f61088c4e607d6987d86579f684bf4dc Mon Sep 17 00:00:00 2001 From: Jonathan Yong <10walls@gmail.com> Date: Wed, 31 Jan 2024 13:31:30 +0000 Subject: uninit-pr108968-register.c: use __UINTPTR_TYPE__ for LLP64 Ensure sp variable is long enough by using __UINTPTR_TYPE__ for rsp. gcc/testsuite/ChangeLog: * c-c++-common/analyzer/uninit-pr108968-register.c: Use __UINTPTR_TYPE__ instead of unsigned long for LLP64. --- gcc/testsuite/c-c++-common/analyzer/uninit-pr108968-register.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'gcc') diff --git a/gcc/testsuite/c-c++-common/analyzer/uninit-pr108968-register.c b/gcc/testsuite/c-c++-common/analyzer/uninit-pr108968-register.c index a76c09e..e9a1c21 100644 --- a/gcc/testsuite/c-c++-common/analyzer/uninit-pr108968-register.c +++ b/gcc/testsuite/c-c++-common/analyzer/uninit-pr108968-register.c @@ -4,6 +4,6 @@ struct cpu_info {}; struct cpu_info *get_cpu_info(void) { - register unsigned long sp asm("rsp"); + register __UINTPTR_TYPE__ sp asm("rsp"); return (struct cpu_info *)((sp | (STACK_SIZE - 1)) + 1) - 1; /* { dg-bogus "use of uninitialized value 'sp'" } */ } -- cgit v1.1 From f6ba433d3c30c20fadd393eed31617a4da81789c Mon Sep 17 00:00:00 2001 From: Martin Uecker Date: Tue, 23 Jan 2024 13:33:34 +0100 Subject: Fix ICE with -g and -std=c23 when forming composite types [PR113438] Set TYPE_STUB_DECL to an artificial decl when creating a new structure as a composite type. PR c/113438 gcc/c/ * c-typeck.cc (composite_type_internal): Set TYPE_STUB_DECL. gcc/testsuite/ * gcc.dg/pr113438.c: New test. --- gcc/c/c-typeck.cc | 5 +++++ gcc/testsuite/gcc.dg/pr113438.c | 7 +++++++ 2 files changed, 12 insertions(+) create mode 100644 gcc/testsuite/gcc.dg/pr113438.c (limited to 'gcc') diff --git a/gcc/c/c-typeck.cc b/gcc/c/c-typeck.cc index 12d1a5a..3b519c4 100644 --- a/gcc/c/c-typeck.cc +++ b/gcc/c/c-typeck.cc @@ -585,6 +585,11 @@ composite_type_internal (tree t1, tree t2, struct composite_cache* cache) /* Setup the struct/union type. Because we inherit all variably modified components, we can ignore the size expression. */ tree expr = NULL_TREE; + + /* Set TYPE_STUB_DECL for debugging symbols. */ + TYPE_STUB_DECL (n) = pushdecl (build_decl (input_location, TYPE_DECL, + NULL_TREE, n)); + n = finish_struct(input_location, n, fields, attributes, NULL, &expr); n = qualify_type (n, t1); diff --git a/gcc/testsuite/gcc.dg/pr113438.c b/gcc/testsuite/gcc.dg/pr113438.c new file mode 100644 index 0000000..5612ee4 --- /dev/null +++ b/gcc/testsuite/gcc.dg/pr113438.c @@ -0,0 +1,7 @@ +/* PR113438 + * { dg-do compile } + * { dg-options "-std=c23 -g" } */ + +void g(struct foo { int x; } a); +void g(struct foo { int x; } a); + -- cgit v1.1 From d836db149d439658cb98688f3f5c6ed58446e333 Mon Sep 17 00:00:00 2001 From: Marek Polacek Date: Tue, 30 Jan 2024 17:11:34 -0500 Subject: c++: add deprecation notice for -fconcepts-ts We plan to remove -fconcepts-ts in GCC 15 and thus remove the flag_concepts_ts code. This note is an admonishing reminder to convert the Concepts TS code to C++20 Concepts. gcc/c-family/ChangeLog: * c-opts.cc (c_common_post_options): Add an inform saying that -fconcepts-ts is deprecated and will be removed in GCC 15. gcc/ChangeLog: * doc/invoke.texi: Mention that -fconcepts-ts was deprecated in GCC 14. --- gcc/c-family/c-opts.cc | 5 +++++ gcc/doc/invoke.texi | 4 +++- 2 files changed, 8 insertions(+), 1 deletion(-) (limited to 'gcc') diff --git a/gcc/c-family/c-opts.cc b/gcc/c-family/c-opts.cc index b38a122..b845aff 100644 --- a/gcc/c-family/c-opts.cc +++ b/gcc/c-family/c-opts.cc @@ -1139,6 +1139,11 @@ c_common_post_options (const char **pfilename) if (cxx_dialect >= cxx20 || flag_concepts_ts) flag_concepts = 1; + /* -fconcepts-ts will be removed in GCC 15. */ + if (flag_concepts_ts) + inform (input_location, "%<-fconcepts-ts%> is deprecated and will be " + "removed in GCC 15; please convert your code to C++20 concepts"); + /* -fimmediate-escalation has no effect when immediate functions are not supported. */ if (flag_immediate_escalation && cxx_dialect < cxx20) diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi index eb931b9..ca2c0e9 100644 --- a/gcc/doc/invoke.texi +++ b/gcc/doc/invoke.texi @@ -3204,7 +3204,9 @@ the language standard, so @option{-fconcepts} defaults to on. Some constructs that were allowed by the earlier C++ Extensions for Concepts Technical Specification, ISO 19217 (2015), but didn't make it into the standard, can additionally be enabled by -@option{-fconcepts-ts}. +@option{-fconcepts-ts}. The option @option{-fconcepts-ts} was deprecated +in GCC 14 and may be removed in GCC 15; users are expected to convert +their code to C++20 concepts. @opindex fconstexpr-depth @item -fconstexpr-depth=@var{n} -- cgit v1.1 From 8123f3ca3fd891034a8366518e756f161c4ff40d Mon Sep 17 00:00:00 2001 From: Robin Dapp Date: Tue, 30 Jan 2024 18:39:08 +0100 Subject: match: Fix vcond into conditional op folding [PR113607]. In PR113607 we see an invalid fold of _429 = .COND_SHL (mask_patt_205.47_276, vect_cst__262, vect_cst__262, { 0, ... }); vect_prephitmp_129.51_282 = _429; vect_iftmp.55_287 = VEC_COND_EXPR ; to Applying pattern match.pd:9607, gimple-match-10.cc:3817 gimple_simplified to vect_iftmp.55_287 = .COND_SHL (mask_patt_205.47_276, vect_cst__262, vect_cst__262, { 0, ... }); where we essentially use COND_SHL's else instead of VEC_COND_EXPR's. This patch adjusts the corresponding match.pd pattern and makes it only match when the else values are the same. That, however, causes the exact test case for which this pattern was introduced for to fail. Therefore XFAIL it for now. gcc/ChangeLog: PR middle-end/113607 * match.pd: Make sure else values match when folding a vec_cond into a conditional operation. gcc/testsuite/ChangeLog: * gcc.target/aarch64/sve/pre_cond_share_1.c: XFAIL. * gcc.target/riscv/rvv/autovec/pr113607-run.c: New test. * gcc.target/riscv/rvv/autovec/pr113607.c: New test. --- gcc/match.pd | 8 ++-- .../gcc.target/aarch64/sve/pre_cond_share_1.c | 2 +- .../gcc.target/riscv/rvv/autovec/pr113607-run.c | 4 ++ .../gcc.target/riscv/rvv/autovec/pr113607.c | 49 ++++++++++++++++++++++ 4 files changed, 58 insertions(+), 5 deletions(-) create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/autovec/pr113607-run.c create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/autovec/pr113607.c (limited to 'gcc') diff --git a/gcc/match.pd b/gcc/match.pd index a82bb08..711c3a1 100644 --- a/gcc/match.pd +++ b/gcc/match.pd @@ -9592,18 +9592,18 @@ and, /* Detect simplification for vector condition folding where - c = mask1 ? (masked_op mask2 a b) : b + c = mask1 ? (masked_op mask2 a b els) : els into - c = masked_op (mask1 & mask2) a b + c = masked_op (mask1 & mask2) a b els where the operation can be partially applied to one operand. */ (for cond_op (COND_BINARY) (simplify (vec_cond @0 - (cond_op:s @1 @2 @3 @4) @3) + (cond_op:s @1 @2 @3 @4) @4) (cond_op (bit_and @1 @0) @2 @3 @4))) /* And same for ternary expressions. */ @@ -9611,7 +9611,7 @@ and, (for cond_op (COND_TERNARY) (simplify (vec_cond @0 - (cond_op:s @1 @2 @3 @4 @5) @4) + (cond_op:s @1 @2 @3 @4 @5) @5) (cond_op (bit_and @1 @0) @2 @3 @4 @5))) /* For pointers @0 and @2 and nonnegative constant offset @1, look for diff --git a/gcc/testsuite/gcc.target/aarch64/sve/pre_cond_share_1.c b/gcc/testsuite/gcc.target/aarch64/sve/pre_cond_share_1.c index b51d0f2..e4f754d 100644 --- a/gcc/testsuite/gcc.target/aarch64/sve/pre_cond_share_1.c +++ b/gcc/testsuite/gcc.target/aarch64/sve/pre_cond_share_1.c @@ -129,4 +129,4 @@ fasten_main(size_t group, size_t ntypes, size_t nposes, size_t natlig, size_t na } /* { dg-final { scan-tree-dump-times {\.COND_MUL} 1 "optimized" } } */ -/* { dg-final { scan-tree-dump-times {\.VCOND} 1 "optimized" } } */ +/* { dg-final { scan-tree-dump-times {\.VCOND} 1 "optimized" { xfail *-*-* } } } */ diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/pr113607-run.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/pr113607-run.c new file mode 100644 index 0000000..0607476 --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/pr113607-run.c @@ -0,0 +1,4 @@ +/* { dg-do run { target { riscv_v && rv64 } } } */ +/* { dg-options "-O3 -march=rv64gcv -mabi=lp64d -fdump-tree-optimized" } */ + +#include "pr113607.c" diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/pr113607.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/pr113607.c new file mode 100644 index 0000000..70a9366 --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/pr113607.c @@ -0,0 +1,49 @@ +/* { dg-do compile } */ +/* { dg-options "-O3 -march=rv64gcv -mabi=lp64d -fdump-tree-optimized" } */ + +struct { + signed b; +} c, d = {6}; + +short e, f; +int g[1000]; +signed char h; +int i, j; +long k, l; + +long m(long n, long o) { + if (n < 1 && o == 0) + return 0; + return n; +} + +static int p() { + long q = 0; + int a = 0; + for (; e < 2; e += 1) + g[e * 7 + 1] = -1; + for (; h < 1; h += 1) { + k = g[8] || f; + l = m(g[f * 7 + 1], k); + a = l; + j = a < 0 || g[f * 7 + 1] < 0 || g[f * 7 + 1] >= 32 ? a : a << g[f * 7 + 1]; + if (j) + ++q; + } + if (q) + c = d; + return i; +} + +int main() { + p(); + if (c.b != 6) + __builtin_abort (); +} + +/* We must not fold VEC_COND_EXPR into COND_SHL. + Therefore, make sure that we still have 2/4 VCOND_MASKs with real else + value. */ + +/* { dg-final { scan-tree-dump-times { = \.VCOND_MASK.\([a-z0-9\._]+, [a-z0-9\._\{\}, ]+, [0-9\.\{\},]+\);} 0 "optimized" } } */ +/* { dg-final { scan-tree-dump-times { = \.VCOND_MASK.\([a-z0-9\._]+, [a-z0-9\._\{\}, ]+, [a-z0-9\._]+\);} 4 "optimized" } } */ -- cgit v1.1 From d22d1a9346f27db41459738c6eb404f8f0956e6f Mon Sep 17 00:00:00 2001 From: Joseph Myers Date: Wed, 31 Jan 2024 21:39:53 +0000 Subject: c: Fix ICE for nested enum redefinitions with/without fixed underlying type [PR112571] Bug 112571 reports an ICE-on-invalid for cases where an enum is defined, without a fixed underlying type, inside the enum type specifier for a definition of that same enum with a fixed underlying type. The ultimate cause is attempting to access ENUM_UNDERLYING_TYPE in a case where it is NULL. Avoid this by clearing ENUM_FIXED_UNDERLYING_TYPE_P in thie case of inconsistent definitions. Bootstrapped wth no regressions for x86_64-pc-linux-gnu. PR c/112571 gcc/c/ * c-decl.cc (start_enum): Clear ENUM_FIXED_UNDERLYING_TYPE_P when defining without a fixed underlying type an enumeration previously declared with a fixed underlying type. gcc/testsuite/ * gcc.dg/c23-enum-9.c, gcc.dg/c23-enum-10.c: New tests. --- gcc/c/c-decl.cc | 7 +++++-- gcc/testsuite/gcc.dg/c23-enum-10.c | 6 ++++++ gcc/testsuite/gcc.dg/c23-enum-9.c | 8 ++++++++ 3 files changed, 19 insertions(+), 2 deletions(-) create mode 100644 gcc/testsuite/gcc.dg/c23-enum-10.c create mode 100644 gcc/testsuite/gcc.dg/c23-enum-9.c (limited to 'gcc') diff --git a/gcc/c/c-decl.cc b/gcc/c/c-decl.cc index 8d18a3e..934e557 100644 --- a/gcc/c/c-decl.cc +++ b/gcc/c/c-decl.cc @@ -9905,8 +9905,11 @@ start_enum (location_t loc, struct c_enum_contents *the_enum, tree name, if (ENUM_FIXED_UNDERLYING_TYPE_P (enumtype) && fixed_underlying_type == NULL_TREE) - error_at (loc, "% declared with but defined without " - "fixed underlying type"); + { + error_at (loc, "% declared with but defined without " + "fixed underlying type"); + ENUM_FIXED_UNDERLYING_TYPE_P (enumtype) = false; + } the_enum->enum_next_value = integer_zero_node; the_enum->enum_type = enumtype; diff --git a/gcc/testsuite/gcc.dg/c23-enum-10.c b/gcc/testsuite/gcc.dg/c23-enum-10.c new file mode 100644 index 0000000..dd5f345 --- /dev/null +++ b/gcc/testsuite/gcc.dg/c23-enum-10.c @@ -0,0 +1,6 @@ +/* PR c/112571. */ +/* { dg-do compile } */ +/* { dg-options "-std=c23" } */ + +enum X : typeof (enum X { A }); /* { dg-error "declared with but defined without fixed underlying type" } */ +/* { dg-error "invalid 'enum' underlying type" "invalid" { target *-*-* } .-1 } */ diff --git a/gcc/testsuite/gcc.dg/c23-enum-9.c b/gcc/testsuite/gcc.dg/c23-enum-9.c new file mode 100644 index 0000000..10bb493 --- /dev/null +++ b/gcc/testsuite/gcc.dg/c23-enum-9.c @@ -0,0 +1,8 @@ +/* PR c/112571. */ +/* { dg-do compile } */ +/* { dg-options "-std=c23" } */ + +enum h : typeof (enum h { D }) { D }; /* { dg-error "declared with but defined without fixed underlying type" } */ +/* { dg-error "invalid 'enum' underlying type" "invalid" { target *-*-* } .-1 } */ +/* { dg-error "nested redefinition" "nested" { target *-*-* } .-2 } */ +/* { dg-error "conflicting redefinition" "conflicting" { target *-*-* } .-3 } */ -- cgit v1.1 From cc7aebff74d8967563fd9af5cb958dfcc8c111e8 Mon Sep 17 00:00:00 2001 From: David Malcolm Date: Wed, 31 Jan 2024 18:26:26 -0500 Subject: analyzer: fix skipping of debug stmts [PR113253] PR analyzer/113253 reports a case where the analyzer output varied with and without -g enabled. The root cause was that debug stmts were in the FOR_EACH_IMM_USE_FAST list for SSA names, leading to the analyzer's state purging logic differing between the -g and non-debugging cases, and thus leading to differences in the exploration of the user's code. Fix by skipping such stmts in the state-purging logic, and removing debug stmts when constructing the supergraph. gcc/analyzer/ChangeLog: PR analyzer/113253 * region-model.cc (region_model::on_stmt_pre): Add gcc_unreachable for debug statements. * state-purge.cc (state_purge_per_ssa_name::state_purge_per_ssa_name): Skip any debug stmts in the FOR_EACH_IMM_USE_FAST list. * supergraph.cc (supergraph::supergraph): Don't add debug stmts to the supernodes. gcc/testsuite/ChangeLog: PR analyzer/113253 * gcc.dg/analyzer/deref-before-check-pr113253.c: New test. Signed-off-by: David Malcolm --- gcc/analyzer/region-model.cc | 5 + gcc/analyzer/state-purge.cc | 9 ++ gcc/analyzer/supergraph.cc | 4 + .../gcc.dg/analyzer/deref-before-check-pr113253.c | 154 +++++++++++++++++++++ 4 files changed, 172 insertions(+) create mode 100644 gcc/testsuite/gcc.dg/analyzer/deref-before-check-pr113253.c (limited to 'gcc') diff --git a/gcc/analyzer/region-model.cc b/gcc/analyzer/region-model.cc index 082972f..a26be70 100644 --- a/gcc/analyzer/region-model.cc +++ b/gcc/analyzer/region-model.cc @@ -1307,6 +1307,11 @@ region_model::on_stmt_pre (const gimple *stmt, /* No-op for now. */ break; + case GIMPLE_DEBUG: + /* We should have stripped these out when building the supergraph. */ + gcc_unreachable (); + break; + case GIMPLE_ASSIGN: { const gassign *assign = as_a (stmt); diff --git a/gcc/analyzer/state-purge.cc b/gcc/analyzer/state-purge.cc index 284a03f..93959fb 100644 --- a/gcc/analyzer/state-purge.cc +++ b/gcc/analyzer/state-purge.cc @@ -329,6 +329,15 @@ state_purge_per_ssa_name::state_purge_per_ssa_name (const state_purge_map &map, map.log ("used by stmt: %s", pp_formatted_text (&pp)); } + if (is_gimple_debug (use_stmt)) + { + /* We skipped debug stmts when building the supergraph, + so ignore them now. */ + if (map.get_logger ()) + map.log ("skipping debug stmt"); + continue; + } + const supernode *snode = map.get_sg ().get_supernode_for_stmt (use_stmt); diff --git a/gcc/analyzer/supergraph.cc b/gcc/analyzer/supergraph.cc index d41a7e6..b822752 100644 --- a/gcc/analyzer/supergraph.cc +++ b/gcc/analyzer/supergraph.cc @@ -182,6 +182,10 @@ supergraph::supergraph (logger *logger) for (gsi = gsi_start_bb (bb); !gsi_end_p (gsi); gsi_next (&gsi)) { gimple *stmt = gsi_stmt (gsi); + /* Discard debug stmts here, so we don't have to check for + them anywhere within the analyzer. */ + if (is_gimple_debug (stmt)) + continue; node_for_stmts->m_stmts.safe_push (stmt); m_stmt_to_node_t.put (stmt, node_for_stmts); m_stmt_uids.make_uid_unique (stmt); diff --git a/gcc/testsuite/gcc.dg/analyzer/deref-before-check-pr113253.c b/gcc/testsuite/gcc.dg/analyzer/deref-before-check-pr113253.c new file mode 100644 index 0000000..d9015ac --- /dev/null +++ b/gcc/testsuite/gcc.dg/analyzer/deref-before-check-pr113253.c @@ -0,0 +1,154 @@ +/* Regression test for PR analyzer/113253 which was showing analyzer + differences with and without -g. + + C only: reduced reproducer doesn't easily work with C++. */ + +/* { dg-additional-options "-O2 -g" } */ + +typedef long int ptrdiff_t; +typedef unsigned long int uintptr_t; +typedef long int EMACS_INT; +enum +{ + EMACS_INT_WIDTH = 64, + VALBITS = EMACS_INT_WIDTH - 3, +}; +typedef struct Lisp_X* Lisp_Word; +enum Lisp_Type +{ + Lisp_Symbol = 0, + Lisp_Vectorlike = 5, +}; +typedef Lisp_Word Lisp_Object; +static inline EMACS_INT(XLI)(Lisp_Object o) +{ + return ((EMACS_INT)(o)); +} +static inline void*(XLP)(Lisp_Object o) +{ + return ((void*)(o)); +} +struct Lisp_Symbol +{}; +typedef uintptr_t Lisp_Word_tag; +extern struct Lisp_Symbol lispsym[1608]; +union vectorlike_header +{ + ptrdiff_t size; +}; +enum pvec_type +{ + PVEC_MARKER, +}; +enum More_Lisp_Bits +{ + PSEUDOVECTOR_SIZE_BITS = 12, + PSEUDOVECTOR_REST_BITS = 12, + PSEUDOVECTOR_AREA_BITS = PSEUDOVECTOR_SIZE_BITS + PSEUDOVECTOR_REST_BITS, + PVEC_TYPE_MASK = 0x3f << PSEUDOVECTOR_AREA_BITS +}; +static inline _Bool +PSEUDOVECTORP(Lisp_Object a, int code) +{ + return ( + ((((union vectorlike_header*)((uintptr_t)XLP((a)) - + (uintptr_t)( + (Lisp_Word_tag)(Lisp_Vectorlike) + << (((0x7fffffffffffffffL >> (3 - 1)) / 2 < + (9223372036854775807L)) + ? 0 + : VALBITS)))) + ->size & + (((9223372036854775807L) - (9223372036854775807L) / 2) | + PVEC_TYPE_MASK)) == + (((9223372036854775807L) - (9223372036854775807L) / 2) | + ((code) << PSEUDOVECTOR_AREA_BITS)))); +} +static inline Lisp_Object +make_lisp_symbol(struct Lisp_Symbol* sym) +{ + Lisp_Object a = ((Lisp_Word)( + ((Lisp_Word_tag)(Lisp_Symbol) + << (((0x7fffffffffffffffL >> (3 - 1)) / 2 < (9223372036854775807L)) + ? 0 + : VALBITS)))); + return a; +} +static inline Lisp_Object +builtin_lisp_symbol(int index) +{ + return make_lisp_symbol(&lispsym[index]); +} +static inline _Bool(BASE_EQ)(Lisp_Object x, Lisp_Object y) +{ + return (XLI(x) == XLI(y)); +} +static inline _Bool(NILP)(Lisp_Object x) +{ + return BASE_EQ(x, builtin_lisp_symbol(0)); +} +struct thread_state +{ + struct buffer* m_current_buffer; +}; +extern struct thread_state* current_thread; +struct Lisp_Marker +{ + struct buffer* buffer; +}; +static inline _Bool +MARKERP(Lisp_Object x) +{ + return PSEUDOVECTORP(x, PVEC_MARKER); +} +static inline struct Lisp_Marker* +XMARKER(Lisp_Object a) +{ + return (( + struct Lisp_Marker*)((uintptr_t)XLP(a) - + (uintptr_t)((Lisp_Word_tag)(Lisp_Vectorlike) + << (((0x7fffffffffffffffL >> (3 - 1)) / 2 < + (9223372036854775807L)) + ? 0 + : VALBITS)))); +} +extern void +unchain_marker(); +struct buffer +{ + Lisp_Object name_; +}; +static inline struct buffer* +XBUFFER(Lisp_Object a) +{ + return ( + (struct buffer*)((uintptr_t)XLP(a) - + (uintptr_t)((Lisp_Word_tag)(Lisp_Vectorlike) + << (((0x7fffffffffffffffL >> (3 - 1)) / 2 < + (9223372036854775807L)) + ? 0 + : VALBITS)))); +} +static inline _Bool +BUFFER_LIVE_P(struct buffer* b) +{ + return !NILP(((b)->name_)); +} +static inline struct buffer* +decode_buffer(Lisp_Object b) +{ + return NILP(b) ? (current_thread->m_current_buffer) : (XBUFFER(b)); +} +static struct buffer* +live_buffer(Lisp_Object buffer) +{ + struct buffer* b = decode_buffer(buffer); + return BUFFER_LIVE_P(b) ? b : ((void*)0); +} +Lisp_Object +set_marker_internal(Lisp_Object position, Lisp_Object buffer) +{ + struct buffer* b = live_buffer(buffer); + if (NILP(position) || (MARKERP(position) && !XMARKER(position)->buffer) || !b) /* { dg-bogus "Wanalyzer-deref-before-check" } */ + unchain_marker(); +} -- cgit v1.1 From dbf847d2c8d1c910948ba34c9338939c67323273 Mon Sep 17 00:00:00 2001 From: Andrew Pinski Date: Tue, 30 Jan 2024 00:50:56 -0800 Subject: aarch64: -mstrict-align vs __arm_data512_t [PR113657] After r14-1187-gd6b756447cd58b, simplify_gen_subreg can return NULL for "unaligned" memory subreg. Since V8DI has an alignment of 8 bytes, using TImode causes simplify_gen_subreg to return NULL. This fixes the issue by using DImode instead for the loop. And then we will have later on the STP/LDP pass combine it back into STP/LDP if needed. Since strict align is less important (usually used for firmware and early boot only), not doing LDP/STP here is ok. Built and tested for aarch64-linux-gnu with no regressions. PR target/113657 gcc/ChangeLog: * config/aarch64/aarch64-simd.md (split for movv8di): For strict aligned mode, use DImode instead of TImode. gcc/testsuite/ChangeLog: * gcc.target/aarch64/acle/ls64_strict_align.c: New test. Signed-off-by: Andrew Pinski --- gcc/config/aarch64/aarch64-simd.md | 11 +++++++---- gcc/testsuite/gcc.target/aarch64/acle/ls64_strict_align.c | 7 +++++++ 2 files changed, 14 insertions(+), 4 deletions(-) create mode 100644 gcc/testsuite/gcc.target/aarch64/acle/ls64_strict_align.c (limited to 'gcc') diff --git a/gcc/config/aarch64/aarch64-simd.md b/gcc/config/aarch64/aarch64-simd.md index f036f6c..f8bb973 100644 --- a/gcc/config/aarch64/aarch64-simd.md +++ b/gcc/config/aarch64/aarch64-simd.md @@ -8221,14 +8221,17 @@ || (memory_operand (operands[0], V8DImode) && register_operand (operands[1], V8DImode))) { + /* V8DI only guarantees 8-byte alignment, whereas TImode requires 16. */ + auto mode = STRICT_ALIGNMENT ? DImode : TImode; + int increment = GET_MODE_SIZE (mode); std::pair last_pair = {}; - for (int offset = 0; offset < 64; offset += 16) + for (int offset = 0; offset < 64; offset += increment) { std::pair pair = { - simplify_gen_subreg (TImode, operands[0], V8DImode, offset), - simplify_gen_subreg (TImode, operands[1], V8DImode, offset) + simplify_gen_subreg (mode, operands[0], V8DImode, offset), + simplify_gen_subreg (mode, operands[1], V8DImode, offset) }; - if (register_operand (pair.first, TImode) + if (register_operand (pair.first, mode) && reg_overlap_mentioned_p (pair.first, pair.second)) last_pair = pair; else diff --git a/gcc/testsuite/gcc.target/aarch64/acle/ls64_strict_align.c b/gcc/testsuite/gcc.target/aarch64/acle/ls64_strict_align.c new file mode 100644 index 0000000..bf49ac7 --- /dev/null +++ b/gcc/testsuite/gcc.target/aarch64/acle/ls64_strict_align.c @@ -0,0 +1,7 @@ +/* { dg-do compile } */ +/* { dg-options "-mstrict-align" } */ +/* PR target/113657 */ + +#pragma GCC target "+ls64" +#pragma GCC aarch64 "arm_acle.h" +__arm_data512_t foo(__arm_data512_t* ptr) { return *ptr; } -- cgit v1.1 From 26c34b809cd1a6249027730a8b52bbf6a1c0f4a8 Mon Sep 17 00:00:00 2001 From: Edwin Lu Date: Wed, 31 Jan 2024 10:40:15 -0800 Subject: RISC-V: Add non-vector types to dfa pipelines This patch adds non-vector related insn reservations and updates/creates new insn reservations so all non-vector typed instructions have a reservation. gcc/ChangeLog: * config/riscv/generic-ooo.md (generic_ooo_sfb_alu): Add reservation (generic_ooo_branch): ditto * config/riscv/generic.md (generic_sfb_alu): ditto (generic_fmul_half): ditto * config/riscv/riscv.md: Remove cbo, pushpop, and rdfrm types * config/riscv/sifive-7.md (sifive_7_hfma):Add reservation (sifive_7_popcount): ditto * config/riscv/vector.md: change rdfrm to fmove * config/riscv/zc.md: change pushpop to load/store Signed-off-by: Edwin Lu --- gcc/config/riscv/generic-ooo.md | 15 ++++++- gcc/config/riscv/generic.md | 20 +++++++-- gcc/config/riscv/riscv.md | 18 ++++---- gcc/config/riscv/sifive-7.md | 17 +++++++- gcc/config/riscv/vector.md | 2 +- gcc/config/riscv/zc.md | 96 ++++++++++++++++++++--------------------- 6 files changed, 102 insertions(+), 66 deletions(-) (limited to 'gcc') diff --git a/gcc/config/riscv/generic-ooo.md b/gcc/config/riscv/generic-ooo.md index 421a7bb9..ef8cb96 100644 --- a/gcc/config/riscv/generic-ooo.md +++ b/gcc/config/riscv/generic-ooo.md @@ -115,9 +115,20 @@ (define_insn_reservation "generic_ooo_alu" 1 (and (eq_attr "tune" "generic_ooo") (eq_attr "type" "unknown,const,arith,shift,slt,multi,auipc,nop,logical,\ - move,bitmanip,min,max,minu,maxu,clz,ctz")) + move,bitmanip,rotate,min,max,minu,maxu,clz,ctz,atomic,\ + condmove,mvpair,zicond")) "generic_ooo_issue,generic_ooo_ixu_alu") +(define_insn_reservation "generic_ooo_sfb_alu" 2 + (and (eq_attr "tune" "generic_ooo") + (eq_attr "type" "sfb_alu")) + "generic_ooo_issue,generic_ooo_ixu_alu") + +;; Branch instructions +(define_insn_reservation "generic_ooo_branch" 1 + (and (eq_attr "tune" "generic_ooo") + (eq_attr "type" "branch,jump,call,jalr,ret,trap")) + "generic_ooo_issue,generic_ooo_ixu_alu") ;; Float move, convert and compare. (define_insn_reservation "generic_ooo_float_move" 3 @@ -184,7 +195,7 @@ (define_insn_reservation "generic_ooo_vec_alu" 3 (and (eq_attr "tune" "generic_ooo") (eq_attr "type" "vialu,viwalu,vext,vicalu,vshift,vnshift,viminmax,vicmp,\ - vimov,vsalu,vaalu,vsshift,vnclip,vmov,vfmov")) + vimov,vsalu,vaalu,vsshift,vnclip,vmov,vfmov,vector")) "generic_ooo_vxu_issue,generic_ooo_vxu_alu") ;; Vector float comparison, conversion etc. diff --git a/gcc/config/riscv/generic.md b/gcc/config/riscv/generic.md index b99ae34..45986cf 100644 --- a/gcc/config/riscv/generic.md +++ b/gcc/config/riscv/generic.md @@ -27,7 +27,9 @@ (define_insn_reservation "generic_alu" 1 (and (eq_attr "tune" "generic") - (eq_attr "type" "unknown,const,arith,shift,slt,multi,auipc,nop,logical,move,bitmanip,min,max,minu,maxu,clz,ctz,cpop")) + (eq_attr "type" "unknown,const,arith,shift,slt,multi,auipc,nop,logical,\ + move,bitmanip,min,max,minu,maxu,clz,ctz,rotate,atomic,\ + condmove,crypto,mvpair,zicond")) "alu") (define_insn_reservation "generic_load" 3 @@ -47,12 +49,17 @@ (define_insn_reservation "generic_branch" 1 (and (eq_attr "tune" "generic") - (eq_attr "type" "branch,jump,call,jalr")) + (eq_attr "type" "branch,jump,call,jalr,ret,trap")) + "alu") + +(define_insn_reservation "generic_sfb_alu" 2 + (and (eq_attr "tune" "generic") + (eq_attr "type" "sfb_alu")) "alu") (define_insn_reservation "generic_imul" 10 (and (eq_attr "tune" "generic") - (eq_attr "type" "imul,clmul")) + (eq_attr "type" "imul,clmul,cpop")) "imuldiv*10") (define_insn_reservation "generic_idivsi" 34 @@ -67,6 +74,12 @@ (eq_attr "mode" "DI"))) "imuldiv*66") +(define_insn_reservation "generic_fmul_half" 5 + (and (eq_attr "tune" "generic") + (and (eq_attr "type" "fadd,fmul,fmadd") + (eq_attr "mode" "HF"))) + "alu") + (define_insn_reservation "generic_fmul_single" 5 (and (eq_attr "tune" "generic") (and (eq_attr "type" "fadd,fmul,fmadd") @@ -88,3 +101,4 @@ (and (eq_attr "tune" "generic") (eq_attr "type" "fsqrt")) "fdivsqrt*25") + diff --git a/gcc/config/riscv/riscv.md b/gcc/config/riscv/riscv.md index b320ad0..c5be1b2 100644 --- a/gcc/config/riscv/riscv.md +++ b/gcc/config/riscv/riscv.md @@ -326,9 +326,7 @@ ;; rotate rotation instructions ;; atomic atomic instructions ;; condmove conditional moves -;; cbo cache block instructions ;; crypto cryptography instructions -;; pushpop zc push and pop instructions ;; mvpair zc move pair instructions ;; zicond zicond instructions ;; Classification of RVV instructions which will be added to each RVV .md pattern and used by scheduler. @@ -468,8 +466,8 @@ mtc,mfc,const,arith,logical,shift,slt,imul,idiv,move,fmove,fadd,fmul, fmadd,fdiv,fcmp,fcvt,fsqrt,multi,auipc,sfb_alu,nop,trap,ghost,bitmanip, rotate,clmul,min,max,minu,maxu,clz,ctz,cpop, - atomic,condmove,cbo,crypto,pushpop,mvpair,zicond,rdvlenb,rdvl,wrvxrm,wrfrm, - rdfrm,vsetvl,vsetvl_pre,vlde,vste,vldm,vstm,vlds,vsts, + atomic,condmove,crypto,mvpair,zicond,rdvlenb,rdvl,wrvxrm,wrfrm, + vsetvl,vsetvl_pre,vlde,vste,vldm,vstm,vlds,vsts, vldux,vldox,vstux,vstox,vldff,vldr,vstr, vlsegde,vssegte,vlsegds,vssegts,vlsegdux,vlsegdox,vssegtux,vssegtox,vlsegdff, vialu,viwalu,vext,vicalu,vshift,vnshift,vicmp,viminmax, @@ -3673,7 +3671,7 @@ UNSPECV_CLEAN)] "TARGET_ZICBOM" "cbo.clean\t%a0" - [(set_attr "type" "cbo")] + [(set_attr "type" "store")] ) (define_insn "riscv_flush_" @@ -3681,7 +3679,7 @@ UNSPECV_FLUSH)] "TARGET_ZICBOM" "cbo.flush\t%a0" - [(set_attr "type" "cbo")] + [(set_attr "type" "store")] ) (define_insn "riscv_inval_" @@ -3689,7 +3687,7 @@ UNSPECV_INVAL)] "TARGET_ZICBOM" "cbo.inval\t%a0" - [(set_attr "type" "cbo")] + [(set_attr "type" "store")] ) (define_insn "riscv_zero_" @@ -3697,7 +3695,7 @@ UNSPECV_ZERO)] "TARGET_ZICBOZ" "cbo.zero\t%a0" - [(set_attr "type" "cbo")] + [(set_attr "type" "store")] ) (define_insn "prefetch" @@ -3713,7 +3711,7 @@ default: gcc_unreachable (); } } - [(set_attr "type" "cbo")]) + [(set_attr "type" "store")]) (define_insn "riscv_prefetchi_" [(unspec_volatile:X [(match_operand:X 0 "address_operand" "r") @@ -3721,7 +3719,7 @@ UNSPECV_PREI)] "TARGET_ZICBOP" "prefetch.i\t%a0" - [(set_attr "type" "cbo")]) + [(set_attr "type" "store")]) (define_expand "extv" [(set (match_operand:GPR 0 "register_operand" "=r") diff --git a/gcc/config/riscv/sifive-7.md b/gcc/config/riscv/sifive-7.md index a63394c..52904f5 100644 --- a/gcc/config/riscv/sifive-7.md +++ b/gcc/config/riscv/sifive-7.md @@ -34,7 +34,7 @@ (define_insn_reservation "sifive_7_branch" 1 (and (eq_attr "tune" "sifive_7") - (eq_attr "type" "branch")) + (eq_attr "type" "branch,ret,trap")) "sifive_7_B") (define_insn_reservation "sifive_7_sfb_alu" 2 @@ -59,7 +59,8 @@ (define_insn_reservation "sifive_7_alu" 2 (and (eq_attr "tune" "sifive_7") - (eq_attr "type" "unknown,arith,shift,slt,multi,logical,move")) + (eq_attr "type" "unknown,arith,shift,slt,multi,logical,move,bitmanip,\ + rotate,min,max,minu,maxu,clz,ctz,atomic,condmove,crypto,mvpair,zicond")) "sifive_7_A|sifive_7_B") (define_insn_reservation "sifive_7_load_immediate" 1 @@ -67,6 +68,12 @@ (eq_attr "type" "nop,const,auipc")) "sifive_7_A|sifive_7_B") +(define_insn_reservation "sifive_7_hfma" 5 + (and (eq_attr "tune" "sifive_7") + (and (eq_attr "type" "fadd,fmul,fmadd") + (eq_attr "mode" "HF"))) + "sifive_7_B") + (define_insn_reservation "sifive_7_sfma" 5 (and (eq_attr "tune" "sifive_7") (and (eq_attr "type" "fadd,fmul,fmadd") @@ -106,6 +113,12 @@ (eq_attr "type" "mfc")) "sifive_7_A") +;; Popcount and clmul. +(define_insn_reservation "sifive_7_popcount" 2 + (and (eq_attr "tune" "sifive_7") + (eq_attr "type" "cpop,clmul")) + "sifive_7_A") + (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") diff --git a/gcc/config/riscv/vector.md b/gcc/config/riscv/vector.md index ab6e099..f89f9c2 100644 --- a/gcc/config/riscv/vector.md +++ b/gcc/config/riscv/vector.md @@ -1054,7 +1054,7 @@ (reg:SI FRM_REGNUM))] "TARGET_VECTOR" "frrm\t%0" - [(set_attr "type" "rdfrm") + [(set_attr "type" "fmove") (set_attr "mode" "SI")] ) diff --git a/gcc/config/riscv/zc.md b/gcc/config/riscv/zc.md index 216232c..462ab37 100644 --- a/gcc/config/riscv/zc.md +++ b/gcc/config/riscv/zc.md @@ -27,7 +27,7 @@ (const_int ))))] "TARGET_ZCMP" "cm.pop {ra}, %0" -[(set_attr "type" "pushpop")]) +[(set_attr "type" "load")]) (define_insn "@gpr_multi_pop_up_to_s0_" [(set (reg:X SP_REGNUM) @@ -41,7 +41,7 @@ (const_int ))))] "TARGET_ZCMP" "cm.pop {ra, s0}, %0" -[(set_attr "type" "pushpop")]) +[(set_attr "type" "load")]) (define_insn "@gpr_multi_pop_up_to_s1_" [(set (reg:X SP_REGNUM) @@ -58,7 +58,7 @@ (const_int ))))] "TARGET_ZCMP" "cm.pop {ra, s0-s1}, %0" -[(set_attr "type" "pushpop")]) +[(set_attr "type" "load")]) (define_insn "@gpr_multi_pop_up_to_s2_" [(set (reg:X SP_REGNUM) @@ -78,7 +78,7 @@ (const_int ))))] "TARGET_ZCMP" "cm.pop {ra, s0-s2}, %0" -[(set_attr "type" "pushpop")]) +[(set_attr "type" "load")]) (define_insn "@gpr_multi_pop_up_to_s3_" [(set (reg:X SP_REGNUM) @@ -101,7 +101,7 @@ (const_int ))))] "TARGET_ZCMP" "cm.pop {ra, s0-s3}, %0" -[(set_attr "type" "pushpop")]) +[(set_attr "type" "load")]) (define_insn "@gpr_multi_pop_up_to_s4_" [(set (reg:X SP_REGNUM) @@ -127,7 +127,7 @@ (const_int ))))] "TARGET_ZCMP" "cm.pop {ra, s0-s4}, %0" -[(set_attr "type" "pushpop")]) +[(set_attr "type" "load")]) (define_insn "@gpr_multi_pop_up_to_s5_" [(set (reg:X SP_REGNUM) @@ -156,7 +156,7 @@ (const_int ))))] "TARGET_ZCMP" "cm.pop {ra, s0-s5}, %0" -[(set_attr "type" "pushpop")]) +[(set_attr "type" "load")]) (define_insn "@gpr_multi_pop_up_to_s6_" [(set (reg:X SP_REGNUM) @@ -188,7 +188,7 @@ (const_int ))))] "TARGET_ZCMP" "cm.pop {ra, s0-s6}, %0" -[(set_attr "type" "pushpop")]) +[(set_attr "type" "load")]) (define_insn "@gpr_multi_pop_up_to_s7_" [(set (reg:X SP_REGNUM) @@ -223,7 +223,7 @@ (const_int ))))] "TARGET_ZCMP" "cm.pop {ra, s0-s7}, %0" -[(set_attr "type" "pushpop")]) +[(set_attr "type" "load")]) (define_insn "@gpr_multi_pop_up_to_s8_" [(set (reg:X SP_REGNUM) @@ -261,7 +261,7 @@ (const_int ))))] "TARGET_ZCMP" "cm.pop {ra, s0-s8}, %0" -[(set_attr "type" "pushpop")]) +[(set_attr "type" "load")]) (define_insn "@gpr_multi_pop_up_to_s9_" [(set (reg:X SP_REGNUM) @@ -302,7 +302,7 @@ (const_int ))))] "TARGET_ZCMP" "cm.pop {ra, s0-s9}, %0" -[(set_attr "type" "pushpop")]) +[(set_attr "type" "load")]) (define_insn "@gpr_multi_pop_up_to_s11_" [(set (reg:X SP_REGNUM) @@ -349,7 +349,7 @@ (const_int ))))] "TARGET_ZCMP" "cm.pop {ra, s0-s11}, %0" -[(set_attr "type" "pushpop")]) +[(set_attr "type" "load")]) (define_insn "@gpr_multi_popret_up_to_ra_" [(set (reg:X SP_REGNUM) @@ -362,7 +362,7 @@ (use (reg:SI RETURN_ADDR_REGNUM))] "TARGET_ZCMP" "cm.popret {ra}, %0" -[(set_attr "type" "pushpop")]) +[(set_attr "type" "load")]) (define_insn "@gpr_multi_popret_up_to_s0_" [(set (reg:X SP_REGNUM) @@ -378,7 +378,7 @@ (use (reg:SI RETURN_ADDR_REGNUM))] "TARGET_ZCMP" "cm.popret {ra, s0}, %0" -[(set_attr "type" "pushpop")]) +[(set_attr "type" "load")]) (define_insn "@gpr_multi_popret_up_to_s1_" [(set (reg:X SP_REGNUM) @@ -397,7 +397,7 @@ (use (reg:SI RETURN_ADDR_REGNUM))] "TARGET_ZCMP" "cm.popret {ra, s0-s1}, %0" -[(set_attr "type" "pushpop")]) +[(set_attr "type" "load")]) (define_insn "@gpr_multi_popret_up_to_s2_" [(set (reg:X SP_REGNUM) @@ -419,7 +419,7 @@ (use (reg:SI RETURN_ADDR_REGNUM))] "TARGET_ZCMP" "cm.popret {ra, s0-s2}, %0" -[(set_attr "type" "pushpop")]) +[(set_attr "type" "load")]) (define_insn "@gpr_multi_popret_up_to_s3_" [(set (reg:X SP_REGNUM) @@ -444,7 +444,7 @@ (use (reg:SI RETURN_ADDR_REGNUM))] "TARGET_ZCMP" "cm.popret {ra, s0-s3}, %0" -[(set_attr "type" "pushpop")]) +[(set_attr "type" "load")]) (define_insn "@gpr_multi_popret_up_to_s4_" [(set (reg:X SP_REGNUM) @@ -472,7 +472,7 @@ (use (reg:SI RETURN_ADDR_REGNUM))] "TARGET_ZCMP" "cm.popret {ra, s0-s4}, %0" -[(set_attr "type" "pushpop")]) +[(set_attr "type" "load")]) (define_insn "@gpr_multi_popret_up_to_s5_" [(set (reg:X SP_REGNUM) @@ -503,7 +503,7 @@ (use (reg:SI RETURN_ADDR_REGNUM))] "TARGET_ZCMP" "cm.popret {ra, s0-s5}, %0" -[(set_attr "type" "pushpop")]) +[(set_attr "type" "load")]) (define_insn "@gpr_multi_popret_up_to_s6_" [(set (reg:X SP_REGNUM) @@ -537,7 +537,7 @@ (use (reg:SI RETURN_ADDR_REGNUM))] "TARGET_ZCMP" "cm.popret {ra, s0-s6}, %0" -[(set_attr "type" "pushpop")]) +[(set_attr "type" "load")]) (define_insn "@gpr_multi_popret_up_to_s7_" [(set (reg:X SP_REGNUM) @@ -574,7 +574,7 @@ (use (reg:SI RETURN_ADDR_REGNUM))] "TARGET_ZCMP" "cm.popret {ra, s0-s7}, %0" -[(set_attr "type" "pushpop")]) +[(set_attr "type" "load")]) (define_insn "@gpr_multi_popret_up_to_s8_" [(set (reg:X SP_REGNUM) @@ -614,7 +614,7 @@ (use (reg:SI RETURN_ADDR_REGNUM))] "TARGET_ZCMP" "cm.popret {ra, s0-s8}, %0" -[(set_attr "type" "pushpop")]) +[(set_attr "type" "load")]) (define_insn "@gpr_multi_popret_up_to_s9_" [(set (reg:X SP_REGNUM) @@ -657,7 +657,7 @@ (use (reg:SI RETURN_ADDR_REGNUM))] "TARGET_ZCMP" "cm.popret {ra, s0-s9}, %0" -[(set_attr "type" "pushpop")]) +[(set_attr "type" "load")]) (define_insn "@gpr_multi_popret_up_to_s11_" [(set (reg:X SP_REGNUM) @@ -706,7 +706,7 @@ (use (reg:SI RETURN_ADDR_REGNUM))] "TARGET_ZCMP" "cm.popret {ra, s0-s11}, %0" -[(set_attr "type" "pushpop")]) +[(set_attr "type" "load")]) (define_insn "@gpr_multi_popretz_up_to_ra_" [(set (reg:X SP_REGNUM) @@ -722,7 +722,7 @@ (use (reg:SI RETURN_ADDR_REGNUM))] "TARGET_ZCMP" "cm.popretz {ra}, %0" -[(set_attr "type" "pushpop")]) +[(set_attr "type" "load")]) (define_insn "@gpr_multi_popretz_up_to_s0_" [(set (reg:X SP_REGNUM) @@ -741,7 +741,7 @@ (use (reg:SI RETURN_ADDR_REGNUM))] "TARGET_ZCMP" "cm.popretz {ra, s0}, %0" -[(set_attr "type" "pushpop")]) +[(set_attr "type" "load")]) (define_insn "@gpr_multi_popretz_up_to_s1_" [(set (reg:X SP_REGNUM) @@ -763,7 +763,7 @@ (use (reg:SI RETURN_ADDR_REGNUM))] "TARGET_ZCMP" "cm.popretz {ra, s0-s1}, %0" -[(set_attr "type" "pushpop")]) +[(set_attr "type" "load")]) (define_insn "@gpr_multi_popretz_up_to_s2_" [(set (reg:X SP_REGNUM) @@ -788,7 +788,7 @@ (use (reg:SI RETURN_ADDR_REGNUM))] "TARGET_ZCMP" "cm.popretz {ra, s0-s2}, %0" -[(set_attr "type" "pushpop")]) +[(set_attr "type" "load")]) (define_insn "@gpr_multi_popretz_up_to_s3_" [(set (reg:X SP_REGNUM) @@ -816,7 +816,7 @@ (use (reg:SI RETURN_ADDR_REGNUM))] "TARGET_ZCMP" "cm.popretz {ra, s0-s3}, %0" -[(set_attr "type" "pushpop")]) +[(set_attr "type" "load")]) (define_insn "@gpr_multi_popretz_up_to_s4_" [(set (reg:X SP_REGNUM) @@ -847,7 +847,7 @@ (use (reg:SI RETURN_ADDR_REGNUM))] "TARGET_ZCMP" "cm.popretz {ra, s0-s4}, %0" -[(set_attr "type" "pushpop")]) +[(set_attr "type" "load")]) (define_insn "@gpr_multi_popretz_up_to_s5_" [(set (reg:X SP_REGNUM) @@ -881,7 +881,7 @@ (use (reg:SI RETURN_ADDR_REGNUM))] "TARGET_ZCMP" "cm.popretz {ra, s0-s5}, %0" -[(set_attr "type" "pushpop")]) +[(set_attr "type" "load")]) (define_insn "@gpr_multi_popretz_up_to_s6_" [(set (reg:X SP_REGNUM) @@ -918,7 +918,7 @@ (use (reg:SI RETURN_ADDR_REGNUM))] "TARGET_ZCMP" "cm.popretz {ra, s0-s6}, %0" -[(set_attr "type" "pushpop")]) +[(set_attr "type" "load")]) (define_insn "@gpr_multi_popretz_up_to_s7_" [(set (reg:X SP_REGNUM) @@ -958,7 +958,7 @@ (use (reg:SI RETURN_ADDR_REGNUM))] "TARGET_ZCMP" "cm.popretz {ra, s0-s7}, %0" -[(set_attr "type" "pushpop")]) +[(set_attr "type" "load")]) (define_insn "@gpr_multi_popretz_up_to_s8_" [(set (reg:X SP_REGNUM) @@ -1001,7 +1001,7 @@ (use (reg:SI RETURN_ADDR_REGNUM))] "TARGET_ZCMP" "cm.popretz {ra, s0-s8}, %0" -[(set_attr "type" "pushpop")]) +[(set_attr "type" "load")]) (define_insn "@gpr_multi_popretz_up_to_s9_" [(set (reg:X SP_REGNUM) @@ -1047,7 +1047,7 @@ (use (reg:SI RETURN_ADDR_REGNUM))] "TARGET_ZCMP" "cm.popretz {ra, s0-s9}, %0" -[(set_attr "type" "pushpop")]) +[(set_attr "type" "load")]) (define_insn "@gpr_multi_popretz_up_to_s11_" [(set (reg:X SP_REGNUM) @@ -1099,7 +1099,7 @@ (use (reg:SI RETURN_ADDR_REGNUM))] "TARGET_ZCMP" "cm.popretz {ra, s0-s11}, %0" -[(set_attr "type" "pushpop")]) +[(set_attr "type" "load")]) (define_insn "@gpr_multi_push_up_to_ra_" [(set (mem:X (plus:X (reg:X SP_REGNUM) @@ -1110,7 +1110,7 @@ (match_operand 0 "stack_push_up_to_ra_operand" "I")))] "TARGET_ZCMP" "cm.push {ra}, %0" -[(set_attr "type" "pushpop")]) +[(set_attr "type" "store")]) (define_insn "@gpr_multi_push_up_to_s0_" [(set (mem:X (plus:X (reg:X SP_REGNUM) @@ -1124,7 +1124,7 @@ (match_operand 0 "stack_push_up_to_s0_operand" "I")))] "TARGET_ZCMP" "cm.push {ra, s0}, %0" -[(set_attr "type" "pushpop")]) +[(set_attr "type" "store")]) (define_insn "@gpr_multi_push_up_to_s1_" [(set (mem:X (plus:X (reg:X SP_REGNUM) @@ -1141,7 +1141,7 @@ (match_operand 0 "stack_push_up_to_s1_operand" "I")))] "TARGET_ZCMP" "cm.push {ra, s0-s1}, %0" -[(set_attr "type" "pushpop")]) +[(set_attr "type" "store")]) (define_insn "@gpr_multi_push_up_to_s2_" [(set (mem:X (plus:X (reg:X SP_REGNUM) @@ -1161,7 +1161,7 @@ (match_operand 0 "stack_push_up_to_s2_operand" "I")))] "TARGET_ZCMP" "cm.push {ra, s0-s2}, %0" -[(set_attr "type" "pushpop")]) +[(set_attr "type" "store")]) (define_insn "@gpr_multi_push_up_to_s3_" [(set (mem:X (plus:X (reg:X SP_REGNUM) @@ -1184,7 +1184,7 @@ (match_operand 0 "stack_push_up_to_s3_operand" "I")))] "TARGET_ZCMP" "cm.push {ra, s0-s3}, %0" -[(set_attr "type" "pushpop")]) +[(set_attr "type" "store")]) (define_insn "@gpr_multi_push_up_to_s4_" [(set (mem:X (plus:X (reg:X SP_REGNUM) @@ -1210,7 +1210,7 @@ (match_operand 0 "stack_push_up_to_s4_operand" "I")))] "TARGET_ZCMP" "cm.push {ra, s0-s4}, %0" -[(set_attr "type" "pushpop")]) +[(set_attr "type" "store")]) (define_insn "@gpr_multi_push_up_to_s5_" [(set (mem:X (plus:X (reg:X SP_REGNUM) @@ -1239,7 +1239,7 @@ (match_operand 0 "stack_push_up_to_s5_operand" "I")))] "TARGET_ZCMP" "cm.push {ra, s0-s5}, %0" -[(set_attr "type" "pushpop")]) +[(set_attr "type" "store")]) (define_insn "@gpr_multi_push_up_to_s6_" [(set (mem:X (plus:X (reg:X SP_REGNUM) @@ -1271,7 +1271,7 @@ (match_operand 0 "stack_push_up_to_s6_operand" "I")))] "TARGET_ZCMP" "cm.push {ra, s0-s6}, %0" -[(set_attr "type" "pushpop")]) +[(set_attr "type" "store")]) (define_insn "@gpr_multi_push_up_to_s7_" [(set (mem:X (plus:X (reg:X SP_REGNUM) @@ -1306,7 +1306,7 @@ (match_operand 0 "stack_push_up_to_s7_operand" "I")))] "TARGET_ZCMP" "cm.push {ra, s0-s7}, %0" -[(set_attr "type" "pushpop")]) +[(set_attr "type" "store")]) (define_insn "@gpr_multi_push_up_to_s8_" [(set (mem:X (plus:X (reg:X SP_REGNUM) @@ -1344,7 +1344,7 @@ (match_operand 0 "stack_push_up_to_s8_operand" "I")))] "TARGET_ZCMP" "cm.push {ra, s0-s8}, %0" -[(set_attr "type" "pushpop")]) +[(set_attr "type" "store")]) (define_insn "@gpr_multi_push_up_to_s9_" [(set (mem:X (plus:X (reg:X SP_REGNUM) @@ -1385,7 +1385,7 @@ (match_operand 0 "stack_push_up_to_s9_operand" "I")))] "TARGET_ZCMP" "cm.push {ra, s0-s9}, %0" -[(set_attr "type" "pushpop")]) +[(set_attr "type" "store")]) (define_insn "@gpr_multi_push_up_to_s11_" [(set (mem:X (plus:X (reg:X SP_REGNUM) @@ -1432,7 +1432,7 @@ (match_operand 0 "stack_push_up_to_s11_operand" "I")))] "TARGET_ZCMP" "cm.push {ra, s0-s11}, %0" -[(set_attr "type" "pushpop")]) +[(set_attr "type" "store")]) ;; ZCMP mv (define_insn "*mva01s" -- cgit v1.1 From e56fb037d9d265682f5e7217d8a4c12a8d3fddf8 Mon Sep 17 00:00:00 2001 From: Edwin Lu Date: Wed, 31 Jan 2024 10:43:09 -0800 Subject: RISC-V: Add vector related pipelines Creates new generic vector pipeline file common to all cpu tunes. Moves all vector related pipelines from generic-ooo to generic-vector-ooo. Creates new vector crypto related insn reservations. gcc/ChangeLog: * config/riscv/generic-ooo.md (generic_ooo): Move reservation (generic_ooo_vec_load): ditto (generic_ooo_vec_store): ditto (generic_ooo_vec_loadstore_seg): ditto (generic_ooo_vec_alu): ditto (generic_ooo_vec_fcmp): ditto (generic_ooo_vec_imul): ditto (generic_ooo_vec_fadd): ditto (generic_ooo_vec_fmul): ditto (generic_ooo_crypto): ditto (generic_ooo_perm): ditto (generic_ooo_vec_reduction): ditto (generic_ooo_vec_ordered_reduction): ditto (generic_ooo_vec_idiv): ditto (generic_ooo_vec_float_divsqrt): ditto (generic_ooo_vec_mask): ditto (generic_ooo_vec_vesetvl): ditto (generic_ooo_vec_setrm): ditto (generic_ooo_vec_readlen): ditto * config/riscv/riscv.md: include generic-vector-ooo * config/riscv/generic-vector-ooo.md: New file. to here Signed-off-by: Edwin Lu Co-authored-by: Robin Dapp --- gcc/config/riscv/generic-ooo.md | 127 +---------------------------- gcc/config/riscv/generic-vector-ooo.md | 143 +++++++++++++++++++++++++++++++++ gcc/config/riscv/riscv.md | 1 + 3 files changed, 145 insertions(+), 126 deletions(-) create mode 100644 gcc/config/riscv/generic-vector-ooo.md (limited to 'gcc') diff --git a/gcc/config/riscv/generic-ooo.md b/gcc/config/riscv/generic-ooo.md index ef8cb96..4e8297b 100644 --- a/gcc/config/riscv/generic-ooo.md +++ b/gcc/config/riscv/generic-ooo.md @@ -1,5 +1,5 @@ ;; RISC-V generic out-of-order core scheduling model. -;; Copyright (C) 2017-2024 Free Software Foundation, Inc. +;; Copyright (C) 2023-2024 Free Software Foundation, Inc. ;; ;; This file is part of GCC. ;; @@ -48,9 +48,6 @@ ;; Integer/float issue queues. (define_cpu_unit "issue0,issue1,issue2,issue3,issue4" "generic_ooo") -;; Separate issue queue for vector instructions. -(define_cpu_unit "generic_ooo_vxu_issue" "generic_ooo") - ;; Integer/float execution units. (define_cpu_unit "ixu0,ixu1,ixu2,ixu3" "generic_ooo") (define_cpu_unit "fxu0,fxu1" "generic_ooo") @@ -58,12 +55,6 @@ ;; Integer subunit for division. (define_cpu_unit "generic_ooo_div" "generic_ooo") -;; Vector execution unit. -(define_cpu_unit "generic_ooo_vxu_alu" "generic_ooo") - -;; Vector subunit that does mult/div/sqrt. -(define_cpu_unit "generic_ooo_vxu_multicycle" "generic_ooo") - ;; Shortcuts (define_reservation "generic_ooo_issue" "issue0|issue1|issue2|issue3|issue4") (define_reservation "generic_ooo_ixu_alu" "ixu0|ixu1|ixu2|ixu3") @@ -92,25 +83,6 @@ (eq_attr "type" "fpstore")) "generic_ooo_issue,generic_ooo_fxu") -;; Vector load/store -(define_insn_reservation "generic_ooo_vec_load" 6 - (and (eq_attr "tune" "generic_ooo") - (eq_attr "type" "vlde,vldm,vlds,vldux,vldox,vldff,vldr")) - "generic_ooo_vxu_issue,generic_ooo_vxu_alu") - -(define_insn_reservation "generic_ooo_vec_store" 6 - (and (eq_attr "tune" "generic_ooo") - (eq_attr "type" "vste,vstm,vsts,vstux,vstox,vstr")) - "generic_ooo_vxu_issue,generic_ooo_vxu_alu") - -;; Vector segment loads/stores. -(define_insn_reservation "generic_ooo_vec_loadstore_seg" 10 - (and (eq_attr "tune" "generic_ooo") - (eq_attr "type" "vlsegde,vlsegds,vlsegdux,vlsegdox,vlsegdff,\ - vssegte,vssegts,vssegtux,vssegtox")) - "generic_ooo_vxu_issue,generic_ooo_vxu_alu") - - ;; Generic integer instructions. (define_insn_reservation "generic_ooo_alu" 1 (and (eq_attr "tune" "generic_ooo") @@ -191,103 +163,6 @@ (eq_attr "type" "cpop,clmul")) "generic_ooo_issue,generic_ooo_ixu_alu") -;; Regular vector operations and integer comparisons. -(define_insn_reservation "generic_ooo_vec_alu" 3 - (and (eq_attr "tune" "generic_ooo") - (eq_attr "type" "vialu,viwalu,vext,vicalu,vshift,vnshift,viminmax,vicmp,\ - vimov,vsalu,vaalu,vsshift,vnclip,vmov,vfmov,vector")) - "generic_ooo_vxu_issue,generic_ooo_vxu_alu") - -;; Vector float comparison, conversion etc. -(define_insn_reservation "generic_ooo_vec_fcmp" 3 - (and (eq_attr "tune" "generic_ooo") - (eq_attr "type" "vfrecp,vfminmax,vfcmp,vfsgnj,vfclass,vfcvtitof,\ - vfcvtftoi,vfwcvtitof,vfwcvtftoi,vfwcvtftof,vfncvtitof,\ - vfncvtftoi,vfncvtftof")) - "generic_ooo_vxu_issue,generic_ooo_vxu_alu") - -;; Vector integer multiplication. -(define_insn_reservation "generic_ooo_vec_imul" 4 - (and (eq_attr "tune" "generic_ooo") - (eq_attr "type" "vimul,viwmul,vimuladd,viwmuladd,vsmul")) - "generic_ooo_vxu_issue,generic_ooo_vxu_alu") - -;; Vector float addition. -(define_insn_reservation "generic_ooo_vec_fadd" 4 - (and (eq_attr "tune" "generic_ooo") - (eq_attr "type" "vfalu,vfwalu")) - "generic_ooo_vxu_issue,generic_ooo_vxu_alu") - -;; Vector float multiplication and FMA. -(define_insn_reservation "generic_ooo_vec_fmul" 6 - (and (eq_attr "tune" "generic_ooo") - (eq_attr "type" "vfmul,vfwmul,vfmuladd,vfwmuladd")) - "generic_ooo_vxu_issue,generic_ooo_vxu_alu") - -;; Vector crypto, assumed to be a generic operation for now. -(define_insn_reservation "generic_ooo_crypto" 4 - (and (eq_attr "tune" "generic_ooo") - (eq_attr "type" "crypto")) - "generic_ooo_vxu_issue,generic_ooo_vxu_alu") - -;; Vector permute. -(define_insn_reservation "generic_ooo_perm" 3 - (and (eq_attr "tune" "generic_ooo") - (eq_attr "type" "vimerge,vfmerge,vslideup,vslidedown,vislide1up,\ - vislide1down,vfslide1up,vfslide1down,vgather,vcompress")) - "generic_ooo_vxu_issue,generic_ooo_vxu_alu") - -;; Vector reduction. -(define_insn_reservation "generic_ooo_vec_reduction" 8 - (and (eq_attr "tune" "generic_ooo") - (eq_attr "type" "vired,viwred,vfredu,vfwredu")) - "generic_ooo_vxu_issue,generic_ooo_vxu_multicycle") - -;; Vector ordered reduction, assume the latency number is for -;; a 128-bit vector. It is scaled in riscv_sched_adjust_cost -;; for larger vectors. -(define_insn_reservation "generic_ooo_vec_ordered_reduction" 10 - (and (eq_attr "tune" "generic_ooo") - (eq_attr "type" "vfredo,vfwredo")) - "generic_ooo_vxu_issue,generic_ooo_vxu_multicycle*3") - -;; Vector integer division, assume not pipelined. -(define_insn_reservation "generic_ooo_vec_idiv" 16 - (and (eq_attr "tune" "generic_ooo") - (eq_attr "type" "vidiv")) - "generic_ooo_vxu_issue,generic_ooo_vxu_multicycle*3") - -;; Vector float divisions and sqrt, assume not pipelined. -(define_insn_reservation "generic_ooo_vec_float_divsqrt" 16 - (and (eq_attr "tune" "generic_ooo") - (eq_attr "type" "vfdiv,vfsqrt")) - "generic_ooo_vxu_issue,generic_ooo_vxu_multicycle*3") - -;; Vector mask operations. -(define_insn_reservation "generic_ooo_vec_mask" 2 - (and (eq_attr "tune" "generic_ooo") - (eq_attr "type" "vmalu,vmpop,vmffs,vmsfs,vmiota,vmidx,vimovvx,vimovxv,\ - vfmovvf,vfmovfv")) - "generic_ooo_vxu_issue,generic_ooo_vxu_alu") - -;; Vector vsetvl. -(define_insn_reservation "generic_ooo_vec_vesetvl" 1 - (and (eq_attr "tune" "generic_ooo") - (eq_attr "type" "vsetvl,vsetvl_pre")) - "generic_ooo_vxu_issue") - -;; Vector rounding mode setters, assume pipeline barrier. -(define_insn_reservation "generic_ooo_vec_setrm" 20 - (and (eq_attr "tune" "generic_ooo") - (eq_attr "type" "wrvxrm,wrfrm")) - "generic_ooo_vxu_issue,generic_ooo_vxu_issue*3") - -;; Vector read vlen/vlenb. -(define_insn_reservation "generic_ooo_vec_readlen" 4 - (and (eq_attr "tune" "generic_ooo") - (eq_attr "type" "rdvlenb,rdvl")) - "generic_ooo_vxu_issue,generic_ooo_vxu_issue") - ;; Transfer from/to coprocessor. Assume not pipelined. (define_insn_reservation "generic_ooo_xfer" 4 (and (eq_attr "tune" "generic_ooo") diff --git a/gcc/config/riscv/generic-vector-ooo.md b/gcc/config/riscv/generic-vector-ooo.md new file mode 100644 index 0000000..96cb1a0 --- /dev/null +++ b/gcc/config/riscv/generic-vector-ooo.md @@ -0,0 +1,143 @@ +;; Copyright (C) 2024-2024 Free Software Foundation, Inc. + +;; This file is part of GCC. + +;; GCC 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, or (at your +;; option) any later version. + +;; GCC 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 +;; . +;; Vector load/store + +(define_automaton "vector_ooo") + +;; Separate issue queue for vector instructions. +(define_cpu_unit "vxu_ooo_issue" "vector_ooo") + +;; Vector execution unit. +(define_cpu_unit "vxu_ooo_alu" "vector_ooo") + +;; Vector subunit that does mult/div/sqrt. +(define_cpu_unit "vxu_ooo_multicycle" "vector_ooo") + +(define_insn_reservation "vec_load" 6 + (eq_attr "type" "vlde,vldm,vlds,vldux,vldox,vldff,vldr") + "vxu_ooo_issue,vxu_ooo_alu") + +(define_insn_reservation "vec_store" 6 + (eq_attr "type" "vste,vstm,vsts,vstux,vstox,vstr") + "vxu_ooo_issue,vxu_ooo_alu") + +;; Vector segment loads/stores. +(define_insn_reservation "vec_loadstore_seg" 10 + (eq_attr "type" "vlsegde,vlsegds,vlsegdux,vlsegdox,vlsegdff,\ + vssegte,vssegts,vssegtux,vssegtox") + "vxu_ooo_issue,vxu_ooo_alu") + +;; Regular vector operations and integer comparisons. +(define_insn_reservation "vec_alu" 3 + (eq_attr "type" "vialu,viwalu,vext,vicalu,vshift,vnshift,viminmax,vicmp,\ + vimov,vsalu,vaalu,vsshift,vnclip,vmov,vfmov,vector,\ + vandn,vbrev,vbrev8,vrev8,vclz,vctz,vrol,vror,vwsll") + "vxu_ooo_issue,vxu_ooo_alu") + +;; Vector float comparison, conversion etc. +(define_insn_reservation "vec_fcmp" 3 + (eq_attr "type" "vfrecp,vfminmax,vfcmp,vfsgnj,vfclass,vfcvtitof,\ + vfcvtftoi,vfwcvtitof,vfwcvtftoi,vfwcvtftof,vfncvtitof,\ + vfncvtftoi,vfncvtftof") + "vxu_ooo_issue,vxu_ooo_alu") + +;; Vector integer multiplication. +(define_insn_reservation "vec_imul" 4 + (eq_attr "type" "vimul,viwmul,vimuladd,viwmuladd,vsmul,vclmul,vclmulh,\ + vghsh,vgmul") + "vxu_ooo_issue,vxu_ooo_alu") + +;; Vector float addition. +(define_insn_reservation "vec_fadd" 4 + (eq_attr "type" "vfalu,vfwalu") + "vxu_ooo_issue,vxu_ooo_alu") + +;; Vector float multiplication and FMA. +(define_insn_reservation "vec_fmul" 6 + (eq_attr "type" "vfmul,vfwmul,vfmuladd,vfwmuladd") + "vxu_ooo_issue,vxu_ooo_alu") + +;; Vector crypto, assumed to be a generic operation for now. +(define_insn_reservation "vec_crypto" 4 + (eq_attr "type" "crypto") + "vxu_ooo_issue,vxu_ooo_alu") + +;; Vector crypto, AES +(define_insn_reservation "vec_crypto_aes" 4 + (eq_attr "type" "vaesef,vaesem,vaesdf,vaesdm,vaeskf1,vaeskf2,vaesz") + "vxu_ooo_issue,vxu_ooo_alu") + +;; Vector crypto, sha +(define_insn_reservation "vec_crypto_sha" 4 + (eq_attr "type" "vsha2ms,vsha2ch,vsha2cl") + "vxu_ooo_issue,vxu_ooo_alu") + +;; Vector crypto, SM3/4 +(define_insn_reservation "vec_crypto_sm" 4 + (eq_attr "type" "vsm4k,vsm4r,vsm3me,vsm3c") + "vxu_ooo_issue,vxu_ooo_alu") + +;; Vector permute. +(define_insn_reservation "vec_perm" 3 + (eq_attr "type" "vimerge,vfmerge,vslideup,vslidedown,vislide1up,\ + vislide1down,vfslide1up,vfslide1down,vgather,vcompress") + "vxu_ooo_issue,vxu_ooo_alu") + +;; Vector reduction. +(define_insn_reservation "vec_reduction" 8 + (eq_attr "type" "vired,viwred,vfredu,vfwredu") + "vxu_ooo_issue,vxu_ooo_multicycle") + +;; Vector ordered reduction, assume the latency number is for +;; a 128-bit vector. It is scaled in riscv_sched_adjust_cost +;; for larger vectors. +(define_insn_reservation "vec_ordered_reduction" 10 + (eq_attr "type" "vfredo,vfwredo") + "vxu_ooo_issue,vxu_ooo_multicycle*3") + +;; Vector integer division, assume not pipelined. +(define_insn_reservation "vec_idiv" 16 + (eq_attr "type" "vidiv") + "vxu_ooo_issue,vxu_ooo_multicycle*3") + +;; Vector float divisions and sqrt, assume not pipelined. +(define_insn_reservation "vec_float_divsqrt" 16 + (eq_attr "type" "vfdiv,vfsqrt") + "vxu_ooo_issue,vxu_ooo_multicycle*3") + +;; Vector mask operations. +(define_insn_reservation "vec_mask" 2 + (eq_attr "type" "vmalu,vmpop,vmffs,vmsfs,vmiota,vmidx,vimovvx,vimovxv,\ + vfmovvf,vfmovfv") + "vxu_ooo_issue,vxu_ooo_alu") + +;; Vector vsetvl. +(define_insn_reservation "vec_vesetvl" 1 + (eq_attr "type" "vsetvl,vsetvl_pre") + "vxu_ooo_issue") + +;; Vector rounding mode setters, assume pipeline barrier. +(define_insn_reservation "vec_setrm" 20 + (eq_attr "type" "wrvxrm,wrfrm") + "vxu_ooo_issue,vxu_ooo_issue*3") + +;; Vector read vlen/vlenb. +(define_insn_reservation "vec_readlen" 4 + (eq_attr "type" "rdvlenb,rdvl") + "vxu_ooo_issue,vxu_ooo_issue") + diff --git a/gcc/config/riscv/riscv.md b/gcc/config/riscv/riscv.md index c5be1b2..53d11a8 100644 --- a/gcc/config/riscv/riscv.md +++ b/gcc/config/riscv/riscv.md @@ -3847,6 +3847,7 @@ (include "generic.md") (include "sifive-7.md") (include "thead.md") +(include "generic-vector-ooo.md") (include "generic-ooo.md") (include "vector.md") (include "vector-crypto.md") -- cgit v1.1 From 4b799a16ae59fc0f508c5931ebf1851a3446b707 Mon Sep 17 00:00:00 2001 From: Edwin Lu Date: Wed, 31 Jan 2024 10:45:43 -0800 Subject: RISC-V: Use default cost model for insn scheduling Use default cost model scheduling on these test cases. All these tests introduce scan dump failures with -mtune generic-ooo. Since the vector cost models are the same across all three tunes, some of the tests in PR113249 will be fixed with this patch series. PR target/113249 gcc/testsuite/ChangeLog: * g++.target/riscv/rvv/base/bug-1.C: use default scheduling * gcc.target/riscv/rvv/autovec/reduc/reduc_call-2.c: ditto * gcc.target/riscv/rvv/base/binop_vx_constraint-102.c: ditto * gcc.target/riscv/rvv/base/binop_vx_constraint-108.c: ditto * gcc.target/riscv/rvv/base/binop_vx_constraint-114.c: ditto * gcc.target/riscv/rvv/base/binop_vx_constraint-119.c: ditto * gcc.target/riscv/rvv/base/binop_vx_constraint-12.c: ditto * gcc.target/riscv/rvv/base/binop_vx_constraint-16.c: ditto * gcc.target/riscv/rvv/base/binop_vx_constraint-17.c: ditto * gcc.target/riscv/rvv/base/binop_vx_constraint-19.c: ditto * gcc.target/riscv/rvv/base/binop_vx_constraint-21.c: ditto * gcc.target/riscv/rvv/base/binop_vx_constraint-23.c: ditto * gcc.target/riscv/rvv/base/binop_vx_constraint-25.c: ditto * gcc.target/riscv/rvv/base/binop_vx_constraint-27.c: ditto * gcc.target/riscv/rvv/base/binop_vx_constraint-29.c: ditto * gcc.target/riscv/rvv/base/binop_vx_constraint-31.c: ditto * gcc.target/riscv/rvv/base/binop_vx_constraint-33.c: ditto * gcc.target/riscv/rvv/base/binop_vx_constraint-35.c: ditto * gcc.target/riscv/rvv/base/binop_vx_constraint-4.c: ditto * gcc.target/riscv/rvv/base/binop_vx_constraint-40.c: ditto * gcc.target/riscv/rvv/base/binop_vx_constraint-44.c: ditto * gcc.target/riscv/rvv/base/binop_vx_constraint-50.c: ditto * gcc.target/riscv/rvv/base/binop_vx_constraint-56.c: ditto * gcc.target/riscv/rvv/base/binop_vx_constraint-62.c: ditto * gcc.target/riscv/rvv/base/binop_vx_constraint-68.c: ditto * gcc.target/riscv/rvv/base/binop_vx_constraint-74.c: ditto * gcc.target/riscv/rvv/base/binop_vx_constraint-79.c: ditto * gcc.target/riscv/rvv/base/binop_vx_constraint-8.c: ditto * gcc.target/riscv/rvv/base/binop_vx_constraint-84.c: ditto * gcc.target/riscv/rvv/base/binop_vx_constraint-90.c: ditto * gcc.target/riscv/rvv/base/binop_vx_constraint-96.c: ditto * gcc.target/riscv/rvv/base/float-point-dynamic-frm-30.c: ditto * gcc.target/riscv/rvv/base/pr108185-1.c: ditto * gcc.target/riscv/rvv/base/pr108185-2.c: ditto * gcc.target/riscv/rvv/base/pr108185-3.c: ditto * gcc.target/riscv/rvv/base/pr108185-4.c: ditto * gcc.target/riscv/rvv/base/pr108185-5.c: ditto * gcc.target/riscv/rvv/base/pr108185-6.c: ditto * gcc.target/riscv/rvv/base/pr108185-7.c: ditto * gcc.target/riscv/rvv/base/shift_vx_constraint-1.c: ditto * gcc.target/riscv/rvv/vsetvl/pr111037-3.c: ditto * gcc.target/riscv/rvv/vsetvl/vlmax_back_prop-28.c: ditto * gcc.target/riscv/rvv/vsetvl/vlmax_back_prop-29.c: ditto * gcc.target/riscv/rvv/vsetvl/vlmax_back_prop-32.c: ditto * gcc.target/riscv/rvv/vsetvl/vlmax_back_prop-33.c: ditto * gcc.target/riscv/rvv/vsetvl/vlmax_single_block-17.c: ditto * gcc.target/riscv/rvv/vsetvl/vlmax_single_block-18.c: ditto * gcc.target/riscv/rvv/vsetvl/vlmax_single_block-19.c: ditto * gcc.target/riscv/rvv/vsetvl/vlmax_switch_vtype-10.c: ditto * gcc.target/riscv/rvv/vsetvl/vlmax_switch_vtype-11.c: ditto * gcc.target/riscv/rvv/vsetvl/vlmax_switch_vtype-12.c: ditto * gcc.target/riscv/rvv/vsetvl/vlmax_switch_vtype-4.c: ditto * gcc.target/riscv/rvv/vsetvl/vlmax_switch_vtype-5.c: ditto * gcc.target/riscv/rvv/vsetvl/vlmax_switch_vtype-6.c: ditto * gcc.target/riscv/rvv/vsetvl/vlmax_switch_vtype-7.c: ditto * gcc.target/riscv/rvv/vsetvl/vlmax_switch_vtype-8.c: ditto * gcc.target/riscv/rvv/vsetvl/vlmax_switch_vtype-9.c: ditto * gfortran.dg/vect/vect-8.f90: ditto Signed-off-by: Edwin Lu --- gcc/testsuite/g++.target/riscv/rvv/base/bug-1.C | 2 ++ gcc/testsuite/gcc.target/riscv/rvv/autovec/reduc/reduc_call-2.c | 2 ++ gcc/testsuite/gcc.target/riscv/rvv/base/binop_vx_constraint-102.c | 2 ++ gcc/testsuite/gcc.target/riscv/rvv/base/binop_vx_constraint-108.c | 2 ++ gcc/testsuite/gcc.target/riscv/rvv/base/binop_vx_constraint-114.c | 2 ++ gcc/testsuite/gcc.target/riscv/rvv/base/binop_vx_constraint-119.c | 2 ++ gcc/testsuite/gcc.target/riscv/rvv/base/binop_vx_constraint-12.c | 2 ++ gcc/testsuite/gcc.target/riscv/rvv/base/binop_vx_constraint-16.c | 2 ++ gcc/testsuite/gcc.target/riscv/rvv/base/binop_vx_constraint-17.c | 2 ++ gcc/testsuite/gcc.target/riscv/rvv/base/binop_vx_constraint-19.c | 2 ++ gcc/testsuite/gcc.target/riscv/rvv/base/binop_vx_constraint-21.c | 2 ++ gcc/testsuite/gcc.target/riscv/rvv/base/binop_vx_constraint-23.c | 2 ++ gcc/testsuite/gcc.target/riscv/rvv/base/binop_vx_constraint-25.c | 2 ++ gcc/testsuite/gcc.target/riscv/rvv/base/binop_vx_constraint-27.c | 2 ++ gcc/testsuite/gcc.target/riscv/rvv/base/binop_vx_constraint-29.c | 2 ++ gcc/testsuite/gcc.target/riscv/rvv/base/binop_vx_constraint-31.c | 2 ++ gcc/testsuite/gcc.target/riscv/rvv/base/binop_vx_constraint-33.c | 2 ++ gcc/testsuite/gcc.target/riscv/rvv/base/binop_vx_constraint-35.c | 2 ++ gcc/testsuite/gcc.target/riscv/rvv/base/binop_vx_constraint-4.c | 2 ++ gcc/testsuite/gcc.target/riscv/rvv/base/binop_vx_constraint-40.c | 2 ++ gcc/testsuite/gcc.target/riscv/rvv/base/binop_vx_constraint-44.c | 2 ++ gcc/testsuite/gcc.target/riscv/rvv/base/binop_vx_constraint-50.c | 2 ++ gcc/testsuite/gcc.target/riscv/rvv/base/binop_vx_constraint-56.c | 2 ++ gcc/testsuite/gcc.target/riscv/rvv/base/binop_vx_constraint-62.c | 2 ++ gcc/testsuite/gcc.target/riscv/rvv/base/binop_vx_constraint-68.c | 2 ++ gcc/testsuite/gcc.target/riscv/rvv/base/binop_vx_constraint-74.c | 2 ++ gcc/testsuite/gcc.target/riscv/rvv/base/binop_vx_constraint-79.c | 2 ++ gcc/testsuite/gcc.target/riscv/rvv/base/binop_vx_constraint-8.c | 2 ++ gcc/testsuite/gcc.target/riscv/rvv/base/binop_vx_constraint-84.c | 2 ++ gcc/testsuite/gcc.target/riscv/rvv/base/binop_vx_constraint-90.c | 2 ++ gcc/testsuite/gcc.target/riscv/rvv/base/binop_vx_constraint-96.c | 2 ++ gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-30.c | 2 ++ gcc/testsuite/gcc.target/riscv/rvv/base/pr108185-1.c | 2 ++ gcc/testsuite/gcc.target/riscv/rvv/base/pr108185-2.c | 2 ++ gcc/testsuite/gcc.target/riscv/rvv/base/pr108185-3.c | 2 ++ gcc/testsuite/gcc.target/riscv/rvv/base/pr108185-4.c | 2 ++ gcc/testsuite/gcc.target/riscv/rvv/base/pr108185-5.c | 2 ++ gcc/testsuite/gcc.target/riscv/rvv/base/pr108185-6.c | 2 ++ gcc/testsuite/gcc.target/riscv/rvv/base/pr108185-7.c | 2 ++ gcc/testsuite/gcc.target/riscv/rvv/base/shift_vx_constraint-1.c | 2 ++ gcc/testsuite/gcc.target/riscv/rvv/vsetvl/pr111037-3.c | 2 ++ gcc/testsuite/gcc.target/riscv/rvv/vsetvl/vlmax_back_prop-28.c | 2 ++ gcc/testsuite/gcc.target/riscv/rvv/vsetvl/vlmax_back_prop-29.c | 2 ++ gcc/testsuite/gcc.target/riscv/rvv/vsetvl/vlmax_back_prop-32.c | 2 ++ gcc/testsuite/gcc.target/riscv/rvv/vsetvl/vlmax_back_prop-33.c | 2 ++ gcc/testsuite/gcc.target/riscv/rvv/vsetvl/vlmax_single_block-17.c | 2 ++ gcc/testsuite/gcc.target/riscv/rvv/vsetvl/vlmax_single_block-18.c | 2 ++ gcc/testsuite/gcc.target/riscv/rvv/vsetvl/vlmax_single_block-19.c | 2 ++ gcc/testsuite/gcc.target/riscv/rvv/vsetvl/vlmax_switch_vtype-10.c | 2 ++ gcc/testsuite/gcc.target/riscv/rvv/vsetvl/vlmax_switch_vtype-11.c | 2 ++ gcc/testsuite/gcc.target/riscv/rvv/vsetvl/vlmax_switch_vtype-12.c | 2 ++ gcc/testsuite/gcc.target/riscv/rvv/vsetvl/vlmax_switch_vtype-4.c | 2 ++ gcc/testsuite/gcc.target/riscv/rvv/vsetvl/vlmax_switch_vtype-5.c | 2 ++ gcc/testsuite/gcc.target/riscv/rvv/vsetvl/vlmax_switch_vtype-6.c | 2 ++ gcc/testsuite/gcc.target/riscv/rvv/vsetvl/vlmax_switch_vtype-7.c | 2 ++ gcc/testsuite/gcc.target/riscv/rvv/vsetvl/vlmax_switch_vtype-8.c | 2 ++ gcc/testsuite/gcc.target/riscv/rvv/vsetvl/vlmax_switch_vtype-9.c | 2 ++ gcc/testsuite/gfortran.dg/vect/vect-8.f90 | 2 ++ 58 files changed, 116 insertions(+) (limited to 'gcc') diff --git a/gcc/testsuite/g++.target/riscv/rvv/base/bug-1.C b/gcc/testsuite/g++.target/riscv/rvv/base/bug-1.C index c1070f9..6f62a64 100644 --- a/gcc/testsuite/g++.target/riscv/rvv/base/bug-1.C +++ b/gcc/testsuite/g++.target/riscv/rvv/base/bug-1.C @@ -1,5 +1,7 @@ /* { dg-do compile } */ /* { dg-options "-march=rv32gcv -mabi=ilp32d -O3" } */ +// PR113249 +/* { dg-additional-options "-fno-schedule-insns -fno-schedule-insns2" } */ #include "riscv_vector.h" template < class T > diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/reduc/reduc_call-2.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/reduc/reduc_call-2.c index 7be22d6..17a6b6f 100644 --- a/gcc/testsuite/gcc.target/riscv/rvv/autovec/reduc/reduc_call-2.c +++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/reduc/reduc_call-2.c @@ -1,5 +1,7 @@ /* { dg-do compile } */ /* { dg-additional-options "-march=rv32gcv_zvfh -mabi=ilp32d --param=riscv-autovec-preference=scalable -fno-vect-cost-model -ffast-math" } */ +// PR113249 +/* { dg-additional-options "-fno-schedule-insns -fno-schedule-insns2" } */ #include "reduc_call-1.c" diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/binop_vx_constraint-102.c b/gcc/testsuite/gcc.target/riscv/rvv/base/binop_vx_constraint-102.c index 4b24b97..8386b42 100644 --- a/gcc/testsuite/gcc.target/riscv/rvv/base/binop_vx_constraint-102.c +++ b/gcc/testsuite/gcc.target/riscv/rvv/base/binop_vx_constraint-102.c @@ -1,5 +1,7 @@ /* { dg-do compile } */ /* { dg-options "-march=rv32gcv -mabi=ilp32 -O3" } */ +// PR113249 +/* { dg-additional-options "-fno-schedule-insns -fno-schedule-insns2" } */ #include "riscv_vector.h" void f (void * in, void *out, int32_t x, int n) diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/binop_vx_constraint-108.c b/gcc/testsuite/gcc.target/riscv/rvv/base/binop_vx_constraint-108.c index 99acc51..e2ed4b7 100644 --- a/gcc/testsuite/gcc.target/riscv/rvv/base/binop_vx_constraint-108.c +++ b/gcc/testsuite/gcc.target/riscv/rvv/base/binop_vx_constraint-108.c @@ -1,5 +1,7 @@ /* { dg-do compile } */ /* { dg-options "-march=rv32gcv -mabi=ilp32 -O3" } */ +// PR113249 +/* { dg-additional-options "-fno-schedule-insns -fno-schedule-insns2" } */ #include "riscv_vector.h" void f (void * in, void *out, int32_t x, int n) diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/binop_vx_constraint-114.c b/gcc/testsuite/gcc.target/riscv/rvv/base/binop_vx_constraint-114.c index d595c44..61340be 100644 --- a/gcc/testsuite/gcc.target/riscv/rvv/base/binop_vx_constraint-114.c +++ b/gcc/testsuite/gcc.target/riscv/rvv/base/binop_vx_constraint-114.c @@ -1,5 +1,7 @@ /* { dg-do compile } */ /* { dg-options "-march=rv32gcv -mabi=ilp32 -O3" } */ +// PR113249 +/* { dg-additional-options "-fno-schedule-insns -fno-schedule-insns2" } */ #include "riscv_vector.h" void f (void * in, void *out, int32_t x, int n) diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/binop_vx_constraint-119.c b/gcc/testsuite/gcc.target/riscv/rvv/base/binop_vx_constraint-119.c index 0b51175..0f1485e 100644 --- a/gcc/testsuite/gcc.target/riscv/rvv/base/binop_vx_constraint-119.c +++ b/gcc/testsuite/gcc.target/riscv/rvv/base/binop_vx_constraint-119.c @@ -1,5 +1,7 @@ /* { dg-do compile } */ /* { dg-options "-march=rv32gcv -mabi=ilp32 -O3" } */ +// PR113249 +/* { dg-additional-options "-fno-schedule-insns -fno-schedule-insns2" } */ #include "riscv_vector.h" void f (void * in, void *out, uint64_t x, int n) diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/binop_vx_constraint-12.c b/gcc/testsuite/gcc.target/riscv/rvv/base/binop_vx_constraint-12.c index 634c12a..173ac62 100644 --- a/gcc/testsuite/gcc.target/riscv/rvv/base/binop_vx_constraint-12.c +++ b/gcc/testsuite/gcc.target/riscv/rvv/base/binop_vx_constraint-12.c @@ -1,5 +1,7 @@ /* { dg-do compile } */ /* { dg-options "-march=rv32gcv -mabi=ilp32d -O3" } */ +// PR113249 +/* { dg-additional-options "-fno-schedule-insns -fno-schedule-insns2" } */ /* { dg-final { check-function-bodies "**" "" } } */ #include "riscv_vector.h" diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/binop_vx_constraint-16.c b/gcc/testsuite/gcc.target/riscv/rvv/base/binop_vx_constraint-16.c index 651d610..1edba89 100644 --- a/gcc/testsuite/gcc.target/riscv/rvv/base/binop_vx_constraint-16.c +++ b/gcc/testsuite/gcc.target/riscv/rvv/base/binop_vx_constraint-16.c @@ -1,5 +1,7 @@ /* { dg-do compile } */ /* { dg-options "-march=rv32gcv -mabi=ilp32d -O3" } */ +// PR113249 +/* { dg-additional-options "-fno-schedule-insns -fno-schedule-insns2" } */ /* { dg-final { check-function-bodies "**" "" } } */ #include "riscv_vector.h" diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/binop_vx_constraint-17.c b/gcc/testsuite/gcc.target/riscv/rvv/base/binop_vx_constraint-17.c index d19a9fd..75340c3 100644 --- a/gcc/testsuite/gcc.target/riscv/rvv/base/binop_vx_constraint-17.c +++ b/gcc/testsuite/gcc.target/riscv/rvv/base/binop_vx_constraint-17.c @@ -1,5 +1,7 @@ /* { dg-do compile } */ /* { dg-options "-march=rv32gcv -mabi=ilp32d -O3" } */ +// PR113249 +/* { dg-additional-options "-fno-schedule-insns -fno-schedule-insns2" } */ /* { dg-final { check-function-bodies "**" "" } } */ #include "riscv_vector.h" diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/binop_vx_constraint-19.c b/gcc/testsuite/gcc.target/riscv/rvv/base/binop_vx_constraint-19.c index 16f4315..7e4aedc 100644 --- a/gcc/testsuite/gcc.target/riscv/rvv/base/binop_vx_constraint-19.c +++ b/gcc/testsuite/gcc.target/riscv/rvv/base/binop_vx_constraint-19.c @@ -1,5 +1,7 @@ /* { dg-do compile } */ /* { dg-options "-march=rv32gcv -mabi=ilp32d -O3" } */ +// PR113249 +/* { dg-additional-options "-fno-schedule-insns -fno-schedule-insns2" } */ /* { dg-final { check-function-bodies "**" "" } } */ #include "riscv_vector.h" diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/binop_vx_constraint-21.c b/gcc/testsuite/gcc.target/riscv/rvv/base/binop_vx_constraint-21.c index 347c846..755e92a 100644 --- a/gcc/testsuite/gcc.target/riscv/rvv/base/binop_vx_constraint-21.c +++ b/gcc/testsuite/gcc.target/riscv/rvv/base/binop_vx_constraint-21.c @@ -1,5 +1,7 @@ /* { dg-do compile } */ /* { dg-options "-march=rv32gcv -mabi=ilp32d -O3" } */ +// PR113249 +/* { dg-additional-options "-fno-schedule-insns -fno-schedule-insns2" } */ /* { dg-final { check-function-bodies "**" "" } } */ #include "riscv_vector.h" diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/binop_vx_constraint-23.c b/gcc/testsuite/gcc.target/riscv/rvv/base/binop_vx_constraint-23.c index bc41444..2c82dc0 100644 --- a/gcc/testsuite/gcc.target/riscv/rvv/base/binop_vx_constraint-23.c +++ b/gcc/testsuite/gcc.target/riscv/rvv/base/binop_vx_constraint-23.c @@ -1,5 +1,7 @@ /* { dg-do compile } */ /* { dg-options "-march=rv32gcv -mabi=ilp32d -O3" } */ +// PR113249 +/* { dg-additional-options "-fno-schedule-insns -fno-schedule-insns2" } */ /* { dg-final { check-function-bodies "**" "" } } */ #include "riscv_vector.h" diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/binop_vx_constraint-25.c b/gcc/testsuite/gcc.target/riscv/rvv/base/binop_vx_constraint-25.c index ce3f3af..e2ac6a3 100644 --- a/gcc/testsuite/gcc.target/riscv/rvv/base/binop_vx_constraint-25.c +++ b/gcc/testsuite/gcc.target/riscv/rvv/base/binop_vx_constraint-25.c @@ -1,5 +1,7 @@ /* { dg-do compile } */ /* { dg-options "-march=rv32gcv -mabi=ilp32d -O3" } */ +// PR113249 +/* { dg-additional-options "-fno-schedule-insns -fno-schedule-insns2" } */ /* { dg-final { check-function-bodies "**" "" } } */ #include "riscv_vector.h" diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/binop_vx_constraint-27.c b/gcc/testsuite/gcc.target/riscv/rvv/base/binop_vx_constraint-27.c index 4946f84..436a0e8 100644 --- a/gcc/testsuite/gcc.target/riscv/rvv/base/binop_vx_constraint-27.c +++ b/gcc/testsuite/gcc.target/riscv/rvv/base/binop_vx_constraint-27.c @@ -1,5 +1,7 @@ /* { dg-do compile } */ /* { dg-options "-march=rv32gcv -mabi=ilp32d -O3" } */ +// PR113249 +/* { dg-additional-options "-fno-schedule-insns -fno-schedule-insns2" } */ /* { dg-final { check-function-bodies "**" "" } } */ #include "riscv_vector.h" diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/binop_vx_constraint-29.c b/gcc/testsuite/gcc.target/riscv/rvv/base/binop_vx_constraint-29.c index 5f2eede..72b3216 100644 --- a/gcc/testsuite/gcc.target/riscv/rvv/base/binop_vx_constraint-29.c +++ b/gcc/testsuite/gcc.target/riscv/rvv/base/binop_vx_constraint-29.c @@ -1,5 +1,7 @@ /* { dg-do compile } */ /* { dg-options "-march=rv32gcv -mabi=ilp32d -O3" } */ +// PR113249 +/* { dg-additional-options "-fno-schedule-insns -fno-schedule-insns2" } */ /* { dg-final { check-function-bodies "**" "" } } */ #include "riscv_vector.h" diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/binop_vx_constraint-31.c b/gcc/testsuite/gcc.target/riscv/rvv/base/binop_vx_constraint-31.c index 5f2eede..72b3216 100644 --- a/gcc/testsuite/gcc.target/riscv/rvv/base/binop_vx_constraint-31.c +++ b/gcc/testsuite/gcc.target/riscv/rvv/base/binop_vx_constraint-31.c @@ -1,5 +1,7 @@ /* { dg-do compile } */ /* { dg-options "-march=rv32gcv -mabi=ilp32d -O3" } */ +// PR113249 +/* { dg-additional-options "-fno-schedule-insns -fno-schedule-insns2" } */ /* { dg-final { check-function-bodies "**" "" } } */ #include "riscv_vector.h" diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/binop_vx_constraint-33.c b/gcc/testsuite/gcc.target/riscv/rvv/base/binop_vx_constraint-33.c index 88fcba6..6908c78 100644 --- a/gcc/testsuite/gcc.target/riscv/rvv/base/binop_vx_constraint-33.c +++ b/gcc/testsuite/gcc.target/riscv/rvv/base/binop_vx_constraint-33.c @@ -1,5 +1,7 @@ /* { dg-do compile } */ /* { dg-options "-march=rv32gcv -mabi=ilp32d -O3" } */ +// PR113249 +/* { dg-additional-options "-fno-schedule-insns -fno-schedule-insns2" } */ /* { dg-final { check-function-bodies "**" "" } } */ #include "riscv_vector.h" diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/binop_vx_constraint-35.c b/gcc/testsuite/gcc.target/riscv/rvv/base/binop_vx_constraint-35.c index 88fcba6..6908c78 100644 --- a/gcc/testsuite/gcc.target/riscv/rvv/base/binop_vx_constraint-35.c +++ b/gcc/testsuite/gcc.target/riscv/rvv/base/binop_vx_constraint-35.c @@ -1,5 +1,7 @@ /* { dg-do compile } */ /* { dg-options "-march=rv32gcv -mabi=ilp32d -O3" } */ +// PR113249 +/* { dg-additional-options "-fno-schedule-insns -fno-schedule-insns2" } */ /* { dg-final { check-function-bodies "**" "" } } */ #include "riscv_vector.h" diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/binop_vx_constraint-4.c b/gcc/testsuite/gcc.target/riscv/rvv/base/binop_vx_constraint-4.c index 87a1645..ee1db1c 100644 --- a/gcc/testsuite/gcc.target/riscv/rvv/base/binop_vx_constraint-4.c +++ b/gcc/testsuite/gcc.target/riscv/rvv/base/binop_vx_constraint-4.c @@ -1,5 +1,7 @@ /* { dg-do compile } */ /* { dg-options "-march=rv32gcv -mabi=ilp32d -O3" } */ +// PR113249 +/* { dg-additional-options "-fno-schedule-insns -fno-schedule-insns2" } */ /* { dg-final { check-function-bodies "**" "" } } */ #include "riscv_vector.h" diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/binop_vx_constraint-40.c b/gcc/testsuite/gcc.target/riscv/rvv/base/binop_vx_constraint-40.c index c0321ce..fb969eb 100644 --- a/gcc/testsuite/gcc.target/riscv/rvv/base/binop_vx_constraint-40.c +++ b/gcc/testsuite/gcc.target/riscv/rvv/base/binop_vx_constraint-40.c @@ -1,5 +1,7 @@ /* { dg-do compile } */ /* { dg-options "-march=rv32gcv -mabi=ilp32d -O3" } */ +// PR113249 +/* { dg-additional-options "-fno-schedule-insns -fno-schedule-insns2" } */ /* { dg-final { check-function-bodies "**" "" } } */ #include "riscv_vector.h" diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/binop_vx_constraint-44.c b/gcc/testsuite/gcc.target/riscv/rvv/base/binop_vx_constraint-44.c index ab0f13b..542f43e 100644 --- a/gcc/testsuite/gcc.target/riscv/rvv/base/binop_vx_constraint-44.c +++ b/gcc/testsuite/gcc.target/riscv/rvv/base/binop_vx_constraint-44.c @@ -1,5 +1,7 @@ /* { dg-do compile } */ /* { dg-options "-march=rv32gcv -mabi=ilp32d -O3" } */ +// PR113249 +/* { dg-additional-options "-fno-schedule-insns -fno-schedule-insns2" } */ /* { dg-final { check-function-bodies "**" "" } } */ #include "riscv_vector.h" diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/binop_vx_constraint-50.c b/gcc/testsuite/gcc.target/riscv/rvv/base/binop_vx_constraint-50.c index 3893e17..31109a8 100644 --- a/gcc/testsuite/gcc.target/riscv/rvv/base/binop_vx_constraint-50.c +++ b/gcc/testsuite/gcc.target/riscv/rvv/base/binop_vx_constraint-50.c @@ -1,5 +1,7 @@ /* { dg-do compile } */ /* { dg-options "-march=rv32gcv -mabi=ilp32 -O3" } */ +// PR113249 +/* { dg-additional-options "-fno-schedule-insns -fno-schedule-insns2" } */ #include "riscv_vector.h" void f (void * in, void *out, int32_t x, int n) diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/binop_vx_constraint-56.c b/gcc/testsuite/gcc.target/riscv/rvv/base/binop_vx_constraint-56.c index b0ea553..924f450 100644 --- a/gcc/testsuite/gcc.target/riscv/rvv/base/binop_vx_constraint-56.c +++ b/gcc/testsuite/gcc.target/riscv/rvv/base/binop_vx_constraint-56.c @@ -1,5 +1,7 @@ /* { dg-do compile } */ /* { dg-options "-march=rv32gcv -mabi=ilp32 -O3" } */ +// PR113249 +/* { dg-additional-options "-fno-schedule-insns -fno-schedule-insns2" } */ #include "riscv_vector.h" void f (void * in, void *out, int64_t x, int n) diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/binop_vx_constraint-62.c b/gcc/testsuite/gcc.target/riscv/rvv/base/binop_vx_constraint-62.c index 350697d..659d8d9 100644 --- a/gcc/testsuite/gcc.target/riscv/rvv/base/binop_vx_constraint-62.c +++ b/gcc/testsuite/gcc.target/riscv/rvv/base/binop_vx_constraint-62.c @@ -1,5 +1,7 @@ /* { dg-do compile } */ /* { dg-options "-march=rv32gcv -mabi=ilp32 -O3" } */ +// PR113249 +/* { dg-additional-options "-fno-schedule-insns -fno-schedule-insns2" } */ #include "riscv_vector.h" void f (void * in, void *out, int64_t x, int n) diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/binop_vx_constraint-68.c b/gcc/testsuite/gcc.target/riscv/rvv/base/binop_vx_constraint-68.c index 0f138c5..6387460 100644 --- a/gcc/testsuite/gcc.target/riscv/rvv/base/binop_vx_constraint-68.c +++ b/gcc/testsuite/gcc.target/riscv/rvv/base/binop_vx_constraint-68.c @@ -1,5 +1,7 @@ /* { dg-do compile } */ /* { dg-options "-march=rv32gcv -mabi=ilp32 -O3" } */ +// PR113249 +/* { dg-additional-options "-fno-schedule-insns -fno-schedule-insns2" } */ #include "riscv_vector.h" void f (void * in, void *out, int64_t x, int n) diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/binop_vx_constraint-74.c b/gcc/testsuite/gcc.target/riscv/rvv/base/binop_vx_constraint-74.c index f4cbf09..a214d70 100644 --- a/gcc/testsuite/gcc.target/riscv/rvv/base/binop_vx_constraint-74.c +++ b/gcc/testsuite/gcc.target/riscv/rvv/base/binop_vx_constraint-74.c @@ -1,5 +1,7 @@ /* { dg-do compile } */ /* { dg-options "-march=rv32gcv -mabi=ilp32 -O3" } */ +// PR113249 +/* { dg-additional-options "-fno-schedule-insns -fno-schedule-insns2" } */ #include "riscv_vector.h" void f (void * in, void *out, int64_t x, int n) diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/binop_vx_constraint-79.c b/gcc/testsuite/gcc.target/riscv/rvv/base/binop_vx_constraint-79.c index d606078..efa659b 100644 --- a/gcc/testsuite/gcc.target/riscv/rvv/base/binop_vx_constraint-79.c +++ b/gcc/testsuite/gcc.target/riscv/rvv/base/binop_vx_constraint-79.c @@ -1,5 +1,7 @@ /* { dg-do compile } */ /* { dg-options "-march=rv32gcv -mabi=ilp32 -O3" } */ +// PR113249 +/* { dg-additional-options "-fno-schedule-insns -fno-schedule-insns2" } */ #include "riscv_vector.h" void f (void * in, void *out, int64_t x, int n) diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/binop_vx_constraint-8.c b/gcc/testsuite/gcc.target/riscv/rvv/base/binop_vx_constraint-8.c index 9bf9ff5..6a26248 100644 --- a/gcc/testsuite/gcc.target/riscv/rvv/base/binop_vx_constraint-8.c +++ b/gcc/testsuite/gcc.target/riscv/rvv/base/binop_vx_constraint-8.c @@ -1,5 +1,7 @@ /* { dg-do compile } */ /* { dg-options "-march=rv32gcv -mabi=ilp32d -O3" } */ +// PR113249 +/* { dg-additional-options "-fno-schedule-insns -fno-schedule-insns2" } */ /* { dg-final { check-function-bodies "**" "" } } */ #include "riscv_vector.h" diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/binop_vx_constraint-84.c b/gcc/testsuite/gcc.target/riscv/rvv/base/binop_vx_constraint-84.c index bca55b2..429fe12 100644 --- a/gcc/testsuite/gcc.target/riscv/rvv/base/binop_vx_constraint-84.c +++ b/gcc/testsuite/gcc.target/riscv/rvv/base/binop_vx_constraint-84.c @@ -1,5 +1,7 @@ /* { dg-do compile } */ /* { dg-options "-march=rv32gcv -mabi=ilp32 -O3" } */ +// PR113249 +/* { dg-additional-options "-fno-schedule-insns -fno-schedule-insns2" } */ #include "riscv_vector.h" void f (void * in, void *out, uint64_t x, int n) diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/binop_vx_constraint-90.c b/gcc/testsuite/gcc.target/riscv/rvv/base/binop_vx_constraint-90.c index 586e264..0cd0af7 100644 --- a/gcc/testsuite/gcc.target/riscv/rvv/base/binop_vx_constraint-90.c +++ b/gcc/testsuite/gcc.target/riscv/rvv/base/binop_vx_constraint-90.c @@ -1,5 +1,7 @@ /* { dg-do compile } */ /* { dg-options "-march=rv32gcv -mabi=ilp32 -O3" } */ +// PR113249 +/* { dg-additional-options "-fno-schedule-insns -fno-schedule-insns2" } */ #include "riscv_vector.h" void f (void * in, void *out, int32_t x, int n) diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/binop_vx_constraint-96.c b/gcc/testsuite/gcc.target/riscv/rvv/base/binop_vx_constraint-96.c index d1bbb78..bb1690e 100644 --- a/gcc/testsuite/gcc.target/riscv/rvv/base/binop_vx_constraint-96.c +++ b/gcc/testsuite/gcc.target/riscv/rvv/base/binop_vx_constraint-96.c @@ -1,5 +1,7 @@ /* { dg-do compile } */ /* { dg-options "-march=rv32gcv -mabi=ilp32 -O3" } */ +// PR113249 +/* { dg-additional-options "-fno-schedule-insns -fno-schedule-insns2" } */ #include "riscv_vector.h" void f (void * in, void *out, int32_t x, int n) diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-30.c b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-30.c index 7e73878..37ef0f0 100644 --- a/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-30.c +++ b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-30.c @@ -1,5 +1,7 @@ /* { dg-do compile } */ /* { dg-options "-march=rv64gcv -mabi=lp64 -O3" } */ +// PR113249 +/* { dg-additional-options "-fno-schedule-insns -fno-schedule-insns2" } */ #include "riscv_vector.h" diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/pr108185-1.c b/gcc/testsuite/gcc.target/riscv/rvv/base/pr108185-1.c index c3d0b10..4c6e88e 100644 --- a/gcc/testsuite/gcc.target/riscv/rvv/base/pr108185-1.c +++ b/gcc/testsuite/gcc.target/riscv/rvv/base/pr108185-1.c @@ -1,5 +1,7 @@ /* { dg-do compile } */ /* { dg-options "-march=rv64gcv -mabi=lp64 -O3" } */ +// PR113249 +/* { dg-additional-options "-fno-schedule-insns -fno-schedule-insns2" } */ #include "riscv_vector.h" diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/pr108185-2.c b/gcc/testsuite/gcc.target/riscv/rvv/base/pr108185-2.c index bd13ba9..0844e3e 100644 --- a/gcc/testsuite/gcc.target/riscv/rvv/base/pr108185-2.c +++ b/gcc/testsuite/gcc.target/riscv/rvv/base/pr108185-2.c @@ -1,5 +1,7 @@ /* { dg-do compile } */ /* { dg-options "-march=rv64gcv -mabi=lp64 -O3" } */ +// PR113249 +/* { dg-additional-options "-fno-schedule-insns -fno-schedule-insns2" } */ #include "riscv_vector.h" diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/pr108185-3.c b/gcc/testsuite/gcc.target/riscv/rvv/base/pr108185-3.c index 99928f7..49a5744 100644 --- a/gcc/testsuite/gcc.target/riscv/rvv/base/pr108185-3.c +++ b/gcc/testsuite/gcc.target/riscv/rvv/base/pr108185-3.c @@ -1,5 +1,7 @@ /* { dg-do compile } */ /* { dg-options "-march=rv64gcv -mabi=lp64 -O3" } */ +// PR113249 +/* { dg-additional-options "-fno-schedule-insns -fno-schedule-insns2" } */ #include "riscv_vector.h" diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/pr108185-4.c b/gcc/testsuite/gcc.target/riscv/rvv/base/pr108185-4.c index 321cd5c..cef0a11 100644 --- a/gcc/testsuite/gcc.target/riscv/rvv/base/pr108185-4.c +++ b/gcc/testsuite/gcc.target/riscv/rvv/base/pr108185-4.c @@ -1,5 +1,7 @@ /* { dg-do compile } */ /* { dg-options "-march=rv64gc_zve64d -mabi=lp64 -O3" } */ +// PR113249 +/* { dg-additional-options "-fno-schedule-insns -fno-schedule-insns2" } */ #include "riscv_vector.h" diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/pr108185-5.c b/gcc/testsuite/gcc.target/riscv/rvv/base/pr108185-5.c index 575a784..3f0d677 100644 --- a/gcc/testsuite/gcc.target/riscv/rvv/base/pr108185-5.c +++ b/gcc/testsuite/gcc.target/riscv/rvv/base/pr108185-5.c @@ -1,5 +1,7 @@ /* { dg-do compile } */ /* { dg-options "-march=rv64gcv -mabi=lp64 -O3" } */ +// PR113249 +/* { dg-additional-options "-fno-schedule-insns -fno-schedule-insns2" } */ #include "riscv_vector.h" diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/pr108185-6.c b/gcc/testsuite/gcc.target/riscv/rvv/base/pr108185-6.c index 95a11d3..4ed6588 100644 --- a/gcc/testsuite/gcc.target/riscv/rvv/base/pr108185-6.c +++ b/gcc/testsuite/gcc.target/riscv/rvv/base/pr108185-6.c @@ -1,5 +1,7 @@ /* { dg-do compile } */ /* { dg-options "-march=rv64gcv -mabi=lp64 -O3" } */ +// PR113249 +/* { dg-additional-options "-fno-schedule-insns -fno-schedule-insns2" } */ #include "riscv_vector.h" diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/pr108185-7.c b/gcc/testsuite/gcc.target/riscv/rvv/base/pr108185-7.c index 8f6f0b1..95b7ff9 100644 --- a/gcc/testsuite/gcc.target/riscv/rvv/base/pr108185-7.c +++ b/gcc/testsuite/gcc.target/riscv/rvv/base/pr108185-7.c @@ -1,5 +1,7 @@ /* { dg-do compile } */ /* { dg-options "-march=rv64gcv -mabi=lp64 -O3" } */ +// PR113249 +/* { dg-additional-options "-fno-schedule-insns -fno-schedule-insns2" } */ #include "riscv_vector.h" diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/shift_vx_constraint-1.c b/gcc/testsuite/gcc.target/riscv/rvv/base/shift_vx_constraint-1.c index 250e017..9e0b41c 100644 --- a/gcc/testsuite/gcc.target/riscv/rvv/base/shift_vx_constraint-1.c +++ b/gcc/testsuite/gcc.target/riscv/rvv/base/shift_vx_constraint-1.c @@ -1,5 +1,7 @@ /* { dg-do compile } */ /* { dg-options "-march=rv32gcv -mabi=ilp32d -O3" } */ +// PR113249 +/* { dg-additional-options "-fno-schedule-insns -fno-schedule-insns2" } */ /* { dg-final { check-function-bodies "**" "" } } */ #include "riscv_vector.h" diff --git a/gcc/testsuite/gcc.target/riscv/rvv/vsetvl/pr111037-3.c b/gcc/testsuite/gcc.target/riscv/rvv/vsetvl/pr111037-3.c index 110e55b..5e1859c 100644 --- a/gcc/testsuite/gcc.target/riscv/rvv/vsetvl/pr111037-3.c +++ b/gcc/testsuite/gcc.target/riscv/rvv/vsetvl/pr111037-3.c @@ -1,5 +1,7 @@ /* { dg-do compile } */ /* { dg-options "--param=riscv-autovec-preference=scalable -march=rv32gc_zve64f_zvfh -mabi=ilp32d -O3" } */ +// PR113249 +/* { dg-additional-options "-fno-schedule-insns -fno-schedule-insns2" } */ #include "riscv_vector.h" diff --git a/gcc/testsuite/gcc.target/riscv/rvv/vsetvl/vlmax_back_prop-28.c b/gcc/testsuite/gcc.target/riscv/rvv/vsetvl/vlmax_back_prop-28.c index 4583504..f4f0e52 100644 --- a/gcc/testsuite/gcc.target/riscv/rvv/vsetvl/vlmax_back_prop-28.c +++ b/gcc/testsuite/gcc.target/riscv/rvv/vsetvl/vlmax_back_prop-28.c @@ -1,5 +1,7 @@ /* { dg-do compile } */ /* { dg-options "--param=riscv-autovec-preference=scalable -march=rv32gcv -mabi=ilp32 -fno-tree-vectorize" } */ +// PR113249 +/* { dg-additional-options "-fno-schedule-insns -fno-schedule-insns2" } */ #include "riscv_vector.h" diff --git a/gcc/testsuite/gcc.target/riscv/rvv/vsetvl/vlmax_back_prop-29.c b/gcc/testsuite/gcc.target/riscv/rvv/vsetvl/vlmax_back_prop-29.c index f16f4b9..7e01b81 100644 --- a/gcc/testsuite/gcc.target/riscv/rvv/vsetvl/vlmax_back_prop-29.c +++ b/gcc/testsuite/gcc.target/riscv/rvv/vsetvl/vlmax_back_prop-29.c @@ -1,5 +1,7 @@ /* { dg-do compile } */ /* { dg-options "--param=riscv-autovec-preference=scalable -march=rv32gcv -mabi=ilp32 -fno-tree-vectorize" } */ +// PR113249 +/* { dg-additional-options "-fno-schedule-insns -fno-schedule-insns2" } */ #include "riscv_vector.h" diff --git a/gcc/testsuite/gcc.target/riscv/rvv/vsetvl/vlmax_back_prop-32.c b/gcc/testsuite/gcc.target/riscv/rvv/vsetvl/vlmax_back_prop-32.c index 43b443b..5615cb1 100644 --- a/gcc/testsuite/gcc.target/riscv/rvv/vsetvl/vlmax_back_prop-32.c +++ b/gcc/testsuite/gcc.target/riscv/rvv/vsetvl/vlmax_back_prop-32.c @@ -1,5 +1,7 @@ /* { dg-do compile } */ /* { dg-options "--param=riscv-autovec-preference=scalable -march=rv32gcv -mabi=ilp32 -fno-tree-vectorize" } */ +// PR113249 +/* { dg-additional-options "-fno-schedule-insns -fno-schedule-insns2" } */ #include "riscv_vector.h" diff --git a/gcc/testsuite/gcc.target/riscv/rvv/vsetvl/vlmax_back_prop-33.c b/gcc/testsuite/gcc.target/riscv/rvv/vsetvl/vlmax_back_prop-33.c index 6785558..c906b15 100644 --- a/gcc/testsuite/gcc.target/riscv/rvv/vsetvl/vlmax_back_prop-33.c +++ b/gcc/testsuite/gcc.target/riscv/rvv/vsetvl/vlmax_back_prop-33.c @@ -1,5 +1,7 @@ /* { dg-do compile } */ /* { dg-options "--param=riscv-autovec-preference=scalable -march=rv32gcv -mabi=ilp32 -fno-tree-vectorize" } */ +// PR113249 +/* { dg-additional-options "-fno-schedule-insns -fno-schedule-insns2" } */ #include "riscv_vector.h" diff --git a/gcc/testsuite/gcc.target/riscv/rvv/vsetvl/vlmax_single_block-17.c b/gcc/testsuite/gcc.target/riscv/rvv/vsetvl/vlmax_single_block-17.c index 960c9bf..006df7e 100644 --- a/gcc/testsuite/gcc.target/riscv/rvv/vsetvl/vlmax_single_block-17.c +++ b/gcc/testsuite/gcc.target/riscv/rvv/vsetvl/vlmax_single_block-17.c @@ -1,5 +1,7 @@ /* { dg-do compile } */ /* { dg-options "--param=riscv-autovec-preference=scalable -march=rv32gcv -mabi=ilp32" } */ +// PR113249 +/* { dg-additional-options "-fno-schedule-insns -fno-schedule-insns2" } */ #include "riscv_vector.h" diff --git a/gcc/testsuite/gcc.target/riscv/rvv/vsetvl/vlmax_single_block-18.c b/gcc/testsuite/gcc.target/riscv/rvv/vsetvl/vlmax_single_block-18.c index 5f22e8d..cc6d822 100644 --- a/gcc/testsuite/gcc.target/riscv/rvv/vsetvl/vlmax_single_block-18.c +++ b/gcc/testsuite/gcc.target/riscv/rvv/vsetvl/vlmax_single_block-18.c @@ -1,5 +1,7 @@ /* { dg-do compile } */ /* { dg-options "--param=riscv-autovec-preference=scalable -march=rv32gcv -mabi=ilp32" } */ +// PR113249 +/* { dg-additional-options "-fno-schedule-insns -fno-schedule-insns2" } */ #include "riscv_vector.h" diff --git a/gcc/testsuite/gcc.target/riscv/rvv/vsetvl/vlmax_single_block-19.c b/gcc/testsuite/gcc.target/riscv/rvv/vsetvl/vlmax_single_block-19.c index e5f35c0..9704e444 100644 --- a/gcc/testsuite/gcc.target/riscv/rvv/vsetvl/vlmax_single_block-19.c +++ b/gcc/testsuite/gcc.target/riscv/rvv/vsetvl/vlmax_single_block-19.c @@ -1,5 +1,7 @@ /* { dg-do compile } */ /* { dg-options "--param=riscv-autovec-preference=scalable -march=rv32gcv -mabi=ilp32" } */ +// PR113249 +/* { dg-additional-options "-fno-schedule-insns -fno-schedule-insns2" } */ #include "riscv_vector.h" diff --git a/gcc/testsuite/gcc.target/riscv/rvv/vsetvl/vlmax_switch_vtype-10.c b/gcc/testsuite/gcc.target/riscv/rvv/vsetvl/vlmax_switch_vtype-10.c index 0532c7d..476735d 100644 --- a/gcc/testsuite/gcc.target/riscv/rvv/vsetvl/vlmax_switch_vtype-10.c +++ b/gcc/testsuite/gcc.target/riscv/rvv/vsetvl/vlmax_switch_vtype-10.c @@ -1,5 +1,7 @@ /* { dg-do compile } */ /* { dg-options "--param=riscv-autovec-preference=scalable -march=rv32gcv -mabi=ilp32 -fno-tree-vectorize" } */ +// PR113249 +/* { dg-additional-options "-fno-schedule-insns -fno-schedule-insns2" } */ #include "riscv_vector.h" diff --git a/gcc/testsuite/gcc.target/riscv/rvv/vsetvl/vlmax_switch_vtype-11.c b/gcc/testsuite/gcc.target/riscv/rvv/vsetvl/vlmax_switch_vtype-11.c index b664c4b..c7b7db3 100644 --- a/gcc/testsuite/gcc.target/riscv/rvv/vsetvl/vlmax_switch_vtype-11.c +++ b/gcc/testsuite/gcc.target/riscv/rvv/vsetvl/vlmax_switch_vtype-11.c @@ -1,5 +1,7 @@ /* { dg-do compile } */ /* { dg-options "--param=riscv-autovec-preference=scalable -march=rv32gcv -mabi=ilp32 -fno-tree-vectorize" } */ +// PR113249 +/* { dg-additional-options "-fno-schedule-insns -fno-schedule-insns2" } */ #include "riscv_vector.h" diff --git a/gcc/testsuite/gcc.target/riscv/rvv/vsetvl/vlmax_switch_vtype-12.c b/gcc/testsuite/gcc.target/riscv/rvv/vsetvl/vlmax_switch_vtype-12.c index 04c4b88..80ff75f 100644 --- a/gcc/testsuite/gcc.target/riscv/rvv/vsetvl/vlmax_switch_vtype-12.c +++ b/gcc/testsuite/gcc.target/riscv/rvv/vsetvl/vlmax_switch_vtype-12.c @@ -1,5 +1,7 @@ /* { dg-do compile } */ /* { dg-options "--param=riscv-autovec-preference=scalable -march=rv32gcv -mabi=ilp32 -fno-tree-vectorize" } */ +// PR113249 +/* { dg-additional-options "-fno-schedule-insns -fno-schedule-insns2" } */ #include "riscv_vector.h" diff --git a/gcc/testsuite/gcc.target/riscv/rvv/vsetvl/vlmax_switch_vtype-4.c b/gcc/testsuite/gcc.target/riscv/rvv/vsetvl/vlmax_switch_vtype-4.c index 1404c9d..127dc7f 100644 --- a/gcc/testsuite/gcc.target/riscv/rvv/vsetvl/vlmax_switch_vtype-4.c +++ b/gcc/testsuite/gcc.target/riscv/rvv/vsetvl/vlmax_switch_vtype-4.c @@ -1,5 +1,7 @@ /* { dg-do compile } */ /* { dg-options "--param=riscv-autovec-preference=scalable -march=rv32gcv -mabi=ilp32" } */ +// PR113249 +/* { dg-additional-options "-fno-schedule-insns -fno-schedule-insns2" } */ #include "riscv_vector.h" diff --git a/gcc/testsuite/gcc.target/riscv/rvv/vsetvl/vlmax_switch_vtype-5.c b/gcc/testsuite/gcc.target/riscv/rvv/vsetvl/vlmax_switch_vtype-5.c index 1404c9d..127dc7f 100644 --- a/gcc/testsuite/gcc.target/riscv/rvv/vsetvl/vlmax_switch_vtype-5.c +++ b/gcc/testsuite/gcc.target/riscv/rvv/vsetvl/vlmax_switch_vtype-5.c @@ -1,5 +1,7 @@ /* { dg-do compile } */ /* { dg-options "--param=riscv-autovec-preference=scalable -march=rv32gcv -mabi=ilp32" } */ +// PR113249 +/* { dg-additional-options "-fno-schedule-insns -fno-schedule-insns2" } */ #include "riscv_vector.h" diff --git a/gcc/testsuite/gcc.target/riscv/rvv/vsetvl/vlmax_switch_vtype-6.c b/gcc/testsuite/gcc.target/riscv/rvv/vsetvl/vlmax_switch_vtype-6.c index 609c68d..e19e869 100644 --- a/gcc/testsuite/gcc.target/riscv/rvv/vsetvl/vlmax_switch_vtype-6.c +++ b/gcc/testsuite/gcc.target/riscv/rvv/vsetvl/vlmax_switch_vtype-6.c @@ -1,5 +1,7 @@ /* { dg-do compile } */ /* { dg-options "--param=riscv-autovec-preference=scalable -march=rv32gcv -mabi=ilp32" } */ +// PR113249 +/* { dg-additional-options "-fno-schedule-insns -fno-schedule-insns2" } */ #include "riscv_vector.h" diff --git a/gcc/testsuite/gcc.target/riscv/rvv/vsetvl/vlmax_switch_vtype-7.c b/gcc/testsuite/gcc.target/riscv/rvv/vsetvl/vlmax_switch_vtype-7.c index 043f177..90eca5b 100644 --- a/gcc/testsuite/gcc.target/riscv/rvv/vsetvl/vlmax_switch_vtype-7.c +++ b/gcc/testsuite/gcc.target/riscv/rvv/vsetvl/vlmax_switch_vtype-7.c @@ -1,5 +1,7 @@ /* { dg-do compile } */ /* { dg-options "--param=riscv-autovec-preference=scalable -march=rv32gcv -mabi=ilp32 -fno-tree-vectorize" } */ +// PR113249 +/* { dg-additional-options "-fno-schedule-insns -fno-schedule-insns2" } */ #include "riscv_vector.h" diff --git a/gcc/testsuite/gcc.target/riscv/rvv/vsetvl/vlmax_switch_vtype-8.c b/gcc/testsuite/gcc.target/riscv/rvv/vsetvl/vlmax_switch_vtype-8.c index 0bedde8..17b217b 100644 --- a/gcc/testsuite/gcc.target/riscv/rvv/vsetvl/vlmax_switch_vtype-8.c +++ b/gcc/testsuite/gcc.target/riscv/rvv/vsetvl/vlmax_switch_vtype-8.c @@ -1,5 +1,7 @@ /* { dg-do compile } */ /* { dg-options "--param=riscv-autovec-preference=scalable -march=rv32gcv -mabi=ilp32 -fno-tree-vectorize" } */ +// PR113249 +/* { dg-additional-options "-fno-schedule-insns -fno-schedule-insns2" } */ #include "riscv_vector.h" diff --git a/gcc/testsuite/gcc.target/riscv/rvv/vsetvl/vlmax_switch_vtype-9.c b/gcc/testsuite/gcc.target/riscv/rvv/vsetvl/vlmax_switch_vtype-9.c index 0bedde8..17b217b 100644 --- a/gcc/testsuite/gcc.target/riscv/rvv/vsetvl/vlmax_switch_vtype-9.c +++ b/gcc/testsuite/gcc.target/riscv/rvv/vsetvl/vlmax_switch_vtype-9.c @@ -1,5 +1,7 @@ /* { dg-do compile } */ /* { dg-options "--param=riscv-autovec-preference=scalable -march=rv32gcv -mabi=ilp32 -fno-tree-vectorize" } */ +// PR113249 +/* { dg-additional-options "-fno-schedule-insns -fno-schedule-insns2" } */ #include "riscv_vector.h" diff --git a/gcc/testsuite/gfortran.dg/vect/vect-8.f90 b/gcc/testsuite/gfortran.dg/vect/vect-8.f90 index 938dfc2..f77ec9f 100644 --- a/gcc/testsuite/gfortran.dg/vect/vect-8.f90 +++ b/gcc/testsuite/gfortran.dg/vect/vect-8.f90 @@ -1,6 +1,8 @@ ! { dg-do compile } ! { dg-require-effective-target vect_double } ! { dg-additional-options "-fno-tree-loop-distribute-patterns -finline-matmul-limit=0" } +! PR113249 +! { dg-options "-fno-schedule-insns -fno-schedule-insns2" { target { riscv*-*-* } } } module lfk_prec integer, parameter :: dp=kind(1.d0) -- cgit v1.1 From 23cd2961bd2ff63583f46e3499a07bd54491d45c Mon Sep 17 00:00:00 2001 From: Edwin Lu Date: Wed, 31 Jan 2024 10:53:07 -0800 Subject: RISC-V: Enable assert for insn_has_dfa_reservation Enables assert that every typed instruction is associated with a dfa reservation gcc/ChangeLog: * config/riscv/riscv.cc (riscv_sched_variable_issue): enable assert --- gcc/config/riscv/riscv.cc | 2 -- 1 file changed, 2 deletions(-) (limited to 'gcc') diff --git a/gcc/config/riscv/riscv.cc b/gcc/config/riscv/riscv.cc index 529ef5e..b08a3e2 100644 --- a/gcc/config/riscv/riscv.cc +++ b/gcc/config/riscv/riscv.cc @@ -8234,9 +8234,7 @@ riscv_sched_variable_issue (FILE *, int, rtx_insn *insn, int more) /* If we ever encounter an insn without an insn reservation, trip an assert so we can find and fix this problem. */ -#if 0 gcc_assert (insn_has_dfa_reservation_p (insn)); -#endif return more - 1; } -- cgit v1.1 From be697c0ab187466a0a76ef228055b591718e3e4d Mon Sep 17 00:00:00 2001 From: Edwin Lu Date: Wed, 31 Jan 2024 21:49:20 -0800 Subject: Revert "RISC-V: Enable assert for insn_has_dfa_reservation" This reverts commit 23cd2961bd2ff63583f46e3499a07bd54491d45c. --- gcc/config/riscv/riscv.cc | 2 ++ 1 file changed, 2 insertions(+) (limited to 'gcc') diff --git a/gcc/config/riscv/riscv.cc b/gcc/config/riscv/riscv.cc index b08a3e2..529ef5e 100644 --- a/gcc/config/riscv/riscv.cc +++ b/gcc/config/riscv/riscv.cc @@ -8234,7 +8234,9 @@ riscv_sched_variable_issue (FILE *, int, rtx_insn *insn, int more) /* If we ever encounter an insn without an insn reservation, trip an assert so we can find and fix this problem. */ +#if 0 gcc_assert (insn_has_dfa_reservation_p (insn)); +#endif return more - 1; } -- cgit v1.1 From 017b4c2a4977a8e50a336e4fef8c4ef817765033 Mon Sep 17 00:00:00 2001 From: Edwin Lu Date: Wed, 31 Jan 2024 21:49:25 -0800 Subject: Revert "RISC-V: Use default cost model for insn scheduling" This reverts commit 4b799a16ae59fc0f508c5931ebf1851a3446b707. --- gcc/testsuite/g++.target/riscv/rvv/base/bug-1.C | 2 -- gcc/testsuite/gcc.target/riscv/rvv/autovec/reduc/reduc_call-2.c | 2 -- gcc/testsuite/gcc.target/riscv/rvv/base/binop_vx_constraint-102.c | 2 -- gcc/testsuite/gcc.target/riscv/rvv/base/binop_vx_constraint-108.c | 2 -- gcc/testsuite/gcc.target/riscv/rvv/base/binop_vx_constraint-114.c | 2 -- gcc/testsuite/gcc.target/riscv/rvv/base/binop_vx_constraint-119.c | 2 -- gcc/testsuite/gcc.target/riscv/rvv/base/binop_vx_constraint-12.c | 2 -- gcc/testsuite/gcc.target/riscv/rvv/base/binop_vx_constraint-16.c | 2 -- gcc/testsuite/gcc.target/riscv/rvv/base/binop_vx_constraint-17.c | 2 -- gcc/testsuite/gcc.target/riscv/rvv/base/binop_vx_constraint-19.c | 2 -- gcc/testsuite/gcc.target/riscv/rvv/base/binop_vx_constraint-21.c | 2 -- gcc/testsuite/gcc.target/riscv/rvv/base/binop_vx_constraint-23.c | 2 -- gcc/testsuite/gcc.target/riscv/rvv/base/binop_vx_constraint-25.c | 2 -- gcc/testsuite/gcc.target/riscv/rvv/base/binop_vx_constraint-27.c | 2 -- gcc/testsuite/gcc.target/riscv/rvv/base/binop_vx_constraint-29.c | 2 -- gcc/testsuite/gcc.target/riscv/rvv/base/binop_vx_constraint-31.c | 2 -- gcc/testsuite/gcc.target/riscv/rvv/base/binop_vx_constraint-33.c | 2 -- gcc/testsuite/gcc.target/riscv/rvv/base/binop_vx_constraint-35.c | 2 -- gcc/testsuite/gcc.target/riscv/rvv/base/binop_vx_constraint-4.c | 2 -- gcc/testsuite/gcc.target/riscv/rvv/base/binop_vx_constraint-40.c | 2 -- gcc/testsuite/gcc.target/riscv/rvv/base/binop_vx_constraint-44.c | 2 -- gcc/testsuite/gcc.target/riscv/rvv/base/binop_vx_constraint-50.c | 2 -- gcc/testsuite/gcc.target/riscv/rvv/base/binop_vx_constraint-56.c | 2 -- gcc/testsuite/gcc.target/riscv/rvv/base/binop_vx_constraint-62.c | 2 -- gcc/testsuite/gcc.target/riscv/rvv/base/binop_vx_constraint-68.c | 2 -- gcc/testsuite/gcc.target/riscv/rvv/base/binop_vx_constraint-74.c | 2 -- gcc/testsuite/gcc.target/riscv/rvv/base/binop_vx_constraint-79.c | 2 -- gcc/testsuite/gcc.target/riscv/rvv/base/binop_vx_constraint-8.c | 2 -- gcc/testsuite/gcc.target/riscv/rvv/base/binop_vx_constraint-84.c | 2 -- gcc/testsuite/gcc.target/riscv/rvv/base/binop_vx_constraint-90.c | 2 -- gcc/testsuite/gcc.target/riscv/rvv/base/binop_vx_constraint-96.c | 2 -- gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-30.c | 2 -- gcc/testsuite/gcc.target/riscv/rvv/base/pr108185-1.c | 2 -- gcc/testsuite/gcc.target/riscv/rvv/base/pr108185-2.c | 2 -- gcc/testsuite/gcc.target/riscv/rvv/base/pr108185-3.c | 2 -- gcc/testsuite/gcc.target/riscv/rvv/base/pr108185-4.c | 2 -- gcc/testsuite/gcc.target/riscv/rvv/base/pr108185-5.c | 2 -- gcc/testsuite/gcc.target/riscv/rvv/base/pr108185-6.c | 2 -- gcc/testsuite/gcc.target/riscv/rvv/base/pr108185-7.c | 2 -- gcc/testsuite/gcc.target/riscv/rvv/base/shift_vx_constraint-1.c | 2 -- gcc/testsuite/gcc.target/riscv/rvv/vsetvl/pr111037-3.c | 2 -- gcc/testsuite/gcc.target/riscv/rvv/vsetvl/vlmax_back_prop-28.c | 2 -- gcc/testsuite/gcc.target/riscv/rvv/vsetvl/vlmax_back_prop-29.c | 2 -- gcc/testsuite/gcc.target/riscv/rvv/vsetvl/vlmax_back_prop-32.c | 2 -- gcc/testsuite/gcc.target/riscv/rvv/vsetvl/vlmax_back_prop-33.c | 2 -- gcc/testsuite/gcc.target/riscv/rvv/vsetvl/vlmax_single_block-17.c | 2 -- gcc/testsuite/gcc.target/riscv/rvv/vsetvl/vlmax_single_block-18.c | 2 -- gcc/testsuite/gcc.target/riscv/rvv/vsetvl/vlmax_single_block-19.c | 2 -- gcc/testsuite/gcc.target/riscv/rvv/vsetvl/vlmax_switch_vtype-10.c | 2 -- gcc/testsuite/gcc.target/riscv/rvv/vsetvl/vlmax_switch_vtype-11.c | 2 -- gcc/testsuite/gcc.target/riscv/rvv/vsetvl/vlmax_switch_vtype-12.c | 2 -- gcc/testsuite/gcc.target/riscv/rvv/vsetvl/vlmax_switch_vtype-4.c | 2 -- gcc/testsuite/gcc.target/riscv/rvv/vsetvl/vlmax_switch_vtype-5.c | 2 -- gcc/testsuite/gcc.target/riscv/rvv/vsetvl/vlmax_switch_vtype-6.c | 2 -- gcc/testsuite/gcc.target/riscv/rvv/vsetvl/vlmax_switch_vtype-7.c | 2 -- gcc/testsuite/gcc.target/riscv/rvv/vsetvl/vlmax_switch_vtype-8.c | 2 -- gcc/testsuite/gcc.target/riscv/rvv/vsetvl/vlmax_switch_vtype-9.c | 2 -- gcc/testsuite/gfortran.dg/vect/vect-8.f90 | 2 -- 58 files changed, 116 deletions(-) (limited to 'gcc') diff --git a/gcc/testsuite/g++.target/riscv/rvv/base/bug-1.C b/gcc/testsuite/g++.target/riscv/rvv/base/bug-1.C index 6f62a64..c1070f9 100644 --- a/gcc/testsuite/g++.target/riscv/rvv/base/bug-1.C +++ b/gcc/testsuite/g++.target/riscv/rvv/base/bug-1.C @@ -1,7 +1,5 @@ /* { dg-do compile } */ /* { dg-options "-march=rv32gcv -mabi=ilp32d -O3" } */ -// PR113249 -/* { dg-additional-options "-fno-schedule-insns -fno-schedule-insns2" } */ #include "riscv_vector.h" template < class T > diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/reduc/reduc_call-2.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/reduc/reduc_call-2.c index 17a6b6f..7be22d6 100644 --- a/gcc/testsuite/gcc.target/riscv/rvv/autovec/reduc/reduc_call-2.c +++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/reduc/reduc_call-2.c @@ -1,7 +1,5 @@ /* { dg-do compile } */ /* { dg-additional-options "-march=rv32gcv_zvfh -mabi=ilp32d --param=riscv-autovec-preference=scalable -fno-vect-cost-model -ffast-math" } */ -// PR113249 -/* { dg-additional-options "-fno-schedule-insns -fno-schedule-insns2" } */ #include "reduc_call-1.c" diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/binop_vx_constraint-102.c b/gcc/testsuite/gcc.target/riscv/rvv/base/binop_vx_constraint-102.c index 8386b42..4b24b97 100644 --- a/gcc/testsuite/gcc.target/riscv/rvv/base/binop_vx_constraint-102.c +++ b/gcc/testsuite/gcc.target/riscv/rvv/base/binop_vx_constraint-102.c @@ -1,7 +1,5 @@ /* { dg-do compile } */ /* { dg-options "-march=rv32gcv -mabi=ilp32 -O3" } */ -// PR113249 -/* { dg-additional-options "-fno-schedule-insns -fno-schedule-insns2" } */ #include "riscv_vector.h" void f (void * in, void *out, int32_t x, int n) diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/binop_vx_constraint-108.c b/gcc/testsuite/gcc.target/riscv/rvv/base/binop_vx_constraint-108.c index e2ed4b7..99acc51 100644 --- a/gcc/testsuite/gcc.target/riscv/rvv/base/binop_vx_constraint-108.c +++ b/gcc/testsuite/gcc.target/riscv/rvv/base/binop_vx_constraint-108.c @@ -1,7 +1,5 @@ /* { dg-do compile } */ /* { dg-options "-march=rv32gcv -mabi=ilp32 -O3" } */ -// PR113249 -/* { dg-additional-options "-fno-schedule-insns -fno-schedule-insns2" } */ #include "riscv_vector.h" void f (void * in, void *out, int32_t x, int n) diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/binop_vx_constraint-114.c b/gcc/testsuite/gcc.target/riscv/rvv/base/binop_vx_constraint-114.c index 61340be..d595c44 100644 --- a/gcc/testsuite/gcc.target/riscv/rvv/base/binop_vx_constraint-114.c +++ b/gcc/testsuite/gcc.target/riscv/rvv/base/binop_vx_constraint-114.c @@ -1,7 +1,5 @@ /* { dg-do compile } */ /* { dg-options "-march=rv32gcv -mabi=ilp32 -O3" } */ -// PR113249 -/* { dg-additional-options "-fno-schedule-insns -fno-schedule-insns2" } */ #include "riscv_vector.h" void f (void * in, void *out, int32_t x, int n) diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/binop_vx_constraint-119.c b/gcc/testsuite/gcc.target/riscv/rvv/base/binop_vx_constraint-119.c index 0f1485e..0b51175 100644 --- a/gcc/testsuite/gcc.target/riscv/rvv/base/binop_vx_constraint-119.c +++ b/gcc/testsuite/gcc.target/riscv/rvv/base/binop_vx_constraint-119.c @@ -1,7 +1,5 @@ /* { dg-do compile } */ /* { dg-options "-march=rv32gcv -mabi=ilp32 -O3" } */ -// PR113249 -/* { dg-additional-options "-fno-schedule-insns -fno-schedule-insns2" } */ #include "riscv_vector.h" void f (void * in, void *out, uint64_t x, int n) diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/binop_vx_constraint-12.c b/gcc/testsuite/gcc.target/riscv/rvv/base/binop_vx_constraint-12.c index 173ac62..634c12a 100644 --- a/gcc/testsuite/gcc.target/riscv/rvv/base/binop_vx_constraint-12.c +++ b/gcc/testsuite/gcc.target/riscv/rvv/base/binop_vx_constraint-12.c @@ -1,7 +1,5 @@ /* { dg-do compile } */ /* { dg-options "-march=rv32gcv -mabi=ilp32d -O3" } */ -// PR113249 -/* { dg-additional-options "-fno-schedule-insns -fno-schedule-insns2" } */ /* { dg-final { check-function-bodies "**" "" } } */ #include "riscv_vector.h" diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/binop_vx_constraint-16.c b/gcc/testsuite/gcc.target/riscv/rvv/base/binop_vx_constraint-16.c index 1edba89..651d610 100644 --- a/gcc/testsuite/gcc.target/riscv/rvv/base/binop_vx_constraint-16.c +++ b/gcc/testsuite/gcc.target/riscv/rvv/base/binop_vx_constraint-16.c @@ -1,7 +1,5 @@ /* { dg-do compile } */ /* { dg-options "-march=rv32gcv -mabi=ilp32d -O3" } */ -// PR113249 -/* { dg-additional-options "-fno-schedule-insns -fno-schedule-insns2" } */ /* { dg-final { check-function-bodies "**" "" } } */ #include "riscv_vector.h" diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/binop_vx_constraint-17.c b/gcc/testsuite/gcc.target/riscv/rvv/base/binop_vx_constraint-17.c index 75340c3..d19a9fd 100644 --- a/gcc/testsuite/gcc.target/riscv/rvv/base/binop_vx_constraint-17.c +++ b/gcc/testsuite/gcc.target/riscv/rvv/base/binop_vx_constraint-17.c @@ -1,7 +1,5 @@ /* { dg-do compile } */ /* { dg-options "-march=rv32gcv -mabi=ilp32d -O3" } */ -// PR113249 -/* { dg-additional-options "-fno-schedule-insns -fno-schedule-insns2" } */ /* { dg-final { check-function-bodies "**" "" } } */ #include "riscv_vector.h" diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/binop_vx_constraint-19.c b/gcc/testsuite/gcc.target/riscv/rvv/base/binop_vx_constraint-19.c index 7e4aedc..16f4315 100644 --- a/gcc/testsuite/gcc.target/riscv/rvv/base/binop_vx_constraint-19.c +++ b/gcc/testsuite/gcc.target/riscv/rvv/base/binop_vx_constraint-19.c @@ -1,7 +1,5 @@ /* { dg-do compile } */ /* { dg-options "-march=rv32gcv -mabi=ilp32d -O3" } */ -// PR113249 -/* { dg-additional-options "-fno-schedule-insns -fno-schedule-insns2" } */ /* { dg-final { check-function-bodies "**" "" } } */ #include "riscv_vector.h" diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/binop_vx_constraint-21.c b/gcc/testsuite/gcc.target/riscv/rvv/base/binop_vx_constraint-21.c index 755e92a..347c846 100644 --- a/gcc/testsuite/gcc.target/riscv/rvv/base/binop_vx_constraint-21.c +++ b/gcc/testsuite/gcc.target/riscv/rvv/base/binop_vx_constraint-21.c @@ -1,7 +1,5 @@ /* { dg-do compile } */ /* { dg-options "-march=rv32gcv -mabi=ilp32d -O3" } */ -// PR113249 -/* { dg-additional-options "-fno-schedule-insns -fno-schedule-insns2" } */ /* { dg-final { check-function-bodies "**" "" } } */ #include "riscv_vector.h" diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/binop_vx_constraint-23.c b/gcc/testsuite/gcc.target/riscv/rvv/base/binop_vx_constraint-23.c index 2c82dc0..bc41444 100644 --- a/gcc/testsuite/gcc.target/riscv/rvv/base/binop_vx_constraint-23.c +++ b/gcc/testsuite/gcc.target/riscv/rvv/base/binop_vx_constraint-23.c @@ -1,7 +1,5 @@ /* { dg-do compile } */ /* { dg-options "-march=rv32gcv -mabi=ilp32d -O3" } */ -// PR113249 -/* { dg-additional-options "-fno-schedule-insns -fno-schedule-insns2" } */ /* { dg-final { check-function-bodies "**" "" } } */ #include "riscv_vector.h" diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/binop_vx_constraint-25.c b/gcc/testsuite/gcc.target/riscv/rvv/base/binop_vx_constraint-25.c index e2ac6a3..ce3f3af 100644 --- a/gcc/testsuite/gcc.target/riscv/rvv/base/binop_vx_constraint-25.c +++ b/gcc/testsuite/gcc.target/riscv/rvv/base/binop_vx_constraint-25.c @@ -1,7 +1,5 @@ /* { dg-do compile } */ /* { dg-options "-march=rv32gcv -mabi=ilp32d -O3" } */ -// PR113249 -/* { dg-additional-options "-fno-schedule-insns -fno-schedule-insns2" } */ /* { dg-final { check-function-bodies "**" "" } } */ #include "riscv_vector.h" diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/binop_vx_constraint-27.c b/gcc/testsuite/gcc.target/riscv/rvv/base/binop_vx_constraint-27.c index 436a0e8..4946f84 100644 --- a/gcc/testsuite/gcc.target/riscv/rvv/base/binop_vx_constraint-27.c +++ b/gcc/testsuite/gcc.target/riscv/rvv/base/binop_vx_constraint-27.c @@ -1,7 +1,5 @@ /* { dg-do compile } */ /* { dg-options "-march=rv32gcv -mabi=ilp32d -O3" } */ -// PR113249 -/* { dg-additional-options "-fno-schedule-insns -fno-schedule-insns2" } */ /* { dg-final { check-function-bodies "**" "" } } */ #include "riscv_vector.h" diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/binop_vx_constraint-29.c b/gcc/testsuite/gcc.target/riscv/rvv/base/binop_vx_constraint-29.c index 72b3216..5f2eede 100644 --- a/gcc/testsuite/gcc.target/riscv/rvv/base/binop_vx_constraint-29.c +++ b/gcc/testsuite/gcc.target/riscv/rvv/base/binop_vx_constraint-29.c @@ -1,7 +1,5 @@ /* { dg-do compile } */ /* { dg-options "-march=rv32gcv -mabi=ilp32d -O3" } */ -// PR113249 -/* { dg-additional-options "-fno-schedule-insns -fno-schedule-insns2" } */ /* { dg-final { check-function-bodies "**" "" } } */ #include "riscv_vector.h" diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/binop_vx_constraint-31.c b/gcc/testsuite/gcc.target/riscv/rvv/base/binop_vx_constraint-31.c index 72b3216..5f2eede 100644 --- a/gcc/testsuite/gcc.target/riscv/rvv/base/binop_vx_constraint-31.c +++ b/gcc/testsuite/gcc.target/riscv/rvv/base/binop_vx_constraint-31.c @@ -1,7 +1,5 @@ /* { dg-do compile } */ /* { dg-options "-march=rv32gcv -mabi=ilp32d -O3" } */ -// PR113249 -/* { dg-additional-options "-fno-schedule-insns -fno-schedule-insns2" } */ /* { dg-final { check-function-bodies "**" "" } } */ #include "riscv_vector.h" diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/binop_vx_constraint-33.c b/gcc/testsuite/gcc.target/riscv/rvv/base/binop_vx_constraint-33.c index 6908c78..88fcba6 100644 --- a/gcc/testsuite/gcc.target/riscv/rvv/base/binop_vx_constraint-33.c +++ b/gcc/testsuite/gcc.target/riscv/rvv/base/binop_vx_constraint-33.c @@ -1,7 +1,5 @@ /* { dg-do compile } */ /* { dg-options "-march=rv32gcv -mabi=ilp32d -O3" } */ -// PR113249 -/* { dg-additional-options "-fno-schedule-insns -fno-schedule-insns2" } */ /* { dg-final { check-function-bodies "**" "" } } */ #include "riscv_vector.h" diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/binop_vx_constraint-35.c b/gcc/testsuite/gcc.target/riscv/rvv/base/binop_vx_constraint-35.c index 6908c78..88fcba6 100644 --- a/gcc/testsuite/gcc.target/riscv/rvv/base/binop_vx_constraint-35.c +++ b/gcc/testsuite/gcc.target/riscv/rvv/base/binop_vx_constraint-35.c @@ -1,7 +1,5 @@ /* { dg-do compile } */ /* { dg-options "-march=rv32gcv -mabi=ilp32d -O3" } */ -// PR113249 -/* { dg-additional-options "-fno-schedule-insns -fno-schedule-insns2" } */ /* { dg-final { check-function-bodies "**" "" } } */ #include "riscv_vector.h" diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/binop_vx_constraint-4.c b/gcc/testsuite/gcc.target/riscv/rvv/base/binop_vx_constraint-4.c index ee1db1c..87a1645 100644 --- a/gcc/testsuite/gcc.target/riscv/rvv/base/binop_vx_constraint-4.c +++ b/gcc/testsuite/gcc.target/riscv/rvv/base/binop_vx_constraint-4.c @@ -1,7 +1,5 @@ /* { dg-do compile } */ /* { dg-options "-march=rv32gcv -mabi=ilp32d -O3" } */ -// PR113249 -/* { dg-additional-options "-fno-schedule-insns -fno-schedule-insns2" } */ /* { dg-final { check-function-bodies "**" "" } } */ #include "riscv_vector.h" diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/binop_vx_constraint-40.c b/gcc/testsuite/gcc.target/riscv/rvv/base/binop_vx_constraint-40.c index fb969eb..c0321ce 100644 --- a/gcc/testsuite/gcc.target/riscv/rvv/base/binop_vx_constraint-40.c +++ b/gcc/testsuite/gcc.target/riscv/rvv/base/binop_vx_constraint-40.c @@ -1,7 +1,5 @@ /* { dg-do compile } */ /* { dg-options "-march=rv32gcv -mabi=ilp32d -O3" } */ -// PR113249 -/* { dg-additional-options "-fno-schedule-insns -fno-schedule-insns2" } */ /* { dg-final { check-function-bodies "**" "" } } */ #include "riscv_vector.h" diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/binop_vx_constraint-44.c b/gcc/testsuite/gcc.target/riscv/rvv/base/binop_vx_constraint-44.c index 542f43e..ab0f13b 100644 --- a/gcc/testsuite/gcc.target/riscv/rvv/base/binop_vx_constraint-44.c +++ b/gcc/testsuite/gcc.target/riscv/rvv/base/binop_vx_constraint-44.c @@ -1,7 +1,5 @@ /* { dg-do compile } */ /* { dg-options "-march=rv32gcv -mabi=ilp32d -O3" } */ -// PR113249 -/* { dg-additional-options "-fno-schedule-insns -fno-schedule-insns2" } */ /* { dg-final { check-function-bodies "**" "" } } */ #include "riscv_vector.h" diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/binop_vx_constraint-50.c b/gcc/testsuite/gcc.target/riscv/rvv/base/binop_vx_constraint-50.c index 31109a8..3893e17 100644 --- a/gcc/testsuite/gcc.target/riscv/rvv/base/binop_vx_constraint-50.c +++ b/gcc/testsuite/gcc.target/riscv/rvv/base/binop_vx_constraint-50.c @@ -1,7 +1,5 @@ /* { dg-do compile } */ /* { dg-options "-march=rv32gcv -mabi=ilp32 -O3" } */ -// PR113249 -/* { dg-additional-options "-fno-schedule-insns -fno-schedule-insns2" } */ #include "riscv_vector.h" void f (void * in, void *out, int32_t x, int n) diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/binop_vx_constraint-56.c b/gcc/testsuite/gcc.target/riscv/rvv/base/binop_vx_constraint-56.c index 924f450..b0ea553 100644 --- a/gcc/testsuite/gcc.target/riscv/rvv/base/binop_vx_constraint-56.c +++ b/gcc/testsuite/gcc.target/riscv/rvv/base/binop_vx_constraint-56.c @@ -1,7 +1,5 @@ /* { dg-do compile } */ /* { dg-options "-march=rv32gcv -mabi=ilp32 -O3" } */ -// PR113249 -/* { dg-additional-options "-fno-schedule-insns -fno-schedule-insns2" } */ #include "riscv_vector.h" void f (void * in, void *out, int64_t x, int n) diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/binop_vx_constraint-62.c b/gcc/testsuite/gcc.target/riscv/rvv/base/binop_vx_constraint-62.c index 659d8d9..350697d 100644 --- a/gcc/testsuite/gcc.target/riscv/rvv/base/binop_vx_constraint-62.c +++ b/gcc/testsuite/gcc.target/riscv/rvv/base/binop_vx_constraint-62.c @@ -1,7 +1,5 @@ /* { dg-do compile } */ /* { dg-options "-march=rv32gcv -mabi=ilp32 -O3" } */ -// PR113249 -/* { dg-additional-options "-fno-schedule-insns -fno-schedule-insns2" } */ #include "riscv_vector.h" void f (void * in, void *out, int64_t x, int n) diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/binop_vx_constraint-68.c b/gcc/testsuite/gcc.target/riscv/rvv/base/binop_vx_constraint-68.c index 6387460..0f138c5 100644 --- a/gcc/testsuite/gcc.target/riscv/rvv/base/binop_vx_constraint-68.c +++ b/gcc/testsuite/gcc.target/riscv/rvv/base/binop_vx_constraint-68.c @@ -1,7 +1,5 @@ /* { dg-do compile } */ /* { dg-options "-march=rv32gcv -mabi=ilp32 -O3" } */ -// PR113249 -/* { dg-additional-options "-fno-schedule-insns -fno-schedule-insns2" } */ #include "riscv_vector.h" void f (void * in, void *out, int64_t x, int n) diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/binop_vx_constraint-74.c b/gcc/testsuite/gcc.target/riscv/rvv/base/binop_vx_constraint-74.c index a214d70..f4cbf09 100644 --- a/gcc/testsuite/gcc.target/riscv/rvv/base/binop_vx_constraint-74.c +++ b/gcc/testsuite/gcc.target/riscv/rvv/base/binop_vx_constraint-74.c @@ -1,7 +1,5 @@ /* { dg-do compile } */ /* { dg-options "-march=rv32gcv -mabi=ilp32 -O3" } */ -// PR113249 -/* { dg-additional-options "-fno-schedule-insns -fno-schedule-insns2" } */ #include "riscv_vector.h" void f (void * in, void *out, int64_t x, int n) diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/binop_vx_constraint-79.c b/gcc/testsuite/gcc.target/riscv/rvv/base/binop_vx_constraint-79.c index efa659b..d606078 100644 --- a/gcc/testsuite/gcc.target/riscv/rvv/base/binop_vx_constraint-79.c +++ b/gcc/testsuite/gcc.target/riscv/rvv/base/binop_vx_constraint-79.c @@ -1,7 +1,5 @@ /* { dg-do compile } */ /* { dg-options "-march=rv32gcv -mabi=ilp32 -O3" } */ -// PR113249 -/* { dg-additional-options "-fno-schedule-insns -fno-schedule-insns2" } */ #include "riscv_vector.h" void f (void * in, void *out, int64_t x, int n) diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/binop_vx_constraint-8.c b/gcc/testsuite/gcc.target/riscv/rvv/base/binop_vx_constraint-8.c index 6a26248..9bf9ff5 100644 --- a/gcc/testsuite/gcc.target/riscv/rvv/base/binop_vx_constraint-8.c +++ b/gcc/testsuite/gcc.target/riscv/rvv/base/binop_vx_constraint-8.c @@ -1,7 +1,5 @@ /* { dg-do compile } */ /* { dg-options "-march=rv32gcv -mabi=ilp32d -O3" } */ -// PR113249 -/* { dg-additional-options "-fno-schedule-insns -fno-schedule-insns2" } */ /* { dg-final { check-function-bodies "**" "" } } */ #include "riscv_vector.h" diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/binop_vx_constraint-84.c b/gcc/testsuite/gcc.target/riscv/rvv/base/binop_vx_constraint-84.c index 429fe12..bca55b2 100644 --- a/gcc/testsuite/gcc.target/riscv/rvv/base/binop_vx_constraint-84.c +++ b/gcc/testsuite/gcc.target/riscv/rvv/base/binop_vx_constraint-84.c @@ -1,7 +1,5 @@ /* { dg-do compile } */ /* { dg-options "-march=rv32gcv -mabi=ilp32 -O3" } */ -// PR113249 -/* { dg-additional-options "-fno-schedule-insns -fno-schedule-insns2" } */ #include "riscv_vector.h" void f (void * in, void *out, uint64_t x, int n) diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/binop_vx_constraint-90.c b/gcc/testsuite/gcc.target/riscv/rvv/base/binop_vx_constraint-90.c index 0cd0af7..586e264 100644 --- a/gcc/testsuite/gcc.target/riscv/rvv/base/binop_vx_constraint-90.c +++ b/gcc/testsuite/gcc.target/riscv/rvv/base/binop_vx_constraint-90.c @@ -1,7 +1,5 @@ /* { dg-do compile } */ /* { dg-options "-march=rv32gcv -mabi=ilp32 -O3" } */ -// PR113249 -/* { dg-additional-options "-fno-schedule-insns -fno-schedule-insns2" } */ #include "riscv_vector.h" void f (void * in, void *out, int32_t x, int n) diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/binop_vx_constraint-96.c b/gcc/testsuite/gcc.target/riscv/rvv/base/binop_vx_constraint-96.c index bb1690e..d1bbb78 100644 --- a/gcc/testsuite/gcc.target/riscv/rvv/base/binop_vx_constraint-96.c +++ b/gcc/testsuite/gcc.target/riscv/rvv/base/binop_vx_constraint-96.c @@ -1,7 +1,5 @@ /* { dg-do compile } */ /* { dg-options "-march=rv32gcv -mabi=ilp32 -O3" } */ -// PR113249 -/* { dg-additional-options "-fno-schedule-insns -fno-schedule-insns2" } */ #include "riscv_vector.h" void f (void * in, void *out, int32_t x, int n) diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-30.c b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-30.c index 37ef0f0..7e73878 100644 --- a/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-30.c +++ b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-30.c @@ -1,7 +1,5 @@ /* { dg-do compile } */ /* { dg-options "-march=rv64gcv -mabi=lp64 -O3" } */ -// PR113249 -/* { dg-additional-options "-fno-schedule-insns -fno-schedule-insns2" } */ #include "riscv_vector.h" diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/pr108185-1.c b/gcc/testsuite/gcc.target/riscv/rvv/base/pr108185-1.c index 4c6e88e..c3d0b10 100644 --- a/gcc/testsuite/gcc.target/riscv/rvv/base/pr108185-1.c +++ b/gcc/testsuite/gcc.target/riscv/rvv/base/pr108185-1.c @@ -1,7 +1,5 @@ /* { dg-do compile } */ /* { dg-options "-march=rv64gcv -mabi=lp64 -O3" } */ -// PR113249 -/* { dg-additional-options "-fno-schedule-insns -fno-schedule-insns2" } */ #include "riscv_vector.h" diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/pr108185-2.c b/gcc/testsuite/gcc.target/riscv/rvv/base/pr108185-2.c index 0844e3e..bd13ba9 100644 --- a/gcc/testsuite/gcc.target/riscv/rvv/base/pr108185-2.c +++ b/gcc/testsuite/gcc.target/riscv/rvv/base/pr108185-2.c @@ -1,7 +1,5 @@ /* { dg-do compile } */ /* { dg-options "-march=rv64gcv -mabi=lp64 -O3" } */ -// PR113249 -/* { dg-additional-options "-fno-schedule-insns -fno-schedule-insns2" } */ #include "riscv_vector.h" diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/pr108185-3.c b/gcc/testsuite/gcc.target/riscv/rvv/base/pr108185-3.c index 49a5744..99928f7 100644 --- a/gcc/testsuite/gcc.target/riscv/rvv/base/pr108185-3.c +++ b/gcc/testsuite/gcc.target/riscv/rvv/base/pr108185-3.c @@ -1,7 +1,5 @@ /* { dg-do compile } */ /* { dg-options "-march=rv64gcv -mabi=lp64 -O3" } */ -// PR113249 -/* { dg-additional-options "-fno-schedule-insns -fno-schedule-insns2" } */ #include "riscv_vector.h" diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/pr108185-4.c b/gcc/testsuite/gcc.target/riscv/rvv/base/pr108185-4.c index cef0a11..321cd5c 100644 --- a/gcc/testsuite/gcc.target/riscv/rvv/base/pr108185-4.c +++ b/gcc/testsuite/gcc.target/riscv/rvv/base/pr108185-4.c @@ -1,7 +1,5 @@ /* { dg-do compile } */ /* { dg-options "-march=rv64gc_zve64d -mabi=lp64 -O3" } */ -// PR113249 -/* { dg-additional-options "-fno-schedule-insns -fno-schedule-insns2" } */ #include "riscv_vector.h" diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/pr108185-5.c b/gcc/testsuite/gcc.target/riscv/rvv/base/pr108185-5.c index 3f0d677..575a784 100644 --- a/gcc/testsuite/gcc.target/riscv/rvv/base/pr108185-5.c +++ b/gcc/testsuite/gcc.target/riscv/rvv/base/pr108185-5.c @@ -1,7 +1,5 @@ /* { dg-do compile } */ /* { dg-options "-march=rv64gcv -mabi=lp64 -O3" } */ -// PR113249 -/* { dg-additional-options "-fno-schedule-insns -fno-schedule-insns2" } */ #include "riscv_vector.h" diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/pr108185-6.c b/gcc/testsuite/gcc.target/riscv/rvv/base/pr108185-6.c index 4ed6588..95a11d3 100644 --- a/gcc/testsuite/gcc.target/riscv/rvv/base/pr108185-6.c +++ b/gcc/testsuite/gcc.target/riscv/rvv/base/pr108185-6.c @@ -1,7 +1,5 @@ /* { dg-do compile } */ /* { dg-options "-march=rv64gcv -mabi=lp64 -O3" } */ -// PR113249 -/* { dg-additional-options "-fno-schedule-insns -fno-schedule-insns2" } */ #include "riscv_vector.h" diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/pr108185-7.c b/gcc/testsuite/gcc.target/riscv/rvv/base/pr108185-7.c index 95b7ff9..8f6f0b1 100644 --- a/gcc/testsuite/gcc.target/riscv/rvv/base/pr108185-7.c +++ b/gcc/testsuite/gcc.target/riscv/rvv/base/pr108185-7.c @@ -1,7 +1,5 @@ /* { dg-do compile } */ /* { dg-options "-march=rv64gcv -mabi=lp64 -O3" } */ -// PR113249 -/* { dg-additional-options "-fno-schedule-insns -fno-schedule-insns2" } */ #include "riscv_vector.h" diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/shift_vx_constraint-1.c b/gcc/testsuite/gcc.target/riscv/rvv/base/shift_vx_constraint-1.c index 9e0b41c..250e017 100644 --- a/gcc/testsuite/gcc.target/riscv/rvv/base/shift_vx_constraint-1.c +++ b/gcc/testsuite/gcc.target/riscv/rvv/base/shift_vx_constraint-1.c @@ -1,7 +1,5 @@ /* { dg-do compile } */ /* { dg-options "-march=rv32gcv -mabi=ilp32d -O3" } */ -// PR113249 -/* { dg-additional-options "-fno-schedule-insns -fno-schedule-insns2" } */ /* { dg-final { check-function-bodies "**" "" } } */ #include "riscv_vector.h" diff --git a/gcc/testsuite/gcc.target/riscv/rvv/vsetvl/pr111037-3.c b/gcc/testsuite/gcc.target/riscv/rvv/vsetvl/pr111037-3.c index 5e1859c..110e55b 100644 --- a/gcc/testsuite/gcc.target/riscv/rvv/vsetvl/pr111037-3.c +++ b/gcc/testsuite/gcc.target/riscv/rvv/vsetvl/pr111037-3.c @@ -1,7 +1,5 @@ /* { dg-do compile } */ /* { dg-options "--param=riscv-autovec-preference=scalable -march=rv32gc_zve64f_zvfh -mabi=ilp32d -O3" } */ -// PR113249 -/* { dg-additional-options "-fno-schedule-insns -fno-schedule-insns2" } */ #include "riscv_vector.h" diff --git a/gcc/testsuite/gcc.target/riscv/rvv/vsetvl/vlmax_back_prop-28.c b/gcc/testsuite/gcc.target/riscv/rvv/vsetvl/vlmax_back_prop-28.c index f4f0e52..4583504 100644 --- a/gcc/testsuite/gcc.target/riscv/rvv/vsetvl/vlmax_back_prop-28.c +++ b/gcc/testsuite/gcc.target/riscv/rvv/vsetvl/vlmax_back_prop-28.c @@ -1,7 +1,5 @@ /* { dg-do compile } */ /* { dg-options "--param=riscv-autovec-preference=scalable -march=rv32gcv -mabi=ilp32 -fno-tree-vectorize" } */ -// PR113249 -/* { dg-additional-options "-fno-schedule-insns -fno-schedule-insns2" } */ #include "riscv_vector.h" diff --git a/gcc/testsuite/gcc.target/riscv/rvv/vsetvl/vlmax_back_prop-29.c b/gcc/testsuite/gcc.target/riscv/rvv/vsetvl/vlmax_back_prop-29.c index 7e01b81..f16f4b9 100644 --- a/gcc/testsuite/gcc.target/riscv/rvv/vsetvl/vlmax_back_prop-29.c +++ b/gcc/testsuite/gcc.target/riscv/rvv/vsetvl/vlmax_back_prop-29.c @@ -1,7 +1,5 @@ /* { dg-do compile } */ /* { dg-options "--param=riscv-autovec-preference=scalable -march=rv32gcv -mabi=ilp32 -fno-tree-vectorize" } */ -// PR113249 -/* { dg-additional-options "-fno-schedule-insns -fno-schedule-insns2" } */ #include "riscv_vector.h" diff --git a/gcc/testsuite/gcc.target/riscv/rvv/vsetvl/vlmax_back_prop-32.c b/gcc/testsuite/gcc.target/riscv/rvv/vsetvl/vlmax_back_prop-32.c index 5615cb1..43b443b 100644 --- a/gcc/testsuite/gcc.target/riscv/rvv/vsetvl/vlmax_back_prop-32.c +++ b/gcc/testsuite/gcc.target/riscv/rvv/vsetvl/vlmax_back_prop-32.c @@ -1,7 +1,5 @@ /* { dg-do compile } */ /* { dg-options "--param=riscv-autovec-preference=scalable -march=rv32gcv -mabi=ilp32 -fno-tree-vectorize" } */ -// PR113249 -/* { dg-additional-options "-fno-schedule-insns -fno-schedule-insns2" } */ #include "riscv_vector.h" diff --git a/gcc/testsuite/gcc.target/riscv/rvv/vsetvl/vlmax_back_prop-33.c b/gcc/testsuite/gcc.target/riscv/rvv/vsetvl/vlmax_back_prop-33.c index c906b15..6785558 100644 --- a/gcc/testsuite/gcc.target/riscv/rvv/vsetvl/vlmax_back_prop-33.c +++ b/gcc/testsuite/gcc.target/riscv/rvv/vsetvl/vlmax_back_prop-33.c @@ -1,7 +1,5 @@ /* { dg-do compile } */ /* { dg-options "--param=riscv-autovec-preference=scalable -march=rv32gcv -mabi=ilp32 -fno-tree-vectorize" } */ -// PR113249 -/* { dg-additional-options "-fno-schedule-insns -fno-schedule-insns2" } */ #include "riscv_vector.h" diff --git a/gcc/testsuite/gcc.target/riscv/rvv/vsetvl/vlmax_single_block-17.c b/gcc/testsuite/gcc.target/riscv/rvv/vsetvl/vlmax_single_block-17.c index 006df7e..960c9bf 100644 --- a/gcc/testsuite/gcc.target/riscv/rvv/vsetvl/vlmax_single_block-17.c +++ b/gcc/testsuite/gcc.target/riscv/rvv/vsetvl/vlmax_single_block-17.c @@ -1,7 +1,5 @@ /* { dg-do compile } */ /* { dg-options "--param=riscv-autovec-preference=scalable -march=rv32gcv -mabi=ilp32" } */ -// PR113249 -/* { dg-additional-options "-fno-schedule-insns -fno-schedule-insns2" } */ #include "riscv_vector.h" diff --git a/gcc/testsuite/gcc.target/riscv/rvv/vsetvl/vlmax_single_block-18.c b/gcc/testsuite/gcc.target/riscv/rvv/vsetvl/vlmax_single_block-18.c index cc6d822..5f22e8d 100644 --- a/gcc/testsuite/gcc.target/riscv/rvv/vsetvl/vlmax_single_block-18.c +++ b/gcc/testsuite/gcc.target/riscv/rvv/vsetvl/vlmax_single_block-18.c @@ -1,7 +1,5 @@ /* { dg-do compile } */ /* { dg-options "--param=riscv-autovec-preference=scalable -march=rv32gcv -mabi=ilp32" } */ -// PR113249 -/* { dg-additional-options "-fno-schedule-insns -fno-schedule-insns2" } */ #include "riscv_vector.h" diff --git a/gcc/testsuite/gcc.target/riscv/rvv/vsetvl/vlmax_single_block-19.c b/gcc/testsuite/gcc.target/riscv/rvv/vsetvl/vlmax_single_block-19.c index 9704e444..e5f35c0 100644 --- a/gcc/testsuite/gcc.target/riscv/rvv/vsetvl/vlmax_single_block-19.c +++ b/gcc/testsuite/gcc.target/riscv/rvv/vsetvl/vlmax_single_block-19.c @@ -1,7 +1,5 @@ /* { dg-do compile } */ /* { dg-options "--param=riscv-autovec-preference=scalable -march=rv32gcv -mabi=ilp32" } */ -// PR113249 -/* { dg-additional-options "-fno-schedule-insns -fno-schedule-insns2" } */ #include "riscv_vector.h" diff --git a/gcc/testsuite/gcc.target/riscv/rvv/vsetvl/vlmax_switch_vtype-10.c b/gcc/testsuite/gcc.target/riscv/rvv/vsetvl/vlmax_switch_vtype-10.c index 476735d..0532c7d 100644 --- a/gcc/testsuite/gcc.target/riscv/rvv/vsetvl/vlmax_switch_vtype-10.c +++ b/gcc/testsuite/gcc.target/riscv/rvv/vsetvl/vlmax_switch_vtype-10.c @@ -1,7 +1,5 @@ /* { dg-do compile } */ /* { dg-options "--param=riscv-autovec-preference=scalable -march=rv32gcv -mabi=ilp32 -fno-tree-vectorize" } */ -// PR113249 -/* { dg-additional-options "-fno-schedule-insns -fno-schedule-insns2" } */ #include "riscv_vector.h" diff --git a/gcc/testsuite/gcc.target/riscv/rvv/vsetvl/vlmax_switch_vtype-11.c b/gcc/testsuite/gcc.target/riscv/rvv/vsetvl/vlmax_switch_vtype-11.c index c7b7db3..b664c4b 100644 --- a/gcc/testsuite/gcc.target/riscv/rvv/vsetvl/vlmax_switch_vtype-11.c +++ b/gcc/testsuite/gcc.target/riscv/rvv/vsetvl/vlmax_switch_vtype-11.c @@ -1,7 +1,5 @@ /* { dg-do compile } */ /* { dg-options "--param=riscv-autovec-preference=scalable -march=rv32gcv -mabi=ilp32 -fno-tree-vectorize" } */ -// PR113249 -/* { dg-additional-options "-fno-schedule-insns -fno-schedule-insns2" } */ #include "riscv_vector.h" diff --git a/gcc/testsuite/gcc.target/riscv/rvv/vsetvl/vlmax_switch_vtype-12.c b/gcc/testsuite/gcc.target/riscv/rvv/vsetvl/vlmax_switch_vtype-12.c index 80ff75f..04c4b88 100644 --- a/gcc/testsuite/gcc.target/riscv/rvv/vsetvl/vlmax_switch_vtype-12.c +++ b/gcc/testsuite/gcc.target/riscv/rvv/vsetvl/vlmax_switch_vtype-12.c @@ -1,7 +1,5 @@ /* { dg-do compile } */ /* { dg-options "--param=riscv-autovec-preference=scalable -march=rv32gcv -mabi=ilp32 -fno-tree-vectorize" } */ -// PR113249 -/* { dg-additional-options "-fno-schedule-insns -fno-schedule-insns2" } */ #include "riscv_vector.h" diff --git a/gcc/testsuite/gcc.target/riscv/rvv/vsetvl/vlmax_switch_vtype-4.c b/gcc/testsuite/gcc.target/riscv/rvv/vsetvl/vlmax_switch_vtype-4.c index 127dc7f..1404c9d 100644 --- a/gcc/testsuite/gcc.target/riscv/rvv/vsetvl/vlmax_switch_vtype-4.c +++ b/gcc/testsuite/gcc.target/riscv/rvv/vsetvl/vlmax_switch_vtype-4.c @@ -1,7 +1,5 @@ /* { dg-do compile } */ /* { dg-options "--param=riscv-autovec-preference=scalable -march=rv32gcv -mabi=ilp32" } */ -// PR113249 -/* { dg-additional-options "-fno-schedule-insns -fno-schedule-insns2" } */ #include "riscv_vector.h" diff --git a/gcc/testsuite/gcc.target/riscv/rvv/vsetvl/vlmax_switch_vtype-5.c b/gcc/testsuite/gcc.target/riscv/rvv/vsetvl/vlmax_switch_vtype-5.c index 127dc7f..1404c9d 100644 --- a/gcc/testsuite/gcc.target/riscv/rvv/vsetvl/vlmax_switch_vtype-5.c +++ b/gcc/testsuite/gcc.target/riscv/rvv/vsetvl/vlmax_switch_vtype-5.c @@ -1,7 +1,5 @@ /* { dg-do compile } */ /* { dg-options "--param=riscv-autovec-preference=scalable -march=rv32gcv -mabi=ilp32" } */ -// PR113249 -/* { dg-additional-options "-fno-schedule-insns -fno-schedule-insns2" } */ #include "riscv_vector.h" diff --git a/gcc/testsuite/gcc.target/riscv/rvv/vsetvl/vlmax_switch_vtype-6.c b/gcc/testsuite/gcc.target/riscv/rvv/vsetvl/vlmax_switch_vtype-6.c index e19e869..609c68d 100644 --- a/gcc/testsuite/gcc.target/riscv/rvv/vsetvl/vlmax_switch_vtype-6.c +++ b/gcc/testsuite/gcc.target/riscv/rvv/vsetvl/vlmax_switch_vtype-6.c @@ -1,7 +1,5 @@ /* { dg-do compile } */ /* { dg-options "--param=riscv-autovec-preference=scalable -march=rv32gcv -mabi=ilp32" } */ -// PR113249 -/* { dg-additional-options "-fno-schedule-insns -fno-schedule-insns2" } */ #include "riscv_vector.h" diff --git a/gcc/testsuite/gcc.target/riscv/rvv/vsetvl/vlmax_switch_vtype-7.c b/gcc/testsuite/gcc.target/riscv/rvv/vsetvl/vlmax_switch_vtype-7.c index 90eca5b..043f177 100644 --- a/gcc/testsuite/gcc.target/riscv/rvv/vsetvl/vlmax_switch_vtype-7.c +++ b/gcc/testsuite/gcc.target/riscv/rvv/vsetvl/vlmax_switch_vtype-7.c @@ -1,7 +1,5 @@ /* { dg-do compile } */ /* { dg-options "--param=riscv-autovec-preference=scalable -march=rv32gcv -mabi=ilp32 -fno-tree-vectorize" } */ -// PR113249 -/* { dg-additional-options "-fno-schedule-insns -fno-schedule-insns2" } */ #include "riscv_vector.h" diff --git a/gcc/testsuite/gcc.target/riscv/rvv/vsetvl/vlmax_switch_vtype-8.c b/gcc/testsuite/gcc.target/riscv/rvv/vsetvl/vlmax_switch_vtype-8.c index 17b217b..0bedde8 100644 --- a/gcc/testsuite/gcc.target/riscv/rvv/vsetvl/vlmax_switch_vtype-8.c +++ b/gcc/testsuite/gcc.target/riscv/rvv/vsetvl/vlmax_switch_vtype-8.c @@ -1,7 +1,5 @@ /* { dg-do compile } */ /* { dg-options "--param=riscv-autovec-preference=scalable -march=rv32gcv -mabi=ilp32 -fno-tree-vectorize" } */ -// PR113249 -/* { dg-additional-options "-fno-schedule-insns -fno-schedule-insns2" } */ #include "riscv_vector.h" diff --git a/gcc/testsuite/gcc.target/riscv/rvv/vsetvl/vlmax_switch_vtype-9.c b/gcc/testsuite/gcc.target/riscv/rvv/vsetvl/vlmax_switch_vtype-9.c index 17b217b..0bedde8 100644 --- a/gcc/testsuite/gcc.target/riscv/rvv/vsetvl/vlmax_switch_vtype-9.c +++ b/gcc/testsuite/gcc.target/riscv/rvv/vsetvl/vlmax_switch_vtype-9.c @@ -1,7 +1,5 @@ /* { dg-do compile } */ /* { dg-options "--param=riscv-autovec-preference=scalable -march=rv32gcv -mabi=ilp32 -fno-tree-vectorize" } */ -// PR113249 -/* { dg-additional-options "-fno-schedule-insns -fno-schedule-insns2" } */ #include "riscv_vector.h" diff --git a/gcc/testsuite/gfortran.dg/vect/vect-8.f90 b/gcc/testsuite/gfortran.dg/vect/vect-8.f90 index f77ec9f..938dfc2 100644 --- a/gcc/testsuite/gfortran.dg/vect/vect-8.f90 +++ b/gcc/testsuite/gfortran.dg/vect/vect-8.f90 @@ -1,8 +1,6 @@ ! { dg-do compile } ! { dg-require-effective-target vect_double } ! { dg-additional-options "-fno-tree-loop-distribute-patterns -finline-matmul-limit=0" } -! PR113249 -! { dg-options "-fno-schedule-insns -fno-schedule-insns2" { target { riscv*-*-* } } } module lfk_prec integer, parameter :: dp=kind(1.d0) -- cgit v1.1 From 2a30dd3a763a3a5f517bd923607b6081157eeaac Mon Sep 17 00:00:00 2001 From: Edwin Lu Date: Wed, 31 Jan 2024 21:49:27 -0800 Subject: Revert "RISC-V: Add vector related pipelines" This reverts commit e56fb037d9d265682f5e7217d8a4c12a8d3fddf8. --- gcc/config/riscv/generic-ooo.md | 127 ++++++++++++++++++++++++++++- gcc/config/riscv/generic-vector-ooo.md | 143 --------------------------------- gcc/config/riscv/riscv.md | 1 - 3 files changed, 126 insertions(+), 145 deletions(-) delete mode 100644 gcc/config/riscv/generic-vector-ooo.md (limited to 'gcc') diff --git a/gcc/config/riscv/generic-ooo.md b/gcc/config/riscv/generic-ooo.md index 4e8297b..ef8cb96 100644 --- a/gcc/config/riscv/generic-ooo.md +++ b/gcc/config/riscv/generic-ooo.md @@ -1,5 +1,5 @@ ;; RISC-V generic out-of-order core scheduling model. -;; Copyright (C) 2023-2024 Free Software Foundation, Inc. +;; Copyright (C) 2017-2024 Free Software Foundation, Inc. ;; ;; This file is part of GCC. ;; @@ -48,6 +48,9 @@ ;; Integer/float issue queues. (define_cpu_unit "issue0,issue1,issue2,issue3,issue4" "generic_ooo") +;; Separate issue queue for vector instructions. +(define_cpu_unit "generic_ooo_vxu_issue" "generic_ooo") + ;; Integer/float execution units. (define_cpu_unit "ixu0,ixu1,ixu2,ixu3" "generic_ooo") (define_cpu_unit "fxu0,fxu1" "generic_ooo") @@ -55,6 +58,12 @@ ;; Integer subunit for division. (define_cpu_unit "generic_ooo_div" "generic_ooo") +;; Vector execution unit. +(define_cpu_unit "generic_ooo_vxu_alu" "generic_ooo") + +;; Vector subunit that does mult/div/sqrt. +(define_cpu_unit "generic_ooo_vxu_multicycle" "generic_ooo") + ;; Shortcuts (define_reservation "generic_ooo_issue" "issue0|issue1|issue2|issue3|issue4") (define_reservation "generic_ooo_ixu_alu" "ixu0|ixu1|ixu2|ixu3") @@ -83,6 +92,25 @@ (eq_attr "type" "fpstore")) "generic_ooo_issue,generic_ooo_fxu") +;; Vector load/store +(define_insn_reservation "generic_ooo_vec_load" 6 + (and (eq_attr "tune" "generic_ooo") + (eq_attr "type" "vlde,vldm,vlds,vldux,vldox,vldff,vldr")) + "generic_ooo_vxu_issue,generic_ooo_vxu_alu") + +(define_insn_reservation "generic_ooo_vec_store" 6 + (and (eq_attr "tune" "generic_ooo") + (eq_attr "type" "vste,vstm,vsts,vstux,vstox,vstr")) + "generic_ooo_vxu_issue,generic_ooo_vxu_alu") + +;; Vector segment loads/stores. +(define_insn_reservation "generic_ooo_vec_loadstore_seg" 10 + (and (eq_attr "tune" "generic_ooo") + (eq_attr "type" "vlsegde,vlsegds,vlsegdux,vlsegdox,vlsegdff,\ + vssegte,vssegts,vssegtux,vssegtox")) + "generic_ooo_vxu_issue,generic_ooo_vxu_alu") + + ;; Generic integer instructions. (define_insn_reservation "generic_ooo_alu" 1 (and (eq_attr "tune" "generic_ooo") @@ -163,6 +191,103 @@ (eq_attr "type" "cpop,clmul")) "generic_ooo_issue,generic_ooo_ixu_alu") +;; Regular vector operations and integer comparisons. +(define_insn_reservation "generic_ooo_vec_alu" 3 + (and (eq_attr "tune" "generic_ooo") + (eq_attr "type" "vialu,viwalu,vext,vicalu,vshift,vnshift,viminmax,vicmp,\ + vimov,vsalu,vaalu,vsshift,vnclip,vmov,vfmov,vector")) + "generic_ooo_vxu_issue,generic_ooo_vxu_alu") + +;; Vector float comparison, conversion etc. +(define_insn_reservation "generic_ooo_vec_fcmp" 3 + (and (eq_attr "tune" "generic_ooo") + (eq_attr "type" "vfrecp,vfminmax,vfcmp,vfsgnj,vfclass,vfcvtitof,\ + vfcvtftoi,vfwcvtitof,vfwcvtftoi,vfwcvtftof,vfncvtitof,\ + vfncvtftoi,vfncvtftof")) + "generic_ooo_vxu_issue,generic_ooo_vxu_alu") + +;; Vector integer multiplication. +(define_insn_reservation "generic_ooo_vec_imul" 4 + (and (eq_attr "tune" "generic_ooo") + (eq_attr "type" "vimul,viwmul,vimuladd,viwmuladd,vsmul")) + "generic_ooo_vxu_issue,generic_ooo_vxu_alu") + +;; Vector float addition. +(define_insn_reservation "generic_ooo_vec_fadd" 4 + (and (eq_attr "tune" "generic_ooo") + (eq_attr "type" "vfalu,vfwalu")) + "generic_ooo_vxu_issue,generic_ooo_vxu_alu") + +;; Vector float multiplication and FMA. +(define_insn_reservation "generic_ooo_vec_fmul" 6 + (and (eq_attr "tune" "generic_ooo") + (eq_attr "type" "vfmul,vfwmul,vfmuladd,vfwmuladd")) + "generic_ooo_vxu_issue,generic_ooo_vxu_alu") + +;; Vector crypto, assumed to be a generic operation for now. +(define_insn_reservation "generic_ooo_crypto" 4 + (and (eq_attr "tune" "generic_ooo") + (eq_attr "type" "crypto")) + "generic_ooo_vxu_issue,generic_ooo_vxu_alu") + +;; Vector permute. +(define_insn_reservation "generic_ooo_perm" 3 + (and (eq_attr "tune" "generic_ooo") + (eq_attr "type" "vimerge,vfmerge,vslideup,vslidedown,vislide1up,\ + vislide1down,vfslide1up,vfslide1down,vgather,vcompress")) + "generic_ooo_vxu_issue,generic_ooo_vxu_alu") + +;; Vector reduction. +(define_insn_reservation "generic_ooo_vec_reduction" 8 + (and (eq_attr "tune" "generic_ooo") + (eq_attr "type" "vired,viwred,vfredu,vfwredu")) + "generic_ooo_vxu_issue,generic_ooo_vxu_multicycle") + +;; Vector ordered reduction, assume the latency number is for +;; a 128-bit vector. It is scaled in riscv_sched_adjust_cost +;; for larger vectors. +(define_insn_reservation "generic_ooo_vec_ordered_reduction" 10 + (and (eq_attr "tune" "generic_ooo") + (eq_attr "type" "vfredo,vfwredo")) + "generic_ooo_vxu_issue,generic_ooo_vxu_multicycle*3") + +;; Vector integer division, assume not pipelined. +(define_insn_reservation "generic_ooo_vec_idiv" 16 + (and (eq_attr "tune" "generic_ooo") + (eq_attr "type" "vidiv")) + "generic_ooo_vxu_issue,generic_ooo_vxu_multicycle*3") + +;; Vector float divisions and sqrt, assume not pipelined. +(define_insn_reservation "generic_ooo_vec_float_divsqrt" 16 + (and (eq_attr "tune" "generic_ooo") + (eq_attr "type" "vfdiv,vfsqrt")) + "generic_ooo_vxu_issue,generic_ooo_vxu_multicycle*3") + +;; Vector mask operations. +(define_insn_reservation "generic_ooo_vec_mask" 2 + (and (eq_attr "tune" "generic_ooo") + (eq_attr "type" "vmalu,vmpop,vmffs,vmsfs,vmiota,vmidx,vimovvx,vimovxv,\ + vfmovvf,vfmovfv")) + "generic_ooo_vxu_issue,generic_ooo_vxu_alu") + +;; Vector vsetvl. +(define_insn_reservation "generic_ooo_vec_vesetvl" 1 + (and (eq_attr "tune" "generic_ooo") + (eq_attr "type" "vsetvl,vsetvl_pre")) + "generic_ooo_vxu_issue") + +;; Vector rounding mode setters, assume pipeline barrier. +(define_insn_reservation "generic_ooo_vec_setrm" 20 + (and (eq_attr "tune" "generic_ooo") + (eq_attr "type" "wrvxrm,wrfrm")) + "generic_ooo_vxu_issue,generic_ooo_vxu_issue*3") + +;; Vector read vlen/vlenb. +(define_insn_reservation "generic_ooo_vec_readlen" 4 + (and (eq_attr "tune" "generic_ooo") + (eq_attr "type" "rdvlenb,rdvl")) + "generic_ooo_vxu_issue,generic_ooo_vxu_issue") + ;; Transfer from/to coprocessor. Assume not pipelined. (define_insn_reservation "generic_ooo_xfer" 4 (and (eq_attr "tune" "generic_ooo") diff --git a/gcc/config/riscv/generic-vector-ooo.md b/gcc/config/riscv/generic-vector-ooo.md deleted file mode 100644 index 96cb1a0..0000000 --- a/gcc/config/riscv/generic-vector-ooo.md +++ /dev/null @@ -1,143 +0,0 @@ -;; Copyright (C) 2024-2024 Free Software Foundation, Inc. - -;; This file is part of GCC. - -;; GCC 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, or (at your -;; option) any later version. - -;; GCC 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 -;; . -;; Vector load/store - -(define_automaton "vector_ooo") - -;; Separate issue queue for vector instructions. -(define_cpu_unit "vxu_ooo_issue" "vector_ooo") - -;; Vector execution unit. -(define_cpu_unit "vxu_ooo_alu" "vector_ooo") - -;; Vector subunit that does mult/div/sqrt. -(define_cpu_unit "vxu_ooo_multicycle" "vector_ooo") - -(define_insn_reservation "vec_load" 6 - (eq_attr "type" "vlde,vldm,vlds,vldux,vldox,vldff,vldr") - "vxu_ooo_issue,vxu_ooo_alu") - -(define_insn_reservation "vec_store" 6 - (eq_attr "type" "vste,vstm,vsts,vstux,vstox,vstr") - "vxu_ooo_issue,vxu_ooo_alu") - -;; Vector segment loads/stores. -(define_insn_reservation "vec_loadstore_seg" 10 - (eq_attr "type" "vlsegde,vlsegds,vlsegdux,vlsegdox,vlsegdff,\ - vssegte,vssegts,vssegtux,vssegtox") - "vxu_ooo_issue,vxu_ooo_alu") - -;; Regular vector operations and integer comparisons. -(define_insn_reservation "vec_alu" 3 - (eq_attr "type" "vialu,viwalu,vext,vicalu,vshift,vnshift,viminmax,vicmp,\ - vimov,vsalu,vaalu,vsshift,vnclip,vmov,vfmov,vector,\ - vandn,vbrev,vbrev8,vrev8,vclz,vctz,vrol,vror,vwsll") - "vxu_ooo_issue,vxu_ooo_alu") - -;; Vector float comparison, conversion etc. -(define_insn_reservation "vec_fcmp" 3 - (eq_attr "type" "vfrecp,vfminmax,vfcmp,vfsgnj,vfclass,vfcvtitof,\ - vfcvtftoi,vfwcvtitof,vfwcvtftoi,vfwcvtftof,vfncvtitof,\ - vfncvtftoi,vfncvtftof") - "vxu_ooo_issue,vxu_ooo_alu") - -;; Vector integer multiplication. -(define_insn_reservation "vec_imul" 4 - (eq_attr "type" "vimul,viwmul,vimuladd,viwmuladd,vsmul,vclmul,vclmulh,\ - vghsh,vgmul") - "vxu_ooo_issue,vxu_ooo_alu") - -;; Vector float addition. -(define_insn_reservation "vec_fadd" 4 - (eq_attr "type" "vfalu,vfwalu") - "vxu_ooo_issue,vxu_ooo_alu") - -;; Vector float multiplication and FMA. -(define_insn_reservation "vec_fmul" 6 - (eq_attr "type" "vfmul,vfwmul,vfmuladd,vfwmuladd") - "vxu_ooo_issue,vxu_ooo_alu") - -;; Vector crypto, assumed to be a generic operation for now. -(define_insn_reservation "vec_crypto" 4 - (eq_attr "type" "crypto") - "vxu_ooo_issue,vxu_ooo_alu") - -;; Vector crypto, AES -(define_insn_reservation "vec_crypto_aes" 4 - (eq_attr "type" "vaesef,vaesem,vaesdf,vaesdm,vaeskf1,vaeskf2,vaesz") - "vxu_ooo_issue,vxu_ooo_alu") - -;; Vector crypto, sha -(define_insn_reservation "vec_crypto_sha" 4 - (eq_attr "type" "vsha2ms,vsha2ch,vsha2cl") - "vxu_ooo_issue,vxu_ooo_alu") - -;; Vector crypto, SM3/4 -(define_insn_reservation "vec_crypto_sm" 4 - (eq_attr "type" "vsm4k,vsm4r,vsm3me,vsm3c") - "vxu_ooo_issue,vxu_ooo_alu") - -;; Vector permute. -(define_insn_reservation "vec_perm" 3 - (eq_attr "type" "vimerge,vfmerge,vslideup,vslidedown,vislide1up,\ - vislide1down,vfslide1up,vfslide1down,vgather,vcompress") - "vxu_ooo_issue,vxu_ooo_alu") - -;; Vector reduction. -(define_insn_reservation "vec_reduction" 8 - (eq_attr "type" "vired,viwred,vfredu,vfwredu") - "vxu_ooo_issue,vxu_ooo_multicycle") - -;; Vector ordered reduction, assume the latency number is for -;; a 128-bit vector. It is scaled in riscv_sched_adjust_cost -;; for larger vectors. -(define_insn_reservation "vec_ordered_reduction" 10 - (eq_attr "type" "vfredo,vfwredo") - "vxu_ooo_issue,vxu_ooo_multicycle*3") - -;; Vector integer division, assume not pipelined. -(define_insn_reservation "vec_idiv" 16 - (eq_attr "type" "vidiv") - "vxu_ooo_issue,vxu_ooo_multicycle*3") - -;; Vector float divisions and sqrt, assume not pipelined. -(define_insn_reservation "vec_float_divsqrt" 16 - (eq_attr "type" "vfdiv,vfsqrt") - "vxu_ooo_issue,vxu_ooo_multicycle*3") - -;; Vector mask operations. -(define_insn_reservation "vec_mask" 2 - (eq_attr "type" "vmalu,vmpop,vmffs,vmsfs,vmiota,vmidx,vimovvx,vimovxv,\ - vfmovvf,vfmovfv") - "vxu_ooo_issue,vxu_ooo_alu") - -;; Vector vsetvl. -(define_insn_reservation "vec_vesetvl" 1 - (eq_attr "type" "vsetvl,vsetvl_pre") - "vxu_ooo_issue") - -;; Vector rounding mode setters, assume pipeline barrier. -(define_insn_reservation "vec_setrm" 20 - (eq_attr "type" "wrvxrm,wrfrm") - "vxu_ooo_issue,vxu_ooo_issue*3") - -;; Vector read vlen/vlenb. -(define_insn_reservation "vec_readlen" 4 - (eq_attr "type" "rdvlenb,rdvl") - "vxu_ooo_issue,vxu_ooo_issue") - diff --git a/gcc/config/riscv/riscv.md b/gcc/config/riscv/riscv.md index 53d11a8..c5be1b2 100644 --- a/gcc/config/riscv/riscv.md +++ b/gcc/config/riscv/riscv.md @@ -3847,7 +3847,6 @@ (include "generic.md") (include "sifive-7.md") (include "thead.md") -(include "generic-vector-ooo.md") (include "generic-ooo.md") (include "vector.md") (include "vector-crypto.md") -- cgit v1.1 From fd4829dde46b9836c40c9ab27bde98521e692119 Mon Sep 17 00:00:00 2001 From: Edwin Lu Date: Wed, 31 Jan 2024 21:50:58 -0800 Subject: Revert "RISC-V: Add non-vector types to dfa pipelines" This reverts commit 26c34b809cd1a6249027730a8b52bbf6a1c0f4a8. --- gcc/config/riscv/generic-ooo.md | 15 +------ gcc/config/riscv/generic.md | 20 ++------- gcc/config/riscv/riscv.md | 18 ++++---- gcc/config/riscv/sifive-7.md | 17 +------- gcc/config/riscv/vector.md | 2 +- gcc/config/riscv/zc.md | 96 ++++++++++++++++++++--------------------- 6 files changed, 66 insertions(+), 102 deletions(-) (limited to 'gcc') diff --git a/gcc/config/riscv/generic-ooo.md b/gcc/config/riscv/generic-ooo.md index ef8cb96..421a7bb9 100644 --- a/gcc/config/riscv/generic-ooo.md +++ b/gcc/config/riscv/generic-ooo.md @@ -115,20 +115,9 @@ (define_insn_reservation "generic_ooo_alu" 1 (and (eq_attr "tune" "generic_ooo") (eq_attr "type" "unknown,const,arith,shift,slt,multi,auipc,nop,logical,\ - move,bitmanip,rotate,min,max,minu,maxu,clz,ctz,atomic,\ - condmove,mvpair,zicond")) + move,bitmanip,min,max,minu,maxu,clz,ctz")) "generic_ooo_issue,generic_ooo_ixu_alu") -(define_insn_reservation "generic_ooo_sfb_alu" 2 - (and (eq_attr "tune" "generic_ooo") - (eq_attr "type" "sfb_alu")) - "generic_ooo_issue,generic_ooo_ixu_alu") - -;; Branch instructions -(define_insn_reservation "generic_ooo_branch" 1 - (and (eq_attr "tune" "generic_ooo") - (eq_attr "type" "branch,jump,call,jalr,ret,trap")) - "generic_ooo_issue,generic_ooo_ixu_alu") ;; Float move, convert and compare. (define_insn_reservation "generic_ooo_float_move" 3 @@ -195,7 +184,7 @@ (define_insn_reservation "generic_ooo_vec_alu" 3 (and (eq_attr "tune" "generic_ooo") (eq_attr "type" "vialu,viwalu,vext,vicalu,vshift,vnshift,viminmax,vicmp,\ - vimov,vsalu,vaalu,vsshift,vnclip,vmov,vfmov,vector")) + vimov,vsalu,vaalu,vsshift,vnclip,vmov,vfmov")) "generic_ooo_vxu_issue,generic_ooo_vxu_alu") ;; Vector float comparison, conversion etc. diff --git a/gcc/config/riscv/generic.md b/gcc/config/riscv/generic.md index 45986cf..b99ae34 100644 --- a/gcc/config/riscv/generic.md +++ b/gcc/config/riscv/generic.md @@ -27,9 +27,7 @@ (define_insn_reservation "generic_alu" 1 (and (eq_attr "tune" "generic") - (eq_attr "type" "unknown,const,arith,shift,slt,multi,auipc,nop,logical,\ - move,bitmanip,min,max,minu,maxu,clz,ctz,rotate,atomic,\ - condmove,crypto,mvpair,zicond")) + (eq_attr "type" "unknown,const,arith,shift,slt,multi,auipc,nop,logical,move,bitmanip,min,max,minu,maxu,clz,ctz,cpop")) "alu") (define_insn_reservation "generic_load" 3 @@ -49,17 +47,12 @@ (define_insn_reservation "generic_branch" 1 (and (eq_attr "tune" "generic") - (eq_attr "type" "branch,jump,call,jalr,ret,trap")) - "alu") - -(define_insn_reservation "generic_sfb_alu" 2 - (and (eq_attr "tune" "generic") - (eq_attr "type" "sfb_alu")) + (eq_attr "type" "branch,jump,call,jalr")) "alu") (define_insn_reservation "generic_imul" 10 (and (eq_attr "tune" "generic") - (eq_attr "type" "imul,clmul,cpop")) + (eq_attr "type" "imul,clmul")) "imuldiv*10") (define_insn_reservation "generic_idivsi" 34 @@ -74,12 +67,6 @@ (eq_attr "mode" "DI"))) "imuldiv*66") -(define_insn_reservation "generic_fmul_half" 5 - (and (eq_attr "tune" "generic") - (and (eq_attr "type" "fadd,fmul,fmadd") - (eq_attr "mode" "HF"))) - "alu") - (define_insn_reservation "generic_fmul_single" 5 (and (eq_attr "tune" "generic") (and (eq_attr "type" "fadd,fmul,fmadd") @@ -101,4 +88,3 @@ (and (eq_attr "tune" "generic") (eq_attr "type" "fsqrt")) "fdivsqrt*25") - diff --git a/gcc/config/riscv/riscv.md b/gcc/config/riscv/riscv.md index c5be1b2..b320ad0 100644 --- a/gcc/config/riscv/riscv.md +++ b/gcc/config/riscv/riscv.md @@ -326,7 +326,9 @@ ;; rotate rotation instructions ;; atomic atomic instructions ;; condmove conditional moves +;; cbo cache block instructions ;; crypto cryptography instructions +;; pushpop zc push and pop instructions ;; mvpair zc move pair instructions ;; zicond zicond instructions ;; Classification of RVV instructions which will be added to each RVV .md pattern and used by scheduler. @@ -466,8 +468,8 @@ mtc,mfc,const,arith,logical,shift,slt,imul,idiv,move,fmove,fadd,fmul, fmadd,fdiv,fcmp,fcvt,fsqrt,multi,auipc,sfb_alu,nop,trap,ghost,bitmanip, rotate,clmul,min,max,minu,maxu,clz,ctz,cpop, - atomic,condmove,crypto,mvpair,zicond,rdvlenb,rdvl,wrvxrm,wrfrm, - vsetvl,vsetvl_pre,vlde,vste,vldm,vstm,vlds,vsts, + atomic,condmove,cbo,crypto,pushpop,mvpair,zicond,rdvlenb,rdvl,wrvxrm,wrfrm, + rdfrm,vsetvl,vsetvl_pre,vlde,vste,vldm,vstm,vlds,vsts, vldux,vldox,vstux,vstox,vldff,vldr,vstr, vlsegde,vssegte,vlsegds,vssegts,vlsegdux,vlsegdox,vssegtux,vssegtox,vlsegdff, vialu,viwalu,vext,vicalu,vshift,vnshift,vicmp,viminmax, @@ -3671,7 +3673,7 @@ UNSPECV_CLEAN)] "TARGET_ZICBOM" "cbo.clean\t%a0" - [(set_attr "type" "store")] + [(set_attr "type" "cbo")] ) (define_insn "riscv_flush_" @@ -3679,7 +3681,7 @@ UNSPECV_FLUSH)] "TARGET_ZICBOM" "cbo.flush\t%a0" - [(set_attr "type" "store")] + [(set_attr "type" "cbo")] ) (define_insn "riscv_inval_" @@ -3687,7 +3689,7 @@ UNSPECV_INVAL)] "TARGET_ZICBOM" "cbo.inval\t%a0" - [(set_attr "type" "store")] + [(set_attr "type" "cbo")] ) (define_insn "riscv_zero_" @@ -3695,7 +3697,7 @@ UNSPECV_ZERO)] "TARGET_ZICBOZ" "cbo.zero\t%a0" - [(set_attr "type" "store")] + [(set_attr "type" "cbo")] ) (define_insn "prefetch" @@ -3711,7 +3713,7 @@ default: gcc_unreachable (); } } - [(set_attr "type" "store")]) + [(set_attr "type" "cbo")]) (define_insn "riscv_prefetchi_" [(unspec_volatile:X [(match_operand:X 0 "address_operand" "r") @@ -3719,7 +3721,7 @@ UNSPECV_PREI)] "TARGET_ZICBOP" "prefetch.i\t%a0" - [(set_attr "type" "store")]) + [(set_attr "type" "cbo")]) (define_expand "extv" [(set (match_operand:GPR 0 "register_operand" "=r") diff --git a/gcc/config/riscv/sifive-7.md b/gcc/config/riscv/sifive-7.md index 52904f5..a63394c 100644 --- a/gcc/config/riscv/sifive-7.md +++ b/gcc/config/riscv/sifive-7.md @@ -34,7 +34,7 @@ (define_insn_reservation "sifive_7_branch" 1 (and (eq_attr "tune" "sifive_7") - (eq_attr "type" "branch,ret,trap")) + (eq_attr "type" "branch")) "sifive_7_B") (define_insn_reservation "sifive_7_sfb_alu" 2 @@ -59,8 +59,7 @@ (define_insn_reservation "sifive_7_alu" 2 (and (eq_attr "tune" "sifive_7") - (eq_attr "type" "unknown,arith,shift,slt,multi,logical,move,bitmanip,\ - rotate,min,max,minu,maxu,clz,ctz,atomic,condmove,crypto,mvpair,zicond")) + (eq_attr "type" "unknown,arith,shift,slt,multi,logical,move")) "sifive_7_A|sifive_7_B") (define_insn_reservation "sifive_7_load_immediate" 1 @@ -68,12 +67,6 @@ (eq_attr "type" "nop,const,auipc")) "sifive_7_A|sifive_7_B") -(define_insn_reservation "sifive_7_hfma" 5 - (and (eq_attr "tune" "sifive_7") - (and (eq_attr "type" "fadd,fmul,fmadd") - (eq_attr "mode" "HF"))) - "sifive_7_B") - (define_insn_reservation "sifive_7_sfma" 5 (and (eq_attr "tune" "sifive_7") (and (eq_attr "type" "fadd,fmul,fmadd") @@ -113,12 +106,6 @@ (eq_attr "type" "mfc")) "sifive_7_A") -;; Popcount and clmul. -(define_insn_reservation "sifive_7_popcount" 2 - (and (eq_attr "tune" "sifive_7") - (eq_attr "type" "cpop,clmul")) - "sifive_7_A") - (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") diff --git a/gcc/config/riscv/vector.md b/gcc/config/riscv/vector.md index f89f9c2..ab6e099 100644 --- a/gcc/config/riscv/vector.md +++ b/gcc/config/riscv/vector.md @@ -1054,7 +1054,7 @@ (reg:SI FRM_REGNUM))] "TARGET_VECTOR" "frrm\t%0" - [(set_attr "type" "fmove") + [(set_attr "type" "rdfrm") (set_attr "mode" "SI")] ) diff --git a/gcc/config/riscv/zc.md b/gcc/config/riscv/zc.md index 462ab37..216232c 100644 --- a/gcc/config/riscv/zc.md +++ b/gcc/config/riscv/zc.md @@ -27,7 +27,7 @@ (const_int ))))] "TARGET_ZCMP" "cm.pop {ra}, %0" -[(set_attr "type" "load")]) +[(set_attr "type" "pushpop")]) (define_insn "@gpr_multi_pop_up_to_s0_" [(set (reg:X SP_REGNUM) @@ -41,7 +41,7 @@ (const_int ))))] "TARGET_ZCMP" "cm.pop {ra, s0}, %0" -[(set_attr "type" "load")]) +[(set_attr "type" "pushpop")]) (define_insn "@gpr_multi_pop_up_to_s1_" [(set (reg:X SP_REGNUM) @@ -58,7 +58,7 @@ (const_int ))))] "TARGET_ZCMP" "cm.pop {ra, s0-s1}, %0" -[(set_attr "type" "load")]) +[(set_attr "type" "pushpop")]) (define_insn "@gpr_multi_pop_up_to_s2_" [(set (reg:X SP_REGNUM) @@ -78,7 +78,7 @@ (const_int ))))] "TARGET_ZCMP" "cm.pop {ra, s0-s2}, %0" -[(set_attr "type" "load")]) +[(set_attr "type" "pushpop")]) (define_insn "@gpr_multi_pop_up_to_s3_" [(set (reg:X SP_REGNUM) @@ -101,7 +101,7 @@ (const_int ))))] "TARGET_ZCMP" "cm.pop {ra, s0-s3}, %0" -[(set_attr "type" "load")]) +[(set_attr "type" "pushpop")]) (define_insn "@gpr_multi_pop_up_to_s4_" [(set (reg:X SP_REGNUM) @@ -127,7 +127,7 @@ (const_int ))))] "TARGET_ZCMP" "cm.pop {ra, s0-s4}, %0" -[(set_attr "type" "load")]) +[(set_attr "type" "pushpop")]) (define_insn "@gpr_multi_pop_up_to_s5_" [(set (reg:X SP_REGNUM) @@ -156,7 +156,7 @@ (const_int ))))] "TARGET_ZCMP" "cm.pop {ra, s0-s5}, %0" -[(set_attr "type" "load")]) +[(set_attr "type" "pushpop")]) (define_insn "@gpr_multi_pop_up_to_s6_" [(set (reg:X SP_REGNUM) @@ -188,7 +188,7 @@ (const_int ))))] "TARGET_ZCMP" "cm.pop {ra, s0-s6}, %0" -[(set_attr "type" "load")]) +[(set_attr "type" "pushpop")]) (define_insn "@gpr_multi_pop_up_to_s7_" [(set (reg:X SP_REGNUM) @@ -223,7 +223,7 @@ (const_int ))))] "TARGET_ZCMP" "cm.pop {ra, s0-s7}, %0" -[(set_attr "type" "load")]) +[(set_attr "type" "pushpop")]) (define_insn "@gpr_multi_pop_up_to_s8_" [(set (reg:X SP_REGNUM) @@ -261,7 +261,7 @@ (const_int ))))] "TARGET_ZCMP" "cm.pop {ra, s0-s8}, %0" -[(set_attr "type" "load")]) +[(set_attr "type" "pushpop")]) (define_insn "@gpr_multi_pop_up_to_s9_" [(set (reg:X SP_REGNUM) @@ -302,7 +302,7 @@ (const_int ))))] "TARGET_ZCMP" "cm.pop {ra, s0-s9}, %0" -[(set_attr "type" "load")]) +[(set_attr "type" "pushpop")]) (define_insn "@gpr_multi_pop_up_to_s11_" [(set (reg:X SP_REGNUM) @@ -349,7 +349,7 @@ (const_int ))))] "TARGET_ZCMP" "cm.pop {ra, s0-s11}, %0" -[(set_attr "type" "load")]) +[(set_attr "type" "pushpop")]) (define_insn "@gpr_multi_popret_up_to_ra_" [(set (reg:X SP_REGNUM) @@ -362,7 +362,7 @@ (use (reg:SI RETURN_ADDR_REGNUM))] "TARGET_ZCMP" "cm.popret {ra}, %0" -[(set_attr "type" "load")]) +[(set_attr "type" "pushpop")]) (define_insn "@gpr_multi_popret_up_to_s0_" [(set (reg:X SP_REGNUM) @@ -378,7 +378,7 @@ (use (reg:SI RETURN_ADDR_REGNUM))] "TARGET_ZCMP" "cm.popret {ra, s0}, %0" -[(set_attr "type" "load")]) +[(set_attr "type" "pushpop")]) (define_insn "@gpr_multi_popret_up_to_s1_" [(set (reg:X SP_REGNUM) @@ -397,7 +397,7 @@ (use (reg:SI RETURN_ADDR_REGNUM))] "TARGET_ZCMP" "cm.popret {ra, s0-s1}, %0" -[(set_attr "type" "load")]) +[(set_attr "type" "pushpop")]) (define_insn "@gpr_multi_popret_up_to_s2_" [(set (reg:X SP_REGNUM) @@ -419,7 +419,7 @@ (use (reg:SI RETURN_ADDR_REGNUM))] "TARGET_ZCMP" "cm.popret {ra, s0-s2}, %0" -[(set_attr "type" "load")]) +[(set_attr "type" "pushpop")]) (define_insn "@gpr_multi_popret_up_to_s3_" [(set (reg:X SP_REGNUM) @@ -444,7 +444,7 @@ (use (reg:SI RETURN_ADDR_REGNUM))] "TARGET_ZCMP" "cm.popret {ra, s0-s3}, %0" -[(set_attr "type" "load")]) +[(set_attr "type" "pushpop")]) (define_insn "@gpr_multi_popret_up_to_s4_" [(set (reg:X SP_REGNUM) @@ -472,7 +472,7 @@ (use (reg:SI RETURN_ADDR_REGNUM))] "TARGET_ZCMP" "cm.popret {ra, s0-s4}, %0" -[(set_attr "type" "load")]) +[(set_attr "type" "pushpop")]) (define_insn "@gpr_multi_popret_up_to_s5_" [(set (reg:X SP_REGNUM) @@ -503,7 +503,7 @@ (use (reg:SI RETURN_ADDR_REGNUM))] "TARGET_ZCMP" "cm.popret {ra, s0-s5}, %0" -[(set_attr "type" "load")]) +[(set_attr "type" "pushpop")]) (define_insn "@gpr_multi_popret_up_to_s6_" [(set (reg:X SP_REGNUM) @@ -537,7 +537,7 @@ (use (reg:SI RETURN_ADDR_REGNUM))] "TARGET_ZCMP" "cm.popret {ra, s0-s6}, %0" -[(set_attr "type" "load")]) +[(set_attr "type" "pushpop")]) (define_insn "@gpr_multi_popret_up_to_s7_" [(set (reg:X SP_REGNUM) @@ -574,7 +574,7 @@ (use (reg:SI RETURN_ADDR_REGNUM))] "TARGET_ZCMP" "cm.popret {ra, s0-s7}, %0" -[(set_attr "type" "load")]) +[(set_attr "type" "pushpop")]) (define_insn "@gpr_multi_popret_up_to_s8_" [(set (reg:X SP_REGNUM) @@ -614,7 +614,7 @@ (use (reg:SI RETURN_ADDR_REGNUM))] "TARGET_ZCMP" "cm.popret {ra, s0-s8}, %0" -[(set_attr "type" "load")]) +[(set_attr "type" "pushpop")]) (define_insn "@gpr_multi_popret_up_to_s9_" [(set (reg:X SP_REGNUM) @@ -657,7 +657,7 @@ (use (reg:SI RETURN_ADDR_REGNUM))] "TARGET_ZCMP" "cm.popret {ra, s0-s9}, %0" -[(set_attr "type" "load")]) +[(set_attr "type" "pushpop")]) (define_insn "@gpr_multi_popret_up_to_s11_" [(set (reg:X SP_REGNUM) @@ -706,7 +706,7 @@ (use (reg:SI RETURN_ADDR_REGNUM))] "TARGET_ZCMP" "cm.popret {ra, s0-s11}, %0" -[(set_attr "type" "load")]) +[(set_attr "type" "pushpop")]) (define_insn "@gpr_multi_popretz_up_to_ra_" [(set (reg:X SP_REGNUM) @@ -722,7 +722,7 @@ (use (reg:SI RETURN_ADDR_REGNUM))] "TARGET_ZCMP" "cm.popretz {ra}, %0" -[(set_attr "type" "load")]) +[(set_attr "type" "pushpop")]) (define_insn "@gpr_multi_popretz_up_to_s0_" [(set (reg:X SP_REGNUM) @@ -741,7 +741,7 @@ (use (reg:SI RETURN_ADDR_REGNUM))] "TARGET_ZCMP" "cm.popretz {ra, s0}, %0" -[(set_attr "type" "load")]) +[(set_attr "type" "pushpop")]) (define_insn "@gpr_multi_popretz_up_to_s1_" [(set (reg:X SP_REGNUM) @@ -763,7 +763,7 @@ (use (reg:SI RETURN_ADDR_REGNUM))] "TARGET_ZCMP" "cm.popretz {ra, s0-s1}, %0" -[(set_attr "type" "load")]) +[(set_attr "type" "pushpop")]) (define_insn "@gpr_multi_popretz_up_to_s2_" [(set (reg:X SP_REGNUM) @@ -788,7 +788,7 @@ (use (reg:SI RETURN_ADDR_REGNUM))] "TARGET_ZCMP" "cm.popretz {ra, s0-s2}, %0" -[(set_attr "type" "load")]) +[(set_attr "type" "pushpop")]) (define_insn "@gpr_multi_popretz_up_to_s3_" [(set (reg:X SP_REGNUM) @@ -816,7 +816,7 @@ (use (reg:SI RETURN_ADDR_REGNUM))] "TARGET_ZCMP" "cm.popretz {ra, s0-s3}, %0" -[(set_attr "type" "load")]) +[(set_attr "type" "pushpop")]) (define_insn "@gpr_multi_popretz_up_to_s4_" [(set (reg:X SP_REGNUM) @@ -847,7 +847,7 @@ (use (reg:SI RETURN_ADDR_REGNUM))] "TARGET_ZCMP" "cm.popretz {ra, s0-s4}, %0" -[(set_attr "type" "load")]) +[(set_attr "type" "pushpop")]) (define_insn "@gpr_multi_popretz_up_to_s5_" [(set (reg:X SP_REGNUM) @@ -881,7 +881,7 @@ (use (reg:SI RETURN_ADDR_REGNUM))] "TARGET_ZCMP" "cm.popretz {ra, s0-s5}, %0" -[(set_attr "type" "load")]) +[(set_attr "type" "pushpop")]) (define_insn "@gpr_multi_popretz_up_to_s6_" [(set (reg:X SP_REGNUM) @@ -918,7 +918,7 @@ (use (reg:SI RETURN_ADDR_REGNUM))] "TARGET_ZCMP" "cm.popretz {ra, s0-s6}, %0" -[(set_attr "type" "load")]) +[(set_attr "type" "pushpop")]) (define_insn "@gpr_multi_popretz_up_to_s7_" [(set (reg:X SP_REGNUM) @@ -958,7 +958,7 @@ (use (reg:SI RETURN_ADDR_REGNUM))] "TARGET_ZCMP" "cm.popretz {ra, s0-s7}, %0" -[(set_attr "type" "load")]) +[(set_attr "type" "pushpop")]) (define_insn "@gpr_multi_popretz_up_to_s8_" [(set (reg:X SP_REGNUM) @@ -1001,7 +1001,7 @@ (use (reg:SI RETURN_ADDR_REGNUM))] "TARGET_ZCMP" "cm.popretz {ra, s0-s8}, %0" -[(set_attr "type" "load")]) +[(set_attr "type" "pushpop")]) (define_insn "@gpr_multi_popretz_up_to_s9_" [(set (reg:X SP_REGNUM) @@ -1047,7 +1047,7 @@ (use (reg:SI RETURN_ADDR_REGNUM))] "TARGET_ZCMP" "cm.popretz {ra, s0-s9}, %0" -[(set_attr "type" "load")]) +[(set_attr "type" "pushpop")]) (define_insn "@gpr_multi_popretz_up_to_s11_" [(set (reg:X SP_REGNUM) @@ -1099,7 +1099,7 @@ (use (reg:SI RETURN_ADDR_REGNUM))] "TARGET_ZCMP" "cm.popretz {ra, s0-s11}, %0" -[(set_attr "type" "load")]) +[(set_attr "type" "pushpop")]) (define_insn "@gpr_multi_push_up_to_ra_" [(set (mem:X (plus:X (reg:X SP_REGNUM) @@ -1110,7 +1110,7 @@ (match_operand 0 "stack_push_up_to_ra_operand" "I")))] "TARGET_ZCMP" "cm.push {ra}, %0" -[(set_attr "type" "store")]) +[(set_attr "type" "pushpop")]) (define_insn "@gpr_multi_push_up_to_s0_" [(set (mem:X (plus:X (reg:X SP_REGNUM) @@ -1124,7 +1124,7 @@ (match_operand 0 "stack_push_up_to_s0_operand" "I")))] "TARGET_ZCMP" "cm.push {ra, s0}, %0" -[(set_attr "type" "store")]) +[(set_attr "type" "pushpop")]) (define_insn "@gpr_multi_push_up_to_s1_" [(set (mem:X (plus:X (reg:X SP_REGNUM) @@ -1141,7 +1141,7 @@ (match_operand 0 "stack_push_up_to_s1_operand" "I")))] "TARGET_ZCMP" "cm.push {ra, s0-s1}, %0" -[(set_attr "type" "store")]) +[(set_attr "type" "pushpop")]) (define_insn "@gpr_multi_push_up_to_s2_" [(set (mem:X (plus:X (reg:X SP_REGNUM) @@ -1161,7 +1161,7 @@ (match_operand 0 "stack_push_up_to_s2_operand" "I")))] "TARGET_ZCMP" "cm.push {ra, s0-s2}, %0" -[(set_attr "type" "store")]) +[(set_attr "type" "pushpop")]) (define_insn "@gpr_multi_push_up_to_s3_" [(set (mem:X (plus:X (reg:X SP_REGNUM) @@ -1184,7 +1184,7 @@ (match_operand 0 "stack_push_up_to_s3_operand" "I")))] "TARGET_ZCMP" "cm.push {ra, s0-s3}, %0" -[(set_attr "type" "store")]) +[(set_attr "type" "pushpop")]) (define_insn "@gpr_multi_push_up_to_s4_" [(set (mem:X (plus:X (reg:X SP_REGNUM) @@ -1210,7 +1210,7 @@ (match_operand 0 "stack_push_up_to_s4_operand" "I")))] "TARGET_ZCMP" "cm.push {ra, s0-s4}, %0" -[(set_attr "type" "store")]) +[(set_attr "type" "pushpop")]) (define_insn "@gpr_multi_push_up_to_s5_" [(set (mem:X (plus:X (reg:X SP_REGNUM) @@ -1239,7 +1239,7 @@ (match_operand 0 "stack_push_up_to_s5_operand" "I")))] "TARGET_ZCMP" "cm.push {ra, s0-s5}, %0" -[(set_attr "type" "store")]) +[(set_attr "type" "pushpop")]) (define_insn "@gpr_multi_push_up_to_s6_" [(set (mem:X (plus:X (reg:X SP_REGNUM) @@ -1271,7 +1271,7 @@ (match_operand 0 "stack_push_up_to_s6_operand" "I")))] "TARGET_ZCMP" "cm.push {ra, s0-s6}, %0" -[(set_attr "type" "store")]) +[(set_attr "type" "pushpop")]) (define_insn "@gpr_multi_push_up_to_s7_" [(set (mem:X (plus:X (reg:X SP_REGNUM) @@ -1306,7 +1306,7 @@ (match_operand 0 "stack_push_up_to_s7_operand" "I")))] "TARGET_ZCMP" "cm.push {ra, s0-s7}, %0" -[(set_attr "type" "store")]) +[(set_attr "type" "pushpop")]) (define_insn "@gpr_multi_push_up_to_s8_" [(set (mem:X (plus:X (reg:X SP_REGNUM) @@ -1344,7 +1344,7 @@ (match_operand 0 "stack_push_up_to_s8_operand" "I")))] "TARGET_ZCMP" "cm.push {ra, s0-s8}, %0" -[(set_attr "type" "store")]) +[(set_attr "type" "pushpop")]) (define_insn "@gpr_multi_push_up_to_s9_" [(set (mem:X (plus:X (reg:X SP_REGNUM) @@ -1385,7 +1385,7 @@ (match_operand 0 "stack_push_up_to_s9_operand" "I")))] "TARGET_ZCMP" "cm.push {ra, s0-s9}, %0" -[(set_attr "type" "store")]) +[(set_attr "type" "pushpop")]) (define_insn "@gpr_multi_push_up_to_s11_" [(set (mem:X (plus:X (reg:X SP_REGNUM) @@ -1432,7 +1432,7 @@ (match_operand 0 "stack_push_up_to_s11_operand" "I")))] "TARGET_ZCMP" "cm.push {ra, s0-s11}, %0" -[(set_attr "type" "store")]) +[(set_attr "type" "pushpop")]) ;; ZCMP mv (define_insn "*mva01s" -- cgit v1.1 From 2f14c0dbb789852947cb58fdf7d3162413f053fa Mon Sep 17 00:00:00 2001 From: Roger Sayle Date: Thu, 1 Feb 2024 06:10:42 +0000 Subject: PR target/113560: Enhance is_widening_mult_rhs_p. This patch resolves PR113560, a code quality regression from GCC12 affecting x86_64, by enhancing the middle-end's tree-ssa-math-opts.cc to recognize more instances of widening multiplications. The widening multiplication perception code identifies cases like: _1 = (unsigned __int128) x; __res = _1 * 100; but in the reported test case, the original input looks like: _1 = (unsigned long long) x; _2 = (unsigned __int128) _1; __res = _2 * 100; which gets optimized by constant folding during tree-ssa to: _2 = x & 18446744073709551615; // x & 0xffffffffffffffff __res = _2 * 100; where the BIT_AND_EXPR hides (has consumed) the extension operation. This reveals the more general deficiency (missed optimization opportunity) in widening multiplication perception that additionally both __int128 foo(__int128 x, __int128 y) { return (x & 1000) * (y & 1000) } and unsigned __int128 bar(unsigned __int128 x, unsigned __int128) { return (x >> 80) * (y >> 80); } should be recognized as widening multiplications. Hence rather than test explicitly for BIT_AND_EXPR (as in the first version of this patch) the more general solution is to make use of range information, as provided by tree_non_zero_bits. As a demonstration of the observed improvements, function foo above currently with -O2 compiles on x86_64 to: foo: movq %rdi, %rsi movq %rdx, %r8 xorl %edi, %edi xorl %r9d, %r9d andl $1000, %esi andl $1000, %r8d movq %rdi, %rcx movq %r9, %rdx imulq %rsi, %rdx movq %rsi, %rax imulq %r8, %rcx addq %rdx, %rcx mulq %r8 addq %rdx, %rcx movq %rcx, %rdx ret with this patch, GCC recognizes the *w and instead generates: foo: movq %rdi, %rsi movq %rdx, %r8 andl $1000, %esi andl $1000, %r8d movq %rsi, %rax imulq %r8 ret which is perhaps easier to understand at the tree-level where __int128 foo (__int128 x, __int128 y) { __int128 _1; __int128 _2; __int128 _5; [local count: 1073741824]: _1 = x_3(D) & 1000; _2 = y_4(D) & 1000; _5 = _1 * _2; return _5; } gets transformed to: __int128 foo (__int128 x, __int128 y) { __int128 _1; __int128 _2; __int128 _5; signed long _7; signed long _8; [local count: 1073741824]: _1 = x_3(D) & 1000; _2 = y_4(D) & 1000; _7 = (signed long) _1; _8 = (signed long) _2; _5 = _7 w* _8; return _5; } 2023-02-01 Roger Sayle Richard Biener gcc/ChangeLog PR target/113560 * tree-ssa-math-opts.cc (is_widening_mult_rhs_p): Use range information via tree_non_zero_bits to check if this operand is suitably extended for a widening (or highpart) multiplication. (convert_mult_to_widen): Insert explicit casts if the RHS or LHS isn't already of the claimed type. gcc/testsuite/ChangeLog PR target/113560 * g++.target/i386/pr113560.C: New test case. * gcc.target/i386/pr113560.c: Likewise. * gcc.dg/pr87954.c: Update test case. --- gcc/testsuite/g++.target/i386/pr113560.C | 19 ++++++++++++ gcc/testsuite/gcc.dg/pr87954.c | 2 +- gcc/testsuite/gcc.target/i386/pr113560.c | 17 ++++++++++ gcc/tree-ssa-math-opts.cc | 53 ++++++++++++++++++++++++++++---- 4 files changed, 84 insertions(+), 7 deletions(-) create mode 100644 gcc/testsuite/g++.target/i386/pr113560.C create mode 100644 gcc/testsuite/gcc.target/i386/pr113560.c (limited to 'gcc') diff --git a/gcc/testsuite/g++.target/i386/pr113560.C b/gcc/testsuite/g++.target/i386/pr113560.C new file mode 100644 index 0000000..179b68f --- /dev/null +++ b/gcc/testsuite/g++.target/i386/pr113560.C @@ -0,0 +1,19 @@ +/* { dg-do compile { target { ! ia32 } } } */ +/* { dg-options "-Ofast -std=c++23 -march=znver4" } */ + +#include +auto f(char *buf, unsigned long long in) noexcept +{ + unsigned long long hi{}; + auto lo{_mulx_u64(in, 0x2af31dc462ull, &hi)}; + lo = _mulx_u64(lo, 100, &hi); + __builtin_memcpy(buf + 2, &hi, 2); + return buf + 10; +} + +/* { dg-final { scan-assembler-times "mulx" 1 } } */ +/* { dg-final { scan-assembler-times "mulq" 1 } } */ +/* { dg-final { scan-assembler-not "addq" } } */ +/* { dg-final { scan-assembler-not "adcq" } } */ +/* { dg-final { scan-assembler-not "salq" } } */ +/* { dg-final { scan-assembler-not "shldq" } } */ diff --git a/gcc/testsuite/gcc.dg/pr87954.c b/gcc/testsuite/gcc.dg/pr87954.c index 620657c..80d0543 100644 --- a/gcc/testsuite/gcc.dg/pr87954.c +++ b/gcc/testsuite/gcc.dg/pr87954.c @@ -18,4 +18,4 @@ imul(unsigned int flags) return type_dma + (is_rec * !is_dma) * KMALLOC_RECLAIM; } -/* { dg-final { scan-tree-dump-times { \* } 1 "optimized" } } */ +/* { dg-final { scan-tree-dump-times { \*w? |WIDEN_MULT_PLUS_EXPR} 1 "optimized" } } */ diff --git a/gcc/testsuite/gcc.target/i386/pr113560.c b/gcc/testsuite/gcc.target/i386/pr113560.c new file mode 100644 index 0000000..ac2e01a --- /dev/null +++ b/gcc/testsuite/gcc.target/i386/pr113560.c @@ -0,0 +1,17 @@ +/* { dg-do compile { target int128 } } */ +/* { dg-options "-O2" } */ + +unsigned __int128 foo(unsigned __int128 x, unsigned __int128 y) +{ + return (x & 1000) * (y & 1000); +} + +__int128 bar(__int128 x, __int128 y) +{ + return (x & 1000) * (y & 1000); +} + +/* { dg-final { scan-assembler-times "\tmulq" 1 } } */ +/* { dg-final { scan-assembler-times "\timulq" 1 } } */ +/* { dg-final { scan-assembler-not "addq" } } */ +/* { dg-final { scan-assembler-not "xorl" } } */ diff --git a/gcc/tree-ssa-math-opts.cc b/gcc/tree-ssa-math-opts.cc index 2db26e4..cffe757 100644 --- a/gcc/tree-ssa-math-opts.cc +++ b/gcc/tree-ssa-math-opts.cc @@ -2552,12 +2552,47 @@ is_widening_mult_rhs_p (tree type, tree rhs, tree *type_out, if (TREE_CODE (rhs) == SSA_NAME) { + /* Use tree_non_zero_bits to see if this operand is zero_extended + for unsigned widening multiplications or non-negative for + signed widening multiplications. */ + if (TREE_CODE (type) == INTEGER_TYPE + && (TYPE_PRECISION (type) & 1) == 0 + && int_mode_for_size (TYPE_PRECISION (type) / 2, 1).exists ()) + { + unsigned int prec = TYPE_PRECISION (type); + unsigned int hprec = prec / 2; + wide_int bits = wide_int::from (tree_nonzero_bits (rhs), prec, + TYPE_SIGN (TREE_TYPE (rhs))); + if (TYPE_UNSIGNED (type) + && wi::bit_and (bits, wi::mask (hprec, true, prec)) == 0) + { + *type_out = build_nonstandard_integer_type (hprec, true); + /* X & MODE_MASK can be simplified to (T)X. */ + stmt = SSA_NAME_DEF_STMT (rhs); + if (is_gimple_assign (stmt) + && gimple_assign_rhs_code (stmt) == BIT_AND_EXPR + && TREE_CODE (gimple_assign_rhs2 (stmt)) == INTEGER_CST + && wi::to_wide (gimple_assign_rhs2 (stmt)) + == wi::mask (hprec, false, prec)) + *new_rhs_out = gimple_assign_rhs1 (stmt); + else + *new_rhs_out = rhs; + return true; + } + else if (!TYPE_UNSIGNED (type) + && wi::bit_and (bits, wi::mask (hprec - 1, true, prec)) == 0) + { + *type_out = build_nonstandard_integer_type (hprec, false); + *new_rhs_out = rhs; + return true; + } + } + stmt = SSA_NAME_DEF_STMT (rhs); if (is_gimple_assign (stmt)) { - if (! widening_mult_conversion_strippable_p (type, stmt)) - rhs1 = rhs; - else + + if (widening_mult_conversion_strippable_p (type, stmt)) { rhs1 = gimple_assign_rhs1 (stmt); @@ -2568,6 +2603,8 @@ is_widening_mult_rhs_p (tree type, tree rhs, tree *type_out, return true; } } + else + rhs1 = rhs; } else rhs1 = rhs; @@ -2827,12 +2864,16 @@ convert_mult_to_widen (gimple *stmt, gimple_stmt_iterator *gsi) if (2 * actual_precision > TYPE_PRECISION (type)) return false; if (actual_precision != TYPE_PRECISION (type1) - || from_unsigned1 != TYPE_UNSIGNED (type1)) + || from_unsigned1 != TYPE_UNSIGNED (type1) + || (TREE_TYPE (rhs1) != type1 + && TREE_CODE (rhs1) != INTEGER_CST)) rhs1 = build_and_insert_cast (gsi, loc, build_nonstandard_integer_type (actual_precision, from_unsigned1), rhs1); if (actual_precision != TYPE_PRECISION (type2) - || from_unsigned2 != TYPE_UNSIGNED (type2)) + || from_unsigned2 != TYPE_UNSIGNED (type2) + || (TREE_TYPE (rhs2) != type2 + && TREE_CODE (rhs2) != INTEGER_CST)) rhs2 = build_and_insert_cast (gsi, loc, build_nonstandard_integer_type (actual_precision, from_unsigned2), rhs2); @@ -3046,7 +3087,7 @@ convert_plusminus_to_widen (gimple_stmt_iterator *gsi, gimple *stmt, || from_unsigned1 != TYPE_UNSIGNED (type1)) mult_rhs1 = build_and_insert_cast (gsi, loc, build_nonstandard_integer_type - (actual_precision, from_unsigned1), + (actual_precision, from_unsigned1), mult_rhs1); if (actual_precision != TYPE_PRECISION (type2) || from_unsigned2 != TYPE_UNSIGNED (type2)) -- cgit v1.1 From ceb242f5302027c44a7dca86c344863004b6fec4 Mon Sep 17 00:00:00 2001 From: Jakub Jelinek Date: Thu, 1 Feb 2024 09:16:57 +0100 Subject: gimple-low: Remove .ASAN_MARK calls on TREE_STATIC variables [PR113531] Since the r14-1500-g4d935f52b0d5c0 commit we promote an initializer_list backing array to static storage where appropriate, but this happens after we decided to add it to asan_poisoned_variables. As a result we add unpoison/poison for it to the gimple. But then sanopt removes the unpoison. So the second time we call the function and want to load from the array asan still considers it poisoned. The following patch fixes it by removing the .ASAN_MARK internal calls during gimple lowering if they refer to TREE_STATIC vars. 2024-02-01 Jakub Jelinek Jason Merrill PR c++/113531 * gimple-low.cc (lower_stmt): Remove .ASAN_MARK calls on variables which were promoted to TREE_STATIC. * g++.dg/asan/initlist1.C: New test. Co-authored-by: Jason Merrill --- gcc/gimple-low.cc | 15 +++++++++++++++ gcc/testsuite/g++.dg/asan/initlist1.C | 20 ++++++++++++++++++++ 2 files changed, 35 insertions(+) create mode 100644 gcc/testsuite/g++.dg/asan/initlist1.C (limited to 'gcc') diff --git a/gcc/gimple-low.cc b/gcc/gimple-low.cc index 0fca974..e19fc2c 100644 --- a/gcc/gimple-low.cc +++ b/gcc/gimple-low.cc @@ -790,6 +790,21 @@ lower_stmt (gimple_stmt_iterator *gsi, struct lower_data *data) return; } + if (gimple_call_internal_p (stmt, IFN_ASAN_MARK)) + { + tree base = gimple_call_arg (stmt, 1); + gcc_checking_assert (TREE_CODE (base) == ADDR_EXPR); + tree decl = TREE_OPERAND (base, 0); + if (VAR_P (decl) && TREE_STATIC (decl)) + { + /* Don't poison a variable with static storage; it might have + gotten marked before gimplify_init_constructor promoted it + to static. */ + gsi_remove (gsi, true); + return; + } + } + /* We delay folding of built calls from gimplification to here so the IL is in consistent state for the diagnostic machineries job. */ diff --git a/gcc/testsuite/g++.dg/asan/initlist1.C b/gcc/testsuite/g++.dg/asan/initlist1.C new file mode 100644 index 0000000..6cd5b7d --- /dev/null +++ b/gcc/testsuite/g++.dg/asan/initlist1.C @@ -0,0 +1,20 @@ +// PR c++/113531 +// { dg-do run { target c++11 } } +// { dg-additional-options "-fsanitize=address" } + +#include + +void f(int) { } + +void g() +{ + for (auto i : { 1, 2, 3 }) + f (i); + f(42); +} + +int main() +{ + g(); + g(); +} -- cgit v1.1 From b84f8a5e0a7ef3e5bd0d186fc7e280d9c43c5b7f Mon Sep 17 00:00:00 2001 From: Richard Biener Date: Thu, 1 Feb 2024 09:18:47 +0100 Subject: tree-optimization/113693 - LC SSA and region VN The following fixes LC SSA preserving with region VN which was broken when availability checking was enhanced to treat not visited value numbers as available. The following makes sure to honor availability data we put in place for LC SSA preserving instead. PR tree-optimization/113693 * tree-ssa-sccvn.cc (rpo_elim::eliminate_avail): Honor avail data when available. * gcc.dg/pr113693.c: New testcase. --- gcc/testsuite/gcc.dg/pr113693.c | 13 +++++++++++++ gcc/tree-ssa-sccvn.cc | 11 +++++++---- 2 files changed, 20 insertions(+), 4 deletions(-) create mode 100644 gcc/testsuite/gcc.dg/pr113693.c (limited to 'gcc') diff --git a/gcc/testsuite/gcc.dg/pr113693.c b/gcc/testsuite/gcc.dg/pr113693.c new file mode 100644 index 0000000..a6f5519 --- /dev/null +++ b/gcc/testsuite/gcc.dg/pr113693.c @@ -0,0 +1,13 @@ +/* { dg-do compile { target bitint } } */ +/* { dg-options "-O2 -fdbg-cnt=vect_loop:1" } */ + +_BitInt(837) g, h; + +void +fn1(void) +{ + for (; g; g++) + for (; h; h++) + ; +} +/* { dg-message "dbgcnt" "" { target *-*-* } 0 } */ diff --git a/gcc/tree-ssa-sccvn.cc b/gcc/tree-ssa-sccvn.cc index 9bed9b3..bbcf865 100644 --- a/gcc/tree-ssa-sccvn.cc +++ b/gcc/tree-ssa-sccvn.cc @@ -7723,12 +7723,15 @@ rpo_elim::eliminate_avail (basic_block bb, tree op) if (SSA_NAME_IS_DEFAULT_DEF (valnum)) return valnum; vn_ssa_aux_t valnum_info = VN_INFO (valnum); - /* See above. */ - if (!valnum_info->visited) - return valnum; vn_avail *av = valnum_info->avail; if (!av) - return NULL_TREE; + { + /* See above. But when there's availability info prefer + what we recorded there for example to preserve LC SSA. */ + if (!valnum_info->visited) + return valnum; + return NULL_TREE; + } if (av->location == bb->index) /* On tramp3d 90% of the cases are here. */ return ssa_name (av->leader); -- cgit v1.1 From 75f49cf82e06971b066b4f440256004775603752 Mon Sep 17 00:00:00 2001 From: Gaius Mulley Date: Thu, 1 Feb 2024 10:24:02 +0000 Subject: PR modula2/111627 defend against ICE Although PR 111627 can be fixed by renaming testsuite modules it highlighted that a possible ICE can occur if a malformed implementation module is actually a program module. This small patch defends against this ICE and checks to see whether the module is a DefImp before testing IsDefinitionForC. gcc/m2/ChangeLog: PR modula2/111627 PR modula2/112506 * gm2-compiler/M2Comp.mod (Pass0CheckMod): Test IsDefImp before checking IsDefinitionForC. Signed-off-by: Gaius Mulley --- gcc/m2/gm2-compiler/M2Comp.mod | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'gcc') diff --git a/gcc/m2/gm2-compiler/M2Comp.mod b/gcc/m2/gm2-compiler/M2Comp.mod index a97f0ed..c10c301 100644 --- a/gcc/m2/gm2-compiler/M2Comp.mod +++ b/gcc/m2/gm2-compiler/M2Comp.mod @@ -869,7 +869,7 @@ BEGIN END ELSIF GenModuleList THEN - IF NOT IsDefinitionForC (sym) + IF IsDefImp (sym) AND (NOT IsDefinitionForC (sym)) THEN (* The implementation module is only useful if -fgen-module-list= is used (to gather all dependencies). Note that we do not insist -- cgit v1.1 From 6c2a40f4f4577f5d0f7bd1cfda48a5701b75744c Mon Sep 17 00:00:00 2001 From: Thomas Schwinge Date: Wed, 31 Jan 2024 10:19:00 +0100 Subject: GCN, RDNA 3: Adjust 'sync_compare_and_swap_lds_insn' For OpenACC/GCN '-march=gfx1100', a lot of libgomp OpenACC test cases FAIL: /tmp/ccGfLJ8a.mkoffload.2.s:406:2: error: instruction not supported on this GPU ds_cmpst_rtn_b32 v0, v0, v4, v3 ^ In RDNA 3, 'ds_cmpst_[...]' has been replaced by 'ds_cmpstore_[...]', and the notes for 'ds_cmpst_[...]' in pre-RDNA 3 ISA manuals: Caution, the order of src and cmp are the *opposite* of the BUFFER_ATOMIC_CMPSWAP opcode. ..., have been resolved for 'ds_cmpstore_[...]' in the RDNA 3 ISA manual: In this architecture the order of src and cmp agree with the BUFFER_ATOMIC_CMPSWAP opcode. ..., and therefore '%2', '%3' now swapped with regards to GCC operand order. Most of the affected libgomp OpenACC test cases then PASS their execution test. gcc/ * config/gcn/gcn.md (sync_compare_and_swap_lds_insn) [TARGET_RDNA3]: Adjust. --- gcc/config/gcn/gcn.md | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) (limited to 'gcc') diff --git a/gcc/config/gcn/gcn.md b/gcc/config/gcn/gcn.md index 1f3c692..925e2ce 100644 --- a/gcc/config/gcn/gcn.md +++ b/gcc/config/gcn/gcn.md @@ -2074,7 +2074,12 @@ (match_operand:SIDI 3 "register_operand" " v")] UNSPECV_ATOMIC))] "" - "ds_cmpst_rtn_b %0, %1, %2, %3\;s_waitcnt\tlgkmcnt(0)" + { + if (TARGET_RDNA3) + return "ds_cmpstore_rtn_b %0, %1, %3, %2\;s_waitcnt\tlgkmcnt(0)"; + else + return "ds_cmpst_rtn_b %0, %1, %2, %3\;s_waitcnt\tlgkmcnt(0)"; + } [(set_attr "type" "ds") (set_attr "length" "12")]) -- cgit v1.1 From f9eb021283d33846006330e73c4a12f9ffeb4d40 Mon Sep 17 00:00:00 2001 From: Thomas Schwinge Date: Wed, 31 Jan 2024 12:25:25 +0100 Subject: GCN: Remove 'SGPR_OR_VGPR_REGNO_P' definition ..., which was always (a) unused, and (b) bogus: always-false. gcc/ * config/gcn/gcn.h (SGPR_OR_VGPR_REGNO_P): Remove. --- gcc/config/gcn/gcn.h | 1 - 1 file changed, 1 deletion(-) (limited to 'gcc') diff --git a/gcc/config/gcn/gcn.h b/gcc/config/gcn/gcn.h index c2afb5e..efe3c91 100644 --- a/gcc/config/gcn/gcn.h +++ b/gcc/config/gcn/gcn.h @@ -180,7 +180,6 @@ #define HARD_FRAME_POINTER_IS_ARG_POINTER 0 #define HARD_FRAME_POINTER_IS_FRAME_POINTER 0 -#define SGPR_OR_VGPR_REGNO_P(N) ((N)>=FIRST_VGPR_REG && (N) <= LAST_SGPR_REG) #define SGPR_REGNO_P(N) ((N) <= LAST_SGPR_REG) #define VGPR_REGNO_P(N) ((N)>=FIRST_VGPR_REG && (N) <= LAST_VGPR_REG) #define AVGPR_REGNO_P(N) ((N)>=FIRST_AVGPR_REG && (N) <= LAST_AVGPR_REG) -- cgit v1.1 From 31938936d740f70bede1011a8a7dbc0689b92e69 Mon Sep 17 00:00:00 2001 From: Thomas Schwinge Date: Wed, 31 Jan 2024 13:27:34 +0100 Subject: GCN: Remove 'FIRST_{SGPR,VGPR,AVGPR}_REG', 'LAST_{SGPR,VGPR,AVGPR}_REG' from machine description They're not used there, and we avoid potentially out-of-sync definitions. gcc/ * config/gcn/gcn.md (FIRST_SGPR_REG, LAST_SGPR_REG) (FIRST_VGPR_REG, LAST_VGPR_REG, FIRST_AVGPR_REG, LAST_AVGPR_REG): Don't 'define_constants'. --- gcc/config/gcn/gcn.md | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) (limited to 'gcc') diff --git a/gcc/config/gcn/gcn.md b/gcc/config/gcn/gcn.md index 925e2ce..3b51453 100644 --- a/gcc/config/gcn/gcn.md +++ b/gcc/config/gcn/gcn.md @@ -23,9 +23,7 @@ ; Named registers (define_constants - [(FIRST_SGPR_REG 0) - (CC_SAVE_REG 22) - (LAST_SGPR_REG 101) + [(CC_SAVE_REG 22) (FLAT_SCRATCH_REG 102) (FLAT_SCRATCH_LO_REG 102) (FLAT_SCRATCH_HI_REG 103) @@ -49,11 +47,7 @@ (EXEC_LO_REG 126) (EXEC_HI_REG 127) (EXECZ_REG 128) - (SCC_REG 129) - (FIRST_VGPR_REG 160) - (LAST_VGPR_REG 415) - (FIRST_AVGPR_REG 416) - (LAST_AVGPR_REG 671)]) + (SCC_REG 129)]) (define_constants [(SP_REGNUM 16) -- cgit v1.1 From dd3455f69577eed9d65e7e00161666fcfbbf444c Mon Sep 17 00:00:00 2001 From: GCC Administrator Date: Thu, 1 Feb 2024 11:40:50 +0000 Subject: Daily bump. --- gcc/ChangeLog | 234 +++++++++++++++++++++++++++++++++++++++ gcc/DATESTAMP | 2 +- gcc/analyzer/ChangeLog | 17 +++ gcc/c-family/ChangeLog | 5 + gcc/c/ChangeLog | 25 +++++ gcc/m2/ChangeLog | 13 +++ gcc/testsuite/ChangeLog | 285 ++++++++++++++++++++++++++++++++++++++++++++++++ 7 files changed, 580 insertions(+), 1 deletion(-) (limited to 'gcc') diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 2f7d6ff..ec3bfe1 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,237 @@ +2024-02-01 Thomas Schwinge + + * config/gcn/gcn.md (FIRST_SGPR_REG, LAST_SGPR_REG) + (FIRST_VGPR_REG, LAST_VGPR_REG, FIRST_AVGPR_REG, LAST_AVGPR_REG): + Don't 'define_constants'. + +2024-02-01 Thomas Schwinge + + * config/gcn/gcn.h (SGPR_OR_VGPR_REGNO_P): Remove. + +2024-02-01 Thomas Schwinge + + * config/gcn/gcn.md (sync_compare_and_swap_lds_insn) + [TARGET_RDNA3]: Adjust. + +2024-02-01 Richard Biener + + PR tree-optimization/113693 + * tree-ssa-sccvn.cc (rpo_elim::eliminate_avail): Honor avail + data when available. + +2024-02-01 Jakub Jelinek + Jason Merrill + + PR c++/113531 + * gimple-low.cc (lower_stmt): Remove .ASAN_MARK calls + on variables which were promoted to TREE_STATIC. + +2024-02-01 Roger Sayle + Richard Biener + + PR target/113560 + * tree-ssa-math-opts.cc (is_widening_mult_rhs_p): Use range + information via tree_non_zero_bits to check if this operand + is suitably extended for a widening (or highpart) multiplication. + (convert_mult_to_widen): Insert explicit casts if the RHS or LHS + isn't already of the claimed type. + +2024-02-01 Edwin Lu + + Revert: + 2024-02-01 Edwin Lu + + * config/riscv/generic-ooo.md (generic_ooo_sfb_alu): Add reservation + (generic_ooo_branch): ditto + * config/riscv/generic.md (generic_sfb_alu): ditto + (generic_fmul_half): ditto + * config/riscv/riscv.md: Remove cbo, pushpop, and rdfrm types + * config/riscv/sifive-7.md (sifive_7_hfma):Add reservation + (sifive_7_popcount): ditto + * config/riscv/vector.md: change rdfrm to fmove + * config/riscv/zc.md: change pushpop to load/store + +2024-02-01 Edwin Lu + + Revert: + 2024-02-01 Edwin Lu + Robin Dapp + + * config/riscv/generic-ooo.md (generic_ooo): Move reservation + (generic_ooo_vec_load): ditto + (generic_ooo_vec_store): ditto + (generic_ooo_vec_loadstore_seg): ditto + (generic_ooo_vec_alu): ditto + (generic_ooo_vec_fcmp): ditto + (generic_ooo_vec_imul): ditto + (generic_ooo_vec_fadd): ditto + (generic_ooo_vec_fmul): ditto + (generic_ooo_crypto): ditto + (generic_ooo_perm): ditto + (generic_ooo_vec_reduction): ditto + (generic_ooo_vec_ordered_reduction): ditto + (generic_ooo_vec_idiv): ditto + (generic_ooo_vec_float_divsqrt): ditto + (generic_ooo_vec_mask): ditto + (generic_ooo_vec_vesetvl): ditto + (generic_ooo_vec_setrm): ditto + (generic_ooo_vec_readlen): ditto + * config/riscv/riscv.md: include generic-vector-ooo + * config/riscv/generic-vector-ooo.md: New file. to here + +2024-02-01 Edwin Lu + + Revert: + 2024-02-01 Edwin Lu + + * config/riscv/riscv.cc (riscv_sched_variable_issue): enable assert + +2024-02-01 Edwin Lu + + * config/riscv/riscv.cc (riscv_sched_variable_issue): enable assert + +2024-02-01 Edwin Lu + Robin Dapp + + * config/riscv/generic-ooo.md (generic_ooo): Move reservation + (generic_ooo_vec_load): ditto + (generic_ooo_vec_store): ditto + (generic_ooo_vec_loadstore_seg): ditto + (generic_ooo_vec_alu): ditto + (generic_ooo_vec_fcmp): ditto + (generic_ooo_vec_imul): ditto + (generic_ooo_vec_fadd): ditto + (generic_ooo_vec_fmul): ditto + (generic_ooo_crypto): ditto + (generic_ooo_perm): ditto + (generic_ooo_vec_reduction): ditto + (generic_ooo_vec_ordered_reduction): ditto + (generic_ooo_vec_idiv): ditto + (generic_ooo_vec_float_divsqrt): ditto + (generic_ooo_vec_mask): ditto + (generic_ooo_vec_vesetvl): ditto + (generic_ooo_vec_setrm): ditto + (generic_ooo_vec_readlen): ditto + * config/riscv/riscv.md: include generic-vector-ooo + * config/riscv/generic-vector-ooo.md: New file. to here + +2024-02-01 Edwin Lu + + * config/riscv/generic-ooo.md (generic_ooo_sfb_alu): Add reservation + (generic_ooo_branch): ditto + * config/riscv/generic.md (generic_sfb_alu): ditto + (generic_fmul_half): ditto + * config/riscv/riscv.md: Remove cbo, pushpop, and rdfrm types + * config/riscv/sifive-7.md (sifive_7_hfma):Add reservation + (sifive_7_popcount): ditto + * config/riscv/vector.md: change rdfrm to fmove + * config/riscv/zc.md: change pushpop to load/store + +2024-02-01 Andrew Pinski + + PR target/113657 + * config/aarch64/aarch64-simd.md (split for movv8di): + For strict aligned mode, use DImode instead of TImode. + +2024-01-31 Robin Dapp + + PR middle-end/113607 + * match.pd: Make sure else values match when folding a + vec_cond into a conditional operation. + +2024-01-31 Marek Polacek + + * doc/invoke.texi: Mention that -fconcepts-ts was deprecated in GCC 14. + +2024-01-31 Tamar Christina + Matthew Malcomson + + PR sanitizer/112644 + * asan.h (asan_intercepted_p): Incercept memset, memmove, memcpy and + memcmp. + * builtins.cc (expand_builtin): Include HWASAN when checking for + builtin inlining. + +2024-01-31 Richard Biener + + PR middle-end/110176 + * match.pd (zext (bool) <= (int) 4294967295u): Make sure + to match INTEGER_CST only without outstanding conversion. + +2024-01-31 Alex Coplan + + PR target/111677 + * config/aarch64/aarch64.cc (aarch64_reg_save_mode): Use + V16QImode for the full 16-byte FPR saves in the vector PCS case. + +2024-01-31 Richard Biener + + PR tree-optimization/111444 + * tree-ssa-sccvn.cc (vn_reference_lookup_3): Do not use + vn_reference_lookup_2 when optimistically skipping may-defs. + +2024-01-31 Richard Biener + + PR tree-optimization/113630 + * tree-ssa-pre.cc (compute_avail): Avoid registering a + reference with a representation with not matching base + access size. + +2024-01-31 Jakub Jelinek + + PR rtl-optimization/113656 + * simplify-rtx.cc (simplify_context::simplify_unary_operation_1) + : Fix up last argument to simplify_gen_unary. + +2024-01-31 Jakub Jelinek + + PR debug/113637 + * dwarf2out.cc (loc_list_from_tree_1): Assume integral types + with BLKmode are larger than DWARF2_ADDR_SIZE. + +2024-01-31 Jakub Jelinek + + PR tree-optimization/113639 + * gimple-lower-bitint.cc (bitint_large_huge::handle_operand_addr): + For VIEW_CONVERT_EXPR set rhs1 to its operand. + +2024-01-31 Richard Biener + + PR tree-optimization/113670 + * tree-vect-data-refs.cc (vect_check_gather_scatter): + Make sure we can take the address of the reference base. + +2024-01-31 Georg-Johann Lay + + * config/avr/avr-mcus.def: Add AVR64DU28, AVR64DU32, ATA5787, + ATA5835, ATtiny64AUTO, ATA5700M322. + * doc/avr-mmcu.texi: Rebuild. + +2024-01-31 Alexandre Oliva + + PR debug/113394 + * ipa-strub.cc (build_ref_type_for): Drop nonaliased. Adjust + caller. + +2024-01-31 Alexandre Oliva + + PR middle-end/112917 + PR middle-end/113100 + * builtins.cc (expand_builtin_stack_address): Use + STACK_ADDRESS_OFFSET. + * doc/extend.texi (__builtin_stack_address): Adjust. + * config/sparc/sparc.h (STACK_ADDRESS_OFFSET): Define. + * doc/tm.texi.in (STACK_ADDRESS_OFFSET): Document. + * doc/tm.texi: Rebuilt. + +2024-01-31 Juzhe-Zhong + + PR target/113495 + * config/riscv/riscv-vsetvl.cc (extract_single_source): Remove. + (pre_vsetvl::compute_vsetvl_def_data): Fix compile time issue. + (pre_vsetvl::compute_transparent): New function. + (pre_vsetvl::compute_lcm_local_properties): Fix compile time time issue. + 2024-01-30 Fangrui Song PR target/105576 diff --git a/gcc/DATESTAMP b/gcc/DATESTAMP index e288d0c..aa4ca8e 100644 --- a/gcc/DATESTAMP +++ b/gcc/DATESTAMP @@ -1 +1 @@ -20240131 +20240201 diff --git a/gcc/analyzer/ChangeLog b/gcc/analyzer/ChangeLog index ce599b1..f666c73 100644 --- a/gcc/analyzer/ChangeLog +++ b/gcc/analyzer/ChangeLog @@ -1,3 +1,20 @@ +2024-01-31 David Malcolm + + PR analyzer/113253 + * region-model.cc (region_model::on_stmt_pre): Add gcc_unreachable + for debug statements. + * state-purge.cc + (state_purge_per_ssa_name::state_purge_per_ssa_name): Skip any + debug stmts in the FOR_EACH_IMM_USE_FAST list. + * supergraph.cc (supergraph::supergraph): Don't add debug stmts + to the supernodes. + +2024-01-31 David Malcolm + + PR analyzer/113509 + * checker-event.cc (state_change_event::get_desc): Don't assume + "var" is non-NULL. + 2024-01-30 David Malcolm PR analyzer/113654 diff --git a/gcc/c-family/ChangeLog b/gcc/c-family/ChangeLog index fd91628..9bce014 100644 --- a/gcc/c-family/ChangeLog +++ b/gcc/c-family/ChangeLog @@ -1,3 +1,8 @@ +2024-01-31 Marek Polacek + + * c-opts.cc (c_common_post_options): Add an inform saying that + -fconcepts-ts is deprecated and will be removed in GCC 15. + 2024-01-27 Lewis Hyatt PR preprocessor/105608 diff --git a/gcc/c/ChangeLog b/gcc/c/ChangeLog index b1c887b..eb3e02c 100644 --- a/gcc/c/ChangeLog +++ b/gcc/c/ChangeLog @@ -1,3 +1,28 @@ +2024-01-31 Joseph Myers + + PR c/112571 + * c-decl.cc (start_enum): Clear ENUM_FIXED_UNDERLYING_TYPE_P when + defining without a fixed underlying type an enumeration previously + declared with a fixed underlying type. + +2024-01-31 Martin Uecker + + PR c/113438 + * c-typeck.cc (composite_type_internal): Set TYPE_STUB_DECL. + +2024-01-31 Joseph Myers + + PR c/111059 + PR c/111911 + * c-tree.h (c_objc_common_truthvalue_conversion): Add third + argument. + * c-convert.cc (c_convert): For conversions to boolean, pass third + argument to c_objc_common_truthvalue_conversion rather than + converting here. + * c-typeck.cc (build_c_cast): Ensure arguments with integer + operands are marked as such for conversion to boolean. + (c_objc_common_truthvalue_conversion): Add third argument TYPE. + 2024-01-21 Martin Uecker PR c/113492 diff --git a/gcc/m2/ChangeLog b/gcc/m2/ChangeLog index 9237324..abac63b 100644 --- a/gcc/m2/ChangeLog +++ b/gcc/m2/ChangeLog @@ -1,3 +1,16 @@ +2024-02-01 Gaius Mulley + + PR modula2/111627 + PR modula2/112506 + * gm2-compiler/M2Comp.mod (Pass0CheckMod): Test IsDefImp before + checking IsDefinitionForC. + +2024-01-31 Gaius Mulley + + * gm2-compiler/M2Comp.mod (Pass0CheckMod): Tidy up comment. + * gm2-compiler/P1Build.bnf (PossiblyExportIdent): Replace + PushTF with PushTFtok. + 2024-01-26 Gaius Mulley * gm2-compiler/M2Check.mod (dumpIndice): New procedure. diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index 532d623..5d40133 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,288 @@ +2024-02-01 Richard Biener + + PR tree-optimization/113693 + * gcc.dg/pr113693.c: New testcase. + +2024-02-01 Jakub Jelinek + Jason Merrill + + PR c++/113531 + * g++.dg/asan/initlist1.C: New test. + +2024-02-01 Roger Sayle + Richard Biener + + PR target/113560 + * g++.target/i386/pr113560.C: New test case. + * gcc.target/i386/pr113560.c: Likewise. + * gcc.dg/pr87954.c: Update test case. + +2024-02-01 Edwin Lu + + Revert: + 2024-02-01 Edwin Lu + + PR target/113249 + * g++.target/riscv/rvv/base/bug-1.C: use default scheduling + * gcc.target/riscv/rvv/autovec/reduc/reduc_call-2.c: ditto + * gcc.target/riscv/rvv/base/binop_vx_constraint-102.c: ditto + * gcc.target/riscv/rvv/base/binop_vx_constraint-108.c: ditto + * gcc.target/riscv/rvv/base/binop_vx_constraint-114.c: ditto + * gcc.target/riscv/rvv/base/binop_vx_constraint-119.c: ditto + * gcc.target/riscv/rvv/base/binop_vx_constraint-12.c: ditto + * gcc.target/riscv/rvv/base/binop_vx_constraint-16.c: ditto + * gcc.target/riscv/rvv/base/binop_vx_constraint-17.c: ditto + * gcc.target/riscv/rvv/base/binop_vx_constraint-19.c: ditto + * gcc.target/riscv/rvv/base/binop_vx_constraint-21.c: ditto + * gcc.target/riscv/rvv/base/binop_vx_constraint-23.c: ditto + * gcc.target/riscv/rvv/base/binop_vx_constraint-25.c: ditto + * gcc.target/riscv/rvv/base/binop_vx_constraint-27.c: ditto + * gcc.target/riscv/rvv/base/binop_vx_constraint-29.c: ditto + * gcc.target/riscv/rvv/base/binop_vx_constraint-31.c: ditto + * gcc.target/riscv/rvv/base/binop_vx_constraint-33.c: ditto + * gcc.target/riscv/rvv/base/binop_vx_constraint-35.c: ditto + * gcc.target/riscv/rvv/base/binop_vx_constraint-4.c: ditto + * gcc.target/riscv/rvv/base/binop_vx_constraint-40.c: ditto + * gcc.target/riscv/rvv/base/binop_vx_constraint-44.c: ditto + * gcc.target/riscv/rvv/base/binop_vx_constraint-50.c: ditto + * gcc.target/riscv/rvv/base/binop_vx_constraint-56.c: ditto + * gcc.target/riscv/rvv/base/binop_vx_constraint-62.c: ditto + * gcc.target/riscv/rvv/base/binop_vx_constraint-68.c: ditto + * gcc.target/riscv/rvv/base/binop_vx_constraint-74.c: ditto + * gcc.target/riscv/rvv/base/binop_vx_constraint-79.c: ditto + * gcc.target/riscv/rvv/base/binop_vx_constraint-8.c: ditto + * gcc.target/riscv/rvv/base/binop_vx_constraint-84.c: ditto + * gcc.target/riscv/rvv/base/binop_vx_constraint-90.c: ditto + * gcc.target/riscv/rvv/base/binop_vx_constraint-96.c: ditto + * gcc.target/riscv/rvv/base/float-point-dynamic-frm-30.c: ditto + * gcc.target/riscv/rvv/base/pr108185-1.c: ditto + * gcc.target/riscv/rvv/base/pr108185-2.c: ditto + * gcc.target/riscv/rvv/base/pr108185-3.c: ditto + * gcc.target/riscv/rvv/base/pr108185-4.c: ditto + * gcc.target/riscv/rvv/base/pr108185-5.c: ditto + * gcc.target/riscv/rvv/base/pr108185-6.c: ditto + * gcc.target/riscv/rvv/base/pr108185-7.c: ditto + * gcc.target/riscv/rvv/base/shift_vx_constraint-1.c: ditto + * gcc.target/riscv/rvv/vsetvl/pr111037-3.c: ditto + * gcc.target/riscv/rvv/vsetvl/vlmax_back_prop-28.c: ditto + * gcc.target/riscv/rvv/vsetvl/vlmax_back_prop-29.c: ditto + * gcc.target/riscv/rvv/vsetvl/vlmax_back_prop-32.c: ditto + * gcc.target/riscv/rvv/vsetvl/vlmax_back_prop-33.c: ditto + * gcc.target/riscv/rvv/vsetvl/vlmax_single_block-17.c: ditto + * gcc.target/riscv/rvv/vsetvl/vlmax_single_block-18.c: ditto + * gcc.target/riscv/rvv/vsetvl/vlmax_single_block-19.c: ditto + * gcc.target/riscv/rvv/vsetvl/vlmax_switch_vtype-10.c: ditto + * gcc.target/riscv/rvv/vsetvl/vlmax_switch_vtype-11.c: ditto + * gcc.target/riscv/rvv/vsetvl/vlmax_switch_vtype-12.c: ditto + * gcc.target/riscv/rvv/vsetvl/vlmax_switch_vtype-4.c: ditto + * gcc.target/riscv/rvv/vsetvl/vlmax_switch_vtype-5.c: ditto + * gcc.target/riscv/rvv/vsetvl/vlmax_switch_vtype-6.c: ditto + * gcc.target/riscv/rvv/vsetvl/vlmax_switch_vtype-7.c: ditto + * gcc.target/riscv/rvv/vsetvl/vlmax_switch_vtype-8.c: ditto + * gcc.target/riscv/rvv/vsetvl/vlmax_switch_vtype-9.c: ditto + * gfortran.dg/vect/vect-8.f90: ditto + +2024-02-01 Edwin Lu + + PR target/113249 + * g++.target/riscv/rvv/base/bug-1.C: use default scheduling + * gcc.target/riscv/rvv/autovec/reduc/reduc_call-2.c: ditto + * gcc.target/riscv/rvv/base/binop_vx_constraint-102.c: ditto + * gcc.target/riscv/rvv/base/binop_vx_constraint-108.c: ditto + * gcc.target/riscv/rvv/base/binop_vx_constraint-114.c: ditto + * gcc.target/riscv/rvv/base/binop_vx_constraint-119.c: ditto + * gcc.target/riscv/rvv/base/binop_vx_constraint-12.c: ditto + * gcc.target/riscv/rvv/base/binop_vx_constraint-16.c: ditto + * gcc.target/riscv/rvv/base/binop_vx_constraint-17.c: ditto + * gcc.target/riscv/rvv/base/binop_vx_constraint-19.c: ditto + * gcc.target/riscv/rvv/base/binop_vx_constraint-21.c: ditto + * gcc.target/riscv/rvv/base/binop_vx_constraint-23.c: ditto + * gcc.target/riscv/rvv/base/binop_vx_constraint-25.c: ditto + * gcc.target/riscv/rvv/base/binop_vx_constraint-27.c: ditto + * gcc.target/riscv/rvv/base/binop_vx_constraint-29.c: ditto + * gcc.target/riscv/rvv/base/binop_vx_constraint-31.c: ditto + * gcc.target/riscv/rvv/base/binop_vx_constraint-33.c: ditto + * gcc.target/riscv/rvv/base/binop_vx_constraint-35.c: ditto + * gcc.target/riscv/rvv/base/binop_vx_constraint-4.c: ditto + * gcc.target/riscv/rvv/base/binop_vx_constraint-40.c: ditto + * gcc.target/riscv/rvv/base/binop_vx_constraint-44.c: ditto + * gcc.target/riscv/rvv/base/binop_vx_constraint-50.c: ditto + * gcc.target/riscv/rvv/base/binop_vx_constraint-56.c: ditto + * gcc.target/riscv/rvv/base/binop_vx_constraint-62.c: ditto + * gcc.target/riscv/rvv/base/binop_vx_constraint-68.c: ditto + * gcc.target/riscv/rvv/base/binop_vx_constraint-74.c: ditto + * gcc.target/riscv/rvv/base/binop_vx_constraint-79.c: ditto + * gcc.target/riscv/rvv/base/binop_vx_constraint-8.c: ditto + * gcc.target/riscv/rvv/base/binop_vx_constraint-84.c: ditto + * gcc.target/riscv/rvv/base/binop_vx_constraint-90.c: ditto + * gcc.target/riscv/rvv/base/binop_vx_constraint-96.c: ditto + * gcc.target/riscv/rvv/base/float-point-dynamic-frm-30.c: ditto + * gcc.target/riscv/rvv/base/pr108185-1.c: ditto + * gcc.target/riscv/rvv/base/pr108185-2.c: ditto + * gcc.target/riscv/rvv/base/pr108185-3.c: ditto + * gcc.target/riscv/rvv/base/pr108185-4.c: ditto + * gcc.target/riscv/rvv/base/pr108185-5.c: ditto + * gcc.target/riscv/rvv/base/pr108185-6.c: ditto + * gcc.target/riscv/rvv/base/pr108185-7.c: ditto + * gcc.target/riscv/rvv/base/shift_vx_constraint-1.c: ditto + * gcc.target/riscv/rvv/vsetvl/pr111037-3.c: ditto + * gcc.target/riscv/rvv/vsetvl/vlmax_back_prop-28.c: ditto + * gcc.target/riscv/rvv/vsetvl/vlmax_back_prop-29.c: ditto + * gcc.target/riscv/rvv/vsetvl/vlmax_back_prop-32.c: ditto + * gcc.target/riscv/rvv/vsetvl/vlmax_back_prop-33.c: ditto + * gcc.target/riscv/rvv/vsetvl/vlmax_single_block-17.c: ditto + * gcc.target/riscv/rvv/vsetvl/vlmax_single_block-18.c: ditto + * gcc.target/riscv/rvv/vsetvl/vlmax_single_block-19.c: ditto + * gcc.target/riscv/rvv/vsetvl/vlmax_switch_vtype-10.c: ditto + * gcc.target/riscv/rvv/vsetvl/vlmax_switch_vtype-11.c: ditto + * gcc.target/riscv/rvv/vsetvl/vlmax_switch_vtype-12.c: ditto + * gcc.target/riscv/rvv/vsetvl/vlmax_switch_vtype-4.c: ditto + * gcc.target/riscv/rvv/vsetvl/vlmax_switch_vtype-5.c: ditto + * gcc.target/riscv/rvv/vsetvl/vlmax_switch_vtype-6.c: ditto + * gcc.target/riscv/rvv/vsetvl/vlmax_switch_vtype-7.c: ditto + * gcc.target/riscv/rvv/vsetvl/vlmax_switch_vtype-8.c: ditto + * gcc.target/riscv/rvv/vsetvl/vlmax_switch_vtype-9.c: ditto + * gfortran.dg/vect/vect-8.f90: ditto + +2024-02-01 Andrew Pinski + + PR target/113657 + * gcc.target/aarch64/acle/ls64_strict_align.c: New test. + +2024-01-31 David Malcolm + + PR analyzer/113253 + * gcc.dg/analyzer/deref-before-check-pr113253.c: New test. + +2024-01-31 Joseph Myers + + PR c/112571 + * gcc.dg/c23-enum-9.c, gcc.dg/c23-enum-10.c: New tests. + +2024-01-31 Robin Dapp + + * gcc.target/aarch64/sve/pre_cond_share_1.c: XFAIL. + * gcc.target/riscv/rvv/autovec/pr113607-run.c: New test. + * gcc.target/riscv/rvv/autovec/pr113607.c: New test. + +2024-01-31 Martin Uecker + + PR c/113438 + * gcc.dg/pr113438.c: New test. + +2024-01-31 Jonathan Yong <10walls@gmail.com> + + * c-c++-common/analyzer/uninit-pr108968-register.c: + Use __UINTPTR_TYPE__ instead of unsigned long for LLP64. + +2024-01-31 Gaius Mulley + + PR modula2/111627 + * gm2/pim/pass/stdio.mod: Moved to... + * gm2/pim/pass/teststdio.mod: ...here. + * gm2/pim/run/pass/builtins.mod: Moved to... + * gm2/pim/run/pass/testbuiltins.mod: ...here. + * gm2/pim/run/pass/math.mod: Moved to... + * gm2/pim/run/pass/testmath.mod: ...here. + * gm2/pim/run/pass/math2.mod: Moved to... + * gm2/pim/run/pass/testmath2.mod: ...here. + +2024-01-31 Tamar Christina + + PR testsuite/113502 + * gcc.target/aarch64/sve/vect-early-break-cbranch.c: Ignore exact branch. + * gcc.target/aarch64/vect-early-break-cbranch.c: Likewise. + +2024-01-31 Tamar Christina + + PR sanitizer/112644 + * c-c++-common/hwasan/hwasan-thread-clears-stack.c: Update testcase. + +2024-01-31 Tamar Christina + Matthew Malcomson + + PR sanitizer/112644 + * c-c++-common/hwasan/builtin-special-handling.c: Update testcase. + +2024-01-31 Richard Biener + + PR middle-end/110176 + * gcc.dg/torture/pr110176.c: New testcase. + +2024-01-31 Alex Coplan + + PR target/111677 + * gcc.target/aarch64/torture/pr111677.c: New test. + +2024-01-31 Rainer Orth + + * gcc.target/i386/auto-init-5.c: Add + -fno-asynchronous-unwind-tables to dg-options. + * gcc.target/i386/auto-init-6.c: Likewise. + +2024-01-31 Richard Biener + + PR tree-optimization/111444 + * gcc.dg/torture/pr111444.c: New testcase. + +2024-01-31 Rainer Orth + + * g++.dg/cpp0x/udlit-extended-id-1.C: Require ucn support. + +2024-01-31 Richard Biener + + PR tree-optimization/113630 + * gcc.dg/torture/pr113630.c: New testcase. + +2024-01-31 Jakub Jelinek + + PR rtl-optimization/113656 + * gcc.target/i386/pr113656.c: New test. + +2024-01-31 Jakub Jelinek + + PR debug/113637 + * gcc.dg/bitint-80.c: New test. + +2024-01-31 Jakub Jelinek + + PR tree-optimization/113639 + * gcc.dg/bitint-79.c: New test. + +2024-01-31 Richard Biener + + PR tree-optimization/113670 + * gcc.target/i386/pr113670.c: New testcase. + +2024-01-31 Alexandre Oliva + + PR debug/113394 + * gcc.dg/strub-internal-pr113394.c: New. + +2024-01-31 Joseph Myers + + PR c/111059 + PR c/111911 + * gcc.c-torture/compile/pr111059-1.c, + gcc.c-torture/compile/pr111059-2.c, + gcc.c-torture/compile/pr111059-3.c, + gcc.c-torture/compile/pr111059-4.c, + gcc.c-torture/compile/pr111059-5.c, + gcc.c-torture/compile/pr111059-6.c, + gcc.c-torture/compile/pr111059-7.c, + gcc.c-torture/compile/pr111059-8.c, + gcc.c-torture/compile/pr111059-9.c, + gcc.c-torture/compile/pr111059-10.c, + gcc.c-torture/compile/pr111059-11.c, + gcc.c-torture/compile/pr111059-12.c, + gcc.c-torture/compile/pr111911-1.c, + gcc.c-torture/compile/pr111911-2.c: New tests. + +2024-01-31 David Malcolm + + PR analyzer/113509 + * c-c++-common/analyzer/stdarg-pr113509.c: New test. + 2024-01-30 Fangrui Song PR target/105576 -- cgit v1.1 From e98edc6a3cdfcdad71a2f7be5818033ea15cdde7 Mon Sep 17 00:00:00 2001 From: Rainer Orth Date: Thu, 1 Feb 2024 12:46:20 +0100 Subject: c++: Fix g++.dg/ext/attr-section2.C etc. with Solaris/SPARC as The new g++.dg/ext/attr-section2*.C tests FAIL on Solaris/SPARC with the native assembler: +FAIL: g++.dg/ext/attr-section2.C -std=c++14 scan-assembler .(section|csect)[ \\\\t]+.foo +FAIL: g++.dg/ext/attr-section2.C -std=c++17 scan-assembler .(section|csect)[ \\\\t]+.foo +FAIL: g++.dg/ext/attr-section2.C -std=c++20 scan-assembler .(section|csect)[ \\\\t]+.foo The problem is that the SPARC assembler requires the section name to be double-quoted, like .section ".foo%_Z3varIiE",#alloc,#write,#progbits This patch allows for that. At the same time, it quotes literal dots in the REs. Tested on sparc-sun-solaris2.11 (as and gas) and i386-pc-solaris2.11 (as and gas). 2024-01-18 Rainer Orth gcc/testsuite: * g++.dg/ext/attr-section2.C (scan-assembler): Quote dots. Allow for double-quoted section name. * g++.dg/ext/attr-section2a.C: Likewise. * g++.dg/ext/attr-section2b.C: Likewise. --- gcc/testsuite/g++.dg/ext/attr-section2.C | 2 +- gcc/testsuite/g++.dg/ext/attr-section2a.C | 2 +- gcc/testsuite/g++.dg/ext/attr-section2b.C | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) (limited to 'gcc') diff --git a/gcc/testsuite/g++.dg/ext/attr-section2.C b/gcc/testsuite/g++.dg/ext/attr-section2.C index 7c9221b..81567c1 100644 --- a/gcc/testsuite/g++.dg/ext/attr-section2.C +++ b/gcc/testsuite/g++.dg/ext/attr-section2.C @@ -6,4 +6,4 @@ template template int var; -// { dg-final { scan-assembler {.(section|csect)[ \t]+.foo} } } +// { dg-final { scan-assembler {\.(section|csect)[ \t]+"?\.foo} } } diff --git a/gcc/testsuite/g++.dg/ext/attr-section2a.C b/gcc/testsuite/g++.dg/ext/attr-section2a.C index 4fa898c..97b3a10 100644 --- a/gcc/testsuite/g++.dg/ext/attr-section2a.C +++ b/gcc/testsuite/g++.dg/ext/attr-section2a.C @@ -11,4 +11,4 @@ int A::var = 42; template struct A; -// { dg-final { scan-assembler {.(section|csect)[ \t]+.foo} } } +// { dg-final { scan-assembler {\.(section|csect)[ \t]+"?\.foo} } } diff --git a/gcc/testsuite/g++.dg/ext/attr-section2b.C b/gcc/testsuite/g++.dg/ext/attr-section2b.C index 9398773..bef0377 100644 --- a/gcc/testsuite/g++.dg/ext/attr-section2b.C +++ b/gcc/testsuite/g++.dg/ext/attr-section2b.C @@ -9,4 +9,4 @@ int* fun() { template int* fun(); -// { dg-final { scan-assembler {.(section|csect)[ \t]+.foo} } } +// { dg-final { scan-assembler {\.(section|csect)[ \t]+"?\.foo} } } -- cgit v1.1 From ee7011eab67d8272f88e954bbab2e42bf6353441 Mon Sep 17 00:00:00 2001 From: Rainer Orth Date: Thu, 1 Feb 2024 12:48:57 +0100 Subject: testsuite: i386: Fix gcc.target/i386/pr70321.c on 32-bit Solaris/x86 gcc.target/i386/pr70321.c FAILs on 32-bit Solaris/x86 since its introduction in commit 43201f2c2173894bf7c423cad6da1c21567e06c0 Author: Roger Sayle Date: Mon May 30 21:20:09 2022 +0100 PR target/70321: Split double word equality/inequality after STV on x86. FAIL: gcc.target/i386/pr70321.c scan-assembler-times mov 1 The failure happens because 32-bit Solaris/x86 defaults to -fno-omit-frame-pointer. Fixed by specifying -fomit-frame-pointer explicitly. Tested on i386-pc-solaris2.11 and i686-pc-linux-gnu. 2024-01-23 Rainer Orth gcc/testsuite: * gcc.target/i386/pr70321.c: Add -fomit-frame-pointer to dg-options. --- gcc/testsuite/gcc.target/i386/pr70321.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'gcc') diff --git a/gcc/testsuite/gcc.target/i386/pr70321.c b/gcc/testsuite/gcc.target/i386/pr70321.c index 57552ef..58f5f56 100644 --- a/gcc/testsuite/gcc.target/i386/pr70321.c +++ b/gcc/testsuite/gcc.target/i386/pr70321.c @@ -1,5 +1,5 @@ /* { dg-do compile { target ia32 } } */ -/* { dg-options "-O2" } */ +/* { dg-options "-O2 -fomit-frame-pointer" } */ void foo (long long ixi) { -- cgit v1.1 From 6353c39699076444190b8e329f7c2fc28204662c Mon Sep 17 00:00:00 2001 From: Rainer Orth Date: Thu, 1 Feb 2024 12:50:50 +0100 Subject: testsuite: i386: Fix gcc.target/i386/avx512vl-stv-rotatedi-1.c on 32-bit Solaris/x86 gcc.target/i386/avx512vl-stv-rotatedi-1.c FAILs on 32-bit Solaris/x86 since its introduction in commit 4814b63c3c2326cb5d7baa63882da60ac011bd97 Author: Roger Sayle Date: Mon Jul 10 09:04:29 2023 +0100 i386: Add AVX512 support for STV of SI/DImode rotation by constant. FAIL: gcc.target/i386/avx512vl-stv-rotatedi-1.c scan-assembler-times vpro[lr]q 29 While the test depends on -mstv, 32-bit Solaris/x86 defaults to -mstackrealign which is incompatible. The patch thus specifies -mstv -mno-stackrealign explicitly. Tested on i386-pc-solaris2.11 and i686-pc-linux-gnu. 2024-01-23 Rainer Orth gcc/testsuite: * gcc.target/i386/avx512vl-stv-rotatedi-1.c: Add -mstv -mno-stackrealign to dg-options. --- gcc/testsuite/gcc.target/i386/avx512vl-stv-rotatedi-1.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'gcc') diff --git a/gcc/testsuite/gcc.target/i386/avx512vl-stv-rotatedi-1.c b/gcc/testsuite/gcc.target/i386/avx512vl-stv-rotatedi-1.c index 2f0ead8..d3b85a1 100644 --- a/gcc/testsuite/gcc.target/i386/avx512vl-stv-rotatedi-1.c +++ b/gcc/testsuite/gcc.target/i386/avx512vl-stv-rotatedi-1.c @@ -1,5 +1,5 @@ /* { dg-do compile { target ia32 } } */ -/* { dg-options "-O2 -mavx512vl" } */ +/* { dg-options "-O2 -mavx512vl -mstv -mno-stackrealign" } */ unsigned long long rot1(unsigned long long x) { return (x>>1) | (x<<63); } unsigned long long rot2(unsigned long long x) { return (x>>2) | (x<<62); } -- cgit v1.1 From 7fd4bb1d987c3dc084bd367c93e689325f24b84a Mon Sep 17 00:00:00 2001 From: Rainer Orth Date: Thu, 1 Feb 2024 12:53:06 +0100 Subject: testsuite: i386: Fix gcc.target/i386/no-callee-saved-1.c etc. on Solaris/x86 The gcc.target/i386/no-callee-saved-[12].c tests FAIL on Solaris/x86: FAIL: gcc.target/i386/no-callee-saved-1.c scan-assembler-not push FAIL: gcc.target/i386/no-callee-saved-2.c scan-assembler-not push In both cases, the test expect the Linux/x86 default of -fomit-frame-pointer, while Solaris/x86 defaults to -fno-omit-frame-pointer. So this patch explicitly specifies -fomit-frame-pointer. Tested on i386-pc-solaris2.11 (as and gas) and i686-pc-linux-gnu. 2024-01-30 Rainer Orth gcc/testsuite: * gcc.target/i386/no-callee-saved-1.c: Add -fomit-frame-pointer to dg-options. * gcc.target/i386/no-callee-saved-2.c: Likewise. --- gcc/testsuite/gcc.target/i386/no-callee-saved-1.c | 2 +- gcc/testsuite/gcc.target/i386/no-callee-saved-2.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'gcc') diff --git a/gcc/testsuite/gcc.target/i386/no-callee-saved-1.c b/gcc/testsuite/gcc.target/i386/no-callee-saved-1.c index 8fe36eb..599c2a3 100644 --- a/gcc/testsuite/gcc.target/i386/no-callee-saved-1.c +++ b/gcc/testsuite/gcc.target/i386/no-callee-saved-1.c @@ -1,5 +1,5 @@ /* { dg-do compile } */ -/* { dg-options "-O2 -mtune-ctrl=^prologue_using_move,^epilogue_using_move" } */ +/* { dg-options "-O2 -mtune-ctrl=^prologue_using_move,^epilogue_using_move -fomit-frame-pointer" } */ extern int bar (int) #ifndef __x86_64__ diff --git a/gcc/testsuite/gcc.target/i386/no-callee-saved-2.c b/gcc/testsuite/gcc.target/i386/no-callee-saved-2.c index ce4ab3b..98e2701 100644 --- a/gcc/testsuite/gcc.target/i386/no-callee-saved-2.c +++ b/gcc/testsuite/gcc.target/i386/no-callee-saved-2.c @@ -1,5 +1,5 @@ /* { dg-do compile } */ -/* { dg-options "-O2 -mtune-ctrl=^prologue_using_move,^epilogue_using_move" } */ +/* { dg-options "-O2 -mtune-ctrl=^prologue_using_move,^epilogue_using_move -fomit-frame-pointer" } */ extern int bar (int) __attribute__ ((no_caller_saved_registers)) #ifndef __x86_64__ -- cgit v1.1 From 5b9b395b8561efe797842b5f1c435d538d0a5de4 Mon Sep 17 00:00:00 2001 From: Rainer Orth Date: Thu, 1 Feb 2024 12:59:29 +0100 Subject: testsuite: i386: Fix gcc.target/i386/pr38534-1.c etc. on Solaris/x86 The gcc.target/i386/pr38534-1.c etc. tests FAIL on 32 and 64-bit Solaris/x86: FAIL: gcc.target/i386/pr38534-1.c scan-assembler-not push FAIL: gcc.target/i386/pr38534-2.c scan-assembler-not push FAIL: gcc.target/i386/pr38534-3.c scan-assembler-not push FAIL: gcc.target/i386/pr38534-4.c scan-assembler-not push The tests assume the Linux/x86 default of -fomit-frame-pointer, while Solaris/x86 defaults to -fno-omit-frame-pointer. Fixed by specifying -fomit-frame-pointer explicitly. Tested on i386-pc-solaris2.11 and i686-pc-linux-gnu. 2024-01-30 Rainer Orth gcc/testsuite: * gcc.target/i386/pr38534-1.c: Add -fomit-frame-pointer to dg-options. * gcc.target/i386/pr38534-2.c: Likewise. * gcc.target/i386/pr38534-3.c: Likewise. * gcc.target/i386/pr38534-4.c: Likewise. --- gcc/testsuite/gcc.target/i386/pr38534-1.c | 2 +- gcc/testsuite/gcc.target/i386/pr38534-2.c | 2 +- gcc/testsuite/gcc.target/i386/pr38534-3.c | 2 +- gcc/testsuite/gcc.target/i386/pr38534-4.c | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) (limited to 'gcc') diff --git a/gcc/testsuite/gcc.target/i386/pr38534-1.c b/gcc/testsuite/gcc.target/i386/pr38534-1.c index 9297959..280f3b4 100644 --- a/gcc/testsuite/gcc.target/i386/pr38534-1.c +++ b/gcc/testsuite/gcc.target/i386/pr38534-1.c @@ -1,5 +1,5 @@ /* { dg-do compile } */ -/* { dg-options "-O2 -mtune-ctrl=^prologue_using_move,^epilogue_using_move" } */ +/* { dg-options "-O2 -mtune-ctrl=^prologue_using_move,^epilogue_using_move -fomit-frame-pointer" } */ #define ARRAY_SIZE 256 diff --git a/gcc/testsuite/gcc.target/i386/pr38534-2.c b/gcc/testsuite/gcc.target/i386/pr38534-2.c index 1fb0136..2e19989 100644 --- a/gcc/testsuite/gcc.target/i386/pr38534-2.c +++ b/gcc/testsuite/gcc.target/i386/pr38534-2.c @@ -1,5 +1,5 @@ /* { dg-do compile } */ -/* { dg-options "-O2 -mtune-ctrl=^prologue_using_move,^epilogue_using_move" } */ +/* { dg-options "-O2 -mtune-ctrl=^prologue_using_move,^epilogue_using_move -fomit-frame-pointer" } */ extern void bar (void) __attribute__ ((no_callee_saved_registers)); extern void fn (void) __attribute__ ((noreturn)); diff --git a/gcc/testsuite/gcc.target/i386/pr38534-3.c b/gcc/testsuite/gcc.target/i386/pr38534-3.c index 87fc35f..af6e195 100644 --- a/gcc/testsuite/gcc.target/i386/pr38534-3.c +++ b/gcc/testsuite/gcc.target/i386/pr38534-3.c @@ -1,5 +1,5 @@ /* { dg-do compile } */ -/* { dg-options "-O2 -mtune-ctrl=^prologue_using_move,^epilogue_using_move" } */ +/* { dg-options "-O2 -mtune-ctrl=^prologue_using_move,^epilogue_using_move -fomit-frame-pointer" } */ typedef void (*fn_t) (void) __attribute__ ((no_callee_saved_registers)); extern fn_t bar; diff --git a/gcc/testsuite/gcc.target/i386/pr38534-4.c b/gcc/testsuite/gcc.target/i386/pr38534-4.c index 561ebee..b204789 100644 --- a/gcc/testsuite/gcc.target/i386/pr38534-4.c +++ b/gcc/testsuite/gcc.target/i386/pr38534-4.c @@ -1,5 +1,5 @@ /* { dg-do compile } */ -/* { dg-options "-O2 -mtune-ctrl=^prologue_using_move,^epilogue_using_move" } */ +/* { dg-options "-O2 -mtune-ctrl=^prologue_using_move,^epilogue_using_move -fomit-frame-pointer" } */ typedef void (*fn_t) (void) __attribute__ ((no_callee_saved_registers)); extern void fn (void) __attribute__ ((noreturn)); -- cgit v1.1 From 099d53e5b5404532e8910d1430f3942c4f07976c Mon Sep 17 00:00:00 2001 From: Rainer Orth Date: Thu, 1 Feb 2024 13:13:06 +0100 Subject: Link shared libasan with -z now on Solaris g++.dg/asan/default-options-1.C FAILs on Solaris/SPARC and x86: FAIL: g++.dg/asan/default-options-1.C -O0 execution test FAIL: g++.dg/asan/default-options-1.C -O1 execution test FAIL: g++.dg/asan/default-options-1.C -O2 execution test FAIL: g++.dg/asan/default-options-1.C -O2 -flto execution test FAIL: g++.dg/asan/default-options-1.C -O2 -flto -flto-partition=none execution test FAIL: g++.dg/asan/default-options-1.C -O3 -g execution test FAIL: g++.dg/asan/default-options-1.C -Os execution test The failure is always the same: AddressSanitizer: CHECK failed: asan_rtl.cpp:397 "((!AsanInitIsRunning() && "ASan init calls itself!")) != (0)" (0x0, 0x0) (tid=1) This happens because libasan makes unportable assumptions about initialization order that don't hold on Solaris. The problem has already been fixed in clang by [Driver] Link shared asan runtime lib with -z now on Solaris/x86 https://reviews.llvm.org/D156325 where it was way more prevalent. This patch applies the same fix to gcc. Tested on i386-pc-solaris2.11 (ld and gld) and sparc-sun-solaris2.11. 2024-01-30 Rainer Orth gcc: * config/sol2.h (LIBASAN_EARLY_SPEC): Add -z now unless -static-libasan. Add missing whitespace. --- gcc/config/sol2.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'gcc') diff --git a/gcc/config/sol2.h b/gcc/config/sol2.h index 5b1d337..85c1f9d 100644 --- a/gcc/config/sol2.h +++ b/gcc/config/sol2.h @@ -255,7 +255,7 @@ along with GCC; see the file COPYING3. If not see " %{!shared:libasan_preinit%O%s} \ %{static-libasan:%{!shared: -Bstatic "\ LD_WHOLE_ARCHIVE_OPTION " -lasan " LD_NO_WHOLE_ARCHIVE_OPTION \ - "-Bdynamic}}%{!static-libasan:-lasan}" + " -Bdynamic}}%{!static-libasan:-z now -lasan}" /* Error out on -fsanitize=thread|leak. */ #define LIBTSAN_EARLY_SPEC "\ -- cgit v1.1 From 5c18df44fd1387653595869c9145c63fffb8cfac Mon Sep 17 00:00:00 2001 From: Monk Chiang Date: Thu, 1 Feb 2024 17:14:18 +0800 Subject: RISC-V: Add minimal support for 7 new unprivileged extensions The RISC-V Profiles specification here: https://github.com/riscv/riscv-profiles/blob/main/profiles.adoc#7-new-isa-extensions These extensions don't add any new features but describe existing features. So this patch only adds parsing. Za64rs: Reservation set size of 64 bytes Za128rs: Reservation set size of 128 bytes Ziccif: Main memory supports instruction fetch with atomicity requirement Ziccrse: Main memory supports forward progress on LR/SC sequences Ziccamoa: Main memory supports all atomics in A Zicclsm: Main memory supports misaligned loads/stores Zic64b: Cache block size isf 64 bytes gcc/ChangeLog: * common/config/riscv/riscv-common.cc: Add Za64rs, Za128rs, Ziccif, Ziccrse, Ziccamoa, Zicclsm, Zic64b items. * config/riscv/riscv.opt: New macro for 7 new unprivileged extensions. * doc/invoke.texi (RISC-V Options): Add Za64rs, Za128rs, Ziccif, Ziccrse, Ziccamoa, Zicclsm, Zic64b extensions. gcc/testsuite/ChangeLog: * gcc.target/riscv/za-ext.c: New test. * gcc.target/riscv/zi-ext.c: New test. --- gcc/common/config/riscv/riscv-common.cc | 14 ++++++++++++++ gcc/config/riscv/riscv.opt | 14 ++++++++++++++ gcc/doc/invoke.texi | 28 ++++++++++++++++++++++++++++ gcc/testsuite/gcc.target/riscv/za-ext.c | 17 +++++++++++++++++ gcc/testsuite/gcc.target/riscv/zi-ext.c | 29 +++++++++++++++++++++++++++++ 5 files changed, 102 insertions(+) create mode 100644 gcc/testsuite/gcc.target/riscv/za-ext.c create mode 100644 gcc/testsuite/gcc.target/riscv/zi-ext.c (limited to 'gcc') diff --git a/gcc/common/config/riscv/riscv-common.cc b/gcc/common/config/riscv/riscv-common.cc index 6ac0422..631ce83 100644 --- a/gcc/common/config/riscv/riscv-common.cc +++ b/gcc/common/config/riscv/riscv-common.cc @@ -247,6 +247,8 @@ static const struct riscv_ext_version riscv_ext_version_table[] = {"zicond", ISA_SPEC_CLASS_NONE, 1, 0}, + {"za64rs", ISA_SPEC_CLASS_NONE, 1, 0}, + {"za128rs", ISA_SPEC_CLASS_NONE, 1, 0}, {"zawrs", ISA_SPEC_CLASS_NONE, 1, 0}, {"zba", ISA_SPEC_CLASS_NONE, 1, 0}, @@ -276,6 +278,11 @@ static const struct riscv_ext_version riscv_ext_version_table[] = {"zicboz",ISA_SPEC_CLASS_NONE, 1, 0}, {"zicbom",ISA_SPEC_CLASS_NONE, 1, 0}, {"zicbop",ISA_SPEC_CLASS_NONE, 1, 0}, + {"zic64b", ISA_SPEC_CLASS_NONE, 1, 0}, + {"ziccamoa", ISA_SPEC_CLASS_NONE, 1, 0}, + {"ziccif", ISA_SPEC_CLASS_NONE, 1, 0}, + {"zicclsm", ISA_SPEC_CLASS_NONE, 1, 0}, + {"ziccrse", ISA_SPEC_CLASS_NONE, 1, 0}, {"zicntr", ISA_SPEC_CLASS_NONE, 2, 0}, {"zihpm", ISA_SPEC_CLASS_NONE, 2, 0}, @@ -1494,6 +1501,8 @@ static const riscv_ext_flag_table_t riscv_ext_flag_table[] = {"zifencei", &gcc_options::x_riscv_zi_subext, MASK_ZIFENCEI}, {"zicond", &gcc_options::x_riscv_zi_subext, MASK_ZICOND}, + {"za64rs", &gcc_options::x_riscv_za_subext, MASK_ZA64RS}, + {"za128rs", &gcc_options::x_riscv_za_subext, MASK_ZA128RS}, {"zawrs", &gcc_options::x_riscv_za_subext, MASK_ZAWRS}, {"zba", &gcc_options::x_riscv_zb_subext, MASK_ZBA}, @@ -1523,6 +1532,11 @@ static const riscv_ext_flag_table_t riscv_ext_flag_table[] = {"zicboz", &gcc_options::x_riscv_zicmo_subext, MASK_ZICBOZ}, {"zicbom", &gcc_options::x_riscv_zicmo_subext, MASK_ZICBOM}, {"zicbop", &gcc_options::x_riscv_zicmo_subext, MASK_ZICBOP}, + {"zic64b", &gcc_options::x_riscv_zicmo_subext, MASK_ZIC64B}, + {"ziccamoa", &gcc_options::x_riscv_zicmo_subext, MASK_ZICCAMOA}, + {"ziccif", &gcc_options::x_riscv_zicmo_subext, MASK_ZICCIF}, + {"zicclsm", &gcc_options::x_riscv_zicmo_subext, MASK_ZICCLSM}, + {"ziccrse", &gcc_options::x_riscv_zicmo_subext, MASK_ZICCRSE}, {"zve32x", &gcc_options::x_target_flags, MASK_VECTOR}, {"zve32f", &gcc_options::x_target_flags, MASK_VECTOR}, diff --git a/gcc/config/riscv/riscv.opt b/gcc/config/riscv/riscv.opt index b6d8e9a..f6ff70b 100644 --- a/gcc/config/riscv/riscv.opt +++ b/gcc/config/riscv/riscv.opt @@ -225,11 +225,25 @@ Mask(ZIHINTPAUSE) Var(riscv_zi_subext) Mask(ZICOND) Var(riscv_zi_subext) +Mask(ZIC64B) Var(riscv_zi_subext) + +Mask(ZICCAMOA) Var(riscv_zi_subext) + +Mask(ZICCIF) Var(riscv_zi_subext) + +Mask(ZICCLSM) Var(riscv_zi_subext) + +Mask(ZICCRSE) Var(riscv_zi_subext) + TargetVariable int riscv_za_subext Mask(ZAWRS) Var(riscv_za_subext) +Mask(ZA64RS) Var(riscv_za_subext) + +Mask(ZA128RS) Var(riscv_za_subext) + TargetVariable int riscv_zb_subext diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi index ca2c0e9..09abd2a 100644 --- a/gcc/doc/invoke.texi +++ b/gcc/doc/invoke.texi @@ -30262,6 +30262,14 @@ Supported extension are listed below: @tab 1.0 @tab Integer conditional operations extension. +@item za64rs +@tab 1.0 +@tab Reservation set size of 64 bytes. + +@item za128rs +@tab 1.0 +@tab Reservation set size of 128 bytes. + @item zawrs @tab 1.0 @tab Wait-on-reservation-set extension. @@ -30370,6 +30378,26 @@ Supported extension are listed below: @tab 1.0 @tab Cache-block prefetch extension. +@item zic64b +@tab 1.0 +@tab Cache block size isf 64 bytes. + +@item ziccamoa +@tab 1.0 +@tab Main memory supports all atomics in A. + +@item ziccif +@tab 1.0 +@tab Main memory supports instruction fetch with atomicity requirement. + +@item zicclsm +@tab 1.0 +@tab Main memory supports misaligned loads/stores. + +@item ziccrse +@tab 1.0 +@tab Main memory supports forward progress on LR/SC sequences. + @item zicntr @tab 2.0 @tab Standard extension for base counters and timers. diff --git a/gcc/testsuite/gcc.target/riscv/za-ext.c b/gcc/testsuite/gcc.target/riscv/za-ext.c new file mode 100644 index 0000000..126da2f --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/za-ext.c @@ -0,0 +1,17 @@ +/* { dg-do compile } */ +/* { dg-options "-march=rv64gc_za64rs_za128rs" { target { rv64 } } } */ +/* { dg-options "-march=rv32gc_za64rs_za128rs" { target { rv32 } } } */ + +#ifndef __riscv_za64rs +#error "Feature macro for 'za64rs' not defined" +#endif + +#ifndef __riscv_za128rs +#error "Feature macro for 'za128rs' not defined" +#endif + +int +foo (int a) +{ + return a; +} diff --git a/gcc/testsuite/gcc.target/riscv/zi-ext.c b/gcc/testsuite/gcc.target/riscv/zi-ext.c new file mode 100644 index 0000000..65a7acb --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/zi-ext.c @@ -0,0 +1,29 @@ +/* { dg-do compile } */ +/* { dg-options "-march=rv64gc_zic64b_ziccamoa_ziccif_zicclsm_ziccrse" { target { rv64 } } } */ +/* { dg-options "-march=rv32gc_zic64b_ziccamoa_ziccif_zicclsm_ziccrse" { target { rv32 } } } */ + +#ifndef __riscv_zic64b +#error "Feature macro for 'zic64b' not defined" +#endif + +#ifndef __riscv_ziccamoa +#error "Feature macro for 'ziccamoa' not defined" +#endif + +#ifndef __riscv_ziccif +#error "Feature macro for 'ziccif' not defined" +#endif + +#ifndef __riscv_zicclsm +#error "Feature macro for 'zicclsm' not defined" +#endif + +#ifndef __riscv_ziccrse +#error "Feature macro for 'ziccrse' not defined" +#endif + +int +foo (int a) +{ + return a; +} -- cgit v1.1 From ec217f7282cd4284cecda1c65a1e04323e6c8354 Mon Sep 17 00:00:00 2001 From: Monk Chiang Date: Thu, 1 Feb 2024 11:01:20 +0800 Subject: RISC-V: Support scheduling for sifive p600 series Add sifive p600 series scheduler module. For more information see https://www.sifive.com/cores/performance-p650-670. Add sifive-p650, sifive-p670 for mcpu option will come in separate patches. gcc/ChangeLog: * config/riscv/riscv.md: Add "fcvt_i2f", "fcvt_f2i" type attribute, and include sifive-p600.md. * config/riscv/generic-ooo.md: Update type attribute. * config/riscv/generic.md: Update type attribute. * config/riscv/sifive-7.md: Update type attribute. * config/riscv/sifive-p600.md: New file. * config/riscv/riscv-cores.def (RISCV_TUNE): Add parameter. * config/riscv/riscv-opts.h (enum riscv_microarchitecture_type): Add sifive_p600. * config/riscv/riscv.cc (sifive_p600_tune_info): New. * config/riscv/riscv.h (TARGET_SFB_ALU): Update. * doc/invoke.texi (RISC-V Options): Add sifive-p600-series --- gcc/config/riscv/generic-ooo.md | 2 +- gcc/config/riscv/generic.md | 2 +- gcc/config/riscv/riscv-cores.def | 1 + gcc/config/riscv/riscv-opts.h | 1 + gcc/config/riscv/riscv.cc | 17 ++++ gcc/config/riscv/riscv.h | 4 +- gcc/config/riscv/riscv.md | 19 +++-- gcc/config/riscv/sifive-7.md | 2 +- gcc/config/riscv/sifive-p600.md | 178 +++++++++++++++++++++++++++++++++++++++ gcc/doc/invoke.texi | 3 +- 10 files changed, 216 insertions(+), 13 deletions(-) create mode 100644 gcc/config/riscv/sifive-p600.md (limited to 'gcc') diff --git a/gcc/config/riscv/generic-ooo.md b/gcc/config/riscv/generic-ooo.md index 421a7bb9..a22f8a3 100644 --- a/gcc/config/riscv/generic-ooo.md +++ b/gcc/config/riscv/generic-ooo.md @@ -127,7 +127,7 @@ (define_insn_reservation "generic_ooo_fcvt" 3 (and (eq_attr "tune" "generic_ooo") - (eq_attr "type" "fcvt")) + (eq_attr "type" "fcvt,fcvt_i2f,fcvt_f2i")) "generic_ooo_issue,generic_ooo_fxu") (define_insn_reservation "generic_ooo_fcmp" 2 diff --git a/gcc/config/riscv/generic.md b/gcc/config/riscv/generic.md index b99ae34..3f0eaa2 100644 --- a/gcc/config/riscv/generic.md +++ b/gcc/config/riscv/generic.md @@ -42,7 +42,7 @@ (define_insn_reservation "generic_xfer" 3 (and (eq_attr "tune" "generic") - (eq_attr "type" "mfc,mtc,fcvt,fmove,fcmp")) + (eq_attr "type" "mfc,mtc,fcvt,fcvt_i2f,fcvt_f2i,fmove,fcmp")) "alu") (define_insn_reservation "generic_branch" 1 diff --git a/gcc/config/riscv/riscv-cores.def b/gcc/config/riscv/riscv-cores.def index b30f4df..a07a79e 100644 --- a/gcc/config/riscv/riscv-cores.def +++ b/gcc/config/riscv/riscv-cores.def @@ -37,6 +37,7 @@ RISCV_TUNE("rocket", generic, rocket_tune_info) RISCV_TUNE("sifive-3-series", generic, rocket_tune_info) RISCV_TUNE("sifive-5-series", generic, rocket_tune_info) RISCV_TUNE("sifive-7-series", sifive_7, sifive_7_tune_info) +RISCV_TUNE("sifive-p600-series", sifive_p600, sifive_p600_tune_info) RISCV_TUNE("thead-c906", generic, thead_c906_tune_info) RISCV_TUNE("generic-ooo", generic_ooo, generic_ooo_tune_info) RISCV_TUNE("size", generic, optimize_size_tune_info) diff --git a/gcc/config/riscv/riscv-opts.h b/gcc/config/riscv/riscv-opts.h index 1500f88..2595166 100644 --- a/gcc/config/riscv/riscv-opts.h +++ b/gcc/config/riscv/riscv-opts.h @@ -55,6 +55,7 @@ extern enum riscv_isa_spec_class riscv_isa_spec; enum riscv_microarchitecture_type { generic, sifive_7, + sifive_p600, generic_ooo }; extern enum riscv_microarchitecture_type riscv_microarchitecture; diff --git a/gcc/config/riscv/riscv.cc b/gcc/config/riscv/riscv.cc index 529ef5e..cead76f 100644 --- a/gcc/config/riscv/riscv.cc +++ b/gcc/config/riscv/riscv.cc @@ -447,6 +447,23 @@ static const struct riscv_tune_param sifive_7_tune_info = { NULL, /* vector cost */ }; +/* Costs to use when optimizing for Sifive p600 Series. */ +static const struct riscv_tune_param sifive_p600_tune_info = { + {COSTS_N_INSNS (4), COSTS_N_INSNS (4)}, /* fp_add */ + {COSTS_N_INSNS (4), COSTS_N_INSNS (4)}, /* fp_mul */ + {COSTS_N_INSNS (20), COSTS_N_INSNS (20)}, /* fp_div */ + {COSTS_N_INSNS (4), COSTS_N_INSNS (4)}, /* int_mul */ + {COSTS_N_INSNS (6), COSTS_N_INSNS (6)}, /* int_div */ + 4, /* issue_rate */ + 4, /* branch_cost */ + 3, /* memory_cost */ + 4, /* fmv_cost */ + true, /* slow_unaligned_access */ + false, /* use_divmod_expansion */ + RISCV_FUSE_LUI_ADDI | RISCV_FUSE_AUIPC_ADDI, /* fusible_ops */ + &generic_vector_cost, /* vector cost */ +}; + /* Costs to use when optimizing for T-HEAD c906. */ static const struct riscv_tune_param thead_c906_tune_info = { {COSTS_N_INSNS (4), COSTS_N_INSNS (5)}, /* fp_add */ diff --git a/gcc/config/riscv/riscv.h b/gcc/config/riscv/riscv.h index 627eba1..e0cb3ba 100644 --- a/gcc/config/riscv/riscv.h +++ b/gcc/config/riscv/riscv.h @@ -896,7 +896,9 @@ extern enum riscv_cc get_riscv_cc (const rtx use); 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 TARGET_SFB_ALU \ + ((riscv_microarchitecture == sifive_7) \ + || (riscv_microarchitecture == sifive_p600)) #define LOGICAL_OP_NON_SHORT_CIRCUIT 0 diff --git a/gcc/config/riscv/riscv.md b/gcc/config/riscv/riscv.md index b320ad0..2a164a0 100644 --- a/gcc/config/riscv/riscv.md +++ b/gcc/config/riscv/riscv.md @@ -314,6 +314,8 @@ ;; fdiv floating point divide ;; fcmp floating point compare ;; fcvt floating point convert +;; fcvt_i2f integer to floating point convert +;; fcvt_f2i floating point to integer convert ;; fsqrt floating point square root ;; multi multiword sequence (or user asm statements) ;; auipc integer addition to PC @@ -466,8 +468,8 @@ (define_attr "type" "unknown,branch,jump,jalr,ret,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,sfb_alu,nop,trap,ghost,bitmanip, - rotate,clmul,min,max,minu,maxu,clz,ctz,cpop, + fmadd,fdiv,fcmp,fcvt,fcvt_i2f,fcvt_f2i,fsqrt,multi,auipc,sfb_alu,nop,trap, + ghost,bitmanip,rotate,clmul,min,max,minu,maxu,clz,ctz,cpop, atomic,condmove,cbo,crypto,pushpop,mvpair,zicond,rdvlenb,rdvl,wrvxrm,wrfrm, rdfrm,vsetvl,vsetvl_pre,vlde,vste,vldm,vstm,vlds,vsts, vldux,vldox,vstux,vstox,vldff,vldr,vstr, @@ -685,7 +687,7 @@ ;; Microarchitectures we know how to tune for. ;; Keep this in sync with enum riscv_microarchitecture. (define_attr "tune" - "generic,sifive_7,generic_ooo" + "generic,sifive_7,sifive_p600,generic_ooo" (const (symbol_ref "((enum attr_tune) riscv_microarchitecture)"))) ;; Describe a user's asm statement. @@ -1973,7 +1975,7 @@ (match_operand:ANYF 1 "register_operand" " f")))] "TARGET_HARD_FLOAT || TARGET_ZFINX" "fcvt.. %0,%1,rtz" - [(set_attr "type" "fcvt") + [(set_attr "type" "fcvt_f2i") (set_attr "mode" "")]) (define_insn "fixuns_trunc2" @@ -1982,7 +1984,7 @@ (match_operand:ANYF 1 "register_operand" " f")))] "TARGET_HARD_FLOAT || TARGET_ZFINX" "fcvt.u. %0,%1,rtz" - [(set_attr "type" "fcvt") + [(set_attr "type" "fcvt_f2i") (set_attr "mode" "")]) (define_insn "float2" @@ -1991,7 +1993,7 @@ (match_operand:GPR 1 "reg_or_0_operand" " rJ")))] "TARGET_HARD_FLOAT || TARGET_ZFINX" "fcvt..\t%0,%z1" - [(set_attr "type" "fcvt") + [(set_attr "type" "fcvt_i2f") (set_attr "mode" "")]) (define_insn "floatuns2" @@ -2000,7 +2002,7 @@ (match_operand:GPR 1 "reg_or_0_operand" " rJ")))] "TARGET_HARD_FLOAT || TARGET_ZFINX" "fcvt..u\t%0,%z1" - [(set_attr "type" "fcvt") + [(set_attr "type" "fcvt_i2f") (set_attr "mode" "")]) (define_insn "l2" @@ -2010,7 +2012,7 @@ RINT))] "TARGET_HARD_FLOAT || TARGET_ZFINX" "fcvt.. %0,%1," - [(set_attr "type" "fcvt") + [(set_attr "type" "fcvt_f2i") (set_attr "mode" "")]) (define_insn "2" @@ -3848,6 +3850,7 @@ (include "pic.md") (include "generic.md") (include "sifive-7.md") +(include "sifive-p600.md") (include "thead.md") (include "generic-ooo.md") (include "vector.md") diff --git a/gcc/config/riscv/sifive-7.md b/gcc/config/riscv/sifive-7.md index a63394c..48bdba4 100644 --- a/gcc/config/riscv/sifive-7.md +++ b/gcc/config/riscv/sifive-7.md @@ -81,7 +81,7 @@ (define_insn_reservation "sifive_7_fp_other" 3 (and (eq_attr "tune" "sifive_7") - (eq_attr "type" "fcvt,fcmp,fmove")) + (eq_attr "type" "fcvt,fcvt_i2f,fcvt_f2i,fcmp,fmove")) "sifive_7_B") (define_insn_reservation "sifive_7_fdiv_s" 27 diff --git a/gcc/config/riscv/sifive-p600.md b/gcc/config/riscv/sifive-p600.md new file mode 100644 index 0000000..c048649 --- /dev/null +++ b/gcc/config/riscv/sifive-p600.md @@ -0,0 +1,178 @@ +;; Scheduling description for Sifive p600 series. + +;; Sifive p600 series is a quad-issue, superscalar, out-of-order processor. + +;; CPU execution units: +;; ialu Integer Units: all arithmetic and logic. +;; +;; bru Branch Resolution Unit: all branches. +;; +;; st Memory Write Unit: all writes to memory. +;; +;; ld Memory Read Unit: all reads from memory. +;; +;; imul Integer Multiply Unit +;; +;; idiv Integer Divide Unit +;; +;; system System Unit: all coprocessor accesses. +;; +;; fpu Floating Point Unit +;; +;; fmul Floating Point Multiply Unit +;; +;; fdiv Floating Point Divide Unit + +;; Four automata are defined to reduce number of states +;; which a single large automaton will have. +(define_automaton "sifive_p600_iex,sifive_p600_fex,sifive_p600_mem,sifive_p600_div") + +;; The Sifive p600 has 7 pipelines: +;; A-pipe Load, Store +;; B1-pipe ALU, Branch +;; B2-pipe ALU, Branch +;; M-pipe ALU, MUL, DIV and I2F(integer to float instruction) +;; C-pipe ALU, Conditional move and system for coprocessor accesses +;; F-pipe FPU, MUL, F2I(float to integer instruction) +;; FM-pipe FPU, MUL, DIV + +(define_cpu_unit "sifive_p600_A" "sifive_p600_mem") +(define_cpu_unit "sifive_p600_B1" "sifive_p600_iex") +(define_cpu_unit "sifive_p600_B2" "sifive_p600_iex") +(define_cpu_unit "sifive_p600_M" "sifive_p600_iex") +(define_cpu_unit "sifive_p600_C" "sifive_p600_iex") +(define_cpu_unit "sifive_p600_F" "sifive_p600_fex") +(define_cpu_unit "sifive_p600_FM" "sifive_p600_fex") + +;; Load and store unit. +(define_cpu_unit "sifive_p600_ld" "sifive_p600_mem") +(define_cpu_unit "sifive_p600_st" "sifive_p600_mem") + +;; Branch unit. +(define_cpu_unit "sifive_p600_bru" "sifive_p600_iex") + +;; Integer and multiply unit. +(define_cpu_unit "sifive_p600_ialu" "sifive_p600_iex") +(define_cpu_unit "sifive_p600_imul" "sifive_p600_iex") +(define_cpu_unit "sifive_p600_system" "sifive_p600_iex") + +;; Divide unit. +(define_cpu_unit "sifive_p600_idiv" "sifive_p600_div") +(define_cpu_unit "sifive_p600_fdiv" "sifive_p600_div") + +;; Float and multiply unit. +(define_cpu_unit "sifive_p600_fmul" "sifive_p600_fex") +(define_cpu_unit "sifive_p600_fpu" "sifive_p600_fex") + +;; ALU instruction can use pipeline C, B1, B2 and M. +(define_reservation "int_pipe" "(sifive_p600_C|sifive_p600_B1|sifive_p600_B2|sifive_p600_M)") +;; FPU instruction can use pipeline F and FM. +(define_reservation "float_pipe" "(sifive_p600_F|sifive_p600_FM)") +;; Branch instruction can use pipeline B1 and B2. +(define_reservation "branch_pipe" "(sifive_p600_B1|sifive_p600_B2)") + +(define_insn_reservation "sifive_p600_load" 3 + (and (eq_attr "tune" "sifive_p600") + (eq_attr "type" "load")) + "sifive_p600_A,sifive_p600_ld*2") + +(define_insn_reservation "sifive_p600_fpload" 4 + (and (eq_attr "tune" "sifive_p600") + (eq_attr "type" "fpload")) + "sifive_p600_A,sifive_p600_ld*3") + +(define_insn_reservation "sifive_p600_store" 1 + (and (eq_attr "tune" "sifive_p600") + (eq_attr "type" "store")) + "sifive_p600_A+sifive_p600_st") + +(define_insn_reservation "sifive_p600_fpstore" 1 + (and (eq_attr "tune" "sifive_p600") + (eq_attr "type" "fpstore")) + "sifive_p600_A+sifive_p600_st") + +(define_insn_reservation "sifive_p600_branch" 1 + (and (eq_attr "tune" "sifive_p600") + (eq_attr "type" "branch,jump,call")) + "branch_pipe+sifive_p600_bru") + +(define_insn_reservation "sifive_p600_sfb_alu" 1 + (and (eq_attr "tune" "sifive_p600") + (eq_attr "type" "sfb_alu")) + "sifive_p600_C+sifive_p600_bru+sifive_p600_ialu") + +(define_insn_reservation "sifive_p600_atomic" 3 + (and (eq_attr "tune" "sifive_p600") + (eq_attr "type" "atomic")) + "sifive_p600_C,sifive_p600_system*2") + +(define_insn_reservation "sifive_p600_mul" 3 + (and (eq_attr "tune" "sifive_p600") + (eq_attr "type" "imul")) + "sifive_p600_M,sifive_p600_imul*2") + +(define_insn_reservation "sifive_p600_div" 16 + (and (eq_attr "tune" "sifive_p600") + (eq_attr "type" "idiv")) + "sifive_p600_M, sifive_p600_idiv*4") + +(define_insn_reservation "sifive_p600_alu" 1 + (and (eq_attr "tune" "sifive_p600") + (eq_attr "type" "unknown,arith,logical,shift,slt,multi,bitmanip,clz,ctz,rotate")) + "int_pipe+sifive_p600_ialu") + +(define_insn_reservation "sifive_p600_cpop" 3 + (and (eq_attr "tune" "sifive_p600") + (eq_attr "type" "cpop")) + "int_pipe,sifive_p600_ialu*2") + +(define_insn_reservation "sifive_p600_load_immediate" 1 + (and (eq_attr "tune" "sifive_p600") + (eq_attr "type" "nop,const,auipc,move")) + "int_pipe") + +(define_insn_reservation "sifive_p600_fma" 4 + (and (eq_attr "tune" "sifive_p600") + (eq_attr "type" "fadd,fmul,fmadd")) + "float_pipe,sifive_p600_fmul*3") + +(define_insn_reservation "sifive_p600_i2f" 2 + (and (eq_attr "tune" "sifive_p600") + (eq_attr "type" "mtc,fcvt_i2f")) + "sifive_p600_M,sifive_p600_ialu") + +(define_insn_reservation "sifive_p600_f2i" 2 + (and (eq_attr "tune" "sifive_p600") + (eq_attr "type" "mfc,fcmp,fcvt_f2i")) + "sifive_p600_F,sifive_p600_fpu") + +(define_insn_reservation "sifive_p600_fmove" 2 + (and (eq_attr "tune" "sifive_p600") + (eq_attr "type" "fmove,fcvt")) + "float_pipe,sifive_p600_fpu") + +(define_insn_reservation "sifive_p600_fdiv_s" 11 + (and (eq_attr "tune" "sifive_p600") + (eq_attr "type" "fdiv,fsqrt") + (eq_attr "mode" "SF")) + "sifive_p600_FM, sifive_p600_fdiv*5") + +(define_insn_reservation "sifive_p600_fdiv_d" 19 + (and (eq_attr "tune" "sifive_p600") + (eq_attr "type" "fdiv,fsqrt") + (eq_attr "mode" "DF")) + "sifive_p600_FM, sifive_p600_fdiv*5") + +(define_bypass 1 "sifive_p600_load,sifive_p600_alu,sifive_p600_mul,sifive_p600_sfb_alu" + "sifive_p600_alu,sifive_p600_branch") + +(define_bypass 1 "sifive_p600_load,sifive_p600_alu,sifive_p600_mul, + sifive_p600_f2i,sifive_p600_fmove,sifive_p600_sfb_alu" + "sifive_p600_store" "riscv_store_data_bypass_p") + +(define_bypass 1 "sifive_p600_i2f" + "sifive_p600_fma,sifive_p600_f2i,sifive_p600_fmove,sifive_p600_fdiv_s,sifive_p600_fdiv_d") + +(define_bypass 1 "sifive_p600_f2i" + "sifive_p600_branch,sifive_p600_sfb_alu,sifive_p600_mul, + sifive_p600_div,sifive_p600_alu,sifive_p600_cpop") diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi index 09abd2a..14730c0 100644 --- a/gcc/doc/invoke.texi +++ b/gcc/doc/invoke.texi @@ -30714,7 +30714,8 @@ Permissible values for this option are: @samp{sifive-e20}, @samp{sifive-e21}, Optimize the output for the given processor, specified by microarchitecture or particular CPU name. Permissible values for this option are: @samp{rocket}, @samp{sifive-3-series}, @samp{sifive-5-series}, @samp{sifive-7-series}, -@samp{thead-c906}, @samp{size}, and all valid options for @option{-mcpu=}. +@samp{thead-c906}, @samp{size}, @samp{sifive-p600-series}, +and all valid options for @option{-mcpu=}. When @option{-mtune=} is not specified, use the setting from @option{-mcpu}, the default is @samp{rocket} if both are not specified. -- cgit v1.1 From 65b105b4f399559685200e1598ead8c7d0935c04 Mon Sep 17 00:00:00 2001 From: Marek Polacek Date: Wed, 31 Jan 2024 17:33:26 -0500 Subject: c++: ICE with throw inside concept [PR112437] We crash in the loop at the end of treat_lvalue_as_rvalue_p for code like template concept Throwable = requires(T x) { throw x; }; because the code assumes that we eventually reach sk_function_parms or sk_try and bail, but in a concept we're in a sk_namespace. We're already checking sk_try so we don't crash in a function-try-block, but I've added a test anyway. PR c++/112437 gcc/cp/ChangeLog: * typeck.cc (treat_lvalue_as_rvalue_p): Bail out on sk_namespace in the move on throw of parms loop. gcc/testsuite/ChangeLog: * g++.dg/cpp2a/concepts-throw1.C: New test. * g++.dg/eh/throw4.C: New test. --- gcc/cp/typeck.cc | 4 +++- gcc/testsuite/g++.dg/cpp2a/concepts-throw1.C | 8 ++++++++ gcc/testsuite/g++.dg/eh/throw4.C | 13 +++++++++++++ 3 files changed, 24 insertions(+), 1 deletion(-) create mode 100644 gcc/testsuite/g++.dg/cpp2a/concepts-throw1.C create mode 100644 gcc/testsuite/g++.dg/eh/throw4.C (limited to 'gcc') diff --git a/gcc/cp/typeck.cc b/gcc/cp/typeck.cc index a15eda3..4937022 100644 --- a/gcc/cp/typeck.cc +++ b/gcc/cp/typeck.cc @@ -10863,7 +10863,9 @@ treat_lvalue_as_rvalue_p (tree expr, bool return_p) for (tree decl = b->names; decl; decl = TREE_CHAIN (decl)) if (decl == retval) return set_implicit_rvalue_p (move (expr)); - if (b->kind == sk_function_parms || b->kind == sk_try) + if (b->kind == sk_function_parms + || b->kind == sk_try + || b->kind == sk_namespace) return NULL_TREE; } } diff --git a/gcc/testsuite/g++.dg/cpp2a/concepts-throw1.C b/gcc/testsuite/g++.dg/cpp2a/concepts-throw1.C new file mode 100644 index 0000000..bc3e3b6 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp2a/concepts-throw1.C @@ -0,0 +1,8 @@ +// PR c++/112437 +// { dg-do compile { target c++20 } } + +struct S {}; +template +concept Throwable = requires(T x) { throw x; }; + +bool a = Throwable; diff --git a/gcc/testsuite/g++.dg/eh/throw4.C b/gcc/testsuite/g++.dg/eh/throw4.C new file mode 100644 index 0000000..b474472 --- /dev/null +++ b/gcc/testsuite/g++.dg/eh/throw4.C @@ -0,0 +1,13 @@ +// PR c++/112437 +// { dg-do compile } + +struct S {}; + +S +foo (S s) +try { + throw s; +} +catch (...) { + throw s; +} -- cgit v1.1 From 019dc63819befb2b82077fb2d76b5dd670946f36 Mon Sep 17 00:00:00 2001 From: Lewis Hyatt Date: Wed, 31 Jan 2024 15:50:11 -0500 Subject: libcpp: Stabilize the location for macros restored after PCH load [PR105608] libcpp currently lacks the infrastructure to assign correct locations to macros that were defined prior to loading a PCH and then restored afterwards. While I plan to address that fully for GCC 15, this patch improves things by using at least a valid location, even if it's not the best one. Without this change, libcpp uses pfile->directive_line as the location for the restored macros, but this location_t applies to the old line map, not the one that was just restored from the PCH, so the resulting location is unpredictable and depends on what was stored in the line maps before. With this change, all restored macros get assigned locations at the line of the #include that triggered the PCH restore. A future patch will store the actual file name and line number of each definition and then synthesize locations in the new line map pointing to the right place. gcc/c-family/ChangeLog: PR preprocessor/105608 * c-pch.cc (c_common_read_pch): Adjust line map so that libcpp assigns a location to restored macros which is the same location that triggered the PCH include. libcpp/ChangeLog: PR preprocessor/105608 * pch.cc (cpp_read_state): Set a valid location for restored macros. --- gcc/c-family/c-pch.cc | 23 +++++++++++++++-------- 1 file changed, 15 insertions(+), 8 deletions(-) (limited to 'gcc') diff --git a/gcc/c-family/c-pch.cc b/gcc/c-family/c-pch.cc index 79b4f88..9bcfdc8 100644 --- a/gcc/c-family/c-pch.cc +++ b/gcc/c-family/c-pch.cc @@ -318,6 +318,7 @@ c_common_read_pch (cpp_reader *pfile, const char *name, struct save_macro_data *smd; expanded_location saved_loc; bool saved_trace_includes; + int cpp_result; timevar_push (TV_PCH_RESTORE); @@ -343,20 +344,26 @@ c_common_read_pch (cpp_reader *pfile, const char *name, cpp_set_line_map (pfile, line_table); rebuild_location_adhoc_htab (line_table); line_table->trace_includes = saved_trace_includes; - linemap_add (line_table, LC_ENTER, 0, saved_loc.file, saved_loc.line); + + /* Set the current location to the line containing the #include (or the + #pragma GCC pch_preprocess) for the purpose of assigning locations to any + macros that are about to be restored. */ + linemap_add (line_table, LC_ENTER, 0, saved_loc.file, + saved_loc.line > 1 ? saved_loc.line - 1 : saved_loc.line); timevar_push (TV_PCH_CPP_RESTORE); - if (cpp_read_state (pfile, name, f, smd) != 0) - { - fclose (f); - timevar_pop (TV_PCH_CPP_RESTORE); - goto end; - } - timevar_pop (TV_PCH_CPP_RESTORE); + cpp_result = cpp_read_state (pfile, name, f, smd); + /* Set the current location to the line following the #include, where we + were prior to processing the PCH. */ + linemap_line_start (line_table, saved_loc.line, 0); + timevar_pop (TV_PCH_CPP_RESTORE); fclose (f); + if (cpp_result != 0) + goto end; + /* Give the front end a chance to take action after a PCH file has been loaded. */ if (lang_post_pch_load) -- cgit v1.1 From a5eb246e04d08ee6d7de06a2389fc3b541ecdde9 Mon Sep 17 00:00:00 2001 From: Thomas Schwinge Date: Wed, 31 Jan 2024 11:56:59 +0100 Subject: GCN: Don't hard-code number of SGPR/VGPR/AVGPR registers Also add 'STATIC_ASSERT's for number of SGPR/VGPR/AVGPR registers (in '#ifndef USED_FOR_TARGET', as otherwise 'STATIC_ASSERT' isn't available). gcc/ * config/gcn/gcn.cc (gcn_hsa_declare_function_name): Don't hard-code number of SGPR/VGPR/AVGPR registers. * config/gcn/gcn.h: Add a 'STATIC_ASSERT's for number of SGPR/VGPR/AVGPR registers. --- gcc/config/gcn/gcn.cc | 6 +++--- gcc/config/gcn/gcn.h | 15 ++++++++++++--- 2 files changed, 15 insertions(+), 6 deletions(-) (limited to 'gcc') diff --git a/gcc/config/gcn/gcn.cc b/gcc/config/gcn/gcn.cc index e80de2c..20be455 100644 --- a/gcc/config/gcn/gcn.cc +++ b/gcc/config/gcn/gcn.cc @@ -6585,15 +6585,15 @@ gcn_hsa_declare_function_name (FILE *file, const char *name, /* Determine count of sgpr/vgpr registers by looking for last one used. */ - for (sgpr = 101; sgpr >= 0; sgpr--) + for (sgpr = LAST_SGPR_REG - FIRST_SGPR_REG; sgpr >= 0; sgpr--) if (df_regs_ever_live_p (FIRST_SGPR_REG + sgpr)) break; sgpr++; - for (vgpr = 255; vgpr >= 0; vgpr--) + for (vgpr = LAST_VGPR_REG - FIRST_VGPR_REG; vgpr >= 0; vgpr--) if (df_regs_ever_live_p (FIRST_VGPR_REG + vgpr)) break; vgpr++; - for (avgpr = 255; avgpr >= 0; avgpr--) + for (avgpr = LAST_AVGPR_REG - FIRST_AVGPR_REG; avgpr >= 0; avgpr--) if (df_regs_ever_live_p (FIRST_AVGPR_REG + avgpr)) break; avgpr++; diff --git a/gcc/config/gcn/gcn.h b/gcc/config/gcn/gcn.h index efe3c91..a17f16a 100644 --- a/gcc/config/gcn/gcn.h +++ b/gcc/config/gcn/gcn.h @@ -146,14 +146,23 @@ #define EXEC_HI_REG 127 #define EXECZ_REG 128 #define SCC_REG 129 + /* 132-159 are reserved to simplify masks. */ + #define FIRST_VGPR_REG 160 #define VGPR_REGNO(N) ((N)+FIRST_VGPR_REG) #define LAST_VGPR_REG 415 + #define FIRST_AVGPR_REG 416 #define AVGPR_REGNO(N) ((N)+FIRST_AVGPR_REG) #define LAST_AVGPR_REG 671 +#ifndef USED_FOR_TARGET +STATIC_ASSERT (LAST_SGPR_REG + 1 - FIRST_SGPR_REG == 102); +STATIC_ASSERT (LAST_VGPR_REG + 1 - FIRST_VGPR_REG == 256); +STATIC_ASSERT (LAST_AVGPR_REG + 1 - FIRST_AVGPR_REG == 256); +#endif /* USED_FOR_TARGET */ + /* Frame Registers, and other registers */ #define HARD_FRAME_POINTER_REGNUM 14 @@ -180,9 +189,9 @@ #define HARD_FRAME_POINTER_IS_ARG_POINTER 0 #define HARD_FRAME_POINTER_IS_FRAME_POINTER 0 -#define SGPR_REGNO_P(N) ((N) <= LAST_SGPR_REG) -#define VGPR_REGNO_P(N) ((N)>=FIRST_VGPR_REG && (N) <= LAST_VGPR_REG) -#define AVGPR_REGNO_P(N) ((N)>=FIRST_AVGPR_REG && (N) <= LAST_AVGPR_REG) +#define SGPR_REGNO_P(N) ((N) >= FIRST_SGPR_REG && (N) <= LAST_SGPR_REG) +#define VGPR_REGNO_P(N) ((N) >= FIRST_VGPR_REG && (N) <= LAST_VGPR_REG) +#define AVGPR_REGNO_P(N) ((N) >= FIRST_AVGPR_REG && (N) <= LAST_AVGPR_REG) #define SSRC_REGNO_P(N) ((N) <= SCC_REG && (N) != VCCZ_REG) #define SDST_REGNO_P(N) ((N) <= EXEC_HI_REG && (N) != VCCZ_REG) #define CC_REG_P(X) (REG_P (X) && CC_REGNO_P (REGNO (X))) -- cgit v1.1 From 4571b4d413a4ba5f1e2d429a2623180ad1c73c0f Mon Sep 17 00:00:00 2001 From: Richard Ball Date: Thu, 1 Feb 2024 17:18:28 +0000 Subject: middle-end: Fix ICE in poly-int.h due to SLP. Adds a check to ensure that the input vector arguments to a function are not variable length. Previously, only the output vector of a function was checked. The ICE in question is within the neon-sve-bridge.c test, and is related to https://gcc.gnu.org/bugzilla/show_bug.cgi?id=111268 gcc/ChangeLog: PR tree-optimization/111268 * tree-vect-slp.cc (vectorizable_slp_permutation_1): Add variable-length check for vector input arguments to a function. --- gcc/tree-vect-slp.cc | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'gcc') diff --git a/gcc/tree-vect-slp.cc b/gcc/tree-vect-slp.cc index 086377a..7cf9504 100644 --- a/gcc/tree-vect-slp.cc +++ b/gcc/tree-vect-slp.cc @@ -8987,7 +8987,8 @@ vectorizable_slp_permutation_1 (vec_info *vinfo, gimple_stmt_iterator *gsi, { /* Calculate every element of every permute mask vector explicitly, instead of relying on the pattern described above. */ - if (!nunits.is_constant (&npatterns)) + if (!nunits.is_constant (&npatterns) + || !TYPE_VECTOR_SUBPARTS (op_vectype).is_constant ()) return -1; nelts_per_pattern = ncopies = 1; if (loop_vec_info linfo = dyn_cast (vinfo)) -- cgit v1.1 From a886a90625a4ba5e1cc3270e69735cc4fe51f19c Mon Sep 17 00:00:00 2001 From: Georg-Johann Lay Date: Wed, 31 Jan 2024 11:37:08 +0100 Subject: AVR: Tabify avr.cc gcc/ * config/avr/avr.cc: Tabify. --- gcc/config/avr/avr.cc | 7434 ++++++++++++++++++++++++------------------------- 1 file changed, 3717 insertions(+), 3717 deletions(-) (limited to 'gcc') diff --git a/gcc/config/avr/avr.cc b/gcc/config/avr/avr.cc index d77e1aad..d21b286 100644 --- a/gcc/config/avr/avr.cc +++ b/gcc/config/avr/avr.cc @@ -147,12 +147,12 @@ static avr_addr_t avr_addr; /* Prototypes for local helper functions. */ -static const char* out_movqi_r_mr (rtx_insn *, rtx[], int*); -static const char* out_movhi_r_mr (rtx_insn *, rtx[], int*); -static const char* out_movsi_r_mr (rtx_insn *, rtx[], int*); -static const char* out_movqi_mr_r (rtx_insn *, rtx[], int*); -static const char* out_movhi_mr_r (rtx_insn *, rtx[], int*); -static const char* out_movsi_mr_r (rtx_insn *, rtx[], int*); +static const char *out_movqi_r_mr (rtx_insn *, rtx[], int *); +static const char *out_movhi_r_mr (rtx_insn *, rtx[], int *); +static const char *out_movsi_r_mr (rtx_insn *, rtx[], int *); +static const char *out_movqi_mr_r (rtx_insn *, rtx[], int *); +static const char *out_movhi_mr_r (rtx_insn *, rtx[], int *); +static const char *out_movsi_mr_r (rtx_insn *, rtx[], int *); static int get_sequence_length (rtx_insn *insns); static int sequent_regs_live (void); @@ -160,14 +160,14 @@ static const char *ptrreg_to_str (int); static const char *cond_string (enum rtx_code); static int avr_num_arg_regs (machine_mode, const_tree); static int avr_operand_rtx_cost (rtx, machine_mode, enum rtx_code, - int, bool); -static void output_reload_in_const (rtx*, rtx, int*, bool); -static struct machine_function * avr_init_machine_status (void); + int, bool); +static void output_reload_in_const (rtx *, rtx, int *, bool); +static struct machine_function *avr_init_machine_status (void); /* Prototypes for hook implementors if needed before their implementation. */ -static bool avr_rtx_costs (rtx, machine_mode, int, int, int*, bool); +static bool avr_rtx_costs (rtx, machine_mode, int, int, int *, bool); /* Allocate registers from r25 to r8 for parameters for function calls. */ @@ -239,7 +239,7 @@ bool avr_has_rodata_p = false; /* Transform UP into lowercase and write the result to LO. You must provide enough space for LO. Return LO. */ -static char* +static char * avr_tolower (char *lo, const char *up) { char *lo0 = lo; @@ -272,7 +272,7 @@ avr_popcount_each_byte (rtx xval, int n_bytes, int pop_mask) unsigned int val8 = UINTVAL (xval8) & GET_MODE_MASK (QImode); if ((pop_mask & (1 << popcount_hwi (val8))) == 0) - return false; + return false; } return true; @@ -317,7 +317,7 @@ public: this->name = name; } - virtual unsigned int execute (function*) + virtual unsigned int execute (function *) { df_note_add_problem (); df_analyze (); @@ -349,9 +349,9 @@ public: this->name = name; } - void avr_rest_of_handle_casesi (function*); + void avr_rest_of_handle_casesi (function *); - virtual bool gate (function*) { return optimize > 0; } + virtual bool gate (function *) { return optimize > 0; } virtual unsigned int execute (function *func) { @@ -384,9 +384,9 @@ public: this->name = name; } - void avr_rest_of_handle_ifelse (function*); + void avr_rest_of_handle_ifelse (function *); - virtual bool gate (function*) { return optimize > 0; } + virtual bool gate (function *) { return optimize > 0; } virtual unsigned int execute (function *func) { @@ -398,19 +398,19 @@ public: } // anon namespace -rtl_opt_pass* +rtl_opt_pass * make_avr_pass_recompute_notes (gcc::context *ctxt) { return new avr_pass_recompute_notes (ctxt, "avr-notes-free-cfg"); } -rtl_opt_pass* +rtl_opt_pass * make_avr_pass_casesi (gcc::context *ctxt) { return new avr_pass_casesi (ctxt, "avr-casesi"); } -rtl_opt_pass* +rtl_opt_pass * make_avr_pass_ifelse (gcc::context *ctxt) { return new avr_pass_ifelse (ctxt, "avr-ifelse"); @@ -419,11 +419,11 @@ make_avr_pass_ifelse (gcc::context *ctxt) /* Make one parallel insn with all the patterns from insns i[0]..i[5]. */ -static rtx_insn* +static rtx_insn * avr_parallel_insn_from_insns (rtx_insn *i[5]) { rtvec vec = gen_rtvec (5, PATTERN (i[0]), PATTERN (i[1]), PATTERN (i[2]), - PATTERN (i[3]), PATTERN (i[4])); + PATTERN (i[3]), PATTERN (i[4])); start_sequence(); emit (gen_rtx_PARALLEL (VOIDmode, vec)); rtx_insn *insn = get_insns(); @@ -449,21 +449,21 @@ avr_is_casesi_sequence (basic_block bb, rtx_insn *insn, rtx_insn *insns[5]) the test, harvest respective insns to INSNS[0..4]. */ if (!(JUMP_P (insns[4] = insn) - // casesi is the only insn that comes up with UNSPEC_INDEX_JMP, - // hence the following test ensures that we are actually dealing - // with code from casesi. - && (set_4 = single_set (insns[4])) - && UNSPEC == GET_CODE (SET_SRC (set_4)) - && UNSPEC_INDEX_JMP == XINT (SET_SRC (set_4), 1) - - && (insns[3] = prev_real_insn (insns[4])) - && (insns[2] = prev_real_insn (insns[3])) - && (insns[1] = prev_real_insn (insns[2])) - - // Insn prior to casesi. - && (insns[0] = prev_real_insn (insns[1])) - && (set_0 = single_set (insns[0])) - && extend_operator (SET_SRC (set_0), SImode))) + // casesi is the only insn that comes up with UNSPEC_INDEX_JMP, + // hence the following test ensures that we are actually dealing + // with code from casesi. + && (set_4 = single_set (insns[4])) + && UNSPEC == GET_CODE (SET_SRC (set_4)) + && UNSPEC_INDEX_JMP == XINT (SET_SRC (set_4), 1) + + && (insns[3] = prev_real_insn (insns[4])) + && (insns[2] = prev_real_insn (insns[3])) + && (insns[1] = prev_real_insn (insns[2])) + + // Insn prior to casesi. + && (insns[0] = prev_real_insn (insns[1])) + && (set_0 = single_set (insns[0])) + && extend_operator (SET_SRC (set_0), SImode))) { return false; } @@ -471,9 +471,9 @@ avr_is_casesi_sequence (basic_block bb, rtx_insn *insn, rtx_insn *insns[5]) if (dump_file) { fprintf (dump_file, ";; Sequence from casesi in " - "[bb %d]:\n\n", bb->index); + "[bb %d]:\n\n", bb->index); for (int i = 0; i < 5; i++) - print_rtl_single (dump_file, insns[i]); + print_rtl_single (dump_file, insns[i]); } /* We have to deal with quite some operands. Extracting them by hand @@ -491,13 +491,13 @@ avr_is_casesi_sequence (basic_block bb, rtx_insn *insn, rtx_insn *insns[5]) if (INSN_CODE (xinsn) < 0) { if (dump_file) - fprintf (dump_file, ";; Sequence not recognized, giving up.\n\n"); + fprintf (dump_file, ";; Sequence not recognized, giving up.\n\n"); return false; } gcc_assert (CODE_FOR_casesi_qi_sequence == INSN_CODE (xinsn) - || CODE_FOR_casesi_hi_sequence == INSN_CODE (xinsn)); + || CODE_FOR_casesi_hi_sequence == INSN_CODE (xinsn)); extract_insn (xinsn); @@ -510,7 +510,7 @@ avr_is_casesi_sequence (basic_block bb, rtx_insn *insn, rtx_insn *insns[5]) { fprintf (dump_file, ";; Operands extracted:\n"); for (int i = 0; i < recog_data.n_operands; i++) - avr_fdump (dump_file, ";; $%d = %r\n", i, recog_data.operand[i]); + avr_fdump (dump_file, ";; $%d = %r\n", i, recog_data.operand[i]); fprintf (dump_file, "\n"); } @@ -539,7 +539,7 @@ avr_casei_sequence_check_operands (rtx *xop) if (!AVR_HAVE_EIJMP_EICALL // $6 is: (plus:HI (subreg:SI ($5) 0) - // (label_ref ($3))) + // (label_ref ($3))) && PLUS == GET_CODE (xop[6]) && LABEL_REF == GET_CODE (XEXP (xop[6], 1)) && rtx_equal_p (xop[3], XEXP (XEXP (xop[6], 1), 0)) @@ -574,7 +574,7 @@ avr_casei_sequence_check_operands (rtx *xop) $4: Label if out-of-bounds. $5: $0 + $1. $6: 3-byte PC: subreg:HI ($5) + label_ref ($3) - 2-byte PC: subreg:HI ($5) + 2-byte PC: subreg:HI ($5) $7: HI reg index into table (Z or pseudo) $8: R24 or const0_rtx (to be clobbered) $9: Extension to SImode of an 8-bit or 16-bit integer register $10. @@ -617,15 +617,15 @@ avr_optimize_casesi (rtx_insn *insns[5], rtx *xop) // ok } else if (ZERO_EXTEND == code - && low_idx >= 0 - && (unsigned) hig_idx <= umax) + && low_idx >= 0 + && (unsigned) hig_idx <= umax) { // ok } else { if (dump_file) - fprintf (dump_file, ";; Case ranges too big, giving up.\n\n"); + fprintf (dump_file, ";; Case ranges too big, giving up.\n\n"); return; } @@ -684,21 +684,21 @@ avr_optimize_casesi (rtx_insn *insns[5], rtx *xop) fprintf (dump_file, ";; New insns: "); for (rtx_insn *insn = seq1; ; insn = NEXT_INSN (insn)) - { - fprintf (dump_file, "%d, ", INSN_UID (insn)); - if (insn == last1) - break; - } + { + fprintf (dump_file, "%d, ", INSN_UID (insn)); + if (insn == last1) + break; + } for (rtx_insn *insn = seq2; ; insn = NEXT_INSN (insn)) - { - fprintf (dump_file, "%d%s", INSN_UID (insn), - insn == last2 ? ".\n\n" : ", "); - if (insn == last2) - break; - } + { + fprintf (dump_file, "%d%s", INSN_UID (insn), + insn == last2 ? ".\n\n" : ", "); + if (insn == last2) + break; + } fprintf (dump_file, ";; Deleting insns: %d, %d, %d.\n\n", - INSN_UID (insns[1]), INSN_UID (insns[2]), INSN_UID (insns[3])); + INSN_UID (insns[1]), INSN_UID (insns[2]), INSN_UID (insns[3])); } // Pseudodelete the SImode and subreg of SImode insns. We don't care @@ -721,12 +721,12 @@ avr_pass_casesi::avr_rest_of_handle_casesi (function *func) rtx_insn *insn, *insns[5]; FOR_BB_INSNS (bb, insn) - { - if (avr_is_casesi_sequence (bb, insn, insns)) - { - avr_optimize_casesi (insns, recog_data.operand); - } - } + { + if (avr_is_casesi_sequence (bb, insn, insns)) + { + avr_optimize_casesi (insns, recog_data.operand); + } + } } } @@ -862,7 +862,7 @@ avr_redundant_compare (enum rtx_code cond1, rtx xval1, Hence, run a mini pass right before split2 which introduces REG_CC. */ void -avr_pass_ifelse::avr_rest_of_handle_ifelse (function*) +avr_pass_ifelse::avr_rest_of_handle_ifelse (function *) { rtx_insn *next_insn; @@ -1045,28 +1045,28 @@ avr_set_core_architecture (void) for (const avr_mcu_t *mcu = avr_mcu_types; ; mcu++) { if (mcu->name == NULL) - { - /* Reached the end of `avr_mcu_types'. This should actually never - happen as options are provided by device-specs. It could be a - typo in a device-specs or calling the compiler proper directly - with -mmcu=. */ - - error ("unknown core architecture %qs specified with %qs", - avr_mmcu, "-mmcu="); - avr_inform_core_architectures (); - break; - } + { + /* Reached the end of `avr_mcu_types'. This should actually never + happen as options are provided by device-specs. It could be a + typo in a device-specs or calling the compiler proper directly + with -mmcu=. */ + + error ("unknown core architecture %qs specified with %qs", + avr_mmcu, "-mmcu="); + avr_inform_core_architectures (); + break; + } else if (strcmp (mcu->name, avr_mmcu) == 0 - // Is this a proper architecture ? + // Is this a proper architecture ? && mcu->macro == NULL) - { - avr_arch = &avr_arch_types[mcu->arch_id]; + { + avr_arch = &avr_arch_types[mcu->arch_id]; avr_arch_index = mcu->arch_id; - if (avr_n_flash < 0) - avr_n_flash = 1 + (mcu->flash_size - 1) / 0x10000; + if (avr_n_flash < 0) + avr_n_flash = 1 + (mcu->flash_size - 1) / 0x10000; - return true; - } + return true; + } } return false; @@ -1278,7 +1278,7 @@ bool avr_mem_flash_p (rtx x) { return (MEM_P (x) - && !ADDR_SPACE_GENERIC_P (MEM_ADDR_SPACE (x))); + && !ADDR_SPACE_GENERIC_P (MEM_ADDR_SPACE (x))); } @@ -1289,7 +1289,7 @@ bool avr_mem_memx_p (rtx x) { return (MEM_P (x) - && ADDR_SPACE_MEMX == MEM_ADDR_SPACE (x)); + && ADDR_SPACE_MEMX == MEM_ADDR_SPACE (x)); } @@ -1302,9 +1302,9 @@ avr_lookup_function_attribute1 (const_tree func, const char *name) if (FUNCTION_DECL == TREE_CODE (func)) { if (NULL_TREE != lookup_attribute (name, DECL_ATTRIBUTES (func))) - { - return true; - } + { + return true; + } func = TREE_TYPE (func); } @@ -1408,12 +1408,12 @@ avr_set_current_function (tree decl) if (cfun->machine->is_OS_task && (cfun->machine->is_signal || cfun->machine->is_interrupt)) error_at (loc, "function attributes %qs and %qs are mutually exclusive", - "OS_task", isr); + "OS_task", isr); if (cfun->machine->is_OS_main && (cfun->machine->is_signal || cfun->machine->is_interrupt)) error_at (loc, "function attributes %qs and %qs are mutually exclusive", - "OS_main", isr); + "OS_main", isr); if (cfun->machine->is_interrupt || cfun->machine->is_signal) { @@ -1422,36 +1422,36 @@ avr_set_current_function (tree decl) const char *name; name = DECL_ASSEMBLER_NAME_SET_P (decl) - ? IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (decl)) - : IDENTIFIER_POINTER (DECL_NAME (decl)); + ? IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (decl)) + : IDENTIFIER_POINTER (DECL_NAME (decl)); /* Skip a leading '*' that might still prefix the assembler name, - e.g. in non-LTO runs. */ + e.g. in non-LTO runs. */ name = default_strip_name_encoding (name); /* Interrupt handlers must be void __vector (void) functions. */ if (args && TREE_CODE (TREE_VALUE (args)) != VOID_TYPE) - error_at (loc, "%qs function cannot have arguments", isr); + error_at (loc, "%qs function cannot have arguments", isr); if (TREE_CODE (ret) != VOID_TYPE) - error_at (loc, "%qs function cannot return a value", isr); + error_at (loc, "%qs function cannot return a value", isr); #if defined WITH_AVRLIBC /* Silently ignore 'signal' if 'interrupt' is present. AVR-LibC startet - using this when it switched from SIGNAL and INTERRUPT to ISR. */ + using this when it switched from SIGNAL and INTERRUPT to ISR. */ if (cfun->machine->is_interrupt) - cfun->machine->is_signal = 0; + cfun->machine->is_signal = 0; /* If the function has the 'signal' or 'interrupt' attribute, ensure - that the name of the function is "__vector_NN" so as to catch - when the user misspells the vector name. */ + that the name of the function is "__vector_NN" so as to catch + when the user misspells the vector name. */ if (!startswith (name, "__vector")) - warning_at (loc, OPT_Wmisspelled_isr, "%qs appears to be a misspelled " - "%qs handler, missing %<__vector%> prefix", name, isr); + warning_at (loc, OPT_Wmisspelled_isr, "%qs appears to be a misspelled " + "%qs handler, missing %<__vector%> prefix", name, isr); #endif // AVR-LibC naming conventions } @@ -1464,8 +1464,8 @@ avr_set_current_function (tree decl) || strcmp ("SIGNAL", name) == 0) { warning_at (loc, OPT_Wmisspelled_isr, "%qs is a reserved identifier" - " in AVR-LibC. Consider %<#include %>" - " before using the %qs macro", name, name); + " in AVR-LibC. Consider %<#include %>" + " before using the %qs macro", name, name); } #endif // AVR-LibC naming conventions @@ -1484,15 +1484,15 @@ avr_accumulate_outgoing_args (void) return TARGET_ACCUMULATE_OUTGOING_ARGS; /* FIXME: For setjmp and in avr_builtin_setjmp_frame_value we don't know - what offset is correct. In some cases it is relative to - virtual_outgoing_args_rtx and in others it is relative to - virtual_stack_vars_rtx. For example code see - gcc.c-torture/execute/built-in-setjmp.c - gcc.c-torture/execute/builtins/sprintf-chk.c */ + what offset is correct. In some cases it is relative to + virtual_outgoing_args_rtx and in others it is relative to + virtual_stack_vars_rtx. For example code see + gcc.c-torture/execute/built-in-setjmp.c + gcc.c-torture/execute/builtins/sprintf-chk.c */ return (TARGET_ACCUMULATE_OUTGOING_ARGS - && !(cfun->calls_setjmp - || cfun->has_nonlocal_label)); + && !(cfun->calls_setjmp + || cfun->has_nonlocal_label)); } @@ -1541,23 +1541,23 @@ avr_regs_to_save (HARD_REG_SET *set) for (int reg = 0; reg < 32; reg++) { /* Do not push/pop __tmp_reg__, __zero_reg__, as well as - any global register variables. */ + any global register variables. */ if (fixed_regs[reg]) - continue; + continue; if ((int_or_sig_p && !crtl->is_leaf && call_used_or_fixed_reg_p (reg)) - || (df_regs_ever_live_p (reg) - && (int_or_sig_p || !call_used_or_fixed_reg_p (reg)) - /* Don't record frame pointer registers here. They are treated - indivitually in prologue. */ - && !(frame_pointer_needed - && (reg == REG_Y || reg == REG_Y + 1)))) - { - if (set) - SET_HARD_REG_BIT (*set, reg); - count++; - } + || (df_regs_ever_live_p (reg) + && (int_or_sig_p || !call_used_or_fixed_reg_p (reg)) + /* Don't record frame pointer registers here. They are treated + indivitually in prologue. */ + && !(frame_pointer_needed + && (reg == REG_Y || reg == REG_Y + 1)))) + { + if (set) + SET_HARD_REG_BIT (*set, reg); + count++; + } } return count; } @@ -1578,7 +1578,7 @@ static bool avr_can_eliminate (const int from ATTRIBUTE_UNUSED, const int to) { return ((frame_pointer_needed && to == FRAME_POINTER_REGNUM) - || !frame_pointer_needed); + || !frame_pointer_needed); } @@ -1610,7 +1610,7 @@ avr_initial_elimination_offset (int from, int to) // by gasisr prologues. offset += avr_regs_to_save (NULL); return (get_frame_size () + avr_outgoing_args_size() - + avr_pc_size + 1 + offset); + + avr_pc_size + 1 + offset); } } @@ -1681,7 +1681,7 @@ avr_return_addr_rtx (int count, rtx tem) { r = gen_rtx_SYMBOL_REF (Pmode, ".L__stack_usage+2"); warning (0, "% contains only 2 bytes" - " of address"); + " of address"); } else r = gen_rtx_SYMBOL_REF (Pmode, ".L__stack_usage+1"); @@ -1700,13 +1700,13 @@ int avr_simple_epilogue (void) { return (! frame_pointer_needed - && get_frame_size () == 0 - && avr_outgoing_args_size() == 0 - && avr_regs_to_save (NULL) == 0 - && ! cfun->machine->is_interrupt - && ! cfun->machine->is_signal - && ! cfun->machine->is_naked - && ! TREE_THIS_VOLATILE (current_function_decl)); + && get_frame_size () == 0 + && avr_outgoing_args_size() == 0 + && avr_regs_to_save (NULL) == 0 + && ! cfun->machine->is_interrupt + && ! cfun->machine->is_signal + && ! cfun->machine->is_naked + && ! TREE_THIS_VOLATILE (current_function_decl)); } /* This function checks sequence of live registers. */ @@ -1720,45 +1720,45 @@ sequent_regs_live (void) for (int reg = 0; reg <= LAST_CALLEE_SAVED_REG; ++reg) { if (fixed_regs[reg]) - { - /* Don't recognize sequences that contain global register - variables. */ + { + /* Don't recognize sequences that contain global register + variables. */ - if (live_seq != 0) - return 0; - else - continue; - } + if (live_seq != 0) + return 0; + else + continue; + } if (!call_used_or_fixed_reg_p (reg)) - { - if (df_regs_ever_live_p (reg)) - { - ++live_seq; - ++cur_seq; - } - else - cur_seq = 0; - } + { + if (df_regs_ever_live_p (reg)) + { + ++live_seq; + ++cur_seq; + } + else + cur_seq = 0; + } } if (!frame_pointer_needed) { if (df_regs_ever_live_p (REG_Y)) - { - ++live_seq; - ++cur_seq; - } + { + ++live_seq; + ++cur_seq; + } else - cur_seq = 0; + cur_seq = 0; if (df_regs_ever_live_p (REG_Y + 1)) - { - ++live_seq; - ++cur_seq; - } + { + ++live_seq; + ++cur_seq; + } else - cur_seq = 0; + cur_seq = 0; } else { @@ -1772,14 +1772,14 @@ namespace { static const pass_data avr_pass_data_pre_proep = { RTL_PASS, // type - "", // name (will be patched) + "", // name (will be patched) OPTGROUP_NONE, // optinfo_flags TV_DF_SCAN, // tv_id - 0, // properties_required - 0, // properties_provided - 0, // properties_destroyed - 0, // todo_flags_start - 0 // todo_flags_finish + 0, // properties_required + 0, // properties_provided + 0, // properties_destroyed + 0, // todo_flags_start + 0 // todo_flags_finish }; @@ -1792,22 +1792,22 @@ public: this->name = name; } - void compute_maybe_gasisr (function*); + void compute_maybe_gasisr (function *); virtual unsigned int execute (function *fun) { if (avr_gasisr_prologues - // Whether this function is an ISR worth scanning at all. - && !fun->machine->is_no_gccisr - && (fun->machine->is_interrupt - || fun->machine->is_signal) - && !cfun->machine->is_naked - // Paranoia: Non-local gotos and labels that might escape. - && !cfun->calls_setjmp - && !cfun->has_nonlocal_label - && !cfun->has_forced_label_in_static) + // Whether this function is an ISR worth scanning at all. + && !fun->machine->is_no_gccisr + && (fun->machine->is_interrupt + || fun->machine->is_signal) + && !cfun->machine->is_naked + // Paranoia: Non-local gotos and labels that might escape. + && !cfun->calls_setjmp + && !cfun->has_nonlocal_label + && !cfun->has_forced_label_in_static) { - compute_maybe_gasisr (fun); + compute_maybe_gasisr (fun); } return 0; @@ -1817,7 +1817,7 @@ public: } // anon namespace -rtl_opt_pass* +rtl_opt_pass * make_avr_pass_pre_proep (gcc::context *ctxt) { return new avr_pass_pre_proep (ctxt, "avr-pre-proep"); @@ -1839,20 +1839,20 @@ avr_pass_pre_proep::compute_maybe_gasisr (function *fun) // out are open coded (tail) calls. if (CALL_P (insn)) - return; + return; // __tablejump2__ clobbers something and is targeted by JMP so // that GAS won't see its usage. if (AVR_HAVE_JMP_CALL - && JUMP_TABLE_DATA_P (insn)) - return; + && JUMP_TABLE_DATA_P (insn)) + return; // Non-local gotos not seen in *FUN. if (JUMP_P (insn) - && find_reg_note (insn, REG_NON_LOCAL_GOTO, NULL_RTX)) - return; + && find_reg_note (insn, REG_NON_LOCAL_GOTO, NULL_RTX)) + return; } fun->machine->gasisr.maybe = 1; @@ -1893,30 +1893,30 @@ avr_hregs_split_reg (HARD_REG_SET *set) for (int regno = 0; regno < 32; regno++) if (TEST_HARD_REG_BIT (*set, regno)) { - // Don't remove a register from *SET which might indicate that - // some RAMP* register might need ISR prologue / epilogue treatment. - - if (AVR_HAVE_RAMPX - && (REG_X == regno || REG_X + 1 == regno) - && TEST_HARD_REG_BIT (*set, REG_X) - && TEST_HARD_REG_BIT (*set, REG_X + 1)) - continue; - - if (AVR_HAVE_RAMPY - && !frame_pointer_needed - && (REG_Y == regno || REG_Y + 1 == regno) - && TEST_HARD_REG_BIT (*set, REG_Y) - && TEST_HARD_REG_BIT (*set, REG_Y + 1)) - continue; - - if (AVR_HAVE_RAMPZ - && (REG_Z == regno || REG_Z + 1 == regno) - && TEST_HARD_REG_BIT (*set, REG_Z) - && TEST_HARD_REG_BIT (*set, REG_Z + 1)) - continue; - - CLEAR_HARD_REG_BIT (*set, regno); - return regno; + // Don't remove a register from *SET which might indicate that + // some RAMP* register might need ISR prologue / epilogue treatment. + + if (AVR_HAVE_RAMPX + && (REG_X == regno || REG_X + 1 == regno) + && TEST_HARD_REG_BIT (*set, REG_X) + && TEST_HARD_REG_BIT (*set, REG_X + 1)) + continue; + + if (AVR_HAVE_RAMPY + && !frame_pointer_needed + && (REG_Y == regno || REG_Y + 1 == regno) + && TEST_HARD_REG_BIT (*set, REG_Y) + && TEST_HARD_REG_BIT (*set, REG_Y + 1)) + continue; + + if (AVR_HAVE_RAMPZ + && (REG_Z == regno || REG_Z + 1 == regno) + && TEST_HARD_REG_BIT (*set, REG_Z) + && TEST_HARD_REG_BIT (*set, REG_Z + 1)) + continue; + + CLEAR_HARD_REG_BIT (*set, regno); + return regno; } return -1; @@ -1967,7 +1967,7 @@ emit_push_sfr (rtx sfr, bool frame_related_p, bool clr_p, int treg) /* OUT IO(SFR), __zero_reg__ */ insn = emit_move_insn (sfr, const0_rtx); if (frame_related_p) - RTX_FRAME_RELATED_P (insn) = 1; + RTX_FRAME_RELATED_P (insn) = 1; } } @@ -1982,262 +1982,262 @@ avr_prologue_setup_frame (HOST_WIDE_INT size, HARD_REG_SET set) = (HOST_WIDE_INT) GET_MODE_MASK (AVR_HAVE_8BIT_SP ? QImode : Pmode); bool minimize = (TARGET_CALL_PROLOGUES - && size < size_max - && live_seq - && !isr_p - && !cfun->machine->is_OS_task - && !cfun->machine->is_OS_main - && !AVR_TINY); + && size < size_max + && live_seq + && !isr_p + && !cfun->machine->is_OS_task + && !cfun->machine->is_OS_main + && !AVR_TINY); if (minimize && (frame_pointer_needed - || avr_outgoing_args_size() > 8 - || (AVR_2_BYTE_PC && live_seq > 6) - || live_seq > 7)) + || avr_outgoing_args_size() > 8 + || (AVR_2_BYTE_PC && live_seq > 6) + || live_seq > 7)) { rtx pattern; int first_reg, reg, offset; emit_move_insn (gen_rtx_REG (HImode, REG_X), - gen_int_mode (size, HImode)); + gen_int_mode (size, HImode)); pattern = gen_call_prologue_saves (gen_int_mode (live_seq, HImode), - gen_int_mode (live_seq+size, HImode)); + gen_int_mode (live_seq+size, HImode)); insn = emit_insn (pattern); RTX_FRAME_RELATED_P (insn) = 1; /* Describe the effect of the unspec_volatile call to prologue_saves. - Note that this formulation assumes that add_reg_note pushes the - notes to the front. Thus we build them in the reverse order of - how we want dwarf2out to process them. */ + Note that this formulation assumes that add_reg_note pushes the + notes to the front. Thus we build them in the reverse order of + how we want dwarf2out to process them. */ /* The function does always set frame_pointer_rtx, but whether that - is going to be permanent in the function is frame_pointer_needed. */ + is going to be permanent in the function is frame_pointer_needed. */ add_reg_note (insn, REG_CFA_ADJUST_CFA, - gen_rtx_SET ((frame_pointer_needed + gen_rtx_SET ((frame_pointer_needed ? frame_pointer_rtx : stack_pointer_rtx), - plus_constant (Pmode, stack_pointer_rtx, - -(size + live_seq)))); + plus_constant (Pmode, stack_pointer_rtx, + -(size + live_seq)))); /* Note that live_seq always contains r28+r29, but the other - registers to be saved are all below 18. */ + registers to be saved are all below 18. */ first_reg = (LAST_CALLEE_SAVED_REG + 1) - (live_seq - 2); for (reg = 29, offset = -live_seq + 1; - reg >= first_reg; - reg = (reg == 28 ? LAST_CALLEE_SAVED_REG : reg - 1), ++offset) - { - rtx m, r; + reg >= first_reg; + reg = (reg == 28 ? LAST_CALLEE_SAVED_REG : reg - 1), ++offset) + { + rtx m, r; - m = gen_rtx_MEM (QImode, plus_constant (Pmode, stack_pointer_rtx, - offset)); - r = gen_rtx_REG (QImode, reg); - add_reg_note (insn, REG_CFA_OFFSET, gen_rtx_SET (m, r)); - } + m = gen_rtx_MEM (QImode, plus_constant (Pmode, stack_pointer_rtx, + offset)); + r = gen_rtx_REG (QImode, reg); + add_reg_note (insn, REG_CFA_OFFSET, gen_rtx_SET (m, r)); + } cfun->machine->stack_usage += size + live_seq; } else /* !minimize */ { for (int reg = 0; reg < 32; ++reg) - if (TEST_HARD_REG_BIT (set, reg)) - emit_push_byte (reg, true); + if (TEST_HARD_REG_BIT (set, reg)) + emit_push_byte (reg, true); if (frame_pointer_needed - && (!(cfun->machine->is_OS_task || cfun->machine->is_OS_main))) - { - /* Push frame pointer. Always be consistent about the - ordering of pushes -- epilogue_restores expects the - register pair to be pushed low byte first. */ + && (!(cfun->machine->is_OS_task || cfun->machine->is_OS_main))) + { + /* Push frame pointer. Always be consistent about the + ordering of pushes -- epilogue_restores expects the + register pair to be pushed low byte first. */ - emit_push_byte (REG_Y, true); - emit_push_byte (REG_Y + 1, true); - } + emit_push_byte (REG_Y, true); + emit_push_byte (REG_Y + 1, true); + } if (frame_pointer_needed - && size == 0) - { - insn = emit_move_insn (frame_pointer_rtx, stack_pointer_rtx); - RTX_FRAME_RELATED_P (insn) = 1; - } + && size == 0) + { + insn = emit_move_insn (frame_pointer_rtx, stack_pointer_rtx); + RTX_FRAME_RELATED_P (insn) = 1; + } if (size != 0) - { - /* Creating a frame can be done by direct manipulation of the - stack or via the frame pointer. These two methods are: - fp = sp - fp -= size - sp = fp - or - sp -= size - fp = sp (*) - the optimum method depends on function type, stack and - frame size. To avoid a complex logic, both methods are - tested and shortest is selected. - - There is also the case where SIZE != 0 and no frame pointer is - needed; this can occur if ACCUMULATE_OUTGOING_ARGS is on. - In that case, insn (*) is not needed in that case. - We use the X register as scratch. This is save because in X - is call-clobbered. - In an interrupt routine, the case of SIZE != 0 together with - !frame_pointer_needed can only occur if the function is not a - leaf function and thus X has already been saved. */ - - int irq_state = -1; - HOST_WIDE_INT size_cfa = size, neg_size; - rtx_insn *fp_plus_insns; - rtx fp, my_fp; - - gcc_assert (frame_pointer_needed - || !isr_p - || !crtl->is_leaf); - - fp = my_fp = (frame_pointer_needed - ? frame_pointer_rtx - : gen_rtx_REG (Pmode, REG_X)); - - if (AVR_HAVE_8BIT_SP) - { - /* The high byte (r29) does not change: - Prefer SUBI (1 cycle) over SBIW (2 cycles, same size). */ - - my_fp = all_regs_rtx[FRAME_POINTER_REGNUM]; - } - - /* Cut down size and avoid size = 0 so that we don't run - into ICE like PR52488 in the remainder. */ - - if (size > size_max) - { - /* Don't error so that insane code from newlib still compiles - and does not break building newlib. As PR51345 is implemented - now, there are multilib variants with -msp8. - - If user wants sanity checks he can use -Wstack-usage= - or similar options. - - For CFA we emit the original, non-saturated size so that - the generic machinery is aware of the real stack usage and - will print the above diagnostic as expected. */ - - size = size_max; - } - - size = trunc_int_for_mode (size, GET_MODE (my_fp)); - neg_size = trunc_int_for_mode (-size, GET_MODE (my_fp)); - - /************ Method 1: Adjust frame pointer ************/ - - start_sequence (); - - /* Normally, the dwarf2out frame-related-expr interpreter does - not expect to have the CFA change once the frame pointer is - set up. Thus, we avoid marking the move insn below and - instead indicate that the entire operation is complete after - the frame pointer subtraction is done. */ - - insn = emit_move_insn (fp, stack_pointer_rtx); - if (frame_pointer_needed) - { - RTX_FRAME_RELATED_P (insn) = 1; - add_reg_note (insn, REG_CFA_ADJUST_CFA, - gen_rtx_SET (fp, stack_pointer_rtx)); - } - - insn = emit_move_insn (my_fp, plus_constant (GET_MODE (my_fp), - my_fp, neg_size)); - - if (frame_pointer_needed) - { - RTX_FRAME_RELATED_P (insn) = 1; - add_reg_note (insn, REG_CFA_ADJUST_CFA, - gen_rtx_SET (fp, plus_constant (Pmode, fp, + { + /* Creating a frame can be done by direct manipulation of the + stack or via the frame pointer. These two methods are: + fp = sp + fp -= size + sp = fp + or + sp -= size + fp = sp (*) + the optimum method depends on function type, stack and + frame size. To avoid a complex logic, both methods are + tested and shortest is selected. + + There is also the case where SIZE != 0 and no frame pointer is + needed; this can occur if ACCUMULATE_OUTGOING_ARGS is on. + In that case, insn (*) is not needed in that case. + We use the X register as scratch. This is save because in X + is call-clobbered. + In an interrupt routine, the case of SIZE != 0 together with + !frame_pointer_needed can only occur if the function is not a + leaf function and thus X has already been saved. */ + + int irq_state = -1; + HOST_WIDE_INT size_cfa = size, neg_size; + rtx_insn *fp_plus_insns; + rtx fp, my_fp; + + gcc_assert (frame_pointer_needed + || !isr_p + || !crtl->is_leaf); + + fp = my_fp = (frame_pointer_needed + ? frame_pointer_rtx + : gen_rtx_REG (Pmode, REG_X)); + + if (AVR_HAVE_8BIT_SP) + { + /* The high byte (r29) does not change: + Prefer SUBI (1 cycle) over SBIW (2 cycles, same size). */ + + my_fp = all_regs_rtx[FRAME_POINTER_REGNUM]; + } + + /* Cut down size and avoid size = 0 so that we don't run + into ICE like PR52488 in the remainder. */ + + if (size > size_max) + { + /* Don't error so that insane code from newlib still compiles + and does not break building newlib. As PR51345 is implemented + now, there are multilib variants with -msp8. + + If user wants sanity checks he can use -Wstack-usage= + or similar options. + + For CFA we emit the original, non-saturated size so that + the generic machinery is aware of the real stack usage and + will print the above diagnostic as expected. */ + + size = size_max; + } + + size = trunc_int_for_mode (size, GET_MODE (my_fp)); + neg_size = trunc_int_for_mode (-size, GET_MODE (my_fp)); + + /************ Method 1: Adjust frame pointer ************/ + + start_sequence (); + + /* Normally, the dwarf2out frame-related-expr interpreter does + not expect to have the CFA change once the frame pointer is + set up. Thus, we avoid marking the move insn below and + instead indicate that the entire operation is complete after + the frame pointer subtraction is done. */ + + insn = emit_move_insn (fp, stack_pointer_rtx); + if (frame_pointer_needed) + { + RTX_FRAME_RELATED_P (insn) = 1; + add_reg_note (insn, REG_CFA_ADJUST_CFA, + gen_rtx_SET (fp, stack_pointer_rtx)); + } + + insn = emit_move_insn (my_fp, plus_constant (GET_MODE (my_fp), + my_fp, neg_size)); + + if (frame_pointer_needed) + { + RTX_FRAME_RELATED_P (insn) = 1; + add_reg_note (insn, REG_CFA_ADJUST_CFA, + gen_rtx_SET (fp, plus_constant (Pmode, fp, -size_cfa))); - } - - /* Copy to stack pointer. Note that since we've already - changed the CFA to the frame pointer this operation - need not be annotated if frame pointer is needed. - Always move through unspec, see PR50063. - For meaning of irq_state see movhi_sp_r insn. */ - - if (cfun->machine->is_interrupt) - irq_state = 1; - - if (TARGET_NO_INTERRUPTS - || cfun->machine->is_signal - || cfun->machine->is_OS_main) - irq_state = 0; - - if (AVR_HAVE_8BIT_SP) - irq_state = 2; - - insn = emit_insn (gen_movhi_sp_r (stack_pointer_rtx, - fp, GEN_INT (irq_state))); - if (!frame_pointer_needed) - { - RTX_FRAME_RELATED_P (insn) = 1; - add_reg_note (insn, REG_CFA_ADJUST_CFA, - gen_rtx_SET (stack_pointer_rtx, - plus_constant (Pmode, - stack_pointer_rtx, - -size_cfa))); - } - - fp_plus_insns = get_insns (); - end_sequence (); - - /************ Method 2: Adjust Stack pointer ************/ - - /* Stack adjustment by means of RCALL . and/or PUSH __TMP_REG__ - can only handle specific offsets. */ - - int n_rcall = size / (AVR_3_BYTE_PC ? 3 : 2); - - if (avr_sp_immediate_operand (gen_int_mode (-size, HImode), HImode) - // Don't use more than 3 RCALLs. - && n_rcall <= 3) - { - rtx_insn *sp_plus_insns; - - start_sequence (); - - insn = emit_move_insn (stack_pointer_rtx, - plus_constant (Pmode, stack_pointer_rtx, - -size)); - RTX_FRAME_RELATED_P (insn) = 1; - add_reg_note (insn, REG_CFA_ADJUST_CFA, - gen_rtx_SET (stack_pointer_rtx, - plus_constant (Pmode, - stack_pointer_rtx, - -size_cfa))); - if (frame_pointer_needed) - { - insn = emit_move_insn (fp, stack_pointer_rtx); - RTX_FRAME_RELATED_P (insn) = 1; - } - - sp_plus_insns = get_insns (); - end_sequence (); - - /************ Use shortest method ************/ - - emit_insn (get_sequence_length (sp_plus_insns) - < get_sequence_length (fp_plus_insns) - ? sp_plus_insns - : fp_plus_insns); - } - else - { - emit_insn (fp_plus_insns); - } - - cfun->machine->stack_usage += size_cfa; - } /* !minimize && size != 0 */ + } + + /* Copy to stack pointer. Note that since we've already + changed the CFA to the frame pointer this operation + need not be annotated if frame pointer is needed. + Always move through unspec, see PR50063. + For meaning of irq_state see movhi_sp_r insn. */ + + if (cfun->machine->is_interrupt) + irq_state = 1; + + if (TARGET_NO_INTERRUPTS + || cfun->machine->is_signal + || cfun->machine->is_OS_main) + irq_state = 0; + + if (AVR_HAVE_8BIT_SP) + irq_state = 2; + + insn = emit_insn (gen_movhi_sp_r (stack_pointer_rtx, + fp, GEN_INT (irq_state))); + if (!frame_pointer_needed) + { + RTX_FRAME_RELATED_P (insn) = 1; + add_reg_note (insn, REG_CFA_ADJUST_CFA, + gen_rtx_SET (stack_pointer_rtx, + plus_constant (Pmode, + stack_pointer_rtx, + -size_cfa))); + } + + fp_plus_insns = get_insns (); + end_sequence (); + + /************ Method 2: Adjust Stack pointer ************/ + + /* Stack adjustment by means of RCALL . and/or PUSH __TMP_REG__ + can only handle specific offsets. */ + + int n_rcall = size / (AVR_3_BYTE_PC ? 3 : 2); + + if (avr_sp_immediate_operand (gen_int_mode (-size, HImode), HImode) + // Don't use more than 3 RCALLs. + && n_rcall <= 3) + { + rtx_insn *sp_plus_insns; + + start_sequence (); + + insn = emit_move_insn (stack_pointer_rtx, + plus_constant (Pmode, stack_pointer_rtx, + -size)); + RTX_FRAME_RELATED_P (insn) = 1; + add_reg_note (insn, REG_CFA_ADJUST_CFA, + gen_rtx_SET (stack_pointer_rtx, + plus_constant (Pmode, + stack_pointer_rtx, + -size_cfa))); + if (frame_pointer_needed) + { + insn = emit_move_insn (fp, stack_pointer_rtx); + RTX_FRAME_RELATED_P (insn) = 1; + } + + sp_plus_insns = get_insns (); + end_sequence (); + + /************ Use shortest method ************/ + + emit_insn (get_sequence_length (sp_plus_insns) + < get_sequence_length (fp_plus_insns) + ? sp_plus_insns + : fp_plus_insns); + } + else + { + emit_insn (fp_plus_insns); + } + + cfun->machine->stack_usage += size_cfa; + } /* !minimize && size != 0 */ } /* !minimize */ } @@ -2267,79 +2267,79 @@ avr_expand_prologue (void) int treg = AVR_TMP_REGNO; /* Enable interrupts. */ if (cfun->machine->is_interrupt) - emit_insn (gen_enable_interrupt ()); + emit_insn (gen_enable_interrupt ()); if (cfun->machine->gasisr.maybe) - { - /* Let GAS PR21472 emit prologue preamble for us which handles SREG, - ZERO_REG and TMP_REG and one additional, optional register for - us in an optimal way. This even scans through inline asm. */ - - cfun->machine->gasisr.yes = 1; - - // The optional reg or TMP_REG if we don't need one. If we need one, - // remove that reg from SET so that it's not puhed / popped twice. - // We also use it below instead of TMP_REG in some places. - - treg = avr_hregs_split_reg (&set); - if (treg < 0) - treg = AVR_TMP_REGNO; - cfun->machine->gasisr.regno = treg; - - // The worst case of pushes. The exact number can be inferred - // at assembly time by magic expression __gcc_isr.n_pushed. - cfun->machine->stack_usage += 3 + (treg != AVR_TMP_REGNO); - - // Emit a Prologue chunk. Epilogue chunk(s) might follow. - // The final Done chunk is emit by final postscan. - emit_insn (gen_gasisr (GEN_INT (GASISR_Prologue), GEN_INT (treg))); - } + { + /* Let GAS PR21472 emit prologue preamble for us which handles SREG, + ZERO_REG and TMP_REG and one additional, optional register for + us in an optimal way. This even scans through inline asm. */ + + cfun->machine->gasisr.yes = 1; + + // The optional reg or TMP_REG if we don't need one. If we need one, + // remove that reg from SET so that it's not puhed / popped twice. + // We also use it below instead of TMP_REG in some places. + + treg = avr_hregs_split_reg (&set); + if (treg < 0) + treg = AVR_TMP_REGNO; + cfun->machine->gasisr.regno = treg; + + // The worst case of pushes. The exact number can be inferred + // at assembly time by magic expression __gcc_isr.n_pushed. + cfun->machine->stack_usage += 3 + (treg != AVR_TMP_REGNO); + + // Emit a Prologue chunk. Epilogue chunk(s) might follow. + // The final Done chunk is emit by final postscan. + emit_insn (gen_gasisr (GEN_INT (GASISR_Prologue), GEN_INT (treg))); + } else // !TARGET_GASISR_PROLOGUES: Classic, dumb prologue preamble. - { - /* Push zero reg. */ - emit_push_byte (AVR_ZERO_REGNO, true); + { + /* Push zero reg. */ + emit_push_byte (AVR_ZERO_REGNO, true); - /* Push tmp reg. */ - emit_push_byte (AVR_TMP_REGNO, true); + /* Push tmp reg. */ + emit_push_byte (AVR_TMP_REGNO, true); - /* Push SREG. */ - /* ??? There's no dwarf2 column reserved for SREG. */ - emit_push_sfr (sreg_rtx, false, false /* clr */, AVR_TMP_REGNO); + /* Push SREG. */ + /* ??? There's no dwarf2 column reserved for SREG. */ + emit_push_sfr (sreg_rtx, false, false /* clr */, AVR_TMP_REGNO); - /* Clear zero reg. */ - emit_move_insn (zero_reg_rtx, const0_rtx); + /* Clear zero reg. */ + emit_move_insn (zero_reg_rtx, const0_rtx); - /* Prevent any attempt to delete the setting of ZERO_REG! */ - emit_use (zero_reg_rtx); - } + /* Prevent any attempt to delete the setting of ZERO_REG! */ + emit_use (zero_reg_rtx); + } /* Push and clear RAMPD/X/Y/Z if present and low-part register is used. - ??? There are no dwarf2 columns reserved for RAMPD/X/Y/Z. */ + ??? There are no dwarf2 columns reserved for RAMPD/X/Y/Z. */ if (AVR_HAVE_RAMPD) - emit_push_sfr (rampd_rtx, false /* frame */, true /* clr */, treg); + emit_push_sfr (rampd_rtx, false /* frame */, true /* clr */, treg); if (AVR_HAVE_RAMPX - && TEST_HARD_REG_BIT (set, REG_X) - && TEST_HARD_REG_BIT (set, REG_X + 1)) - { - emit_push_sfr (rampx_rtx, false /* frame */, true /* clr */, treg); - } + && TEST_HARD_REG_BIT (set, REG_X) + && TEST_HARD_REG_BIT (set, REG_X + 1)) + { + emit_push_sfr (rampx_rtx, false /* frame */, true /* clr */, treg); + } if (AVR_HAVE_RAMPY - && (frame_pointer_needed - || (TEST_HARD_REG_BIT (set, REG_Y) - && TEST_HARD_REG_BIT (set, REG_Y + 1)))) - { - emit_push_sfr (rampy_rtx, false /* frame */, true /* clr */, treg); - } + && (frame_pointer_needed + || (TEST_HARD_REG_BIT (set, REG_Y) + && TEST_HARD_REG_BIT (set, REG_Y + 1)))) + { + emit_push_sfr (rampy_rtx, false /* frame */, true /* clr */, treg); + } if (AVR_HAVE_RAMPZ - && TEST_HARD_REG_BIT (set, REG_Z) - && TEST_HARD_REG_BIT (set, REG_Z + 1)) - { - emit_push_sfr (rampz_rtx, false /* frame */, AVR_HAVE_RAMPD, treg); - } + && TEST_HARD_REG_BIT (set, REG_Z) + && TEST_HARD_REG_BIT (set, REG_Z + 1)) + { + emit_push_sfr (rampz_rtx, false /* frame */, AVR_HAVE_RAMPD, treg); + } } /* is_interrupt is_signal */ avr_prologue_setup_frame (size, set); @@ -2363,23 +2363,23 @@ avr_asm_function_end_prologue (FILE *file) else { if (cfun->machine->is_interrupt) - { - fputs ("/* prologue: Interrupt */\n", file); - } + { + fputs ("/* prologue: Interrupt */\n", file); + } else if (cfun->machine->is_signal) - { - fputs ("/* prologue: Signal */\n", file); - } + { + fputs ("/* prologue: Signal */\n", file); + } else - fputs ("/* prologue: function */\n", file); + fputs ("/* prologue: function */\n", file); } if (ACCUMULATE_OUTGOING_ARGS) fprintf (file, "/* outgoing args size = %d */\n", - avr_outgoing_args_size()); + avr_outgoing_args_size()); fprintf (file, "/* frame size = " HOST_WIDE_INT_PRINT_DEC " */\n", - (HOST_WIDE_INT) get_frame_size()); + (HOST_WIDE_INT) get_frame_size()); if (!cfun->machine->gasisr.yes) { @@ -2452,29 +2452,29 @@ avr_expand_epilogue (bool sibcall_p) live_seq = sequent_regs_live (); minimize = (TARGET_CALL_PROLOGUES - && live_seq - && !isr_p - && !cfun->machine->is_OS_task - && !cfun->machine->is_OS_main - && !AVR_TINY); + && live_seq + && !isr_p + && !cfun->machine->is_OS_task + && !cfun->machine->is_OS_main + && !AVR_TINY); if (minimize && (live_seq > 4 - || frame_pointer_needed - || size)) + || frame_pointer_needed + || size)) { /* Get rid of frame. */ if (!frame_pointer_needed) - { - emit_move_insn (frame_pointer_rtx, stack_pointer_rtx); - } + { + emit_move_insn (frame_pointer_rtx, stack_pointer_rtx); + } if (size) - { - emit_move_insn (frame_pointer_rtx, - plus_constant (Pmode, frame_pointer_rtx, size)); - } + { + emit_move_insn (frame_pointer_rtx, + plus_constant (Pmode, frame_pointer_rtx, size)); + } emit_insn (gen_epilogue_restores (gen_int_mode (live_seq, HImode))); return; @@ -2490,26 +2490,26 @@ avr_expand_epilogue (bool sibcall_p) HOST_WIDE_INT size_max; gcc_assert (frame_pointer_needed - || !isr_p - || !crtl->is_leaf); + || !isr_p + || !crtl->is_leaf); fp = my_fp = (frame_pointer_needed - ? frame_pointer_rtx - : gen_rtx_REG (Pmode, REG_X)); + ? frame_pointer_rtx + : gen_rtx_REG (Pmode, REG_X)); if (AVR_HAVE_8BIT_SP) - { - /* The high byte (r29) does not change: - Prefer SUBI (1 cycle) over SBIW (2 cycles). */ + { + /* The high byte (r29) does not change: + Prefer SUBI (1 cycle) over SBIW (2 cycles). */ - my_fp = all_regs_rtx[FRAME_POINTER_REGNUM]; - } + my_fp = all_regs_rtx[FRAME_POINTER_REGNUM]; + } /* For rationale see comment in prologue generation. */ size_max = (HOST_WIDE_INT) GET_MODE_MASK (GET_MODE (my_fp)); if (size > size_max) - size = size_max; + size = size_max; size = trunc_int_for_mode (size, GET_MODE (my_fp)); /********** Method 1: Adjust fp register **********/ @@ -2517,20 +2517,20 @@ avr_expand_epilogue (bool sibcall_p) start_sequence (); if (!frame_pointer_needed) - emit_move_insn (fp, stack_pointer_rtx); + emit_move_insn (fp, stack_pointer_rtx); emit_move_insn (my_fp, plus_constant (GET_MODE (my_fp), my_fp, size)); /* Copy to stack pointer. */ if (TARGET_NO_INTERRUPTS) - irq_state = 0; + irq_state = 0; if (AVR_HAVE_8BIT_SP) - irq_state = 2; + irq_state = 2; emit_insn (gen_movhi_sp_r (stack_pointer_rtx, fp, - GEN_INT (irq_state))); + GEN_INT (irq_state))); fp_plus_insns = get_insns (); end_sequence (); @@ -2538,33 +2538,33 @@ avr_expand_epilogue (bool sibcall_p) /********** Method 2: Adjust Stack pointer **********/ if (avr_sp_immediate_operand (gen_int_mode (size, HImode), HImode)) - { - rtx_insn *sp_plus_insns; + { + rtx_insn *sp_plus_insns; - start_sequence (); + start_sequence (); - emit_move_insn (stack_pointer_rtx, - plus_constant (Pmode, stack_pointer_rtx, size)); + emit_move_insn (stack_pointer_rtx, + plus_constant (Pmode, stack_pointer_rtx, size)); - sp_plus_insns = get_insns (); - end_sequence (); + sp_plus_insns = get_insns (); + end_sequence (); - /************ Use shortest method ************/ + /************ Use shortest method ************/ - emit_insn (get_sequence_length (sp_plus_insns) - < get_sequence_length (fp_plus_insns) - ? sp_plus_insns - : fp_plus_insns); - } + emit_insn (get_sequence_length (sp_plus_insns) + < get_sequence_length (fp_plus_insns) + ? sp_plus_insns + : fp_plus_insns); + } else - emit_insn (fp_plus_insns); + emit_insn (fp_plus_insns); } /* size != 0 */ if (frame_pointer_needed && !(cfun->machine->is_OS_task || cfun->machine->is_OS_main)) { /* Restore previous frame_pointer. See avr_expand_prologue for - rationale for not using pophi. */ + rationale for not using pophi. */ emit_pop_byte (REG_Y + 1); emit_pop_byte (REG_Y); @@ -2588,58 +2588,58 @@ avr_expand_epilogue (bool sibcall_p) if (isr_p) { /* Restore RAMPZ/Y/X/D using tmp_reg as scratch. - The conditions to restore them must be tha same as in prologue. */ + The conditions to restore them must be tha same as in prologue. */ if (AVR_HAVE_RAMPZ - && TEST_HARD_REG_BIT (set, REG_Z) - && TEST_HARD_REG_BIT (set, REG_Z + 1)) - { - emit_pop_byte (treg); - emit_move_insn (rampz_rtx, all_regs_rtx[treg]); - } + && TEST_HARD_REG_BIT (set, REG_Z) + && TEST_HARD_REG_BIT (set, REG_Z + 1)) + { + emit_pop_byte (treg); + emit_move_insn (rampz_rtx, all_regs_rtx[treg]); + } if (AVR_HAVE_RAMPY - && (frame_pointer_needed - || (TEST_HARD_REG_BIT (set, REG_Y) - && TEST_HARD_REG_BIT (set, REG_Y + 1)))) - { - emit_pop_byte (treg); - emit_move_insn (rampy_rtx, all_regs_rtx[treg]); - } + && (frame_pointer_needed + || (TEST_HARD_REG_BIT (set, REG_Y) + && TEST_HARD_REG_BIT (set, REG_Y + 1)))) + { + emit_pop_byte (treg); + emit_move_insn (rampy_rtx, all_regs_rtx[treg]); + } if (AVR_HAVE_RAMPX - && TEST_HARD_REG_BIT (set, REG_X) - && TEST_HARD_REG_BIT (set, REG_X + 1)) - { - emit_pop_byte (treg); - emit_move_insn (rampx_rtx, all_regs_rtx[treg]); - } + && TEST_HARD_REG_BIT (set, REG_X) + && TEST_HARD_REG_BIT (set, REG_X + 1)) + { + emit_pop_byte (treg); + emit_move_insn (rampx_rtx, all_regs_rtx[treg]); + } if (AVR_HAVE_RAMPD) - { - emit_pop_byte (treg); - emit_move_insn (rampd_rtx, all_regs_rtx[treg]); - } + { + emit_pop_byte (treg); + emit_move_insn (rampd_rtx, all_regs_rtx[treg]); + } if (cfun->machine->gasisr.yes) - { - // Emit an Epilogue chunk. - emit_insn (gen_gasisr (GEN_INT (GASISR_Epilogue), - GEN_INT (cfun->machine->gasisr.regno))); - } + { + // Emit an Epilogue chunk. + emit_insn (gen_gasisr (GEN_INT (GASISR_Epilogue), + GEN_INT (cfun->machine->gasisr.regno))); + } else // !TARGET_GASISR_PROLOGUES - { - /* Restore SREG using tmp_reg as scratch. */ + { + /* Restore SREG using tmp_reg as scratch. */ - emit_pop_byte (AVR_TMP_REGNO); - emit_move_insn (sreg_rtx, tmp_reg_rtx); + emit_pop_byte (AVR_TMP_REGNO); + emit_move_insn (sreg_rtx, tmp_reg_rtx); - /* Restore tmp REG. */ - emit_pop_byte (AVR_TMP_REGNO); + /* Restore tmp REG. */ + emit_pop_byte (AVR_TMP_REGNO); - /* Restore zero REG. */ - emit_pop_byte (AVR_ZERO_REGNO); - } + /* Restore zero REG. */ + emit_pop_byte (AVR_ZERO_REGNO); + } } if (!sibcall_p) @@ -2718,13 +2718,13 @@ avr_address_tiny_absdata_p (rtx x, machine_mode mode) static inline bool avr_reg_ok_for_addr_p (rtx reg, addr_space_t as, - RTX_CODE outer_code, bool strict) + RTX_CODE outer_code, bool strict) { return (REG_P (reg) - && (avr_regno_mode_code_ok_for_base_p (REGNO (reg), QImode, - as, outer_code, UNKNOWN) - || (!strict - && REGNO (reg) >= FIRST_PSEUDO_REGISTER))); + && (avr_regno_mode_code_ok_for_base_p (REGNO (reg), QImode, + as, outer_code, UNKNOWN) + || (!strict + && REGNO (reg) >= FIRST_PSEUDO_REGISTER))); } @@ -2740,51 +2740,51 @@ avr_legitimate_address_p (machine_mode mode, rtx x, bool strict) { case REG: ok = avr_reg_ok_for_addr_p (x, ADDR_SPACE_GENERIC, - MEM, strict); + MEM, strict); if (strict - && GET_MODE_SIZE (mode) > 4 - && REG_X == REGNO (x)) - { - ok = false; - } + && GET_MODE_SIZE (mode) > 4 + && REG_X == REGNO (x)) + { + ok = false; + } break; case POST_INC: case PRE_DEC: ok = avr_reg_ok_for_addr_p (XEXP (x, 0), ADDR_SPACE_GENERIC, - GET_CODE (x), strict); + GET_CODE (x), strict); break; case PLUS: { - rtx reg = XEXP (x, 0); - rtx op1 = XEXP (x, 1); - - if (REG_P (reg) - && CONST_INT_P (op1) - && INTVAL (op1) >= 0) - { - bool fit = IN_RANGE (INTVAL (op1), 0, MAX_LD_OFFSET (mode)); - - if (fit) - { - ok = (! strict - || avr_reg_ok_for_addr_p (reg, ADDR_SPACE_GENERIC, - PLUS, strict)); - - if (reg == frame_pointer_rtx - || reg == arg_pointer_rtx) - { - ok = true; - } - } - else if (frame_pointer_needed - && reg == frame_pointer_rtx) - { - ok = true; - } - } + rtx reg = XEXP (x, 0); + rtx op1 = XEXP (x, 1); + + if (REG_P (reg) + && CONST_INT_P (op1) + && INTVAL (op1) >= 0) + { + bool fit = IN_RANGE (INTVAL (op1), 0, MAX_LD_OFFSET (mode)); + + if (fit) + { + ok = (! strict + || avr_reg_ok_for_addr_p (reg, ADDR_SPACE_GENERIC, + PLUS, strict)); + + if (reg == frame_pointer_rtx + || reg == arg_pointer_rtx) + { + ok = true; + } + } + else if (frame_pointer_needed + && reg == frame_pointer_rtx) + { + ok = true; + } + } } break; @@ -2796,7 +2796,7 @@ avr_legitimate_address_p (machine_mode mode, rtx x, bool strict) && CONSTANT_ADDRESS_P (x)) { /* avrtiny's load / store instructions only cover addresses 0..0xbf: - IN / OUT range is 0..0x3f and LDS / STS can access 0x40..0xbf. */ + IN / OUT range is 0..0x3f and LDS / STS can access 0x40..0xbf. */ ok = avr_address_tiny_absdata_p (x, mode); } @@ -2804,19 +2804,19 @@ avr_legitimate_address_p (machine_mode mode, rtx x, bool strict) if (avr_log.legitimate_address_p) { avr_edump ("\n%?: ret=%d, mode=%m strict=%d " - "reload_completed=%d reload_in_progress=%d %s:", - ok, mode, strict, reload_completed, reload_in_progress, - reg_renumber ? "(reg_renumber)" : ""); + "reload_completed=%d reload_in_progress=%d %s:", + ok, mode, strict, reload_completed, reload_in_progress, + reg_renumber ? "(reg_renumber)" : ""); if (GET_CODE (x) == PLUS - && REG_P (XEXP (x, 0)) - && CONST_INT_P (XEXP (x, 1)) - && IN_RANGE (INTVAL (XEXP (x, 1)), 0, MAX_LD_OFFSET (mode)) - && reg_renumber) - { - avr_edump ("(r%d ---> r%d)", REGNO (XEXP (x, 0)), - true_regnum (XEXP (x, 0))); - } + && REG_P (XEXP (x, 0)) + && CONST_INT_P (XEXP (x, 1)) + && IN_RANGE (INTVAL (XEXP (x, 1)), 0, MAX_LD_OFFSET (mode)) + && reg_renumber) + { + avr_edump ("(r%d ---> r%d)", REGNO (XEXP (x, 0)), + true_regnum (XEXP (x, 0))); + } avr_edump ("\n%r\n", x); } @@ -2840,27 +2840,27 @@ avr_legitimize_address (rtx x, rtx oldx, machine_mode mode) if (AVR_TINY) { if (CONSTANT_ADDRESS_P (x) - && ! avr_address_tiny_absdata_p (x, mode)) - { - x = force_reg (Pmode, x); - } + && ! avr_address_tiny_absdata_p (x, mode)) + { + x = force_reg (Pmode, x); + } } if (GET_CODE (oldx) == PLUS && REG_P (XEXP (oldx, 0))) { if (REG_P (XEXP (oldx, 1))) - x = force_reg (GET_MODE (oldx), oldx); + x = force_reg (GET_MODE (oldx), oldx); else if (CONST_INT_P (XEXP (oldx, 1))) - { - int offs = INTVAL (XEXP (oldx, 1)); - if (frame_pointer_rtx != XEXP (oldx, 0) - && offs > MAX_LD_OFFSET (mode)) - { - big_offset_p = true; - x = force_reg (GET_MODE (oldx), oldx); - } - } + { + int offs = INTVAL (XEXP (oldx, 1)); + if (frame_pointer_rtx != XEXP (oldx, 0) + && offs > MAX_LD_OFFSET (mode)) + { + big_offset_p = true; + x = force_reg (GET_MODE (oldx), oldx); + } + } } if (avr_log.legitimize_address) @@ -2868,7 +2868,7 @@ avr_legitimize_address (rtx x, rtx oldx, machine_mode mode) avr_edump ("\n%?: mode=%m\n %r\n", mode, oldx); if (x != oldx) - avr_edump (" %s --> %r\n", big_offset_p ? "(big offset)" : "", x); + avr_edump (" %s --> %r\n", big_offset_p ? "(big offset)" : "", x); } return x; @@ -2882,9 +2882,9 @@ avr_legitimize_address (rtx x, rtx oldx, machine_mode mode) rtx avr_legitimize_reload_address (rtx *px, machine_mode mode, - int opnum, int type, int addr_type, - int ind_levels ATTRIBUTE_UNUSED, - rtx (*mk_memloc)(rtx,int)) + int opnum, int type, int addr_type, + int ind_levels ATTRIBUTE_UNUSED, + rtx (*mk_memloc)(rtx,int)) { rtx x = *px; @@ -2892,15 +2892,15 @@ avr_legitimize_reload_address (rtx *px, machine_mode mode, avr_edump ("\n%?:%m %r\n", mode, x); if (1 && (GET_CODE (x) == POST_INC - || GET_CODE (x) == PRE_DEC)) + || GET_CODE (x) == PRE_DEC)) { push_reload (XEXP (x, 0), XEXP (x, 0), &XEXP (x, 0), &XEXP (x, 0), - POINTER_REGS, GET_MODE (x), GET_MODE (x), 0, 0, - opnum, RELOAD_OTHER); + POINTER_REGS, GET_MODE (x), GET_MODE (x), 0, 0, + opnum, RELOAD_OTHER); if (avr_log.legitimize_reload_address) - avr_edump (" RCLASS.1 = %R\n IN = %r\n OUT = %r\n", - POINTER_REGS, XEXP (x, 0), XEXP (x, 0)); + avr_edump (" RCLASS.1 = %R\n IN = %r\n OUT = %r\n", + POINTER_REGS, XEXP (x, 0), XEXP (x, 0)); return x; } @@ -2914,44 +2914,44 @@ avr_legitimize_reload_address (rtx *px, machine_mode mode, bool fit = INTVAL (XEXP (x, 1)) <= MAX_LD_OFFSET (mode); if (fit) - { - if (reg_equiv_address (REGNO (XEXP (x, 0))) != 0) - { - int regno = REGNO (XEXP (x, 0)); - rtx mem = mk_memloc (x, regno); - - push_reload (XEXP (mem, 0), NULL_RTX, &XEXP (mem, 0), NULL, - POINTER_REGS, Pmode, VOIDmode, 0, 0, - 1, (enum reload_type) addr_type); - - if (avr_log.legitimize_reload_address) - avr_edump (" RCLASS.2 = %R\n IN = %r\n OUT = %r\n", - POINTER_REGS, XEXP (mem, 0), NULL_RTX); - - push_reload (mem, NULL_RTX, &XEXP (x, 0), NULL, - BASE_POINTER_REGS, GET_MODE (x), VOIDmode, 0, 0, - opnum, (enum reload_type) type); - - if (avr_log.legitimize_reload_address) - avr_edump (" RCLASS.2 = %R\n IN = %r\n OUT = %r\n", - BASE_POINTER_REGS, mem, NULL_RTX); - - return x; - } - } + { + if (reg_equiv_address (REGNO (XEXP (x, 0))) != 0) + { + int regno = REGNO (XEXP (x, 0)); + rtx mem = mk_memloc (x, regno); + + push_reload (XEXP (mem, 0), NULL_RTX, &XEXP (mem, 0), NULL, + POINTER_REGS, Pmode, VOIDmode, 0, 0, + 1, (enum reload_type) addr_type); + + if (avr_log.legitimize_reload_address) + avr_edump (" RCLASS.2 = %R\n IN = %r\n OUT = %r\n", + POINTER_REGS, XEXP (mem, 0), NULL_RTX); + + push_reload (mem, NULL_RTX, &XEXP (x, 0), NULL, + BASE_POINTER_REGS, GET_MODE (x), VOIDmode, 0, 0, + opnum, (enum reload_type) type); + + if (avr_log.legitimize_reload_address) + avr_edump (" RCLASS.2 = %R\n IN = %r\n OUT = %r\n", + BASE_POINTER_REGS, mem, NULL_RTX); + + return x; + } + } else if (! (frame_pointer_needed - && XEXP (x, 0) == frame_pointer_rtx)) - { - push_reload (x, NULL_RTX, px, NULL, - POINTER_REGS, GET_MODE (x), VOIDmode, 0, 0, - opnum, (enum reload_type) type); + && XEXP (x, 0) == frame_pointer_rtx)) + { + push_reload (x, NULL_RTX, px, NULL, + POINTER_REGS, GET_MODE (x), VOIDmode, 0, 0, + opnum, (enum reload_type) type); - if (avr_log.legitimize_reload_address) - avr_edump (" RCLASS.3 = %R\n IN = %r\n OUT = %r\n", - POINTER_REGS, x, NULL_RTX); + if (avr_log.legitimize_reload_address) + avr_edump (" RCLASS.3 = %R\n IN = %r\n OUT = %r\n", + POINTER_REGS, x, NULL_RTX); - return x; - } + return x; + } } return NULL_RTX; @@ -2971,17 +2971,17 @@ avr_legitimize_reload_address (rtx *px, machine_mode mode, Don't output anything. */ -static const char* -avr_asm_len (const char* tpl, rtx* operands, int* plen, int n_words) +static const char * +avr_asm_len (const char *tpl, rtx *operands, int *plen, int n_words) { if (plen == NULL) output_asm_insn (tpl, operands); else { if (n_words < 0) - *plen = -n_words; + *plen = -n_words; else - *plen += n_words; + *plen += n_words; } return ""; @@ -2990,7 +2990,7 @@ avr_asm_len (const char* tpl, rtx* operands, int* plen, int n_words) /* Return a pointer register name as a string. */ -static const char* +static const char * ptrreg_to_str (int regno) { switch (regno) @@ -3000,7 +3000,7 @@ ptrreg_to_str (int regno) case REG_Z: return "Z"; default: output_operand_lossage ("address operand requires constraint for" - " X, Y, or Z register"); + " X, Y, or Z register"); } return NULL; } @@ -3008,7 +3008,7 @@ ptrreg_to_str (int regno) /* Return the condition name as a string. Used in conditional jump constructing */ -static const char* +static const char * cond_string (enum rtx_code code) { bool cc_overflow_unusable = false; @@ -3021,14 +3021,14 @@ cond_string (enum rtx_code code) return "eq"; case GE: if (cc_overflow_unusable) - return "pl"; + return "pl"; else - return "ge"; + return "ge"; case LT: if (cc_overflow_unusable) - return "mi"; + return "mi"; else - return "lt"; + return "lt"; case GEU: return "sh"; case LTU: @@ -3086,40 +3086,40 @@ avr_print_operand_address (FILE *file, machine_mode /*mode*/, rtx addr) default: if (CONSTANT_ADDRESS_P (addr) - && text_segment_operand (addr, VOIDmode)) - { - rtx x = addr; - if (GET_CODE (x) == CONST) - x = XEXP (x, 0); - if (GET_CODE (x) == PLUS && CONST_INT_P (XEXP (x, 1))) - { - /* Assembler gs() will implant word address. Make offset - a byte offset inside gs() for assembler. This is - needed because the more logical (constant+gs(sym)) is not - accepted by gas. For 128K and smaller devices this is ok. - For large devices it will create a trampoline to offset - from symbol which may not be what the user really wanted. */ - - fprintf (file, "gs("); - output_addr_const (file, XEXP (x, 0)); - fprintf (file, "+" HOST_WIDE_INT_PRINT_DEC ")", - 2 * INTVAL (XEXP (x, 1))); - if (AVR_3_BYTE_PC) - if (warning (0, "pointer offset from symbol maybe incorrect")) - { - output_addr_const (stderr, addr); - fprintf (stderr, "\n"); - } - } - else - { - fprintf (file, "gs("); - output_addr_const (file, addr); - fprintf (file, ")"); - } - } + && text_segment_operand (addr, VOIDmode)) + { + rtx x = addr; + if (GET_CODE (x) == CONST) + x = XEXP (x, 0); + if (GET_CODE (x) == PLUS && CONST_INT_P (XEXP (x, 1))) + { + /* Assembler gs() will implant word address. Make offset + a byte offset inside gs() for assembler. This is + needed because the more logical (constant+gs(sym)) is not + accepted by gas. For 128K and smaller devices this is ok. + For large devices it will create a trampoline to offset + from symbol which may not be what the user really wanted. */ + + fprintf (file, "gs("); + output_addr_const (file, XEXP (x, 0)); + fprintf (file, "+" HOST_WIDE_INT_PRINT_DEC ")", + 2 * INTVAL (XEXP (x, 1))); + if (AVR_3_BYTE_PC) + if (warning (0, "pointer offset from symbol maybe incorrect")) + { + output_addr_const (stderr, addr); + fprintf (stderr, "\n"); + } + } + else + { + fprintf (file, "gs("); + output_addr_const (file, addr); + fprintf (file, ")"); + } + } else - output_addr_const (file, addr); + output_addr_const (file, addr); } } @@ -3152,37 +3152,37 @@ avr_print_operand (FILE *file, rtx x, int code) if (code == '~') { if (!AVR_HAVE_JMP_CALL) - fputc ('r', file); + fputc ('r', file); } else if (code == '!') { if (AVR_HAVE_EIJMP_EICALL) - fputc ('e', file); + fputc ('e', file); } else if (code == 't' - || code == 'T') + || code == 'T') { static int t_regno = -1; static int t_nbits = -1; if (REG_P (x) && t_regno < 0 && code == 'T') - { - t_regno = REGNO (x); - t_nbits = GET_MODE_BITSIZE (GET_MODE (x)); - } + { + t_regno = REGNO (x); + t_nbits = GET_MODE_BITSIZE (GET_MODE (x)); + } else if (CONST_INT_P (x) && t_regno >= 0 - && IN_RANGE (INTVAL (x), 0, t_nbits - 1)) - { - int bpos = INTVAL (x); + && IN_RANGE (INTVAL (x), 0, t_nbits - 1)) + { + int bpos = INTVAL (x); - fprintf (file, "%s", reg_names[t_regno + bpos / 8]); - if (code == 'T') - fprintf (file, ",%d", bpos % 8); + fprintf (file, "%s", reg_names[t_regno + bpos / 8]); + if (code == 'T') + fprintf (file, ",%d", bpos % 8); - t_regno = -1; - } + t_regno = -1; + } else - fatal_insn ("operands to %T/%t must be reg + const_int:", x); + fatal_insn ("operands to %T/%t must be reg + const_int:", x); } else if (code == 'E' || code == 'F') { @@ -3197,101 +3197,101 @@ avr_print_operand (FILE *file, rtx x, int code) else if (REG_P (x)) { if (x == zero_reg_rtx) - fprintf (file, "__zero_reg__"); + fprintf (file, "__zero_reg__"); else if (code == 'r' && REGNO (x) < 32) - fprintf (file, "%d", (int) REGNO (x)); + fprintf (file, "%d", (int) REGNO (x)); else - fprintf (file, "%s", reg_names[REGNO (x) + abcd]); + fprintf (file, "%s", reg_names[REGNO (x) + abcd]); } else if (CONST_INT_P (x)) { HOST_WIDE_INT ival = INTVAL (x); if ('i' != code) - fprintf (file, HOST_WIDE_INT_PRINT_DEC, ival + abcd); + fprintf (file, HOST_WIDE_INT_PRINT_DEC, ival + abcd); else if (low_io_address_operand (x, VOIDmode) - || high_io_address_operand (x, VOIDmode)) - { - if (AVR_HAVE_RAMPZ && ival == avr_addr.rampz) - fprintf (file, "__RAMPZ__"); - else if (AVR_HAVE_RAMPY && ival == avr_addr.rampy) - fprintf (file, "__RAMPY__"); - else if (AVR_HAVE_RAMPX && ival == avr_addr.rampx) - fprintf (file, "__RAMPX__"); - else if (AVR_HAVE_RAMPD && ival == avr_addr.rampd) - fprintf (file, "__RAMPD__"); - else if ((AVR_XMEGA || AVR_TINY) && ival == avr_addr.ccp) - fprintf (file, "__CCP__"); - else if (ival == avr_addr.sreg) fprintf (file, "__SREG__"); - else if (ival == avr_addr.sp_l) fprintf (file, "__SP_L__"); - else if (ival == avr_addr.sp_h) fprintf (file, "__SP_H__"); - else - { - fprintf (file, HOST_WIDE_INT_PRINT_HEX, - ival - avr_arch->sfr_offset); - } - } + || high_io_address_operand (x, VOIDmode)) + { + if (AVR_HAVE_RAMPZ && ival == avr_addr.rampz) + fprintf (file, "__RAMPZ__"); + else if (AVR_HAVE_RAMPY && ival == avr_addr.rampy) + fprintf (file, "__RAMPY__"); + else if (AVR_HAVE_RAMPX && ival == avr_addr.rampx) + fprintf (file, "__RAMPX__"); + else if (AVR_HAVE_RAMPD && ival == avr_addr.rampd) + fprintf (file, "__RAMPD__"); + else if ((AVR_XMEGA || AVR_TINY) && ival == avr_addr.ccp) + fprintf (file, "__CCP__"); + else if (ival == avr_addr.sreg) fprintf (file, "__SREG__"); + else if (ival == avr_addr.sp_l) fprintf (file, "__SP_L__"); + else if (ival == avr_addr.sp_h) fprintf (file, "__SP_H__"); + else + { + fprintf (file, HOST_WIDE_INT_PRINT_HEX, + ival - avr_arch->sfr_offset); + } + } else - fatal_insn ("bad address, not an I/O address:", x); + fatal_insn ("bad address, not an I/O address:", x); } else if (MEM_P (x)) { rtx addr = XEXP (x, 0); if (code == 'm') - { - if (!CONSTANT_P (addr)) - fatal_insn ("bad address, not a constant:", addr); - /* Assembler template with m-code is data - not progmem section */ - if (text_segment_operand (addr, VOIDmode)) - if (warning (0, "accessing data memory with" - " program memory address")) - { - output_addr_const (stderr, addr); - fprintf(stderr,"\n"); - } - output_addr_const (file, addr); - } + { + if (!CONSTANT_P (addr)) + fatal_insn ("bad address, not a constant:", addr); + /* Assembler template with m-code is data - not progmem section */ + if (text_segment_operand (addr, VOIDmode)) + if (warning (0, "accessing data memory with" + " program memory address")) + { + output_addr_const (stderr, addr); + fprintf(stderr,"\n"); + } + output_addr_const (file, addr); + } else if (code == 'i') - { - avr_print_operand (file, addr, 'i'); - } + { + avr_print_operand (file, addr, 'i'); + } else if (code == 'o') - { - if (GET_CODE (addr) != PLUS) - fatal_insn ("bad address, not (reg+disp):", addr); + { + if (GET_CODE (addr) != PLUS) + fatal_insn ("bad address, not (reg+disp):", addr); - avr_print_operand (file, XEXP (addr, 1), 0); - } + avr_print_operand (file, XEXP (addr, 1), 0); + } else if (code == 'b') - { - if (GET_CODE (addr) != PLUS) - fatal_insn ("bad address, not (reg+disp):", addr); + { + if (GET_CODE (addr) != PLUS) + fatal_insn ("bad address, not (reg+disp):", addr); - avr_print_operand_address (file, VOIDmode, XEXP (addr, 0)); - } + avr_print_operand_address (file, VOIDmode, XEXP (addr, 0)); + } else if (code == 'p' || code == 'r') - { - if (GET_CODE (addr) != POST_INC && GET_CODE (addr) != PRE_DEC) - fatal_insn ("bad address, not post_inc or pre_dec:", addr); - - if (code == 'p') - /* X, Y, Z */ - avr_print_operand_address (file, VOIDmode, XEXP (addr, 0)); - else - avr_print_operand (file, XEXP (addr, 0), 0); /* r26, r28, r30 */ - } + { + if (GET_CODE (addr) != POST_INC && GET_CODE (addr) != PRE_DEC) + fatal_insn ("bad address, not post_inc or pre_dec:", addr); + + if (code == 'p') + /* X, Y, Z */ + avr_print_operand_address (file, VOIDmode, XEXP (addr, 0)); + else + avr_print_operand (file, XEXP (addr, 0), 0); /* r26, r28, r30 */ + } else if (GET_CODE (addr) == PLUS) - { - avr_print_operand_address (file, VOIDmode, XEXP (addr, 0)); - if (REGNO (XEXP (addr, 0)) == REG_X) - fatal_insn ("internal compiler error. Bad address:" - ,addr); - fputc ('+', file); - avr_print_operand (file, XEXP (addr, 1), code); - } + { + avr_print_operand_address (file, VOIDmode, XEXP (addr, 0)); + if (REGNO (XEXP (addr, 0)) == REG_X) + fatal_insn ("internal compiler error. Bad address:" + ,addr); + fputc ('+', file); + avr_print_operand (file, XEXP (addr, 1), code); + } else - avr_print_operand_address (file, VOIDmode, addr); + avr_print_operand_address (file, VOIDmode, addr); } else if (code == 'i') { @@ -3305,12 +3305,12 @@ avr_print_operand (FILE *file, rtx x, int code) { /* Constant progmem address - like used in jmp or call */ if (text_segment_operand (x, VOIDmode) == 0) - if (warning (0, "accessing program memory" - " with data memory address")) - { - output_addr_const (stderr, x); - fprintf(stderr,"\n"); - } + if (warning (0, "accessing program memory" + " with data memory address")) + { + output_addr_const (stderr, x); + fprintf(stderr,"\n"); + } /* Use normal symbol for direct address no linker trampoline needed */ output_addr_const (file, x); } @@ -3318,15 +3318,15 @@ avr_print_operand (FILE *file, rtx x, int code) { HOST_WIDE_INT ival = INTVAL (avr_to_int_mode (x)); if (code != 0) - output_operand_lossage ("Unsupported code '%c' for fixed-point:", - code); + output_operand_lossage ("Unsupported code '%c' for fixed-point:", + code); fprintf (file, HOST_WIDE_INT_PRINT_DEC, ival); } else if (CONST_DOUBLE_P (x)) { long val; if (GET_MODE (x) != SFmode) - fatal_insn ("internal compiler error. Unknown mode:", x); + fatal_insn ("internal compiler error. Unknown mode:", x); REAL_VALUE_TO_TARGET_SINGLE (*CONST_DOUBLE_REAL_VALUE (x), val); fprintf (file, "0x%lx", val); } @@ -3350,9 +3350,9 @@ avr_print_operand (FILE *file, rtx x, int code) static bool avr_use_by_pieces_infrastructure_p (unsigned HOST_WIDE_INT size, - unsigned int align ATTRIBUTE_UNUSED, - enum by_pieces_operation op, - bool speed_p) + unsigned int align ATTRIBUTE_UNUSED, + enum by_pieces_operation op, + bool speed_p) { if (op != MOVE_BY_PIECES || (speed_p && size > MOVE_MAX_PIECES)) @@ -3370,7 +3370,7 @@ int avr_jump_mode (rtx x, rtx_insn *insn) { int dest_addr = INSN_ADDRESSES (INSN_UID (GET_CODE (x) == LABEL_REF - ? XEXP (x, 0) : x)); + ? XEXP (x, 0) : x)); int cur_addr = INSN_ADDRESSES (INSN_UID (insn)); int jump_distance = cur_addr - dest_addr; @@ -3389,7 +3389,7 @@ avr_jump_mode (rtx x, rtx_insn *insn) LEN is a number returned by avr_jump_mode function. If REVERSE nonzero then condition code in X must be reversed. */ -const char* +const char * ret_cond_branch (rtx x, int len, int reverse) { RTX_CODE cond = reverse ? reverse_condition (GET_CODE (x)) : GET_CODE (x); @@ -3419,13 +3419,13 @@ ret_cond_branch (rtx x, int len, int reverse) "jmp %0")); case GTU: return (len == 1 ? ("breq .+2" CR_TAB - "brsh %0") : - len == 2 ? ("breq .+4" CR_TAB - "brlo .+2" CR_TAB - "rjmp %0") : - ("breq .+6" CR_TAB - "brlo .+4" CR_TAB - "jmp %0")); + "brsh %0") : + len == 2 ? ("breq .+4" CR_TAB + "brlo .+2" CR_TAB + "rjmp %0") : + ("breq .+6" CR_TAB + "brlo .+4" CR_TAB + "jmp %0")); case LE: if (cc_overflow_unusable) return (len == 1 ? ("breq %0" CR_TAB @@ -3447,12 +3447,12 @@ ret_cond_branch (rtx x, int len, int reverse) "jmp %0")); case LEU: return (len == 1 ? ("breq %0" CR_TAB - "brlo %0") : - len == 2 ? ("breq .+2" CR_TAB - "brsh .+2" CR_TAB + "brlo %0") : + len == 2 ? ("breq .+2" CR_TAB + "brsh .+2" CR_TAB "rjmp %0") : - ("breq .+2" CR_TAB - "brsh .+4" CR_TAB + ("breq .+2" CR_TAB + "brsh .+4" CR_TAB "jmp %0")); default: if (reverse) @@ -3470,19 +3470,19 @@ ret_cond_branch (rtx x, int len, int reverse) } } else - { - switch (len) - { - case 1: - return "br%j1 %0"; - case 2: - return ("br%k1 .+2" CR_TAB - "rjmp %0"); - default: - return ("br%k1 .+4" CR_TAB - "jmp %0"); - } - } + { + switch (len) + { + case 1: + return "br%j1 %0"; + case 2: + return ("br%k1 .+2" CR_TAB + "rjmp %0"); + default: + return ("br%k1 .+4" CR_TAB + "jmp %0"); + } + } } return ""; } @@ -3493,25 +3493,25 @@ ret_cond_branch (rtx x, int len, int reverse) void avr_final_prescan_insn (rtx_insn *insn, rtx *operand ATTRIBUTE_UNUSED, - int num_operands ATTRIBUTE_UNUSED) + int num_operands ATTRIBUTE_UNUSED) { if (avr_log.rtx_costs) { rtx set = single_set (insn); if (set) - fprintf (asm_out_file, "/* DEBUG: cost = %d. */\n", - set_src_cost (SET_SRC (set), GET_MODE (SET_DEST (set)), + fprintf (asm_out_file, "/* DEBUG: cost = %d. */\n", + set_src_cost (SET_SRC (set), GET_MODE (SET_DEST (set)), optimize_insn_for_speed_p ())); else - fprintf (asm_out_file, "/* DEBUG: pattern-cost = %d. */\n", - rtx_cost (PATTERN (insn), VOIDmode, INSN, 0, - optimize_insn_for_speed_p())); + fprintf (asm_out_file, "/* DEBUG: pattern-cost = %d. */\n", + rtx_cost (PATTERN (insn), VOIDmode, INSN, 0, + optimize_insn_for_speed_p())); } if (avr_log.insn_addresses) fprintf (asm_out_file, ";; ADDR = %d\n", - (int) INSN_ADDRESSES (INSN_UID (insn))); + (int) INSN_ADDRESSES (INSN_UID (insn))); } @@ -3521,14 +3521,14 @@ avr_final_prescan_insn (rtx_insn *insn, rtx *operand ATTRIBUTE_UNUSED, after the last epilogue. */ static void -avr_asm_final_postscan_insn (FILE *stream, rtx_insn *insn, rtx*, int) +avr_asm_final_postscan_insn (FILE *stream, rtx_insn *insn, rtx *, int) { if (cfun->machine->gasisr.yes && !next_real_insn (insn)) { app_disable(); fprintf (stream, "\t__gcc_isr %d,r%d\n", GASISR_Done, - cfun->machine->gasisr.regno); + cfun->machine->gasisr.regno); } } @@ -3550,7 +3550,7 @@ avr_function_arg_regno_p (int r) void avr_init_cumulative_args (CUMULATIVE_ARGS *cum, tree fntype, rtx libname, - tree fndecl ATTRIBUTE_UNUSED) + tree fndecl ATTRIBUTE_UNUSED) { cum->nregs = AVR_TINY ? 6 : 18; cum->regno = FIRST_CUM_REG; @@ -3622,10 +3622,10 @@ avr_function_arg_advance (cumulative_args_t cum_v, && !call_used_or_fixed_reg_p (cum->regno)) { /* FIXME: We ship info on failing tail-call in struct machine_function. - This uses internals of calls.cc:expand_call() and the way args_so_far - is used. targetm.function_ok_for_sibcall() needs to be extended to - pass &args_so_far, too. At present, CUMULATIVE_ARGS is target - dependent so that such an extension is not wanted. */ + This uses internals of calls.cc:expand_call() and the way args_so_far + is used. targetm.function_ok_for_sibcall() needs to be extended to + pass &args_so_far, too. At present, CUMULATIVE_ARGS is target + dependent so that such an extension is not wanted. */ cfun->machine->sibcall_fails = 1; } @@ -3638,9 +3638,9 @@ avr_function_arg_advance (cumulative_args_t cum_v, && cum->nregs >= 0) { for (int regno = cum->regno; regno < cum->regno + bytes; regno++) - if (fixed_regs[regno]) - warning (0, "fixed register %s used to pass parameter to function", - reg_names[regno]); + if (fixed_regs[regno]) + warning (0, "fixed register %s used to pass parameter to function", + reg_names[regno]); } if (cum->nregs <= 0) @@ -3683,10 +3683,10 @@ avr_function_ok_for_sibcall (tree decl_callee, tree exp_callee) decl_callee = fntype_callee; while (FUNCTION_TYPE != TREE_CODE (decl_callee) - && METHOD_TYPE != TREE_CODE (decl_callee)) - { - decl_callee = TREE_TYPE (decl_callee); - } + && METHOD_TYPE != TREE_CODE (decl_callee)) + { + decl_callee = TREE_TYPE (decl_callee); + } } /* Ensure that caller and callee have compatible epilogues */ @@ -3716,8 +3716,8 @@ avr_load_libgcc_p (rtx op) int n_bytes = GET_MODE_SIZE (mode); return (n_bytes > 2 - && !AVR_HAVE_LPMX - && avr_mem_flash_p (op)); + && !AVR_HAVE_LPMX + && avr_mem_flash_p (op)); } /* Return true if a value of mode MODE is read by __xload_* function. */ @@ -3728,7 +3728,7 @@ avr_xload_libgcc_p (machine_mode mode) int n_bytes = GET_MODE_SIZE (mode); return (n_bytes > 1 - || avr_n_flash > 1); + || avr_n_flash > 1); } @@ -3747,38 +3747,38 @@ static rtx avr_find_unused_d_reg (rtx_insn *insn, rtx exclude) { bool isr_p = (avr_interrupt_function_p (current_function_decl) - || avr_signal_function_p (current_function_decl)); + || avr_signal_function_p (current_function_decl)); for (int regno = 16; regno < 32; regno++) { rtx reg = all_regs_rtx[regno]; if ((exclude - && reg_overlap_mentioned_p (exclude, reg)) - || fixed_regs[regno]) - { - continue; - } + && reg_overlap_mentioned_p (exclude, reg)) + || fixed_regs[regno]) + { + continue; + } /* Try non-live register */ if (!df_regs_ever_live_p (regno) - && (TREE_THIS_VOLATILE (current_function_decl) - || cfun->machine->is_OS_task - || cfun->machine->is_OS_main - || (!isr_p && call_used_or_fixed_reg_p (regno)))) - { - return reg; - } + && (TREE_THIS_VOLATILE (current_function_decl) + || cfun->machine->is_OS_task + || cfun->machine->is_OS_main + || (!isr_p && call_used_or_fixed_reg_p (regno)))) + { + return reg; + } /* Any live register can be used if it is unused after. - Prologue/epilogue will care for it as needed. */ + Prologue/epilogue will care for it as needed. */ if (df_regs_ever_live_p (regno) - && reg_unused_after (insn, reg)) - { - return reg; - } + && reg_unused_after (insn, reg)) + { + return reg; + } } return NULL_RTX; @@ -3788,7 +3788,7 @@ avr_find_unused_d_reg (rtx_insn *insn, rtx exclude) /* Helper function for the next function in the case where only restricted version of LPM instruction is available. */ -static const char* +static const char * avr_out_lpm_no_lpmx (rtx_insn *insn, rtx *xop, int *plen) { rtx dest = xop[0]; @@ -3811,68 +3811,68 @@ avr_out_lpm_no_lpmx (rtx_insn *insn, rtx *xop, int *plen) gcc_assert (REG_Z == REGNO (addr)); switch (n_bytes) - { - default: - gcc_unreachable(); - - case 1: - avr_asm_len ("%4lpm", xop, plen, 1); - - if (regno_dest != LPM_REGNO) - avr_asm_len ("mov %0,%3", xop, plen, 1); - - return ""; + { + default: + gcc_unreachable(); - case 2: - if (REGNO (dest) == REG_Z) - return avr_asm_len ("%4lpm" CR_TAB - "push %3" CR_TAB - "adiw %2,1" CR_TAB - "%4lpm" CR_TAB - "mov %B0,%3" CR_TAB - "pop %A0", xop, plen, 6); + case 1: + avr_asm_len ("%4lpm", xop, plen, 1); - avr_asm_len ("%4lpm" CR_TAB - "mov %A0,%3" CR_TAB - "adiw %2,1" CR_TAB - "%4lpm" CR_TAB - "mov %B0,%3", xop, plen, 5); + if (regno_dest != LPM_REGNO) + avr_asm_len ("mov %0,%3", xop, plen, 1); - if (!reg_unused_after (insn, addr)) - avr_asm_len ("sbiw %2,1", xop, plen, 1); + return ""; - break; /* 2 */ - } + case 2: + if (REGNO (dest) == REG_Z) + return avr_asm_len ("%4lpm" CR_TAB + "push %3" CR_TAB + "adiw %2,1" CR_TAB + "%4lpm" CR_TAB + "mov %B0,%3" CR_TAB + "pop %A0", xop, plen, 6); + + avr_asm_len ("%4lpm" CR_TAB + "mov %A0,%3" CR_TAB + "adiw %2,1" CR_TAB + "%4lpm" CR_TAB + "mov %B0,%3", xop, plen, 5); + + if (!reg_unused_after (insn, addr)) + avr_asm_len ("sbiw %2,1", xop, plen, 1); + + break; /* 2 */ + } break; /* REG */ case POST_INC: gcc_assert (REG_Z == REGNO (XEXP (addr, 0)) - && n_bytes <= 4); + && n_bytes <= 4); if (regno_dest == LPM_REGNO) - avr_asm_len ("%4lpm" CR_TAB - "adiw %2,1", xop, plen, 2); + avr_asm_len ("%4lpm" CR_TAB + "adiw %2,1", xop, plen, 2); else - avr_asm_len ("%4lpm" CR_TAB - "mov %A0,%3" CR_TAB - "adiw %2,1", xop, plen, 3); + avr_asm_len ("%4lpm" CR_TAB + "mov %A0,%3" CR_TAB + "adiw %2,1", xop, plen, 3); if (n_bytes >= 2) - avr_asm_len ("%4lpm" CR_TAB - "mov %B0,%3" CR_TAB - "adiw %2,1", xop, plen, 3); + avr_asm_len ("%4lpm" CR_TAB + "mov %B0,%3" CR_TAB + "adiw %2,1", xop, plen, 3); if (n_bytes >= 3) - avr_asm_len ("%4lpm" CR_TAB - "mov %C0,%3" CR_TAB - "adiw %2,1", xop, plen, 3); + avr_asm_len ("%4lpm" CR_TAB + "mov %C0,%3" CR_TAB + "adiw %2,1", xop, plen, 3); if (n_bytes >= 4) - avr_asm_len ("%4lpm" CR_TAB - "mov %D0,%3" CR_TAB - "adiw %2,1", xop, plen, 3); + avr_asm_len ("%4lpm" CR_TAB + "mov %D0,%3" CR_TAB + "adiw %2,1", xop, plen, 3); break; /* POST_INC */ @@ -3887,7 +3887,7 @@ avr_out_lpm_no_lpmx (rtx_insn *insn, rtx *xop, int *plen) If PLEN != 0 set *PLEN to the length in words of the instruction sequence. Return "". */ -const char* +const char * avr_out_lpm (rtx_insn *insn, rtx *op, int *plen) { rtx xop[7]; @@ -3905,7 +3905,7 @@ avr_out_lpm (rtx_insn *insn, rtx *op, int *plen) if (MEM_P (dest)) { warning (0, "writing to address space %qs not supported", - avr_addrspace[MEM_ADDR_SPACE (dest)].name); + avr_addrspace[MEM_ADDR_SPACE (dest)].name); return ""; } @@ -3933,28 +3933,28 @@ avr_out_lpm (rtx_insn *insn, rtx *op, int *plen) xop[3] = avr_find_unused_d_reg (insn, lpm_addr_reg_rtx); if (xop[3] != NULL_RTX) - { - avr_asm_len ("ldi %3,%4" CR_TAB - "out %i6,%3", xop, plen, 2); - } + { + avr_asm_len ("ldi %3,%4" CR_TAB + "out %i6,%3", xop, plen, 2); + } else if (segment == 1) - { - avr_asm_len ("clr %5" CR_TAB - "inc %5" CR_TAB - "out %i6,%5", xop, plen, 3); - } + { + avr_asm_len ("clr %5" CR_TAB + "inc %5" CR_TAB + "out %i6,%5", xop, plen, 3); + } else - { - avr_asm_len ("mov %5,%2" CR_TAB - "ldi %2,%4" CR_TAB - "out %i6,%2" CR_TAB - "mov %2,%5", xop, plen, 4); - } + { + avr_asm_len ("mov %5,%2" CR_TAB + "ldi %2,%4" CR_TAB + "out %i6,%2" CR_TAB + "mov %2,%5", xop, plen, 4); + } xop[4] = xstring_e; if (!AVR_HAVE_ELPMX) - return avr_out_lpm_no_lpmx (insn, xop, plen); + return avr_out_lpm_no_lpmx (insn, xop, plen); } else if (!AVR_HAVE_LPMX) { @@ -3973,70 +3973,70 @@ avr_out_lpm (rtx_insn *insn, rtx *op, int *plen) gcc_assert (REG_Z == REGNO (addr)); switch (n_bytes) - { - default: - gcc_unreachable(); + { + default: + gcc_unreachable(); - case 1: - avr_asm_len ("%4lpm %0,%a2", xop, plen, 1); - break; + case 1: + avr_asm_len ("%4lpm %0,%a2", xop, plen, 1); + break; - case 2: - if (REGNO (dest) == REG_Z) - avr_asm_len ("%4lpm %5,%a2+" CR_TAB - "%4lpm %B0,%a2" CR_TAB - "mov %A0,%5", xop, plen, 3); - else - { - avr_asm_len ("%4lpm %A0,%a2+" CR_TAB - "%4lpm %B0,%a2", xop, plen, 2); + case 2: + if (REGNO (dest) == REG_Z) + avr_asm_len ("%4lpm %5,%a2+" CR_TAB + "%4lpm %B0,%a2" CR_TAB + "mov %A0,%5", xop, plen, 3); + else + { + avr_asm_len ("%4lpm %A0,%a2+" CR_TAB + "%4lpm %B0,%a2", xop, plen, 2); - if (!reg_unused_after (insn, addr)) - avr_asm_len ("sbiw %2,1", xop, plen, 1); - } + if (!reg_unused_after (insn, addr)) + avr_asm_len ("sbiw %2,1", xop, plen, 1); + } - break; /* 2 */ + break; /* 2 */ - case 3: + case 3: - avr_asm_len ("%4lpm %A0,%a2+" CR_TAB - "%4lpm %B0,%a2+" CR_TAB - "%4lpm %C0,%a2", xop, plen, 3); + avr_asm_len ("%4lpm %A0,%a2+" CR_TAB + "%4lpm %B0,%a2+" CR_TAB + "%4lpm %C0,%a2", xop, plen, 3); - if (!reg_unused_after (insn, addr)) - avr_asm_len ("sbiw %2,2", xop, plen, 1); + if (!reg_unused_after (insn, addr)) + avr_asm_len ("sbiw %2,2", xop, plen, 1); - break; /* 3 */ + break; /* 3 */ - case 4: + case 4: - avr_asm_len ("%4lpm %A0,%a2+" CR_TAB - "%4lpm %B0,%a2+", xop, plen, 2); + avr_asm_len ("%4lpm %A0,%a2+" CR_TAB + "%4lpm %B0,%a2+", xop, plen, 2); - if (REGNO (dest) == REG_Z - 2) - avr_asm_len ("%4lpm %5,%a2+" CR_TAB - "%4lpm %C0,%a2" CR_TAB - "mov %D0,%5", xop, plen, 3); - else - { - avr_asm_len ("%4lpm %C0,%a2+" CR_TAB - "%4lpm %D0,%a2", xop, plen, 2); + if (REGNO (dest) == REG_Z - 2) + avr_asm_len ("%4lpm %5,%a2+" CR_TAB + "%4lpm %C0,%a2" CR_TAB + "mov %D0,%5", xop, plen, 3); + else + { + avr_asm_len ("%4lpm %C0,%a2+" CR_TAB + "%4lpm %D0,%a2", xop, plen, 2); - if (!reg_unused_after (insn, addr)) - avr_asm_len ("sbiw %2,3", xop, plen, 1); - } + if (!reg_unused_after (insn, addr)) + avr_asm_len ("sbiw %2,3", xop, plen, 1); + } - break; /* 4 */ - } /* n_bytes */ + break; /* 4 */ + } /* n_bytes */ break; /* REG */ case POST_INC: gcc_assert (REG_Z == REGNO (XEXP (addr, 0)) - && n_bytes <= 4); + && n_bytes <= 4); - avr_asm_len ("%4lpm %A0,%a2+", xop, plen, 1); + avr_asm_len ("%4lpm %A0,%a2+", xop, plen, 1); if (n_bytes >= 2) avr_asm_len ("%4lpm %B0,%a2+", xop, plen, 1); if (n_bytes >= 3) avr_asm_len ("%4lpm %C0,%a2+", xop, plen, 1); if (n_bytes >= 4) avr_asm_len ("%4lpm %D0,%a2+", xop, plen, 1); @@ -4059,7 +4059,7 @@ avr_out_lpm (rtx_insn *insn, rtx *op, int *plen) /* Worker function for xload_8 insn. */ -const char* +const char * avr_out_xload (rtx_insn *insn ATTRIBUTE_UNUSED, rtx *op, int *plen) { rtx xop[4]; @@ -4072,7 +4072,7 @@ avr_out_xload (rtx_insn *insn ATTRIBUTE_UNUSED, rtx *op, int *plen) avr_asm_len (AVR_HAVE_LPMX ? "lpm %3,%a2" : "lpm", xop, plen, -1); avr_asm_len ("sbrc %1,7" CR_TAB - "ld %3,%a2", xop, plen, 2); + "ld %3,%a2", xop, plen, 2); if (REGNO (xop[0]) != REGNO (xop[3])) avr_asm_len ("mov %0,%3", xop, plen, 1); @@ -4081,7 +4081,7 @@ avr_out_xload (rtx_insn *insn ATTRIBUTE_UNUSED, rtx *op, int *plen) } -const char* +const char * output_movqi (rtx_insn *insn, rtx operands[], int *plen) { rtx dest = operands[0]; @@ -4098,21 +4098,21 @@ output_movqi (rtx_insn *insn, rtx operands[], int *plen) if (REG_P (dest)) { if (REG_P (src)) /* mov r,r */ - { - if (test_hard_reg_class (STACK_REG, dest)) - return avr_asm_len ("out %0,%1", operands, plen, -1); - else if (test_hard_reg_class (STACK_REG, src)) - return avr_asm_len ("in %0,%1", operands, plen, -1); - - return avr_asm_len ("mov %0,%1", operands, plen, -1); - } + { + if (test_hard_reg_class (STACK_REG, dest)) + return avr_asm_len ("out %0,%1", operands, plen, -1); + else if (test_hard_reg_class (STACK_REG, src)) + return avr_asm_len ("in %0,%1", operands, plen, -1); + + return avr_asm_len ("mov %0,%1", operands, plen, -1); + } else if (CONSTANT_P (src)) - { - output_reload_in_const (operands, NULL_RTX, plen, false); - return ""; - } + { + output_reload_in_const (operands, NULL_RTX, plen, false); + return ""; + } else if (MEM_P (src)) - return out_movqi_r_mr (insn, operands, plen); /* mov r,m */ + return out_movqi_r_mr (insn, operands, plen); /* mov r,m */ } else if (MEM_P (dest)) { @@ -4145,51 +4145,51 @@ output_movhi (rtx_insn *insn, rtx xop[], int *plen) if (REG_P (dest)) { if (REG_P (src)) /* mov r,r */ - { - if (test_hard_reg_class (STACK_REG, dest)) - { - if (AVR_HAVE_8BIT_SP) - return avr_asm_len ("out __SP_L__,%A1", xop, plen, -1); - - if (AVR_XMEGA) - return avr_asm_len ("out __SP_L__,%A1" CR_TAB - "out __SP_H__,%B1", xop, plen, -2); - - /* Use simple load of SP if no interrupts are used. */ - - return TARGET_NO_INTERRUPTS - ? avr_asm_len ("out __SP_H__,%B1" CR_TAB - "out __SP_L__,%A1", xop, plen, -2) - : avr_asm_len ("in __tmp_reg__,__SREG__" CR_TAB - "cli" CR_TAB - "out __SP_H__,%B1" CR_TAB - "out __SREG__,__tmp_reg__" CR_TAB - "out __SP_L__,%A1", xop, plen, -5); - } - else if (test_hard_reg_class (STACK_REG, src)) - { - return !AVR_HAVE_SPH - ? avr_asm_len ("in %A0,__SP_L__" CR_TAB - "clr %B0", xop, plen, -2) - - : avr_asm_len ("in %A0,__SP_L__" CR_TAB - "in %B0,__SP_H__", xop, plen, -2); - } - - return AVR_HAVE_MOVW - ? avr_asm_len ("movw %0,%1", xop, plen, -1) - - : avr_asm_len ("mov %A0,%A1" CR_TAB - "mov %B0,%B1", xop, plen, -2); - } /* REG_P (src) */ - else if (CONSTANT_P (src)) - { - return output_reload_inhi (xop, NULL, plen); - } + { + if (test_hard_reg_class (STACK_REG, dest)) + { + if (AVR_HAVE_8BIT_SP) + return avr_asm_len ("out __SP_L__,%A1", xop, plen, -1); + + if (AVR_XMEGA) + return avr_asm_len ("out __SP_L__,%A1" CR_TAB + "out __SP_H__,%B1", xop, plen, -2); + + /* Use simple load of SP if no interrupts are used. */ + + return TARGET_NO_INTERRUPTS + ? avr_asm_len ("out __SP_H__,%B1" CR_TAB + "out __SP_L__,%A1", xop, plen, -2) + : avr_asm_len ("in __tmp_reg__,__SREG__" CR_TAB + "cli" CR_TAB + "out __SP_H__,%B1" CR_TAB + "out __SREG__,__tmp_reg__" CR_TAB + "out __SP_L__,%A1", xop, plen, -5); + } + else if (test_hard_reg_class (STACK_REG, src)) + { + return !AVR_HAVE_SPH + ? avr_asm_len ("in %A0,__SP_L__" CR_TAB + "clr %B0", xop, plen, -2) + + : avr_asm_len ("in %A0,__SP_L__" CR_TAB + "in %B0,__SP_H__", xop, plen, -2); + } + + return AVR_HAVE_MOVW + ? avr_asm_len ("movw %0,%1", xop, plen, -1) + + : avr_asm_len ("mov %A0,%A1" CR_TAB + "mov %B0,%B1", xop, plen, -2); + } /* REG_P (src) */ + else if (CONSTANT_P (src)) + { + return output_reload_inhi (xop, NULL, plen); + } else if (MEM_P (src)) - { - return out_movhi_r_mr (insn, xop, plen); /* mov r,m */ - } + { + return out_movhi_r_mr (insn, xop, plen); /* mov r,m */ + } } else if (MEM_P (dest)) { @@ -4209,7 +4209,7 @@ output_movhi (rtx_insn *insn, rtx xop[], int *plen) /* Same as out_movqi_r_mr, but TINY does not have ADIW or SBIW */ -static const char* +static const char * avr_out_movqi_r_mr_reg_disp_tiny (rtx_insn *insn, rtx op[], int *plen) { rtx dest = op[0]; @@ -4217,7 +4217,7 @@ avr_out_movqi_r_mr_reg_disp_tiny (rtx_insn *insn, rtx op[], int *plen) rtx x = XEXP (src, 0); avr_asm_len (TINY_ADIW (%I1, %J1, %o1) CR_TAB - "ld %0,%b1" , op, plen, -3); + "ld %0,%b1" , op, plen, -3); if (!reg_overlap_mentioned_p (dest, XEXP (x, 0)) && !reg_unused_after (insn, XEXP (x, 0))) @@ -4226,7 +4226,7 @@ avr_out_movqi_r_mr_reg_disp_tiny (rtx_insn *insn, rtx op[], int *plen) return ""; } -static const char* +static const char * out_movqi_r_mr (rtx_insn *insn, rtx op[], int *plen) { rtx dest = op[0]; @@ -4237,8 +4237,8 @@ out_movqi_r_mr (rtx_insn *insn, rtx op[], int *plen) { int n_words = AVR_TINY ? 1 : 2; return io_address_operand (x, QImode) - ? avr_asm_len ("in %0,%i1", op, plen, -1) - : avr_asm_len ("lds %0,%m1", op, plen, -n_words); + ? avr_asm_len ("in %0,%i1", op, plen, -1) + : avr_asm_len ("lds %0,%m1", op, plen, -n_words); } if (GET_CODE (x) == PLUS @@ -4250,40 +4250,40 @@ out_movqi_r_mr (rtx_insn *insn, rtx op[], int *plen) int disp = INTVAL (XEXP (x, 1)); if (AVR_TINY) - return avr_out_movqi_r_mr_reg_disp_tiny (insn, op, plen); + return avr_out_movqi_r_mr_reg_disp_tiny (insn, op, plen); if (disp - GET_MODE_SIZE (GET_MODE (src)) >= 63) - { - if (REGNO (XEXP (x, 0)) != REG_Y) - fatal_insn ("incorrect insn:",insn); - - if (disp <= 63 + MAX_LD_OFFSET (GET_MODE (src))) - return avr_asm_len ("adiw r28,%o1-63" CR_TAB - "ldd %0,Y+63" CR_TAB - "sbiw r28,%o1-63", op, plen, -3); - - return avr_asm_len ("subi r28,lo8(-%o1)" CR_TAB - "sbci r29,hi8(-%o1)" CR_TAB - "ld %0,Y" CR_TAB - "subi r28,lo8(%o1)" CR_TAB - "sbci r29,hi8(%o1)", op, plen, -5); - } + { + if (REGNO (XEXP (x, 0)) != REG_Y) + fatal_insn ("incorrect insn:",insn); + + if (disp <= 63 + MAX_LD_OFFSET (GET_MODE (src))) + return avr_asm_len ("adiw r28,%o1-63" CR_TAB + "ldd %0,Y+63" CR_TAB + "sbiw r28,%o1-63", op, plen, -3); + + return avr_asm_len ("subi r28,lo8(-%o1)" CR_TAB + "sbci r29,hi8(-%o1)" CR_TAB + "ld %0,Y" CR_TAB + "subi r28,lo8(%o1)" CR_TAB + "sbci r29,hi8(%o1)", op, plen, -5); + } else if (REGNO (XEXP (x, 0)) == REG_X) - { - /* This is a paranoid case LEGITIMIZE_RELOAD_ADDRESS must exclude - it but I have this situation with extremal optimizing options. */ + { + /* This is a paranoid case LEGITIMIZE_RELOAD_ADDRESS must exclude + it but I have this situation with extremal optimizing options. */ - avr_asm_len ("adiw r26,%o1" CR_TAB - "ld %0,X", op, plen, -2); + avr_asm_len ("adiw r26,%o1" CR_TAB + "ld %0,X", op, plen, -2); - if (!reg_overlap_mentioned_p (dest, XEXP (x, 0)) - && !reg_unused_after (insn, XEXP (x, 0))) - { - avr_asm_len ("sbiw r26,%o1", op, plen, 1); - } + if (!reg_overlap_mentioned_p (dest, XEXP (x, 0)) + && !reg_unused_after (insn, XEXP (x, 0))) + { + avr_asm_len ("sbiw r26,%o1", op, plen, 1); + } - return ""; - } + return ""; + } return avr_asm_len ("ldd %0,%1", op, plen, -1); } @@ -4294,7 +4294,7 @@ out_movqi_r_mr (rtx_insn *insn, rtx op[], int *plen) /* Same as movhi_r_mr, but TINY does not have ADIW, SBIW and LDD */ -static const char* +static const char * avr_out_movhi_r_mr_reg_no_disp_tiny (rtx_insn *insn, rtx op[], int *plen) { rtx dest = op[0]; @@ -4304,13 +4304,13 @@ avr_out_movhi_r_mr_reg_no_disp_tiny (rtx_insn *insn, rtx op[], int *plen) int reg_dest = true_regnum (dest); int reg_base = true_regnum (base); - if (reg_dest == reg_base) /* R = (R) */ + if (reg_dest == reg_base) /* R = (R) */ return avr_asm_len ("ld __tmp_reg__,%1+" CR_TAB "ld %B0,%1" CR_TAB "mov %A0,__tmp_reg__", op, plen, -3); avr_asm_len ("ld %A0,%1+" CR_TAB - "ld %B0,%1", op, plen, -2); + "ld %B0,%1", op, plen, -2); if (!reg_unused_after (insn, base)) avr_asm_len (TINY_SBIW (%E1, %F1, 1), op, plen, 2); @@ -4321,7 +4321,7 @@ avr_out_movhi_r_mr_reg_no_disp_tiny (rtx_insn *insn, rtx op[], int *plen) /* Same as movhi_r_mr, but TINY does not have ADIW, SBIW and LDD */ -static const char* +static const char * avr_out_movhi_r_mr_reg_disp_tiny (rtx_insn *insn, rtx op[], int *plen) { rtx dest = op[0]; @@ -4334,18 +4334,18 @@ avr_out_movhi_r_mr_reg_disp_tiny (rtx_insn *insn, rtx op[], int *plen) if (reg_base == reg_dest) { return avr_asm_len (TINY_ADIW (%I1, %J1, %o1) CR_TAB - "ld __tmp_reg__,%b1+" CR_TAB - "ld %B0,%b1" CR_TAB - "mov %A0,__tmp_reg__", op, plen, -5); + "ld __tmp_reg__,%b1+" CR_TAB + "ld %B0,%b1" CR_TAB + "mov %A0,__tmp_reg__", op, plen, -5); } else { avr_asm_len (TINY_ADIW (%I1, %J1, %o1) CR_TAB - "ld %A0,%b1+" CR_TAB - "ld %B0,%b1", op, plen, -4); + "ld %A0,%b1+" CR_TAB + "ld %B0,%b1", op, plen, -4); if (!reg_unused_after (insn, XEXP (base, 0))) - avr_asm_len (TINY_SBIW (%I1, %J1, %o1+1), op, plen, 2); + avr_asm_len (TINY_SBIW (%I1, %J1, %o1+1), op, plen, 2); return ""; } @@ -4354,7 +4354,7 @@ avr_out_movhi_r_mr_reg_disp_tiny (rtx_insn *insn, rtx op[], int *plen) /* Same as movhi_r_mr, but TINY does not have ADIW, SBIW and LDD */ -static const char* +static const char * avr_out_movhi_r_mr_pre_dec_tiny (rtx_insn *insn, rtx op[], int *plen) { int mem_volatile_p = 0; @@ -4371,16 +4371,16 @@ avr_out_movhi_r_mr_pre_dec_tiny (rtx_insn *insn, rtx op[], int *plen) if (!mem_volatile_p) return avr_asm_len ("ld %B0,%1" CR_TAB - "ld %A0,%1", op, plen, -2); + "ld %A0,%1", op, plen, -2); return avr_asm_len (TINY_SBIW (%I1, %J1, 2) CR_TAB - "ld %A0,%p1+" CR_TAB - "ld %B0,%p1" CR_TAB - TINY_SBIW (%I1, %J1, 1), op, plen, -6); + "ld %A0,%p1+" CR_TAB + "ld %B0,%p1" CR_TAB + TINY_SBIW (%I1, %J1, 1), op, plen, -6); } -static const char* +static const char * out_movhi_r_mr (rtx_insn *insn, rtx op[], int *plen) { rtx dest = op[0]; @@ -4395,22 +4395,22 @@ out_movhi_r_mr (rtx_insn *insn, rtx op[], int *plen) if (reg_base > 0) { if (AVR_TINY) - return avr_out_movhi_r_mr_reg_no_disp_tiny (insn, op, plen); + return avr_out_movhi_r_mr_reg_no_disp_tiny (insn, op, plen); if (reg_dest == reg_base) /* R = (R) */ - return avr_asm_len ("ld __tmp_reg__,%1+" CR_TAB - "ld %B0,%1" CR_TAB - "mov %A0,__tmp_reg__", op, plen, -3); + return avr_asm_len ("ld __tmp_reg__,%1+" CR_TAB + "ld %B0,%1" CR_TAB + "mov %A0,__tmp_reg__", op, plen, -3); if (reg_base != REG_X) - return avr_asm_len ("ld %A0,%1" CR_TAB - "ldd %B0,%1+1", op, plen, -2); + return avr_asm_len ("ld %A0,%1" CR_TAB + "ldd %B0,%1+1", op, plen, -2); avr_asm_len ("ld %A0,X+" CR_TAB - "ld %B0,X", op, plen, -2); + "ld %B0,X", op, plen, -2); if (!reg_unused_after (insn, base)) - avr_asm_len ("sbiw r26,1", op, plen, 1); + avr_asm_len ("sbiw r26,1", op, plen, 1); return ""; } @@ -4420,56 +4420,56 @@ out_movhi_r_mr (rtx_insn *insn, rtx op[], int *plen) int reg_base = true_regnum (XEXP (base, 0)); if (AVR_TINY) - return avr_out_movhi_r_mr_reg_disp_tiny (insn, op, plen); + return avr_out_movhi_r_mr_reg_disp_tiny (insn, op, plen); if (disp > MAX_LD_OFFSET (GET_MODE (src))) - { - if (REGNO (XEXP (base, 0)) != REG_Y) - fatal_insn ("incorrect insn:",insn); - - return disp <= 63 + MAX_LD_OFFSET (GET_MODE (src)) - ? avr_asm_len ("adiw r28,%o1-62" CR_TAB - "ldd %A0,Y+62" CR_TAB - "ldd %B0,Y+63" CR_TAB - "sbiw r28,%o1-62", op, plen, -4) - - : avr_asm_len ("subi r28,lo8(-%o1)" CR_TAB - "sbci r29,hi8(-%o1)" CR_TAB - "ld %A0,Y" CR_TAB - "ldd %B0,Y+1" CR_TAB - "subi r28,lo8(%o1)" CR_TAB - "sbci r29,hi8(%o1)", op, plen, -6); - } + { + if (REGNO (XEXP (base, 0)) != REG_Y) + fatal_insn ("incorrect insn:",insn); + + return disp <= 63 + MAX_LD_OFFSET (GET_MODE (src)) + ? avr_asm_len ("adiw r28,%o1-62" CR_TAB + "ldd %A0,Y+62" CR_TAB + "ldd %B0,Y+63" CR_TAB + "sbiw r28,%o1-62", op, plen, -4) + + : avr_asm_len ("subi r28,lo8(-%o1)" CR_TAB + "sbci r29,hi8(-%o1)" CR_TAB + "ld %A0,Y" CR_TAB + "ldd %B0,Y+1" CR_TAB + "subi r28,lo8(%o1)" CR_TAB + "sbci r29,hi8(%o1)", op, plen, -6); + } /* This is a paranoid case. LEGITIMIZE_RELOAD_ADDRESS must exclude - it but I have this situation with extremal - optimization options. */ + it but I have this situation with extremal + optimization options. */ if (reg_base == REG_X) - { - if (reg_base == reg_dest) - return avr_asm_len ("adiw r26,%o1" CR_TAB - "ld __tmp_reg__,X+" CR_TAB - "ld %B0,X" CR_TAB - "mov %A0,__tmp_reg__", op, plen, -4); + { + if (reg_base == reg_dest) + return avr_asm_len ("adiw r26,%o1" CR_TAB + "ld __tmp_reg__,X+" CR_TAB + "ld %B0,X" CR_TAB + "mov %A0,__tmp_reg__", op, plen, -4); - avr_asm_len ("adiw r26,%o1" CR_TAB - "ld %A0,X+" CR_TAB - "ld %B0,X", op, plen, -3); + avr_asm_len ("adiw r26,%o1" CR_TAB + "ld %A0,X+" CR_TAB + "ld %B0,X", op, plen, -3); - if (!reg_unused_after (insn, XEXP (base, 0))) - avr_asm_len ("sbiw r26,%o1+1", op, plen, 1); + if (!reg_unused_after (insn, XEXP (base, 0))) + avr_asm_len ("sbiw r26,%o1+1", op, plen, 1); - return ""; - } + return ""; + } return reg_base == reg_dest - ? avr_asm_len ("ldd __tmp_reg__,%A1" CR_TAB - "ldd %B0,%B1" CR_TAB - "mov %A0,__tmp_reg__", op, plen, -3) + ? avr_asm_len ("ldd __tmp_reg__,%A1" CR_TAB + "ldd %B0,%B1" CR_TAB + "mov %A0,__tmp_reg__", op, plen, -3) - : avr_asm_len ("ldd %A0,%A1" CR_TAB - "ldd %B0,%B1", op, plen, -2); + : avr_asm_len ("ldd %A0,%A1" CR_TAB + "ldd %B0,%B1", op, plen, -2); } else if (GET_CODE (base) == PRE_DEC) /* (--R) */ { @@ -4477,46 +4477,46 @@ out_movhi_r_mr (rtx_insn *insn, rtx op[], int *plen) return avr_out_movhi_r_mr_pre_dec_tiny (insn, op, plen); if (reg_overlap_mentioned_p (dest, XEXP (base, 0))) - fatal_insn ("incorrect insn:", insn); + fatal_insn ("incorrect insn:", insn); if (!mem_volatile_p) - return avr_asm_len ("ld %B0,%1" CR_TAB - "ld %A0,%1", op, plen, -2); + return avr_asm_len ("ld %B0,%1" CR_TAB + "ld %A0,%1", op, plen, -2); return REGNO (XEXP (base, 0)) == REG_X - ? avr_asm_len ("sbiw r26,2" CR_TAB - "ld %A0,X+" CR_TAB - "ld %B0,X" CR_TAB - "sbiw r26,1", op, plen, -4) + ? avr_asm_len ("sbiw r26,2" CR_TAB + "ld %A0,X+" CR_TAB + "ld %B0,X" CR_TAB + "sbiw r26,1", op, plen, -4) - : avr_asm_len ("sbiw %r1,2" CR_TAB - "ld %A0,%p1" CR_TAB - "ldd %B0,%p1+1", op, plen, -3); + : avr_asm_len ("sbiw %r1,2" CR_TAB + "ld %A0,%p1" CR_TAB + "ldd %B0,%p1+1", op, plen, -3); } else if (GET_CODE (base) == POST_INC) /* (R++) */ { if (reg_overlap_mentioned_p (dest, XEXP (base, 0))) - fatal_insn ("incorrect insn:", insn); + fatal_insn ("incorrect insn:", insn); return avr_asm_len ("ld %A0,%1" CR_TAB - "ld %B0,%1", op, plen, -2); + "ld %B0,%1", op, plen, -2); } else if (CONSTANT_ADDRESS_P (base)) { int n_words = AVR_TINY ? 2 : 4; return io_address_operand (base, HImode) - ? avr_asm_len ("in %A0,%i1" CR_TAB - "in %B0,%i1+1", op, plen, -2) + ? avr_asm_len ("in %A0,%i1" CR_TAB + "in %B0,%i1+1", op, plen, -2) - : avr_asm_len ("lds %A0,%m1" CR_TAB - "lds %B0,%m1+1", op, plen, -n_words); + : avr_asm_len ("lds %A0,%m1" CR_TAB + "lds %B0,%m1+1", op, plen, -n_words); } fatal_insn ("unknown move insn:",insn); return ""; } -static const char* +static const char * avr_out_movsi_r_mr_reg_no_disp_tiny (rtx_insn *insn, rtx op[], int *l) { rtx dest = op[0]; @@ -4562,7 +4562,7 @@ avr_out_movsi_r_mr_reg_no_disp_tiny (rtx_insn *insn, rtx op[], int *l) } -static const char* +static const char * avr_out_movsi_r_mr_reg_disp_tiny (rtx_insn *insn, rtx op[], int *l) { rtx dest = op[0]; @@ -4575,42 +4575,42 @@ avr_out_movsi_r_mr_reg_disp_tiny (rtx_insn *insn, rtx op[], int *l) { /* "ld r26,-X" is undefined */ return *l = 9, (TINY_ADIW (%I1, %J1, %o1+3) CR_TAB - "ld %D0,%b1" CR_TAB - "ld %C0,-%b1" CR_TAB - "ld __tmp_reg__,-%b1" CR_TAB - TINY_SBIW (%I1, %J1, 1) CR_TAB - "ld %A0,%b1" CR_TAB - "mov %B0,__tmp_reg__"); + "ld %D0,%b1" CR_TAB + "ld %C0,-%b1" CR_TAB + "ld __tmp_reg__,-%b1" CR_TAB + TINY_SBIW (%I1, %J1, 1) CR_TAB + "ld %A0,%b1" CR_TAB + "mov %B0,__tmp_reg__"); } else if (reg_dest == reg_base - 2) { return *l = 7, (TINY_ADIW (%I1, %J1, %o1) CR_TAB - "ld %A0,%b1+" CR_TAB - "ld %B0,%b1+" CR_TAB - "ld __tmp_reg__,%b1+" CR_TAB - "ld %D0,%b1" CR_TAB - "mov %C0,__tmp_reg__"); + "ld %A0,%b1+" CR_TAB + "ld %B0,%b1+" CR_TAB + "ld __tmp_reg__,%b1+" CR_TAB + "ld %D0,%b1" CR_TAB + "mov %C0,__tmp_reg__"); } else if (reg_unused_after (insn, XEXP (base, 0))) { return *l = 6, (TINY_ADIW (%I1, %J1, %o1) CR_TAB - "ld %A0,%b1+" CR_TAB - "ld %B0,%b1+" CR_TAB - "ld %C0,%b1+" CR_TAB - "ld %D0,%b1"); + "ld %A0,%b1+" CR_TAB + "ld %B0,%b1+" CR_TAB + "ld %C0,%b1+" CR_TAB + "ld %D0,%b1"); } else { return *l = 8, (TINY_ADIW (%I1, %J1, %o1) CR_TAB - "ld %A0,%b1+" CR_TAB - "ld %B0,%b1+" CR_TAB - "ld %C0,%b1+" CR_TAB - "ld %D0,%b1" CR_TAB - TINY_SBIW (%I1, %J1, %o1+3)); + "ld %A0,%b1+" CR_TAB + "ld %B0,%b1+" CR_TAB + "ld %C0,%b1+" CR_TAB + "ld %D0,%b1" CR_TAB + TINY_SBIW (%I1, %J1, %o1+3)); } } -static const char* +static const char * out_movsi_r_mr (rtx_insn *insn, rtx op[], int *l) { rtx dest = op[0]; @@ -4626,11 +4626,11 @@ out_movsi_r_mr (rtx_insn *insn, rtx op[], int *l) if (reg_base > 0) { if (AVR_TINY) - return avr_out_movsi_r_mr_reg_no_disp_tiny (insn, op, l); + return avr_out_movsi_r_mr_reg_no_disp_tiny (insn, op, l); - if (reg_base == REG_X) /* (R26) */ - { - if (reg_dest == REG_X) + if (reg_base == REG_X) /* (R26) */ + { + if (reg_dest == REG_X) /* "ld r26,-X" is undefined */ return *l=7, ("adiw r26,3" CR_TAB "ld r29,X" CR_TAB @@ -4639,51 +4639,51 @@ out_movsi_r_mr (rtx_insn *insn, rtx op[], int *l) "sbiw r26,1" CR_TAB "ld r26,X" CR_TAB "mov r27,__tmp_reg__"); - else if (reg_dest == REG_X - 2) - return *l=5, ("ld %A0,X+" CR_TAB - "ld %B0,X+" CR_TAB - "ld __tmp_reg__,X+" CR_TAB - "ld %D0,X" CR_TAB - "mov %C0,__tmp_reg__"); - else if (reg_unused_after (insn, base)) - return *l=4, ("ld %A0,X+" CR_TAB - "ld %B0,X+" CR_TAB - "ld %C0,X+" CR_TAB - "ld %D0,X"); - else - return *l=5, ("ld %A0,X+" CR_TAB - "ld %B0,X+" CR_TAB - "ld %C0,X+" CR_TAB - "ld %D0,X" CR_TAB - "sbiw r26,3"); - } + else if (reg_dest == REG_X - 2) + return *l=5, ("ld %A0,X+" CR_TAB + "ld %B0,X+" CR_TAB + "ld __tmp_reg__,X+" CR_TAB + "ld %D0,X" CR_TAB + "mov %C0,__tmp_reg__"); + else if (reg_unused_after (insn, base)) + return *l=4, ("ld %A0,X+" CR_TAB + "ld %B0,X+" CR_TAB + "ld %C0,X+" CR_TAB + "ld %D0,X"); + else + return *l=5, ("ld %A0,X+" CR_TAB + "ld %B0,X+" CR_TAB + "ld %C0,X+" CR_TAB + "ld %D0,X" CR_TAB + "sbiw r26,3"); + } else - { - if (reg_dest == reg_base) - return *l=5, ("ldd %D0,%1+3" CR_TAB - "ldd %C0,%1+2" CR_TAB - "ldd __tmp_reg__,%1+1" CR_TAB - "ld %A0,%1" CR_TAB - "mov %B0,__tmp_reg__"); - else if (reg_base == reg_dest + 2) - return *l=5, ("ld %A0,%1" CR_TAB - "ldd %B0,%1+1" CR_TAB - "ldd __tmp_reg__,%1+2" CR_TAB - "ldd %D0,%1+3" CR_TAB - "mov %C0,__tmp_reg__"); - else - return *l=4, ("ld %A0,%1" CR_TAB - "ldd %B0,%1+1" CR_TAB - "ldd %C0,%1+2" CR_TAB - "ldd %D0,%1+3"); - } + { + if (reg_dest == reg_base) + return *l=5, ("ldd %D0,%1+3" CR_TAB + "ldd %C0,%1+2" CR_TAB + "ldd __tmp_reg__,%1+1" CR_TAB + "ld %A0,%1" CR_TAB + "mov %B0,__tmp_reg__"); + else if (reg_base == reg_dest + 2) + return *l=5, ("ld %A0,%1" CR_TAB + "ldd %B0,%1+1" CR_TAB + "ldd __tmp_reg__,%1+2" CR_TAB + "ldd %D0,%1+3" CR_TAB + "mov %C0,__tmp_reg__"); + else + return *l=4, ("ld %A0,%1" CR_TAB + "ldd %B0,%1+1" CR_TAB + "ldd %C0,%1+2" CR_TAB + "ldd %D0,%1+3"); + } } else if (GET_CODE (base) == PLUS) /* (R + i) */ { int disp = INTVAL (XEXP (base, 1)); if (AVR_TINY) - return avr_out_movsi_r_mr_reg_disp_tiny (insn, op, l); + return avr_out_movsi_r_mr_reg_disp_tiny (insn, op, l); if (disp > MAX_LD_OFFSET (GET_MODE (src))) { @@ -4741,21 +4741,21 @@ out_movsi_r_mr (rtx_insn *insn, rtx op[], int *l) "sbiw r26,%o1+3"); } if (reg_dest == reg_base) - return *l=5, ("ldd %D0,%D1" CR_TAB - "ldd %C0,%C1" CR_TAB - "ldd __tmp_reg__,%B1" CR_TAB - "ldd %A0,%A1" CR_TAB - "mov %B0,__tmp_reg__"); + return *l=5, ("ldd %D0,%D1" CR_TAB + "ldd %C0,%C1" CR_TAB + "ldd __tmp_reg__,%B1" CR_TAB + "ldd %A0,%A1" CR_TAB + "mov %B0,__tmp_reg__"); else if (reg_dest == reg_base - 2) - return *l=5, ("ldd %A0,%A1" CR_TAB - "ldd %B0,%B1" CR_TAB - "ldd __tmp_reg__,%C1" CR_TAB - "ldd %D0,%D1" CR_TAB - "mov %C0,__tmp_reg__"); + return *l=5, ("ldd %A0,%A1" CR_TAB + "ldd %B0,%B1" CR_TAB + "ldd __tmp_reg__,%C1" CR_TAB + "ldd %D0,%D1" CR_TAB + "mov %C0,__tmp_reg__"); return *l=4, ("ldd %A0,%A1" CR_TAB - "ldd %B0,%B1" CR_TAB - "ldd %C0,%C1" CR_TAB - "ldd %D0,%D1"); + "ldd %B0,%B1" CR_TAB + "ldd %C0,%C1" CR_TAB + "ldd %D0,%D1"); } else if (GET_CODE (base) == PRE_DEC) /* (--R) */ return *l=4, ("ld %D0,%1" CR_TAB @@ -4770,28 +4770,28 @@ out_movsi_r_mr (rtx_insn *insn, rtx op[], int *l) else if (CONSTANT_ADDRESS_P (base)) { if (io_address_operand (base, SImode)) - { - *l = 4; - return ("in %A0,%i1" CR_TAB - "in %B0,%i1+1" CR_TAB - "in %C0,%i1+2" CR_TAB - "in %D0,%i1+3"); - } + { + *l = 4; + return ("in %A0,%i1" CR_TAB + "in %B0,%i1+1" CR_TAB + "in %C0,%i1+2" CR_TAB + "in %D0,%i1+3"); + } else - { - *l = AVR_TINY ? 4 : 8; - return ("lds %A0,%m1" CR_TAB - "lds %B0,%m1+1" CR_TAB - "lds %C0,%m1+2" CR_TAB - "lds %D0,%m1+3"); - } + { + *l = AVR_TINY ? 4 : 8; + return ("lds %A0,%m1" CR_TAB + "lds %B0,%m1+1" CR_TAB + "lds %C0,%m1+2" CR_TAB + "lds %D0,%m1+3"); + } } fatal_insn ("unknown move insn:",insn); return ""; } -static const char* +static const char * avr_out_movsi_mr_r_reg_no_disp_tiny (rtx_insn *insn, rtx op[], int *l) { rtx dest = op[0]; @@ -4804,35 +4804,35 @@ avr_out_movsi_mr_r_reg_no_disp_tiny (rtx_insn *insn, rtx op[], int *l) { /* "ld r26,-X" is undefined */ if (reg_unused_after (insn, base)) - { - return *l = 7, ("mov __tmp_reg__, %B1" CR_TAB + { + return *l = 7, ("mov __tmp_reg__, %B1" CR_TAB "st %0,%A1" CR_TAB TINY_ADIW (%E0, %F0, 1) CR_TAB "st %0+,__tmp_reg__" CR_TAB "st %0+,%C1" CR_TAB "st %0+,%D1"); - } + } else - { - return *l = 9, ("mov __tmp_reg__, %B1" CR_TAB + { + return *l = 9, ("mov __tmp_reg__, %B1" CR_TAB "st %0,%A1" CR_TAB TINY_ADIW (%E0, %F0, 1) CR_TAB "st %0+,__tmp_reg__" CR_TAB "st %0+,%C1" CR_TAB "st %0+,%D1" CR_TAB TINY_SBIW (%E0, %F0, 3)); - } + } } else if (reg_base == reg_src + 2) { if (reg_unused_after (insn, base)) return *l = 7, ("mov __zero_reg__,%C1" CR_TAB - "mov __tmp_reg__,%D1" CR_TAB - "st %0+,%A1" CR_TAB - "st %0+,%B1" CR_TAB - "st %0+,__zero_reg__" CR_TAB - "st %0,__tmp_reg__" CR_TAB - "clr __zero_reg__"); + "mov __tmp_reg__,%D1" CR_TAB + "st %0+,%A1" CR_TAB + "st %0+,%B1" CR_TAB + "st %0+,__zero_reg__" CR_TAB + "st %0,__tmp_reg__" CR_TAB + "clr __zero_reg__"); else return *l = 9, ("mov __zero_reg__,%C1" CR_TAB "mov __tmp_reg__,%D1" CR_TAB @@ -4851,7 +4851,7 @@ avr_out_movsi_mr_r_reg_no_disp_tiny (rtx_insn *insn, rtx op[], int *l) TINY_SBIW (%E0, %F0, 3)); } -static const char* +static const char * avr_out_movsi_mr_r_reg_disp_tiny (rtx op[], int *l) { rtx dest = op[0]; @@ -4864,38 +4864,38 @@ avr_out_movsi_mr_r_reg_disp_tiny (rtx op[], int *l) { *l = 11; return ("mov __tmp_reg__,%A2" CR_TAB - "mov __zero_reg__,%B2" CR_TAB - TINY_ADIW (%I0, %J0, %o0) CR_TAB - "st %b0+,__tmp_reg__" CR_TAB - "st %b0+,__zero_reg__" CR_TAB - "st %b0+,%C2" CR_TAB - "st %b0,%D2" CR_TAB - "clr __zero_reg__" CR_TAB - TINY_SBIW (%I0, %J0, %o0+3)); + "mov __zero_reg__,%B2" CR_TAB + TINY_ADIW (%I0, %J0, %o0) CR_TAB + "st %b0+,__tmp_reg__" CR_TAB + "st %b0+,__zero_reg__" CR_TAB + "st %b0+,%C2" CR_TAB + "st %b0,%D2" CR_TAB + "clr __zero_reg__" CR_TAB + TINY_SBIW (%I0, %J0, %o0+3)); } else if (reg_src == reg_base - 2) { *l = 11; return ("mov __tmp_reg__,%C2" CR_TAB - "mov __zero_reg__,%D2" CR_TAB - TINY_ADIW (%I0, %J0, %o0) CR_TAB - "st %b0+,%A0" CR_TAB - "st %b0+,%B0" CR_TAB - "st %b0+,__tmp_reg__" CR_TAB - "st %b0,__zero_reg__" CR_TAB - "clr __zero_reg__" CR_TAB - TINY_SBIW (%I0, %J0, %o0+3)); + "mov __zero_reg__,%D2" CR_TAB + TINY_ADIW (%I0, %J0, %o0) CR_TAB + "st %b0+,%A0" CR_TAB + "st %b0+,%B0" CR_TAB + "st %b0+,__tmp_reg__" CR_TAB + "st %b0,__zero_reg__" CR_TAB + "clr __zero_reg__" CR_TAB + TINY_SBIW (%I0, %J0, %o0+3)); } *l = 8; return (TINY_ADIW (%I0, %J0, %o0) CR_TAB - "st %b0+,%A1" CR_TAB - "st %b0+,%B1" CR_TAB - "st %b0+,%C1" CR_TAB - "st %b0,%D1" CR_TAB - TINY_SBIW (%I0, %J0, %o0+3)); + "st %b0+,%A1" CR_TAB + "st %b0+,%B1" CR_TAB + "st %b0+,%C1" CR_TAB + "st %b0,%D1" CR_TAB + TINY_SBIW (%I0, %J0, %o0+3)); } -static const char* +static const char * out_movsi_mr_r (rtx_insn *insn, rtx op[], int *l) { rtx dest = op[0]; @@ -4911,76 +4911,76 @@ out_movsi_mr_r (rtx_insn *insn, rtx op[], int *l) if (CONSTANT_ADDRESS_P (base)) { if (io_address_operand (base, SImode)) - { - return *l=4,("out %i0, %A1" CR_TAB - "out %i0+1,%B1" CR_TAB - "out %i0+2,%C1" CR_TAB - "out %i0+3,%D1"); - } + { + return *l=4,("out %i0, %A1" CR_TAB + "out %i0+1,%B1" CR_TAB + "out %i0+2,%C1" CR_TAB + "out %i0+3,%D1"); + } else - { - *l = AVR_TINY ? 4 : 8; - return ("sts %m0,%A1" CR_TAB - "sts %m0+1,%B1" CR_TAB - "sts %m0+2,%C1" CR_TAB - "sts %m0+3,%D1"); - } + { + *l = AVR_TINY ? 4 : 8; + return ("sts %m0,%A1" CR_TAB + "sts %m0+1,%B1" CR_TAB + "sts %m0+2,%C1" CR_TAB + "sts %m0+3,%D1"); + } } - if (reg_base > 0) /* (r) */ + if (reg_base > 0) /* (r) */ { if (AVR_TINY) - return avr_out_movsi_mr_r_reg_no_disp_tiny (insn, op, l); + return avr_out_movsi_mr_r_reg_no_disp_tiny (insn, op, l); - if (reg_base == REG_X) /* (R26) */ - { - if (reg_src == REG_X) - { + if (reg_base == REG_X) /* (R26) */ + { + if (reg_src == REG_X) + { /* "st X+,r26" is undefined */ - if (reg_unused_after (insn, base)) + if (reg_unused_after (insn, base)) return *l=6, ("mov __tmp_reg__,r27" CR_TAB "st X,r26" CR_TAB "adiw r26,1" CR_TAB "st X+,__tmp_reg__" CR_TAB "st X+,r28" CR_TAB "st X,r29"); - else - return *l=7, ("mov __tmp_reg__,r27" CR_TAB + else + return *l=7, ("mov __tmp_reg__,r27" CR_TAB "st X,r26" CR_TAB "adiw r26,1" CR_TAB "st X+,__tmp_reg__" CR_TAB "st X+,r28" CR_TAB "st X,r29" CR_TAB "sbiw r26,3"); - } - else if (reg_base == reg_src + 2) - { - if (reg_unused_after (insn, base)) - return *l=7, ("mov __zero_reg__,%C1" CR_TAB - "mov __tmp_reg__,%D1" CR_TAB - "st %0+,%A1" CR_TAB - "st %0+,%B1" CR_TAB - "st %0+,__zero_reg__" CR_TAB - "st %0,__tmp_reg__" CR_TAB - "clr __zero_reg__"); - else - return *l=8, ("mov __zero_reg__,%C1" CR_TAB - "mov __tmp_reg__,%D1" CR_TAB - "st %0+,%A1" CR_TAB - "st %0+,%B1" CR_TAB - "st %0+,__zero_reg__" CR_TAB - "st %0,__tmp_reg__" CR_TAB - "clr __zero_reg__" CR_TAB - "sbiw r26,3"); - } - return *l=5, ("st %0+,%A1" CR_TAB - "st %0+,%B1" CR_TAB - "st %0+,%C1" CR_TAB - "st %0,%D1" CR_TAB - "sbiw r26,3"); - } + } + else if (reg_base == reg_src + 2) + { + if (reg_unused_after (insn, base)) + return *l=7, ("mov __zero_reg__,%C1" CR_TAB + "mov __tmp_reg__,%D1" CR_TAB + "st %0+,%A1" CR_TAB + "st %0+,%B1" CR_TAB + "st %0+,__zero_reg__" CR_TAB + "st %0,__tmp_reg__" CR_TAB + "clr __zero_reg__"); + else + return *l=8, ("mov __zero_reg__,%C1" CR_TAB + "mov __tmp_reg__,%D1" CR_TAB + "st %0+,%A1" CR_TAB + "st %0+,%B1" CR_TAB + "st %0+,__zero_reg__" CR_TAB + "st %0,__tmp_reg__" CR_TAB + "clr __zero_reg__" CR_TAB + "sbiw r26,3"); + } + return *l=5, ("st %0+,%A1" CR_TAB + "st %0+,%B1" CR_TAB + "st %0+,%C1" CR_TAB + "st %0,%D1" CR_TAB + "sbiw r26,3"); + } else - return *l=4, ("st %0,%A1" CR_TAB + return *l=4, ("st %0,%A1" CR_TAB "std %0+1,%B1" CR_TAB "std %0+2,%C1" CR_TAB "std %0+3,%D1"); @@ -4990,7 +4990,7 @@ out_movsi_mr_r (rtx_insn *insn, rtx op[], int *l) int disp = INTVAL (XEXP (base, 1)); if (AVR_TINY) - return avr_out_movsi_mr_r_reg_disp_tiny (op, l); + return avr_out_movsi_mr_r_reg_disp_tiny (op, l); reg_base = REGNO (XEXP (base, 0)); if (disp > MAX_LD_OFFSET (GET_MODE (dest))) @@ -5125,8 +5125,8 @@ output_movsisf (rtx_insn *insn, rtx operands[], int *l) } else if (CONSTANT_P (src)) { - return output_reload_insisf (operands, NULL_RTX, real_l); - } + return output_reload_insisf (operands, NULL_RTX, real_l); + } else if (MEM_P (src)) return out_movsi_r_mr (insn, operands, real_l); /* mov r,m */ } @@ -5135,7 +5135,7 @@ output_movsisf (rtx_insn *insn, rtx operands[], int *l) const char *templ; if (src == CONST0_RTX (GET_MODE (dest))) - operands[1] = zero_reg_rtx; + operands[1] = zero_reg_rtx; templ = out_movsi_mr_r (insn, operands, real_l); @@ -5152,7 +5152,7 @@ output_movsisf (rtx_insn *insn, rtx operands[], int *l) /* Handle loads of 24-bit types from memory to register. */ -static const char* +static const char * avr_out_load_psi_reg_no_disp_tiny (rtx_insn *insn, rtx *op, int *plen) { rtx dest = op[0]; @@ -5164,11 +5164,11 @@ avr_out_load_psi_reg_no_disp_tiny (rtx_insn *insn, rtx *op, int *plen) if (reg_base == reg_dest) { return avr_asm_len (TINY_ADIW (%E1, %F1, 2) CR_TAB - "ld %C0,%1" CR_TAB - "ld __tmp_reg__,-%1" CR_TAB - TINY_SBIW (%E1, %F1, 1) CR_TAB - "ld %A0,%1" CR_TAB - "mov %B0,__tmp_reg__", op, plen, -8); + "ld %C0,%1" CR_TAB + "ld __tmp_reg__,-%1" CR_TAB + TINY_SBIW (%E1, %F1, 1) CR_TAB + "ld %A0,%1" CR_TAB + "mov %B0,__tmp_reg__", op, plen, -8); } else { @@ -5177,15 +5177,15 @@ avr_out_load_psi_reg_no_disp_tiny (rtx_insn *insn, rtx *op, int *plen) "ld %C0,%1", op, plen, -3); if (reg_dest != reg_base - 2 - && !reg_unused_after (insn, base)) - { - avr_asm_len (TINY_SBIW (%E1, %F1, 2), op, plen, 2); - } + && !reg_unused_after (insn, base)) + { + avr_asm_len (TINY_SBIW (%E1, %F1, 2), op, plen, 2); + } return ""; } } -static const char* +static const char * avr_out_load_psi_reg_disp_tiny (rtx_insn *insn, rtx *op, int *plen) { rtx dest = op[0]; @@ -5198,28 +5198,28 @@ avr_out_load_psi_reg_disp_tiny (rtx_insn *insn, rtx *op, int *plen) if (reg_base == reg_dest) { return avr_asm_len (TINY_ADIW (%I1, %J1, %o1+2) CR_TAB - "ld %C0,%b1" CR_TAB - "ld __tmp_reg__,-%b1" CR_TAB - TINY_SBIW (%I1, %J1, 1) CR_TAB - "ld %A0,%b1" CR_TAB - "mov %B0,__tmp_reg__", op, plen, -8); + "ld %C0,%b1" CR_TAB + "ld __tmp_reg__,-%b1" CR_TAB + TINY_SBIW (%I1, %J1, 1) CR_TAB + "ld %A0,%b1" CR_TAB + "mov %B0,__tmp_reg__", op, plen, -8); } else { avr_asm_len (TINY_ADIW (%I1, %J1, %o1) CR_TAB - "ld %A0,%b1+" CR_TAB - "ld %B0,%b1+" CR_TAB - "ld %C0,%b1", op, plen, -5); + "ld %A0,%b1+" CR_TAB + "ld %B0,%b1+" CR_TAB + "ld %C0,%b1", op, plen, -5); if (reg_dest != reg_base - 2 - && !reg_unused_after (insn, XEXP (base, 0))) - avr_asm_len (TINY_SBIW (%I1, %J1, %o1+2), op, plen, 2); + && !reg_unused_after (insn, XEXP (base, 0))) + avr_asm_len (TINY_SBIW (%I1, %J1, %o1+2), op, plen, 2); return ""; } } -static const char* +static const char * avr_out_load_psi (rtx_insn *insn, rtx *op, int *plen) { rtx dest = op[0]; @@ -5231,126 +5231,126 @@ avr_out_load_psi (rtx_insn *insn, rtx *op, int *plen) if (reg_base > 0) { if (AVR_TINY) - return avr_out_load_psi_reg_no_disp_tiny (insn, op, plen); - - if (reg_base == REG_X) /* (R26) */ - { - if (reg_dest == REG_X) - /* "ld r26,-X" is undefined */ - return avr_asm_len ("adiw r26,2" CR_TAB - "ld r28,X" CR_TAB - "ld __tmp_reg__,-X" CR_TAB - "sbiw r26,1" CR_TAB - "ld r26,X" CR_TAB - "mov r27,__tmp_reg__", op, plen, -6); - else - { - avr_asm_len ("ld %A0,X+" CR_TAB - "ld %B0,X+" CR_TAB - "ld %C0,X", op, plen, -3); - - if (reg_dest != REG_X - 2 - && !reg_unused_after (insn, base)) - { - avr_asm_len ("sbiw r26,2", op, plen, 1); - } - - return ""; - } - } + return avr_out_load_psi_reg_no_disp_tiny (insn, op, plen); + + if (reg_base == REG_X) /* (R26) */ + { + if (reg_dest == REG_X) + /* "ld r26,-X" is undefined */ + return avr_asm_len ("adiw r26,2" CR_TAB + "ld r28,X" CR_TAB + "ld __tmp_reg__,-X" CR_TAB + "sbiw r26,1" CR_TAB + "ld r26,X" CR_TAB + "mov r27,__tmp_reg__", op, plen, -6); + else + { + avr_asm_len ("ld %A0,X+" CR_TAB + "ld %B0,X+" CR_TAB + "ld %C0,X", op, plen, -3); + + if (reg_dest != REG_X - 2 + && !reg_unused_after (insn, base)) + { + avr_asm_len ("sbiw r26,2", op, plen, 1); + } + + return ""; + } + } else /* reg_base != REG_X */ - { - if (reg_dest == reg_base) - return avr_asm_len ("ldd %C0,%1+2" CR_TAB - "ldd __tmp_reg__,%1+1" CR_TAB - "ld %A0,%1" CR_TAB - "mov %B0,__tmp_reg__", op, plen, -4); - else - return avr_asm_len ("ld %A0,%1" CR_TAB - "ldd %B0,%1+1" CR_TAB - "ldd %C0,%1+2", op, plen, -3); - } + { + if (reg_dest == reg_base) + return avr_asm_len ("ldd %C0,%1+2" CR_TAB + "ldd __tmp_reg__,%1+1" CR_TAB + "ld %A0,%1" CR_TAB + "mov %B0,__tmp_reg__", op, plen, -4); + else + return avr_asm_len ("ld %A0,%1" CR_TAB + "ldd %B0,%1+1" CR_TAB + "ldd %C0,%1+2", op, plen, -3); + } } else if (GET_CODE (base) == PLUS) /* (R + i) */ { int disp = INTVAL (XEXP (base, 1)); if (AVR_TINY) - return avr_out_load_psi_reg_disp_tiny (insn, op, plen); + return avr_out_load_psi_reg_disp_tiny (insn, op, plen); if (disp > MAX_LD_OFFSET (GET_MODE (src))) - { - if (REGNO (XEXP (base, 0)) != REG_Y) - fatal_insn ("incorrect insn:",insn); - - if (disp <= 63 + MAX_LD_OFFSET (GET_MODE (src))) - return avr_asm_len ("adiw r28,%o1-61" CR_TAB - "ldd %A0,Y+61" CR_TAB - "ldd %B0,Y+62" CR_TAB - "ldd %C0,Y+63" CR_TAB - "sbiw r28,%o1-61", op, plen, -5); - - return avr_asm_len ("subi r28,lo8(-%o1)" CR_TAB - "sbci r29,hi8(-%o1)" CR_TAB - "ld %A0,Y" CR_TAB - "ldd %B0,Y+1" CR_TAB - "ldd %C0,Y+2" CR_TAB - "subi r28,lo8(%o1)" CR_TAB - "sbci r29,hi8(%o1)", op, plen, -7); - } + { + if (REGNO (XEXP (base, 0)) != REG_Y) + fatal_insn ("incorrect insn:",insn); + + if (disp <= 63 + MAX_LD_OFFSET (GET_MODE (src))) + return avr_asm_len ("adiw r28,%o1-61" CR_TAB + "ldd %A0,Y+61" CR_TAB + "ldd %B0,Y+62" CR_TAB + "ldd %C0,Y+63" CR_TAB + "sbiw r28,%o1-61", op, plen, -5); + + return avr_asm_len ("subi r28,lo8(-%o1)" CR_TAB + "sbci r29,hi8(-%o1)" CR_TAB + "ld %A0,Y" CR_TAB + "ldd %B0,Y+1" CR_TAB + "ldd %C0,Y+2" CR_TAB + "subi r28,lo8(%o1)" CR_TAB + "sbci r29,hi8(%o1)", op, plen, -7); + } reg_base = true_regnum (XEXP (base, 0)); if (reg_base == REG_X) - { - /* R = (X + d) */ - if (reg_dest == REG_X) - { - /* "ld r26,-X" is undefined */ - return avr_asm_len ("adiw r26,%o1+2" CR_TAB - "ld r28,X" CR_TAB - "ld __tmp_reg__,-X" CR_TAB - "sbiw r26,1" CR_TAB - "ld r26,X" CR_TAB - "mov r27,__tmp_reg__", op, plen, -6); - } - - avr_asm_len ("adiw r26,%o1" CR_TAB - "ld %A0,X+" CR_TAB - "ld %B0,X+" CR_TAB - "ld %C0,X", op, plen, -4); - - if (reg_dest != REG_W - && !reg_unused_after (insn, XEXP (base, 0))) - avr_asm_len ("sbiw r26,%o1+2", op, plen, 1); - - return ""; - } + { + /* R = (X + d) */ + if (reg_dest == REG_X) + { + /* "ld r26,-X" is undefined */ + return avr_asm_len ("adiw r26,%o1+2" CR_TAB + "ld r28,X" CR_TAB + "ld __tmp_reg__,-X" CR_TAB + "sbiw r26,1" CR_TAB + "ld r26,X" CR_TAB + "mov r27,__tmp_reg__", op, plen, -6); + } + + avr_asm_len ("adiw r26,%o1" CR_TAB + "ld %A0,X+" CR_TAB + "ld %B0,X+" CR_TAB + "ld %C0,X", op, plen, -4); + + if (reg_dest != REG_W + && !reg_unused_after (insn, XEXP (base, 0))) + avr_asm_len ("sbiw r26,%o1+2", op, plen, 1); + + return ""; + } if (reg_dest == reg_base) - return avr_asm_len ("ldd %C0,%C1" CR_TAB - "ldd __tmp_reg__,%B1" CR_TAB - "ldd %A0,%A1" CR_TAB - "mov %B0,__tmp_reg__", op, plen, -4); + return avr_asm_len ("ldd %C0,%C1" CR_TAB + "ldd __tmp_reg__,%B1" CR_TAB + "ldd %A0,%A1" CR_TAB + "mov %B0,__tmp_reg__", op, plen, -4); return avr_asm_len ("ldd %A0,%A1" CR_TAB - "ldd %B0,%B1" CR_TAB - "ldd %C0,%C1", op, plen, -3); + "ldd %B0,%B1" CR_TAB + "ldd %C0,%C1", op, plen, -3); } else if (GET_CODE (base) == PRE_DEC) /* (--R) */ return avr_asm_len ("ld %C0,%1" CR_TAB - "ld %B0,%1" CR_TAB - "ld %A0,%1", op, plen, -3); + "ld %B0,%1" CR_TAB + "ld %A0,%1", op, plen, -3); else if (GET_CODE (base) == POST_INC) /* (R++) */ return avr_asm_len ("ld %A0,%1" CR_TAB - "ld %B0,%1" CR_TAB - "ld %C0,%1", op, plen, -3); + "ld %B0,%1" CR_TAB + "ld %C0,%1", op, plen, -3); else if (CONSTANT_ADDRESS_P (base)) { int n_words = AVR_TINY ? 3 : 6; - return avr_asm_len ("lds %A0,%m1" CR_TAB - "lds %B0,%m1+1" CR_TAB - "lds %C0,%m1+2", op, plen , -n_words); + return avr_asm_len ("lds %A0,%m1" CR_TAB + "lds %B0,%m1+1" CR_TAB + "lds %C0,%m1+2", op, plen , -n_words); } fatal_insn ("unknown move insn:",insn); @@ -5358,7 +5358,7 @@ avr_out_load_psi (rtx_insn *insn, rtx *op, int *plen) } -static const char* +static const char * avr_out_store_psi_reg_no_disp_tiny (rtx_insn *insn, rtx *op, int *plen) { rtx dest = op[0]; @@ -5370,25 +5370,25 @@ avr_out_store_psi_reg_no_disp_tiny (rtx_insn *insn, rtx *op, int *plen) if (reg_base == reg_src) { avr_asm_len ("st %0,%A1" CR_TAB - "mov __tmp_reg__,%B1" CR_TAB - TINY_ADIW (%E0, %F0, 1) CR_TAB /* st X+, r27 is undefined */ - "st %0+,__tmp_reg__" CR_TAB - "st %0,%C1", op, plen, -6); + "mov __tmp_reg__,%B1" CR_TAB + TINY_ADIW (%E0, %F0, 1) CR_TAB /* st X+, r27 is undefined */ + "st %0+,__tmp_reg__" CR_TAB + "st %0,%C1", op, plen, -6); } else if (reg_src == reg_base - 2) { avr_asm_len ("st %0,%A1" CR_TAB - "mov __tmp_reg__,%C1" CR_TAB - TINY_ADIW (%E0, %F0, 1) CR_TAB - "st %0+,%B1" CR_TAB - "st %0,__tmp_reg__", op, plen, 6); + "mov __tmp_reg__,%C1" CR_TAB + TINY_ADIW (%E0, %F0, 1) CR_TAB + "st %0+,%B1" CR_TAB + "st %0,__tmp_reg__", op, plen, 6); } else { avr_asm_len ("st %0+,%A1" CR_TAB - "st %0+,%B1" CR_TAB - "st %0,%C1", op, plen, -3); + "st %0+,%B1" CR_TAB + "st %0,%C1", op, plen, -3); } if (!reg_unused_after (insn, base)) @@ -5397,7 +5397,7 @@ avr_out_store_psi_reg_no_disp_tiny (rtx_insn *insn, rtx *op, int *plen) return ""; } -static const char* +static const char * avr_out_store_psi_reg_disp_tiny (rtx_insn *insn, rtx *op, int *plen) { rtx dest = op[0]; @@ -5408,23 +5408,23 @@ avr_out_store_psi_reg_disp_tiny (rtx_insn *insn, rtx *op, int *plen) if (reg_src == reg_base) avr_asm_len ("mov __tmp_reg__,%A1" CR_TAB - "mov __zero_reg__,%B1" CR_TAB - TINY_ADIW (%I0, %J0, %o0) CR_TAB - "st %b0+,__tmp_reg__" CR_TAB - "st %b0+,__zero_reg__" CR_TAB - "st %b0,%C1" CR_TAB - "clr __zero_reg__", op, plen, -8); + "mov __zero_reg__,%B1" CR_TAB + TINY_ADIW (%I0, %J0, %o0) CR_TAB + "st %b0+,__tmp_reg__" CR_TAB + "st %b0+,__zero_reg__" CR_TAB + "st %b0,%C1" CR_TAB + "clr __zero_reg__", op, plen, -8); else if (reg_src == reg_base - 2) avr_asm_len ("mov __tmp_reg__,%C1" CR_TAB - TINY_ADIW (%I0, %J0, %o0) CR_TAB - "st %b0+,%A1" CR_TAB - "st %b0+,%B1" CR_TAB - "st %b0,__tmp_reg__", op, plen, -6); + TINY_ADIW (%I0, %J0, %o0) CR_TAB + "st %b0+,%A1" CR_TAB + "st %b0+,%B1" CR_TAB + "st %b0,__tmp_reg__", op, plen, -6); else avr_asm_len (TINY_ADIW (%I0, %J0, %o0) CR_TAB - "st %b0+,%A1" CR_TAB - "st %b0+,%B1" CR_TAB - "st %b0,%C1", op, plen, -5); + "st %b0+,%A1" CR_TAB + "st %b0+,%B1" CR_TAB + "st %b0,%C1", op, plen, -5); if (!reg_unused_after (insn, XEXP (base, 0))) avr_asm_len (TINY_SBIW (%I0, %J0, %o0+2), op, plen, 2); @@ -5434,7 +5434,7 @@ avr_out_store_psi_reg_disp_tiny (rtx_insn *insn, rtx *op, int *plen) /* Handle store of 24-bit type from register or zero to memory. */ -static const char* +static const char * avr_out_store_psi (rtx_insn *insn, rtx *op, int *plen) { rtx dest = op[0]; @@ -5446,90 +5446,90 @@ avr_out_store_psi (rtx_insn *insn, rtx *op, int *plen) { int n_words = AVR_TINY ? 3 : 6; return avr_asm_len ("sts %m0,%A1" CR_TAB - "sts %m0+1,%B1" CR_TAB - "sts %m0+2,%C1", op, plen, -n_words); + "sts %m0+1,%B1" CR_TAB + "sts %m0+2,%C1", op, plen, -n_words); } - if (reg_base > 0) /* (r) */ + if (reg_base > 0) /* (r) */ { if (AVR_TINY) - return avr_out_store_psi_reg_no_disp_tiny (insn, op, plen); + return avr_out_store_psi_reg_no_disp_tiny (insn, op, plen); - if (reg_base == REG_X) /* (R26) */ - { - gcc_assert (!reg_overlap_mentioned_p (base, src)); + if (reg_base == REG_X) /* (R26) */ + { + gcc_assert (!reg_overlap_mentioned_p (base, src)); - avr_asm_len ("st %0+,%A1" CR_TAB - "st %0+,%B1" CR_TAB - "st %0,%C1", op, plen, -3); + avr_asm_len ("st %0+,%A1" CR_TAB + "st %0+,%B1" CR_TAB + "st %0,%C1", op, plen, -3); - if (!reg_unused_after (insn, base)) - avr_asm_len ("sbiw r26,2", op, plen, 1); + if (!reg_unused_after (insn, base)) + avr_asm_len ("sbiw r26,2", op, plen, 1); - return ""; - } + return ""; + } else - return avr_asm_len ("st %0,%A1" CR_TAB - "std %0+1,%B1" CR_TAB - "std %0+2,%C1", op, plen, -3); + return avr_asm_len ("st %0,%A1" CR_TAB + "std %0+1,%B1" CR_TAB + "std %0+2,%C1", op, plen, -3); } else if (GET_CODE (base) == PLUS) /* (R + i) */ { int disp = INTVAL (XEXP (base, 1)); if (AVR_TINY) - return avr_out_store_psi_reg_disp_tiny (insn, op, plen); + return avr_out_store_psi_reg_disp_tiny (insn, op, plen); reg_base = REGNO (XEXP (base, 0)); if (disp > MAX_LD_OFFSET (GET_MODE (dest))) - { - if (reg_base != REG_Y) - fatal_insn ("incorrect insn:",insn); - - if (disp <= 63 + MAX_LD_OFFSET (GET_MODE (dest))) - return avr_asm_len ("adiw r28,%o0-61" CR_TAB - "std Y+61,%A1" CR_TAB - "std Y+62,%B1" CR_TAB - "std Y+63,%C1" CR_TAB - "sbiw r28,%o0-61", op, plen, -5); - - return avr_asm_len ("subi r28,lo8(-%o0)" CR_TAB - "sbci r29,hi8(-%o0)" CR_TAB - "st Y,%A1" CR_TAB - "std Y+1,%B1" CR_TAB - "std Y+2,%C1" CR_TAB - "subi r28,lo8(%o0)" CR_TAB - "sbci r29,hi8(%o0)", op, plen, -7); - } + { + if (reg_base != REG_Y) + fatal_insn ("incorrect insn:",insn); + + if (disp <= 63 + MAX_LD_OFFSET (GET_MODE (dest))) + return avr_asm_len ("adiw r28,%o0-61" CR_TAB + "std Y+61,%A1" CR_TAB + "std Y+62,%B1" CR_TAB + "std Y+63,%C1" CR_TAB + "sbiw r28,%o0-61", op, plen, -5); + + return avr_asm_len ("subi r28,lo8(-%o0)" CR_TAB + "sbci r29,hi8(-%o0)" CR_TAB + "st Y,%A1" CR_TAB + "std Y+1,%B1" CR_TAB + "std Y+2,%C1" CR_TAB + "subi r28,lo8(%o0)" CR_TAB + "sbci r29,hi8(%o0)", op, plen, -7); + } if (reg_base == REG_X) - { - /* (X + d) = R */ - gcc_assert (!reg_overlap_mentioned_p (XEXP (base, 0), src)); + { + /* (X + d) = R */ + gcc_assert (!reg_overlap_mentioned_p (XEXP (base, 0), src)); - avr_asm_len ("adiw r26,%o0" CR_TAB - "st X+,%A1" CR_TAB - "st X+,%B1" CR_TAB - "st X,%C1", op, plen, -4); + avr_asm_len ("adiw r26,%o0" CR_TAB + "st X+,%A1" CR_TAB + "st X+,%B1" CR_TAB + "st X,%C1", op, plen, -4); - if (!reg_unused_after (insn, XEXP (base, 0))) - avr_asm_len ("sbiw r26,%o0+2", op, plen, 1); + if (!reg_unused_after (insn, XEXP (base, 0))) + avr_asm_len ("sbiw r26,%o0+2", op, plen, 1); - return ""; - } + return ""; + } return avr_asm_len ("std %A0,%A1" CR_TAB - "std %B0,%B1" CR_TAB - "std %C0,%C1", op, plen, -3); + "std %B0,%B1" CR_TAB + "std %C0,%C1", op, plen, -3); } else if (GET_CODE (base) == PRE_DEC) /* (--R) */ return avr_asm_len ("st %0,%C1" CR_TAB - "st %0,%B1" CR_TAB - "st %0,%A1", op, plen, -3); + "st %0,%B1" CR_TAB + "st %0,%A1", op, plen, -3); else if (GET_CODE (base) == POST_INC) /* (R++) */ return avr_asm_len ("st %0,%A1" CR_TAB - "st %0,%B1" CR_TAB - "st %0,%C1", op, plen, -3); + "st %0,%B1" CR_TAB + "st %0,%C1", op, plen, -3); fatal_insn ("unknown move insn:",insn); return ""; @@ -5553,34 +5553,34 @@ avr_out_movpsi (rtx_insn *insn, rtx *op, int *plen) if (register_operand (dest, VOIDmode)) { if (register_operand (src, VOIDmode)) /* mov r,r */ - { - if (true_regnum (dest) > true_regnum (src)) - { - avr_asm_len ("mov %C0,%C1", op, plen, -1); - - if (AVR_HAVE_MOVW) - return avr_asm_len ("movw %A0,%A1", op, plen, 1); - else - return avr_asm_len ("mov %B0,%B1" CR_TAB - "mov %A0,%A1", op, plen, 2); - } - else - { - if (AVR_HAVE_MOVW) - avr_asm_len ("movw %A0,%A1", op, plen, -1); - else - avr_asm_len ("mov %A0,%A1" CR_TAB - "mov %B0,%B1", op, plen, -2); - - return avr_asm_len ("mov %C0,%C1", op, plen, 1); - } - } + { + if (true_regnum (dest) > true_regnum (src)) + { + avr_asm_len ("mov %C0,%C1", op, plen, -1); + + if (AVR_HAVE_MOVW) + return avr_asm_len ("movw %A0,%A1", op, plen, 1); + else + return avr_asm_len ("mov %B0,%B1" CR_TAB + "mov %A0,%A1", op, plen, 2); + } + else + { + if (AVR_HAVE_MOVW) + avr_asm_len ("movw %A0,%A1", op, plen, -1); + else + avr_asm_len ("mov %A0,%A1" CR_TAB + "mov %B0,%B1", op, plen, -2); + + return avr_asm_len ("mov %C0,%C1", op, plen, 1); + } + } else if (CONSTANT_P (src)) - { - return avr_out_reload_inpsi (op, NULL_RTX, plen); - } + { + return avr_out_reload_inpsi (op, NULL_RTX, plen); + } else if (MEM_P (src)) - return avr_out_load_psi (insn, op, plen); /* mov r,m */ + return avr_out_load_psi (insn, op, plen); /* mov r,m */ } else if (MEM_P (dest)) { @@ -5596,7 +5596,7 @@ avr_out_movpsi (rtx_insn *insn, rtx *op, int *plen) return ""; } -static const char* +static const char * avr_out_movqi_mr_r_reg_disp_tiny (rtx_insn *insn, rtx op[], int *plen) { rtx dest = op[0]; @@ -5606,13 +5606,13 @@ avr_out_movqi_mr_r_reg_disp_tiny (rtx_insn *insn, rtx op[], int *plen) if (reg_overlap_mentioned_p (src, XEXP (x, 0))) { avr_asm_len ("mov __tmp_reg__,%1" CR_TAB - TINY_ADIW (%I0, %J0, %o0) CR_TAB - "st %b0,__tmp_reg__", op, plen, -4); + TINY_ADIW (%I0, %J0, %o0) CR_TAB + "st %b0,__tmp_reg__", op, plen, -4); } else { avr_asm_len (TINY_ADIW (%I0, %J0, %o0) CR_TAB - "st %b0,%1", op, plen, -3); + "st %b0,%1", op, plen, -3); } if (!reg_unused_after (insn, XEXP (x, 0))) @@ -5621,7 +5621,7 @@ avr_out_movqi_mr_r_reg_disp_tiny (rtx_insn *insn, rtx op[], int *plen) return ""; } -static const char* +static const char * out_movqi_mr_r (rtx_insn *insn, rtx op[], int *plen) { rtx dest = op[0]; @@ -5632,55 +5632,55 @@ out_movqi_mr_r (rtx_insn *insn, rtx op[], int *plen) { int n_words = AVR_TINY ? 1 : 2; return io_address_operand (x, QImode) - ? avr_asm_len ("out %i0,%1", op, plen, -1) - : avr_asm_len ("sts %m0,%1", op, plen, -n_words); + ? avr_asm_len ("out %i0,%1", op, plen, -1) + : avr_asm_len ("sts %m0,%1", op, plen, -n_words); } else if (GET_CODE (x) == PLUS - && REG_P (XEXP (x, 0)) - && CONST_INT_P (XEXP (x, 1))) + && REG_P (XEXP (x, 0)) + && CONST_INT_P (XEXP (x, 1))) { /* memory access by reg+disp */ int disp = INTVAL (XEXP (x, 1)); if (AVR_TINY) - return avr_out_movqi_mr_r_reg_disp_tiny (insn, op, plen); + return avr_out_movqi_mr_r_reg_disp_tiny (insn, op, plen); if (disp - GET_MODE_SIZE (GET_MODE (dest)) >= 63) - { - if (REGNO (XEXP (x, 0)) != REG_Y) - fatal_insn ("incorrect insn:",insn); - - if (disp <= 63 + MAX_LD_OFFSET (GET_MODE (dest))) - return avr_asm_len ("adiw r28,%o0-63" CR_TAB - "std Y+63,%1" CR_TAB - "sbiw r28,%o0-63", op, plen, -3); - - return avr_asm_len ("subi r28,lo8(-%o0)" CR_TAB - "sbci r29,hi8(-%o0)" CR_TAB - "st Y,%1" CR_TAB - "subi r28,lo8(%o0)" CR_TAB - "sbci r29,hi8(%o0)", op, plen, -5); - } + { + if (REGNO (XEXP (x, 0)) != REG_Y) + fatal_insn ("incorrect insn:",insn); + + if (disp <= 63 + MAX_LD_OFFSET (GET_MODE (dest))) + return avr_asm_len ("adiw r28,%o0-63" CR_TAB + "std Y+63,%1" CR_TAB + "sbiw r28,%o0-63", op, plen, -3); + + return avr_asm_len ("subi r28,lo8(-%o0)" CR_TAB + "sbci r29,hi8(-%o0)" CR_TAB + "st Y,%1" CR_TAB + "subi r28,lo8(%o0)" CR_TAB + "sbci r29,hi8(%o0)", op, plen, -5); + } else if (REGNO (XEXP (x, 0)) == REG_X) - { - if (reg_overlap_mentioned_p (src, XEXP (x, 0))) - { - avr_asm_len ("mov __tmp_reg__,%1" CR_TAB - "adiw r26,%o0" CR_TAB - "st X,__tmp_reg__", op, plen, -3); - } - else - { - avr_asm_len ("adiw r26,%o0" CR_TAB - "st X,%1", op, plen, -2); - } - - if (!reg_unused_after (insn, XEXP (x, 0))) - avr_asm_len ("sbiw r26,%o0", op, plen, 1); - - return ""; - } + { + if (reg_overlap_mentioned_p (src, XEXP (x, 0))) + { + avr_asm_len ("mov __tmp_reg__,%1" CR_TAB + "adiw r26,%o0" CR_TAB + "st X,__tmp_reg__", op, plen, -3); + } + else + { + avr_asm_len ("adiw r26,%o0" CR_TAB + "st X,%1", op, plen, -2); + } + + if (!reg_unused_after (insn, XEXP (x, 0))) + avr_asm_len ("sbiw r26,%o0", op, plen, 1); + + return ""; + } return avr_asm_len ("std %0,%1", op, plen, -1); } @@ -5692,7 +5692,7 @@ out_movqi_mr_r (rtx_insn *insn, rtx op[], int *plen) /* Helper for the next function for XMEGA. It does the same but with low byte first. */ -static const char* +static const char * avr_out_movhi_mr_r_xmega (rtx_insn *insn, rtx op[], int *plen) { rtx dest = op[0]; @@ -5708,101 +5708,101 @@ avr_out_movhi_mr_r_xmega (rtx_insn *insn, rtx op[], int *plen) if (CONSTANT_ADDRESS_P (base)) { return io_address_operand (base, HImode) - ? avr_asm_len ("out %i0,%A1" CR_TAB - "out %i0+1,%B1", op, plen, -2) + ? avr_asm_len ("out %i0,%A1" CR_TAB + "out %i0+1,%B1", op, plen, -2) - : avr_asm_len ("sts %m0,%A1" CR_TAB - "sts %m0+1,%B1", op, plen, -4); + : avr_asm_len ("sts %m0,%A1" CR_TAB + "sts %m0+1,%B1", op, plen, -4); } if (reg_base > 0) { if (reg_base != REG_X) - return avr_asm_len ("st %0,%A1" CR_TAB - "std %0+1,%B1", op, plen, -2); + return avr_asm_len ("st %0,%A1" CR_TAB + "std %0+1,%B1", op, plen, -2); if (reg_src == REG_X) - /* "st X+,r26" and "st -X,r26" are undefined. */ - avr_asm_len ("mov __tmp_reg__,r27" CR_TAB - "st X,r26" CR_TAB - "adiw r26,1" CR_TAB - "st X,__tmp_reg__", op, plen, -4); + /* "st X+,r26" and "st -X,r26" are undefined. */ + avr_asm_len ("mov __tmp_reg__,r27" CR_TAB + "st X,r26" CR_TAB + "adiw r26,1" CR_TAB + "st X,__tmp_reg__", op, plen, -4); else - avr_asm_len ("st X+,%A1" CR_TAB - "st X,%B1", op, plen, -2); + avr_asm_len ("st X+,%A1" CR_TAB + "st X,%B1", op, plen, -2); return reg_unused_after (insn, base) - ? "" - : avr_asm_len ("sbiw r26,1", op, plen, 1); + ? "" + : avr_asm_len ("sbiw r26,1", op, plen, 1); } else if (GET_CODE (base) == PLUS) { int disp = INTVAL (XEXP (base, 1)); reg_base = REGNO (XEXP (base, 0)); if (disp > MAX_LD_OFFSET (GET_MODE (dest))) - { - if (reg_base != REG_Y) - fatal_insn ("incorrect insn:",insn); - - return disp <= 63 + MAX_LD_OFFSET (GET_MODE (dest)) - ? avr_asm_len ("adiw r28,%o0-62" CR_TAB - "std Y+62,%A1" CR_TAB - "std Y+63,%B1" CR_TAB - "sbiw r28,%o0-62", op, plen, -4) - - : avr_asm_len ("subi r28,lo8(-%o0)" CR_TAB - "sbci r29,hi8(-%o0)" CR_TAB - "st Y,%A1" CR_TAB - "std Y+1,%B1" CR_TAB - "subi r28,lo8(%o0)" CR_TAB - "sbci r29,hi8(%o0)", op, plen, -6); - } + { + if (reg_base != REG_Y) + fatal_insn ("incorrect insn:",insn); + + return disp <= 63 + MAX_LD_OFFSET (GET_MODE (dest)) + ? avr_asm_len ("adiw r28,%o0-62" CR_TAB + "std Y+62,%A1" CR_TAB + "std Y+63,%B1" CR_TAB + "sbiw r28,%o0-62", op, plen, -4) + + : avr_asm_len ("subi r28,lo8(-%o0)" CR_TAB + "sbci r29,hi8(-%o0)" CR_TAB + "st Y,%A1" CR_TAB + "std Y+1,%B1" CR_TAB + "subi r28,lo8(%o0)" CR_TAB + "sbci r29,hi8(%o0)", op, plen, -6); + } if (reg_base != REG_X) - return avr_asm_len ("std %A0,%A1" CR_TAB - "std %B0,%B1", op, plen, -2); + return avr_asm_len ("std %A0,%A1" CR_TAB + "std %B0,%B1", op, plen, -2); /* (X + d) = R */ return reg_src == REG_X - ? avr_asm_len ("mov __tmp_reg__,r26" CR_TAB - "mov __zero_reg__,r27" CR_TAB - "adiw r26,%o0" CR_TAB - "st X+,__tmp_reg__" CR_TAB - "st X,__zero_reg__" CR_TAB - "clr __zero_reg__" CR_TAB - "sbiw r26,%o0+1", op, plen, -7) - - : avr_asm_len ("adiw r26,%o0" CR_TAB - "st X+,%A1" CR_TAB - "st X,%B1" CR_TAB - "sbiw r26,%o0+1", op, plen, -4); + ? avr_asm_len ("mov __tmp_reg__,r26" CR_TAB + "mov __zero_reg__,r27" CR_TAB + "adiw r26,%o0" CR_TAB + "st X+,__tmp_reg__" CR_TAB + "st X,__zero_reg__" CR_TAB + "clr __zero_reg__" CR_TAB + "sbiw r26,%o0+1", op, plen, -7) + + : avr_asm_len ("adiw r26,%o0" CR_TAB + "st X+,%A1" CR_TAB + "st X,%B1" CR_TAB + "sbiw r26,%o0+1", op, plen, -4); } else if (GET_CODE (base) == PRE_DEC) /* (--R) */ { if (!mem_volatile_p) - return avr_asm_len ("st %0,%B1" CR_TAB - "st %0,%A1", op, plen, -2); + return avr_asm_len ("st %0,%B1" CR_TAB + "st %0,%A1", op, plen, -2); return REGNO (XEXP (base, 0)) == REG_X - ? avr_asm_len ("sbiw r26,2" CR_TAB - "st X+,%A1" CR_TAB - "st X,%B1" CR_TAB - "sbiw r26,1", op, plen, -4) + ? avr_asm_len ("sbiw r26,2" CR_TAB + "st X+,%A1" CR_TAB + "st X,%B1" CR_TAB + "sbiw r26,1", op, plen, -4) - : avr_asm_len ("sbiw %r0,2" CR_TAB - "st %p0,%A1" CR_TAB - "std %p0+1,%B1", op, plen, -3); + : avr_asm_len ("sbiw %r0,2" CR_TAB + "st %p0,%A1" CR_TAB + "std %p0+1,%B1", op, plen, -3); } else if (GET_CODE (base) == POST_INC) /* (R++) */ { return avr_asm_len ("st %0,%A1" CR_TAB - "st %0,%B1", op, plen, -2); + "st %0,%B1", op, plen, -2); } fatal_insn ("unknown move insn:",insn); return ""; } -static const char* +static const char * avr_out_movhi_mr_r_reg_no_disp_tiny (rtx_insn *insn, rtx op[], int *plen) { rtx dest = op[0]; @@ -5815,26 +5815,26 @@ avr_out_movhi_mr_r_reg_no_disp_tiny (rtx_insn *insn, rtx op[], int *plen) if (reg_base == reg_src) { return !mem_volatile_p && reg_unused_after (insn, src) - ? avr_asm_len ("mov __tmp_reg__,%B1" CR_TAB - "st %0,%A1" CR_TAB - TINY_ADIW (%E0, %F0, 1) CR_TAB - "st %0,__tmp_reg__", op, plen, -5) - : avr_asm_len ("mov __tmp_reg__,%B1" CR_TAB - TINY_ADIW (%E0, %F0, 1) CR_TAB - "st %0,__tmp_reg__" CR_TAB - TINY_SBIW (%E0, %F0, 1) CR_TAB - "st %0, %A1", op, plen, -7); + ? avr_asm_len ("mov __tmp_reg__,%B1" CR_TAB + "st %0,%A1" CR_TAB + TINY_ADIW (%E0, %F0, 1) CR_TAB + "st %0,__tmp_reg__", op, plen, -5) + : avr_asm_len ("mov __tmp_reg__,%B1" CR_TAB + TINY_ADIW (%E0, %F0, 1) CR_TAB + "st %0,__tmp_reg__" CR_TAB + TINY_SBIW (%E0, %F0, 1) CR_TAB + "st %0, %A1", op, plen, -7); } return !mem_volatile_p && reg_unused_after (insn, base) ? avr_asm_len ("st %0+,%A1" CR_TAB - "st %0,%B1", op, plen, -2) + "st %0,%B1", op, plen, -2) : avr_asm_len (TINY_ADIW (%E0, %F0, 1) CR_TAB - "st %0,%B1" CR_TAB - "st -%0,%A1", op, plen, -4); + "st %0,%B1" CR_TAB + "st -%0,%A1", op, plen, -4); } -static const char* +static const char * avr_out_movhi_mr_r_reg_disp_tiny (rtx_insn *insn, rtx op[], int *plen) { rtx dest = op[0]; @@ -5845,15 +5845,15 @@ avr_out_movhi_mr_r_reg_disp_tiny (rtx_insn *insn, rtx op[], int *plen) if (reg_src == reg_base) avr_asm_len ("mov __tmp_reg__,%A1" CR_TAB - "mov __zero_reg__,%B1" CR_TAB - TINY_ADIW (%I0, %J0, %o0+1) CR_TAB - "st %b0,__zero_reg__" CR_TAB - "st -%b0,__tmp_reg__" CR_TAB - "clr __zero_reg__", op, plen, -7); + "mov __zero_reg__,%B1" CR_TAB + TINY_ADIW (%I0, %J0, %o0+1) CR_TAB + "st %b0,__zero_reg__" CR_TAB + "st -%b0,__tmp_reg__" CR_TAB + "clr __zero_reg__", op, plen, -7); else avr_asm_len (TINY_ADIW (%I0, %J0, %o0+1) CR_TAB - "st %b0,%B1" CR_TAB - "st -%b0,%A1", op, plen, -4); + "st %b0,%B1" CR_TAB + "st -%b0,%A1", op, plen, -4); if (!reg_unused_after (insn, XEXP (base, 0))) avr_asm_len (TINY_SBIW (%I0, %J0, %o0), op, plen, 2); @@ -5861,16 +5861,16 @@ avr_out_movhi_mr_r_reg_disp_tiny (rtx_insn *insn, rtx op[], int *plen) return ""; } -static const char* +static const char * avr_out_movhi_mr_r_post_inc_tiny (rtx op[], int *plen) { return avr_asm_len (TINY_ADIW (%I0, %J0, 1) CR_TAB - "st %p0,%B1" CR_TAB - "st -%p0,%A1" CR_TAB - TINY_ADIW (%I0, %J0, 2), op, plen, -6); + "st %p0,%B1" CR_TAB + "st -%p0,%A1" CR_TAB + TINY_ADIW (%I0, %J0, 2), op, plen, -6); } -static const char* +static const char * out_movhi_mr_r (rtx_insn *insn, rtx op[], int *plen) { rtx dest = op[0]; @@ -5893,111 +5893,111 @@ out_movhi_mr_r (rtx_insn *insn, rtx op[], int *plen) { int n_words = AVR_TINY ? 2 : 4; return io_address_operand (base, HImode) - ? avr_asm_len ("out %i0+1,%B1" CR_TAB - "out %i0,%A1", op, plen, -2) + ? avr_asm_len ("out %i0+1,%B1" CR_TAB + "out %i0,%A1", op, plen, -2) - : avr_asm_len ("sts %m0+1,%B1" CR_TAB - "sts %m0,%A1", op, plen, -n_words); + : avr_asm_len ("sts %m0+1,%B1" CR_TAB + "sts %m0,%A1", op, plen, -n_words); } if (reg_base > 0) { if (AVR_TINY) - return avr_out_movhi_mr_r_reg_no_disp_tiny (insn, op, plen); + return avr_out_movhi_mr_r_reg_no_disp_tiny (insn, op, plen); if (reg_base != REG_X) - return avr_asm_len ("std %0+1,%B1" CR_TAB - "st %0,%A1", op, plen, -2); + return avr_asm_len ("std %0+1,%B1" CR_TAB + "st %0,%A1", op, plen, -2); if (reg_src == REG_X) - /* "st X+,r26" and "st -X,r26" are undefined. */ - return !mem_volatile_p && reg_unused_after (insn, src) - ? avr_asm_len ("mov __tmp_reg__,r27" CR_TAB - "st X,r26" CR_TAB - "adiw r26,1" CR_TAB - "st X,__tmp_reg__", op, plen, -4) - - : avr_asm_len ("mov __tmp_reg__,r27" CR_TAB - "adiw r26,1" CR_TAB - "st X,__tmp_reg__" CR_TAB - "sbiw r26,1" CR_TAB - "st X,r26", op, plen, -5); + /* "st X+,r26" and "st -X,r26" are undefined. */ + return !mem_volatile_p && reg_unused_after (insn, src) + ? avr_asm_len ("mov __tmp_reg__,r27" CR_TAB + "st X,r26" CR_TAB + "adiw r26,1" CR_TAB + "st X,__tmp_reg__", op, plen, -4) + + : avr_asm_len ("mov __tmp_reg__,r27" CR_TAB + "adiw r26,1" CR_TAB + "st X,__tmp_reg__" CR_TAB + "sbiw r26,1" CR_TAB + "st X,r26", op, plen, -5); return !mem_volatile_p && reg_unused_after (insn, base) - ? avr_asm_len ("st X+,%A1" CR_TAB - "st X,%B1", op, plen, -2) - : avr_asm_len ("adiw r26,1" CR_TAB - "st X,%B1" CR_TAB - "st -X,%A1", op, plen, -3); + ? avr_asm_len ("st X+,%A1" CR_TAB + "st X,%B1", op, plen, -2) + : avr_asm_len ("adiw r26,1" CR_TAB + "st X,%B1" CR_TAB + "st -X,%A1", op, plen, -3); } else if (GET_CODE (base) == PLUS) { int disp = INTVAL (XEXP (base, 1)); if (AVR_TINY) - return avr_out_movhi_mr_r_reg_disp_tiny (insn, op, plen); + return avr_out_movhi_mr_r_reg_disp_tiny (insn, op, plen); reg_base = REGNO (XEXP (base, 0)); if (disp > MAX_LD_OFFSET (GET_MODE (dest))) - { - if (reg_base != REG_Y) - fatal_insn ("incorrect insn:",insn); - - return disp <= 63 + MAX_LD_OFFSET (GET_MODE (dest)) - ? avr_asm_len ("adiw r28,%o0-62" CR_TAB - "std Y+63,%B1" CR_TAB - "std Y+62,%A1" CR_TAB - "sbiw r28,%o0-62", op, plen, -4) - - : avr_asm_len ("subi r28,lo8(-%o0)" CR_TAB - "sbci r29,hi8(-%o0)" CR_TAB - "std Y+1,%B1" CR_TAB - "st Y,%A1" CR_TAB - "subi r28,lo8(%o0)" CR_TAB - "sbci r29,hi8(%o0)", op, plen, -6); - } + { + if (reg_base != REG_Y) + fatal_insn ("incorrect insn:",insn); + + return disp <= 63 + MAX_LD_OFFSET (GET_MODE (dest)) + ? avr_asm_len ("adiw r28,%o0-62" CR_TAB + "std Y+63,%B1" CR_TAB + "std Y+62,%A1" CR_TAB + "sbiw r28,%o0-62", op, plen, -4) + + : avr_asm_len ("subi r28,lo8(-%o0)" CR_TAB + "sbci r29,hi8(-%o0)" CR_TAB + "std Y+1,%B1" CR_TAB + "st Y,%A1" CR_TAB + "subi r28,lo8(%o0)" CR_TAB + "sbci r29,hi8(%o0)", op, plen, -6); + } if (reg_base != REG_X) - return avr_asm_len ("std %B0,%B1" CR_TAB - "std %A0,%A1", op, plen, -2); + return avr_asm_len ("std %B0,%B1" CR_TAB + "std %A0,%A1", op, plen, -2); /* (X + d) = R */ return reg_src == REG_X - ? avr_asm_len ("mov __tmp_reg__,r26" CR_TAB - "mov __zero_reg__,r27" CR_TAB - "adiw r26,%o0+1" CR_TAB - "st X,__zero_reg__" CR_TAB - "st -X,__tmp_reg__" CR_TAB - "clr __zero_reg__" CR_TAB - "sbiw r26,%o0", op, plen, -7) - - : avr_asm_len ("adiw r26,%o0+1" CR_TAB - "st X,%B1" CR_TAB - "st -X,%A1" CR_TAB - "sbiw r26,%o0", op, plen, -4); + ? avr_asm_len ("mov __tmp_reg__,r26" CR_TAB + "mov __zero_reg__,r27" CR_TAB + "adiw r26,%o0+1" CR_TAB + "st X,__zero_reg__" CR_TAB + "st -X,__tmp_reg__" CR_TAB + "clr __zero_reg__" CR_TAB + "sbiw r26,%o0", op, plen, -7) + + : avr_asm_len ("adiw r26,%o0+1" CR_TAB + "st X,%B1" CR_TAB + "st -X,%A1" CR_TAB + "sbiw r26,%o0", op, plen, -4); } else if (GET_CODE (base) == PRE_DEC) /* (--R) */ { return avr_asm_len ("st %0,%B1" CR_TAB - "st %0,%A1", op, plen, -2); + "st %0,%A1", op, plen, -2); } else if (GET_CODE (base) == POST_INC) /* (R++) */ { if (!mem_volatile_p) - return avr_asm_len ("st %0,%A1" CR_TAB - "st %0,%B1", op, plen, -2); + return avr_asm_len ("st %0,%A1" CR_TAB + "st %0,%B1", op, plen, -2); if (AVR_TINY) - return avr_out_movhi_mr_r_post_inc_tiny (op, plen); + return avr_out_movhi_mr_r_post_inc_tiny (op, plen); return REGNO (XEXP (base, 0)) == REG_X - ? avr_asm_len ("adiw r26,1" CR_TAB - "st X,%B1" CR_TAB - "st -X,%A1" CR_TAB - "adiw r26,2", op, plen, -4) + ? avr_asm_len ("adiw r26,1" CR_TAB + "st X,%B1" CR_TAB + "st -X,%A1" CR_TAB + "adiw r26,2", op, plen, -4) - : avr_asm_len ("std %p0+1,%B1" CR_TAB - "st %p0,%A1" CR_TAB - "adiw %r0,2", op, plen, -3); + : avr_asm_len ("std %p0+1,%B1" CR_TAB + "st %p0,%A1" CR_TAB + "adiw %r0,2", op, plen, -3); } fatal_insn ("unknown move insn:",insn); return ""; @@ -6009,10 +6009,10 @@ static bool avr_frame_pointer_required_p (void) { return (cfun->calls_alloca - || cfun->calls_setjmp - || cfun->has_nonlocal_label - || crtl->args.info.nregs == 0 - || get_frame_size () > 0); + || cfun->calls_setjmp + || cfun->has_nonlocal_label + || crtl->args.info.nregs == 0 + || get_frame_size () > 0); } @@ -6157,7 +6157,7 @@ avr_canonicalize_comparison (int *icode, rtx *op0, rtx *op1, bool op0_fixed) PLEN != NULL: Set *PLEN to the length (in words) of the sequence. Don't output anything. */ -const char* +const char * avr_out_compare (rtx_insn *insn, rtx *xop, int *plen) { /* Register to compare and value to compare against. */ @@ -6186,7 +6186,7 @@ avr_out_compare (rtx_insn *insn, rtx *xop, int *plen) gcc_assert (REG_P (xreg)); gcc_assert ((CONST_INT_P (xval) && n_bytes <= 4) - || (const_double_operand (xval, VOIDmode) && n_bytes == 8)); + || (const_double_operand (xval, VOIDmode) && n_bytes == 8)); if (plen) *plen = 0; @@ -6201,29 +6201,29 @@ avr_out_compare (rtx_insn *insn, rtx *xop, int *plen) && reg_unused_after (insn, xreg)) { if (xval == const1_rtx) - { - avr_asm_len ("dec %A0" CR_TAB - "or %A0,%B0", xop, plen, 2); + { + avr_asm_len ("dec %A0" CR_TAB + "or %A0,%B0", xop, plen, 2); - if (n_bytes >= 3) - avr_asm_len ("or %A0,%C0", xop, plen, 1); + if (n_bytes >= 3) + avr_asm_len ("or %A0,%C0", xop, plen, 1); - if (n_bytes >= 4) - avr_asm_len ("or %A0,%D0", xop, plen, 1); + if (n_bytes >= 4) + avr_asm_len ("or %A0,%D0", xop, plen, 1); - return ""; - } + return ""; + } else if (xval == constm1_rtx) - { - if (n_bytes >= 4) - avr_asm_len ("and %A0,%D0", xop, plen, 1); + { + if (n_bytes >= 4) + avr_asm_len ("and %A0,%D0", xop, plen, 1); - if (n_bytes >= 3) - avr_asm_len ("and %A0,%C0", xop, plen, 1); + if (n_bytes >= 3) + avr_asm_len ("and %A0,%C0", xop, plen, 1); - return avr_asm_len ("and %A0,%B0" CR_TAB - "com %A0", xop, plen, 2); - } + return avr_asm_len ("and %A0,%B0" CR_TAB + "com %A0", xop, plen, 2); + } } /* Comparisons == -1 and != -1 of a d-register that's used after the @@ -6245,13 +6245,13 @@ avr_out_compare (rtx_insn *insn, rtx *xop, int *plen) rtx xhi8 = simplify_gen_subreg (QImode, xval, mode, 1); if (INTVAL (xlo8) == INTVAL (xhi8)) - { - xop[0] = xreg; - xop[1] = xlo8; + { + xop[0] = xreg; + xop[1] = xlo8; - return avr_asm_len ("cpi %A0,%1" CR_TAB - "cpc %B0,%A0", xop, plen, 2); - } + return avr_asm_len ("cpi %A0,%1" CR_TAB + "cpc %B0,%A0", xop, plen, 2); + } } for (int i = 0; i < n_bytes; i++) @@ -6272,74 +6272,74 @@ avr_out_compare (rtx_insn *insn, rtx *xop, int *plen) /* Word registers >= R24 can use SBIW/ADIW with 0..63. */ if (i == 0 - && test_hard_reg_class (ADDW_REGS, reg8)) - { - int val16 = trunc_int_for_mode (INTVAL (xval), HImode); - - if (IN_RANGE (val16, 0, 63) - && (val8 == 0 - || reg_unused_after (insn, xreg))) - { - if (AVR_TINY) - avr_asm_len (TINY_SBIW (%A0, %B0, %1), xop, plen, 2); - else - avr_asm_len ("sbiw %0,%1", xop, plen, 1); - - i++; - continue; - } - - if (n_bytes == 2 - && IN_RANGE (val16, -63, -1) - && compare_eq_p (insn) - && reg_unused_after (insn, xreg)) - { - return AVR_TINY - ? avr_asm_len (TINY_ADIW (%A0, %B0, %n1), xop, plen, 2) - : avr_asm_len ("adiw %0,%n1", xop, plen, 1); - } - } + && test_hard_reg_class (ADDW_REGS, reg8)) + { + int val16 = trunc_int_for_mode (INTVAL (xval), HImode); + + if (IN_RANGE (val16, 0, 63) + && (val8 == 0 + || reg_unused_after (insn, xreg))) + { + if (AVR_TINY) + avr_asm_len (TINY_SBIW (%A0, %B0, %1), xop, plen, 2); + else + avr_asm_len ("sbiw %0,%1", xop, plen, 1); + + i++; + continue; + } + + if (n_bytes == 2 + && IN_RANGE (val16, -63, -1) + && compare_eq_p (insn) + && reg_unused_after (insn, xreg)) + { + return AVR_TINY + ? avr_asm_len (TINY_ADIW (%A0, %B0, %n1), xop, plen, 2) + : avr_asm_len ("adiw %0,%n1", xop, plen, 1); + } + } /* Comparing against 0 is easy. */ if (val8 == 0) - { - avr_asm_len (i == 0 - ? "cp %0,__zero_reg__" - : "cpc %0,__zero_reg__", xop, plen, 1); - continue; - } + { + avr_asm_len (i == 0 + ? "cp %0,__zero_reg__" + : "cpc %0,__zero_reg__", xop, plen, 1); + continue; + } /* Upper registers can compare and subtract-with-carry immediates. - Notice that compare instructions do the same as respective subtract - instruction; the only difference is that comparisons don't write - the result back to the target register. */ + Notice that compare instructions do the same as respective subtract + instruction; the only difference is that comparisons don't write + the result back to the target register. */ if (ld_reg_p) - { - if (i == 0) - { - avr_asm_len ("cpi %0,%1", xop, plen, 1); - continue; - } - else if (reg_unused_after (insn, xreg)) - { - avr_asm_len ("sbci %0,%1", xop, plen, 1); - continue; - } - } + { + if (i == 0) + { + avr_asm_len ("cpi %0,%1", xop, plen, 1); + continue; + } + else if (reg_unused_after (insn, xreg)) + { + avr_asm_len ("sbci %0,%1", xop, plen, 1); + continue; + } + } /* Must load the value into the scratch register. */ gcc_assert (REG_P (xop[2])); if (clobber_val != (int) val8) - avr_asm_len ("ldi %2,%1", xop, plen, 1); + avr_asm_len ("ldi %2,%1", xop, plen, 1); clobber_val = (int) val8; avr_asm_len (i == 0 - ? "cp %0,%2" - : "cpc %0,%2", xop, plen, 1); + ? "cp %0,%2" + : "cpc %0,%2", xop, plen, 1); } return ""; @@ -6348,7 +6348,7 @@ avr_out_compare (rtx_insn *insn, rtx *xop, int *plen) /* Prepare operands of compare_const_di2 to be used with avr_out_compare. */ -const char* +const char * avr_out_compare64 (rtx_insn *insn, rtx *op, int *plen) { rtx xop[3]; @@ -6362,7 +6362,7 @@ avr_out_compare64 (rtx_insn *insn, rtx *op, int *plen) /* Output test instruction for HImode. */ -const char* +const char * avr_out_tsthi (rtx_insn *insn, rtx *op, int *plen) { if (compare_sign_p (insn)) @@ -6370,7 +6370,7 @@ avr_out_tsthi (rtx_insn *insn, rtx *op, int *plen) avr_asm_len ("tst %B0", op, plen, -1); } else if (reg_unused_after (insn, op[0]) - && compare_eq_p (insn)) + && compare_eq_p (insn)) { /* Faster than sbiw if we can clobber the operand. */ avr_asm_len ("or %A0,%B0", op, plen, -1); @@ -6386,7 +6386,7 @@ avr_out_tsthi (rtx_insn *insn, rtx *op, int *plen) /* Output test instruction for PSImode. */ -const char* +const char * avr_out_tstpsi (rtx_insn *insn, rtx *op, int *plen) { if (compare_sign_p (insn)) @@ -6394,11 +6394,11 @@ avr_out_tstpsi (rtx_insn *insn, rtx *op, int *plen) avr_asm_len ("tst %C0", op, plen, -1); } else if (reg_unused_after (insn, op[0]) - && compare_eq_p (insn)) + && compare_eq_p (insn)) { /* Faster than sbiw if we can clobber the operand. */ avr_asm_len ("or %A0,%B0" CR_TAB - "or %A0,%C0", op, plen, -2); + "or %A0,%C0", op, plen, -2); } else { @@ -6411,7 +6411,7 @@ avr_out_tstpsi (rtx_insn *insn, rtx *op, int *plen) /* Output test instruction for SImode. */ -const char* +const char * avr_out_tstsi (rtx_insn *insn, rtx *op, int *plen) { if (compare_sign_p (insn)) @@ -6419,12 +6419,12 @@ avr_out_tstsi (rtx_insn *insn, rtx *op, int *plen) avr_asm_len ("tst %D0", op, plen, -1); } else if (reg_unused_after (insn, op[0]) - && compare_eq_p (insn)) + && compare_eq_p (insn)) { /* Faster than sbiw if we can clobber the operand. */ avr_asm_len ("or %A0,%B0" CR_TAB - "or %A0,%C0" CR_TAB - "or %A0,%D0", op, plen, -3); + "or %A0,%C0" CR_TAB + "or %A0,%D0", op, plen, -3); } else { @@ -6441,7 +6441,7 @@ avr_out_tstsi (rtx_insn *insn, rtx *op, int *plen) PLEN != 0: Set *PLEN to the code length in words. Don't output anything. PLEN == 0: Print instructions. */ -const char* +const char * avr_out_cmp_ext (rtx xop[], enum rtx_code code, int *plen) { // The smaller reg is the one that's to be extended. Get its index as z. @@ -6533,56 +6533,56 @@ out_shift_with_cnt (const char *templ, rtx_insn *insn, rtx operands[], If a scratch reg is not available, then the parallel will contain only a set and clobber of REG_CC. */ bool scratch = (GET_CODE (PATTERN (insn)) == PARALLEL - && XVECLEN (PATTERN (insn), 0) == 3 - && REG_P (operands[3])); + && XVECLEN (PATTERN (insn), 0) == 3 + && REG_P (operands[3])); int count = INTVAL (operands[2]); int max_len = 10; /* If larger than this, always use a loop. */ if (count <= 0) - return; + return; if (count < 8 && !scratch) - use_zero_reg = true; + use_zero_reg = true; if (optimize_size) - max_len = t_len + (scratch ? 3 : (use_zero_reg ? 4 : 5)); + max_len = t_len + (scratch ? 3 : (use_zero_reg ? 4 : 5)); if (t_len * count <= max_len) - { - /* Output shifts inline with no loop - faster. */ + { + /* Output shifts inline with no loop - faster. */ - while (count-- > 0) - avr_asm_len (templ, op, plen, t_len); + while (count-- > 0) + avr_asm_len (templ, op, plen, t_len); - return; - } + return; + } if (scratch) - { - avr_asm_len ("ldi %3,%2", op, plen, 1); - } + { + avr_asm_len ("ldi %3,%2", op, plen, 1); + } else if (use_zero_reg) - { - /* Hack to save one word: use __zero_reg__ as loop counter. - Set one bit, then shift in a loop until it is 0 again. */ + { + /* Hack to save one word: use __zero_reg__ as loop counter. + Set one bit, then shift in a loop until it is 0 again. */ - op[3] = zero_reg_rtx; + op[3] = zero_reg_rtx; - avr_asm_len ("set" CR_TAB - "bld %3,%2-1", op, plen, 2); - } + avr_asm_len ("set" CR_TAB + "bld %3,%2-1", op, plen, 2); + } else - { - /* No scratch register available, use one from LD_REGS (saved in - __tmp_reg__) that doesn't overlap with registers to shift. */ + { + /* No scratch register available, use one from LD_REGS (saved in + __tmp_reg__) that doesn't overlap with registers to shift. */ - op[3] = all_regs_rtx[((REGNO (op[0]) - 1) & 15) + 16]; - op[4] = tmp_reg_rtx; - saved_in_tmp = true; + op[3] = all_regs_rtx[((REGNO (op[0]) - 1) & 15) + 16]; + op[4] = tmp_reg_rtx; + saved_in_tmp = true; - avr_asm_len ("mov %4,%3" CR_TAB - "ldi %3,%2", op, plen, 2); - } + avr_asm_len ("mov %4,%3" CR_TAB + "ldi %3,%2", op, plen, 2); + } second_label = false; } @@ -6600,11 +6600,11 @@ out_shift_with_cnt (const char *templ, rtx_insn *insn, rtx operands[], op[3] = op[2]; if (!reg_unused_after (insn, op[2]) - || reg_overlap_mentioned_p (op[0], op[2])) - { - op[3] = tmp_reg_rtx; - avr_asm_len ("mov %3,%2", op, plen, 1); - } + || reg_overlap_mentioned_p (op[0], op[2])) + { + op[3] = tmp_reg_rtx; + avr_asm_len ("mov %3,%2", op, plen, 1); + } } else fatal_insn ("bad shift insn:", insn); @@ -6718,7 +6718,7 @@ ashlqi3_out (rtx_insn *insn, rtx operands[], int *len) fatal_insn ("internal compiler error. Incorrect shift:", insn); out_shift_with_cnt ("lsl %0", - insn, operands, len, 1); + insn, operands, len, 1); return ""; } @@ -6731,8 +6731,8 @@ ashlhi3_out (rtx_insn *insn, rtx operands[], int *len) if (CONST_INT_P (operands[2])) { int scratch = (GET_CODE (PATTERN (insn)) == PARALLEL - && XVECLEN (PATTERN (insn), 0) == 3 - && REG_P (operands[3])); + && XVECLEN (PATTERN (insn), 0) == 3 + && REG_P (operands[3])); int ldi_ok = test_hard_reg_class (LD_REGS, operands[0]); int k; int *t = len; @@ -6977,14 +6977,14 @@ ashlhi3_out (rtx_insn *insn, rtx operands[], int *len) len = t; } out_shift_with_cnt ("lsl %A0" CR_TAB - "rol %B0", insn, operands, len, 2); + "rol %B0", insn, operands, len, 2); return ""; } /* 24-bit shift left */ -const char* +const char * avr_out_ashlpsi3 (rtx_insn *insn, rtx *op, int *plen) { if (plen) @@ -6993,54 +6993,54 @@ avr_out_ashlpsi3 (rtx_insn *insn, rtx *op, int *plen) if (CONST_INT_P (op[2])) { switch (INTVAL (op[2])) - { - default: - if (INTVAL (op[2]) < 24) - break; - - return avr_asm_len ("clr %A0" CR_TAB - "clr %B0" CR_TAB - "clr %C0", op, plen, 3); - - case 8: - { - int reg0 = REGNO (op[0]); - int reg1 = REGNO (op[1]); - - if (reg0 >= reg1) - return avr_asm_len ("mov %C0,%B1" CR_TAB - "mov %B0,%A1" CR_TAB - "clr %A0", op, plen, 3); - else - return avr_asm_len ("clr %A0" CR_TAB - "mov %B0,%A1" CR_TAB - "mov %C0,%B1", op, plen, 3); - } - - case 16: - { - int reg0 = REGNO (op[0]); - int reg1 = REGNO (op[1]); - - if (reg0 + 2 != reg1) - avr_asm_len ("mov %C0,%A0", op, plen, 1); - - return avr_asm_len ("clr %B0" CR_TAB - "clr %A0", op, plen, 2); - } - - case 23: - return avr_asm_len ("clr %C0" CR_TAB - "lsr %A0" CR_TAB - "ror %C0" CR_TAB - "clr %B0" CR_TAB - "clr %A0", op, plen, 5); - } + { + default: + if (INTVAL (op[2]) < 24) + break; + + return avr_asm_len ("clr %A0" CR_TAB + "clr %B0" CR_TAB + "clr %C0", op, plen, 3); + + case 8: + { + int reg0 = REGNO (op[0]); + int reg1 = REGNO (op[1]); + + if (reg0 >= reg1) + return avr_asm_len ("mov %C0,%B1" CR_TAB + "mov %B0,%A1" CR_TAB + "clr %A0", op, plen, 3); + else + return avr_asm_len ("clr %A0" CR_TAB + "mov %B0,%A1" CR_TAB + "mov %C0,%B1", op, plen, 3); + } + + case 16: + { + int reg0 = REGNO (op[0]); + int reg1 = REGNO (op[1]); + + if (reg0 + 2 != reg1) + avr_asm_len ("mov %C0,%A0", op, plen, 1); + + return avr_asm_len ("clr %B0" CR_TAB + "clr %A0", op, plen, 2); + } + + case 23: + return avr_asm_len ("clr %C0" CR_TAB + "lsr %A0" CR_TAB + "ror %C0" CR_TAB + "clr %B0" CR_TAB + "clr %A0", op, plen, 5); + } } out_shift_with_cnt ("lsl %A0" CR_TAB - "rol %B0" CR_TAB - "rol %C0", insn, op, plen, 3); + "rol %B0" CR_TAB + "rol %C0", insn, op, plen, 3); return ""; } @@ -7128,9 +7128,9 @@ ashlsi3_out (rtx_insn *insn, rtx operands[], int *len) len = t; } out_shift_with_cnt ("lsl %A0" CR_TAB - "rol %B0" CR_TAB - "rol %C0" CR_TAB - "rol %D0", insn, operands, len, 4); + "rol %B0" CR_TAB + "rol %C0" CR_TAB + "rol %D0", insn, operands, len, 4); return ""; } @@ -7201,7 +7201,7 @@ ashrqi3_out (rtx_insn *insn, rtx operands[], int *len) fatal_insn ("internal compiler error. Incorrect shift:", insn); out_shift_with_cnt ("asr %0", - insn, operands, len, 1); + insn, operands, len, 1); return ""; } @@ -7214,8 +7214,8 @@ ashrhi3_out (rtx_insn *insn, rtx operands[], int *len) if (CONST_INT_P (operands[2])) { int scratch = (GET_CODE (PATTERN (insn)) == PARALLEL - && XVECLEN (PATTERN (insn), 0) == 3 - && REG_P (operands[3])); + && XVECLEN (PATTERN (insn), 0) == 3 + && REG_P (operands[3])); int ldi_ok = test_hard_reg_class (LD_REGS, operands[0]); int k; int *t = len; @@ -7261,9 +7261,9 @@ ashrhi3_out (rtx_insn *insn, rtx operands[], int *len) "sbc %B0,%B0"); else return *len = 4, ("mov %A0,%B1" CR_TAB - "clr %B0" CR_TAB - "sbrc %A0,7" CR_TAB - "dec %B0"); + "clr %B0" CR_TAB + "sbrc %A0,7" CR_TAB + "dec %B0"); } case 9: @@ -7366,14 +7366,14 @@ ashrhi3_out (rtx_insn *insn, rtx operands[], int *len) len = t; } out_shift_with_cnt ("asr %B0" CR_TAB - "ror %A0", insn, operands, len, 2); + "ror %A0", insn, operands, len, 2); return ""; } /* 24-bit arithmetic shift right */ -const char* +const char * avr_out_ashrpsi3 (rtx_insn *insn, rtx *op, int *plen) { int dest = REGNO (op[0]); @@ -7382,50 +7382,50 @@ avr_out_ashrpsi3 (rtx_insn *insn, rtx *op, int *plen) if (CONST_INT_P (op[2])) { if (plen) - *plen = 0; + *plen = 0; switch (INTVAL (op[2])) - { - case 8: - if (dest <= src) - return avr_asm_len ("mov %A0,%B1" CR_TAB - "mov %B0,%C1" CR_TAB - "clr %C0" CR_TAB - "sbrc %B0,7" CR_TAB - "dec %C0", op, plen, 5); - else - return avr_asm_len ("clr %C0" CR_TAB - "sbrc %C1,7" CR_TAB - "dec %C0" CR_TAB - "mov %B0,%C1" CR_TAB - "mov %A0,%B1", op, plen, 5); - - case 16: - if (dest != src + 2) - avr_asm_len ("mov %A0,%C1", op, plen, 1); - - return avr_asm_len ("clr %B0" CR_TAB - "sbrc %A0,7" CR_TAB - "com %B0" CR_TAB - "mov %C0,%B0", op, plen, 4); - - default: - if (INTVAL (op[2]) < 24) - break; - - /* fall through */ - - case 23: - return avr_asm_len ("lsl %C0" CR_TAB - "sbc %A0,%A0" CR_TAB - "mov %B0,%A0" CR_TAB - "mov %C0,%A0", op, plen, 4); - } /* switch */ + { + case 8: + if (dest <= src) + return avr_asm_len ("mov %A0,%B1" CR_TAB + "mov %B0,%C1" CR_TAB + "clr %C0" CR_TAB + "sbrc %B0,7" CR_TAB + "dec %C0", op, plen, 5); + else + return avr_asm_len ("clr %C0" CR_TAB + "sbrc %C1,7" CR_TAB + "dec %C0" CR_TAB + "mov %B0,%C1" CR_TAB + "mov %A0,%B1", op, plen, 5); + + case 16: + if (dest != src + 2) + avr_asm_len ("mov %A0,%C1", op, plen, 1); + + return avr_asm_len ("clr %B0" CR_TAB + "sbrc %A0,7" CR_TAB + "com %B0" CR_TAB + "mov %C0,%B0", op, plen, 4); + + default: + if (INTVAL (op[2]) < 24) + break; + + /* fall through */ + + case 23: + return avr_asm_len ("lsl %C0" CR_TAB + "sbc %A0,%A0" CR_TAB + "mov %B0,%A0" CR_TAB + "mov %C0,%A0", op, plen, 4); + } /* switch */ } out_shift_with_cnt ("asr %C0" CR_TAB - "ror %B0" CR_TAB - "ror %A0", insn, op, plen, 3); + "ror %B0" CR_TAB + "ror %A0", insn, op, plen, 3); return ""; } @@ -7521,9 +7521,9 @@ ashrsi3_out (rtx_insn *insn, rtx operands[], int *len) len = t; } out_shift_with_cnt ("asr %D0" CR_TAB - "ror %C0" CR_TAB - "ror %B0" CR_TAB - "ror %A0", insn, operands, len, 4); + "ror %C0" CR_TAB + "ror %B0" CR_TAB + "ror %A0", insn, operands, len, 4); return ""; } @@ -7618,7 +7618,7 @@ lshrqi3_out (rtx_insn *insn, rtx operands[], int *len) fatal_insn ("internal compiler error. Incorrect shift:", insn); out_shift_with_cnt ("lsr %0", - insn, operands, len, 1); + insn, operands, len, 1); return ""; } @@ -7630,8 +7630,8 @@ lshrhi3_out (rtx_insn *insn, rtx operands[], int *len) if (CONST_INT_P (operands[2])) { int scratch = (GET_CODE (PATTERN (insn)) == PARALLEL - && XVECLEN (PATTERN (insn), 0) == 3 - && REG_P (operands[3])); + && XVECLEN (PATTERN (insn), 0) == 3 + && REG_P (operands[3])); int ldi_ok = test_hard_reg_class (LD_REGS, operands[0]); int k; int *t = len; @@ -7876,14 +7876,14 @@ lshrhi3_out (rtx_insn *insn, rtx operands[], int *len) len = t; } out_shift_with_cnt ("lsr %B0" CR_TAB - "ror %A0", insn, operands, len, 2); + "ror %A0", insn, operands, len, 2); return ""; } /* 24-bit logic shift right */ -const char* +const char * avr_out_lshrpsi3 (rtx_insn *insn, rtx *op, int *plen) { int dest = REGNO (op[0]); @@ -7892,45 +7892,45 @@ avr_out_lshrpsi3 (rtx_insn *insn, rtx *op, int *plen) if (CONST_INT_P (op[2])) { if (plen) - *plen = 0; + *plen = 0; switch (INTVAL (op[2])) - { - case 8: - if (dest <= src) - return avr_asm_len ("mov %A0,%B1" CR_TAB - "mov %B0,%C1" CR_TAB - "clr %C0", op, plen, 3); - else - return avr_asm_len ("clr %C0" CR_TAB - "mov %B0,%C1" CR_TAB - "mov %A0,%B1", op, plen, 3); - - case 16: - if (dest != src + 2) - avr_asm_len ("mov %A0,%C1", op, plen, 1); - - return avr_asm_len ("clr %B0" CR_TAB - "clr %C0", op, plen, 2); - - default: - if (INTVAL (op[2]) < 24) - break; - - /* fall through */ - - case 23: - return avr_asm_len ("bst %C1,7" CR_TAB - "clr %A0" CR_TAB - "clr %B0" CR_TAB - "clr %C0" CR_TAB - "bld %A0,0", op, plen, 5); - } /* switch */ + { + case 8: + if (dest <= src) + return avr_asm_len ("mov %A0,%B1" CR_TAB + "mov %B0,%C1" CR_TAB + "clr %C0", op, plen, 3); + else + return avr_asm_len ("clr %C0" CR_TAB + "mov %B0,%C1" CR_TAB + "mov %A0,%B1", op, plen, 3); + + case 16: + if (dest != src + 2) + avr_asm_len ("mov %A0,%C1", op, plen, 1); + + return avr_asm_len ("clr %B0" CR_TAB + "clr %C0", op, plen, 2); + + default: + if (INTVAL (op[2]) < 24) + break; + + /* fall through */ + + case 23: + return avr_asm_len ("bst %C1,7" CR_TAB + "clr %A0" CR_TAB + "clr %B0" CR_TAB + "clr %C0" CR_TAB + "bld %A0,0", op, plen, 5); + } /* switch */ } out_shift_with_cnt ("lsr %C0" CR_TAB - "ror %B0" CR_TAB - "ror %A0", insn, op, plen, 3); + "ror %B0" CR_TAB + "ror %A0", insn, op, plen, 3); return ""; } @@ -8024,9 +8024,9 @@ lshrsi3_out (rtx_insn *insn, rtx operands[], int *len) len = t; } out_shift_with_cnt ("lsr %D0" CR_TAB - "ror %C0" CR_TAB - "ror %B0" CR_TAB - "ror %A0", insn, operands, len, 4); + "ror %C0" CR_TAB + "ror %B0" CR_TAB + "ror %A0", insn, operands, len, 4); return ""; } @@ -8059,7 +8059,7 @@ lshrsi3_out (rtx_insn *insn, rtx operands[], int *len) static void avr_out_plus_1 (rtx *xop, int *plen, enum rtx_code code, int *pcc, - enum rtx_code code_sat, int sign, bool out_label) + enum rtx_code code_sat, int sign, bool out_label) { /* MODE of the operation. */ machine_mode mode = GET_MODE (xop[0]); @@ -8097,26 +8097,26 @@ avr_out_plus_1 (rtx *xop, int *plen, enum rtx_code code, int *pcc, *pcc = MINUS == code ? (int) CC_SET_CZN : (int) CC_CLOBBER; for (int i = 0; i < n_bytes; i++) - { - /* We operate byte-wise on the destination. */ - op[0] = simplify_gen_subreg (QImode, xop[0], mode, i); - op[1] = simplify_gen_subreg (QImode, xop[2], mode, i); - - if (i == 0) - avr_asm_len (code == PLUS ? "add %0,%1" : "sub %0,%1", - op, plen, 1); - else - avr_asm_len (code == PLUS ? "adc %0,%1" : "sbc %0,%1", - op, plen, 1); - } + { + /* We operate byte-wise on the destination. */ + op[0] = simplify_gen_subreg (QImode, xop[0], mode, i); + op[1] = simplify_gen_subreg (QImode, xop[2], mode, i); + + if (i == 0) + avr_asm_len (code == PLUS ? "add %0,%1" : "sub %0,%1", + op, plen, 1); + else + avr_asm_len (code == PLUS ? "adc %0,%1" : "sbc %0,%1", + op, plen, 1); + } if (reg_overlap_mentioned_p (xop[0], xop[2])) - { - gcc_assert (REGNO (xop[0]) == REGNO (xop[2])); + { + gcc_assert (REGNO (xop[0]) == REGNO (xop[2])); - if (MINUS == code) - return; - } + if (MINUS == code) + return; + } goto saturate; } @@ -8145,19 +8145,19 @@ avr_out_plus_1 (rtx *xop, int *plen, enum rtx_code code, int *pcc, if (SS_PLUS == code_sat && MINUS == code && sign < 0 && 0x80 == (INTVAL (simplify_gen_subreg (QImode, xval, imode, n_bytes-1)) - & GET_MODE_MASK (QImode))) + & GET_MODE_MASK (QImode))) { /* We compute x + 0x80 by means of SUB instructions. We negated the - constant subtrahend above and are left with x - (-128) so that we - need something like SUBI r,128 which does not exist because SUBI sets - V according to the sign of the subtrahend. Notice the only case - where this must be done is when NEG overflowed in case [2s] because - the V computation needs the right sign of the subtrahend. */ + constant subtrahend above and are left with x - (-128) so that we + need something like SUBI r,128 which does not exist because SUBI sets + V according to the sign of the subtrahend. Notice the only case + where this must be done is when NEG overflowed in case [2s] because + the V computation needs the right sign of the subtrahend. */ rtx msb = simplify_gen_subreg (QImode, xop[0], mode, n_bytes - 1); avr_asm_len ("subi %0,128" CR_TAB - "brmi 0f", &msb, plen, 2); + "brmi 0f", &msb, plen, 2); out_brvc = false; goto saturate; @@ -8181,100 +8181,100 @@ avr_out_plus_1 (rtx *xop, int *plen, enum rtx_code code, int *pcc, /* To get usable cc0 no low-bytes must have been skipped. */ if (i && !started) - *pcc = CC_CLOBBER; + *pcc = CC_CLOBBER; if (!started - && i % 2 == 0 - && i + 2 <= n_bytes - && test_hard_reg_class (ADDW_REGS, reg8)) - { - rtx xval16 = simplify_gen_subreg (HImode, xval, imode, i); - unsigned int val16 = UINTVAL (xval16) & GET_MODE_MASK (HImode); - - /* Registers R24, X, Y, Z can use ADIW/SBIW with constants < 64 - i.e. operate word-wise. */ - - if (val16 < 64) - { - if (val16 != 0) - { - started = true; - avr_asm_len (code == PLUS ? "adiw %0,%1" : "sbiw %0,%1", - op, plen, 1); - - if (n_bytes == 2 && PLUS == code) - *pcc = CC_SET_CZN; - } - - i++; - continue; - } - } + && i % 2 == 0 + && i + 2 <= n_bytes + && test_hard_reg_class (ADDW_REGS, reg8)) + { + rtx xval16 = simplify_gen_subreg (HImode, xval, imode, i); + unsigned int val16 = UINTVAL (xval16) & GET_MODE_MASK (HImode); - if (val8 == 0) - { - if (started) - avr_asm_len (code == PLUS - ? "adc %0,__zero_reg__" : "sbc %0,__zero_reg__", - op, plen, 1); - continue; - } + /* Registers R24, X, Y, Z can use ADIW/SBIW with constants < 64 + i.e. operate word-wise. */ + + if (val16 < 64) + { + if (val16 != 0) + { + started = true; + avr_asm_len (code == PLUS ? "adiw %0,%1" : "sbiw %0,%1", + op, plen, 1); + + if (n_bytes == 2 && PLUS == code) + *pcc = CC_SET_CZN; + } + + i++; + continue; + } + } + + if (val8 == 0) + { + if (started) + avr_asm_len (code == PLUS + ? "adc %0,__zero_reg__" : "sbc %0,__zero_reg__", + op, plen, 1); + continue; + } else if ((val8 == 1 || val8 == 0xff) - && UNKNOWN == code_sat - && !started - && i == n_bytes - 1) - { - avr_asm_len ((code == PLUS) ^ (val8 == 1) ? "dec %0" : "inc %0", - op, plen, 1); - *pcc = CC_CLOBBER; - break; - } + && UNKNOWN == code_sat + && !started + && i == n_bytes - 1) + { + avr_asm_len ((code == PLUS) ^ (val8 == 1) ? "dec %0" : "inc %0", + op, plen, 1); + *pcc = CC_CLOBBER; + break; + } switch (code) - { - case PLUS: + { + case PLUS: - gcc_assert (plen != NULL || (op[2] && REG_P (op[2]))); + gcc_assert (plen != NULL || (op[2] && REG_P (op[2]))); - if (plen != NULL && UNKNOWN != code_sat) - { - /* This belongs to the x + 0x80 corner case. The code with - ADD instruction is not smaller, thus make this case - expensive so that the caller won't pick it. */ + if (plen != NULL && UNKNOWN != code_sat) + { + /* This belongs to the x + 0x80 corner case. The code with + ADD instruction is not smaller, thus make this case + expensive so that the caller won't pick it. */ - *plen += 10; - break; - } + *plen += 10; + break; + } - if (clobber_val != (int) val8) - avr_asm_len ("ldi %2,%1", op, plen, 1); - clobber_val = (int) val8; + if (clobber_val != (int) val8) + avr_asm_len ("ldi %2,%1", op, plen, 1); + clobber_val = (int) val8; - avr_asm_len (started ? "adc %0,%2" : "add %0,%2", op, plen, 1); + avr_asm_len (started ? "adc %0,%2" : "add %0,%2", op, plen, 1); - break; /* PLUS */ + break; /* PLUS */ - case MINUS: + case MINUS: - if (ld_reg_p) - avr_asm_len (started ? "sbci %0,%1" : "subi %0,%1", op, plen, 1); - else - { - gcc_assert (plen != NULL || REG_P (op[2])); + if (ld_reg_p) + avr_asm_len (started ? "sbci %0,%1" : "subi %0,%1", op, plen, 1); + else + { + gcc_assert (plen != NULL || REG_P (op[2])); - if (clobber_val != (int) val8) - avr_asm_len ("ldi %2,%1", op, plen, 1); - clobber_val = (int) val8; + if (clobber_val != (int) val8) + avr_asm_len ("ldi %2,%1", op, plen, 1); + clobber_val = (int) val8; - avr_asm_len (started ? "sbc %0,%2" : "sub %0,%2", op, plen, 1); - } + avr_asm_len (started ? "sbc %0,%2" : "sub %0,%2", op, plen, 1); + } - break; /* MINUS */ + break; /* MINUS */ - default: - /* Unknown code */ - gcc_unreachable(); - } + default: + /* Unknown code */ + gcc_unreachable(); + } started = true; @@ -8338,86 +8338,86 @@ avr_out_plus_1 (rtx *xop, int *plen, enum rtx_code code, int *pcc, case SS_MINUS: if (out_brvc) - avr_asm_len ("brvc 0f", op, plen, 1); + avr_asm_len ("brvc 0f", op, plen, 1); if (reg_overlap_mentioned_p (xop[0], xop[2])) - { - /* [1s,reg] */ - - if (n_bytes == 1) - avr_asm_len ("ldi %0,0x7f" CR_TAB - "adc %0,__zero_reg__", op, plen, 2); - else - avr_asm_len ("ldi %0,0x7f" CR_TAB - "ldi %1,0xff" CR_TAB - "adc %1,__zero_reg__" CR_TAB - "adc %0,__zero_reg__", op, plen, 4); - } + { + /* [1s,reg] */ + + if (n_bytes == 1) + avr_asm_len ("ldi %0,0x7f" CR_TAB + "adc %0,__zero_reg__", op, plen, 2); + else + avr_asm_len ("ldi %0,0x7f" CR_TAB + "ldi %1,0xff" CR_TAB + "adc %1,__zero_reg__" CR_TAB + "adc %0,__zero_reg__", op, plen, 4); + } else if (sign == 0 && PLUS == code) - { - /* [1s,reg] */ - - op[2] = simplify_gen_subreg (QImode, xop[2], mode, n_bytes-1); - - if (n_bytes == 1) - avr_asm_len ("ldi %0,0x80" CR_TAB - "sbrs %2,7" CR_TAB - "dec %0", op, plen, 3); - else - avr_asm_len ("ldi %0,0x80" CR_TAB - "cp %2,%0" CR_TAB - "sbc %1,%1" CR_TAB - "sbci %0,0", op, plen, 4); - } + { + /* [1s,reg] */ + + op[2] = simplify_gen_subreg (QImode, xop[2], mode, n_bytes-1); + + if (n_bytes == 1) + avr_asm_len ("ldi %0,0x80" CR_TAB + "sbrs %2,7" CR_TAB + "dec %0", op, plen, 3); + else + avr_asm_len ("ldi %0,0x80" CR_TAB + "cp %2,%0" CR_TAB + "sbc %1,%1" CR_TAB + "sbci %0,0", op, plen, 4); + } else if (sign == 0 && MINUS == code) - { - /* [3s,reg] */ - - op[2] = simplify_gen_subreg (QImode, xop[2], mode, n_bytes-1); - - if (n_bytes == 1) - avr_asm_len ("ldi %0,0x7f" CR_TAB - "sbrs %2,7" CR_TAB - "inc %0", op, plen, 3); - else - avr_asm_len ("ldi %0,0x7f" CR_TAB - "cp %0,%2" CR_TAB - "sbc %1,%1" CR_TAB - "sbci %0,-1", op, plen, 4); - } + { + /* [3s,reg] */ + + op[2] = simplify_gen_subreg (QImode, xop[2], mode, n_bytes-1); + + if (n_bytes == 1) + avr_asm_len ("ldi %0,0x7f" CR_TAB + "sbrs %2,7" CR_TAB + "inc %0", op, plen, 3); + else + avr_asm_len ("ldi %0,0x7f" CR_TAB + "cp %0,%2" CR_TAB + "sbc %1,%1" CR_TAB + "sbci %0,-1", op, plen, 4); + } else if ((sign < 0) ^ (SS_MINUS == code_sat)) - { - /* [1s,const,B < 0] [2s,B < 0] */ - /* [3s,const,B > 0] [4s,B > 0] */ - - if (n_bytes == 8) - { - avr_asm_len ("%~call __clr_8", op, plen, len_call); - need_copy = false; - } - - avr_asm_len ("ldi %0,0x80", op, plen, 1); - if (n_bytes > 1 && need_copy) - avr_asm_len ("clr %1", op, plen, 1); - } + { + /* [1s,const,B < 0] [2s,B < 0] */ + /* [3s,const,B > 0] [4s,B > 0] */ + + if (n_bytes == 8) + { + avr_asm_len ("%~call __clr_8", op, plen, len_call); + need_copy = false; + } + + avr_asm_len ("ldi %0,0x80", op, plen, 1); + if (n_bytes > 1 && need_copy) + avr_asm_len ("clr %1", op, plen, 1); + } else if ((sign > 0) ^ (SS_MINUS == code_sat)) - { - /* [1s,const,B > 0] [2s,B > 0] */ - /* [3s,const,B < 0] [4s,B < 0] */ - - if (n_bytes == 8) - { - avr_asm_len ("sec" CR_TAB - "%~call __sbc_8", op, plen, 1 + len_call); - need_copy = false; - } - - avr_asm_len ("ldi %0,0x7f", op, plen, 1); - if (n_bytes > 1 && need_copy) - avr_asm_len ("ldi %1,0xff", op, plen, 1); - } + { + /* [1s,const,B > 0] [2s,B > 0] */ + /* [3s,const,B < 0] [4s,B < 0] */ + + if (n_bytes == 8) + { + avr_asm_len ("sec" CR_TAB + "%~call __sbc_8", op, plen, 1 + len_call); + need_copy = false; + } + + avr_asm_len ("ldi %0,0x7f", op, plen, 1); + if (n_bytes > 1 && need_copy) + avr_asm_len ("ldi %1,0xff", op, plen, 1); + } else - gcc_unreachable(); + gcc_unreachable(); break; @@ -8427,22 +8427,22 @@ avr_out_plus_1 (rtx *xop, int *plen, enum rtx_code code, int *pcc, avr_asm_len (PLUS == code ? "brcc 0f" : "brcs 0f", op, plen, 1); if (n_bytes == 8) - { - if (MINUS == code) - avr_asm_len ("sec", op, plen, 1); - avr_asm_len ("%~call __sbc_8", op, plen, len_call); + { + if (MINUS == code) + avr_asm_len ("sec", op, plen, 1); + avr_asm_len ("%~call __sbc_8", op, plen, len_call); - need_copy = false; - } + need_copy = false; + } else - { - if (MINUS == code && !test_hard_reg_class (LD_REGS, op[0])) - avr_asm_len ("sec" CR_TAB - "sbc %0,%0", op, plen, 2); - else - avr_asm_len (PLUS == code ? "sbc %0,%0" : "ldi %0,0xff", - op, plen, 1); - } + { + if (MINUS == code && !test_hard_reg_class (LD_REGS, op[0])) + avr_asm_len ("sec" CR_TAB + "sbc %0,%0", op, plen, 2); + else + avr_asm_len (PLUS == code ? "sbc %0,%0" : "ldi %0,0xff", + op, plen, 1); + } break; /* US_PLUS */ case US_MINUS: @@ -8451,12 +8451,12 @@ avr_out_plus_1 (rtx *xop, int *plen, enum rtx_code code, int *pcc, avr_asm_len (PLUS == code ? "brcs 0f" : "brcc 0f", op, plen, 1); if (n_bytes == 8) - { - avr_asm_len ("%~call __clr_8", op, plen, len_call); - need_copy = false; - } + { + avr_asm_len ("%~call __clr_8", op, plen, len_call); + need_copy = false; + } else - avr_asm_len ("clr %0", op, plen, 1); + avr_asm_len ("clr %0", op, plen, 1); break; } @@ -8467,37 +8467,37 @@ avr_out_plus_1 (rtx *xop, int *plen, enum rtx_code code, int *pcc, if (need_copy && n_bytes > 1) { if (US_MINUS == code_sat || US_PLUS == code_sat) - { - avr_asm_len ("mov %1,%0", op, plen, 1); - - if (n_bytes > 2) - { - op[0] = xop[0]; - if (AVR_HAVE_MOVW) - avr_asm_len ("movw %0,%1", op, plen, 1); - else - avr_asm_len ("mov %A0,%1" CR_TAB - "mov %B0,%1", op, plen, 2); - } - } + { + avr_asm_len ("mov %1,%0", op, plen, 1); + + if (n_bytes > 2) + { + op[0] = xop[0]; + if (AVR_HAVE_MOVW) + avr_asm_len ("movw %0,%1", op, plen, 1); + else + avr_asm_len ("mov %A0,%1" CR_TAB + "mov %B0,%1", op, plen, 2); + } + } else if (n_bytes > 2) - { - op[0] = xop[0]; - avr_asm_len ("mov %A0,%1" CR_TAB - "mov %B0,%1", op, plen, 2); - } + { + op[0] = xop[0]; + avr_asm_len ("mov %A0,%1" CR_TAB + "mov %B0,%1", op, plen, 2); + } } if (need_copy && n_bytes == 8) { if (AVR_HAVE_MOVW) - avr_asm_len ("movw %r0+2,%0" CR_TAB - "movw %r0+4,%0", xop, plen, 2); + avr_asm_len ("movw %r0+2,%0" CR_TAB + "movw %r0+4,%0", xop, plen, 2); else - avr_asm_len ("mov %r0+2,%0" CR_TAB - "mov %r0+3,%0" CR_TAB - "mov %r0+4,%0" CR_TAB - "mov %r0+5,%0", xop, plen, 4); + avr_asm_len ("mov %r0+2,%0" CR_TAB + "mov %r0+3,%0" CR_TAB + "mov %r0+4,%0" CR_TAB + "mov %r0+5,%0", xop, plen, 4); } if (out_label) @@ -8513,7 +8513,7 @@ avr_out_plus_1 (rtx *xop, int *plen, enum rtx_code code, int *pcc, This is a helper for the function below. The only insns that need this are additions/subtraction for pointer modes, i.e. HImode and PSImode. */ -static const char* +static const char * avr_out_plus_symbol (rtx *xop, enum rtx_code code, int *plen, int *pcc) { machine_mode mode = GET_MODE (xop[0]); @@ -8525,14 +8525,14 @@ avr_out_plus_symbol (rtx *xop, enum rtx_code code, int *plen, int *pcc) *pcc = MINUS == code ? (int) CC_SET_CZN : (int) CC_SET_N; avr_asm_len (PLUS == code - ? "subi %A0,lo8(-(%2))" CR_TAB "sbci %B0,hi8(-(%2))" - : "subi %A0,lo8(%2)" CR_TAB "sbci %B0,hi8(%2)", - xop, plen, -2); + ? "subi %A0,lo8(-(%2))" CR_TAB "sbci %B0,hi8(-(%2))" + : "subi %A0,lo8(%2)" CR_TAB "sbci %B0,hi8(%2)", + xop, plen, -2); if (PSImode == mode) avr_asm_len (PLUS == code - ? "sbci %C0,hlo8(-(%2))" - : "sbci %C0,hlo8(%2)", xop, plen, 1); + ? "sbci %C0,hlo8(-(%2))" + : "sbci %C0,hlo8(%2)", xop, plen, 1); return ""; } @@ -8559,7 +8559,7 @@ avr_out_plus_symbol (rtx *xop, enum rtx_code code, int *plen, int *pcc) Return "" */ -const char* +const char * avr_out_plus (rtx insn, rtx *xop, int *plen, int *pcc, bool out_label) { int cc_plus, cc_minus, cc_dummy; @@ -8598,11 +8598,11 @@ avr_out_plus (rtx insn, rtx *xop, int *plen, int *pcc, bool out_label) else { if (!REG_P (xop[2]) - && !CONST_INT_P (xop[2]) - && !CONST_FIXED_P (xop[2])) - { - return avr_out_plus_symbol (xop, code, plen, pcc); - } + && !CONST_INT_P (xop[2]) + && !CONST_FIXED_P (xop[2])) + { + return avr_out_plus_symbol (xop, code, plen, pcc); + } op[0] = avr_to_int_mode (xop[0]); op[1] = avr_to_int_mode (xop[1]); @@ -8653,7 +8653,7 @@ avr_out_plus (rtx insn, rtx *xop, int *plen, int *pcc, bool out_label) If PLEN == NULL, then output the instructions. If PLEN != NULL, then set *PLEN to the length of the sequence in words. */ -const char* +const char * avr_out_plus_set_ZN (rtx *xop, int *plen) { if (plen) @@ -8772,7 +8772,7 @@ avr_out_plus_set_ZN (rtx *xop, int *plen) register or SCRATCH if no clobber register is needed for the operation. INSN is an INSN_P or a pattern of an insn. */ -const char* +const char * avr_out_bitop (rtx insn, rtx *xop, int *plen) { /* CODE and MODE of the operation. */ @@ -8820,94 +8820,94 @@ avr_out_bitop (rtx insn, rtx *xop, int *plen) op[1] = GEN_INT (val8); switch (code) - { - case IOR: + { + case IOR: if (pop8 == 0) - continue; - else if (ld_reg_p) - avr_asm_len ("ori %0,%1", op, plen, 1); + continue; + else if (ld_reg_p) + avr_asm_len ("ori %0,%1", op, plen, 1); else if (pop8 == 1) - { - if (set_t != 1) - avr_asm_len ("set", op, plen, 1); - set_t = 1; - - op[1] = GEN_INT (exact_log2 (val8)); - avr_asm_len ("bld %0,%1", op, plen, 1); - } + { + if (set_t != 1) + avr_asm_len ("set", op, plen, 1); + set_t = 1; + + op[1] = GEN_INT (exact_log2 (val8)); + avr_asm_len ("bld %0,%1", op, plen, 1); + } else if (pop8 == 8) - { - if (op[3] != NULL_RTX) - avr_asm_len ("mov %0,%3", op, plen, 1); - else - avr_asm_len ("clr %0" CR_TAB - "dec %0", op, plen, 2); + { + if (op[3] != NULL_RTX) + avr_asm_len ("mov %0,%3", op, plen, 1); + else + avr_asm_len ("clr %0" CR_TAB + "dec %0", op, plen, 2); - op[3] = op[0]; - } - else - { - if (clobber_val != (int) val8) - avr_asm_len ("ldi %2,%1", op, plen, 1); - clobber_val = (int) val8; + op[3] = op[0]; + } + else + { + if (clobber_val != (int) val8) + avr_asm_len ("ldi %2,%1", op, plen, 1); + clobber_val = (int) val8; - avr_asm_len ("or %0,%2", op, plen, 1); - } + avr_asm_len ("or %0,%2", op, plen, 1); + } - continue; /* IOR */ + continue; /* IOR */ - case AND: + case AND: if (pop8 == 8) - continue; + continue; else if (pop8 == 0) - avr_asm_len ("clr %0", op, plen, 1); - else if (ld_reg_p) - avr_asm_len ("andi %0,%1", op, plen, 1); + avr_asm_len ("clr %0", op, plen, 1); + else if (ld_reg_p) + avr_asm_len ("andi %0,%1", op, plen, 1); else if (pop8 == 7) - { - if (set_t != 0) - avr_asm_len ("clt", op, plen, 1); - set_t = 0; + { + if (set_t != 0) + avr_asm_len ("clt", op, plen, 1); + set_t = 0; - op[1] = GEN_INT (exact_log2 (GET_MODE_MASK (QImode) & ~val8)); - avr_asm_len ("bld %0,%1", op, plen, 1); - } - else - { - if (clobber_val != (int) val8) - avr_asm_len ("ldi %2,%1", op, plen, 1); - clobber_val = (int) val8; + op[1] = GEN_INT (exact_log2 (GET_MODE_MASK (QImode) & ~val8)); + avr_asm_len ("bld %0,%1", op, plen, 1); + } + else + { + if (clobber_val != (int) val8) + avr_asm_len ("ldi %2,%1", op, plen, 1); + clobber_val = (int) val8; - avr_asm_len ("and %0,%2", op, plen, 1); - } + avr_asm_len ("and %0,%2", op, plen, 1); + } - continue; /* AND */ + continue; /* AND */ - case XOR: + case XOR: if (pop8 == 0) - continue; + continue; else if (pop8 == 8) - avr_asm_len ("com %0", op, plen, 1); - else if (ld_reg_p && val8 == (1 << 7)) - avr_asm_len ("subi %0,%1", op, plen, 1); - else - { - if (clobber_val != (int) val8) - avr_asm_len ("ldi %2,%1", op, plen, 1); - clobber_val = (int) val8; - - avr_asm_len ("eor %0,%2", op, plen, 1); - } - - continue; /* XOR */ - - default: - /* Unknown rtx_code */ - gcc_unreachable(); - } + avr_asm_len ("com %0", op, plen, 1); + else if (ld_reg_p && val8 == (1 << 7)) + avr_asm_len ("subi %0,%1", op, plen, 1); + else + { + if (clobber_val != (int) val8) + avr_asm_len ("ldi %2,%1", op, plen, 1); + clobber_val = (int) val8; + + avr_asm_len ("eor %0,%2", op, plen, 1); + } + + continue; /* XOR */ + + default: + /* Unknown rtx_code */ + gcc_unreachable(); + } } /* for all sub-bytes */ return ""; @@ -8919,7 +8919,7 @@ avr_out_bitop (rtx insn, rtx *xop, int *plen) otherwise, set *PLEN to the length of the instruction sequence (in words) as printed with PLEN == NULL. */ -const char* +const char * avr_out_sign_extend (rtx_insn *insn, rtx *xop, int *plen) { // Size in bytes of source resp. destination operand. @@ -8937,11 +8937,11 @@ avr_out_sign_extend (rtx_insn *insn, rtx *xop, int *plen) gcc_assert (n_src <= 2); if (n_src == 2) - avr_asm_len (AVR_HAVE_MOVW - ? "movw %0,%1" - : "mov %B0,%B1", xop, plen, 1); + avr_asm_len (AVR_HAVE_MOVW + ? "movw %0,%1" + : "mov %B0,%B1", xop, plen, 1); if (n_src == 1 || !AVR_HAVE_MOVW) - avr_asm_len ("mov %A0,%A1", xop, plen, 1); + avr_asm_len ("mov %A0,%A1", xop, plen, 1); } // Set Carry to the sign bit MSB.7... @@ -8968,7 +8968,7 @@ avr_out_sign_extend (rtx_insn *insn, rtx *xop, int *plen) PLEN != NULL: Set *PLEN to the length of that sequence. Return "". */ -const char* +const char * avr_out_addto_sp (rtx *op, int *plen) { int pc_len = AVR_2_BYTE_PC ? 2 : 3; @@ -8980,24 +8980,24 @@ avr_out_addto_sp (rtx *op, int *plen) if (addend < 0) { if (flag_verbose_asm || flag_print_asm_name) - avr_asm_len (ASM_COMMENT_START "SP -= %n0", op, plen, 0); + avr_asm_len (ASM_COMMENT_START "SP -= %n0", op, plen, 0); while (addend <= -pc_len) - { - addend += pc_len; - avr_asm_len ("rcall .", op, plen, 1); - } + { + addend += pc_len; + avr_asm_len ("rcall .", op, plen, 1); + } while (addend++ < 0) - avr_asm_len ("push __tmp_reg__", op, plen, 1); + avr_asm_len ("push __tmp_reg__", op, plen, 1); } else if (addend > 0) { if (flag_verbose_asm || flag_print_asm_name) - avr_asm_len (ASM_COMMENT_START "SP += %0", op, plen, 0); + avr_asm_len (ASM_COMMENT_START "SP += %0", op, plen, 0); while (addend-- > 0) - avr_asm_len ("pop __tmp_reg__", op, plen, 1); + avr_asm_len ("pop __tmp_reg__", op, plen, 1); } return ""; @@ -9010,57 +9010,57 @@ avr_out_addto_sp (rtx *op, int *plen) If PLEN != NULL then store the length of the sequence (in words) in *PLEN. Return "". */ -const char* +const char * avr_out_insert_notbit (rtx_insn *insn, rtx op[], int *plen) { if (INTVAL (op[1]) == 7 && test_hard_reg_class (LD_REGS, op[0])) { /* If the inserted bit number is 7 and we have a d-reg, then invert - the bit after the insertion by means of SUBI *,0x80. */ + the bit after the insertion by means of SUBI *,0x80. */ if (INTVAL (op[3]) == 7 - && REGNO (op[0]) == REGNO (op[2])) - { - avr_asm_len ("subi %0,0x80", op, plen, -1); - } + && REGNO (op[0]) == REGNO (op[2])) + { + avr_asm_len ("subi %0,0x80", op, plen, -1); + } else - { - avr_asm_len ("bst %2,%3" CR_TAB - "bld %0,%1" CR_TAB - "subi %0,0x80", op, plen, -3); - } + { + avr_asm_len ("bst %2,%3" CR_TAB + "bld %0,%1" CR_TAB + "subi %0,0x80", op, plen, -3); + } } else if (test_hard_reg_class (LD_REGS, op[0]) - && (INTVAL (op[1]) != INTVAL (op[3]) - || !reg_overlap_mentioned_p (op[0], op[2]))) + && (INTVAL (op[1]) != INTVAL (op[3]) + || !reg_overlap_mentioned_p (op[0], op[2]))) { /* If the destination bit is in a d-reg we can jump depending - on the source bit and use ANDI / ORI. This just applies if we - have not an early-clobber situation with the bit. */ + on the source bit and use ANDI / ORI. This just applies if we + have not an early-clobber situation with the bit. */ avr_asm_len ("andi %0,~(1<<%1)" CR_TAB - "sbrs %2,%3" CR_TAB - "ori %0,1<<%1", op, plen, -3); + "sbrs %2,%3" CR_TAB + "ori %0,1<<%1", op, plen, -3); } else { /* Otherwise, invert the bit by means of COM before we store it with - BST and then undo the COM if needed. */ + BST and then undo the COM if needed. */ avr_asm_len ("com %2" CR_TAB - "bst %2,%3", op, plen, -2); + "bst %2,%3", op, plen, -2); if (!reg_unused_after (insn, op[2]) - // A simple 'reg_unused_after' is not enough because that function - // assumes that the destination register is overwritten completely - // and hence is in order for our purpose. This is not the case - // with BLD which just changes one bit of the destination. - || reg_overlap_mentioned_p (op[0], op[2])) - { - /* Undo the COM from above. */ - avr_asm_len ("com %2", op, plen, 1); - } + // A simple 'reg_unused_after' is not enough because that function + // assumes that the destination register is overwritten completely + // and hence is in order for our purpose. This is not the case + // with BLD which just changes one bit of the destination. + || reg_overlap_mentioned_p (op[0], op[2])) + { + /* Undo the COM from above. */ + avr_asm_len ("com %2", op, plen, 1); + } avr_asm_len ("bld %0,%1", op, plen, 1); } @@ -9076,7 +9076,7 @@ avr_out_insert_notbit (rtx_insn *insn, rtx op[], int *plen) PLEN != 0: Set *PLEN to the code length in words. Don't output anything. PLEN == 0: Output instructions. */ -const char* +const char * avr_out_extr (rtx_insn *insn, rtx xop[], int *plen) { rtx dest = xop[0]; @@ -9143,8 +9143,8 @@ avr_out_extr (rtx_insn *insn, rtx xop[], int *plen) PLEN != 0: Set *PLEN to the code length in words. Don't output anything. PLEN == 0: Output instructions. */ -const char* -avr_out_extr_not (rtx_insn* /* insn */, rtx xop[], int *plen) +const char * +avr_out_extr_not (rtx_insn * /* insn */, rtx xop[], int *plen) { rtx dest = xop[0]; rtx src = xop[1]; @@ -9208,7 +9208,7 @@ avr_out_extr_not (rtx_insn* /* insn */, rtx xop[], int *plen) shifted by 1 bit. When the destination is a signed fractional, the sign is stored in either the carry or T bit. */ -const char* +const char * avr_out_fract (rtx_insn *insn, rtx operands[], bool intsigned, int *plen) { rtx xop[6]; @@ -9259,17 +9259,17 @@ avr_out_fract (rtx_insn *insn, rtx operands[], bool intsigned, int *plen) val[i]->regno_msb = REGNO (xop[i]) + val[i]->bytes - 1; if (SCALAR_INT_MODE_P (mode)) - { - val[i]->sbit = intsigned; - val[i]->fbit = 0; - } + { + val[i]->sbit = intsigned; + val[i]->fbit = 0; + } else if (ALL_SCALAR_FIXED_POINT_MODE_P (mode)) - { - val[i]->sbit = SIGNED_SCALAR_FIXED_POINT_MODE_P (mode); - val[i]->fbit = GET_MODE_FBIT (mode); - } + { + val[i]->sbit = SIGNED_SCALAR_FIXED_POINT_MODE_P (mode); + val[i]->fbit = GET_MODE_FBIT (mode); + } else - fatal_insn ("unsupported fixed-point conversion", insn); + fatal_insn ("unsupported fixed-point conversion", insn); val[i]->fbyte = (1 + val[i]->fbit) / BITS_PER_UNIT; val[i]->ibyte = val[i]->bytes - val[i]->fbyte; @@ -9308,9 +9308,9 @@ avr_out_fract (rtx_insn *insn, rtx operands[], bool intsigned, int *plen) && !TARGET_FRACT_CONV_TRUNC) { bool overlap - = (src.regno <= - (offset ? dest.regno_msb - sign_bytes : dest.regno + zero_bytes - 1) - && dest.regno - offset -1 >= dest.regno); + = (src.regno <= + (offset ? dest.regno_msb - sign_bytes : dest.regno + zero_bytes - 1) + && dest.regno - offset -1 >= dest.regno); unsigned s0 = dest.regno - offset -1; bool use_src = true; unsigned sn; @@ -9318,103 +9318,103 @@ avr_out_fract (rtx_insn *insn, rtx operands[], bool intsigned, int *plen) bool have_carry = false; if (src.ibyte > dest.ibyte) - copied_msb -= src.ibyte - dest.ibyte; + copied_msb -= src.ibyte - dest.ibyte; for (sn = s0; sn <= copied_msb; sn++) - if (!IN_RANGE (sn, dest.regno, dest.regno_msb) - && !reg_unused_after (insn, all_regs_rtx[sn])) - use_src = false; + if (!IN_RANGE (sn, dest.regno, dest.regno_msb) + && !reg_unused_after (insn, all_regs_rtx[sn])) + use_src = false; if (use_src && TEST_HARD_REG_BIT (reg_class_contents[LD_REGS], s0)) - { - avr_asm_len ("tst %0" CR_TAB "brpl 0f", - &all_regs_rtx[src.regno_msb], plen, 2); - sn = src.regno; - if (sn < s0) - { - if (TEST_HARD_REG_BIT (reg_class_contents[LD_REGS], sn)) - avr_asm_len ("cpi %0,1", &all_regs_rtx[sn], plen, 1); - else - avr_asm_len ("sec" CR_TAB - "cpc %0,__zero_reg__", - &all_regs_rtx[sn], plen, 2); - have_carry = true; - } - while (++sn < s0) - avr_asm_len ("cpc %0,__zero_reg__", &all_regs_rtx[sn], plen, 1); - - avr_asm_len (have_carry ? "sbci %0,128" : "subi %0,129", - &all_regs_rtx[s0], plen, 1); - for (sn = src.regno + src.fbyte; sn <= copied_msb; sn++) - avr_asm_len ("sbci %0,255", &all_regs_rtx[sn], plen, 1); - avr_asm_len ("\n0:", NULL, plen, 0); - frac_rounded = true; - } + { + avr_asm_len ("tst %0" CR_TAB "brpl 0f", + &all_regs_rtx[src.regno_msb], plen, 2); + sn = src.regno; + if (sn < s0) + { + if (TEST_HARD_REG_BIT (reg_class_contents[LD_REGS], sn)) + avr_asm_len ("cpi %0,1", &all_regs_rtx[sn], plen, 1); + else + avr_asm_len ("sec" CR_TAB + "cpc %0,__zero_reg__", + &all_regs_rtx[sn], plen, 2); + have_carry = true; + } + while (++sn < s0) + avr_asm_len ("cpc %0,__zero_reg__", &all_regs_rtx[sn], plen, 1); + + avr_asm_len (have_carry ? "sbci %0,128" : "subi %0,129", + &all_regs_rtx[s0], plen, 1); + for (sn = src.regno + src.fbyte; sn <= copied_msb; sn++) + avr_asm_len ("sbci %0,255", &all_regs_rtx[sn], plen, 1); + avr_asm_len ("\n0:", NULL, plen, 0); + frac_rounded = true; + } else if (use_src && overlap) - { - avr_asm_len ("clr __tmp_reg__" CR_TAB - "sbrc %1,0" CR_TAB - "dec __tmp_reg__", xop, plen, 1); - sn = src.regno; - if (sn < s0) - { - avr_asm_len ("add %0,__tmp_reg__", &all_regs_rtx[sn], plen, 1); - have_carry = true; - } - - while (++sn < s0) - avr_asm_len ("adc %0,__tmp_reg__", &all_regs_rtx[sn], plen, 1); - - if (have_carry) - avr_asm_len ("clt" CR_TAB - "bld __tmp_reg__,7" CR_TAB - "adc %0,__tmp_reg__", - &all_regs_rtx[s0], plen, 1); - else - avr_asm_len ("lsr __tmp_reg" CR_TAB - "add %0,__tmp_reg__", - &all_regs_rtx[s0], plen, 2); - for (sn = src.regno + src.fbyte; sn <= copied_msb; sn++) - avr_asm_len ("adc %0,__zero_reg__", &all_regs_rtx[sn], plen, 1); - frac_rounded = true; - } + { + avr_asm_len ("clr __tmp_reg__" CR_TAB + "sbrc %1,0" CR_TAB + "dec __tmp_reg__", xop, plen, 1); + sn = src.regno; + if (sn < s0) + { + avr_asm_len ("add %0,__tmp_reg__", &all_regs_rtx[sn], plen, 1); + have_carry = true; + } + + while (++sn < s0) + avr_asm_len ("adc %0,__tmp_reg__", &all_regs_rtx[sn], plen, 1); + + if (have_carry) + avr_asm_len ("clt" CR_TAB + "bld __tmp_reg__,7" CR_TAB + "adc %0,__tmp_reg__", + &all_regs_rtx[s0], plen, 1); + else + avr_asm_len ("lsr __tmp_reg" CR_TAB + "add %0,__tmp_reg__", + &all_regs_rtx[s0], plen, 2); + for (sn = src.regno + src.fbyte; sn <= copied_msb; sn++) + avr_asm_len ("adc %0,__zero_reg__", &all_regs_rtx[sn], plen, 1); + frac_rounded = true; + } else if (overlap) - { - bool use_src - = (TEST_HARD_REG_BIT (reg_class_contents[LD_REGS], s0) - && (IN_RANGE (s0, dest.regno, dest.regno_msb) - || reg_unused_after (insn, all_regs_rtx[s0]))); - xop[2] = all_regs_rtx[s0]; - unsigned sn = src.regno; - if (!use_src || sn == s0) - avr_asm_len ("mov __tmp_reg__,%2", xop, plen, 1); - /* We need to consider to-be-discarded bits - if the value is negative. */ - if (sn < s0) - { - avr_asm_len ("tst %0" CR_TAB - "brpl 0f", - &all_regs_rtx[src.regno_msb], plen, 2); - /* Test to-be-discarded bytes for any nozero bits. - ??? Could use OR or SBIW to test two registers at once. */ - if (sn < s0) - avr_asm_len ("cp %0,__zero_reg__", &all_regs_rtx[sn], plen, 1); - - while (++sn < s0) - avr_asm_len ("cpc %0,__zero_reg__", &all_regs_rtx[sn], plen, 1); - /* Set bit 0 in __tmp_reg__ if any of the lower bits was set. */ - if (use_src) - avr_asm_len ("breq 0f" CR_TAB - "ori %2,1" - "\n0:\t" "mov __tmp_reg__,%2", - xop, plen, 3); - else - avr_asm_len ("breq 0f" CR_TAB - "set" CR_TAB - "bld __tmp_reg__,0\n0:", - xop, plen, 3); - } - lsb_in_tmp_reg = true; - } + { + bool use_src + = (TEST_HARD_REG_BIT (reg_class_contents[LD_REGS], s0) + && (IN_RANGE (s0, dest.regno, dest.regno_msb) + || reg_unused_after (insn, all_regs_rtx[s0]))); + xop[2] = all_regs_rtx[s0]; + unsigned sn = src.regno; + if (!use_src || sn == s0) + avr_asm_len ("mov __tmp_reg__,%2", xop, plen, 1); + /* We need to consider to-be-discarded bits + if the value is negative. */ + if (sn < s0) + { + avr_asm_len ("tst %0" CR_TAB + "brpl 0f", + &all_regs_rtx[src.regno_msb], plen, 2); + /* Test to-be-discarded bytes for any nozero bits. + ??? Could use OR or SBIW to test two registers at once. */ + if (sn < s0) + avr_asm_len ("cp %0,__zero_reg__", &all_regs_rtx[sn], plen, 1); + + while (++sn < s0) + avr_asm_len ("cpc %0,__zero_reg__", &all_regs_rtx[sn], plen, 1); + /* Set bit 0 in __tmp_reg__ if any of the lower bits was set. */ + if (use_src) + avr_asm_len ("breq 0f" CR_TAB + "ori %2,1" + "\n0:\t" "mov __tmp_reg__,%2", + xop, plen, 3); + else + avr_asm_len ("breq 0f" CR_TAB + "set" CR_TAB + "bld __tmp_reg__,0\n0:", + xop, plen, 3); + } + lsb_in_tmp_reg = true; + } } /* Step 1: Clear bytes at the low end and copy payload bits from source @@ -9447,85 +9447,85 @@ avr_out_fract (rtx_insn *insn, rtx operands[], bool intsigned, int *plen) int stepw = 0; if (clr0) - { - if (AVR_HAVE_MOVW && clr1 && clrw) - { - xop[2] = all_regs_rtx[d0 & ~1]; - xop[3] = clrw; - code = "movw %2,%3"; - stepw = step; - } - else - { - xop[2] = all_regs_rtx[d0]; - code = "clr %2"; - - if (++clr_n >= 2 - && !clrw - && d0 % 2 == (step > 0)) - { - clrw = all_regs_rtx[d0 & ~1]; - } - } - } + { + if (AVR_HAVE_MOVW && clr1 && clrw) + { + xop[2] = all_regs_rtx[d0 & ~1]; + xop[3] = clrw; + code = "movw %2,%3"; + stepw = step; + } + else + { + xop[2] = all_regs_rtx[d0]; + code = "clr %2"; + + if (++clr_n >= 2 + && !clrw + && d0 % 2 == (step > 0)) + { + clrw = all_regs_rtx[d0 & ~1]; + } + } + } else if (offset && s0 <= (signed) src.regno_msb) - { - int movw = AVR_HAVE_MOVW && offset % 2 == 0 - && d0 % 2 == (offset > 0) - && d1 <= dest.regno_msb && d1 >= dest.regno - && s1 <= (signed) src.regno_msb && s1 >= (signed) src.regno; - - xop[2] = all_regs_rtx[d0 & ~movw]; - xop[3] = all_regs_rtx[s0 & ~movw]; - code = movw ? "movw %2,%3" : "mov %2,%3"; - stepw = step * movw; - } + { + int movw = AVR_HAVE_MOVW && offset % 2 == 0 + && d0 % 2 == (offset > 0) + && d1 <= dest.regno_msb && d1 >= dest.regno + && s1 <= (signed) src.regno_msb && s1 >= (signed) src.regno; + + xop[2] = all_regs_rtx[d0 & ~movw]; + xop[3] = all_regs_rtx[s0 & ~movw]; + code = movw ? "movw %2,%3" : "mov %2,%3"; + stepw = step * movw; + } if (code) - { - if (sign_extend && shift != ASHIFT && !sign_in_carry - && (d0 == src.regno_msb || d0 + stepw == src.regno_msb)) - { - /* We are going to override the sign bit. If we sign-extend, - store the sign in the Carry flag. This is not needed if - the destination will be ASHIFT in the remainder because - the ASHIFT will set Carry without extra instruction. */ - - avr_asm_len ("lsl %0", &all_regs_rtx[src.regno_msb], plen, 1); - sign_in_carry = true; - } - - unsigned src_msb = dest.regno_msb - sign_bytes - offset + 1; - - if (!sign_extend && shift == ASHIFTRT && !msb_in_carry - && src.ibyte > dest.ibyte - && (d0 == src_msb || d0 + stepw == src_msb)) - { - /* We are going to override the MSB. If we shift right, - store the MSB in the Carry flag. This is only needed if - we don't sign-extend becaue with sign-extension the MSB - (the sign) will be produced by the sign extension. */ - - avr_asm_len ("lsr %0", &all_regs_rtx[src_msb], plen, 1); - msb_in_carry = true; - } - - unsigned src_lsb = dest.regno - offset -1; - - if (shift == ASHIFT && src.fbyte > dest.fbyte && !lsb_in_carry + { + if (sign_extend && shift != ASHIFT && !sign_in_carry + && (d0 == src.regno_msb || d0 + stepw == src.regno_msb)) + { + /* We are going to override the sign bit. If we sign-extend, + store the sign in the Carry flag. This is not needed if + the destination will be ASHIFT in the remainder because + the ASHIFT will set Carry without extra instruction. */ + + avr_asm_len ("lsl %0", &all_regs_rtx[src.regno_msb], plen, 1); + sign_in_carry = true; + } + + unsigned src_msb = dest.regno_msb - sign_bytes - offset + 1; + + if (!sign_extend && shift == ASHIFTRT && !msb_in_carry + && src.ibyte > dest.ibyte + && (d0 == src_msb || d0 + stepw == src_msb)) + { + /* We are going to override the MSB. If we shift right, + store the MSB in the Carry flag. This is only needed if + we don't sign-extend becaue with sign-extension the MSB + (the sign) will be produced by the sign extension. */ + + avr_asm_len ("lsr %0", &all_regs_rtx[src_msb], plen, 1); + msb_in_carry = true; + } + + unsigned src_lsb = dest.regno - offset -1; + + if (shift == ASHIFT && src.fbyte > dest.fbyte && !lsb_in_carry && !lsb_in_tmp_reg - && (d0 == src_lsb || d0 + stepw == src_lsb)) - { - /* We are going to override the new LSB; store it into carry. */ + && (d0 == src_lsb || d0 + stepw == src_lsb)) + { + /* We are going to override the new LSB; store it into carry. */ - avr_asm_len ("lsl %0", &all_regs_rtx[src_lsb], plen, 1); - code_ashift = "rol %0"; - lsb_in_carry = true; - } + avr_asm_len ("lsl %0", &all_regs_rtx[src_lsb], plen, 1); + code_ashift = "rol %0"; + lsb_in_carry = true; + } - avr_asm_len (code, xop, plen, 1); - d0 += stepw; - } + avr_asm_len (code, xop, plen, 1); + d0 += stepw; + } } /* Step 2: Shift destination left by 1 bit position. This might be needed @@ -9553,7 +9553,7 @@ avr_out_fract (rtx_insn *insn, rtx operands[], bool intsigned, int *plen) /* Overflow goes with set carry. Clear carry otherwise. */ avr_asm_len ("brvs 0f" CR_TAB - "clc\n0:", NULL, plen, 2); + "clc\n0:", NULL, plen, 2); } /* Likewise, when converting from accumulator types to integer, we need to round up negative values. */ @@ -9603,32 +9603,32 @@ avr_out_fract (rtx_insn *insn, rtx operands[], bool intsigned, int *plen) avr_asm_len ("dec __zero_reg__", NULL, plen, 1); if (have_carry) avr_asm_len ("clt" CR_TAB - "bld __zero_reg__,7", NULL, plen, 2); + "bld __zero_reg__,7", NULL, plen, 2); else avr_asm_len ("lsr __zero_reg__", NULL, plen, 1); avr_asm_len (have_carry && lsb_in_tmp_reg - ? "adc __tmp_reg__,__zero_reg__" - : have_carry ? "adc %2,__zero_reg__" - : lsb_in_tmp_reg ? "add __tmp_reg__,__zero_reg__" - : "add %2,__zero_reg__", + ? "adc __tmp_reg__,__zero_reg__" + : have_carry ? "adc %2,__zero_reg__" + : lsb_in_tmp_reg ? "add __tmp_reg__,__zero_reg__" + : "add %2,__zero_reg__", xop, plen, 1); avr_asm_len ("eor __zero_reg__,__zero_reg__", NULL, plen, 1); } - for (d0 = dest.regno + zero_bytes; + for (d0 = dest.regno + zero_bytes; d0 <= dest.regno_msb - sign_bytes; d0++) avr_asm_len ("adc %0,__zero_reg__", &all_regs_rtx[d0], plen, 1); - avr_asm_len (lsb_in_tmp_reg + avr_asm_len (lsb_in_tmp_reg ? "\n0:\t" "lsl __tmp_reg__" - : "\n0:\t" "lsl %2", + : "\n0:\t" "lsl %2", xop, plen, 1); } else if (MAY_CLOBBER (s0)) - avr_asm_len ("lsl %0", &all_regs_rtx[s0], plen, 1); + avr_asm_len ("lsl %0", &all_regs_rtx[s0], plen, 1); else - avr_asm_len ("mov __tmp_reg__,%0" CR_TAB - "lsl __tmp_reg__", &all_regs_rtx[s0], plen, 2); + avr_asm_len ("mov __tmp_reg__,%0" CR_TAB + "lsl __tmp_reg__", &all_regs_rtx[s0], plen, 2); code_ashift = "rol %0"; lsb_in_carry = true; @@ -9637,11 +9637,11 @@ avr_out_fract (rtx_insn *insn, rtx operands[], bool intsigned, int *plen) if (shift == ASHIFT) { for (d0 = dest.regno + zero_bytes; - d0 <= dest.regno_msb - sign_bytes; d0++) - { - avr_asm_len (code_ashift, &all_regs_rtx[d0], plen, 1); - code_ashift = "rol %0"; - } + d0 <= dest.regno_msb - sign_bytes; d0++) + { + avr_asm_len (code_ashift, &all_regs_rtx[d0], plen, 1); + code_ashift = "rol %0"; + } lsb_in_carry = false; sign_in_carry = true; @@ -9656,10 +9656,10 @@ avr_out_fract (rtx_insn *insn, rtx operands[], bool intsigned, int *plen) unsigned s0 = dest.regno_msb - sign_bytes - offset + 1; if (MAY_CLOBBER (s0)) - avr_asm_len ("lsr %0", &all_regs_rtx[s0], plen, 1); + avr_asm_len ("lsr %0", &all_regs_rtx[s0], plen, 1); else - avr_asm_len ("mov __tmp_reg__,%0" CR_TAB - "lsr __tmp_reg__", &all_regs_rtx[s0], plen, 2); + avr_asm_len ("mov __tmp_reg__,%0" CR_TAB + "lsr __tmp_reg__", &all_regs_rtx[s0], plen, 2); msb_in_carry = true; } @@ -9672,10 +9672,10 @@ avr_out_fract (rtx_insn *insn, rtx operands[], bool intsigned, int *plen) unsigned s0 = src.regno_msb; if (MAY_CLOBBER (s0)) - avr_asm_len ("lsl %0", &all_regs_rtx[s0], plen, 1); + avr_asm_len ("lsl %0", &all_regs_rtx[s0], plen, 1); else - avr_asm_len ("mov __tmp_reg__,%0" CR_TAB - "lsl __tmp_reg__", &all_regs_rtx[s0], plen, 2); + avr_asm_len ("mov __tmp_reg__,%0" CR_TAB + "lsl __tmp_reg__", &all_regs_rtx[s0], plen, 2); sign_in_carry = true; } @@ -9688,21 +9688,21 @@ avr_out_fract (rtx_insn *insn, rtx operands[], bool intsigned, int *plen) for (d0 = dest.regno_msb - sign_bytes + 1; d0 <= dest.regno_msb; d0++) { if (AVR_HAVE_MOVW && movw - && d0 % 2 == 0 && d0 + 1 <= dest.regno_msb) - { - xop[2] = all_regs_rtx[d0]; - xop[3] = movw; - avr_asm_len ("movw %2,%3", xop, plen, 1); - d0++; - } + && d0 % 2 == 0 && d0 + 1 <= dest.regno_msb) + { + xop[2] = all_regs_rtx[d0]; + xop[3] = movw; + avr_asm_len ("movw %2,%3", xop, plen, 1); + d0++; + } else - { - avr_asm_len (sign_extend ? "sbc %0,%0" : "clr %0", - &all_regs_rtx[d0], plen, 1); + { + avr_asm_len (sign_extend ? "sbc %0,%0" : "clr %0", + &all_regs_rtx[d0], plen, 1); - if (++copies >= 2 && !movw && d0 % 2 == 1) - movw = all_regs_rtx[d0-1]; - } + if (++copies >= 2 && !movw && d0 % 2 == 1) + movw = all_regs_rtx[d0-1]; + } } /* for */ @@ -9714,17 +9714,17 @@ avr_out_fract (rtx_insn *insn, rtx operands[], bool intsigned, int *plen) const char *code_ashiftrt = "lsr %0"; if (sign_extend || msb_in_carry) - code_ashiftrt = "ror %0"; + code_ashiftrt = "ror %0"; if (src.sbit && src.ibyte == dest.ibyte) - code_ashiftrt = "asr %0"; + code_ashiftrt = "asr %0"; for (d0 = dest.regno_msb - sign_bytes; - d0 >= dest.regno + zero_bytes - 1 && d0 >= dest.regno; d0--) - { - avr_asm_len (code_ashiftrt, &all_regs_rtx[d0], plen, 1); - code_ashiftrt = "ror %0"; - } + d0 >= dest.regno + zero_bytes - 1 && d0 >= dest.regno; d0--) + { + avr_asm_len (code_ashiftrt, &all_regs_rtx[d0], plen, 1); + code_ashiftrt = "ror %0"; + } } #undef MAY_CLOBBER @@ -9739,7 +9739,7 @@ avr_out_fract (rtx_insn *insn, rtx operands[], bool intsigned, int *plen) of the sequence if PLEN != NULL. Most of this function deals with preparing operands for calls to `avr_out_plus' and `avr_out_bitop'. */ -const char* +const char * avr_out_round (rtx_insn *insn ATTRIBUTE_UNUSED, rtx *xop, int *plen) { scalar_mode mode = as_a (GET_MODE (xop[0])); @@ -9771,7 +9771,7 @@ avr_out_round (rtx_insn *insn ATTRIBUTE_UNUSED, rtx *xop, int *plen) avr_out_plus (xpattern, op, plen_add, NULL, false /* Don't print "0:" */); avr_asm_len ("rjmp 1f" CR_TAB - "0:", NULL, plen_add, 1); + "0:", NULL, plen_add, 1); // Keep all bits from RP and higher: ... 2^(-RP) // Clear all bits from RP+1 and lower: 2^(-RP-1) ... @@ -9843,101 +9843,101 @@ avr_rotate_bytes (rtx operands[]) src = simplify_gen_subreg (move_mode, operands[1], mode, 0); dst = simplify_gen_subreg (move_mode, operands[0], mode, 1); if (!rtx_equal_p (dst, src)) - { - emit_move_insn (dst, gen_rtx_XOR (QImode, dst, src)); - emit_move_insn (src, gen_rtx_XOR (QImode, src, dst)); - emit_move_insn (dst, gen_rtx_XOR (QImode, dst, src)); - } + { + emit_move_insn (dst, gen_rtx_XOR (QImode, dst, src)); + emit_move_insn (src, gen_rtx_XOR (QImode, src, dst)); + emit_move_insn (dst, gen_rtx_XOR (QImode, dst, src)); + } } else { #define MAX_SIZE 8 /* GET_MODE_SIZE (DImode) / GET_MODE_SIZE (QImode) */ /* Create linked list of moves to determine move order. */ struct { - rtx src, dst; - int links; + rtx src, dst; + int links; } move[MAX_SIZE + 8]; int blocked, moves; gcc_assert (size <= MAX_SIZE); /* Generate list of subreg moves. */ for (int i = 0; i < size; i++) - { - int from = i; - int to = (from + offset) % size; - move[i].src = simplify_gen_subreg (move_mode, operands[1], - mode, from * move_size); - move[i].dst = simplify_gen_subreg (move_mode, operands[0], - mode, to * move_size); - move[i].links = -1; - } + { + int from = i; + int to = (from + offset) % size; + move[i].src = simplify_gen_subreg (move_mode, operands[1], + mode, from * move_size); + move[i].dst = simplify_gen_subreg (move_mode, operands[0], + mode, to * move_size); + move[i].links = -1; + } /* Mark dependence where a dst of one move is the src of another move. - The first move is a conflict as it must wait until second is - performed. We ignore moves to self - we catch this later. */ + The first move is a conflict as it must wait until second is + performed. We ignore moves to self - we catch this later. */ if (overlapped) - for (int i = 0; i < size; i++) - if (reg_overlap_mentioned_p (move[i].dst, operands[1])) - for (int j = 0; j < size; j++) - if (j != i && rtx_equal_p (move[j].src, move[i].dst)) - { - /* The dst of move i is the src of move j. */ - move[i].links = j; - break; - } + for (int i = 0; i < size; i++) + if (reg_overlap_mentioned_p (move[i].dst, operands[1])) + for (int j = 0; j < size; j++) + if (j != i && rtx_equal_p (move[j].src, move[i].dst)) + { + /* The dst of move i is the src of move j. */ + move[i].links = j; + break; + } blocked = -1; moves = 0; /* Go through move list and perform non-conflicting moves. As each - non-overlapping move is made, it may remove other conflicts - so the process is repeated until no conflicts remain. */ + non-overlapping move is made, it may remove other conflicts + so the process is repeated until no conflicts remain. */ do - { - blocked = -1; - moves = 0; - /* Emit move where dst is not also a src or we have used that - src already. */ - for (int i = 0; i < size; i++) - if (move[i].src != NULL_RTX) - { - if (move[i].links == -1 - || move[move[i].links].src == NULL_RTX) - { - moves++; - /* Ignore NOP moves to self. */ - if (!rtx_equal_p (move[i].dst, move[i].src)) - emit_move_insn (move[i].dst, move[i].src); - - /* Remove conflict from list. */ - move[i].src = NULL_RTX; - } - else - blocked = i; - } - - /* Check for deadlock. This is when no moves occurred and we have - at least one blocked move. */ - if (moves == 0 && blocked != -1) - { - /* Need to use scratch register to break deadlock. - Add move to put dst of blocked move into scratch. - When this move occurs, it will break chain deadlock. - The scratch register is substituted for real move. */ - - gcc_assert (SCRATCH != GET_CODE (scratch)); - - move[size].src = move[blocked].dst; - move[size].dst = scratch; - /* Scratch move is never blocked. */ - move[size].links = -1; - /* Make sure we have valid link. */ - gcc_assert (move[blocked].links != -1); - /* Replace src of blocking move with scratch reg. */ - move[move[blocked].links].src = scratch; - /* Make dependent on scratch move occurring. */ - move[blocked].links = size; - size=size+1; - } - } + { + blocked = -1; + moves = 0; + /* Emit move where dst is not also a src or we have used that + src already. */ + for (int i = 0; i < size; i++) + if (move[i].src != NULL_RTX) + { + if (move[i].links == -1 + || move[move[i].links].src == NULL_RTX) + { + moves++; + /* Ignore NOP moves to self. */ + if (!rtx_equal_p (move[i].dst, move[i].src)) + emit_move_insn (move[i].dst, move[i].src); + + /* Remove conflict from list. */ + move[i].src = NULL_RTX; + } + else + blocked = i; + } + + /* Check for deadlock. This is when no moves occurred and we have + at least one blocked move. */ + if (moves == 0 && blocked != -1) + { + /* Need to use scratch register to break deadlock. + Add move to put dst of blocked move into scratch. + When this move occurs, it will break chain deadlock. + The scratch register is substituted for real move. */ + + gcc_assert (SCRATCH != GET_CODE (scratch)); + + move[size].src = move[blocked].dst; + move[size].dst = scratch; + /* Scratch move is never blocked. */ + move[size].links = -1; + /* Make sure we have valid link. */ + gcc_assert (move[blocked].links != -1); + /* Replace src of blocking move with scratch reg. */ + move[move[blocked].links].src = scratch; + /* Make dependent on scratch move occurring. */ + move[blocked].links = size; + size=size+1; + } + } while (blocked != -1); } return true; @@ -9977,7 +9977,7 @@ avr_adjust_insn_length (rtx_insn *insn, int len) if (adjust_len == ADJUST_LEN_NO) { /* Nothing to adjust: The length from attribute "length" is fine. - This is the default. */ + This is the default. */ return len; } @@ -10205,10 +10205,10 @@ avr_assemble_integer (rtx x, unsigned int size, int aligned_p) /* varasm fails to handle big fixed modes that don't fit in hwi. */ for (unsigned n = 0; n < size; n++) - { - rtx xn = simplify_gen_subreg (QImode, x, GET_MODE (x), n); - default_assemble_integer (xn, 1, aligned_p); - } + { + rtx xn = simplify_gen_subreg (QImode, x, GET_MODE (x), n); + default_assemble_integer (xn, 1, aligned_p); + } return true; } @@ -10244,18 +10244,18 @@ static bool avr_class_likely_spilled_p (reg_class_t c) { return (c != ALL_REGS && - (AVR_TINY ? 1 : c != ADDW_REGS)); + (AVR_TINY ? 1 : c != ADDW_REGS)); } /* Valid attributes: - progmem - Put data to program memory. - signal - Make a function to be hardware interrupt. - After function prologue interrupts remain disabled. - interrupt - Make a function to be hardware interrupt. Before function - prologue interrupts are enabled by means of SEI. - naked - Don't generate function prologue/epilogue and RET - instruction. */ + progmem - Put data to program memory. + signal - Make a function to be hardware interrupt. + After function prologue interrupts remain disabled. + interrupt - Make a function to be hardware interrupt. Before function + prologue interrupts are enabled by means of SEI. + naked - Don't generate function prologue/epilogue and RET + instruction. */ /* Handle a "progmem" attribute; arguments as in struct attribute_spec.handler. */ @@ -10283,7 +10283,7 @@ avr_handle_progmem_attribute (tree *node, tree name, } else if (TREE_STATIC (*node) || DECL_EXTERNAL (*node)) { - *no_add_attrs = false; + *no_add_attrs = false; } else { @@ -10317,9 +10317,9 @@ avr_handle_fndecl_attribute (tree *node, tree name, static tree avr_handle_fntype_attribute (tree *node, tree name, - tree args ATTRIBUTE_UNUSED, - int flags ATTRIBUTE_UNUSED, - bool *no_add_attrs) + tree args ATTRIBUTE_UNUSED, + int flags ATTRIBUTE_UNUSED, + bool *no_add_attrs) { if (TREE_CODE (*node) != FUNCTION_TYPE) { @@ -10333,24 +10333,24 @@ avr_handle_fntype_attribute (tree *node, tree name, static tree avr_handle_absdata_attribute (tree *node, tree name, tree /* args */, - int /* flags */, bool *no_add) + int /* flags */, bool *no_add) { location_t loc = DECL_SOURCE_LOCATION (*node); if (AVR_TINY) { if (TREE_CODE (*node) != VAR_DECL - || (!TREE_STATIC (*node) && !DECL_EXTERNAL (*node))) - { - warning_at (loc, OPT_Wattributes, "%qE attribute only applies to" - " variables in static storage", name); - *no_add = true; - } + || (!TREE_STATIC (*node) && !DECL_EXTERNAL (*node))) + { + warning_at (loc, OPT_Wattributes, "%qE attribute only applies to" + " variables in static storage", name); + *no_add = true; + } } else { warning_at (loc, OPT_Wattributes, "%qE attribute only supported" - " for reduced Tiny cores", name); + " for reduced Tiny cores", name); *no_add = true; } @@ -10439,8 +10439,8 @@ avr_eval_addr_attrib (rtx x) if (SYMBOL_REF_FLAGS (x) & SYMBOL_FLAG_IO) { attr = lookup_attribute ("io", DECL_ATTRIBUTES (decl)); - if (!attr || !TREE_VALUE (attr)) - attr = lookup_attribute ("io_low", DECL_ATTRIBUTES (decl)); + if (!attr || !TREE_VALUE (attr)) + attr = lookup_attribute ("io_low", DECL_ATTRIBUTES (decl)); } if (!attr || !TREE_VALUE (attr)) attr = lookup_attribute ("address", DECL_ATTRIBUTES (decl)); @@ -10491,16 +10491,16 @@ avr_addr_space_supported_p (addr_space_t as, location_t loc) if (AVR_TINY) { if (loc != UNKNOWN_LOCATION) - error_at (loc, "address spaces are not supported for reduced " - "Tiny devices"); + error_at (loc, "address spaces are not supported for reduced " + "Tiny devices"); return false; } else if (avr_addrspace[as].segment >= avr_n_flash) { if (loc != UNKNOWN_LOCATION) - error_at (loc, "address space %qs not supported for devices with " - "flash size up to %d KiB", avr_addrspace[as].name, - 64 * avr_n_flash); + error_at (loc, "address space %qs not supported for devices with " + "flash size up to %d KiB", avr_addrspace[as].name, + 64 * avr_n_flash); return false; } @@ -10578,7 +10578,7 @@ static bool avr_decl_absdata_p (tree decl, tree attributes) { return (VAR_P (decl) - && NULL_TREE != lookup_attribute ("absdata", attributes)); + && NULL_TREE != lookup_attribute ("absdata", attributes)); } @@ -10601,23 +10601,23 @@ avr_nonconst_pointer_addrspace (tree typ) /* Pointer to function: Test the function's return type. */ if (FUNCTION_TYPE == TREE_CODE (target)) - return avr_nonconst_pointer_addrspace (TREE_TYPE (target)); + return avr_nonconst_pointer_addrspace (TREE_TYPE (target)); /* "Ordinary" pointers... */ while (TREE_CODE (target) == ARRAY_TYPE) - target = TREE_TYPE (target); + target = TREE_TYPE (target); /* Pointers to non-generic address space must be const. */ as = TYPE_ADDR_SPACE (target); if (!ADDR_SPACE_GENERIC_P (as) - && !TYPE_READONLY (target) - && avr_addr_space_supported_p (as)) - { - return as; - } + && !TYPE_READONLY (target) + && avr_addr_space_supported_p (as)) + { + return as; + } /* Scan pointer's target type. */ @@ -10651,40 +10651,40 @@ avr_pgm_check_var_decl (tree node) case VAR_DECL: if (as = avr_nonconst_pointer_addrspace (TREE_TYPE (node)), as) - reason = _("variable"); + reason = _("variable"); break; case PARM_DECL: if (as = avr_nonconst_pointer_addrspace (TREE_TYPE (node)), as) - reason = _("function parameter"); + reason = _("function parameter"); break; case FIELD_DECL: if (as = avr_nonconst_pointer_addrspace (TREE_TYPE (node)), as) - reason = _("structure field"); + reason = _("structure field"); break; case FUNCTION_DECL: if (as = avr_nonconst_pointer_addrspace (TREE_TYPE (TREE_TYPE (node))), - as) - reason = _("return type of function"); + as) + reason = _("return type of function"); break; case POINTER_TYPE: if (as = avr_nonconst_pointer_addrspace (node), as) - reason = _("pointer"); + reason = _("pointer"); break; } if (reason) { if (TYPE_P (node)) - error ("pointer targeting address space %qs must be const in %qT", - avr_addrspace[as].name, node); + error ("pointer targeting address space %qs must be const in %qT", + avr_addrspace[as].name, node); else - error ("pointer targeting address space %qs must be const" - " in %s %q+D", - avr_addrspace[as].name, reason, node); + error ("pointer targeting address space %qs must be const" + " in %s %q+D", + avr_addrspace[as].name, reason, node); } return reason == NULL; @@ -10720,7 +10720,7 @@ avr_insert_attributes (tree node, tree *attributes) && NULL == lookup_attribute ("OS_task", *attributes)) { *attributes = tree_cons (get_identifier ("OS_task"), - NULL, *attributes); + NULL, *attributes); } /* Add the section attribute if the variable is in progmem. */ @@ -10733,31 +10733,31 @@ avr_insert_attributes (tree node, tree *attributes) tree node0 = node; /* For C++, we have to peel arrays in order to get correct - determination of readonlyness. */ + determination of readonlyness. */ do - node0 = TREE_TYPE (node0); + node0 = TREE_TYPE (node0); while (TREE_CODE (node0) == ARRAY_TYPE); if (error_mark_node == node0) - return; + return; as = TYPE_ADDR_SPACE (TREE_TYPE (node)); if (!TYPE_READONLY (node0) - && !TREE_READONLY (node)) - { - const char *reason = "__attribute__((progmem))"; + && !TREE_READONLY (node)) + { + const char *reason = "__attribute__((progmem))"; - if (!ADDR_SPACE_GENERIC_P (as)) - reason = avr_addrspace[as].name; + if (!ADDR_SPACE_GENERIC_P (as)) + reason = avr_addrspace[as].name; - if (avr_log.progmem) - avr_edump ("\n%?: %t\n%t\n", node, node0); + if (avr_log.progmem) + avr_edump ("\n%?: %t\n%t\n", node, node0); - error ("variable %q+D must be const in order to be put into" - " read-only section by means of %qs", node, reason); - } + error ("variable %q+D must be const in order to be put into" + " read-only section by means of %qs", node, reason); + } } } @@ -10966,12 +10966,12 @@ avr_asm_named_section (const char *name, unsigned int flags, tree decl) const char *new_prefix = avr_addrspace[as].section_name; if (startswith (name, old_prefix)) - { - const char *sname = ACONCAT ((new_prefix, - name + strlen (old_prefix), NULL)); - default_elf_asm_named_section (sname, flags, decl); - return; - } + { + const char *sname = ACONCAT ((new_prefix, + name + strlen (old_prefix), NULL)); + default_elf_asm_named_section (sname, flags, decl); + return; + } default_elf_asm_named_section (new_prefix, flags, decl); return; @@ -11015,11 +11015,11 @@ avr_section_type_flags (tree decl, const char *name, int reloc) addr_space_t as = TYPE_ADDR_SPACE (TREE_TYPE (decl)); /* Attribute progmem puts data in generic address space. - Set section flags as if it was in __flash to get the right - section prefix in the remainder. */ + Set section flags as if it was in __flash to get the right + section prefix in the remainder. */ if (ADDR_SPACE_GENERIC_P (as)) - as = ADDR_SPACE_FLASH; + as = ADDR_SPACE_FLASH; flags |= as * SECTION_MACH_DEP; flags &= ~SECTION_WRITE; @@ -11059,7 +11059,7 @@ avr_decl_maybe_lds_p (tree node) while (ARRAY_TYPE == TREE_CODE (node)); return (node != error_mark_node - && !TYPE_READONLY (node)); + && !TYPE_READONLY (node)); } @@ -11080,22 +11080,22 @@ avr_encode_section_info (tree decl, rtx rtl, int new_decl_p) && avr_progmem_p (decl, DECL_ATTRIBUTES (decl))) { if (!TREE_READONLY (decl)) - { - // This might happen with C++ if stuff needs constructing. - error ("variable %q+D with dynamic initialization put " - "into program memory area", decl); - } + { + // This might happen with C++ if stuff needs constructing. + error ("variable %q+D with dynamic initialization put " + "into program memory area", decl); + } else if (NULL_TREE == DECL_INITIAL (decl)) - { - // Don't warn for (implicit) aliases like in PR80462. - tree asmname = DECL_ASSEMBLER_NAME (decl); - varpool_node *node = varpool_node::get_for_asmname (asmname); - bool alias_p = node && node->alias; - - if (!alias_p) - warning (OPT_Wuninitialized, "uninitialized variable %q+D put " - "into program memory area", decl); - } + { + // Don't warn for (implicit) aliases like in PR80462. + tree asmname = DECL_ASSEMBLER_NAME (decl); + varpool_node *node = varpool_node::get_for_asmname (asmname); + bool alias_p = node && node->alias; + + if (!alias_p) + warning (OPT_Wuninitialized, "uninitialized variable %q+D put " + "into program memory area", decl); + } } default_encode_section_info (decl, rtl, new_decl_p); @@ -11114,10 +11114,10 @@ avr_encode_section_info (tree decl, rtx rtl, int new_decl_p) addr_space_t as = TYPE_ADDR_SPACE (type); /* PSTR strings are in generic space but located in flash: - patch address space. */ + patch address space. */ if (!AVR_TINY && avr_progmem_p (decl, attr) == -1) - as = ADDR_SPACE_FLASH; + as = ADDR_SPACE_FLASH; AVR_SYMBOL_SET_ADDR_SPACE (sym, as); @@ -11136,9 +11136,9 @@ avr_encode_section_info (tree decl, rtx rtl, int new_decl_p) if (io_low_attr || (io_attr && addr_attr - && low_io_address_operand - (GEN_INT (TREE_INT_CST_LOW - (TREE_VALUE (TREE_VALUE (addr_attr)))), QImode))) + && low_io_address_operand + (GEN_INT (TREE_INT_CST_LOW + (TREE_VALUE (TREE_VALUE (addr_attr)))), QImode))) SYMBOL_REF_FLAGS (sym) |= SYMBOL_FLAG_IO_LOW; if (io_attr || io_low_attr) SYMBOL_REF_FLAGS (sym) |= SYMBOL_FLAG_IO; @@ -11174,7 +11174,7 @@ avr_encode_section_info (tree decl, rtx rtl, int new_decl_p) using that section anyway, also use it in the public case. */ DECL_COMMON (decl) = 1; - set_decl_section_name (decl, (const char*) nullptr); + set_decl_section_name (decl, (const char *) nullptr); set_decl_tls_model (decl, (tls_model) 2); } } @@ -11190,30 +11190,30 @@ avr_encode_section_info (tree decl, rtx rtl, int new_decl_p) bool progmem_p = avr_progmem_p (decl, DECL_ATTRIBUTES (decl)) == -1; if (progmem_p) - { - // Tag symbols for addition of 0x4000 (avr_arch->flash_pm_offset). - SYMBOL_REF_FLAGS (sym) |= AVR_SYMBOL_FLAG_TINY_PM; - } + { + // Tag symbols for addition of 0x4000 (avr_arch->flash_pm_offset). + SYMBOL_REF_FLAGS (sym) |= AVR_SYMBOL_FLAG_TINY_PM; + } if (avr_decl_absdata_p (decl, DECL_ATTRIBUTES (decl)) - || (TARGET_ABSDATA - && !progmem_p - && !addr_attr - && avr_decl_maybe_lds_p (decl)) - || (addr_attr - // If addr_attr is non-null, it has an argument. Peek into it. - && TREE_INT_CST_LOW (TREE_VALUE (TREE_VALUE (addr_attr))) < 0xc0)) - { - // May be accessed by LDS / STS. - SYMBOL_REF_FLAGS (sym) |= AVR_SYMBOL_FLAG_TINY_ABSDATA; - } + || (TARGET_ABSDATA + && !progmem_p + && !addr_attr + && avr_decl_maybe_lds_p (decl)) + || (addr_attr + // If addr_attr is non-null, it has an argument. Peek into it. + && TREE_INT_CST_LOW (TREE_VALUE (TREE_VALUE (addr_attr))) < 0xc0)) + { + // May be accessed by LDS / STS. + SYMBOL_REF_FLAGS (sym) |= AVR_SYMBOL_FLAG_TINY_ABSDATA; + } if (progmem_p - && avr_decl_absdata_p (decl, DECL_ATTRIBUTES (decl))) - { - error ("%q+D has incompatible attributes %qs and %qs", - decl, "progmem", "absdata"); - } + && avr_decl_absdata_p (decl, DECL_ATTRIBUTES (decl))) + { + error ("%q+D has incompatible attributes %qs and %qs", + decl, "progmem", "absdata"); + } } } @@ -11223,7 +11223,7 @@ avr_encode_section_info (tree decl, rtx rtl, int new_decl_p) static section * avr_asm_select_section (tree decl, int reloc, unsigned HOST_WIDE_INT align) { - section * sect = default_elf_select_section (decl, reloc, align); + section *sect = default_elf_select_section (decl, reloc, align); if (decl && DECL_P (decl) && avr_progmem_p (decl, DECL_ATTRIBUTES (decl))) @@ -11231,33 +11231,33 @@ avr_asm_select_section (tree decl, int reloc, unsigned HOST_WIDE_INT align) addr_space_t as = TYPE_ADDR_SPACE (TREE_TYPE (decl)); /* __progmem__ goes in generic space but shall be allocated to - .progmem.data */ + .progmem.data */ if (ADDR_SPACE_GENERIC_P (as)) - as = ADDR_SPACE_FLASH; + as = ADDR_SPACE_FLASH; if (sect->common.flags & SECTION_NAMED) - { - const char * name = sect->named.name; - const char * old_prefix = ".rodata"; - const char * new_prefix = avr_addrspace[as].section_name; + { + const char *name = sect->named.name; + const char *old_prefix = ".rodata"; + const char *new_prefix = avr_addrspace[as].section_name; if (startswith (name, old_prefix)) - { - const char *sname = ACONCAT ((new_prefix, - name + strlen (old_prefix), NULL)); - return get_section (sname, - sect->common.flags & ~SECTION_DECLARED, - sect->named.decl); - } - } + { + const char *sname = ACONCAT ((new_prefix, + name + strlen (old_prefix), NULL)); + return get_section (sname, + sect->common.flags & ~SECTION_DECLARED, + sect->named.decl); + } + } if (!progmem_section[as]) - { - progmem_section[as] - = get_unnamed_section (0, avr_output_progmem_section_asm_op, - avr_addrspace[as].section_name); - } + { + progmem_section[as] + = get_unnamed_section (0, avr_output_progmem_section_asm_op, + avr_addrspace[as].section_name); + } return progmem_section[as]; } @@ -11390,8 +11390,8 @@ avr_adjust_reg_alloc_order (void) so different allocation order should be used. */ const int *order = (TARGET_ORDER_1 ? (AVR_TINY ? tiny_order_1 : order_1) - : TARGET_ORDER_2 ? (AVR_TINY ? tiny_order_0 : order_2) - : (AVR_TINY ? tiny_order_0 : order_0)); + : TARGET_ORDER_2 ? (AVR_TINY ? tiny_order_0 : order_2) + : (AVR_TINY ? tiny_order_0 : order_0)); for (size_t i = 0; i < ARRAY_SIZE (order_0); ++i) reg_alloc_order[i] = order[i]; @@ -11402,11 +11402,11 @@ avr_adjust_reg_alloc_order (void) static int avr_register_move_cost (machine_mode mode ATTRIBUTE_UNUSED, - reg_class_t from, reg_class_t to) + reg_class_t from, reg_class_t to) { return (from == STACK_REG ? 6 - : to == STACK_REG ? 12 - : 2); + : to == STACK_REG ? 12 + : 2); } @@ -11414,14 +11414,14 @@ avr_register_move_cost (machine_mode mode ATTRIBUTE_UNUSED, static int avr_memory_move_cost (machine_mode mode, - reg_class_t rclass ATTRIBUTE_UNUSED, - bool in ATTRIBUTE_UNUSED) + reg_class_t rclass ATTRIBUTE_UNUSED, + bool in ATTRIBUTE_UNUSED) { return (mode == QImode ? 2 - : mode == HImode ? 4 - : mode == SImode ? 8 - : mode == SFmode ? 8 - : 16); + : mode == HImode ? 4 + : mode == SImode ? 8 + : mode == SFmode ? 8 + : 16); } @@ -11438,14 +11438,14 @@ avr_mul_highpart_cost (rtx x, int) { // This is the wider mode. machine_mode mode = GET_MODE (x); - + // The middle-end might still have PR81444, i.e. it is calling the cost // functions with strange modes. Fix this now by also considering // PSImode (should actually be SImode instead). if (HImode == mode || PSImode == mode || SImode == mode) - { - return COSTS_N_INSNS (2); - } + { + return COSTS_N_INSNS (2); + } } return 10000; @@ -11544,7 +11544,7 @@ avr_operand_rtx_cost (rtx x, machine_mode mode, enum rtx_code outer, static bool avr_rtx_costs_1 (rtx x, machine_mode mode, int outer_code, - int opno ATTRIBUTE_UNUSED, int *total, bool speed) + int opno ATTRIBUTE_UNUSED, int *total, bool speed) { enum rtx_code code = GET_CODE (x); HOST_WIDE_INT val; @@ -11573,11 +11573,11 @@ avr_rtx_costs_1 (rtx x, machine_mode mode, int outer_code, *total = COSTS_N_INSNS (1); break; - case E_HImode: - case E_PSImode: - case E_SImode: - *total = COSTS_N_INSNS (2 * GET_MODE_SIZE (mode) - 1); - break; + case E_HImode: + case E_PSImode: + case E_SImode: + *total = COSTS_N_INSNS (2 * GET_MODE_SIZE (mode) - 1); + break; default: return false; @@ -11622,37 +11622,37 @@ avr_rtx_costs_1 (rtx x, machine_mode mode, int outer_code, switch (mode) { case E_QImode: - if (AVR_HAVE_MUL - && MULT == GET_CODE (XEXP (x, 0)) - && register_operand (XEXP (x, 1), QImode)) - { - /* multiply-add */ - *total = COSTS_N_INSNS (speed ? 4 : 3); - /* multiply-add with constant: will be split and load constant. */ - if (CONST_INT_P (XEXP (XEXP (x, 0), 1))) - *total = COSTS_N_INSNS (1) + *total; - return true; - } + if (AVR_HAVE_MUL + && MULT == GET_CODE (XEXP (x, 0)) + && register_operand (XEXP (x, 1), QImode)) + { + /* multiply-add */ + *total = COSTS_N_INSNS (speed ? 4 : 3); + /* multiply-add with constant: will be split and load constant. */ + if (CONST_INT_P (XEXP (XEXP (x, 0), 1))) + *total = COSTS_N_INSNS (1) + *total; + return true; + } *total = COSTS_N_INSNS (1); if (!CONST_INT_P (XEXP (x, 1))) *total += avr_operand_rtx_cost (XEXP (x, 1), mode, code, 1, speed); break; case E_HImode: - if (AVR_HAVE_MUL - && (MULT == GET_CODE (XEXP (x, 0)) - || ASHIFT == GET_CODE (XEXP (x, 0))) - && register_operand (XEXP (x, 1), HImode) - && (ZERO_EXTEND == GET_CODE (XEXP (XEXP (x, 0), 0)) - || SIGN_EXTEND == GET_CODE (XEXP (XEXP (x, 0), 0)))) - { - /* multiply-add */ - *total = COSTS_N_INSNS (speed ? 5 : 4); - /* multiply-add with constant: will be split and load constant. */ - if (CONST_INT_P (XEXP (XEXP (x, 0), 1))) - *total = COSTS_N_INSNS (1) + *total; - return true; - } + if (AVR_HAVE_MUL + && (MULT == GET_CODE (XEXP (x, 0)) + || ASHIFT == GET_CODE (XEXP (x, 0))) + && register_operand (XEXP (x, 1), HImode) + && (ZERO_EXTEND == GET_CODE (XEXP (XEXP (x, 0), 0)) + || SIGN_EXTEND == GET_CODE (XEXP (XEXP (x, 0), 0)))) + { + /* multiply-add */ + *total = COSTS_N_INSNS (speed ? 5 : 4); + /* multiply-add with constant: will be split and load constant. */ + if (CONST_INT_P (XEXP (XEXP (x, 0), 1))) + *total = COSTS_N_INSNS (1) + *total; + return true; + } if (!CONST_INT_P (XEXP (x, 1))) { *total = COSTS_N_INSNS (2); @@ -11665,18 +11665,18 @@ avr_rtx_costs_1 (rtx x, machine_mode mode, int outer_code, *total = COSTS_N_INSNS (2); break; - case E_PSImode: - if (!CONST_INT_P (XEXP (x, 1))) - { - *total = COSTS_N_INSNS (3); - *total += avr_operand_rtx_cost (XEXP (x, 1), mode, code, 1, - speed); - } - else if (IN_RANGE (INTVAL (XEXP (x, 1)), -63, 63)) - *total = COSTS_N_INSNS (2); - else - *total = COSTS_N_INSNS (3); - break; + case E_PSImode: + if (!CONST_INT_P (XEXP (x, 1))) + { + *total = COSTS_N_INSNS (3); + *total += avr_operand_rtx_cost (XEXP (x, 1), mode, code, 1, + speed); + } + else if (IN_RANGE (INTVAL (XEXP (x, 1)), -63, 63)) + *total = COSTS_N_INSNS (2); + else + *total = COSTS_N_INSNS (3); + break; case E_SImode: if (!CONST_INT_P (XEXP (x, 1))) @@ -11699,67 +11699,67 @@ avr_rtx_costs_1 (rtx x, machine_mode mode, int outer_code, case MINUS: if (AVR_HAVE_MUL - && QImode == mode - && register_operand (XEXP (x, 0), QImode) - && MULT == GET_CODE (XEXP (x, 1))) - { - /* multiply-sub */ - *total = COSTS_N_INSNS (speed ? 4 : 3); - /* multiply-sub with constant: will be split and load constant. */ - if (CONST_INT_P (XEXP (XEXP (x, 1), 1))) - *total = COSTS_N_INSNS (1) + *total; - return true; - } + && QImode == mode + && register_operand (XEXP (x, 0), QImode) + && MULT == GET_CODE (XEXP (x, 1))) + { + /* multiply-sub */ + *total = COSTS_N_INSNS (speed ? 4 : 3); + /* multiply-sub with constant: will be split and load constant. */ + if (CONST_INT_P (XEXP (XEXP (x, 1), 1))) + *total = COSTS_N_INSNS (1) + *total; + return true; + } if (AVR_HAVE_MUL - && HImode == mode - && register_operand (XEXP (x, 0), HImode) - && (MULT == GET_CODE (XEXP (x, 1)) - || ASHIFT == GET_CODE (XEXP (x, 1))) - && (ZERO_EXTEND == GET_CODE (XEXP (XEXP (x, 1), 0)) - || SIGN_EXTEND == GET_CODE (XEXP (XEXP (x, 1), 0)))) - { - /* multiply-sub */ - *total = COSTS_N_INSNS (speed ? 5 : 4); - /* multiply-sub with constant: will be split and load constant. */ - if (CONST_INT_P (XEXP (XEXP (x, 1), 1))) - *total = COSTS_N_INSNS (1) + *total; - return true; - } + && HImode == mode + && register_operand (XEXP (x, 0), HImode) + && (MULT == GET_CODE (XEXP (x, 1)) + || ASHIFT == GET_CODE (XEXP (x, 1))) + && (ZERO_EXTEND == GET_CODE (XEXP (XEXP (x, 1), 0)) + || SIGN_EXTEND == GET_CODE (XEXP (XEXP (x, 1), 0)))) + { + /* multiply-sub */ + *total = COSTS_N_INSNS (speed ? 5 : 4); + /* multiply-sub with constant: will be split and load constant. */ + if (CONST_INT_P (XEXP (XEXP (x, 1), 1))) + *total = COSTS_N_INSNS (1) + *total; + return true; + } /* FALLTHRU */ case AND: case IOR: if (IOR == code - && HImode == mode - && ASHIFT == GET_CODE (XEXP (x, 0))) - { - *total = COSTS_N_INSNS (2); - // Just a rough estimate. If we see no sign- or zero-extend, - // then increase the cost a little bit. - if (REG_P (XEXP (XEXP (x, 0), 0))) - *total += COSTS_N_INSNS (1); - if (REG_P (XEXP (x, 1))) - *total += COSTS_N_INSNS (1); - return true; - } + && HImode == mode + && ASHIFT == GET_CODE (XEXP (x, 0))) + { + *total = COSTS_N_INSNS (2); + // Just a rough estimate. If we see no sign- or zero-extend, + // then increase the cost a little bit. + if (REG_P (XEXP (XEXP (x, 0), 0))) + *total += COSTS_N_INSNS (1); + if (REG_P (XEXP (x, 1))) + *total += COSTS_N_INSNS (1); + return true; + } if (IOR == code - && AND == GET_CODE (XEXP (x, 0)) - && AND == GET_CODE (XEXP (x, 1)) - && single_zero_operand (XEXP (XEXP (x, 0), 1), mode)) - { - // Open-coded bit transfer. - *total = COSTS_N_INSNS (2); - return true; - } + && AND == GET_CODE (XEXP (x, 0)) + && AND == GET_CODE (XEXP (x, 1)) + && single_zero_operand (XEXP (XEXP (x, 0), 1), mode)) + { + // Open-coded bit transfer. + *total = COSTS_N_INSNS (2); + return true; + } if (AND == code - && single_one_operand (XEXP (x, 1), mode) - && (ASHIFT == GET_CODE (XEXP (x, 0)) - || ASHIFTRT == GET_CODE (XEXP (x, 0)) - || LSHIFTRT == GET_CODE (XEXP (x, 0)))) - { - // "*insv.any_shift. - *total = COSTS_N_INSNS (1 + GET_MODE_SIZE (mode)); - return true; - } + && single_one_operand (XEXP (x, 1), mode) + && (ASHIFT == GET_CODE (XEXP (x, 0)) + || ASHIFTRT == GET_CODE (XEXP (x, 0)) + || LSHIFTRT == GET_CODE (XEXP (x, 0)))) + { + // "*insv.any_shift. + *total = COSTS_N_INSNS (1 + GET_MODE_SIZE (mode)); + return true; + } *total = COSTS_N_INSNS (GET_MODE_SIZE (mode)); *total += avr_operand_rtx_cost (XEXP (x, 0), mode, code, 0, speed); if (!CONST_INT_P (XEXP (x, 1))) @@ -11786,81 +11786,81 @@ avr_rtx_costs_1 (rtx x, machine_mode mode, int outer_code, case E_HImode: if (AVR_HAVE_MUL) - { - rtx op0 = XEXP (x, 0); - rtx op1 = XEXP (x, 1); - enum rtx_code code0 = GET_CODE (op0); - enum rtx_code code1 = GET_CODE (op1); - bool ex0 = SIGN_EXTEND == code0 || ZERO_EXTEND == code0; - bool ex1 = SIGN_EXTEND == code1 || ZERO_EXTEND == code1; - - if (ex0 - && (u8_operand (op1, HImode) - || s8_operand (op1, HImode))) - { - *total = COSTS_N_INSNS (!speed ? 4 : 6); - return true; - } - if (ex0 - && register_operand (op1, HImode)) - { - *total = COSTS_N_INSNS (!speed ? 5 : 8); - return true; - } - else if (ex0 || ex1) - { - *total = COSTS_N_INSNS (!speed ? 3 : 5); - return true; - } - else if (register_operand (op0, HImode) - && (u8_operand (op1, HImode) - || s8_operand (op1, HImode))) - { - *total = COSTS_N_INSNS (!speed ? 6 : 9); - return true; - } - else - *total = COSTS_N_INSNS (!speed ? 7 : 10); - } + { + rtx op0 = XEXP (x, 0); + rtx op1 = XEXP (x, 1); + enum rtx_code code0 = GET_CODE (op0); + enum rtx_code code1 = GET_CODE (op1); + bool ex0 = SIGN_EXTEND == code0 || ZERO_EXTEND == code0; + bool ex1 = SIGN_EXTEND == code1 || ZERO_EXTEND == code1; + + if (ex0 + && (u8_operand (op1, HImode) + || s8_operand (op1, HImode))) + { + *total = COSTS_N_INSNS (!speed ? 4 : 6); + return true; + } + if (ex0 + && register_operand (op1, HImode)) + { + *total = COSTS_N_INSNS (!speed ? 5 : 8); + return true; + } + else if (ex0 || ex1) + { + *total = COSTS_N_INSNS (!speed ? 3 : 5); + return true; + } + else if (register_operand (op0, HImode) + && (u8_operand (op1, HImode) + || s8_operand (op1, HImode))) + { + *total = COSTS_N_INSNS (!speed ? 6 : 9); + return true; + } + else + *total = COSTS_N_INSNS (!speed ? 7 : 10); + } else if (!speed) *total = COSTS_N_INSNS (AVR_HAVE_JMP_CALL ? 2 : 1); else return false; break; - case E_PSImode: - if (!speed) - *total = COSTS_N_INSNS (AVR_HAVE_JMP_CALL ? 2 : 1); - else - *total = 10; - break; + case E_PSImode: + if (!speed) + *total = COSTS_N_INSNS (AVR_HAVE_JMP_CALL ? 2 : 1); + else + *total = 10; + break; case E_SImode: case E_DImode: if (AVR_HAVE_MUL) - { - if (!speed) - { - /* Add some additional costs besides CALL like moves etc. */ - - *total = COSTS_N_INSNS (AVR_HAVE_JMP_CALL ? 5 : 4); - } - else - { - /* Just a rough estimate. Even with -O2 we don't want bulky - code expanded inline. */ - - *total = COSTS_N_INSNS (25); - } - } - else - { - if (speed) - *total = COSTS_N_INSNS (300); - else - /* Add some additional costs besides CALL like moves etc. */ - *total = COSTS_N_INSNS (AVR_HAVE_JMP_CALL ? 5 : 4); - } + { + if (!speed) + { + /* Add some additional costs besides CALL like moves etc. */ + + *total = COSTS_N_INSNS (AVR_HAVE_JMP_CALL ? 5 : 4); + } + else + { + /* Just a rough estimate. Even with -O2 we don't want bulky + code expanded inline. */ + + *total = COSTS_N_INSNS (25); + } + } + else + { + if (speed) + *total = COSTS_N_INSNS (300); + else + /* Add some additional costs besides CALL like moves etc. */ + *total = COSTS_N_INSNS (AVR_HAVE_JMP_CALL ? 5 : 4); + } if (mode == DImode) *total *= 2; @@ -11879,14 +11879,14 @@ avr_rtx_costs_1 (rtx x, machine_mode mode, int outer_code, case UDIV: case UMOD: if (!speed) - *total = COSTS_N_INSNS (AVR_HAVE_JMP_CALL ? 2 : 1); + *total = COSTS_N_INSNS (AVR_HAVE_JMP_CALL ? 2 : 1); else - *total = COSTS_N_INSNS (15 * GET_MODE_SIZE (mode)); + *total = COSTS_N_INSNS (15 * GET_MODE_SIZE (mode)); *total += avr_operand_rtx_cost (XEXP (x, 0), mode, code, 0, speed); /* For div/mod with const-int divisor we have at least the cost of - loading the divisor. */ + loading the divisor. */ if (CONST_INT_P (XEXP (x, 1))) - *total += COSTS_N_INSNS (GET_MODE_SIZE (mode)); + *total += COSTS_N_INSNS (GET_MODE_SIZE (mode)); /* Add some overall penaly for clobbering and moving around registers */ *total += COSTS_N_INSNS (2); return true; @@ -11949,23 +11949,23 @@ avr_rtx_costs_1 (rtx x, machine_mode mode, int outer_code, break; case E_HImode: - if (AVR_HAVE_MUL) - { - if (const_2_to_7_operand (XEXP (x, 1), HImode) - && (SIGN_EXTEND == GET_CODE (XEXP (x, 0)) - || ZERO_EXTEND == GET_CODE (XEXP (x, 0)))) - { - *total = COSTS_N_INSNS (!speed ? 4 : 6); - return true; - } - } - - if (const1_rtx == (XEXP (x, 1)) - && SIGN_EXTEND == GET_CODE (XEXP (x, 0))) - { - *total = COSTS_N_INSNS (2); - return true; - } + if (AVR_HAVE_MUL) + { + if (const_2_to_7_operand (XEXP (x, 1), HImode) + && (SIGN_EXTEND == GET_CODE (XEXP (x, 0)) + || ZERO_EXTEND == GET_CODE (XEXP (x, 0)))) + { + *total = COSTS_N_INSNS (!speed ? 4 : 6); + return true; + } + } + + if (const1_rtx == (XEXP (x, 1)) + && SIGN_EXTEND == GET_CODE (XEXP (x, 0))) + { + *total = COSTS_N_INSNS (2); + return true; + } if (!CONST_INT_P (XEXP (x, 1))) { @@ -12007,36 +12007,36 @@ avr_rtx_costs_1 (rtx x, machine_mode mode, int outer_code, *total = COSTS_N_INSNS (!speed ? 5 : 10); break; default: - *total = COSTS_N_INSNS (!speed ? 5 : 41); - *total += avr_operand_rtx_cost (XEXP (x, 1), mode, code, 1, + *total = COSTS_N_INSNS (!speed ? 5 : 41); + *total += avr_operand_rtx_cost (XEXP (x, 1), mode, code, 1, speed); } break; - case E_PSImode: - if (!CONST_INT_P (XEXP (x, 1))) - { - *total = COSTS_N_INSNS (!speed ? 6 : 73); - } - else - switch (INTVAL (XEXP (x, 1))) - { - case 0: - *total = 0; - break; - case 1: - case 8: - case 16: - *total = COSTS_N_INSNS (3); - break; - case 23: - *total = COSTS_N_INSNS (5); - break; - default: - *total = COSTS_N_INSNS (!speed ? 5 : 3 * INTVAL (XEXP (x, 1))); - break; - } - break; + case E_PSImode: + if (!CONST_INT_P (XEXP (x, 1))) + { + *total = COSTS_N_INSNS (!speed ? 6 : 73); + } + else + switch (INTVAL (XEXP (x, 1))) + { + case 0: + *total = 0; + break; + case 1: + case 8: + case 16: + *total = COSTS_N_INSNS (3); + break; + case 23: + *total = COSTS_N_INSNS (5); + break; + default: + *total = COSTS_N_INSNS (!speed ? 5 : 3 * INTVAL (XEXP (x, 1))); + break; + } + break; case E_SImode: if (!CONST_INT_P (XEXP (x, 1))) @@ -12123,57 +12123,57 @@ avr_rtx_costs_1 (rtx x, machine_mode mode, int outer_code, break; case 2: case 7: - case 8: - case 9: + case 8: + case 9: *total = COSTS_N_INSNS (4); break; - case 10: + case 10: case 14: *total = COSTS_N_INSNS (5); break; - case 11: - *total = COSTS_N_INSNS (!speed ? 5 : 6); + case 11: + *total = COSTS_N_INSNS (!speed ? 5 : 6); break; - case 12: - *total = COSTS_N_INSNS (!speed ? 5 : 7); + case 12: + *total = COSTS_N_INSNS (!speed ? 5 : 7); break; - case 6: + case 6: case 13: - *total = COSTS_N_INSNS (!speed ? 5 : 8); + *total = COSTS_N_INSNS (!speed ? 5 : 8); break; default: - *total = COSTS_N_INSNS (!speed ? 5 : 41); - *total += avr_operand_rtx_cost (XEXP (x, 1), mode, code, 1, + *total = COSTS_N_INSNS (!speed ? 5 : 41); + *total += avr_operand_rtx_cost (XEXP (x, 1), mode, code, 1, speed); } break; - case E_PSImode: - if (!CONST_INT_P (XEXP (x, 1))) - { - *total = COSTS_N_INSNS (!speed ? 6 : 73); - } - else - switch (INTVAL (XEXP (x, 1))) - { - case 0: - *total = 0; - break; - case 1: - *total = COSTS_N_INSNS (3); - break; - case 16: - case 8: - *total = COSTS_N_INSNS (5); - break; - case 23: - *total = COSTS_N_INSNS (4); - break; - default: - *total = COSTS_N_INSNS (!speed ? 5 : 3 * INTVAL (XEXP (x, 1))); - break; - } - break; + case E_PSImode: + if (!CONST_INT_P (XEXP (x, 1))) + { + *total = COSTS_N_INSNS (!speed ? 6 : 73); + } + else + switch (INTVAL (XEXP (x, 1))) + { + case 0: + *total = 0; + break; + case 1: + *total = COSTS_N_INSNS (3); + break; + case 16: + case 8: + *total = COSTS_N_INSNS (5); + break; + case 23: + *total = COSTS_N_INSNS (4); + break; + default: + *total = COSTS_N_INSNS (!speed ? 5 : 3 * INTVAL (XEXP (x, 1))); + break; + } + break; case E_SImode: if (!CONST_INT_P (XEXP (x, 1))) @@ -12217,10 +12217,10 @@ avr_rtx_costs_1 (rtx x, machine_mode mode, int outer_code, case LSHIFTRT: if (outer_code == TRUNCATE) - { - *total = avr_mul_highpart_cost (x, speed); - return true; - } + { + *total = avr_mul_highpart_cost (x, speed); + return true; + } switch (mode) { @@ -12269,7 +12269,7 @@ avr_rtx_costs_1 (rtx x, machine_mode mode, int outer_code, *total = COSTS_N_INSNS (4); break; case 7: - case 11: + case 11: *total = COSTS_N_INSNS (5); break; case 3: @@ -12286,36 +12286,36 @@ avr_rtx_costs_1 (rtx x, machine_mode mode, int outer_code, *total = COSTS_N_INSNS (!speed ? 5 : 9); break; default: - *total = COSTS_N_INSNS (!speed ? 5 : 41); - *total += avr_operand_rtx_cost (XEXP (x, 1), mode, code, 1, + *total = COSTS_N_INSNS (!speed ? 5 : 41); + *total += avr_operand_rtx_cost (XEXP (x, 1), mode, code, 1, speed); } break; - case E_PSImode: - if (!CONST_INT_P (XEXP (x, 1))) - { - *total = COSTS_N_INSNS (!speed ? 6 : 73); - } - else - switch (INTVAL (XEXP (x, 1))) - { - case 0: - *total = 0; - break; - case 1: - case 8: - case 16: - *total = COSTS_N_INSNS (3); - break; - case 23: - *total = COSTS_N_INSNS (5); - break; - default: - *total = COSTS_N_INSNS (!speed ? 5 : 3 * INTVAL (XEXP (x, 1))); - break; - } - break; + case E_PSImode: + if (!CONST_INT_P (XEXP (x, 1))) + { + *total = COSTS_N_INSNS (!speed ? 6 : 73); + } + else + switch (INTVAL (XEXP (x, 1))) + { + case 0: + *total = 0; + break; + case 1: + case 8: + case 16: + *total = COSTS_N_INSNS (3); + break; + case 23: + *total = COSTS_N_INSNS (5); + break; + default: + *total = COSTS_N_INSNS (!speed ? 5 : 3 * INTVAL (XEXP (x, 1))); + break; + } + break; case E_SImode: if (!CONST_INT_P (XEXP (x, 1))) @@ -12367,29 +12367,29 @@ avr_rtx_costs_1 (rtx x, machine_mode mode, int outer_code, 1, speed); break; - case E_HImode: + case E_HImode: *total = COSTS_N_INSNS (2); if (!CONST_INT_P (XEXP (x, 1))) - *total += avr_operand_rtx_cost (XEXP (x, 1), HImode, code, + *total += avr_operand_rtx_cost (XEXP (x, 1), HImode, code, 1, speed); else if (INTVAL (XEXP (x, 1)) != 0) *total += COSTS_N_INSNS (1); - break; - - case E_PSImode: - *total = COSTS_N_INSNS (3); - if (CONST_INT_P (XEXP (x, 1)) && INTVAL (XEXP (x, 1)) != 0) - *total += COSTS_N_INSNS (2); - break; - - case E_SImode: - *total = COSTS_N_INSNS (4); - if (!CONST_INT_P (XEXP (x, 1))) - *total += avr_operand_rtx_cost (XEXP (x, 1), SImode, code, + break; + + case E_PSImode: + *total = COSTS_N_INSNS (3); + if (CONST_INT_P (XEXP (x, 1)) && INTVAL (XEXP (x, 1)) != 0) + *total += COSTS_N_INSNS (2); + break; + + case E_SImode: + *total = COSTS_N_INSNS (4); + if (!CONST_INT_P (XEXP (x, 1))) + *total += avr_operand_rtx_cost (XEXP (x, 1), SImode, code, 1, speed); else if (INTVAL (XEXP (x, 1)) != 0) *total += COSTS_N_INSNS (3); - break; + break; default: return false; @@ -12400,10 +12400,10 @@ avr_rtx_costs_1 (rtx x, machine_mode mode, int outer_code, case TRUNCATE: if (LSHIFTRT == GET_CODE (XEXP (x, 0))) - { - *total = avr_mul_highpart_cost (XEXP (x, 0), speed); - return true; - } + { + *total = avr_mul_highpart_cost (XEXP (x, 0), speed); + return true; + } break; case IF_THEN_ELSE: @@ -12433,7 +12433,7 @@ avr_rtx_costs (rtx x, machine_mode mode, int outer_code, if (avr_log.rtx_costs) { avr_edump ("\n%?=%b (%s) total=%d, outer=%C:\n%r\n", - done, speed ? "speed" : "size", *total, outer_code, x); + done, speed ? "speed" : "size", *total, outer_code, x); } return done; @@ -12490,27 +12490,27 @@ avr_insn_cost (rtx_insn *insn, bool speed) static int avr_address_cost (rtx x, machine_mode mode ATTRIBUTE_UNUSED, - addr_space_t as ATTRIBUTE_UNUSED, - bool speed ATTRIBUTE_UNUSED) + addr_space_t as ATTRIBUTE_UNUSED, + bool speed ATTRIBUTE_UNUSED) { int cost = 4; if (GET_CODE (x) == PLUS && CONST_INT_P (XEXP (x, 1)) && (REG_P (XEXP (x, 0)) - || SUBREG_P (XEXP (x, 0)))) + || SUBREG_P (XEXP (x, 0)))) { if (INTVAL (XEXP (x, 1)) > MAX_LD_OFFSET(mode)) - cost = 18; + cost = 18; } else if (CONSTANT_ADDRESS_P (x)) { if (io_address_operand (x, QImode)) - cost = 2; + cost = 2; if (AVR_TINY - && avr_address_tiny_absdata_p (x, QImode)) - cost = 2; + && avr_address_tiny_absdata_p (x, QImode)) + cost = 2; } if (avr_log.address_cost) @@ -12538,16 +12538,16 @@ extra_constraint_Q (rtx x) int regno = REGNO (xx); ok = (/* allocate pseudos */ - regno >= FIRST_PSEUDO_REGISTER - /* strictly check */ - || regno == REG_Z || regno == REG_Y - /* XXX frame & arg pointer checks */ - || xx == frame_pointer_rtx - || xx == arg_pointer_rtx); + regno >= FIRST_PSEUDO_REGISTER + /* strictly check */ + || regno == REG_Z || regno == REG_Y + /* XXX frame & arg pointer checks */ + || xx == frame_pointer_rtx + || xx == arg_pointer_rtx); if (avr_log.constraints) - avr_edump ("\n%?=%d reload_completed=%d reload_in_progress=%d\n %r\n", - ok, reload_completed, reload_in_progress, x); + avr_edump ("\n%?=%d reload_completed=%d reload_in_progress=%d\n %r\n", + ok, reload_completed, reload_in_progress, x); } return ok; @@ -12615,8 +12615,8 @@ avr_libcall_value (machine_mode mode, static rtx avr_function_value (const_tree type, - const_tree fn_decl_or_type ATTRIBUTE_UNUSED, - bool outgoing ATTRIBUTE_UNUSED) + const_tree fn_decl_or_type ATTRIBUTE_UNUSED, + bool outgoing ATTRIBUTE_UNUSED) { unsigned int offs; @@ -12668,24 +12668,24 @@ avr_2word_insn_p (rtx_insn *insn) case CODE_FOR_movuqq_insn: case CODE_FOR_movqq_insn: { - rtx set = single_set (insn); - rtx src = SET_SRC (set); - rtx dest = SET_DEST (set); - - /* Factor out LDS and STS from movqi_insn. */ - - if (MEM_P (dest) - && (REG_P (src) || src == CONST0_RTX (GET_MODE (dest)))) - { - return CONSTANT_ADDRESS_P (XEXP (dest, 0)); - } - else if (REG_P (dest) - && MEM_P (src)) - { - return CONSTANT_ADDRESS_P (XEXP (src, 0)); - } - - return false; + rtx set = single_set (insn); + rtx src = SET_SRC (set); + rtx dest = SET_DEST (set); + + /* Factor out LDS and STS from movqi_insn. */ + + if (MEM_P (dest) + && (REG_P (src) || src == CONST0_RTX (GET_MODE (dest)))) + { + return CONSTANT_ADDRESS_P (XEXP (dest, 0)); + } + else if (REG_P (dest) + && MEM_P (src)) + { + return CONSTANT_ADDRESS_P (XEXP (src, 0)); + } + + return false; } case CODE_FOR_call_insn: @@ -12706,8 +12706,8 @@ jump_over_one_insn_p (rtx_insn *insn, rtx dest) int jump_offset = dest_addr - jump_addr - get_attr_length (insn); return (jump_offset == 1 - || (jump_offset == 2 - && avr_2word_insn_p (next_active_insn (insn)))); + || (jump_offset == 2 + && avr_2word_insn_p (next_active_insn (insn)))); } /* Implement TARGET_HARD_REGNO_NREGS. CCmode is four units for historical @@ -12738,12 +12738,12 @@ avr_hard_regno_mode_ok (unsigned int regno, machine_mode mode) return mode == CCmode; /* NOTE: 8-bit values must not be disallowed for R28 or R29. - Disallowing QI et al. in these regs might lead to code like - (set (subreg:QI (reg:HI 28) n) ...) - which will result in wrong code because reload does not - handle SUBREGs of hard regsisters like this. - This could be fixed in reload. However, it appears - that fixing reload is not wanted by reload people. */ + Disallowing QI et al. in these regs might lead to code like + (set (subreg:QI (reg:HI 28) n) ...) + which will result in wrong code because reload does not + handle SUBREGs of hard regsisters like this. + This could be fixed in reload. However, it appears + that fixing reload is not wanted by reload people. */ /* Any GENERAL_REGS register can hold 8-bit values. */ @@ -12751,9 +12751,9 @@ avr_hard_regno_mode_ok (unsigned int regno, machine_mode mode) return true; /* FIXME: Ideally, the following test is not needed. - However, it turned out that it can reduce the number - of spill fails. AVR and it's poor endowment with - address registers is extreme stress test for reload. */ + However, it turned out that it can reduce the number + of spill fails. AVR and it's poor endowment with + address registers is extreme stress test for reload. */ if (GET_MODE_SIZE (mode) >= 4 && regno >= REG_X) @@ -12772,9 +12772,9 @@ avr_hard_regno_call_part_clobbered (unsigned, unsigned regno, machine_mode mode) { /* FIXME: This hook gets called with MODE:REGNO combinations that don't - represent valid hard registers like, e.g. HI:29. Returning TRUE - for such registers can lead to performance degradation as mentioned - in PR53595. Thus, report invalid hard registers as FALSE. */ + represent valid hard registers like, e.g. HI:29. Returning TRUE + for such registers can lead to performance degradation as mentioned + in PR53595. Thus, report invalid hard registers as FALSE. */ if (!avr_hard_regno_mode_ok (regno, mode)) return 0; @@ -12783,9 +12783,9 @@ avr_hard_regno_call_part_clobbered (unsigned, unsigned regno, 17/18 or 19/20 (if AVR_TINY), 27/28 and 29/30. */ return ((regno <= LAST_CALLEE_SAVED_REG - && regno + GET_MODE_SIZE (mode) > 1 + LAST_CALLEE_SAVED_REG) - || (regno < REG_Y && regno + GET_MODE_SIZE (mode) > REG_Y) - || (regno < REG_Z && regno + GET_MODE_SIZE (mode) > REG_Z)); + && regno + GET_MODE_SIZE (mode) > 1 + LAST_CALLEE_SAVED_REG) + || (regno < REG_Y && regno + GET_MODE_SIZE (mode) > REG_Y) + || (regno < REG_Z && regno + GET_MODE_SIZE (mode) > REG_Z)); } @@ -12793,8 +12793,8 @@ avr_hard_regno_call_part_clobbered (unsigned, unsigned regno, enum reg_class avr_mode_code_base_reg_class (machine_mode mode ATTRIBUTE_UNUSED, - addr_space_t as, RTX_CODE outer_code, - RTX_CODE index_code ATTRIBUTE_UNUSED) + addr_space_t as, RTX_CODE outer_code, + RTX_CODE index_code ATTRIBUTE_UNUSED) { if (!ADDR_SPACE_GENERIC_P (as)) { @@ -12812,39 +12812,39 @@ avr_mode_code_base_reg_class (machine_mode mode ATTRIBUTE_UNUSED, bool avr_regno_mode_code_ok_for_base_p (int regno, - machine_mode mode ATTRIBUTE_UNUSED, - addr_space_t as ATTRIBUTE_UNUSED, - RTX_CODE outer_code, - RTX_CODE index_code ATTRIBUTE_UNUSED) + machine_mode mode ATTRIBUTE_UNUSED, + addr_space_t as ATTRIBUTE_UNUSED, + RTX_CODE outer_code, + RTX_CODE index_code ATTRIBUTE_UNUSED) { bool ok = false; if (!ADDR_SPACE_GENERIC_P (as)) { if (regno < FIRST_PSEUDO_REGISTER - && regno == REG_Z) - { - return true; - } + && regno == REG_Z) + { + return true; + } if (reg_renumber) - { - regno = reg_renumber[regno]; + { + regno = reg_renumber[regno]; - if (regno == REG_Z) - { - return true; - } - } + if (regno == REG_Z) + { + return true; + } + } return false; } if (regno < FIRST_PSEUDO_REGISTER && (regno == REG_X - || regno == REG_Y - || regno == REG_Z - || regno == ARG_POINTER_REGNUM)) + || regno == REG_Y + || regno == REG_Z + || regno == ARG_POINTER_REGNUM)) { ok = true; } @@ -12853,12 +12853,12 @@ avr_regno_mode_code_ok_for_base_p (int regno, regno = reg_renumber[regno]; if (regno == REG_X - || regno == REG_Y - || regno == REG_Z - || regno == ARG_POINTER_REGNUM) - { - ok = true; - } + || regno == REG_Y + || regno == REG_Z + || regno == ARG_POINTER_REGNUM) + { + ok = true; + } } if (avr_strict_X @@ -12877,7 +12877,7 @@ avr_regno_mode_code_ok_for_base_p (int regno, CLOBBER_REG is a QI clobber register or NULL_RTX. LEN == NULL: output instructions. LEN != NULL: set *LEN to the length of the instruction sequence - (in words) printed with LEN = NULL. + (in words) printed with LEN = NULL. If CLEAR_P is true, OP[0] had been cleard to Zero already. If CLEAR_P is false, nothing is known about OP[0]. @@ -12901,7 +12901,7 @@ output_reload_in_const (rtx *op, rtx clobber_reg, int *len, bool clear_p) int n_bytes = GET_MODE_SIZE (mode); gcc_assert (REG_P (dest) - && CONSTANT_P (src)); + && CONSTANT_P (src)); if (len) *len = 0; @@ -12922,11 +12922,11 @@ output_reload_in_const (rtx *op, rtx clobber_reg, int *len, bool clear_p) if (NULL_RTX == clobber_reg && !test_hard_reg_class (LD_REGS, dest) && (! (CONST_INT_P (src) || CONST_FIXED_P (src) || CONST_DOUBLE_P (src)) - || !avr_popcount_each_byte (src, n_bytes, - (1 << 0) | (1 << 1) | (1 << 8)))) + || !avr_popcount_each_byte (src, n_bytes, + (1 << 0) | (1 << 1) | (1 << 8)))) { /* We have no clobber register but need one. Cook one up. - That's cheaper than loading from constant pool. */ + That's cheaper than loading from constant pool. */ cooked_clobber_p = true; clobber_reg = all_regs_rtx[REG_Z + 1]; @@ -12947,25 +12947,25 @@ output_reload_in_const (rtx *op, rtx clobber_reg, int *len, bool clear_p) ldreg_p = test_hard_reg_class (LD_REGS, xdest[n]); if (!CONST_INT_P (src) - && !CONST_FIXED_P (src) - && !CONST_DOUBLE_P (src)) - { - static const char* const asm_code[][2] = - { - { "ldi %2,lo8(%1)" CR_TAB "mov %0,%2", "ldi %0,lo8(%1)" }, - { "ldi %2,hi8(%1)" CR_TAB "mov %0,%2", "ldi %0,hi8(%1)" }, - { "ldi %2,hlo8(%1)" CR_TAB "mov %0,%2", "ldi %0,hlo8(%1)" }, - { "ldi %2,hhi8(%1)" CR_TAB "mov %0,%2", "ldi %0,hhi8(%1)" } - }; - - xop[0] = xdest[n]; - xop[1] = src; - xop[2] = clobber_reg; - - avr_asm_len (asm_code[n][ldreg_p], xop, len, ldreg_p ? 1 : 2); - - continue; - } + && !CONST_FIXED_P (src) + && !CONST_DOUBLE_P (src)) + { + static const char *const asm_code[][2] = + { + { "ldi %2,lo8(%1)" CR_TAB "mov %0,%2", "ldi %0,lo8(%1)" }, + { "ldi %2,hi8(%1)" CR_TAB "mov %0,%2", "ldi %0,hi8(%1)" }, + { "ldi %2,hlo8(%1)" CR_TAB "mov %0,%2", "ldi %0,hlo8(%1)" }, + { "ldi %2,hhi8(%1)" CR_TAB "mov %0,%2", "ldi %0,hhi8(%1)" } + }; + + xop[0] = xdest[n]; + xop[1] = src; + xop[2] = clobber_reg; + + avr_asm_len (asm_code[n][ldreg_p], xop, len, ldreg_p ? 1 : 2); + + continue; + } /* Crop the n-th source byte. */ @@ -12975,107 +12975,107 @@ output_reload_in_const (rtx *op, rtx clobber_reg, int *len, bool clear_p) /* Look if we can reuse the low word by means of MOVW. */ if (n == 2 - && n_bytes >= 4 - && AVR_HAVE_MOVW) - { - rtx lo16 = simplify_gen_subreg (HImode, src, mode, 0); - rtx hi16 = simplify_gen_subreg (HImode, src, mode, 2); - - if (INTVAL (lo16) == INTVAL (hi16)) - { + && n_bytes >= 4 + && AVR_HAVE_MOVW) + { + rtx lo16 = simplify_gen_subreg (HImode, src, mode, 0); + rtx hi16 = simplify_gen_subreg (HImode, src, mode, 2); + + if (INTVAL (lo16) == INTVAL (hi16)) + { if (INTVAL (lo16) != 0 || !clear_p) avr_asm_len ("movw %C0,%A0", &op[0], len, 1); - break; - } - } + break; + } + } /* Don't use CLR so that cc0 is set as expected. */ if (ival[n] == 0) - { - if (!clear_p) - avr_asm_len (ldreg_p ? "ldi %0,0" - : AVR_ZERO_REGNO == REGNO (xdest[n]) ? "clr %0" - : "mov %0,__zero_reg__", - &xdest[n], len, 1); - continue; - } + { + if (!clear_p) + avr_asm_len (ldreg_p ? "ldi %0,0" + : AVR_ZERO_REGNO == REGNO (xdest[n]) ? "clr %0" + : "mov %0,__zero_reg__", + &xdest[n], len, 1); + continue; + } if (clobber_val == ival[n] - && REGNO (clobber_reg) == REGNO (xdest[n])) - { - continue; - } + && REGNO (clobber_reg) == REGNO (xdest[n])) + { + continue; + } /* LD_REGS can use LDI to move a constant value */ if (ldreg_p) - { - xop[0] = xdest[n]; - xop[1] = xval; - avr_asm_len ("ldi %0,lo8(%1)", xop, len, 1); - continue; - } + { + xop[0] = xdest[n]; + xop[1] = xval; + avr_asm_len ("ldi %0,lo8(%1)", xop, len, 1); + continue; + } /* Try to reuse value already loaded in some lower byte. */ for (int j = 0; j < n; j++) - if (ival[j] == ival[n]) - { - xop[0] = xdest[n]; - xop[1] = xdest[j]; + if (ival[j] == ival[n]) + { + xop[0] = xdest[n]; + xop[1] = xdest[j]; - avr_asm_len ("mov %0,%1", xop, len, 1); - done_byte = true; - break; - } + avr_asm_len ("mov %0,%1", xop, len, 1); + done_byte = true; + break; + } if (done_byte) - continue; + continue; /* Need no clobber reg for -1: Use CLR/DEC */ if (ival[n] == -1) - { - if (!clear_p) - avr_asm_len ("clr %0", &xdest[n], len, 1); + { + if (!clear_p) + avr_asm_len ("clr %0", &xdest[n], len, 1); - avr_asm_len ("dec %0", &xdest[n], len, 1); - continue; - } + avr_asm_len ("dec %0", &xdest[n], len, 1); + continue; + } else if (ival[n] == 1) - { - if (!clear_p) - avr_asm_len ("clr %0", &xdest[n], len, 1); + { + if (!clear_p) + avr_asm_len ("clr %0", &xdest[n], len, 1); - avr_asm_len ("inc %0", &xdest[n], len, 1); - continue; - } + avr_asm_len ("inc %0", &xdest[n], len, 1); + continue; + } /* Use T flag or INC to manage powers of 2 if we have - no clobber reg. */ + no clobber reg. */ if (NULL_RTX == clobber_reg - && single_one_operand (xval, QImode)) - { - xop[0] = xdest[n]; - xop[1] = GEN_INT (exact_log2 (ival[n] & GET_MODE_MASK (QImode))); + && single_one_operand (xval, QImode)) + { + xop[0] = xdest[n]; + xop[1] = GEN_INT (exact_log2 (ival[n] & GET_MODE_MASK (QImode))); - gcc_assert (constm1_rtx != xop[1]); + gcc_assert (constm1_rtx != xop[1]); - if (!set_p) - { - set_p = true; - avr_asm_len ("set", xop, len, 1); - } + if (!set_p) + { + set_p = true; + avr_asm_len ("set", xop, len, 1); + } - if (!clear_p) - avr_asm_len ("clr %0", xop, len, 1); + if (!clear_p) + avr_asm_len ("clr %0", xop, len, 1); - avr_asm_len ("bld %0,%1", xop, len, 1); - continue; - } + avr_asm_len ("bld %0,%1", xop, len, 1); + continue; + } /* We actually need the LD_REGS clobber reg. */ @@ -13087,7 +13087,7 @@ output_reload_in_const (rtx *op, rtx clobber_reg, int *len, bool clear_p) clobber_val = ival[n]; avr_asm_len ("ldi %2,lo8(%1)" CR_TAB - "mov %0,%2", xop, len, 2); + "mov %0,%2", xop, len, 2); } /* If we cooked up a clobber reg above, restore it. */ @@ -13106,11 +13106,11 @@ output_reload_in_const (rtx *op, rtx clobber_reg, int *len, bool clear_p) PLEN == NULL: Output instructions. PLEN != NULL: Output nothing. Set *PLEN to number of words occupied - by the insns printed. + by the insns printed. Return "". */ -const char* +const char * output_reload_inhi (rtx *op, rtx clobber_reg, int *plen) { output_reload_in_const (op, clobber_reg, plen, false); @@ -13126,7 +13126,7 @@ output_reload_inhi (rtx *op, rtx clobber_reg, int *plen) LEN == NULL: Output instructions. LEN != NULL: Output nothing. Set *LEN to number of words occupied - by the insns printed. + by the insns printed. Return "". */ @@ -13136,41 +13136,41 @@ output_reload_insisf (rtx *op, rtx clobber_reg, int *len) if (AVR_HAVE_MOVW && !test_hard_reg_class (LD_REGS, op[0]) && (CONST_INT_P (op[1]) - || CONST_FIXED_P (op[1]) - || CONST_DOUBLE_P (op[1]))) + || CONST_FIXED_P (op[1]) + || CONST_DOUBLE_P (op[1]))) { int len_clr, len_noclr; /* In some cases it is better to clear the destination beforehand, e.g. - CLR R2 CLR R3 MOVW R4,R2 INC R2 + CLR R2 CLR R3 MOVW R4,R2 INC R2 - is shorther than + is shorther than - CLR R2 INC R2 CLR R3 CLR R4 CLR R5 + CLR R2 INC R2 CLR R3 CLR R4 CLR R5 - We find it too tedious to work that out in the print function. - Instead, we call the print function twice to get the lengths of - both methods and use the shortest one. */ + We find it too tedious to work that out in the print function. + Instead, we call the print function twice to get the lengths of + both methods and use the shortest one. */ output_reload_in_const (op, clobber_reg, &len_clr, true); output_reload_in_const (op, clobber_reg, &len_noclr, false); if (len_noclr - len_clr == 4) - { - /* Default needs 4 CLR instructions: clear register beforehand. */ + { + /* Default needs 4 CLR instructions: clear register beforehand. */ - avr_asm_len ("mov %A0,__zero_reg__" CR_TAB - "mov %B0,__zero_reg__" CR_TAB - "movw %C0,%A0", &op[0], len, 3); + avr_asm_len ("mov %A0,__zero_reg__" CR_TAB + "mov %B0,__zero_reg__" CR_TAB + "movw %C0,%A0", &op[0], len, 3); - output_reload_in_const (op, clobber_reg, len, true); + output_reload_in_const (op, clobber_reg, len, true); - if (len) - *len += 3; + if (len) + *len += 3; - return ""; - } + return ""; + } } /* Default: destination not pre-cleared. */ @@ -13179,7 +13179,7 @@ output_reload_insisf (rtx *op, rtx clobber_reg, int *len) return ""; } -const char* +const char * avr_out_reload_inpsi (rtx *op, rtx clobber_reg, int *len) { output_reload_in_const (op, clobber_reg, len, false); @@ -13237,7 +13237,7 @@ avr_output_addr_vec (rtx_insn *labl, rtx table) sec_name = ACONCAT ((sec_name, ".", fname, NULL)); fprintf (stream, "\t.section\t%s,\"%s\",@progbits\n", sec_name, - AVR_HAVE_JMP_CALL ? "a" : "ax"); + AVR_HAVE_JMP_CALL ? "a" : "ax"); } // Output the label that preceeds the table. @@ -13254,9 +13254,9 @@ avr_output_addr_vec (rtx_insn *labl, rtx table) int value = CODE_LABEL_NUMBER (XEXP (XVECEXP (table, 0, idx), 0)); if (AVR_HAVE_JMP_CALL) - fprintf (stream, "\t.word gs(.L%d)\n", value); + fprintf (stream, "\t.word gs(.L%d)\n", value); else - fprintf (stream, "\trjmp .L%d\n", value); + fprintf (stream, "\trjmp .L%d\n", value); } // Switch back to original section. As we clobbered the section above, @@ -13275,42 +13275,42 @@ avr_conditional_register_usage (void) if (AVR_TINY) { const int tiny_reg_alloc_order[] = { - 24, 25, - 22, 23, - 30, 31, - 26, 27, - 28, 29, - 21, 20, 19, 18, - 16, 17, - 32, 33, 34, 35, - 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0 + 24, 25, + 22, 23, + 30, 31, + 26, 27, + 28, 29, + 21, 20, 19, 18, + 16, 17, + 32, 33, 34, 35, + 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0 }; /* Set R0-R17 as fixed registers. Reset R0-R17 in call used register list - - R0-R15 are not available in Tiny Core devices - - R16 and R17 are fixed registers. */ + - R0-R15 are not available in Tiny Core devices + - R16 and R17 are fixed registers. */ for (size_t i = 0; i <= 17; i++) - { - fixed_regs[i] = 1; - call_used_regs[i] = 1; - } + { + fixed_regs[i] = 1; + call_used_regs[i] = 1; + } /* Set R18 to R21 as callee saved registers - - R18, R19, R20 and R21 are the callee saved registers in - Tiny Core devices */ + - R18, R19, R20 and R21 are the callee saved registers in + Tiny Core devices */ for (size_t i = 18; i <= LAST_CALLEE_SAVED_REG; i++) - { - call_used_regs[i] = 0; - } + { + call_used_regs[i] = 0; + } /* Update register allocation order for Tiny Core devices */ for (size_t i = 0; i < ARRAY_SIZE (tiny_reg_alloc_order); i++) - { - reg_alloc_order[i] = tiny_reg_alloc_order[i]; - } + { + reg_alloc_order[i] = tiny_reg_alloc_order[i]; + } CLEAR_HARD_REG_SET (reg_class_contents[(int) ADDW_REGS]); CLEAR_HARD_REG_SET (reg_class_contents[(int) NO_LD_REGS]); @@ -13366,7 +13366,7 @@ avr_hard_regno_rename_ok (unsigned int old_reg, if ((!reload_completed || frame_pointer_needed) && (old_reg == REG_Y || old_reg == REG_Y + 1 - || new_reg == REG_Y || new_reg == REG_Y + 1)) + || new_reg == REG_Y || new_reg == REG_Y + 1)) { return 0; } @@ -13382,7 +13382,7 @@ avr_hard_regno_rename_ok (unsigned int old_reg, Operand 2: bit number. Operand 3: label to jump to if the test is true. */ -const char* +const char * avr_out_sbxx_branch (rtx_insn *insn, rtx operands[]) { enum rtx_code comp = GET_CODE (operands[0]); @@ -13407,37 +13407,37 @@ avr_out_sbxx_branch (rtx_insn *insn, rtx operands[]) case SYMBOL_REF: if (low_io_address_operand (operands[1], QImode)) - { - if (comp == EQ) - output_asm_insn ("sbis %i1,%2", operands); - else - output_asm_insn ("sbic %i1,%2", operands); - } + { + if (comp == EQ) + output_asm_insn ("sbis %i1,%2", operands); + else + output_asm_insn ("sbic %i1,%2", operands); + } else - { + { gcc_assert (io_address_operand (operands[1], QImode)); - output_asm_insn ("in __tmp_reg__,%i1", operands); - if (comp == EQ) - output_asm_insn ("sbrs __tmp_reg__,%2", operands); - else - output_asm_insn ("sbrc __tmp_reg__,%2", operands); - } + output_asm_insn ("in __tmp_reg__,%i1", operands); + if (comp == EQ) + output_asm_insn ("sbrs __tmp_reg__,%2", operands); + else + output_asm_insn ("sbrc __tmp_reg__,%2", operands); + } break; /* CONST_INT */ case REG: if (comp == EQ) - output_asm_insn ("sbrs %T1%T2", operands); + output_asm_insn ("sbrs %T1%T2", operands); else - output_asm_insn ("sbrc %T1%T2", operands); + output_asm_insn ("sbrc %T1%T2", operands); break; /* REG */ - } /* switch */ + } /* switch */ if (long_jump) return ("rjmp .+4" CR_TAB - "jmp %x3"); + "jmp %x3"); if (!reverse) return "rjmp %x3"; @@ -13570,36 +13570,36 @@ avr_addr_space_legitimate_address_p (machine_mode mode, rtx x, bool strict, case ADDR_SPACE_FLASH5: switch (GET_CODE (x)) - { - case REG: - ok = avr_reg_ok_for_pgm_addr (x, strict); - break; + { + case REG: + ok = avr_reg_ok_for_pgm_addr (x, strict); + break; - case POST_INC: - ok = avr_reg_ok_for_pgm_addr (XEXP (x, 0), strict); - break; + case POST_INC: + ok = avr_reg_ok_for_pgm_addr (XEXP (x, 0), strict); + break; - default: - break; - } + default: + break; + } break; /* FLASH */ case ADDR_SPACE_MEMX: if (REG_P (x)) - ok = (!strict - && can_create_pseudo_p()); + ok = (!strict + && can_create_pseudo_p()); if (LO_SUM == GET_CODE (x)) - { - rtx hi = XEXP (x, 0); - rtx lo = XEXP (x, 1); + { + rtx hi = XEXP (x, 0); + rtx lo = XEXP (x, 1); - ok = (REG_P (hi) - && (!strict || REGNO (hi) < FIRST_PSEUDO_REGISTER) - && REG_P (lo) - && REGNO (lo) == REG_Z); - } + ok = (REG_P (hi) + && (!strict || REGNO (hi) < FIRST_PSEUDO_REGISTER) + && REG_P (lo) + && REGNO (lo) == REG_Z); + } break; /* MEMX */ } @@ -13607,19 +13607,19 @@ avr_addr_space_legitimate_address_p (machine_mode mode, rtx x, bool strict, if (avr_log.legitimate_address_p) { avr_edump ("\n%?: ret=%b, mode=%m strict=%d " - "reload_completed=%d reload_in_progress=%d %s:", - ok, mode, strict, reload_completed, reload_in_progress, - reg_renumber ? "(reg_renumber)" : ""); + "reload_completed=%d reload_in_progress=%d %s:", + ok, mode, strict, reload_completed, reload_in_progress, + reg_renumber ? "(reg_renumber)" : ""); if (GET_CODE (x) == PLUS - && REG_P (XEXP (x, 0)) - && CONST_INT_P (XEXP (x, 1)) - && IN_RANGE (INTVAL (XEXP (x, 1)), 0, MAX_LD_OFFSET (mode)) - && reg_renumber) - { - avr_edump ("(r%d ---> r%d)", REGNO (XEXP (x, 0)), - true_regnum (XEXP (x, 0))); - } + && REG_P (XEXP (x, 0)) + && CONST_INT_P (XEXP (x, 1)) + && IN_RANGE (INTVAL (XEXP (x, 1)), 0, MAX_LD_OFFSET (mode)) + && reg_renumber) + { + avr_edump ("(r%d ---> r%d)", REGNO (XEXP (x, 0)), + true_regnum (XEXP (x, 0))); + } avr_edump ("\n%r\n", x); } @@ -13632,7 +13632,7 @@ avr_addr_space_legitimate_address_p (machine_mode mode, rtx x, bool strict, static rtx avr_addr_space_legitimize_address (rtx x, rtx old_x, - machine_mode mode, addr_space_t as) + machine_mode mode, addr_space_t as) { if (ADDR_SPACE_GENERIC_P (as)) return avr_legitimize_address (x, old_x, mode); @@ -13656,7 +13656,7 @@ avr_addr_space_convert (rtx src, tree type_from, tree type_to) if (avr_log.progmem) avr_edump ("\n%!: op = %r\nfrom = %t\nto = %t\n", - src, type_from, type_to); + src, type_from, type_to); /* Up-casting from 16-bit to 24-bit pointer. */ @@ -13668,31 +13668,31 @@ avr_addr_space_convert (rtx src, tree type_from, tree type_to) rtx reg = gen_reg_rtx (PSImode); while (CONST == GET_CODE (sym) || PLUS == GET_CODE (sym)) - sym = XEXP (sym, 0); + sym = XEXP (sym, 0); /* Look at symbol flags: avr_encode_section_info set the flags - also if attribute progmem was seen so that we get the right - promotion for, e.g. PSTR-like strings that reside in generic space - but are located in flash. In that case we patch the incoming - address space. */ + also if attribute progmem was seen so that we get the right + promotion for, e.g. PSTR-like strings that reside in generic space + but are located in flash. In that case we patch the incoming + address space. */ if (SYMBOL_REF_P (sym) - && ADDR_SPACE_FLASH == AVR_SYMBOL_GET_ADDR_SPACE (sym)) - { - as_from = ADDR_SPACE_FLASH; - } + && ADDR_SPACE_FLASH == AVR_SYMBOL_GET_ADDR_SPACE (sym)) + { + as_from = ADDR_SPACE_FLASH; + } /* Linearize memory: RAM has bit 23 set. */ msb = ADDR_SPACE_GENERIC_P (as_from) - ? 0x80 - : avr_addrspace[as_from].segment; + ? 0x80 + : avr_addrspace[as_from].segment; src = force_reg (Pmode, src); emit_insn (msb == 0 - ? gen_zero_extendhipsi2 (reg, src) - : gen_n_extendhipsi2 (reg, gen_int_mode (msb, QImode), src)); + ? gen_zero_extendhipsi2 (reg, src) + : gen_n_extendhipsi2 (reg, gen_int_mode (msb, QImode), src)); return reg; } @@ -13707,7 +13707,7 @@ avr_addr_space_convert (rtx src, tree type_from, tree type_to) src = force_reg (PSImode, src); emit_move_insn (new_src, - simplify_gen_subreg (Pmode, src, PSImode, 0)); + simplify_gen_subreg (Pmode, src, PSImode, 0)); return new_src; } @@ -13719,7 +13719,7 @@ avr_addr_space_convert (rtx src, tree type_from, tree type_to) static bool avr_addr_space_subset_p (addr_space_t subset ATTRIBUTE_UNUSED, - addr_space_t superset ATTRIBUTE_UNUSED) + addr_space_t superset ATTRIBUTE_UNUSED) { /* Allow any kind of pointer mess. */ @@ -13737,23 +13737,23 @@ avr_convert_to_type (tree type, tree expr) provided -Waddr-space-convert is on. FIXME: Filter out cases where the target object is known to - be located in the right memory, like in + be located in the right memory, like in - (const __flash*) PSTR ("text") + (const __flash*) PSTR ("text") - Also try to distinguish between explicit casts requested by - the user and implicit casts like + Also try to distinguish between explicit casts requested by + the user and implicit casts like - void f (const __flash char*); + void f (const __flash char*); - void g (const char *p) - { - f ((const __flash*) p); - } + void g (const char *p) + { + f ((const __flash*) p); + } - under the assumption that an explicit casts means that the user - knows what he is doing, e.g. interface with PSTR or old style - code with progmem and pgm_read_xxx. + under the assumption that an explicit casts means that the user + knows what he is doing, e.g. interface with PSTR or old style + code with progmem and pgm_read_xxx. */ if (avr_warn_addr_space_convert @@ -13765,22 +13765,22 @@ avr_convert_to_type (tree type, tree expr) addr_space_t as_new = TYPE_ADDR_SPACE (TREE_TYPE (type)); if (avr_log.progmem) - avr_edump ("%?: type = %t\nexpr = %t\n\n", type, expr); + avr_edump ("%?: type = %t\nexpr = %t\n\n", type, expr); if (as_new != ADDR_SPACE_MEMX - && as_new != as_old) - { - location_t loc = EXPR_LOCATION (expr); - const char *name_old = avr_addrspace[as_old].name; - const char *name_new = avr_addrspace[as_new].name; + && as_new != as_old) + { + location_t loc = EXPR_LOCATION (expr); + const char *name_old = avr_addrspace[as_old].name; + const char *name_new = avr_addrspace[as_new].name; - warning (OPT_Waddr_space_convert, - "conversion from address space %qs to address space %qs", - ADDR_SPACE_GENERIC_P (as_old) ? "generic" : name_old, - ADDR_SPACE_GENERIC_P (as_new) ? "generic" : name_new); + warning (OPT_Waddr_space_convert, + "conversion from address space %qs to address space %qs", + ADDR_SPACE_GENERIC_P (as_old) ? "generic" : name_old, + ADDR_SPACE_GENERIC_P (as_new) ? "generic" : name_new); - return fold_build1_loc (loc, ADDR_SPACE_CONVERT_EXPR, type, expr); - } + return fold_build1_loc (loc, ADDR_SPACE_CONVERT_EXPR, type, expr); + } } return NULL_TREE; @@ -13803,12 +13803,12 @@ avr_legitimate_combined_insn (rtx_insn *insn) const_rtx op = *iter; if (SUBREG_P (op) - && MEM_P (SUBREG_REG (op)) - && (GET_MODE_SIZE (GET_MODE (op)) - > GET_MODE_SIZE (GET_MODE (SUBREG_REG (op))))) - { - return false; - } + && MEM_P (SUBREG_REG (op)) + && (GET_MODE_SIZE (GET_MODE (op)) + > GET_MODE_SIZE (GET_MODE (SUBREG_REG (op))))) + { + return false; + } } return true; @@ -13826,7 +13826,7 @@ avr_legitimate_combined_insn (rtx_insn *insn) replace OP[n] with a newly created pseudo register HREG == 0: Also emit a move insn that copies the contents of that - hard register into the new pseudo. + hard register into the new pseudo. HREG != 0: Also set HREG[n] to the hard register. */ @@ -13838,23 +13838,23 @@ avr_fix_operands (rtx *op, rtx *hreg, unsigned opmask, unsigned rmask) rtx reg = *op; if (hreg) - *hreg = NULL_RTX; + *hreg = NULL_RTX; if ((opmask & 1) - && REG_P (reg) - && REGNO (reg) < FIRST_PSEUDO_REGISTER - // This hard-reg overlaps other prohibited hard regs? - && (rmask & regmask (GET_MODE (reg), REGNO (reg)))) - { - *op = gen_reg_rtx (GET_MODE (reg)); - if (hreg == NULL) - emit_move_insn (*op, reg); - else - *hreg = reg; - } + && REG_P (reg) + && REGNO (reg) < FIRST_PSEUDO_REGISTER + // This hard-reg overlaps other prohibited hard regs? + && (rmask & regmask (GET_MODE (reg), REGNO (reg)))) + { + *op = gen_reg_rtx (GET_MODE (reg)); + if (hreg == NULL) + emit_move_insn (*op, reg); + else + *hreg = reg; + } if (hreg) - hreg++; + hreg++; } } @@ -13875,7 +13875,7 @@ avr_move_fixed_operands (rtx *op, rtx *hreg, unsigned mask) { for (; mask; mask >>= 1, op++, hreg++) if ((mask & 1) - && *hreg) + && *hreg) emit_move_insn (*hreg, *op); return true; @@ -13897,7 +13897,7 @@ avr_move_fixed_operands (rtx *op, rtx *hreg, unsigned mask) bool avr_emit3_fix_outputs (rtx (*gen)(rtx,rtx,rtx), rtx *op, - unsigned opmask, unsigned rmask) + unsigned opmask, unsigned rmask) { const int n = 3; rtx hreg[n]; @@ -13970,15 +13970,15 @@ avr_emit_cpymemhi (rtx *xop) int segment = avr_addrspace[as].segment; if (segment - && avr_n_flash > 1) - { - a_hi8 = GEN_INT (segment); - emit_move_insn (rampz_rtx, a_hi8 = copy_to_mode_reg (QImode, a_hi8)); - } + && avr_n_flash > 1) + { + a_hi8 = GEN_INT (segment); + emit_move_insn (rampz_rtx, a_hi8 = copy_to_mode_reg (QImode, a_hi8)); + } else if (!ADDR_SPACE_GENERIC_P (as)) - { - as = ADDR_SPACE_FLASH; - } + { + as = ADDR_SPACE_FLASH; + } addr1 = a_src; @@ -13989,35 +13989,35 @@ avr_emit_cpymemhi (rtx *xop) xas = GEN_INT (as); /* FIXME: Register allocator might come up with spill fails if it is left - on its own. Thus, we allocate the pointer registers by hand: - Z = source address - X = destination address */ + on its own. Thus, we allocate the pointer registers by hand: + Z = source address + X = destination address */ emit_move_insn (lpm_addr_reg_rtx, addr1); emit_move_insn (gen_rtx_REG (HImode, REG_X), a_dest); /* FIXME: Register allocator does a bad job and might spill address - register(s) inside the loop leading to additional move instruction - to/from stack which could clobber tmp_reg. Thus, do *not* emit - load and store as separate insns. Instead, we perform the copy - by means of one monolithic insn. */ + register(s) inside the loop leading to additional move instruction + to/from stack which could clobber tmp_reg. Thus, do *not* emit + load and store as separate insns. Instead, we perform the copy + by means of one monolithic insn. */ gcc_assert (TMP_REGNO == LPM_REGNO); if (as != ADDR_SPACE_MEMX) { /* Load instruction ([E]LPM or LD) is known at compile time: - Do the copy-loop inline. */ + Do the copy-loop inline. */ rtx (*fun) (rtx, rtx, rtx) - = QImode == loop_mode ? gen_cpymem_qi : gen_cpymem_hi; + = QImode == loop_mode ? gen_cpymem_qi : gen_cpymem_hi; insn = fun (xas, loop_reg, loop_reg); } else { rtx (*fun) (rtx, rtx) - = QImode == loop_mode ? gen_cpymemx_qi : gen_cpymemx_hi; + = QImode == loop_mode ? gen_cpymemx_qi : gen_cpymemx_hi; emit_move_insn (gen_rtx_REG (QImode, 23), a_hi8); @@ -14038,7 +14038,7 @@ avr_emit_cpymemhi (rtx *xop) X : Destination address */ -const char* +const char * avr_out_cpymem (rtx_insn *insn ATTRIBUTE_UNUSED, rtx *op, int *plen) { addr_space_t as = (addr_space_t) INTVAL (op[0]); @@ -14072,10 +14072,10 @@ avr_out_cpymem (rtx_insn *insn ATTRIBUTE_UNUSED, rtx *op, int *plen) case ADDR_SPACE_FLASH: if (AVR_HAVE_LPMX) - avr_asm_len ("lpm %2,Z+", xop, plen, 1); + avr_asm_len ("lpm %2,Z+", xop, plen, 1); else - avr_asm_len ("lpm" CR_TAB - "adiw r30,1", xop, plen, 2); + avr_asm_len ("lpm" CR_TAB + "adiw r30,1", xop, plen, 2); break; case ADDR_SPACE_FLASH1: @@ -14085,10 +14085,10 @@ avr_out_cpymem (rtx_insn *insn ATTRIBUTE_UNUSED, rtx *op, int *plen) case ADDR_SPACE_FLASH5: if (AVR_HAVE_ELPMX) - avr_asm_len ("elpm %2,Z+", xop, plen, 1); + avr_asm_len ("elpm %2,Z+", xop, plen, 1); else - avr_asm_len ("elpm" CR_TAB - "adiw r30,1", xop, plen, 2); + avr_asm_len ("elpm" CR_TAB + "adiw r30,1", xop, plen, 2); break; } @@ -14109,7 +14109,7 @@ avr_out_cpymem (rtx_insn *insn ATTRIBUTE_UNUSED, rtx *op, int *plen) else { avr_asm_len ("subi %A1,1" CR_TAB - "sbci %B1,0", xop, plen, 2); + "sbci %B1,0", xop, plen, 2); } /* Loop until zero */ @@ -14141,7 +14141,7 @@ avr_expand_delay_cycles (rtx operands0) loop_count = ((cycles - 9) / 6) + 1; cycles_used = ((loop_count - 1) * 6) + 9; emit_insn (gen_delay_cycles_4 (gen_int_mode (loop_count, SImode), - avr_mem_clobber())); + avr_mem_clobber())); cycles -= cycles_used; } @@ -14149,10 +14149,10 @@ avr_expand_delay_cycles (rtx operands0) { loop_count = ((cycles - 7) / 5) + 1; if (loop_count > 0xFFFFFF) - loop_count = 0xFFFFFF; + loop_count = 0xFFFFFF; cycles_used = ((loop_count - 1) * 5) + 7; emit_insn (gen_delay_cycles_3 (gen_int_mode (loop_count, SImode), - avr_mem_clobber())); + avr_mem_clobber())); cycles -= cycles_used; } @@ -14160,10 +14160,10 @@ avr_expand_delay_cycles (rtx operands0) { loop_count = ((cycles - 5) / 4) + 1; if (loop_count > 0xFFFF) - loop_count = 0xFFFF; + loop_count = 0xFFFF; cycles_used = ((loop_count - 1) * 4) + 5; emit_insn (gen_delay_cycles_2 (gen_int_mode (loop_count, HImode), - avr_mem_clobber())); + avr_mem_clobber())); cycles -= cycles_used; } @@ -14171,10 +14171,10 @@ avr_expand_delay_cycles (rtx operands0) { loop_count = cycles / 3; if (loop_count > 255) - loop_count = 255; + loop_count = 255; cycles_used = loop_count * 3; emit_insn (gen_delay_cycles_1 (gen_int_mode (loop_count, QImode), - avr_mem_clobber())); + avr_mem_clobber())); cycles -= cycles_used; } @@ -14243,17 +14243,17 @@ avr_map_metric (unsigned int a, int mode) unsigned ai = avr_map (a, i); if (mode == MAP_FIXED_0_7) - metric += ai == i; + metric += ai == i; else if (mode == MAP_NONFIXED_0_7) - metric += ai < 8 && ai != i; + metric += ai < 8 && ai != i; else if (mode == MAP_MASK_FIXED_0_7) - metric |= ((unsigned) (ai == i)) << i; + metric |= ((unsigned) (ai == i)) << i; else if (mode == MAP_PREIMAGE_0_7) - metric += ai < 8; + metric += ai < 8; else if (mode == MAP_MASK_PREIMAGE_F) - metric |= ((unsigned) (ai == 0xf)) << i; + metric |= ((unsigned) (ai == 0xf)) << i; else - gcc_unreachable(); + gcc_unreachable(); } return metric; @@ -14348,14 +14348,14 @@ avr_map_decompose (unsigned int f, const avr_map_op_t *g, bool val_const_p) int x = avr_map (f, i); if (x <= 7) - { - x = avr_map (ginv, x); + { + x = avr_map (ginv, x); - /* The bit is no element of the image of G: no avail (cost = -1) */ + /* The bit is no element of the image of G: no avail (cost = -1) */ - if (x > 7) - return f_ginv; - } + if (x > 7) + return f_ginv; + } f_ginv.map = (f_ginv.map << 4) + x; } @@ -14375,8 +14375,8 @@ avr_map_decompose (unsigned int f, const avr_map_op_t *g, bool val_const_p) rtx xop[4]; /* Get the cost of the insn by calling the output worker with some - fake values. Mimic effect of reloading xop[3]: Unused operands - are mapped to 0 and used operands are reloaded to xop[0]. */ + fake values. Mimic effect of reloading xop[3]: Unused operands + are mapped to 0 and used operands are reloaded to xop[0]. */ xop[0] = all_regs_rtx[24]; xop[1] = gen_int_mode (f_ginv.map, SImode); @@ -14416,28 +14416,28 @@ avr_move_bits (rtx *xop, unsigned int map, bool fixp_p, int *plen) for (int b = 0; b < 8; b++) for (int bit_dest = 0; bit_dest < 8; bit_dest++) { - int bit_src = avr_map (map, bit_dest); + int bit_src = avr_map (map, bit_dest); - if (b != bit_src - || bit_src >= 8 - /* Same position: No need to copy as requested by FIXP_P. */ - || (bit_dest == bit_src && !fixp_p)) - continue; + if (b != bit_src + || bit_src >= 8 + /* Same position: No need to copy as requested by FIXP_P. */ + || (bit_dest == bit_src && !fixp_p)) + continue; - if (t_bit_src != bit_src) - { - /* Source bit is not yet in T: Store it to T. */ + if (t_bit_src != bit_src) + { + /* Source bit is not yet in T: Store it to T. */ - t_bit_src = bit_src; + t_bit_src = bit_src; - xop[3] = GEN_INT (bit_src); - avr_asm_len ("bst %T1%T3", xop, plen, 1); - } + xop[3] = GEN_INT (bit_src); + avr_asm_len ("bst %T1%T3", xop, plen, 1); + } - /* Load destination bit with T. */ + /* Load destination bit with T. */ - xop[3] = GEN_INT (bit_dest); - avr_asm_len ("bld %T0%T3", xop, plen, 1); + xop[3] = GEN_INT (bit_dest); + avr_asm_len ("bld %T0%T3", xop, plen, 1); } } @@ -14447,14 +14447,14 @@ avr_move_bits (rtx *xop, unsigned int map, bool fixp_p, int *plen) OP[0]: Result OP[1]: The mapping composed of nibbles. If nibble no. N is - 0: Bit N of result is copied from bit OP[2].0 - ... ... - 7: Bit N of result is copied from bit OP[2].7 - 0xf: Bit N of result is copied from bit OP[3].N + 0: Bit N of result is copied from bit OP[2].0 + ... ... + 7: Bit N of result is copied from bit OP[2].7 + 0xf: Bit N of result is copied from bit OP[3].N OP[2]: Bits to be inserted OP[3]: Target value */ -const char* +const char * avr_out_insert_bits (rtx *op, int *plen) { unsigned int map = UINTVAL (op[1]) & GET_MODE_MASK (SImode); @@ -14496,30 +14496,30 @@ avr_out_insert_bits (rtx *op, int *plen) gcc_assert (REG_P (xop[2])); /* Get the code size of the bit insertions; once with all bits - moved and once with fixed points omitted. */ + moved and once with fixed points omitted. */ avr_move_bits (xop, map, true, &n_fix); avr_move_bits (xop, map, false, &n_nofix); if (fixp_p && n_fix - n_nofix > 3) - { - xop[3] = gen_int_mode (~mask_fixed, QImode); + { + xop[3] = gen_int_mode (~mask_fixed, QImode); - avr_asm_len ("eor %0,%1" CR_TAB - "andi %0,%3" CR_TAB - "eor %0,%1", xop, plen, 3); - fixp_p = false; - } + avr_asm_len ("eor %0,%1" CR_TAB + "andi %0,%3" CR_TAB + "eor %0,%1", xop, plen, 3); + fixp_p = false; + } } else { /* XOP[2] is unused */ if (fixp_p && mask_fixed) - { - avr_asm_len ("mov %0,%1", xop, plen, 1); - fixp_p = false; - } + { + avr_asm_len ("mov %0,%1", xop, plen, 1); + fixp_p = false; + } } /* Move/insert remaining bits. */ @@ -14597,47 +14597,47 @@ avr_init_builtins (void) = build_function_type_list (void_type_node, NULL_TREE); tree uchar_ftype_uchar = build_function_type_list (unsigned_char_type_node, - unsigned_char_type_node, - NULL_TREE); + unsigned_char_type_node, + NULL_TREE); tree uint_ftype_uchar_uchar = build_function_type_list (unsigned_type_node, - unsigned_char_type_node, - unsigned_char_type_node, - NULL_TREE); + unsigned_char_type_node, + unsigned_char_type_node, + NULL_TREE); tree int_ftype_char_char = build_function_type_list (integer_type_node, - char_type_node, - char_type_node, - NULL_TREE); + char_type_node, + char_type_node, + NULL_TREE); tree int_ftype_char_uchar = build_function_type_list (integer_type_node, - char_type_node, - unsigned_char_type_node, - NULL_TREE); + char_type_node, + unsigned_char_type_node, + NULL_TREE); tree void_ftype_ulong = build_function_type_list (void_type_node, - long_unsigned_type_node, - NULL_TREE); + long_unsigned_type_node, + NULL_TREE); tree uchar_ftype_ulong_uchar_uchar = build_function_type_list (unsigned_char_type_node, - long_unsigned_type_node, - unsigned_char_type_node, - unsigned_char_type_node, - NULL_TREE); + long_unsigned_type_node, + unsigned_char_type_node, + unsigned_char_type_node, + NULL_TREE); tree const_memx_void_node = build_qualified_type (void_type_node, - TYPE_QUAL_CONST - | ENCODE_QUAL_ADDR_SPACE (ADDR_SPACE_MEMX)); + TYPE_QUAL_CONST + | ENCODE_QUAL_ADDR_SPACE (ADDR_SPACE_MEMX)); tree const_memx_ptr_type_node = build_pointer_type_for_mode (const_memx_void_node, PSImode, false); tree char_ftype_const_memx_ptr = build_function_type_list (char_type_node, - const_memx_ptr_type_node, - NULL); + const_memx_ptr_type_node, + NULL); #define ITYP(T) \ lang_hooks.types.type_for_size (TYPE_PRECISION (T), TYPE_UNSIGNED (T)) @@ -14755,12 +14755,12 @@ avr_init_builtins (void) { \ int id = AVR_BUILTIN_ ## NAME; \ const char *Name = "__builtin_avr_" #NAME; \ - char *name = (char*) alloca (1 + strlen (Name)); \ + char *name = (char *) alloca (1 + strlen (Name)); \ \ gcc_assert (id < AVR_BUILTIN_COUNT); \ avr_bdesc[id].fndecl \ = add_builtin_function (avr_tolower (name, Name), TYPE, id, \ - BUILT_IN_MD, LIBNAME, NULL_TREE); \ + BUILT_IN_MD, LIBNAME, NULL_TREE); \ } #include "builtins.def" #undef DEF_BUILTIN @@ -14796,18 +14796,18 @@ avr_default_expand_builtin (enum insn_code icode, tree exp, rtx target) machine_mode mode = insn_data[icode].operand[n + 1].mode; if ((opmode == SImode || opmode == VOIDmode) && mode == HImode) - { - opmode = HImode; - op = gen_lowpart (HImode, op); - } + { + opmode = HImode; + op = gen_lowpart (HImode, op); + } /* In case the insn wants input operands in modes different from - the result, abort. */ + the result, abort. */ gcc_assert (opmode == mode || opmode == VOIDmode); if (!insn_data[icode].operand[n + 1].predicate (op, mode)) - op = copy_to_mode_reg (mode, op); + op = copy_to_mode_reg (mode, op); xop[n] = op; } @@ -14840,9 +14840,9 @@ avr_default_expand_builtin (enum insn_code icode, tree exp, rtx target) static rtx avr_expand_builtin (tree exp, rtx target, - rtx subtarget ATTRIBUTE_UNUSED, - machine_mode mode ATTRIBUTE_UNUSED, - int ignore) + rtx subtarget ATTRIBUTE_UNUSED, + machine_mode mode ATTRIBUTE_UNUSED, + int ignore) { tree fndecl = TREE_OPERAND (CALL_EXPR_FN (exp), 0); const char *bname = IDENTIFIER_POINTER (DECL_NAME (fndecl)); @@ -14861,43 +14861,43 @@ avr_expand_builtin (tree exp, rtx target, case AVR_BUILTIN_DELAY_CYCLES: { - arg0 = CALL_EXPR_ARG (exp, 0); - op0 = expand_expr (arg0, NULL_RTX, VOIDmode, EXPAND_NORMAL); + arg0 = CALL_EXPR_ARG (exp, 0); + op0 = expand_expr (arg0, NULL_RTX, VOIDmode, EXPAND_NORMAL); - if (!CONST_INT_P (op0)) - error ("%s expects a compile time integer constant", bname); - else - avr_expand_delay_cycles (op0); + if (!CONST_INT_P (op0)) + error ("%s expects a compile time integer constant", bname); + else + avr_expand_delay_cycles (op0); - return NULL_RTX; + return NULL_RTX; } case AVR_BUILTIN_NOPS: { - arg0 = CALL_EXPR_ARG (exp, 0); - op0 = expand_expr (arg0, NULL_RTX, VOIDmode, EXPAND_NORMAL); + arg0 = CALL_EXPR_ARG (exp, 0); + op0 = expand_expr (arg0, NULL_RTX, VOIDmode, EXPAND_NORMAL); - if (!CONST_INT_P (op0)) - error ("%s expects a compile time integer constant", bname); - else - avr_expand_nops (op0); + if (!CONST_INT_P (op0)) + error ("%s expects a compile time integer constant", bname); + else + avr_expand_nops (op0); - return NULL_RTX; + return NULL_RTX; } case AVR_BUILTIN_INSERT_BITS: { - arg0 = CALL_EXPR_ARG (exp, 0); - op0 = expand_expr (arg0, NULL_RTX, VOIDmode, EXPAND_NORMAL); + arg0 = CALL_EXPR_ARG (exp, 0); + op0 = expand_expr (arg0, NULL_RTX, VOIDmode, EXPAND_NORMAL); - if (!CONST_INT_P (op0)) - { - error ("%s expects a compile time long integer constant" - " as first argument", bname); - return target; - } + if (!CONST_INT_P (op0)) + { + error ("%s expects a compile time long integer constant" + " as first argument", bname); + return target; + } - break; + break; } case AVR_BUILTIN_ROUNDHR: case AVR_BUILTIN_ROUNDUHR: @@ -14911,33 +14911,33 @@ avr_expand_builtin (tree exp, rtx target, case AVR_BUILTIN_ROUNDLLK: case AVR_BUILTIN_ROUNDULLK: /* Warn about odd rounding. Rounding points >= FBIT will have - no effect. */ + no effect. */ if (TREE_CODE (CALL_EXPR_ARG (exp, 1)) != INTEGER_CST) - break; + break; int rbit = (int) TREE_INT_CST_LOW (CALL_EXPR_ARG (exp, 1)); if (rbit >= (int) GET_MODE_FBIT (mode)) - { - warning (OPT_Wextra, "rounding to %d bits has no effect for " - "fixed-point value with %d fractional bits", - rbit, GET_MODE_FBIT (mode)); - - return expand_expr (CALL_EXPR_ARG (exp, 0), NULL_RTX, mode, - EXPAND_NORMAL); - } + { + warning (OPT_Wextra, "rounding to %d bits has no effect for " + "fixed-point value with %d fractional bits", + rbit, GET_MODE_FBIT (mode)); + + return expand_expr (CALL_EXPR_ARG (exp, 0), NULL_RTX, mode, + EXPAND_NORMAL); + } else if (rbit <= - (int) GET_MODE_IBIT (mode)) - { - warning (0, "rounding result will always be 0"); - return CONST0_RTX (mode); - } + { + warning (0, "rounding result will always be 0"); + return CONST0_RTX (mode); + } /* The rounding points RP satisfies now: -IBIT < RP < FBIT. - TR 18037 only specifies results for RP > 0. However, the - remaining cases of -IBIT < RP <= 0 can easily be supported - without any additional overhead. */ + TR 18037 only specifies results for RP > 0. However, the + remaining cases of -IBIT < RP <= 0 can easily be supported + without any additional overhead. */ break; /* round */ } @@ -14996,7 +14996,7 @@ avr_fold_absfx (tree tval) static tree avr_fold_builtin (tree fndecl, int n_args ATTRIBUTE_UNUSED, tree *arg, - bool ignore ATTRIBUTE_UNUSED) + bool ignore ATTRIBUTE_UNUSED) { unsigned int fcode = DECL_MD_FUNCTION_CODE (fndecl); tree val_type = TREE_TYPE (TREE_TYPE (fndecl)); @@ -15011,8 +15011,8 @@ avr_fold_builtin (tree fndecl, int n_args ATTRIBUTE_UNUSED, tree *arg, case AVR_BUILTIN_SWAP: { - return fold_build2 (LROTATE_EXPR, val_type, arg[0], - build_int_cst (val_type, 4)); + return fold_build2 (LROTATE_EXPR, val_type, arg[0], + build_int_cst (val_type, 4)); } case AVR_BUILTIN_ABSHR: @@ -15049,139 +15049,139 @@ avr_fold_builtin (tree fndecl, int n_args ATTRIBUTE_UNUSED, tree *arg, case AVR_BUILTIN_BITSULLK: case AVR_BUILTIN_ULLKBITS: gcc_assert (TYPE_PRECISION (val_type) - == TYPE_PRECISION (TREE_TYPE (arg[0]))); + == TYPE_PRECISION (TREE_TYPE (arg[0]))); return build1 (VIEW_CONVERT_EXPR, val_type, arg[0]); case AVR_BUILTIN_INSERT_BITS: { - tree tbits = arg[1]; - tree tval = arg[2]; - tree tmap; - tree map_type = TREE_VALUE (TYPE_ARG_TYPES (TREE_TYPE (fndecl))); - unsigned int map; - bool changed = false; - avr_map_op_t best_g; - - if (TREE_CODE (arg[0]) != INTEGER_CST) - { - /* No constant as first argument: Don't fold this and run into - error in avr_expand_builtin. */ - - break; - } - - tmap = wide_int_to_tree (map_type, wi::to_wide (arg[0])); - map = TREE_INT_CST_LOW (tmap); - - if (TREE_CODE (tval) != INTEGER_CST + tree tbits = arg[1]; + tree tval = arg[2]; + tree tmap; + tree map_type = TREE_VALUE (TYPE_ARG_TYPES (TREE_TYPE (fndecl))); + unsigned int map; + bool changed = false; + avr_map_op_t best_g; + + if (TREE_CODE (arg[0]) != INTEGER_CST) + { + /* No constant as first argument: Don't fold this and run into + error in avr_expand_builtin. */ + + break; + } + + tmap = wide_int_to_tree (map_type, wi::to_wide (arg[0])); + map = TREE_INT_CST_LOW (tmap); + + if (TREE_CODE (tval) != INTEGER_CST && avr_map_metric (map, MAP_MASK_PREIMAGE_F) == 0) - { - /* There are no F in the map, i.e. 3rd operand is unused. - Replace that argument with some constant to render - respective input unused. */ + { + /* There are no F in the map, i.e. 3rd operand is unused. + Replace that argument with some constant to render + respective input unused. */ - tval = build_int_cst (val_type, 0); - changed = true; - } + tval = build_int_cst (val_type, 0); + changed = true; + } - if (TREE_CODE (tbits) != INTEGER_CST + if (TREE_CODE (tbits) != INTEGER_CST && avr_map_metric (map, MAP_PREIMAGE_0_7) == 0) - { - /* Similar for the bits to be inserted. If they are unused, - we can just as well pass 0. */ + { + /* Similar for the bits to be inserted. If they are unused, + we can just as well pass 0. */ - tbits = build_int_cst (val_type, 0); - } + tbits = build_int_cst (val_type, 0); + } - if (TREE_CODE (tbits) == INTEGER_CST) - { - /* Inserting bits known at compile time is easy and can be - performed by AND and OR with appropriate masks. */ + if (TREE_CODE (tbits) == INTEGER_CST) + { + /* Inserting bits known at compile time is easy and can be + performed by AND and OR with appropriate masks. */ - int bits = TREE_INT_CST_LOW (tbits); - int mask_ior = 0, mask_and = 0xff; + int bits = TREE_INT_CST_LOW (tbits); + int mask_ior = 0, mask_and = 0xff; - for (size_t i = 0; i < 8; i++) - { - int mi = avr_map (map, i); + for (size_t i = 0; i < 8; i++) + { + int mi = avr_map (map, i); - if (mi < 8) - { - if (bits & (1 << mi)) mask_ior |= (1 << i); - else mask_and &= ~(1 << i); - } - } + if (mi < 8) + { + if (bits & (1 << mi)) mask_ior |= (1 << i); + else mask_and &= ~(1 << i); + } + } - tval = fold_build2 (BIT_IOR_EXPR, val_type, tval, - build_int_cst (val_type, mask_ior)); - return fold_build2 (BIT_AND_EXPR, val_type, tval, - build_int_cst (val_type, mask_and)); - } + tval = fold_build2 (BIT_IOR_EXPR, val_type, tval, + build_int_cst (val_type, mask_ior)); + return fold_build2 (BIT_AND_EXPR, val_type, tval, + build_int_cst (val_type, mask_and)); + } - if (changed) - return build_call_expr (fndecl, 3, tmap, tbits, tval); + if (changed) + return build_call_expr (fndecl, 3, tmap, tbits, tval); - /* If bits don't change their position, we can use vanilla logic - to merge the two arguments... */ + /* If bits don't change their position, we can use vanilla logic + to merge the two arguments... */ - if (avr_map_metric (map, MAP_NONFIXED_0_7) == 0 - // ...except when we are copying just one bit. In that - // case, BLD/BST is better than XOR/AND/XOR, see PR90622. - && avr_map_metric (map, MAP_FIXED_0_7) != 1) - { - int mask_f = avr_map_metric (map, MAP_MASK_PREIMAGE_F); - tree tres, tmask = build_int_cst (val_type, mask_f ^ 0xff); + if (avr_map_metric (map, MAP_NONFIXED_0_7) == 0 + // ...except when we are copying just one bit. In that + // case, BLD/BST is better than XOR/AND/XOR, see PR90622. + && avr_map_metric (map, MAP_FIXED_0_7) != 1) + { + int mask_f = avr_map_metric (map, MAP_MASK_PREIMAGE_F); + tree tres, tmask = build_int_cst (val_type, mask_f ^ 0xff); - tres = fold_build2 (BIT_XOR_EXPR, val_type, tbits, tval); - tres = fold_build2 (BIT_AND_EXPR, val_type, tres, tmask); - return fold_build2 (BIT_XOR_EXPR, val_type, tres, tval); - } + tres = fold_build2 (BIT_XOR_EXPR, val_type, tbits, tval); + tres = fold_build2 (BIT_AND_EXPR, val_type, tres, tmask); + return fold_build2 (BIT_XOR_EXPR, val_type, tres, tval); + } - /* Try to decomposing map to reduce overall cost. */ + /* Try to decomposing map to reduce overall cost. */ - if (avr_log.builtin) - avr_edump ("\n%?: %x\n%?: ROL cost: ", map); + if (avr_log.builtin) + avr_edump ("\n%?: %x\n%?: ROL cost: ", map); - best_g = avr_map_op[0]; - best_g.cost = 1000; + best_g = avr_map_op[0]; + best_g.cost = 1000; - for (size_t i = 0; i < ARRAY_SIZE (avr_map_op); i++) - { - avr_map_op_t g - = avr_map_decompose (map, avr_map_op + i, - TREE_CODE (tval) == INTEGER_CST); + for (size_t i = 0; i < ARRAY_SIZE (avr_map_op); i++) + { + avr_map_op_t g + = avr_map_decompose (map, avr_map_op + i, + TREE_CODE (tval) == INTEGER_CST); - if (g.cost >= 0 && g.cost < best_g.cost) - best_g = g; - } + if (g.cost >= 0 && g.cost < best_g.cost) + best_g = g; + } - if (avr_log.builtin) - avr_edump ("\n"); + if (avr_log.builtin) + avr_edump ("\n"); - if (best_g.arg == 0) - /* No optimization found */ - break; + if (best_g.arg == 0) + /* No optimization found */ + break; - /* Apply operation G to the 2nd argument. */ + /* Apply operation G to the 2nd argument. */ - if (avr_log.builtin) - avr_edump ("%?: using OP(%s%d, %x) cost %d\n", - best_g.str, best_g.arg, best_g.map, best_g.cost); + if (avr_log.builtin) + avr_edump ("%?: using OP(%s%d, %x) cost %d\n", + best_g.str, best_g.arg, best_g.map, best_g.cost); - /* Do right-shifts arithmetically: They copy the MSB instead of - shifting in a non-usable value (0) as with logic right-shift. */ + /* Do right-shifts arithmetically: They copy the MSB instead of + shifting in a non-usable value (0) as with logic right-shift. */ - tbits = fold_convert (signed_char_type_node, tbits); - tbits = fold_build2 (best_g.code, signed_char_type_node, tbits, - build_int_cst (val_type, best_g.arg)); - tbits = fold_convert (val_type, tbits); + tbits = fold_convert (signed_char_type_node, tbits); + tbits = fold_build2 (best_g.code, signed_char_type_node, tbits, + build_int_cst (val_type, best_g.arg)); + tbits = fold_convert (val_type, tbits); - /* Use map o G^-1 instead of original map to undo the effect of G. */ + /* Use map o G^-1 instead of original map to undo the effect of G. */ - tmap = wide_int_to_tree (map_type, best_g.map); + tmap = wide_int_to_tree (map_type, best_g.map); - return build_call_expr (fndecl, 3, tmap, tbits, tval); + return build_call_expr (fndecl, 3, tmap, tbits, tval); } /* AVR_BUILTIN_INSERT_BITS */ } @@ -15194,10 +15194,10 @@ avr_fold_builtin (tree fndecl, int n_args ATTRIBUTE_UNUSED, tree *arg, static rtx_insn * avr_md_asm_adjust (vec &/*outputs*/, vec &/*inputs*/, - vec & /*input_modes*/, - vec &/*constraints*/, + vec & /*input_modes*/, + vec &/*constraints*/, vec &/*uses*/, - vec &clobbers, HARD_REG_SET &clobbered_regs, + vec &clobbers, HARD_REG_SET &clobbered_regs, location_t /*loc*/) { clobbers.safe_push (cc_reg_rtx); -- cgit v1.1 From 3ba5be16a2be3eaedf2870ca1e25cfe826945948 Mon Sep 17 00:00:00 2001 From: Patrick Palka Date: Thu, 1 Feb 2024 13:17:48 -0500 Subject: c++: ttp TEMPLATE_DECL equivalence [PR112737] Here during declaration matching we undesirably consider the two TT{42} CTAD expressions to be non-equivalent ultimately because for CTAD placeholder equivalence we compare the TEMPLATE_DECLs via pointer identity, and here the corresponding TEMPLATE_DECLs for TT are different since they're from different scopes. On the other hand, the corresponding TEMPLATE_TEMPLATE_PARMs are deemed equivalent according to cp_tree_equal (since they have the same position and template parameters). This turns out to be the root cause of some of the xtreme-header modules regressions. So this patch relaxes ttp CTAD placeholder equivalence accordingly, by comparing the TEMPLATE_TEMPLATE_PARM instead of the TEMPLATE_DECL. It turns out this issue also affects function template-id equivalence as with g in the second testcase, so it makes sense to relax TEMPLATE_DECL equivalence more generally in cp_tree_equal. In passing this patch improves ctp_hasher::hash for CTAD placeholders, so that they don't all get the same hash. PR c++/112737 gcc/cp/ChangeLog: * pt.cc (iterative_hash_template_arg) : Adjust hashing to match cp_tree_equal. (ctp_hasher::hash): Also hash CLASS_PLACEHOLDER_TEMPLATE. * tree.cc (cp_tree_equal) : Return true for ttp TEMPLATE_DECLs if their TEMPLATE_TEMPLATE_PARMs are equivalent. * typeck.cc (structural_comptypes) : Use cp_tree_equal to compare CLASS_PLACEHOLDER_TEMPLATE. gcc/testsuite/ChangeLog: * g++.dg/template/ttp42.C: New test. * g++.dg/template/ttp43.C: New test. Reviewed-by: Jason Merrill --- gcc/cp/pt.cc | 7 +++++++ gcc/cp/tree.cc | 6 +++++- gcc/cp/typeck.cc | 4 ++-- gcc/testsuite/g++.dg/template/ttp42.C | 14 ++++++++++++++ gcc/testsuite/g++.dg/template/ttp43.C | 17 +++++++++++++++++ 5 files changed, 45 insertions(+), 3 deletions(-) create mode 100644 gcc/testsuite/g++.dg/template/ttp42.C create mode 100644 gcc/testsuite/g++.dg/template/ttp43.C (limited to 'gcc') diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc index 5871cb6..16febb1 100644 --- a/gcc/cp/pt.cc +++ b/gcc/cp/pt.cc @@ -1816,6 +1816,11 @@ iterative_hash_template_arg (tree arg, hashval_t val) } return iterative_hash_template_arg (TREE_TYPE (arg), val); + case TEMPLATE_DECL: + if (DECL_TEMPLATE_TEMPLATE_PARM_P (arg)) + return iterative_hash_template_arg (TREE_TYPE (arg), val); + break; + case TARGET_EXPR: return iterative_hash_template_arg (TARGET_EXPR_INITIAL (arg), val); @@ -4499,6 +4504,8 @@ struct ctp_hasher : ggc_ptr_hash hashval_t val = iterative_hash_object (code, 0); val = iterative_hash_object (TEMPLATE_TYPE_LEVEL (t), val); val = iterative_hash_object (TEMPLATE_TYPE_IDX (t), val); + if (TREE_CODE (t) == TEMPLATE_TYPE_PARM) + val = iterative_hash_template_arg (CLASS_PLACEHOLDER_TEMPLATE (t), val); if (TREE_CODE (t) == BOUND_TEMPLATE_TEMPLATE_PARM) val = iterative_hash_template_arg (TYPE_TI_ARGS (t), val); --comparing_specializations; diff --git a/gcc/cp/tree.cc b/gcc/cp/tree.cc index 77f57e0..5c8c05d 100644 --- a/gcc/cp/tree.cc +++ b/gcc/cp/tree.cc @@ -4084,11 +4084,15 @@ cp_tree_equal (tree t1, tree t2) } return false; + case TEMPLATE_DECL: + if (DECL_TEMPLATE_TEMPLATE_PARM_P (t1) + && DECL_TEMPLATE_TEMPLATE_PARM_P (t2)) + return cp_tree_equal (TREE_TYPE (t1), TREE_TYPE (t2)); + /* Fall through. */ case VAR_DECL: case CONST_DECL: case FIELD_DECL: case FUNCTION_DECL: - case TEMPLATE_DECL: case IDENTIFIER_NODE: case SSA_NAME: case USING_DECL: diff --git a/gcc/cp/typeck.cc b/gcc/cp/typeck.cc index 4937022..132c55c 100644 --- a/gcc/cp/typeck.cc +++ b/gcc/cp/typeck.cc @@ -1573,8 +1573,8 @@ structural_comptypes (tree t1, tree t2, int strict) return false; /* If T1 and T2 don't represent the same class template deduction, they aren't equal. */ - if (CLASS_PLACEHOLDER_TEMPLATE (t1) - != CLASS_PLACEHOLDER_TEMPLATE (t2)) + if (!cp_tree_equal (CLASS_PLACEHOLDER_TEMPLATE (t1), + CLASS_PLACEHOLDER_TEMPLATE (t2))) return false; /* Constrained 'auto's are distinct from parms that don't have the same constraints. */ diff --git a/gcc/testsuite/g++.dg/template/ttp42.C b/gcc/testsuite/g++.dg/template/ttp42.C new file mode 100644 index 0000000..da08e85 --- /dev/null +++ b/gcc/testsuite/g++.dg/template/ttp42.C @@ -0,0 +1,14 @@ +// PR c++/112737 +// { dg-do compile { target c++17 } } + +template class TT> +decltype(TT{42}) f(); // #1 + +template class TT> +decltype(TT{42}) f(); // redeclaration of #1 + +template struct A { A(T); }; + +int main() { + f(); +} diff --git a/gcc/testsuite/g++.dg/template/ttp43.C b/gcc/testsuite/g++.dg/template/ttp43.C new file mode 100644 index 0000000..afafd32 --- /dev/null +++ b/gcc/testsuite/g++.dg/template/ttp43.C @@ -0,0 +1,17 @@ +// PR c++/112737 +// { dg-do compile { target c++11 } } + +template class, class T> +void g(T); + +template class TT, class T> +decltype(g(T{})) f(T); // #1 + +template class TT, class T> +decltype(g(T{})) f(T); // redeclaration of #1 + +template struct A; + +int main() { + f(0); +} -- cgit v1.1 From f26094751ebd8f8603a0e62a8f1aab6a99c932e9 Mon Sep 17 00:00:00 2001 From: John David Anglin Date: Thu, 1 Feb 2024 18:46:47 +0000 Subject: hppa: Fix bug in atomic_storedi_1 pattern The first alternative stores the floating-point status register in the destination. It should store zero. We need to copy %fr0 to another floating-point register to initialize it to zero. 2024-02-01 John David Anglin gcc/ChangeLog: * config/pa/pa.md (atomic_storedi_1): Fix bug in alternative 1. --- gcc/config/pa/pa.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'gcc') diff --git a/gcc/config/pa/pa.md b/gcc/config/pa/pa.md index 52ad0c3..aecdcc9 100644 --- a/gcc/config/pa/pa.md +++ b/gcc/config/pa/pa.md @@ -10723,13 +10723,13 @@ add,l %2,%3,%3\;bv,n %%r0(%3)" (define_insn "atomic_storedi_1" [(set (mem:DI (match_operand:SI 0 "register_operand" "r,r")) (match_operand:DI 1 "reg_or_0_operand" "M,r")) - (clobber (match_scratch:DI 2 "=X,f"))] + (clobber (match_scratch:DI 2 "=f,f"))] "!TARGET_64BIT && !TARGET_SOFT_FLOAT" "@ - {fstds|fstd} %%fr0,0(%0) + fcpy,dbl %%fr0,%2\n\t{fstds|fstd} %2,0(%0) {stws|stw} %1,-16(%%sp)\n\t{stws|stw} %R1,-12(%%sp)\n\t{fldds|fldd} -16(%%sp),%2\n\t{fstds|fstd} %2,0(%0)" [(set_attr "type" "move,move") - (set_attr "length" "4,16")]) + (set_attr "length" "8,16")]) ;; PA 2.0 hardware supports out-of-order execution of loads and stores, so ;; we need memory barriers to enforce program order for memory references -- cgit v1.1 From d71c7f107a4931c4c03729474d2397919b568817 Mon Sep 17 00:00:00 2001 From: John David Anglin Date: Thu, 1 Feb 2024 18:57:15 +0000 Subject: xfail gnat.dg/trampoline3.adb scan-assembler-not check on hppa*-*-* We still require an executable stack for trampolines on hppa*-*-*. 2024-02-01 John David Anglin gcc/testsuite/ChangeLog: * gnat.dg/trampoline3.adb: xfail scan-assembler-not check on hppa*-*-*. --- gcc/testsuite/gnat.dg/trampoline3.adb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'gcc') diff --git a/gcc/testsuite/gnat.dg/trampoline3.adb b/gcc/testsuite/gnat.dg/trampoline3.adb index 2805766..10b6e5d 100644 --- a/gcc/testsuite/gnat.dg/trampoline3.adb +++ b/gcc/testsuite/gnat.dg/trampoline3.adb @@ -19,4 +19,4 @@ begin I := P(0); end; --- { dg-final { scan-assembler-not "GNU-stack.*x" } } +-- { dg-final { scan-assembler-not "GNU-stack.*x" { xfail hppa*-*-* } } } -- cgit v1.1 From 44764984cf24e27cf7756cffd197283b9c62db8b Mon Sep 17 00:00:00 2001 From: Uros Bizjak Date: Thu, 1 Feb 2024 21:23:24 +0100 Subject: i386: Improve *cmp_doubleword splitter [PR113701] The fix for PR70321 introduced a splitter that split a doubleword comparison into a pair of XORs followed by an IOR to set the (zero) flags register. To help the reload, splitter forced SUBREG pieces of double-word input values to a pseudo, but this regressed gcc.target/i386/pr82580.c: int f0 (U x, U y) { return x == y; } from: xorq %rdx, %rdi xorq %rcx, %rsi xorl %eax, %eax orq %rsi, %rdi sete %al ret to: xchgq %rdi, %rsi movq %rdx, %r8 movq %rcx, %rax movq %rsi, %rdx movq %rdi, %rcx xorq %rax, %rcx xorq %r8, %rdx xorl %eax, %eax orq %rcx, %rdx sete %al ret To mitigate the regression, remove this legacy heuristic (workaround?). There have been many incremental changes and improvements to x86 TImode and register allocation, so this legacy workaround is not only no longer useful, but it actually hurts register allocation. The patched compiler now produces: xchgq %rdi, %rsi xorl %eax, %eax xorq %rsi, %rdx xorq %rdi, %rcx orq %rcx, %rdx sete %al ret PR target/113701 gcc/ChangeLog: * config/i386/i386.md (*cmp_doubleword): Do not force SUBREG pieces to pseudos. --- gcc/config/i386/i386.md | 4 ---- 1 file changed, 4 deletions(-) (limited to 'gcc') diff --git a/gcc/config/i386/i386.md b/gcc/config/i386/i386.md index bac0a6a..a82f2e4 100644 --- a/gcc/config/i386/i386.md +++ b/gcc/config/i386/i386.md @@ -1632,10 +1632,6 @@ (set (match_dup 4) (ior:DWIH (match_dup 4) (match_dup 5)))])] { split_double_mode (mode, &operands[0], 2, &operands[0], &operands[2]); - /* Placing the SUBREG pieces in pseudos helps reload. */ - for (int i = 0; i < 4; i++) - if (SUBREG_P (operands[i])) - operands[i] = force_reg (mode, operands[i]); operands[4] = gen_reg_rtx (mode); -- cgit v1.1 From 8efcdbf59bfed2b888db7def16c7641f26927260 Mon Sep 17 00:00:00 2001 From: Marek Polacek Date: Thu, 1 Feb 2024 16:11:43 -0500 Subject: c++: -Wdangling-reference tweak to unbreak aarch64 My recent -Wdangling-reference change to not warn on std::span-like classes unfortunately caused a new warning: extending reference_like_class_p also opens the door to new warnings since we use reference_like_class_p for checking the return type of the function: either it must be a reference or a reference_like_class_p. We can consider even non-templates as std::span-like to get rid of the warning here. gcc/cp/ChangeLog: * call.cc (reference_like_class_p): Consider even non-templates for std::span-like classes. gcc/ChangeLog: * doc/invoke.texi: Update -Wdangling-reference documentation. gcc/testsuite/ChangeLog: * g++.dg/warn/Wdangling-reference21.C: New test. --- gcc/cp/call.cc | 8 ++--- gcc/doc/invoke.texi | 2 +- gcc/testsuite/g++.dg/warn/Wdangling-reference21.C | 44 +++++++++++++++++++++++ 3 files changed, 48 insertions(+), 6 deletions(-) create mode 100644 gcc/testsuite/g++.dg/warn/Wdangling-reference21.C (limited to 'gcc') diff --git a/gcc/cp/call.cc b/gcc/cp/call.cc index 42cbd0d..1dac147 100644 --- a/gcc/cp/call.cc +++ b/gcc/cp/call.cc @@ -14082,8 +14082,8 @@ reference_like_class_p (tree ctype) return true; } - /* Avoid warning if CTYPE looks like std::span: it's a class template, - has a T* member, and a trivial destructor. For example, + /* Avoid warning if CTYPE looks like std::span: it has a T* member and + a trivial destructor. For example, template struct Span { @@ -14092,9 +14092,7 @@ reference_like_class_p (tree ctype) }; is considered std::span-like. */ - if (NON_UNION_CLASS_TYPE_P (ctype) - && CLASSTYPE_TEMPLATE_INSTANTIATION (ctype) - && TYPE_HAS_TRIVIAL_DESTRUCTOR (ctype)) + if (NON_UNION_CLASS_TYPE_P (ctype) && TYPE_HAS_TRIVIAL_DESTRUCTOR (ctype)) for (tree field = next_aggregate_field (TYPE_FIELDS (ctype)); field; field = next_aggregate_field (DECL_CHAIN (field))) if (TYPE_PTR_P (TREE_TYPE (field))) diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi index 14730c0..e9c691d 100644 --- a/gcc/doc/invoke.texi +++ b/gcc/doc/invoke.texi @@ -3929,7 +3929,7 @@ struct Span @{ @}; @end smallexample -as @code{std::span}-like; that is, the class is a non-union class template +as @code{std::span}-like; that is, the class is a non-union class that has a pointer data member and a trivial destructor. This warning is enabled by @option{-Wall}. diff --git a/gcc/testsuite/g++.dg/warn/Wdangling-reference21.C b/gcc/testsuite/g++.dg/warn/Wdangling-reference21.C new file mode 100644 index 0000000..e1b6e3d --- /dev/null +++ b/gcc/testsuite/g++.dg/warn/Wdangling-reference21.C @@ -0,0 +1,44 @@ +// { dg-do compile { target c++11 } } +// { dg-options "-Wdangling-reference" } +// Reduced from config/aarch64/aarch64-early-ra.cc. + +template struct array_slice { + using iterator = T *; + iterator begin(); + iterator end(); + iterator m_base; +}; + +struct allocno_group_info { }; + +char recog_data_2; +int record_constraints_op; +struct early_ra { + using operand_mask = int; + struct allocno_info { + int is_earlyclobbered; + }; + struct allocno_subgroup { + array_slice allocnos(); + allocno_group_info *group; + }; + allocno_subgroup get_allocno_subgroup(int); + void record_constraints(); +}; +void early_ra::record_constraints() { + operand_mask earlyclobber_operands, matched_operands, unmatched_operands, + matches_operands, op_mask = operand_mask(); + auto record_operand = [&](int, int) { + operand_mask overlaps; + matches_operands |= overlaps; + }; + for (int opno = 0; recog_data_2; ++opno) { + operand_mask op_mask = earlyclobber_operands |= op_mask; + if (0) + record_operand(1, 0); + } + if (op_mask || (matched_operands & unmatched_operands && 0)) + for (auto &allocno : get_allocno_subgroup(record_constraints_op).allocnos()) + allocno.is_earlyclobbered = true; +} + -- cgit v1.1 From e2554540460add5357aeadbe99fb709aebbb415a Mon Sep 17 00:00:00 2001 From: GCC Administrator Date: Fri, 2 Feb 2024 00:18:18 +0000 Subject: Daily bump. --- gcc/ChangeLog | 62 +++++++++++++++++++++++++++++++++++++++++++++++++ gcc/DATESTAMP | 2 +- gcc/c-family/ChangeLog | 7 ++++++ gcc/cp/ChangeLog | 23 ++++++++++++++++++ gcc/testsuite/ChangeLog | 57 +++++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 150 insertions(+), 1 deletion(-) (limited to 'gcc') diff --git a/gcc/ChangeLog b/gcc/ChangeLog index ec3bfe1..c63ad2f 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,65 @@ +2024-02-01 Marek Polacek + + * doc/invoke.texi: Update -Wdangling-reference documentation. + +2024-02-01 Uros Bizjak + + PR target/113701 + * config/i386/i386.md (*cmp_doubleword): + Do not force SUBREG pieces to pseudos. + +2024-02-01 John David Anglin + + * config/pa/pa.md (atomic_storedi_1): Fix bug in + alternative 1. + +2024-02-01 Georg-Johann Lay + + * config/avr/avr.cc: Tabify. + +2024-02-01 Richard Ball + + PR tree-optimization/111268 + * tree-vect-slp.cc (vectorizable_slp_permutation_1): + Add variable-length check for vector input arguments + to a function. + +2024-02-01 Thomas Schwinge + + * config/gcn/gcn.cc (gcn_hsa_declare_function_name): Don't + hard-code number of SGPR/VGPR/AVGPR registers. + * config/gcn/gcn.h: Add a 'STATIC_ASSERT's for number of + SGPR/VGPR/AVGPR registers. + +2024-02-01 Monk Chiang + + * config/riscv/riscv.md: Add "fcvt_i2f", "fcvt_f2i" type + attribute, and include sifive-p600.md. + * config/riscv/generic-ooo.md: Update type attribute. + * config/riscv/generic.md: Update type attribute. + * config/riscv/sifive-7.md: Update type attribute. + * config/riscv/sifive-p600.md: New file. + * config/riscv/riscv-cores.def (RISCV_TUNE): Add parameter. + * config/riscv/riscv-opts.h (enum riscv_microarchitecture_type): + Add sifive_p600. + * config/riscv/riscv.cc (sifive_p600_tune_info): New. + * config/riscv/riscv.h (TARGET_SFB_ALU): Update. + * doc/invoke.texi (RISC-V Options): Add sifive-p600-series + +2024-02-01 Monk Chiang + + * common/config/riscv/riscv-common.cc: Add Za64rs, Za128rs, + Ziccif, Ziccrse, Ziccamoa, Zicclsm, Zic64b items. + * config/riscv/riscv.opt: New macro for 7 new unprivileged + extensions. + * doc/invoke.texi (RISC-V Options): Add Za64rs, Za128rs, + Ziccif, Ziccrse, Ziccamoa, Zicclsm, Zic64b extensions. + +2024-02-01 Rainer Orth + + * config/sol2.h (LIBASAN_EARLY_SPEC): Add -z now unless + -static-libasan. Add missing whitespace. + 2024-02-01 Thomas Schwinge * config/gcn/gcn.md (FIRST_SGPR_REG, LAST_SGPR_REG) diff --git a/gcc/DATESTAMP b/gcc/DATESTAMP index aa4ca8e..656861b 100644 --- a/gcc/DATESTAMP +++ b/gcc/DATESTAMP @@ -1 +1 @@ -20240201 +20240202 diff --git a/gcc/c-family/ChangeLog b/gcc/c-family/ChangeLog index 9bce014..6741eb5 100644 --- a/gcc/c-family/ChangeLog +++ b/gcc/c-family/ChangeLog @@ -1,3 +1,10 @@ +2024-02-01 Lewis Hyatt + + PR preprocessor/105608 + * c-pch.cc (c_common_read_pch): Adjust line map so that libcpp + assigns a location to restored macros which is the same location + that triggered the PCH include. + 2024-01-31 Marek Polacek * c-opts.cc (c_common_post_options): Add an inform saying that diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index 4198641..bcc9c3a 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,3 +1,26 @@ +2024-02-01 Marek Polacek + + * call.cc (reference_like_class_p): Consider even non-templates for + std::span-like classes. + +2024-02-01 Patrick Palka + + PR c++/112737 + * pt.cc (iterative_hash_template_arg) : + Adjust hashing to match cp_tree_equal. + (ctp_hasher::hash): Also hash CLASS_PLACEHOLDER_TEMPLATE. + * tree.cc (cp_tree_equal) : Return true + for ttp TEMPLATE_DECLs if their TEMPLATE_TEMPLATE_PARMs are + equivalent. + * typeck.cc (structural_comptypes) : + Use cp_tree_equal to compare CLASS_PLACEHOLDER_TEMPLATE. + +2024-02-01 Marek Polacek + + PR c++/112437 + * typeck.cc (treat_lvalue_as_rvalue_p): Bail out on sk_namespace in + the move on throw of parms loop. + 2024-01-30 Marek Polacek PR c++/110358 diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index 5d40133..8ab0cca 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,60 @@ +2024-02-01 Marek Polacek + + * g++.dg/warn/Wdangling-reference21.C: New test. + +2024-02-01 John David Anglin + + * gnat.dg/trampoline3.adb: xfail scan-assembler-not + check on hppa*-*-*. + +2024-02-01 Patrick Palka + + PR c++/112737 + * g++.dg/template/ttp42.C: New test. + * g++.dg/template/ttp43.C: New test. + +2024-02-01 Marek Polacek + + PR c++/112437 + * g++.dg/cpp2a/concepts-throw1.C: New test. + * g++.dg/eh/throw4.C: New test. + +2024-02-01 Monk Chiang + + * gcc.target/riscv/za-ext.c: New test. + * gcc.target/riscv/zi-ext.c: New test. + +2024-02-01 Rainer Orth + + * gcc.target/i386/pr38534-1.c: Add -fomit-frame-pointer to + dg-options. + * gcc.target/i386/pr38534-2.c: Likewise. + * gcc.target/i386/pr38534-3.c: Likewise. + * gcc.target/i386/pr38534-4.c: Likewise. + +2024-02-01 Rainer Orth + + * gcc.target/i386/no-callee-saved-1.c: Add -fomit-frame-pointer to + dg-options. + * gcc.target/i386/no-callee-saved-2.c: Likewise. + +2024-02-01 Rainer Orth + + * gcc.target/i386/avx512vl-stv-rotatedi-1.c: Add -mstv + -mno-stackrealign to dg-options. + +2024-02-01 Rainer Orth + + * gcc.target/i386/pr70321.c: Add -fomit-frame-pointer to + dg-options. + +2024-02-01 Rainer Orth + + * g++.dg/ext/attr-section2.C (scan-assembler): Quote dots. Allow + for double-quoted section name. + * g++.dg/ext/attr-section2a.C: Likewise. + * g++.dg/ext/attr-section2b.C: Likewise. + 2024-02-01 Richard Biener PR tree-optimization/113693 -- cgit v1.1 From 3499793d04886856a416898bac82ede6c4b5c79e Mon Sep 17 00:00:00 2001 From: Lulu Cheng Date: Tue, 30 Jan 2024 15:02:32 +0800 Subject: LoongArch: Modify the address calculation logic for obtaining array element values through fp. Modify address calculation logic from (((a x C) + fp) + offset) to ((fp + offset) + a x C). Thereby modifying the register dependencies and optimizing the code. The value of C is 2 4 or 8. The following is the assembly code before and after a loop modification in spec2006 401.bzip: old | new 735 .L71: | 735 .L71: 736 slli.d $r12,$r15,2 | 736 slli.d $r12,$r15,2 737 ldx.w $r13,$r22,$r12 | 737 ldx.w $r13,$r22,$r12 738 addi.d $r15,$r15,-1 | 738 addi.d $r15,$r15,-1 739 slli.w $r16,$r15,0 | 739 slli.w $r16,$r15,0 740 addi.w $r13,$r13,-1 | 740 addi.w $r13,$r13,-1 741 slti $r14,$r13,0 | 741 slti $r14,$r13,0 742 add.w $r12,$r26,$r13 | 742 add.w $r12,$r26,$r13 743 maskeqz $r12,$r12,$r14 | 743 maskeqz $r12,$r12,$r14 744 masknez $r14,$r13,$r14 | 744 masknez $r14,$r13,$r14 745 or $r12,$r12,$r14 | 745 or $r12,$r12,$r14 746 ldx.bu $r14,$r30,$r12 | 746 ldx.bu $r14,$r30,$r12 747 lu12i.w $r13,4096>>12 | 747 alsl.d $r14,$r14,$r18,2 748 ori $r13,$r13,432 | 748 ldptr.w $r13,$r14,0 749 add.d $r13,$r13,$r3 | 749 addi.w $r17,$r13,-1 750 alsl.d $r14,$r14,$r13,2 | 750 stptr.w $r17,$r14,0 751 ldptr.w $r13,$r14,-1968 | 751 slli.d $r13,$r13,2 752 addi.w $r17,$r13,-1 | 752 stx.w $r12,$r22,$r13 753 st.w $r17,$r14,-1968 | 753 ldptr.w $r12,$r19,0 754 slli.d $r13,$r13,2 | 754 blt $r12,$r16,.L71 755 stx.w $r12,$r22,$r13 | 755 .align 4 756 ldptr.w $r12,$r18,-2048 | 756 757 blt $r12,$r16,.L71 | 757 758 .align 4 | 758 This patch is ported from riscv's commit r14-3111. gcc/ChangeLog: * config/loongarch/loongarch.cc (mem_shadd_or_shadd_rtx_p): New function. (loongarch_legitimize_address): Add logical transformation code. --- gcc/config/loongarch/loongarch.cc | 43 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 43 insertions(+) (limited to 'gcc') diff --git a/gcc/config/loongarch/loongarch.cc b/gcc/config/loongarch/loongarch.cc index b494040..b8f6f66 100644 --- a/gcc/config/loongarch/loongarch.cc +++ b/gcc/config/loongarch/loongarch.cc @@ -3219,6 +3219,22 @@ loongarch_split_symbol (rtx temp, rtx addr, machine_mode mode, rtx *low_out) return true; } +/* Helper loongarch_legitimize_address. Given X, return true if it + is a left shift by 1, 2 or 3 positions or a multiply by 2, 4 or 8. + + This respectively represent canonical shift-add rtxs or scaled + memory addresses. */ +static bool +mem_shadd_or_shadd_rtx_p (rtx x) +{ + return ((GET_CODE (x) == ASHIFT + || GET_CODE (x) == MULT) + && CONST_INT_P (XEXP (x, 1)) + && ((GET_CODE (x) == ASHIFT && IN_RANGE (INTVAL (XEXP (x, 1)), 1, 3)) + || (GET_CODE (x) == MULT + && IN_RANGE (exact_log2 (INTVAL (XEXP (x, 1))), 1, 3)))); +} + /* This function is used to implement LEGITIMIZE_ADDRESS. If X can be legitimized in a way that the generic machinery might not expect, return a new address, otherwise return NULL. MODE is the mode of @@ -3242,6 +3258,33 @@ loongarch_legitimize_address (rtx x, rtx oldx ATTRIBUTE_UNUSED, loongarch_split_plus (x, &base, &offset); if (offset != 0) { + /* Handle (plus (plus (mult (a) (mem_shadd_constant)) (fp)) (C)) case. */ + if (GET_CODE (base) == PLUS && mem_shadd_or_shadd_rtx_p (XEXP (base, 0)) + && IMM12_OPERAND (offset)) + { + rtx index = XEXP (base, 0); + rtx fp = XEXP (base, 1); + + if (REG_P (fp) && REGNO (fp) == VIRTUAL_STACK_VARS_REGNUM) + { + /* If we were given a MULT, we must fix the constant + as we're going to create the ASHIFT form. */ + int shift_val = INTVAL (XEXP (index, 1)); + if (GET_CODE (index) == MULT) + shift_val = exact_log2 (shift_val); + + rtx reg1 = gen_reg_rtx (Pmode); + rtx reg3 = gen_reg_rtx (Pmode); + loongarch_emit_binary (PLUS, reg1, fp, GEN_INT (offset)); + loongarch_emit_binary (PLUS, reg3, + gen_rtx_ASHIFT (Pmode, XEXP (index, 0), + GEN_INT (shift_val)), + reg1); + + return reg3; + } + } + if (!loongarch_valid_base_register_p (base, mode, false)) base = copy_to_mode_reg (Pmode, base); addr = loongarch_add_offset (NULL, base, offset); -- cgit v1.1 From 252f7705a52240a0a2949842c8e33a0db2ea613b Mon Sep 17 00:00:00 2001 From: Lulu Cheng Date: Thu, 25 Jan 2024 14:44:39 +0800 Subject: LoongArch: Merge template got_load_tls_{ld/gd/le/ie}. gcc/ChangeLog: * config/loongarch/loongarch.cc (loongarch_load_tls): Load all types of tls symbols through one function. (loongarch_got_load_tls_gd): Delete. (loongarch_got_load_tls_ld): Delete. (loongarch_got_load_tls_ie): Delete. (loongarch_got_load_tls_le): Delete. (loongarch_call_tls_get_addr): Modify the called function name. (loongarch_legitimize_tls_address): Likewise. * config/loongarch/loongarch.md (@got_load_tls_gd): Delete. (@load_tls): New template. (@got_load_tls_ld): Delete. (@got_load_tls_le): Delete. (@got_load_tls_ie): Delete. --- gcc/config/loongarch/loongarch.cc | 47 ++++++------------------------- gcc/config/loongarch/loongarch.md | 59 +++++++++++++++------------------------ 2 files changed, 30 insertions(+), 76 deletions(-) (limited to 'gcc') diff --git a/gcc/config/loongarch/loongarch.cc b/gcc/config/loongarch/loongarch.cc index b8f6f66..986dc1d 100644 --- a/gcc/config/loongarch/loongarch.cc +++ b/gcc/config/loongarch/loongarch.cc @@ -2736,36 +2736,12 @@ loongarch_add_offset (rtx temp, rtx reg, HOST_WIDE_INT offset) /* The __tls_get_attr symbol. */ static GTY (()) rtx loongarch_tls_symbol; -/* Load an entry from the GOT for a TLS GD access. */ +/* Load an entry for a TLS access. */ static rtx -loongarch_got_load_tls_gd (rtx dest, rtx sym) +loongarch_load_tls (rtx dest, rtx sym) { - return gen_got_load_tls_gd (Pmode, dest, sym); -} - -/* Load an entry from the GOT for a TLS LD access. */ - -static rtx -loongarch_got_load_tls_ld (rtx dest, rtx sym) -{ - return gen_got_load_tls_ld (Pmode, dest, sym); -} - -/* Load an entry from the GOT for a TLS IE access. */ - -static rtx -loongarch_got_load_tls_ie (rtx dest, rtx sym) -{ - return gen_got_load_tls_ie (Pmode, dest, sym); -} - -/* Add in the thread pointer for a TLS LE access. */ - -static rtx -loongarch_got_load_tls_le (rtx dest, rtx sym) -{ - return gen_got_load_tls_le (Pmode, dest, sym); + return gen_load_tls (Pmode, dest, sym); } /* Return an instruction sequence that calls __tls_get_addr. SYM is @@ -2809,14 +2785,7 @@ loongarch_call_tls_get_addr (rtx sym, enum loongarch_symbol_type type, rtx v0) emit_insn (gen_tls_low (Pmode, a0, high, loc)); } else - { - if (type == SYMBOL_TLSLDM) - emit_insn (loongarch_got_load_tls_ld (a0, loc)); - else if (type == SYMBOL_TLSGD) - emit_insn (loongarch_got_load_tls_gd (a0, loc)); - else - gcc_unreachable (); - } + emit_insn (loongarch_load_tls (a0, loc)); if (flag_plt) { @@ -2953,10 +2922,10 @@ loongarch_legitimize_tls_address (rtx loc) /* la.tls.ie; tp-relative add. */ tp = gen_rtx_REG (Pmode, THREAD_POINTER_REGNUM); tmp1 = gen_reg_rtx (Pmode); + tmp2 = loongarch_unspec_address (loc, SYMBOL_TLS_IE); dest = gen_reg_rtx (Pmode); if (la_opt_explicit_relocs != EXPLICIT_RELOCS_NONE) { - tmp2 = loongarch_unspec_address (loc, SYMBOL_TLS_IE); tmp3 = gen_reg_rtx (Pmode); rtx high = gen_rtx_HIGH (Pmode, copy_rtx (tmp2)); high = loongarch_force_temporary (tmp3, high); @@ -2979,7 +2948,7 @@ loongarch_legitimize_tls_address (rtx loc) emit_insn (gen_ld_from_got (Pmode, tmp1, high, tmp2)); } else - emit_insn (loongarch_got_load_tls_ie (tmp1, loc)); + emit_insn (loongarch_load_tls (tmp1, tmp2)); emit_insn (gen_add3_insn (dest, tmp1, tp)); } break; @@ -3011,11 +2980,11 @@ loongarch_legitimize_tls_address (rtx loc) tp = gen_rtx_REG (Pmode, THREAD_POINTER_REGNUM); tmp1 = gen_reg_rtx (Pmode); + tmp2 = loongarch_unspec_address (loc, SYMBOL_TLS_LE); dest = gen_reg_rtx (Pmode); if (la_opt_explicit_relocs != EXPLICIT_RELOCS_NONE) { - tmp2 = loongarch_unspec_address (loc, SYMBOL_TLS_LE); tmp3 = gen_reg_rtx (Pmode); rtx high = gen_rtx_HIGH (Pmode, copy_rtx (tmp2)); high = loongarch_force_temporary (tmp3, high); @@ -3043,7 +3012,7 @@ loongarch_legitimize_tls_address (rtx loc) } } else - emit_insn (loongarch_got_load_tls_le (tmp1, loc)); + emit_insn (loongarch_load_tls (tmp1, tmp2)); emit_insn (gen_add3_insn (dest, tmp1, tp)); } break; diff --git a/gcc/config/loongarch/loongarch.md b/gcc/config/loongarch/loongarch.md index dda3cdf..231c656 100644 --- a/gcc/config/loongarch/loongarch.md +++ b/gcc/config/loongarch/loongarch.md @@ -51,10 +51,7 @@ UNSPEC_BITREV_8B ;; TLS - UNSPEC_TLS_GD - UNSPEC_TLS_LD - UNSPEC_TLS_LE - UNSPEC_TLS_IE + UNSPEC_TLS ;; Stack tie UNSPEC_TIE @@ -2701,45 +2698,33 @@ ;; Thread-Local Storage -(define_insn "@got_load_tls_gd" +(define_insn "@load_tls" [(set (match_operand:P 0 "register_operand" "=r") (unspec:P [(match_operand:P 1 "symbolic_operand" "")] - UNSPEC_TLS_GD))] + UNSPEC_TLS))] "" - "la.tls.gd\t%0,%1" - [(set_attr "got" "load") - (set_attr "mode" "")]) - -(define_insn "@got_load_tls_ld" - [(set (match_operand:P 0 "register_operand" "=r") - (unspec:P - [(match_operand:P 1 "symbolic_operand" "")] - UNSPEC_TLS_LD))] - "" - "la.tls.ld\t%0,%1" - [(set_attr "got" "load") - (set_attr "mode" "")]) +{ + enum loongarch_symbol_type symbol_type; + gcc_assert (loongarch_symbolic_constant_p (operands[1], &symbol_type)); -(define_insn "@got_load_tls_le" - [(set (match_operand:P 0 "register_operand" "=r") - (unspec:P - [(match_operand:P 1 "symbolic_operand" "")] - UNSPEC_TLS_LE))] - "" - "la.tls.le\t%0,%1" - [(set_attr "got" "load") - (set_attr "mode" "")]) + switch (symbol_type) + { + case SYMBOL_TLS_LE: + return "la.tls.le\t%0,%1"; + case SYMBOL_TLS_IE: + return "la.tls.ie\t%0,%1"; + case SYMBOL_TLSLDM: + return "la.tls.ld\t%0,%1"; + case SYMBOL_TLSGD: + return "la.tls.gd\t%0,%1"; -(define_insn "@got_load_tls_ie" - [(set (match_operand:P 0 "register_operand" "=r") - (unspec:P - [(match_operand:P 1 "symbolic_operand" "")] - UNSPEC_TLS_IE))] - "" - "la.tls.ie\t%0,%1" - [(set_attr "got" "load") - (set_attr "mode" "")]) + default: + gcc_unreachable (); + } +} + [(set_attr "mode" "") + (set_attr "insn_count" "2")]) ;; Move operand 1 to the high word of operand 0 using movgr2frh.w, preserving the ;; value in the low word. -- cgit v1.1 From fa972949d0f45696f95fe098232083ef37cccea1 Mon Sep 17 00:00:00 2001 From: Lulu Cheng Date: Thu, 25 Jan 2024 19:10:46 +0800 Subject: LoongArch: Add the macro implementation of mcmodel=extreme. gcc/ChangeLog: * config/loongarch/loongarch-protos.h (loongarch_symbol_extreme_p): Add function declaration. * config/loongarch/loongarch.cc (loongarch_symbolic_constant_p): For SYMBOL_PCREL64, non-zero addend of "la.local $rd,$rt,sym+addend" is not allowed (loongarch_load_tls): Added macro support in extreme mode. (loongarch_call_tls_get_addr): Likewise. (loongarch_legitimize_tls_address): Likewise. (loongarch_force_address): Likewise. (loongarch_legitimize_move): Likewise. (loongarch_output_mi_thunk): Likewise. (loongarch_option_override_internal): Remove the code that detects explicit relocs status. (loongarch_handle_model_attribute): Likewise. * config/loongarch/loongarch.md (movdi_symbolic_off64): New template. * config/loongarch/predicates.md (symbolic_off64_operand): New predicate. (symbolic_off64_or_reg_operand): Likewise. gcc/testsuite/ChangeLog: * gcc.target/loongarch/attr-model-5.c: New test. * gcc.target/loongarch/func-call-extreme-5.c: New test. * gcc.target/loongarch/func-call-extreme-6.c: New test. * gcc.target/loongarch/tls-extreme-macro.c: New test. --- gcc/config/loongarch/loongarch-protos.h | 1 + gcc/config/loongarch/loongarch.cc | 110 +++++++++++++-------- gcc/config/loongarch/loongarch.md | 48 ++++++++- gcc/config/loongarch/predicates.md | 12 +++ gcc/testsuite/gcc.target/loongarch/attr-model-5.c | 8 ++ .../gcc.target/loongarch/func-call-extreme-5.c | 7 ++ .../gcc.target/loongarch/func-call-extreme-6.c | 7 ++ .../gcc.target/loongarch/tls-extreme-macro.c | 35 +++++++ 8 files changed, 184 insertions(+), 44 deletions(-) create mode 100644 gcc/testsuite/gcc.target/loongarch/attr-model-5.c create mode 100644 gcc/testsuite/gcc.target/loongarch/func-call-extreme-5.c create mode 100644 gcc/testsuite/gcc.target/loongarch/func-call-extreme-6.c create mode 100644 gcc/testsuite/gcc.target/loongarch/tls-extreme-macro.c (limited to 'gcc') diff --git a/gcc/config/loongarch/loongarch-protos.h b/gcc/config/loongarch/loongarch-protos.h index 9ffc92a..1fdfda9 100644 --- a/gcc/config/loongarch/loongarch-protos.h +++ b/gcc/config/loongarch/loongarch-protos.h @@ -222,4 +222,5 @@ extern rtx loongarch_build_signbit_mask (machine_mode, bool, bool); extern void loongarch_emit_swrsqrtsf (rtx, rtx, machine_mode, bool); extern void loongarch_emit_swdivsf (rtx, rtx, rtx, machine_mode); extern bool loongarch_explicit_relocs_p (enum loongarch_symbol_type); +extern bool loongarch_symbol_extreme_p (enum loongarch_symbol_type); #endif /* ! GCC_LOONGARCH_PROTOS_H */ diff --git a/gcc/config/loongarch/loongarch.cc b/gcc/config/loongarch/loongarch.cc index 986dc1d..9ea20fe 100644 --- a/gcc/config/loongarch/loongarch.cc +++ b/gcc/config/loongarch/loongarch.cc @@ -1935,8 +1935,13 @@ loongarch_symbolic_constant_p (rtx x, enum loongarch_symbol_type *symbol_type) relocations. */ switch (*symbol_type) { - case SYMBOL_PCREL: case SYMBOL_PCREL64: + /* When the code model is extreme, the non-zero offset situation + has not been handled well, so it is disabled here now. */ + if (!loongarch_explicit_relocs_p (SYMBOL_PCREL64)) + return false; + /* fall through */ + case SYMBOL_PCREL: /* GAS rejects offsets outside the range [-2^31, 2^31-1]. */ return sext_hwi (INTVAL (offset), 32) == INTVAL (offset); @@ -2739,9 +2744,15 @@ static GTY (()) rtx loongarch_tls_symbol; /* Load an entry for a TLS access. */ static rtx -loongarch_load_tls (rtx dest, rtx sym) +loongarch_load_tls (rtx dest, rtx sym, enum loongarch_symbol_type type) { - return gen_load_tls (Pmode, dest, sym); + /* TLS LE gets a 32 or 64 bit offset here, so one register can do it. */ + if (type == SYMBOL_TLS_LE) + return gen_load_tls (Pmode, dest, sym); + + return loongarch_symbol_extreme_p (type) + ? gen_movdi_symbolic_off64 (dest, sym, gen_reg_rtx (DImode)) + : gen_load_tls (Pmode, dest, sym); } /* Return an instruction sequence that calls __tls_get_addr. SYM is @@ -2773,8 +2784,6 @@ loongarch_call_tls_get_addr (rtx sym, enum loongarch_symbol_type type, rtx v0) if (TARGET_CMODEL_EXTREME) { - gcc_assert (TARGET_EXPLICIT_RELOCS); - rtx tmp1 = gen_reg_rtx (Pmode); emit_insn (gen_tls_low (Pmode, tmp1, gen_rtx_REG (Pmode, 0), loc)); emit_insn (gen_lui_h_lo20 (tmp1, tmp1, loc)); @@ -2785,7 +2794,7 @@ loongarch_call_tls_get_addr (rtx sym, enum loongarch_symbol_type type, rtx v0) emit_insn (gen_tls_low (Pmode, a0, high, loc)); } else - emit_insn (loongarch_load_tls (a0, loc)); + emit_insn (loongarch_load_tls (a0, loc, type)); if (flag_plt) { @@ -2852,22 +2861,28 @@ loongarch_call_tls_get_addr (rtx sym, enum loongarch_symbol_type type, rtx v0) case CMODEL_EXTREME: { - gcc_assert (TARGET_EXPLICIT_RELOCS); - - rtx tmp1 = gen_reg_rtx (Pmode); - rtx high = gen_reg_rtx (Pmode); - - loongarch_emit_move (high, - gen_rtx_HIGH (Pmode, loongarch_tls_symbol)); - loongarch_emit_move (tmp1, gen_rtx_LO_SUM (Pmode, - gen_rtx_REG (Pmode, 0), - loongarch_tls_symbol)); - emit_insn (gen_lui_h_lo20 (tmp1, tmp1, loongarch_tls_symbol)); - emit_insn (gen_lui_h_hi12 (tmp1, tmp1, loongarch_tls_symbol)); - loongarch_emit_move (dest, - gen_rtx_MEM (Pmode, - gen_rtx_PLUS (Pmode, - high, tmp1))); + if (loongarch_explicit_relocs_p (SYMBOL_GOT_DISP)) + { + rtx tmp1 = gen_reg_rtx (Pmode); + rtx high = gen_reg_rtx (Pmode); + + loongarch_emit_move (high, + gen_rtx_HIGH (Pmode, + loongarch_tls_symbol)); + loongarch_emit_move (tmp1, + gen_rtx_LO_SUM (Pmode, + gen_rtx_REG (Pmode, 0), + loongarch_tls_symbol)); + emit_insn (gen_lui_h_lo20 (tmp1, tmp1, loongarch_tls_symbol)); + emit_insn (gen_lui_h_hi12 (tmp1, tmp1, loongarch_tls_symbol)); + loongarch_emit_move (dest, + gen_rtx_MEM (Pmode, + gen_rtx_PLUS (Pmode, + high, tmp1))); + } + else + emit_insn (gen_movdi_symbolic_off64 (dest, loongarch_tls_symbol, + gen_reg_rtx (DImode))); } break; @@ -2932,8 +2947,6 @@ loongarch_legitimize_tls_address (rtx loc) if (TARGET_CMODEL_EXTREME) { - gcc_assert (TARGET_EXPLICIT_RELOCS); - rtx tmp3 = gen_reg_rtx (Pmode); emit_insn (gen_tls_low (Pmode, tmp3, gen_rtx_REG (Pmode, 0), tmp2)); @@ -2948,7 +2961,7 @@ loongarch_legitimize_tls_address (rtx loc) emit_insn (gen_ld_from_got (Pmode, tmp1, high, tmp2)); } else - emit_insn (loongarch_load_tls (tmp1, tmp2)); + emit_insn (loongarch_load_tls (tmp1, tmp2, SYMBOL_TLS_IE)); emit_insn (gen_add3_insn (dest, tmp1, tp)); } break; @@ -3005,14 +3018,12 @@ loongarch_legitimize_tls_address (rtx loc) if (TARGET_CMODEL_EXTREME) { - gcc_assert (TARGET_EXPLICIT_RELOCS); - emit_insn (gen_lui_h_lo20 (tmp1, tmp1, tmp2)); emit_insn (gen_lui_h_hi12 (tmp1, tmp1, tmp2)); } } else - emit_insn (loongarch_load_tls (tmp1, tmp2)); + emit_insn (loongarch_load_tls (tmp1, tmp2, SYMBOL_TLS_LE)); emit_insn (gen_add3_insn (dest, tmp1, tp)); } break; @@ -3085,7 +3096,7 @@ loongarch_force_address (rtx x, machine_mode mode) return x; } -static bool +bool loongarch_symbol_extreme_p (enum loongarch_symbol_type type) { switch (type) @@ -3406,6 +3417,21 @@ loongarch_legitimize_move (machine_mode mode, rtx dest, rtx src) return true; } + /* Obtain the address of the symbol through the macro instruction + of two registers. */ + enum loongarch_symbol_type symbol_type; + if (TARGET_64BIT && register_operand (dest, mode) + && loongarch_symbolic_constant_p (src, &symbol_type) + && loongarch_symbol_extreme_p (symbol_type)) + { + gcc_assert (can_create_pseudo_p ()); + rtx tmp_reg = gen_reg_rtx (DImode); + emit_insn (gen_movdi_symbolic_off64 (dest, src, tmp_reg)); + set_unique_reg_note (get_last_insn (), REG_UNUSED, tmp_reg); + set_unique_reg_note (get_last_insn (), REG_EQUAL, src); + return true; + } + return false; } @@ -7462,12 +7488,22 @@ loongarch_output_mi_thunk (FILE *file, tree thunk_fndecl ATTRIBUTE_UNUSED, allowed, otherwise load the address into a register first. */ if (use_sibcall_p) { - insn = emit_call_insn (gen_sibcall_internal (fnaddr, const0_rtx)); + if (TARGET_CMODEL_EXTREME) + { + emit_insn (gen_movdi_symbolic_off64 (temp1, fnaddr, temp2)); + insn = emit_call_insn (gen_sibcall_internal (temp1, const0_rtx)); + } + else + insn = emit_call_insn (gen_sibcall_internal (fnaddr, const0_rtx)); SIBLING_CALL_P (insn) = 1; } else { - loongarch_emit_move (temp1, fnaddr); + if (TARGET_CMODEL_EXTREME) + emit_insn (gen_movdi_symbolic_off64 (temp1, fnaddr, temp2)); + else + loongarch_emit_move (temp1, fnaddr); + emit_jump_insn (gen_indirect_jump (temp1)); } @@ -7572,10 +7608,6 @@ loongarch_option_override_internal (struct gcc_options *opts, switch (la_target.cmodel) { case CMODEL_EXTREME: - if (la_opt_explicit_relocs == EXPLICIT_RELOCS_NONE) - error ("code model %qs is not compatible with %s", - "extreme", "-mexplicit-relocs=none"); - if (opts->x_flag_plt) { if (global_options_set.x_flag_plt) @@ -7993,14 +8025,6 @@ loongarch_handle_model_attribute (tree *node, tree name, tree arg, int, *no_add_attrs = true; return NULL_TREE; } - if (la_opt_explicit_relocs == EXPLICIT_RELOCS_NONE) - { - error_at (DECL_SOURCE_LOCATION (decl), - "%qE attribute is not compatible with %s", name, - "-mexplicit-relocs=none"); - *no_add_attrs = true; - return NULL_TREE; - } arg = TREE_VALUE (arg); if (TREE_CODE (arg) != STRING_CST) diff --git a/gcc/config/loongarch/loongarch.md b/gcc/config/loongarch/loongarch.md index 231c656..5ec1d5a 100644 --- a/gcc/config/loongarch/loongarch.md +++ b/gcc/config/loongarch/loongarch.md @@ -82,6 +82,8 @@ UNSPEC_SIBCALL_VALUE_MULTIPLE_INTERNAL_1 UNSPEC_CALL_VALUE_MULTIPLE_INTERNAL_1 + + UNSPEC_LOAD_SYMBOL_OFFSET64 ]) (define_c_enum "unspecv" [ @@ -2182,6 +2184,46 @@ [(set_attr "move_type" "move,const,load,store,mgtf,fpload,mftg,fpstore") (set_attr "mode" "DI")]) +;; Use two registers to get the global symbol address from the got table. +;; la.global rd, rt, sym + +(define_insn_and_split "movdi_symbolic_off64" + [(set (match_operand:DI 0 "register_operand" "=r,r") + (match_operand:DI 1 "symbolic_off64_or_reg_operand" "Yd,r")) + (unspec:DI [(const_int 0)] + UNSPEC_LOAD_SYMBOL_OFFSET64) + (clobber (match_operand:DI 2 "register_operand" "=&r,r"))] + "TARGET_64BIT && TARGET_CMODEL_EXTREME" +{ + if (which_alternative == 1) + return "#"; + + enum loongarch_symbol_type symbol_type; + gcc_assert (loongarch_symbolic_constant_p (operands[1], &symbol_type)); + + switch (symbol_type) + { + case SYMBOL_PCREL64: + return "la.local\t%0,%2,%1"; + case SYMBOL_GOT_DISP: + return "la.global\t%0,%2,%1"; + case SYMBOL_TLS_IE: + return "la.tls.ie\t%0,%2,%1"; + case SYMBOL_TLSGD: + return "la.tls.gd\t%0,%2,%1"; + case SYMBOL_TLSLDM: + return "la.tls.ld\t%0,%2,%1"; + + default: + gcc_unreachable (); + } +} + "&& REG_P (operands[1]) && find_reg_note (insn, REG_UNUSED, operands[2]) != 0" + [(set (match_dup 0) (match_dup 1))] + "" + [(set_attr "mode" "DI") + (set_attr "insn_count" "5")]) + ;; 32-bit Integer moves (define_expand "movsi" @@ -2724,7 +2766,11 @@ } } [(set_attr "mode" "") - (set_attr "insn_count" "2")]) + (set (attr "insn_count") + (if_then_else + (match_test "TARGET_CMODEL_EXTREME") + (const_int 4) + (const_int 2)))]) ;; Move operand 1 to the high word of operand 0 using movgr2frh.w, preserving the ;; value in the low word. diff --git a/gcc/config/loongarch/predicates.md b/gcc/config/loongarch/predicates.md index 01aad8d..eba7f24 100644 --- a/gcc/config/loongarch/predicates.md +++ b/gcc/config/loongarch/predicates.md @@ -576,6 +576,18 @@ || symbolic_pcrel_offset_operand (op, Pmode)); }) +(define_predicate "symbolic_off64_operand" + (match_code "const,symbol_ref,label_ref") +{ + enum loongarch_symbol_type type; + return loongarch_symbolic_constant_p (op, &type) + && loongarch_symbol_extreme_p (type); +}) + +(define_predicate "symbolic_off64_or_reg_operand" + (ior (match_operand 0 "register_operand") + (match_operand 0 "symbolic_off64_operand"))) + (define_predicate "equality_operator" (match_code "eq,ne")) diff --git a/gcc/testsuite/gcc.target/loongarch/attr-model-5.c b/gcc/testsuite/gcc.target/loongarch/attr-model-5.c new file mode 100644 index 0000000..5f2c3ec --- /dev/null +++ b/gcc/testsuite/gcc.target/loongarch/attr-model-5.c @@ -0,0 +1,8 @@ +/* { dg-do compile } */ +/* { dg-options "-mexplicit-relocs=none -mcmodel=extreme -O2 -fno-pic" } */ +/* { dg-final { scan-assembler "la.local\t\\\$r\[0-9\]+,\\\$r\[0-9\]+,x" } } */ +/* { dg-final { scan-assembler "la.local\t\\\$r\[0-9\]+,y" } } */ +/* { dg-final { scan-assembler "la.local\t\\\$r\[0-9\]+,\\\$r\[0-9\]+,counter" } } */ + +#define ATTR_MODEL_TEST +#include "attr-model-test.c" diff --git a/gcc/testsuite/gcc.target/loongarch/func-call-extreme-5.c b/gcc/testsuite/gcc.target/loongarch/func-call-extreme-5.c new file mode 100644 index 0000000..b1bd9d2 --- /dev/null +++ b/gcc/testsuite/gcc.target/loongarch/func-call-extreme-5.c @@ -0,0 +1,7 @@ +/* { dg-do compile } */ +/* { dg-options "-mabi=lp64d -O0 -fpic -fno-plt -mexplicit-relocs=none -mcmodel=extreme" } */ +/* { dg-final { scan-assembler "test:.*la.global\t\\\$r\[0-9\]+,\\\$r\[0-9\]+,g" } } */ +/* { dg-final { scan-assembler "test1:.*la.global\t\\\$r\[0-9\]+,\\\$r\[0-9\]+,f" } } */ +/* { dg-final { scan-assembler "test2:.*la.local\t\\\$r\[0-9\]+,\\\$r\[0-9\]+,l" } } */ + +#include "func-call-extreme-1.c" diff --git a/gcc/testsuite/gcc.target/loongarch/func-call-extreme-6.c b/gcc/testsuite/gcc.target/loongarch/func-call-extreme-6.c new file mode 100644 index 0000000..6e6ad5c --- /dev/null +++ b/gcc/testsuite/gcc.target/loongarch/func-call-extreme-6.c @@ -0,0 +1,7 @@ +/* { dg-do compile } */ +/* { dg-options "-mabi=lp64d -O0 -fno-pic -fno-plt -mexplicit-relocs=none -mcmodel=extreme" } */ +/* { dg-final { scan-assembler "test:.*la.global\t\\\$r\[0-9\]+,\\\$r\[0-9\]+,g" } } */ +/* { dg-final { scan-assembler "test1:.*la.local\t\\\$r\[0-9\]+,\\\$r\[0-9\]+,f" } } */ +/* { dg-final { scan-assembler "test2:.*la.local\t\\\$r\[0-9\]+,\\\$r\[0-9\]+,l" } } */ + +#include "func-call-extreme-1.c" diff --git a/gcc/testsuite/gcc.target/loongarch/tls-extreme-macro.c b/gcc/testsuite/gcc.target/loongarch/tls-extreme-macro.c new file mode 100644 index 0000000..4341f82 --- /dev/null +++ b/gcc/testsuite/gcc.target/loongarch/tls-extreme-macro.c @@ -0,0 +1,35 @@ +/* { dg-do compile } */ +/* { dg-options "-march=loongarch64 -mabi=lp64d -O2 -mcmodel=extreme -fno-plt -mexplicit-relocs=none" } */ +/* { dg-final { scan-assembler "test_le:.*la.tls.le\t\\\$r\[0-9\]+,\\\.L" { target tls_native } } } */ +/* { dg-final { scan-assembler "test_ie:.*la.tls.ie\t\\\$r\[0-9\]+,\\\$r\[0-9\]+,\\\.L" { target tls_native } } } */ +/* { dg-final { scan-assembler "test_ld:.*la.tls.ld\t\\\$r\[0-9\]+,\\\$r\[0-9\]+,\\\.L.*la.global\t\\\$r\[0-9\]+,\\\$r\[0-9\]+,__tls_get_addr" { target tls_native } } } */ +/* { dg-final { scan-assembler "test_le:.*la.tls.gd\t\\\$r\[0-9\]+,\\\$r\[0-9\]+,\\\.L.*la.global\t\\\$r\[0-9\]+,\\\$r\[0-9\]+,__tls_get_addr" { target tls_native } } } */ + +__thread int c __attribute__ ((tls_model ("local-exec"))); +__thread int d __attribute__ ((tls_model ("initial-exec"))); +__thread int e __attribute__ ((tls_model ("local-dynamic"))); +__thread int f __attribute__ ((tls_model ("global-dynamic"))); + +int +test_le (void) +{ + return c; +} + +int +test_ie (void) +{ + return d; +} + +int +test_ld (void) +{ + return e; +} + +int +test_gd (void) +{ + return f; +} -- cgit v1.1 From 5fbd80223e15520038b81f6cce8d3d30d93b3502 Mon Sep 17 00:00:00 2001 From: Lulu Cheng Date: Fri, 26 Jan 2024 10:46:51 +0800 Subject: LoongArch: Enable explicit reloc for extreme TLS GD/LD with -mexplicit-relocs=auto. Binutils does not support relaxation using four instructions to obtain symbol addresses gcc/ChangeLog: * config/loongarch/loongarch.cc (loongarch_explicit_relocs_p): When the code model of the symbol is extreme and -mexplicit-relocs=auto, the macro instruction loading symbol address is not applicable. (loongarch_call_tls_get_addr): Adjust code. (loongarch_legitimize_tls_address): Likewise. gcc/testsuite/ChangeLog: * gcc.target/loongarch/explicit-relocs-extreme-auto-tls-ld-gd.c: New test. * gcc.target/loongarch/explicit-relocs-medium-auto-tls-ld-gd.c: New test. --- gcc/config/loongarch/loongarch.cc | 19 +++++++++---------- .../explicit-relocs-extreme-auto-tls-ld-gd.c | 5 +++++ .../loongarch/explicit-relocs-medium-auto-tls-ld-gd.c | 5 +++++ 3 files changed, 19 insertions(+), 10 deletions(-) create mode 100644 gcc/testsuite/gcc.target/loongarch/explicit-relocs-extreme-auto-tls-ld-gd.c create mode 100644 gcc/testsuite/gcc.target/loongarch/explicit-relocs-medium-auto-tls-ld-gd.c (limited to 'gcc') diff --git a/gcc/config/loongarch/loongarch.cc b/gcc/config/loongarch/loongarch.cc index 9ea20fe..987a374 100644 --- a/gcc/config/loongarch/loongarch.cc +++ b/gcc/config/loongarch/loongarch.cc @@ -1971,6 +1971,10 @@ loongarch_explicit_relocs_p (enum loongarch_symbol_type type) if (la_opt_explicit_relocs != EXPLICIT_RELOCS_AUTO) return la_opt_explicit_relocs == EXPLICIT_RELOCS_ALWAYS; + /* The linker don't know how to relax accesses in extreme code model. */ + if (loongarch_symbol_extreme_p (type)) + return true; + switch (type) { case SYMBOL_TLS_IE: @@ -1982,11 +1986,6 @@ loongarch_explicit_relocs_p (enum loongarch_symbol_type type) does not relax 64-bit pc-relative accesses as at now. */ return true; case SYMBOL_GOT_DISP: - /* The linker don't know how to relax GOT accesses in extreme - code model. */ - if (TARGET_CMODEL_EXTREME) - return true; - /* If we are performing LTO for a final link, and we have the linker plugin so we know the resolution of the symbols, then all GOT references are binding to external symbols or @@ -2776,7 +2775,7 @@ loongarch_call_tls_get_addr (rtx sym, enum loongarch_symbol_type type, rtx v0) start_sequence (); - if (la_opt_explicit_relocs == EXPLICIT_RELOCS_ALWAYS) + if (loongarch_explicit_relocs_p (type)) { /* Split tls symbol to high and low. */ rtx high = gen_rtx_HIGH (Pmode, copy_rtx (loc)); @@ -2809,7 +2808,7 @@ loongarch_call_tls_get_addr (rtx sym, enum loongarch_symbol_type type, rtx v0) case CMODEL_MEDIUM: { rtx reg = gen_reg_rtx (Pmode); - if (TARGET_EXPLICIT_RELOCS) + if (la_opt_explicit_relocs != EXPLICIT_RELOCS_NONE) { emit_insn (gen_pcalau12i (Pmode, reg, loongarch_tls_symbol)); rtx call = gen_call_value_internal_1 (Pmode, v0, reg, @@ -2845,7 +2844,7 @@ loongarch_call_tls_get_addr (rtx sym, enum loongarch_symbol_type type, rtx v0) case CMODEL_NORMAL: case CMODEL_MEDIUM: { - if (TARGET_EXPLICIT_RELOCS) + if (loongarch_explicit_relocs_p (SYMBOL_GOT_DISP)) { rtx high = gen_reg_rtx (Pmode); loongarch_emit_move (high, @@ -2939,7 +2938,7 @@ loongarch_legitimize_tls_address (rtx loc) tmp1 = gen_reg_rtx (Pmode); tmp2 = loongarch_unspec_address (loc, SYMBOL_TLS_IE); dest = gen_reg_rtx (Pmode); - if (la_opt_explicit_relocs != EXPLICIT_RELOCS_NONE) + if (loongarch_explicit_relocs_p (SYMBOL_TLS_IE)) { tmp3 = gen_reg_rtx (Pmode); rtx high = gen_rtx_HIGH (Pmode, copy_rtx (tmp2)); @@ -2996,7 +2995,7 @@ loongarch_legitimize_tls_address (rtx loc) tmp2 = loongarch_unspec_address (loc, SYMBOL_TLS_LE); dest = gen_reg_rtx (Pmode); - if (la_opt_explicit_relocs != EXPLICIT_RELOCS_NONE) + if (loongarch_explicit_relocs_p (SYMBOL_TLS_LE)) { tmp3 = gen_reg_rtx (Pmode); rtx high = gen_rtx_HIGH (Pmode, copy_rtx (tmp2)); diff --git a/gcc/testsuite/gcc.target/loongarch/explicit-relocs-extreme-auto-tls-ld-gd.c b/gcc/testsuite/gcc.target/loongarch/explicit-relocs-extreme-auto-tls-ld-gd.c new file mode 100644 index 0000000..35bd457 --- /dev/null +++ b/gcc/testsuite/gcc.target/loongarch/explicit-relocs-extreme-auto-tls-ld-gd.c @@ -0,0 +1,5 @@ +/* { dg-do compile } */ +/* { dg-options "-O2 -fPIC -mexplicit-relocs=auto -mcmodel=extreme -fno-plt" } */ +/* { dg-final { scan-assembler-not "la.tls.\[lg\]d" { target tls_native } } } */ + +#include "./explicit-relocs-auto-tls-ld-gd.c" diff --git a/gcc/testsuite/gcc.target/loongarch/explicit-relocs-medium-auto-tls-ld-gd.c b/gcc/testsuite/gcc.target/loongarch/explicit-relocs-medium-auto-tls-ld-gd.c new file mode 100644 index 0000000..47bffae --- /dev/null +++ b/gcc/testsuite/gcc.target/loongarch/explicit-relocs-medium-auto-tls-ld-gd.c @@ -0,0 +1,5 @@ +/* { dg-do compile } */ +/* { dg-options "-O2 -fPIC -mexplicit-relocs=auto -mcmodel=medium -fplt" } */ +/* { dg-final { scan-assembler-not "la.global" { target tls_native } } } */ + +#include "./explicit-relocs-auto-tls-ld-gd.c" -- cgit v1.1 From 3932899a833f82537f96826daa5af8568b66adfc Mon Sep 17 00:00:00 2001 From: Lulu Cheng Date: Fri, 26 Jan 2024 11:14:00 +0800 Subject: LoongArch: Added support for loading __get_tls_addr symbol address using call36. gcc/ChangeLog: * config/loongarch/loongarch.cc (loongarch_call_tls_get_addr): Add support for call36. gcc/testsuite/ChangeLog: * gcc.target/loongarch/explicit-relocs-medium-call36-auto-tls-ld-gd.c: New test. --- gcc/config/loongarch/loongarch.cc | 22 ++++++++++++++++------ .../explicit-relocs-medium-call36-auto-tls-ld-gd.c | 5 +++++ 2 files changed, 21 insertions(+), 6 deletions(-) create mode 100644 gcc/testsuite/gcc.target/loongarch/explicit-relocs-medium-call36-auto-tls-ld-gd.c (limited to 'gcc') diff --git a/gcc/config/loongarch/loongarch.cc b/gcc/config/loongarch/loongarch.cc index 987a374..e1e69ef 100644 --- a/gcc/config/loongarch/loongarch.cc +++ b/gcc/config/loongarch/loongarch.cc @@ -2807,17 +2807,27 @@ loongarch_call_tls_get_addr (rtx sym, enum loongarch_symbol_type type, rtx v0) case CMODEL_MEDIUM: { - rtx reg = gen_reg_rtx (Pmode); if (la_opt_explicit_relocs != EXPLICIT_RELOCS_NONE) { - emit_insn (gen_pcalau12i (Pmode, reg, loongarch_tls_symbol)); - rtx call = gen_call_value_internal_1 (Pmode, v0, reg, - loongarch_tls_symbol, - const0_rtx); - insn = emit_call_insn (call); + rtx call; + + if (HAVE_AS_SUPPORT_CALL36) + call = gen_call_value_internal (v0, loongarch_tls_symbol, + const0_rtx); + else + { + rtx reg = gen_reg_rtx (Pmode); + emit_insn (gen_pcalau12i (Pmode, reg, + loongarch_tls_symbol)); + call = gen_call_value_internal_1 (Pmode, v0, reg, + loongarch_tls_symbol, + const0_rtx); + } + insn = emit_call_insn (call); } else { + rtx reg = gen_reg_rtx (Pmode); emit_move_insn (reg, loongarch_tls_symbol); insn = emit_call_insn (gen_call_value_internal (v0, reg, diff --git a/gcc/testsuite/gcc.target/loongarch/explicit-relocs-medium-call36-auto-tls-ld-gd.c b/gcc/testsuite/gcc.target/loongarch/explicit-relocs-medium-call36-auto-tls-ld-gd.c new file mode 100644 index 0000000..d1a4820 --- /dev/null +++ b/gcc/testsuite/gcc.target/loongarch/explicit-relocs-medium-call36-auto-tls-ld-gd.c @@ -0,0 +1,5 @@ +/* { dg-do compile } */ +/* { dg-options "-O2 -fPIC -mexplicit-relocs=auto -mcmodel=medium -fplt" } */ +/* { dg-final { scan-assembler "pcaddu18i\t\\\$r1,%call36\\\(__tls_get_addr\\\)" { target { tls_native && loongarch_call36_support } } } } */ + +#include "./explicit-relocs-auto-tls-ld-gd.c" -- cgit v1.1 From f72586e5b9cbb91a099cb6970480eedcbce9f0c7 Mon Sep 17 00:00:00 2001 From: Xi Ruoyao Date: Mon, 29 Jan 2024 15:20:07 +0800 Subject: LoongArch: Don't split the instructions containing relocs for extreme code model. The ABI mandates the pcalau12i/addi.d/lu32i.d/lu52i.d instructions for addressing a symbol to be adjacent. So model them as "one large instruction", i.e. define_insn, with two output registers. The real address is the sum of these two registers. The advantage of this approach is the RTL passes can still use ldx/stx instructions to skip an addi.d instruction. gcc/ChangeLog: * config/loongarch/loongarch.md (unspec): Add UNSPEC_LA_PCREL_64_PART1 and UNSPEC_LA_PCREL_64_PART2. (la_pcrel64_two_parts): New define_insn. * config/loongarch/loongarch.cc (loongarch_tls_symbol): Fix a typo in the comment. (loongarch_call_tls_get_addr): If -mcmodel=extreme -mexplicit-relocs={always,auto}, use la_pcrel64_two_parts for addressing the TLS symbol and __tls_get_addr. Emit an REG_EQUAL note to allow CSE addressing __tls_get_addr. (loongarch_legitimize_tls_address): If -mcmodel=extreme -mexplicit-relocs={always,auto}, address TLS IE symbols with la_pcrel64_two_parts. (loongarch_split_symbol): If -mcmodel=extreme -mexplicit-relocs={always,auto}, address symbols with la_pcrel64_two_parts. (loongarch_output_mi_thunk): Clean up unreachable code. If -mcmodel=extreme -mexplicit-relocs={always,auto}, address the MI thunks with la_pcrel64_two_parts. gcc/testsuite/ChangeLog: * gcc.target/loongarch/func-call-extreme-1.c (dg-options): Use -O2 instead of -O0 to ensure the pcalau12i/addi/lu32i/lu52i instruction sequences are not reordered by the compiler. (NOIPA): Disallow interprocedural optimizations. * gcc.target/loongarch/func-call-extreme-2.c: Remove the content duplicated from func-call-extreme-1.c, include it instead. (dg-options): Likewise. * gcc.target/loongarch/func-call-extreme-3.c (dg-options): Likewise. * gcc.target/loongarch/func-call-extreme-4.c (dg-options): Likewise. * gcc.target/loongarch/cmodel-extreme-1.c: New test. * gcc.target/loongarch/cmodel-extreme-2.c: New test. * g++.target/loongarch/cmodel-extreme-mi-thunk-1.C: New test. * g++.target/loongarch/cmodel-extreme-mi-thunk-2.C: New test. * g++.target/loongarch/cmodel-extreme-mi-thunk-3.C: New test. --- gcc/config/loongarch/loongarch.cc | 131 ++++++++++++--------- gcc/config/loongarch/loongarch.md | 20 ++++ .../loongarch/cmodel-extreme-mi-thunk-1.C | 11 ++ .../loongarch/cmodel-extreme-mi-thunk-2.C | 6 + .../loongarch/cmodel-extreme-mi-thunk-3.C | 6 + .../gcc.target/loongarch/cmodel-extreme-1.c | 18 +++ .../gcc.target/loongarch/cmodel-extreme-2.c | 7 ++ .../gcc.target/loongarch/func-call-extreme-1.c | 14 ++- .../gcc.target/loongarch/func-call-extreme-2.c | 29 +---- .../gcc.target/loongarch/func-call-extreme-3.c | 2 +- .../gcc.target/loongarch/func-call-extreme-4.c | 2 +- 11 files changed, 154 insertions(+), 92 deletions(-) create mode 100644 gcc/testsuite/g++.target/loongarch/cmodel-extreme-mi-thunk-1.C create mode 100644 gcc/testsuite/g++.target/loongarch/cmodel-extreme-mi-thunk-2.C create mode 100644 gcc/testsuite/g++.target/loongarch/cmodel-extreme-mi-thunk-3.C create mode 100644 gcc/testsuite/gcc.target/loongarch/cmodel-extreme-1.c create mode 100644 gcc/testsuite/gcc.target/loongarch/cmodel-extreme-2.c (limited to 'gcc') diff --git a/gcc/config/loongarch/loongarch.cc b/gcc/config/loongarch/loongarch.cc index e1e69ef..e806bbf 100644 --- a/gcc/config/loongarch/loongarch.cc +++ b/gcc/config/loongarch/loongarch.cc @@ -2737,7 +2737,7 @@ loongarch_add_offset (rtx temp, rtx reg, HOST_WIDE_INT offset) return plus_constant (Pmode, reg, offset); } -/* The __tls_get_attr symbol. */ +/* The __tls_get_addr symbol. */ static GTY (()) rtx loongarch_tls_symbol; /* Load an entry for a TLS access. */ @@ -2777,20 +2777,22 @@ loongarch_call_tls_get_addr (rtx sym, enum loongarch_symbol_type type, rtx v0) if (loongarch_explicit_relocs_p (type)) { - /* Split tls symbol to high and low. */ - rtx high = gen_rtx_HIGH (Pmode, copy_rtx (loc)); - high = loongarch_force_temporary (tmp, high); - if (TARGET_CMODEL_EXTREME) { - rtx tmp1 = gen_reg_rtx (Pmode); - emit_insn (gen_tls_low (Pmode, tmp1, gen_rtx_REG (Pmode, 0), loc)); - emit_insn (gen_lui_h_lo20 (tmp1, tmp1, loc)); - emit_insn (gen_lui_h_hi12 (tmp1, tmp1, loc)); - emit_move_insn (a0, gen_rtx_PLUS (Pmode, high, tmp1)); + rtx part1 = gen_reg_rtx (Pmode); + rtx part2 = gen_reg_rtx (Pmode); + + emit_insn (gen_la_pcrel64_two_parts (part1, part2, loc)); + emit_move_insn (a0, gen_rtx_PLUS (Pmode, part1, part2)); } else - emit_insn (gen_tls_low (Pmode, a0, high, loc)); + { + /* Split tls symbol to high and low. */ + rtx high = gen_rtx_HIGH (Pmode, copy_rtx (loc)); + + high = loongarch_force_temporary (tmp, high); + emit_insn (gen_tls_low (Pmode, a0, high, loc)); + } } else emit_insn (loongarch_load_tls (a0, loc, type)); @@ -2872,22 +2874,28 @@ loongarch_call_tls_get_addr (rtx sym, enum loongarch_symbol_type type, rtx v0) { if (loongarch_explicit_relocs_p (SYMBOL_GOT_DISP)) { - rtx tmp1 = gen_reg_rtx (Pmode); - rtx high = gen_reg_rtx (Pmode); + gcc_assert (la_opt_explicit_relocs != EXPLICIT_RELOCS_NONE); - loongarch_emit_move (high, - gen_rtx_HIGH (Pmode, - loongarch_tls_symbol)); - loongarch_emit_move (tmp1, - gen_rtx_LO_SUM (Pmode, - gen_rtx_REG (Pmode, 0), + rtx part1 = gen_reg_rtx (Pmode); + rtx part2 = gen_reg_rtx (Pmode); + + emit_insn (gen_la_pcrel64_two_parts (part1, part2, loongarch_tls_symbol)); - emit_insn (gen_lui_h_lo20 (tmp1, tmp1, loongarch_tls_symbol)); - emit_insn (gen_lui_h_hi12 (tmp1, tmp1, loongarch_tls_symbol)); - loongarch_emit_move (dest, - gen_rtx_MEM (Pmode, - gen_rtx_PLUS (Pmode, - high, tmp1))); + loongarch_emit_move ( + dest, + gen_rtx_MEM (Pmode, gen_rtx_PLUS (Pmode, + part1, + part2))); + + /* Put an REG_EQUAL note here to allow CSE (storing + part1 + part2, i.e. the address of tls_get_addr into + a saved register and use it for multiple TLS + accesses). */ + rtx sum = gen_rtx_UNSPEC ( + Pmode, gen_rtvec (1, loongarch_tls_symbol), + UNSPEC_ADDRESS_FIRST + + loongarch_classify_symbol (loongarch_tls_symbol)); + set_unique_reg_note (get_last_insn (), REG_EQUAL, sum); } else emit_insn (gen_movdi_symbolic_off64 (dest, loongarch_tls_symbol, @@ -2950,24 +2958,30 @@ loongarch_legitimize_tls_address (rtx loc) dest = gen_reg_rtx (Pmode); if (loongarch_explicit_relocs_p (SYMBOL_TLS_IE)) { - tmp3 = gen_reg_rtx (Pmode); - rtx high = gen_rtx_HIGH (Pmode, copy_rtx (tmp2)); - high = loongarch_force_temporary (tmp3, high); - if (TARGET_CMODEL_EXTREME) { - rtx tmp3 = gen_reg_rtx (Pmode); - emit_insn (gen_tls_low (Pmode, tmp3, - gen_rtx_REG (Pmode, 0), tmp2)); - emit_insn (gen_lui_h_lo20 (tmp3, tmp3, tmp2)); - emit_insn (gen_lui_h_hi12 (tmp3, tmp3, tmp2)); + gcc_assert (la_opt_explicit_relocs + != EXPLICIT_RELOCS_NONE); + + rtx part1 = gen_reg_rtx (Pmode); + rtx part2 = gen_reg_rtx (Pmode); + + emit_insn (gen_la_pcrel64_two_parts (part1, part2, + tmp2)); emit_move_insn (tmp1, gen_rtx_MEM (Pmode, gen_rtx_PLUS (Pmode, - high, tmp3))); + part1, + part2))); } else - emit_insn (gen_ld_from_got (Pmode, tmp1, high, tmp2)); + { + tmp3 = gen_reg_rtx (Pmode); + rtx high = gen_rtx_HIGH (Pmode, copy_rtx (tmp2)); + + high = loongarch_force_temporary (tmp3, high); + emit_insn (gen_ld_from_got (Pmode, tmp1, high, tmp2)); + } } else emit_insn (loongarch_load_tls (tmp1, tmp2, SYMBOL_TLS_IE)); @@ -3146,24 +3160,23 @@ loongarch_split_symbol (rtx temp, rtx addr, machine_mode mode, rtx *low_out) || !loongarch_split_symbol_type (symbol_type)) return false; - rtx high, temp1 = NULL; + rtx high; if (temp == NULL) temp = gen_reg_rtx (Pmode); - /* Get the 12-31 bits of the address. */ - high = gen_rtx_HIGH (Pmode, copy_rtx (addr)); - high = loongarch_force_temporary (temp, high); - if (loongarch_symbol_extreme_p (symbol_type) && can_create_pseudo_p ()) { gcc_assert (la_opt_explicit_relocs != EXPLICIT_RELOCS_NONE); - temp1 = gen_reg_rtx (Pmode); - emit_move_insn (temp1, gen_rtx_LO_SUM (Pmode, gen_rtx_REG (Pmode, 0), - addr)); - emit_insn (gen_lui_h_lo20 (temp1, temp1, addr)); - emit_insn (gen_lui_h_hi12 (temp1, temp1, addr)); + high = gen_reg_rtx (Pmode); + emit_insn (gen_la_pcrel64_two_parts (high, temp, addr)); + } + else + { + /* Get the 12-31 bits of the address. */ + high = gen_rtx_HIGH (Pmode, copy_rtx (addr)); + high = loongarch_force_temporary (temp, high); } if (low_out) @@ -3172,7 +3185,7 @@ loongarch_split_symbol (rtx temp, rtx addr, machine_mode mode, rtx *low_out) case SYMBOL_PCREL64: if (can_create_pseudo_p ()) { - *low_out = gen_rtx_PLUS (Pmode, high, temp1); + *low_out = gen_rtx_PLUS (Pmode, high, temp); break; } /* fall through */ @@ -3184,7 +3197,8 @@ loongarch_split_symbol (rtx temp, rtx addr, machine_mode mode, rtx *low_out) /* SYMBOL_GOT_DISP symbols are loaded from the GOT. */ { if (TARGET_CMODEL_EXTREME && can_create_pseudo_p ()) - *low_out = gen_rtx_MEM (Pmode, gen_rtx_PLUS (Pmode, high, temp1)); + *low_out = gen_rtx_MEM (Pmode, gen_rtx_PLUS (Pmode, high, + temp)); else { rtx low = gen_rtx_LO_SUM (Pmode, high, addr); @@ -7497,21 +7511,24 @@ loongarch_output_mi_thunk (FILE *file, tree thunk_fndecl ATTRIBUTE_UNUSED, allowed, otherwise load the address into a register first. */ if (use_sibcall_p) { - if (TARGET_CMODEL_EXTREME) - { - emit_insn (gen_movdi_symbolic_off64 (temp1, fnaddr, temp2)); - insn = emit_call_insn (gen_sibcall_internal (temp1, const0_rtx)); - } - else - insn = emit_call_insn (gen_sibcall_internal (fnaddr, const0_rtx)); + /* If TARGET_CMODEL_EXTREME, we cannot do a direct jump at all + and const_call_insn_operand should have returned false. */ + gcc_assert (!TARGET_CMODEL_EXTREME); + + insn = emit_call_insn (gen_sibcall_internal (fnaddr, const0_rtx)); SIBLING_CALL_P (insn) = 1; } else { - if (TARGET_CMODEL_EXTREME) + if (!TARGET_CMODEL_EXTREME) + loongarch_emit_move (temp1, fnaddr); + else if (la_opt_explicit_relocs == EXPLICIT_RELOCS_NONE) emit_insn (gen_movdi_symbolic_off64 (temp1, fnaddr, temp2)); else - loongarch_emit_move (temp1, fnaddr); + { + emit_insn (gen_la_pcrel64_two_parts (temp1, temp2, fnaddr)); + emit_move_insn (temp1, gen_rtx_PLUS (Pmode, temp1, temp2)); + } emit_jump_insn (gen_indirect_jump (temp1)); } diff --git a/gcc/config/loongarch/loongarch.md b/gcc/config/loongarch/loongarch.md index 5ec1d5a..dffa41b 100644 --- a/gcc/config/loongarch/loongarch.md +++ b/gcc/config/loongarch/loongarch.md @@ -84,6 +84,8 @@ UNSPEC_CALL_VALUE_MULTIPLE_INTERNAL_1 UNSPEC_LOAD_SYMBOL_OFFSET64 + UNSPEC_LA_PCREL_64_PART1 + UNSPEC_LA_PCREL_64_PART2 ]) (define_c_enum "unspecv" [ @@ -2224,6 +2226,24 @@ [(set_attr "mode" "DI") (set_attr "insn_count" "5")]) +;; The 64-bit PC-relative part of address loading. +;; Note that the psABI does not allow splitting it. +(define_insn "la_pcrel64_two_parts" + [(set (match_operand:DI 0 "register_operand" "=r") + (unspec:DI [(match_operand:DI 2 "") (pc)] UNSPEC_LA_PCREL_64_PART1)) + (set (match_operand:DI 1 "register_operand" "=r") + (unspec:DI [(match_dup 2) (pc)] UNSPEC_LA_PCREL_64_PART2))] + "TARGET_ABI_LP64 && la_opt_explicit_relocs != EXPLICIT_RELOCS_NONE" + { + return "pcalau12i\t%0,%r2\n\t" + "addi.d\t%1,$r0,%L2\n\t" + "lu32i.d\t%1,%R2\n\t" + "lu52i.d\t%1,%1,%H2"; + } + [(set_attr "move_type" "move") + (set_attr "mode" "DI") + (set_attr "length" "16")]) + ;; 32-bit Integer moves (define_expand "movsi" diff --git a/gcc/testsuite/g++.target/loongarch/cmodel-extreme-mi-thunk-1.C b/gcc/testsuite/g++.target/loongarch/cmodel-extreme-mi-thunk-1.C new file mode 100644 index 0000000..ff1f7c1 --- /dev/null +++ b/gcc/testsuite/g++.target/loongarch/cmodel-extreme-mi-thunk-1.C @@ -0,0 +1,11 @@ +/* { dg-do compile } */ +/* { dg-options "-O2 -fno-inline -march=loongarch64 -mabi=lp64d -O2 -mcmodel=extreme -fno-plt -mexplicit-relocs=always -mdirect-extern-access" } */ + +struct A { + virtual ~A(); +}; + +struct B : virtual A {}; +void var() { B(); } + +/* { dg-final { scan-assembler "pcalau12i\t\[^\n\]*%pc_hi20\\(\\.LTHUNK0\\)\n\taddi\\.d\t\[^\n\]*%pc_lo12\\(\\\.LTHUNK0\\)\n\tlu32i\\.d\t\[^\n\]*%pc64_lo20\\(\\.LTHUNK0\\)\n\tlu52i\\.d\t\[^\n\]*%pc64_hi12\\(\\.LTHUNK0\\)" } } */ diff --git a/gcc/testsuite/g++.target/loongarch/cmodel-extreme-mi-thunk-2.C b/gcc/testsuite/g++.target/loongarch/cmodel-extreme-mi-thunk-2.C new file mode 100644 index 0000000..c9aa16b --- /dev/null +++ b/gcc/testsuite/g++.target/loongarch/cmodel-extreme-mi-thunk-2.C @@ -0,0 +1,6 @@ +/* { dg-do compile } */ +/* { dg-options "-O2 -fno-inline -march=loongarch64 -mabi=lp64d -O2 -mcmodel=extreme -fno-plt -mexplicit-relocs=auto -mdirect-extern-access" } */ + +#include "cmodel-extreme-mi-thunk-1.C" + +/* { dg-final { scan-assembler "pcalau12i\t\[^\n\]*%pc_hi20\\(\\.LTHUNK0\\)\n\taddi\\.d\t\[^\n\]*%pc_lo12\\(\\\.LTHUNK0\\)\n\tlu32i\\.d\t\[^\n\]*%pc64_lo20\\(\\.LTHUNK0\\)\n\tlu52i\\.d\t\[^\n\]*%pc64_hi12\\(\\.LTHUNK0\\)" } } */ diff --git a/gcc/testsuite/g++.target/loongarch/cmodel-extreme-mi-thunk-3.C b/gcc/testsuite/g++.target/loongarch/cmodel-extreme-mi-thunk-3.C new file mode 100644 index 0000000..afb86c8 --- /dev/null +++ b/gcc/testsuite/g++.target/loongarch/cmodel-extreme-mi-thunk-3.C @@ -0,0 +1,6 @@ +/* { dg-do compile } */ +/* { dg-options "-O2 -fno-inline -march=loongarch64 -mabi=lp64d -O2 -mcmodel=extreme -fno-plt -mexplicit-relocs=none -mdirect-extern-access" } */ + +#include "cmodel-extreme-mi-thunk-1.C" + +/* { dg-final { scan-assembler "la.local\t\[^\n\]*\\.LTHUNK0" } } */ diff --git a/gcc/testsuite/gcc.target/loongarch/cmodel-extreme-1.c b/gcc/testsuite/gcc.target/loongarch/cmodel-extreme-1.c new file mode 100644 index 0000000..564ee40 --- /dev/null +++ b/gcc/testsuite/gcc.target/loongarch/cmodel-extreme-1.c @@ -0,0 +1,18 @@ +/* { dg-do compile } */ +/* { dg-options "-march=loongarch64 -mabi=lp64d -O2 -mcmodel=extreme -fno-plt -mexplicit-relocs=always -fdump-rtl-final" } */ + +int a; +extern int b; +__thread int c __attribute__ ((tls_model ("local-exec"))); +__thread int d __attribute__ ((tls_model ("initial-exec"))); +__thread int e __attribute__ ((tls_model ("local-dynamic"))); +__thread int f __attribute__ ((tls_model ("global-dynamic"))); + +void +test (void) +{ + a = b + c + d + e + f; +} + +/* a, b, d, e, f, and __tls_get_addr. */ +/* { dg-final { scan-rtl-dump-times "la_pcrel64_two_parts" 6 "final" } } */ diff --git a/gcc/testsuite/gcc.target/loongarch/cmodel-extreme-2.c b/gcc/testsuite/gcc.target/loongarch/cmodel-extreme-2.c new file mode 100644 index 0000000..ce83480 --- /dev/null +++ b/gcc/testsuite/gcc.target/loongarch/cmodel-extreme-2.c @@ -0,0 +1,7 @@ +/* { dg-do compile } */ +/* { dg-options "-march=loongarch64 -mabi=lp64d -O2 -mcmodel=extreme -fno-plt -mexplicit-relocs=auto -fdump-rtl-final" } */ + +#include "cmodel-extreme-1.c" + +/* a, b, d, e, f, and __tls_get_addr. */ +/* { dg-final { scan-rtl-dump-times "la_pcrel64_two_parts" 6 "final" } } */ diff --git a/gcc/testsuite/gcc.target/loongarch/func-call-extreme-1.c b/gcc/testsuite/gcc.target/loongarch/func-call-extreme-1.c index db1e0f8..fdb4cf1 100644 --- a/gcc/testsuite/gcc.target/loongarch/func-call-extreme-1.c +++ b/gcc/testsuite/gcc.target/loongarch/func-call-extreme-1.c @@ -1,31 +1,33 @@ /* { dg-do compile } */ -/* { dg-options "-mabi=lp64d -O0 -fno-pic -fno-plt -mexplicit-relocs -mcmodel=extreme" } */ +/* { dg-options "-mabi=lp64d -O2 -fno-pic -fno-plt -mexplicit-relocs -mcmodel=extreme" } */ /* { dg-final { scan-assembler "test:.*pcalau12i.*%got_pc_hi20.*\n\taddi\.d.*%got_pc_lo12.*\n\tlu32i\.d.*%got64_pc_lo20.*\n\tlu52i\.d.*%got64_pc_hi12.*\n\tldx\.d" } } */ /* { dg-final { scan-assembler "test1:.*pcalau12i.*%pc_hi20.*\n\taddi\.d.*%pc_lo12.*\n\tlu32i\.d.*%pc64_lo20.*\n\tlu52i\.d.*pc64_hi12.*\n\tadd\.d" } } */ /* { dg-final { scan-assembler "test2:.*pcalau12i.*%pc_hi20.*\n\taddi\.d.*%pc_lo12.*\n\tlu32i\.d.*%pc64_lo20.*\n\tlu52i\.d.*pc64_hi12.*\n\tadd\.d" } } */ +#define NOIPA __attribute__ ((noipa)) + extern void g (void); -void +NOIPA void f (void) {} -static void +NOIPA static void l (void) {} -void +NOIPA void test (void) { g (); } -void +NOIPA void test1 (void) { f (); } -void +NOIPA void test2 (void) { l (); diff --git a/gcc/testsuite/gcc.target/loongarch/func-call-extreme-2.c b/gcc/testsuite/gcc.target/loongarch/func-call-extreme-2.c index 21bf81a..dfba388 100644 --- a/gcc/testsuite/gcc.target/loongarch/func-call-extreme-2.c +++ b/gcc/testsuite/gcc.target/loongarch/func-call-extreme-2.c @@ -1,32 +1,7 @@ /* { dg-do compile } */ -/* { dg-options "-mabi=lp64d -O0 -fpic -fno-plt -mexplicit-relocs -mcmodel=extreme" } */ +/* { dg-options "-mabi=lp64d -O2 -fpic -fno-plt -mexplicit-relocs -mcmodel=extreme" } */ /* { dg-final { scan-assembler "test:.*pcalau12i.*%got_pc_hi20.*\n\taddi\.d.*%got_pc_lo12.*\n\tlu32i\.d.*%got64_pc_lo20.*\n\tlu52i\.d.*%got64_pc_hi12.*\n\tldx\.d" } } */ /* { dg-final { scan-assembler "test1:.*pcalau12i.*%got_pc_hi20.*\n\taddi\.d.*%got_pc_lo12.*\n\tlu32i\.d.*%got64_pc_lo20.*\n\tlu52i\.d.*%got64_pc_hi12.*\n\tldx\.d" } } */ /* { dg-final { scan-assembler "test2:.*pcalau12i.*%pc_hi20.*\n\taddi\.d.*%pc_lo12.*\n\tlu32i\.d.*%pc64_lo20.*\n\tlu52i\.d.*pc64_hi12.*\n\tadd\.d" } } */ -extern void g (void); -void -f (void) -{} - -static void -l (void) -{} - -void -test (void) -{ - g (); -} - -void -test1 (void) -{ - f (); -} - -void -test2 (void) -{ - l (); -} +#include "func-call-extreme-1.c" diff --git a/gcc/testsuite/gcc.target/loongarch/func-call-extreme-3.c b/gcc/testsuite/gcc.target/loongarch/func-call-extreme-3.c index a4da44b..1f5234f8 100644 --- a/gcc/testsuite/gcc.target/loongarch/func-call-extreme-3.c +++ b/gcc/testsuite/gcc.target/loongarch/func-call-extreme-3.c @@ -1,5 +1,5 @@ /* { dg-do compile } */ -/* { dg-options "-mabi=lp64d -O0 -fno-pic -fno-plt -mexplicit-relocs=auto -mcmodel=extreme" } */ +/* { dg-options "-mabi=lp64d -O2 -fno-pic -fno-plt -mexplicit-relocs=auto -mcmodel=extreme" } */ /* { dg-final { scan-assembler "test:.*pcalau12i.*%got_pc_hi20.*\n\taddi\.d.*%got_pc_lo12.*\n\tlu32i\.d.*%got64_pc_lo20.*\n\tlu52i\.d.*%got64_pc_hi12.*\n\tldx\.d" } } */ /* { dg-final { scan-assembler "test1:.*pcalau12i.*%pc_hi20.*\n\taddi\.d.*%pc_lo12.*\n\tlu32i\.d.*%pc64_lo20.*\n\tlu52i\.d.*pc64_hi12.*\n\tadd\.d" } } */ /* { dg-final { scan-assembler "test2:.*pcalau12i.*%pc_hi20.*\n\taddi\.d.*%pc_lo12.*\n\tlu32i\.d.*%pc64_lo20.*\n\tlu52i\.d.*pc64_hi12.*\n\tadd\.d" } } */ diff --git a/gcc/testsuite/gcc.target/loongarch/func-call-extreme-4.c b/gcc/testsuite/gcc.target/loongarch/func-call-extreme-4.c index 16b00f4..c422850 100644 --- a/gcc/testsuite/gcc.target/loongarch/func-call-extreme-4.c +++ b/gcc/testsuite/gcc.target/loongarch/func-call-extreme-4.c @@ -1,5 +1,5 @@ /* { dg-do compile } */ -/* { dg-options "-mabi=lp64d -O0 -fpic -fno-plt -mexplicit-relocs=auto -mcmodel=extreme" } */ +/* { dg-options "-mabi=lp64d -O2 -fpic -fno-plt -mexplicit-relocs=auto -mcmodel=extreme" } */ /* { dg-final { scan-assembler "test:.*pcalau12i.*%got_pc_hi20.*\n\taddi\.d.*%got_pc_lo12.*\n\tlu32i\.d.*%got64_pc_lo20.*\n\tlu52i\.d.*%got64_pc_hi12.*\n\tldx\.d" } } */ /* { dg-final { scan-assembler "test1:.*pcalau12i.*%got_pc_hi20.*\n\taddi\.d.*%got_pc_lo12.*\n\tlu32i\.d.*%got64_pc_lo20.*\n\tlu52i\.d.*%got64_pc_hi12.*\n\tldx\.d" } } */ /* { dg-final { scan-assembler "test2:.*pcalau12i.*%pc_hi20.*\n\taddi\.d.*%pc_lo12.*\n\tlu32i\.d.*%pc64_lo20.*\n\tlu52i\.d.*pc64_hi12.*\n\tadd\.d" } } */ -- cgit v1.1 From 593d518a6339f0f6546660de762811a463490176 Mon Sep 17 00:00:00 2001 From: Li Wei Date: Fri, 26 Jan 2024 16:41:11 +0800 Subject: LoongArch: Adjust cost of vector_stmt that match multiply-add pattern. We found that when only 128-bit vectorization was enabled, 549.fotonik3d_r failed to vectorize effectively. For this reason, we adjust the cost of 128-bit vector_stmt that match the multiply-add pattern to facilitate 128-bit vectorization. The experimental results show that after the modification, 549.fotonik3d_r performance can be improved by 9.77% under the 128-bit vectorization option. gcc/ChangeLog: * config/loongarch/loongarch.cc (loongarch_multiply_add_p): New. (loongarch_vector_costs::add_stmt_cost): Adjust. gcc/testsuite/ChangeLog: * gfortran.dg/vect/vect-10.f90: New test. --- gcc/config/loongarch/loongarch.cc | 48 ++++++++++++++++++++ gcc/testsuite/gfortran.dg/vect/vect-10.f90 | 71 ++++++++++++++++++++++++++++++ 2 files changed, 119 insertions(+) create mode 100644 gcc/testsuite/gfortran.dg/vect/vect-10.f90 (limited to 'gcc') diff --git a/gcc/config/loongarch/loongarch.cc b/gcc/config/loongarch/loongarch.cc index e806bbf..8bc1844 100644 --- a/gcc/config/loongarch/loongarch.cc +++ b/gcc/config/loongarch/loongarch.cc @@ -4157,6 +4157,37 @@ loongarch_vector_costs::determine_suggested_unroll_factor (loop_vec_info loop_vi return 1 << ceil_log2 (uf); } +/* Check if assign stmt rhs op comes from a multiply-add operation. */ +static bool +loongarch_multiply_add_p (vec_info *vinfo, stmt_vec_info stmt_info) +{ + gassign *assign = dyn_cast (stmt_info->stmt); + if (!assign) + return false; + tree_code code = gimple_assign_rhs_code (assign); + if (code != PLUS_EXPR && code != MINUS_EXPR) + return false; + + auto is_mul_result = [&](int i) + { + tree rhs = gimple_op (assign, i); + if (TREE_CODE (rhs) != SSA_NAME) + return false; + + stmt_vec_info def_stmt_info = vinfo->lookup_def (rhs); + if (!def_stmt_info + || STMT_VINFO_DEF_TYPE (def_stmt_info) != vect_internal_def) + return false; + gassign *rhs_assign = dyn_cast (def_stmt_info->stmt); + if (!rhs_assign || gimple_assign_rhs_code (rhs_assign) != MULT_EXPR) + return false; + + return true; + }; + + return is_mul_result (1) || is_mul_result (2); +} + unsigned loongarch_vector_costs::add_stmt_cost (int count, vect_cost_for_stmt kind, stmt_vec_info stmt_info, slp_tree, @@ -4169,6 +4200,23 @@ loongarch_vector_costs::add_stmt_cost (int count, vect_cost_for_stmt kind, { int stmt_cost = loongarch_builtin_vectorization_cost (kind, vectype, misalign); + if (vectype && stmt_info) + { + gassign *assign = dyn_cast (STMT_VINFO_STMT (stmt_info)); + machine_mode mode = TYPE_MODE (vectype); + + /* We found through testing that this strategy (the stmt that + matches the multiply-add pattern) has positive returns only + when applied to the 128-bit vector stmt, so this restriction + is currently made. */ + if (kind == vector_stmt && GET_MODE_SIZE (mode) == 16 && assign) + { + if (!vect_is_reduction (stmt_info) + && loongarch_multiply_add_p (m_vinfo, stmt_info)) + stmt_cost = 0; + } + } + retval = adjust_cost_for_freq (stmt_info, where, count * stmt_cost); m_costs[where] += retval; diff --git a/gcc/testsuite/gfortran.dg/vect/vect-10.f90 b/gcc/testsuite/gfortran.dg/vect/vect-10.f90 new file mode 100644 index 0000000..b85bc27 --- /dev/null +++ b/gcc/testsuite/gfortran.dg/vect/vect-10.f90 @@ -0,0 +1,71 @@ +! { dg-do compile } +! { dg-additional-options "-Ofast -mlsx -fvect-cost-model=dynamic" { target loongarch64*-*-* } } + +MODULE material_mod + +IMPLICIT NONE + +integer, parameter :: dfp = selected_real_kind (13, 99) +integer, parameter :: rfp = dfp + +PUBLIC Mat_updateE, iepx, iepy, iepz + +PRIVATE + +integer, dimension (:, :, :), allocatable :: iepx, iepy, iepz +real (kind = rfp), dimension (:), allocatable :: Dbdx, Dbdy, Dbdz +integer :: imin, jmin, kmin +integer, dimension (6) :: Exsize +integer, dimension (6) :: Eysize +integer, dimension (6) :: Ezsize +integer, dimension (6) :: Hxsize +integer, dimension (6) :: Hysize +integer, dimension (6) :: Hzsize + +CONTAINS + +SUBROUTINE mat_updateE (nx, ny, nz, Hx, Hy, Hz, Ex, Ey, Ez) + +integer, intent (in) :: nx, ny, nz + +real (kind = rfp), intent (inout), & + dimension (Exsize (1) : Exsize (2), Exsize (3) : Exsize (4), Exsize (5) : Exsize (6)) :: Ex +real (kind = rfp), intent (inout), & + dimension (Eysize (1) : Eysize (2), Eysize (3) : Eysize (4), Eysize (5) : Eysize (6)) :: Ey +real (kind = rfp), intent (inout), & + dimension (Ezsize (1) : Ezsize (2), Ezsize (3) : Ezsize (4), Ezsize (5) : Ezsize (6)) :: Ez +real (kind = rfp), intent (in), & + dimension (Hxsize (1) : Hxsize (2), Hxsize (3) : Hxsize (4), Hxsize (5) : Hxsize (6)) :: Hx +real (kind = rfp), intent (in), & + dimension (Hysize (1) : Hysize (2), Hysize (3) : Hysize (4), Hysize (5) : Hysize (6)) :: Hy +real (kind = rfp), intent (in), & + dimension (Hzsize (1) : Hzsize (2), Hzsize (3) : Hzsize (4), Hzsize (5) : Hzsize (6)) :: Hz + +integer :: i, j, k, mp + +do k = kmin, nz + do j = jmin, ny + do i = imin, nx + mp = iepx (i, j, k) + Ex (i, j, k) = Ex (i, j, k) + & + Dbdy (mp) * (Hz (i, j, k ) - Hz (i, j-1, k)) + & + Dbdz (mp) * (Hy (i, j, k-1) - Hy (i, j , k)) + + mp = iepy (i, j, k) + Ey (i, j, k) = Ey (i, j, k) + & + Dbdz (mp) * (Hx (i , j, k) - Hx (i, j, k-1)) + & + Dbdx (mp) * (Hz (i-1, j, k) - Hz (i, j, k )) + + mp = iepz (i, j, k) + Ez (i, j, k) = Ez (i, j, k) + & + Dbdx (mp) * (Hy (i, j , k) - Hy (i-1, j, k)) + & + Dbdy (mp) * (Hx (i, j-1, k) - Hx (i , j, k)) + end do + end do +end do + +END SUBROUTINE mat_updateE + +END MODULE material_mod + +! { dg-final { scan-tree-dump-times "vectorized 1 loops" 1 "vect" { target loongarch64*-*-* } } } -- cgit v1.1 From 92acc92ee575417a0cfe593aed407f0e1c35408c Mon Sep 17 00:00:00 2001 From: Jiahao Xu Date: Wed, 24 Jan 2024 17:19:32 +0800 Subject: LoongArch: Fix incorrect return type for frecipe/frsqrte intrinsic functions gcc/ChangeLog: * config/loongarch/larchintrin.h (__frecipe_s): Update function return type. (__frecipe_d): Ditto. (__frsqrte_s): Ditto. (__frsqrte_d): Ditto. gcc/testsuite/ChangeLog: * gcc.target/loongarch/larch-frecipe-intrinsic.c: New test. --- gcc/config/loongarch/larchintrin.h | 16 ++++++------ .../gcc.target/loongarch/larch-frecipe-intrinsic.c | 30 ++++++++++++++++++++++ 2 files changed, 38 insertions(+), 8 deletions(-) create mode 100644 gcc/testsuite/gcc.target/loongarch/larch-frecipe-intrinsic.c (limited to 'gcc') diff --git a/gcc/config/loongarch/larchintrin.h b/gcc/config/loongarch/larchintrin.h index 7692415..ff2c9f4 100644 --- a/gcc/config/loongarch/larchintrin.h +++ b/gcc/config/loongarch/larchintrin.h @@ -336,38 +336,38 @@ __iocsrwr_d (unsigned long int _1, unsigned int _2) #ifdef __loongarch_frecipe /* Assembly instruction format: fd, fj. */ /* Data types in instruction templates: SF, SF. */ -extern __inline void +extern __inline float __attribute__ ((__gnu_inline__, __always_inline__, __artificial__)) __frecipe_s (float _1) { - __builtin_loongarch_frecipe_s ((float) _1); + return (float) __builtin_loongarch_frecipe_s ((float) _1); } /* Assembly instruction format: fd, fj. */ /* Data types in instruction templates: DF, DF. */ -extern __inline void +extern __inline double __attribute__ ((__gnu_inline__, __always_inline__, __artificial__)) __frecipe_d (double _1) { - __builtin_loongarch_frecipe_d ((double) _1); + return (double) __builtin_loongarch_frecipe_d ((double) _1); } /* Assembly instruction format: fd, fj. */ /* Data types in instruction templates: SF, SF. */ -extern __inline void +extern __inline float __attribute__ ((__gnu_inline__, __always_inline__, __artificial__)) __frsqrte_s (float _1) { - __builtin_loongarch_frsqrte_s ((float) _1); + return (float) __builtin_loongarch_frsqrte_s ((float) _1); } /* Assembly instruction format: fd, fj. */ /* Data types in instruction templates: DF, DF. */ -extern __inline void +extern __inline double __attribute__ ((__gnu_inline__, __always_inline__, __artificial__)) __frsqrte_d (double _1) { - __builtin_loongarch_frsqrte_d ((double) _1); + return (double) __builtin_loongarch_frsqrte_d ((double) _1); } #endif diff --git a/gcc/testsuite/gcc.target/loongarch/larch-frecipe-intrinsic.c b/gcc/testsuite/gcc.target/loongarch/larch-frecipe-intrinsic.c new file mode 100644 index 0000000..6ce2bde --- /dev/null +++ b/gcc/testsuite/gcc.target/loongarch/larch-frecipe-intrinsic.c @@ -0,0 +1,30 @@ +/* Test intrinsics for frecipe.{s/d} and frsqrte.{s/d} instructions */ +/* { dg-do compile } */ +/* { dg-options "-mfrecipe -O2" } */ +/* { dg-final { scan-assembler-times "test_frecipe_s:.*frecipe\\.s.*test_frecipe_s" 1 } } */ +/* { dg-final { scan-assembler-times "test_frecipe_d:.*frecipe\\.d.*test_frecipe_d" 1 } } */ +/* { dg-final { scan-assembler-times "test_frsqrte_s:.*frsqrte\\.s.*test_frsqrte_s" 1 } } */ +/* { dg-final { scan-assembler-times "test_frsqrte_d:.*frsqrte\\.d.*test_frsqrte_d" 1 } } */ + +#include + +float +test_frecipe_s (float _1) +{ + return __frecipe_s (_1); +} +double +test_frecipe_d (double _1) +{ + return __frecipe_d (_1); +} +float +test_frsqrte_s (float _1) +{ + return __frsqrte_s (_1); +} +double +test_frsqrte_d (double _1) +{ + return __frsqrte_d (_1); +} -- cgit v1.1 From 22622a5a314114fa2c6033fd7b4f7a2060e55284 Mon Sep 17 00:00:00 2001 From: Juzhe-Zhong Date: Thu, 1 Feb 2024 20:24:48 +0800 Subject: RISC-V: Remove vsetvl_pre bogus instructions in VSETVL PASS I realize there is a RTL regression between GCC-14 and GCC-13. https://godbolt.org/z/Ga7K6MqaT GCC-14: (insn 9 13 31 2 (set (reg:DI 15 a5 [138]) (unspec:DI [ (const_int 64 [0x40]) ] UNSPEC_VLMAX)) "/app/example.c":5:15 2566 {vlmax_avldi} (expr_list:REG_EQUIV (unspec:DI [ (const_int 64 [0x40]) ] UNSPEC_VLMAX) (nil))) (insn 31 9 10 2 (parallel [ (set (reg:DI 15 a5 [138]) (unspec:DI [ (reg:DI 0 zero) (const_int 32 [0x20]) (const_int 7 [0x7]) (const_int 1 [0x1]) repeated x2 ] UNSPEC_VSETVL)) (set (reg:SI 66 vl) (unspec:SI [ (reg:DI 0 zero) (const_int 32 [0x20]) (const_int 7 [0x7]) ] UNSPEC_VSETVL)) (set (reg:SI 67 vtype) (unspec:SI [ (const_int 32 [0x20]) (const_int 7 [0x7]) (const_int 1 [0x1]) repeated x2 ] UNSPEC_VSETVL)) ]) "/app/example.c":5:15 3281 {vsetvldi} (nil)) GCC-13: (insn 10 7 26 2 (set (reg/f:DI 11 a1 [139]) (plus:DI (reg:DI 11 a1 [142]) (const_int 800 [0x320]))) "/app/example.c":6:32 5 {adddi3} (nil)) (insn 26 10 9 2 (parallel [ (set (reg:DI 15 a5) (unspec:DI [ (reg:DI 0 zero) (const_int 32 [0x20]) (const_int 7 [0x7]) (const_int 1 [0x1]) repeated x2 ] UNSPEC_VSETVL)) (set (reg:SI 66 vl) (unspec:SI [ (reg:DI 0 zero) (const_int 32 [0x20]) (const_int 7 [0x7]) ] UNSPEC_VSETVL)) (set (reg:SI 67 vtype) (unspec:SI [ (const_int 32 [0x20]) (const_int 7 [0x7]) (const_int 1 [0x1]) repeated x2 ] UNSPEC_VSETVL)) ]) "/app/example.c":5:15 792 {vsetvldi} (nil)) GCC-13 doesn't have: (insn 9 13 31 2 (set (reg:DI 15 a5 [138]) (unspec:DI [ (const_int 64 [0x40]) ] UNSPEC_VLMAX)) "/app/example.c":5:15 2566 {vlmax_avldi} (expr_list:REG_EQUIV (unspec:DI [ (const_int 64 [0x40]) ] UNSPEC_VLMAX) (nil))) vsetvl_pre doesn't emit any assembler which is just used for occupying scalar register. It should be removed in VSETVL PASS. Tested on both RV32 and RV64 no regression. gcc/ChangeLog: * config/riscv/riscv-vsetvl.cc (vsetvl_pre_insn_p): New function. (pre_vsetvl::cleaup): Remove vsetvl_pre. (pre_vsetvl::remove_vsetvl_pre_insns): New function. gcc/testsuite/ChangeLog: * gcc.target/riscv/rvv/vsetvl/vsetvl_pre-1.c: New test. --- gcc/config/riscv/riscv-vsetvl.cc | 64 ++++++++++++++++++++++ .../gcc.target/riscv/rvv/vsetvl/vsetvl_pre-1.c | 12 ++++ 2 files changed, 76 insertions(+) create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/vsetvl/vsetvl_pre-1.c (limited to 'gcc') diff --git a/gcc/config/riscv/riscv-vsetvl.cc b/gcc/config/riscv/riscv-vsetvl.cc index cec8623..2c0dcdf 100644 --- a/gcc/config/riscv/riscv-vsetvl.cc +++ b/gcc/config/riscv/riscv-vsetvl.cc @@ -315,6 +315,48 @@ vsetvl_insn_p (rtx_insn *rinsn) || INSN_CODE (rinsn) == CODE_FOR_vsetvlsi); } +/* Return true if it is the bogus vsetvl_pre instruction: + + (define_insn "@vlmax_avl" + [(set (match_operand:P 0 "register_operand" "=r") + (unspec:P [(match_operand:P 1 "const_int_operand" "i")] UNSPEC_VLMAX))] + "TARGET_VECTOR" + "" + [(set_attr "type" "vsetvl_pre")]) + + As described above, it's the bogus instruction which doesn't any assembler + and should be removed eventually. It's used for occupying a scalar register + for VLMAX avl RVV instruction before register allocation. + + Before RA: + + ... + vsetvl_pre (set r136) + vadd.vv (use r136 with VLMAX avl) + ... + + After RA: + + ... + vsetvl_pre (set a5) + vadd.vv (use r136 with VLMAX avl) + ... + + VSETVL PASS: + + ... + vsetvl_pre (set a5) ---> removed. + vsetvl a5,zero,... ---> Inserted. + vadd.vv + ... +*/ +static bool +vsetvl_pre_insn_p (rtx_insn *rinsn) +{ + return recog_memoized (rinsn) >= 0 + && get_attr_type (rinsn) == TYPE_VSETVL_PRE; +} + /* Return true if it is vsetvl zero, rs1. */ static bool vsetvl_discard_result_insn_p (rtx_insn *rinsn) @@ -2376,6 +2418,7 @@ public: void cleaup (); void remove_avl_operand (); void remove_unused_dest_operand (); + void remove_vsetvl_pre_insns (); void dump (FILE *file, const char *title) const { @@ -3307,6 +3350,7 @@ pre_vsetvl::cleaup () { remove_avl_operand (); remove_unused_dest_operand (); + remove_vsetvl_pre_insns (); } void @@ -3374,6 +3418,26 @@ pre_vsetvl::remove_unused_dest_operand () } } +/* Remove all bogus vsetvl_pre instructions. */ +void +pre_vsetvl::remove_vsetvl_pre_insns () +{ + basic_block cfg_bb; + rtx_insn *rinsn; + FOR_ALL_BB_FN (cfg_bb, cfun) + FOR_BB_INSNS (cfg_bb, rinsn) + if (NONDEBUG_INSN_P (rinsn) && vsetvl_pre_insn_p (rinsn)) + { + if (dump_file) + { + fprintf (dump_file, " Eliminate vsetvl_pre insn %d:\n", + INSN_UID (rinsn)); + print_rtl_single (dump_file, rinsn); + } + remove_insn (rinsn); + } +} + const pass_data pass_data_vsetvl = { RTL_PASS, /* type */ "vsetvl", /* name */ diff --git a/gcc/testsuite/gcc.target/riscv/rvv/vsetvl/vsetvl_pre-1.c b/gcc/testsuite/gcc.target/riscv/rvv/vsetvl/vsetvl_pre-1.c new file mode 100644 index 0000000..98eacc1 --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/rvv/vsetvl/vsetvl_pre-1.c @@ -0,0 +1,12 @@ +/* { dg-do compile } */ +/* { dg-options "--param=riscv-autovec-preference=scalable -march=rv64gcv -mabi=lp64d -O3 -fdump-rtl-vsetvl-details" } */ + +#include "riscv_vector.h" +void +foo (int *in, int *out) +{ + vint32mf2_t v = *(vint32mf2_t *) (in + 100); + *(vint32mf2_t *) (out + 200) = v; +} + +/* { dg-final { scan-rtl-dump "Eliminate vsetvl_pre" "vsetvl" { target { no-opts "-O0" } } } } */ -- cgit v1.1 From e0701f8f7b6dcddb299eb5345e510cf9ea419150 Mon Sep 17 00:00:00 2001 From: Pan Li Date: Wed, 31 Jan 2024 09:50:15 +0800 Subject: RISC-V: Cleanup the comments for the psabi This patch would like to cleanup some comments which are out of date or incorrect. gcc/ChangeLog: * config/riscv/riscv.cc (riscv_get_arg_info): Cleanup comments. (riscv_pass_by_reference): Ditto. (riscv_fntype_abi): Ditto. Signed-off-by: Pan Li --- gcc/config/riscv/riscv.cc | 21 +++++++++------------ 1 file changed, 9 insertions(+), 12 deletions(-) (limited to 'gcc') diff --git a/gcc/config/riscv/riscv.cc b/gcc/config/riscv/riscv.cc index cead76f..d7cdd71 100644 --- a/gcc/config/riscv/riscv.cc +++ b/gcc/config/riscv/riscv.cc @@ -5084,8 +5084,7 @@ riscv_get_arg_info (struct riscv_arg_info *info, const CUMULATIVE_ARGS *cum, info->gpr_offset = cum->num_gprs; info->fpr_offset = cum->num_fprs; - /* When disable vector_abi or scalable vector argument is anonymous, this - argument is passed by reference. */ + /* Passed by reference when the scalable vector argument is anonymous. */ if (riscv_v_ext_mode_p (mode) && !named) return NULL_RTX; @@ -5282,8 +5281,9 @@ riscv_pass_by_reference (cumulative_args_t cum_v, const function_arg_info &arg) so we can avoid the call to riscv_get_arg_info in this case. */ if (cum != NULL) { - /* Don't pass by reference if we can use a floating-point register. */ riscv_get_arg_info (&info, cum, arg.mode, arg.type, arg.named, false); + + /* Don't pass by reference if we can use a floating-point register. */ if (info.num_fprs) return false; @@ -5296,9 +5296,9 @@ riscv_pass_by_reference (cumulative_args_t cum_v, const function_arg_info &arg) return false; } - /* When vector abi disabled(without --param=riscv-vector-abi option) or - scalable vector argument is anonymous or cannot be passed through vector - registers, this argument is passed by reference. */ + /* Passed by reference when: + 1. The scalable vector argument is anonymous. + 2. Args cannot be passed through vector registers. */ if (riscv_v_ext_mode_p (arg.mode)) return true; @@ -5409,12 +5409,9 @@ riscv_arguments_is_vector_type_p (const_tree fntype) static const predefined_function_abi & riscv_fntype_abi (const_tree fntype) { - /* Implementing an experimental vector calling convention, the proposal - can be viewed at the bellow link: - https://github.com/riscv-non-isa/riscv-elf-psabi-doc/pull/389 - - You can enable this feature via the `--param=riscv-vector-abi` compiler - option. */ + /* Implement the vector calling convention. For more details please + reference the below link. + https://github.com/riscv-non-isa/riscv-elf-psabi-doc/pull/389 */ if (riscv_return_value_is_vector_type_p (fntype) || riscv_arguments_is_vector_type_p (fntype)) return riscv_v_abi (); -- cgit v1.1 From 0b786ff38ab398087820d91241e030a28c451df9 Mon Sep 17 00:00:00 2001 From: Jason Merrill Date: Thu, 1 Feb 2024 16:54:39 -0500 Subject: c++: variable template array of unknown bound [PR113638] When we added variable templates, we didn't extend the VAR_HAD_UNKNOWN_BOUND handling for class template static data members to handle them as well. PR c++/113638 gcc/cp/ChangeLog: * cp-tree.h: Adjust comment. * pt.cc (instantiate_template): Set VAR_HAD_UNKNOWN_BOUND for variable template. gcc/testsuite/ChangeLog: * g++.dg/cpp1y/var-templ-array1.C: New test. --- gcc/cp/cp-tree.h | 2 +- gcc/cp/pt.cc | 13 ++++++++++--- gcc/testsuite/g++.dg/cpp1y/var-templ-array1.C | 7 +++++++ 3 files changed, 18 insertions(+), 4 deletions(-) create mode 100644 gcc/testsuite/g++.dg/cpp1y/var-templ-array1.C (limited to 'gcc') diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h index f46b448..969c723 100644 --- a/gcc/cp/cp-tree.h +++ b/gcc/cp/cp-tree.h @@ -3251,7 +3251,7 @@ struct GTY(()) lang_decl { #define DECL_CONV_FN_TYPE(FN) \ TREE_TYPE ((gcc_checking_assert (DECL_CONV_FN_P (FN)), DECL_NAME (FN))) -/* Nonzero if NODE, a static data member, was declared in its class as an +/* Nonzero if NODE, a templated variable, was declared as an array of unknown bound. */ #define VAR_HAD_UNKNOWN_BOUND(NODE) \ (DECL_LANG_SPECIFIC (VAR_DECL_CHECK (NODE)) \ diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc index 16febb1..9d30a27 100644 --- a/gcc/cp/pt.cc +++ b/gcc/cp/pt.cc @@ -22105,9 +22105,16 @@ instantiate_template (tree tmpl, tree orig_args, tsubst_flags_t complain) DECL_TI_TEMPLATE (fndecl) = tmpl; DECL_TI_ARGS (fndecl) = targ_ptr; if (VAR_P (pattern)) - /* Now that we we've formed this variable template specialization, - remember the result of most_specialized_partial_spec for it. */ - TI_PARTIAL_INFO (DECL_TEMPLATE_INFO (fndecl)) = partial_ti; + { + /* Now that we we've formed this variable template specialization, + remember the result of most_specialized_partial_spec for it. */ + TI_PARTIAL_INFO (DECL_TEMPLATE_INFO (fndecl)) = partial_ti; + + /* And remember if the variable was declared with []. */ + if (TREE_CODE (TREE_TYPE (fndecl)) == ARRAY_TYPE + && TYPE_DOMAIN (TREE_TYPE (fndecl)) == NULL_TREE) + SET_VAR_HAD_UNKNOWN_BOUND (fndecl); + } fndecl = register_specialization (fndecl, gen_tmpl, targ_ptr, false, hash); if (fndecl == error_mark_node) diff --git a/gcc/testsuite/g++.dg/cpp1y/var-templ-array1.C b/gcc/testsuite/g++.dg/cpp1y/var-templ-array1.C new file mode 100644 index 0000000..b0ff7e7 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp1y/var-templ-array1.C @@ -0,0 +1,7 @@ +// PR c++/113638 +// { dg-do compile { target c++14 } } + +template +constexpr int my_array[]{Is...}; +constexpr auto t1 = my_array<2>; +static_assert(sizeof(my_array<1>) == sizeof(int) * 1, ""); -- cgit v1.1 From f4998609908e4926fc095ce97cb84b187294fd1d Mon Sep 17 00:00:00 2001 From: Jason Merrill Date: Thu, 1 Feb 2024 17:23:53 -0500 Subject: c++: no_unique_address and constexpr [PR112439] Here, because we don't build a CONSTRUCTOR for an empty base, we were wrongly marking the Foo CONSTRUCTOR as complete after initializing the Empty member. Fixed by checking empty_base here as well. PR c++/112439 gcc/cp/ChangeLog: * constexpr.cc (cxx_eval_store_expression): Check empty_base before marking a CONSTRUCTOR readonly. gcc/testsuite/ChangeLog: * g++.dg/cpp2a/no_unique_address15.C: New test. --- gcc/cp/constexpr.cc | 1 + gcc/testsuite/g++.dg/cpp2a/no_unique_address15.C | 19 +++++++++++++++++++ 2 files changed, 20 insertions(+) create mode 100644 gcc/testsuite/g++.dg/cpp2a/no_unique_address15.C (limited to 'gcc') diff --git a/gcc/cp/constexpr.cc b/gcc/cp/constexpr.cc index 6350fe154..2ebb147 100644 --- a/gcc/cp/constexpr.cc +++ b/gcc/cp/constexpr.cc @@ -6694,6 +6694,7 @@ cxx_eval_store_expression (const constexpr_ctx *ctx, tree t, object. Make a note of this fact by marking the CONSTRUCTOR TREE_READONLY. */ if (TREE_CODE (t) == INIT_EXPR + && !empty_base && TREE_CODE (*valp) == CONSTRUCTOR && TYPE_READONLY (type)) { diff --git a/gcc/testsuite/g++.dg/cpp2a/no_unique_address15.C b/gcc/testsuite/g++.dg/cpp2a/no_unique_address15.C new file mode 100644 index 0000000..3e7cf08 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp2a/no_unique_address15.C @@ -0,0 +1,19 @@ +// PR c++/112439 +// { dg-do compile { target c++14 } } + +struct Empty {}; + +class Foo { +public: + constexpr Foo(int x, Empty y, int z) : a(x), b(y) + { + c = z; + } + +private: + int a{}; + [[no_unique_address]] Empty b{}; + [[no_unique_address]] int c{}; +}; + +constexpr Foo r{1, {}, 3}; -- cgit v1.1 From 63f0907bbbc941f4aca5f44655af02675a5b47f5 Mon Sep 17 00:00:00 2001 From: Rainer Orth Date: Fri, 2 Feb 2024 09:33:16 +0100 Subject: testsuite: i386: Fix gcc.target/i386/apx-ndd-cmov.c on Solaris/x86 gcc.target/i386/apx-ndd-cmov.c FAILs on 64-bit Solaris/x86 with the native assembler: FAIL: gcc.target/i386/apx-ndd-cmov.c scan-assembler-times cmove[^\\n\\r]*, %eax 1 FAIL: gcc.target/i386/apx-ndd-cmov.c scan-assembler-times cmovge[^\\n\\r]*, %eax 1 The gas vs. as difference is - cmove c+4(%rip), %esi, %eax + cmovl.e c+4(%rip), %esi, %eax - cmovge %ecx, %edx, %eax + cmovl.ge %ecx, %edx, %eax This patch accounts for both forms. Tested on i386-pc-solaris2.11 (as and gas) and i686-pc-linux-gnu. 2024-02-01 Rainer Orth gcc/testsuite: * gcc.target/i386/apx-ndd-cmov.c (scan-assembler-times): Allow for cmovl.e, cmovl.ge. --- gcc/testsuite/gcc.target/i386/apx-ndd-cmov.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'gcc') diff --git a/gcc/testsuite/gcc.target/i386/apx-ndd-cmov.c b/gcc/testsuite/gcc.target/i386/apx-ndd-cmov.c index 459dc96..1406db5 100644 --- a/gcc/testsuite/gcc.target/i386/apx-ndd-cmov.c +++ b/gcc/testsuite/gcc.target/i386/apx-ndd-cmov.c @@ -1,7 +1,7 @@ /* { dg-do compile { target { ! ia32 } } } */ /* { dg-options "-O2 -m64 -mapxf" } */ -/* { dg-final { scan-assembler-times "cmove\[^\n\r]*, %eax" 1 } } */ -/* { dg-final { scan-assembler-times "cmovge\[^\n\r]*, %eax" 1 } } */ +/* { dg-final { scan-assembler-times "cmov(l\.)?e\[^\n\r]*, %eax" 1 } } */ +/* { dg-final { scan-assembler-times "cmov(l\.)?ge\[^\n\r]*, %eax" 1 } } */ unsigned int c[4]; -- cgit v1.1 From 8939854ad67fbc6c650370ab28d344bbe51f9bfd Mon Sep 17 00:00:00 2001 From: Rainer Orth Date: Fri, 2 Feb 2024 09:46:50 +0100 Subject: testsuite: i386: Fix gcc.target/i386/pieces-memcpy-7.c etc. on Solaris/x86 gcc.target/i386/pieces-memcpy-7.c etc. FAIL on 32-bit Solaris/x86: FAIL: gcc.target/i386/pieces-memcpy-7.c scan-assembler-not %[re]bp FAIL: gcc.target/i386/pieces-memcpy-8.c scan-assembler-not %[re]bp FAIL: gcc.target/i386/pieces-memcpy-9.c scan-assembler-not %[re]bp FAIL: gcc.target/i386/pieces-memset-36.c scan-assembler-not %[re]bp FAIL: gcc.target/i386/pieces-memset-40.c scan-assembler-not %[re]bp FAIL: gcc.target/i386/pieces-memset-9.c scan-assembler-not %[re]bp The problem is that the tests assume -mno-stackrealign while 32-bit Solaris/x86 defaults to -mstackrealign. Fixed by explicitly specifying -mno-stackrealign. Tested on i386-pc-solaris2.11 and i686-pc-linux-gnu. 2024-02-01 Rainer Orth gcc/testsuite: * gcc.target/i386/pieces-memcpy-7.c (dg-additional-options): Add -mno-stackrealign. * gcc.target/i386/pieces-memcpy-8.c: Likewise. * gcc.target/i386/pieces-memcpy-9.c: Likewise. * gcc.target/i386/pieces-memset-36.c: Likewise. * gcc.target/i386/pieces-memset-40.c: Likewise. * gcc.target/i386/pieces-memset-9.c: Likewise. --- gcc/testsuite/gcc.target/i386/pieces-memcpy-7.c | 4 ++-- gcc/testsuite/gcc.target/i386/pieces-memcpy-8.c | 4 ++-- gcc/testsuite/gcc.target/i386/pieces-memcpy-9.c | 4 ++-- gcc/testsuite/gcc.target/i386/pieces-memset-36.c | 4 ++-- gcc/testsuite/gcc.target/i386/pieces-memset-40.c | 4 ++-- gcc/testsuite/gcc.target/i386/pieces-memset-9.c | 4 ++-- 6 files changed, 12 insertions(+), 12 deletions(-) (limited to 'gcc') diff --git a/gcc/testsuite/gcc.target/i386/pieces-memcpy-7.c b/gcc/testsuite/gcc.target/i386/pieces-memcpy-7.c index 64fd8b4..8efa1d4 100644 --- a/gcc/testsuite/gcc.target/i386/pieces-memcpy-7.c +++ b/gcc/testsuite/gcc.target/i386/pieces-memcpy-7.c @@ -1,7 +1,7 @@ /* { dg-do compile } */ /* { dg-options "-O2 -mno-avx -msse2 -mtune=generic" } */ -/* Cope with --enable-frame-pointer. */ -/* { dg-additional-options "-fomit-frame-pointer" } */ +/* Cope with --enable-frame-pointer, Solaris/x86 -mstackrealign default. */ +/* { dg-additional-options "-fomit-frame-pointer -mno-stackrealign" } */ void foo (int a1, int a2, int a3, int a4, int a5, int a6, char *dst, char *src) diff --git a/gcc/testsuite/gcc.target/i386/pieces-memcpy-8.c b/gcc/testsuite/gcc.target/i386/pieces-memcpy-8.c index fc60c46..3c86c49 100644 --- a/gcc/testsuite/gcc.target/i386/pieces-memcpy-8.c +++ b/gcc/testsuite/gcc.target/i386/pieces-memcpy-8.c @@ -1,7 +1,7 @@ /* { dg-do compile } */ /* { dg-options "-O2 -mno-avx2 -mavx -mtune=generic" } */ -/* Cope with --enable-frame-pointer. */ -/* { dg-additional-options "-fomit-frame-pointer" } */ +/* Cope with --enable-frame-pointer, Solaris/x86 -mstackrealign default. */ +/* { dg-additional-options "-fomit-frame-pointer -mno-stackrealign" } */ void foo (int a1, int a2, int a3, int a4, int a5, int a6, char *dst, char *src) diff --git a/gcc/testsuite/gcc.target/i386/pieces-memcpy-9.c b/gcc/testsuite/gcc.target/i386/pieces-memcpy-9.c index 62fcb6f..a332d5a 100644 --- a/gcc/testsuite/gcc.target/i386/pieces-memcpy-9.c +++ b/gcc/testsuite/gcc.target/i386/pieces-memcpy-9.c @@ -1,7 +1,7 @@ /* { dg-do compile } */ /* { dg-options "-O2 -mavx512f -mtune=generic" } */ -/* Cope with --enable-frame-pointer. */ -/* { dg-additional-options "-fomit-frame-pointer" } */ +/* Cope with --enable-frame-pointer, Solaris/x86 -mstackrealign default. */ +/* { dg-additional-options "-fomit-frame-pointer -mno-stackrealign" } */ void foo (int a1, int a2, int a3, int a4, int a5, int a6, char *dst, char *src) diff --git a/gcc/testsuite/gcc.target/i386/pieces-memset-36.c b/gcc/testsuite/gcc.target/i386/pieces-memset-36.c index d1bbfa2..18b2dcc 100644 --- a/gcc/testsuite/gcc.target/i386/pieces-memset-36.c +++ b/gcc/testsuite/gcc.target/i386/pieces-memset-36.c @@ -1,7 +1,7 @@ /* { dg-do compile } */ /* { dg-options "-O2 -mno-avx512f -mavx2 -mtune=generic" } */ -/* Cope with --enable-frame-pointer. */ -/* { dg-additional-options "-fomit-frame-pointer" } */ +/* Cope with --enable-frame-pointer, Solaris/x86 -mstackrealign default. */ +/* { dg-additional-options "-fomit-frame-pointer -mno-stackrealign" } */ extern char *dst; diff --git a/gcc/testsuite/gcc.target/i386/pieces-memset-40.c b/gcc/testsuite/gcc.target/i386/pieces-memset-40.c index 37a9dcc..86358c9 100644 --- a/gcc/testsuite/gcc.target/i386/pieces-memset-40.c +++ b/gcc/testsuite/gcc.target/i386/pieces-memset-40.c @@ -1,7 +1,7 @@ /* { dg-do compile } */ /* { dg-options "-O2 -mno-avx512f -mavx2 -mtune=sandybridge" } */ -/* Cope with --enable-frame-pointer. */ -/* { dg-additional-options "-fomit-frame-pointer" } */ +/* Cope with --enable-frame-pointer, Solaris/x86 -mstackrealign default. */ +/* { dg-additional-options "-fomit-frame-pointer -mno-stackrealign" } */ extern char *dst; diff --git a/gcc/testsuite/gcc.target/i386/pieces-memset-9.c b/gcc/testsuite/gcc.target/i386/pieces-memset-9.c index d64cf6b..8a6f095 100644 --- a/gcc/testsuite/gcc.target/i386/pieces-memset-9.c +++ b/gcc/testsuite/gcc.target/i386/pieces-memset-9.c @@ -1,7 +1,7 @@ /* { dg-do compile } */ /* { dg-options "-O2 -march=x86-64 -mavx512f -mtune=generic" } */ -/* Cope with --enable-frame-pointer. */ -/* { dg-additional-options "-fomit-frame-pointer" } */ +/* Cope with --enable-frame-pointer, Solaris/x86 -mstackrealign default. */ +/* { dg-additional-options "-fomit-frame-pointer -mno-stackrealign" } */ extern char *dst; -- cgit v1.1 From 74489c19070703361acc20bc172f304cae845a96 Mon Sep 17 00:00:00 2001 From: Juzhe-Zhong Date: Thu, 1 Feb 2024 23:45:50 +0800 Subject: RISC-V: Allow LICM hoist POLY_INT configuration code sequence Realize in recent benchmark evaluation (coremark-pro zip-test): vid.v v2 vmv.v.i v5,0 .L9: vle16.v v3,0(a4) vrsub.vx v4,v2,a6 ---> LICM failed to hoist it outside the loop. The root cause is: (insn 56 47 57 4 (set (subreg:DI (reg:HI 220) 0) (reg:DI 223)) "rvv.c":11:9 208 {*movdi_64bit} -> Its result used by the following vrsub.vx then supress the hoist of the vrsub.vx (nil)) (insn 57 56 59 4 (set (reg:RVVMF2HI 216) (if_then_else:RVVMF2HI (unspec:RVVMF32BI [ (const_vector:RVVMF32BI repeat [ (const_int 1 [0x1]) ]) (reg:DI 350) (const_int 2 [0x2]) repeated x2 (const_int 1 [0x1]) (reg:SI 66 vl) (reg:SI 67 vtype) ] UNSPEC_VPREDICATE) (minus:RVVMF2HI (vec_duplicate:RVVMF2HI (reg:HI 220)) (reg:RVVMF2HI 217)) (unspec:RVVMF2HI [ (reg:DI 0 zero) ] UNSPEC_VUNDEF))) "rvv.c":11:9 6938 {pred_subrvvmf2hi_reverse_scalar} (expr_list:REG_DEAD (reg:HI 220) (nil))) This patch fixes it generate (set (reg:HI) (subreg:HI (reg:DI))) instead of (set (subreg:DI (reg:DI)) (reg:DI)). After this patch: vid.v v2 vrsub.vx v2,v2,a7 vmv.v.i v4,0 .L3: vle16.v v3,0(a4) Tested on both RV32 and RV64 no regression. gcc/ChangeLog: * config/riscv/riscv.cc (riscv_legitimize_move): Fix poly_int dest generation. gcc/testsuite/ChangeLog: * gcc.target/riscv/rvv/autovec/poly_licm-1.c: New test. * gcc.target/riscv/rvv/autovec/poly_licm-2.c: New test. --- gcc/config/riscv/riscv.cc | 9 ++++---- .../gcc.target/riscv/rvv/autovec/poly_licm-1.c | 18 +++++++++++++++ .../gcc.target/riscv/rvv/autovec/poly_licm-2.c | 27 ++++++++++++++++++++++ 3 files changed, 50 insertions(+), 4 deletions(-) create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/autovec/poly_licm-1.c create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/autovec/poly_licm-2.c (limited to 'gcc') diff --git a/gcc/config/riscv/riscv.cc b/gcc/config/riscv/riscv.cc index d7cdd71..3230fe1 100644 --- a/gcc/config/riscv/riscv.cc +++ b/gcc/config/riscv/riscv.cc @@ -2728,16 +2728,17 @@ riscv_legitimize_move (machine_mode mode, rtx dest, rtx src) (const_poly_int:HI [m, n]) (const_poly_int:SI [m, n]). */ rtx tmp = gen_reg_rtx (Pmode); - riscv_legitimize_poly_move (Pmode, gen_lowpart (Pmode, dest), tmp, - src); + rtx tmp2 = gen_reg_rtx (Pmode); + riscv_legitimize_poly_move (Pmode, tmp2, tmp, src); + emit_move_insn (dest, gen_lowpart (mode, tmp2)); } else { /* In RV32 system, handle (const_poly_int:SI [m, n]) (const_poly_int:DI [m, n]). In RV64 system, handle (const_poly_int:DI [m, n]). - FIXME: Maybe we could gen SImode in RV32 and then sign-extend to DImode, - the offset should not exceed 4GiB in general. */ + FIXME: Maybe we could gen SImode in RV32 and then sign-extend to + DImode, the offset should not exceed 4GiB in general. */ rtx tmp = gen_reg_rtx (mode); riscv_legitimize_poly_move (mode, dest, tmp, src); } diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/poly_licm-1.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/poly_licm-1.c new file mode 100644 index 0000000..b7da65f --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/poly_licm-1.c @@ -0,0 +1,18 @@ +/* { dg-do compile } */ +/* { dg-options "-march=rv64gcv -mabi=lp64d -O3 -fno-schedule-insns -fno-schedule-insns2" } */ + +extern int wsize; + +typedef unsigned short Posf; +#define NIL 0 + +void foo (Posf *p) +{ + register unsigned n, m; + do { + m = *--p; + *p = (Posf)(m >= wsize ? m-wsize : NIL); + } while (--n); +} + +/* { dg-final { scan-assembler-times {vid\.v\s+v[0-9]+\s+addi\s+\s*[a-x0-9]+,\s*[a-x0-9]+,\s*-1\s+vrsub\.vx\s+} 1 } } */ diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/poly_licm-2.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/poly_licm-2.c new file mode 100644 index 0000000..ffb3c63 --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/poly_licm-2.c @@ -0,0 +1,27 @@ +/* { dg-do compile } */ +/* { dg-options "-march=rv64gcv -mabi=lp64d -O3 -fno-schedule-insns -fno-schedule-insns2" } */ + +typedef unsigned short uint16_t; + +void AAA (uint16_t *x, uint16_t *y, unsigned wsize, unsigned count) +{ + unsigned m = 0, n = count; + register uint16_t *p; + + p = x; + + do { + m = *--p; + *p = (uint16_t)(m >= wsize ? m-wsize : 0); + } while (--n); + + n = wsize; + p = y; + + do { + m = *--p; + *p = (uint16_t)(m >= wsize ? m-wsize : 0); + } while (--n); +} + +/* { dg-final { scan-assembler-times {vid\.v\s+v[0-9]+\s+vrsub\.vx\s+} 2 } } */ -- cgit v1.1 From e439c7827f5c5723fdd7df9c5fac55319db204af Mon Sep 17 00:00:00 2001 From: Iain Sandoe Date: Wed, 24 Jan 2024 08:05:30 +0000 Subject: testsuite, gfortran: Update link flags [PR112862]. The regressions here are caused by two issues: 1. In some cases there is no generated runpath for libatomic 2. In other cases there are duplicate paths. This patch simplifies the addition of the options in the main gfortran exp and removes the duplicates elewhere. We need to add options to locate libgfortran and the dependent libs libquadmath (supporting REAL*16) and libatomic (supporting operations used by coarrays). Usually '-L' options are added to point to the relevant directories for the uninstalled libraries. In cases where libraries are available as both shared and convenience some additional checks are made. For some targets -static-xxxx options are handled by specs substitution and need a '-B' option rather than '-L'. For Darwin, when embedded runpaths are in use (the default for all versions after macOS 10.11), '-B' is also needed to provide the runpath. When '-B' is used, this results in a '-L' for each path that exists (so that appending a '-L' as well is a needless duplicate). There are also cases where tools warn for duplicates, leading to spurious fails. PR target/112862 gcc/testsuite/ChangeLog: * gfortran.dg/coarray/caf.exp: Remove duplicate additions of libatomic handling. * gfortran.dg/dg.exp: Likewise. * lib/gfortran.exp: Decide on whether to present -B or -L to reference the paths to uninstalled libgfortran, libqadmath and libatomic and use that to generate the link flags. --- gcc/testsuite/gfortran.dg/coarray/caf.exp | 16 +------ gcc/testsuite/gfortran.dg/dg.exp | 20 --------- gcc/testsuite/lib/gfortran.exp | 73 +++++++++++++++++++++---------- 3 files changed, 51 insertions(+), 58 deletions(-) (limited to 'gcc') diff --git a/gcc/testsuite/gfortran.dg/coarray/caf.exp b/gcc/testsuite/gfortran.dg/coarray/caf.exp index dae46bd..31c13cd 100644 --- a/gcc/testsuite/gfortran.dg/coarray/caf.exp +++ b/gcc/testsuite/gfortran.dg/coarray/caf.exp @@ -70,18 +70,6 @@ proc dg-compile-aux-modules { args } { } } -# Add -latomic only where supported. Assume built-in support elsewhere. -set maybe_atomic_lib "" -if [check_effective_target_libatomic_available] { - if ![is_remote host] { - if [info exists TOOL_OPTIONS] { - set maybe_atomic_lib "[atomic_link_flags [get_multilibs ${TOOL_OPTIONS}]]" - } else { - set maybe_atomic_lib "[atomic_link_flags [get_multilibs]]" - } - } -} - # Main loop. foreach test [lsort [glob -nocomplain $srcdir/$subdir/*.\[fF\]{,90,95,03,08} ]] { # If we're only testing specific files and this isn't one of them, skip it. @@ -105,14 +93,14 @@ foreach test [lsort [glob -nocomplain $srcdir/$subdir/*.\[fF\]{,90,95,03,08} ]] foreach flags $option_list { verbose "Testing $nshort (single), $flags" 1 set gfortran_aux_module_flags "-fcoarray=single $flags" - dg-test $test "-fcoarray=single $flags" $maybe_atomic_lib + dg-test $test "-fcoarray=single $flags" {} cleanup-modules "" } foreach flags $option_list { verbose "Testing $nshort (libcaf_single), $flags" 1 set gfortran_aux_module_flags "-fcoarray=lib $flags -lcaf_single" - dg-test $test "-fcoarray=lib $flags -lcaf_single" $maybe_atomic_lib + dg-test $test "-fcoarray=lib $flags -lcaf_single" {} cleanup-modules "" } } diff --git a/gcc/testsuite/gfortran.dg/dg.exp b/gcc/testsuite/gfortran.dg/dg.exp index f936fd3..7a9cb89 100644 --- a/gcc/testsuite/gfortran.dg/dg.exp +++ b/gcc/testsuite/gfortran.dg/dg.exp @@ -54,27 +54,7 @@ proc dg-compile-aux-modules { args } { } } -# coarray tests might need libatomic. Assume that it is either not needed or -# provided by builtins if it's not available. -set maybe_atomic_lib "" -if [check_effective_target_libatomic_available] { - if ![is_remote host] { - if [info exists TOOL_OPTIONS] { - set maybe_atomic_lib "[atomic_link_flags [get_multilibs ${TOOL_OPTIONS}]]" - } else { - set maybe_atomic_lib "[atomic_link_flags [get_multilibs]]" - } - } else { - set maybe_atomic_lib "" - } -} - set all_flags $DEFAULT_FFLAGS -if { $maybe_atomic_lib != "" } { - foreach f $maybe_atomic_lib { - lappend all_flags $f - } -} # Main loop. gfortran-dg-runtest [lsort \ diff --git a/gcc/testsuite/lib/gfortran.exp b/gcc/testsuite/lib/gfortran.exp index c3e258b..1ccb81c 100644 --- a/gcc/testsuite/lib/gfortran.exp +++ b/gcc/testsuite/lib/gfortran.exp @@ -79,6 +79,7 @@ proc gfortran_link_flags { paths } { global ld_library_path global GFORTRAN_UNDER_TEST global shlib_ext + global ENABLE_DARWIN_AT_RPATH set gccpath ${paths} set libio_dir "" @@ -87,39 +88,63 @@ proc gfortran_link_flags { paths } { set shlib_ext [get_shlib_extension] verbose "shared lib extension: $shlib_ext" + # We need to add options to locate libgfortran and the dependent libs + # libquadmath (supporting REAL*16) and libatomic (supporting operations + # used by coarrays). Usually '-L' options are added to point to the + # relevant directories for the uninstalled libraries. + + # In cases where libraries are available as both shared and convenience + # some additional checks are made. + + # For some targets -static-xxxx options are handled by specs substitution + # and need a '-B' option rather than '-L'. For Darwin, when embedded + # runpaths are in use (the default for all versions after macOS 10.11), + # '-B' is also needed to provide the runpath. + # When '-B' is used, this results in a '-L' for each path that exists (so + # that appending a '-L' as well is a needless duplicate). There are also + # cases where tools warn for duplicates, leading to spurious fails. + # Therefore the objective of the code below is to add just one '-L' or + # '-B' for each of the libraries. + + set target_wants_B_option 0 + if { [istarget *-*-darwin9* ] || [istarget *-*-darwin\[12\]* ] } { + set target_wants_B_option 1 + } + if { $gccpath != "" } { - if [file exists "${gccpath}/libgfortran/.libs/libgfortran.a"] { - # Some targets use libgfortran.a%s in their specs, so they need a -B option - # for uninstalled testing. - append flags "-B${gccpath}/libgfortran/.libs " - append flags "-L${gccpath}/libgfortran/.libs " - append ld_library_path ":${gccpath}/libgfortran/.libs" - } - if [file exists "${gccpath}/libgfortran/.libs/libgfortran.${shlib_ext}"] { - append flags "-L${gccpath}/libgfortran/.libs " - append ld_library_path ":${gccpath}/libgfortran/.libs" - } if [file exists "${gccpath}/libgfortran/libgforbegin.a"] { append flags "-L${gccpath}/libgfortran " } - if [file exists "${gccpath}/libatomic/.libs/libatomic.${shlib_ext}"] { - append flags "-L${gccpath}/libatomic/.libs " - append ld_library_path ":${gccpath}/libatomic/.libs" + if { [file exists "${gccpath}/libgfortran/.libs/libgfortran.a"] || + [file exists "${gccpath}/libgfortran/.libs/libgfortran.${shlib_ext}"] } { + if { $target_wants_B_option } { + append flags "-B${gccpath}/libgfortran/.libs " + } else { + append flags "-L${gccpath}/libgfortran/.libs " + } + append ld_library_path ":${gccpath}/libgfortran/.libs" } - if [file exists "${gccpath}/libatomic/libatomic.a"] { - append flags "-L${gccpath}/libatomic " + + if { [file exists "${gccpath}/libatomic/.libs/libatomic.a"] || + [file exists "${gccpath}/libatomic/.libs/libatomic.${shlib_ext}"] } { + if { $target_wants_B_option } { + append flags "-B${gccpath}/libatomic/.libs " + } else { + append flags "-L${gccpath}/libatomic/.libs " + } + append ld_library_path ":${gccpath}/libatomic/.libs" } - if [file exists "${gccpath}/libquadmath/.libs/libquadmath.a"] { - # Some targets use libquadmath.a%s in their specs, so they need a -B option - # for uninstalled testing. + + if { [file exists "${gccpath}/libquadmath/.libs/libquadmath.a"] || + [file exists "${gccpath}/libquadmath/.libs/libquadmath.${shlib_ext}"] } { + if { $target_wants_B_option } { append flags "-B${gccpath}/libquadmath/.libs " + } else { append flags "-L${gccpath}/libquadmath/.libs " - append ld_library_path ":${gccpath}/libquadmath/.libs" - } - if [file exists "${gccpath}/libquadmath/.libs/libquadmath.${shlib_ext}"] { - append flags "-L${gccpath}/libquadmath/.libs " - append ld_library_path ":${gccpath}/libquadmath/.libs" + } + append ld_library_path ":${gccpath}/libquadmath/.libs" } + if [file exists "${gccpath}/libiberty/libiberty.a"] { append flags "-L${gccpath}/libiberty " } -- cgit v1.1 From bec7100445f07259d5df69c9f442ea72a90fc37e Mon Sep 17 00:00:00 2001 From: Iain Sandoe Date: Wed, 24 Jan 2024 08:05:41 +0000 Subject: testsuite, Objective-C++: Update link flags [PR112863]. These regressions are caused by missing or duplicate runpaths which now fire linker warnings. We need to add options to locate libobjc (and on Darwin libobjc-gnu) along with libstdc++. Usually '-L' options are added to point to the relevant directories for the uninstalled libraries. In cases where libraries are available as both shared and convenience some additional checks are made. For some targets -static-xxxx options are handled by specs substitution and need a '-B' option rather than '-L'. For Darwin, when embedded runpaths are in use (the default for all versions after macOS 10.11), '-B' is also needed to provide the runpath. When '-B' is used, this results in a '-L' for each path that exists (so that appending a '-L' as well is a needless duplicate). There are also cases where tools warn for duplicates, leading to spurious fails. PR target/112863 gcc/testsuite/ChangeLog: * lib/obj-c++.exp: Decide on whether to present -B or -L to reference the paths to uninstalled libobjc/libobjc-gnu and libstdc++ and use that to generate the link flags. --- gcc/testsuite/lib/obj-c++.exp | 69 ++++++++++++++++++++++++++----------------- 1 file changed, 42 insertions(+), 27 deletions(-) (limited to 'gcc') diff --git a/gcc/testsuite/lib/obj-c++.exp b/gcc/testsuite/lib/obj-c++.exp index 397b70c..854dc26 100644 --- a/gcc/testsuite/lib/obj-c++.exp +++ b/gcc/testsuite/lib/obj-c++.exp @@ -110,34 +110,43 @@ proc obj-c++_link_flags { paths } { set shlib_ext [get_shlib_extension] verbose "shared lib extension: $shlib_ext" + # We need to add options to locate libobjc/libobjc-gnu and libstdc++ + # Usually '-L' options are added to point to the relevant directories for + # the uninstalled libraries. + + # In cases where libraries are available as both shared and convenience + # some additional checks are made. + + # For some targets -static-xxxx options are handled by specs substitution + # and need a '-B' option rather than '-L'. For Darwin, when embedded + # runpaths are in use (the default for all versions after macOS 10.11), + # '-B' is also needed to provide the runpath. + # When '-B' is used, this results in a '-L' for each path that exists (so + # that appending a '-L' as well is a needless duplicate). There are also + # cases where tools warn for duplicates, leading to spurious fails. + # Therefore the objective of the code below is to add just one '-L' or + # '-B' for each of the libraries. + + set target_wants_B_option 0 + if { [istarget *-*-darwin9* ] || [istarget *-*-darwin\[12\]* ] } { + set target_wants_B_option 1 + } + if { $gccpath != "" } { - if [file exists "${gccpath}/lib/libstdc++.a"] { - append ld_library_path ":${gccpath}/lib" - } - if [file exists "${gccpath}/libg++/libg++.a"] { - append flags " -L${gccpath}/libg++ " - append ld_library_path ":${gccpath}/libg++" - } - if [file exists "${gccpath}/libstdc++/libstdc++.a"] { - append flags " -L${gccpath}/libstdc++ " - append ld_library_path ":${gccpath}/libstdc++" - } - if [file exists "${gccpath}/libstdc++-v3/src/.libs/libstdc++.a"] { - # Allow for %s spec substitutions - append flags " -B${gccpath}/libstdc++-v3/src/.libs " - append flags " -L${gccpath}/libstdc++-v3/src/.libs " - append ld_library_path ":${gccpath}/libstdc++-v3/src/.libs" - } - # Look for libstdc++.${shlib_ext}. - if [file exists "${gccpath}/libstdc++-v3/src/.libs/libstdc++.${shlib_ext}"] { - # Allow for %s spec substitutions - append flags " -B${gccpath}/libstdc++-v3/src/.libs " - append flags " -L${gccpath}/libstdc++-v3/src/.libs " - append ld_library_path ":${gccpath}/libstdc++-v3/src/.libs" + if { [file exists "${gccpath}/libstdc++-v3/src/.libs/libstdc++.a"] || + [file exists "${gccpath}/libstdc++-v3/src/.libs/libstdc++.${shlib_ext}"] } { + if { $target_wants_B_option } { + append flags "-B${gccpath}/libstdc++-v3/src/.libs " + } else { + append flags "-L${gccpath}/libstdc++-v3/src/.libs " + } + append ld_library_path ":${gccpath}/libstdc++-v3/src/.libs" } + if [file exists "${gccpath}/libiberty/libiberty.a"] { append flags " -L${gccpath}/libiberty " } + if [file exists "${gccpath}/librx/librx.a"] { append flags " -L${gccpath}/librx " } @@ -159,9 +168,11 @@ proc obj-c++_link_flags { paths } { if { $libobjc_dir != "" } { set libobjc_dir [file dirname ${libobjc_dir}] - # Allow for %s spec substitutions - append flags " -B${libobjc_dir} " - append flags " -L${libobjc_dir} " + if { $target_wants_B_option } { + append flags "-B${libobjc_dir} " + } else { + append flags "-L${libobjc_dir} " + } append ld_library_path ":${libobjc_dir}" } append ld_library_path \ @@ -176,7 +187,11 @@ proc obj-c++_link_flags { paths } { } set libstdcpp [lookfor_file ${tool_root_dir} libstdc++]; if { $libstdcpp != "" } { - append flags "-L${libstdcpp} "; + if { $target_wants_B_option } { + append flags "-B${libstdcpp} " + } else { + append flags "-L${libstdcpp} " + } append ld_library_path ":${libstdcpp}" } set libiberty [lookfor_file ${tool_root_dir} libiberty]; -- cgit v1.1 From 3e0b495311e982d349a28322fa305083ef25f866 Mon Sep 17 00:00:00 2001 From: Lehua Ding Date: Fri, 2 Feb 2024 17:01:20 +0800 Subject: Revert "RISC-V: Allow LICM hoist POLY_INT configuration code sequence" This reverts commit 74489c19070703361acc20bc172f304cae845a96. --- gcc/config/riscv/riscv.cc | 9 ++++---- .../gcc.target/riscv/rvv/autovec/poly_licm-1.c | 18 --------------- .../gcc.target/riscv/rvv/autovec/poly_licm-2.c | 27 ---------------------- 3 files changed, 4 insertions(+), 50 deletions(-) delete mode 100644 gcc/testsuite/gcc.target/riscv/rvv/autovec/poly_licm-1.c delete mode 100644 gcc/testsuite/gcc.target/riscv/rvv/autovec/poly_licm-2.c (limited to 'gcc') diff --git a/gcc/config/riscv/riscv.cc b/gcc/config/riscv/riscv.cc index 3230fe1..d7cdd71 100644 --- a/gcc/config/riscv/riscv.cc +++ b/gcc/config/riscv/riscv.cc @@ -2728,17 +2728,16 @@ riscv_legitimize_move (machine_mode mode, rtx dest, rtx src) (const_poly_int:HI [m, n]) (const_poly_int:SI [m, n]). */ rtx tmp = gen_reg_rtx (Pmode); - rtx tmp2 = gen_reg_rtx (Pmode); - riscv_legitimize_poly_move (Pmode, tmp2, tmp, src); - emit_move_insn (dest, gen_lowpart (mode, tmp2)); + riscv_legitimize_poly_move (Pmode, gen_lowpart (Pmode, dest), tmp, + src); } else { /* In RV32 system, handle (const_poly_int:SI [m, n]) (const_poly_int:DI [m, n]). In RV64 system, handle (const_poly_int:DI [m, n]). - FIXME: Maybe we could gen SImode in RV32 and then sign-extend to - DImode, the offset should not exceed 4GiB in general. */ + FIXME: Maybe we could gen SImode in RV32 and then sign-extend to DImode, + the offset should not exceed 4GiB in general. */ rtx tmp = gen_reg_rtx (mode); riscv_legitimize_poly_move (mode, dest, tmp, src); } diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/poly_licm-1.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/poly_licm-1.c deleted file mode 100644 index b7da65f..0000000 --- a/gcc/testsuite/gcc.target/riscv/rvv/autovec/poly_licm-1.c +++ /dev/null @@ -1,18 +0,0 @@ -/* { dg-do compile } */ -/* { dg-options "-march=rv64gcv -mabi=lp64d -O3 -fno-schedule-insns -fno-schedule-insns2" } */ - -extern int wsize; - -typedef unsigned short Posf; -#define NIL 0 - -void foo (Posf *p) -{ - register unsigned n, m; - do { - m = *--p; - *p = (Posf)(m >= wsize ? m-wsize : NIL); - } while (--n); -} - -/* { dg-final { scan-assembler-times {vid\.v\s+v[0-9]+\s+addi\s+\s*[a-x0-9]+,\s*[a-x0-9]+,\s*-1\s+vrsub\.vx\s+} 1 } } */ diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/poly_licm-2.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/poly_licm-2.c deleted file mode 100644 index ffb3c63..0000000 --- a/gcc/testsuite/gcc.target/riscv/rvv/autovec/poly_licm-2.c +++ /dev/null @@ -1,27 +0,0 @@ -/* { dg-do compile } */ -/* { dg-options "-march=rv64gcv -mabi=lp64d -O3 -fno-schedule-insns -fno-schedule-insns2" } */ - -typedef unsigned short uint16_t; - -void AAA (uint16_t *x, uint16_t *y, unsigned wsize, unsigned count) -{ - unsigned m = 0, n = count; - register uint16_t *p; - - p = x; - - do { - m = *--p; - *p = (uint16_t)(m >= wsize ? m-wsize : 0); - } while (--n); - - n = wsize; - p = y; - - do { - m = *--p; - *p = (uint16_t)(m >= wsize ? m-wsize : 0); - } while (--n); -} - -/* { dg-final { scan-assembler-times {vid\.v\s+v[0-9]+\s+vrsub\.vx\s+} 2 } } */ -- cgit v1.1 From 5487daffa612c8fbe284e4f627aa6e5207ae22e3 Mon Sep 17 00:00:00 2001 From: Rainer Orth Date: Fri, 2 Feb 2024 10:06:01 +0100 Subject: testsuite: i386: Restrict gcc.target/i386/pr80569.c to gas gcc.target/i386/pr80569.c FAILs on Solaris/x86 with the native assembler: FAIL: gcc.target/i386/pr80569.c (test for excess errors) Excess errors: Assembler: pr80569.c "/var/tmp//ccm4_iqb.s", line 2 : Illegal mnemonic Near line: " .code16gcc" "/var/tmp//ccm4_iqb.s", line 2 : Syntax error Near line: " .code16gcc" .code16gcc is a gas extension, so restrict the test to gas. Tested on i386-pc-solaris2.11 (as and gas) and i686-pc-linux-gnu. 2024-02-01 Rainer Orth gcc/testsuite: * gcc.target/i386/pr80569.c: Require gas. --- gcc/testsuite/gcc.target/i386/pr80569.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'gcc') diff --git a/gcc/testsuite/gcc.target/i386/pr80569.c b/gcc/testsuite/gcc.target/i386/pr80569.c index 8e11c40..8314bc1 100644 --- a/gcc/testsuite/gcc.target/i386/pr80569.c +++ b/gcc/testsuite/gcc.target/i386/pr80569.c @@ -1,6 +1,8 @@ /* PR target/80569 */ /* { dg-do assemble } */ /* { dg-options "-O2 -m16 -march=haswell" } */ +/* Non-gas assemblers choke on .code16gcc. */ +/* { dg-require-effective-target gas } */ void load_kernel(void *setup_addr) { -- cgit v1.1 From a9e3818fdc3cfa8d51b7526c0f6b61b268cc4be5 Mon Sep 17 00:00:00 2001 From: Rainer Orth Date: Fri, 2 Feb 2024 10:12:18 +0100 Subject: testsuite: i386: Fix gcc.target/i386/sse2-stv-1.c on Solaris/x86 gcc.target/i386/sse2-stv-1.c FAILs on 32-bit Solaris/x86: FAIL: gcc.target/i386/sse2-stv-1.c scan-assembler-not %[er]sp FAIL: gcc.target/i386/sse2-stv-1.c scan-assembler-not shldl The test assumes the Linux/x86 default of -mno-stackrealign, while 32-bit Solaris/x86 default to -mstackrealign. Fixed by explicitly specifying -mno-stackrealign. Tested on i386-pc-solaris2.11 and i686-pc-linux-gnu. 2024-02-01 Rainer Orth gcc/testsuite: * gcc.target/i386/sse2-stv-1.c (dg-options): Add -mno-stackrealign. --- gcc/testsuite/gcc.target/i386/sse2-stv-1.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'gcc') diff --git a/gcc/testsuite/gcc.target/i386/sse2-stv-1.c b/gcc/testsuite/gcc.target/i386/sse2-stv-1.c index a95d4ed..72b57b5 100644 --- a/gcc/testsuite/gcc.target/i386/sse2-stv-1.c +++ b/gcc/testsuite/gcc.target/i386/sse2-stv-1.c @@ -1,5 +1,5 @@ /* { dg-do compile { target ia32 } } */ -/* { dg-options "-O2 -msse2" } */ +/* { dg-options "-O2 -msse2 -mno-stackrealign" } */ unsigned long long a,b,c,d; -- cgit v1.1 From e5b14d956e38d88542d51bdb697f2161838d1b67 Mon Sep 17 00:00:00 2001 From: Rainer Orth Date: Fri, 2 Feb 2024 11:25:45 +0100 Subject: testsuite: i386: Fix gcc.target/i386/pr71321.c on Solaris/x86 gcc.target/i386/pr71321.c FAILs on 64-bit Solaris/x86 with the native assembler: FAIL: gcc.target/i386/pr71321.c scan-assembler-not lea.*0 The problem is that /bin/as doesn't fully support cfi directives, so the .eh_frame section is specified explicitly, which includes ".long 0". The regular expression above includes ".*", which does multiline matches. AFAICS those aren't needed here. This patch changes the RE not to use multiline patches. Tested on i386-pc-solaris2.11 (as and gas) and i686-pc-linux-gnu. 2024-02-01 Rainer Orth gcc/testsuite: * gcc.target/i386/pr71321.c (scan-assembler-not): Avoid multiline matches. --- gcc/testsuite/gcc.target/i386/pr71321.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'gcc') diff --git a/gcc/testsuite/gcc.target/i386/pr71321.c b/gcc/testsuite/gcc.target/i386/pr71321.c index 24d144b..7a006d1 100644 --- a/gcc/testsuite/gcc.target/i386/pr71321.c +++ b/gcc/testsuite/gcc.target/i386/pr71321.c @@ -12,4 +12,4 @@ unsigned cvt_to_2digit_ascii(uint8_t i) { return cvt_to_2digit(i, 10) + 0x0a3030; } -/* { dg-final { scan-assembler-not "lea.*0" } } */ +/* { dg-final { scan-assembler-not "lea\[^\n\r]*0" } } */ -- cgit v1.1 From a8f335ccb61bf6105192a4197ef2d84900614dc1 Mon Sep 17 00:00:00 2001 From: Jakub Jelinek Date: Fri, 2 Feb 2024 11:25:13 +0100 Subject: tree-ssa-math-opts: Fix is_widening_mult_rhs_p - unbreak bootstrap [PR113705] On Tue, Jan 30, 2024 at 07:33:10AM -0000, Roger Sayle wrote: + wide_int bits = wide_int::from (tree_nonzero_bits (rhs), + prec, + TYPE_SIGN (TREE_TYPE (rhs))); ... > + if (gimple_assign_rhs_code (stmt) == BIT_AND_EXPR > + && TREE_CODE (gimple_assign_rhs2 (stmt)) == INTEGER_CST > + && wi::to_wide (gimple_assign_rhs2 (stmt)) > + == wi::mask (hprec, false, prec)) This change broke bootstrap on aarch64-linux. The problem can be seen even on the reduced testcase. The IL on the unreduced testcase before widening_mul has: # val_583 = PHI ... pretmp_266 = MEM[(const struct wide_int_storage *)&D.160657].len; _264 = pretmp_266 & 65535; ... _176 = (sizetype) val_583; _439 = (sizetype) _264; _284 = _439 * 8; _115 = _176 + _284; where 583/266/264 have unsigned int type and 176/439/284/115 have sizetype. widening_mul first turns that into: # val_583 = PHI ... pretmp_266 = MEM[(const struct wide_int_storage *)&D.160657].len; _264 = pretmp_266 & 65535; ... _176 = (sizetype) val_583; _439 = (sizetype) _264; _284 = _264 w* 8; _115 = _176 + _284; and then is_widening_mult_rhs_p is called, with type sizetype (64-bit), rhs _264, hprec 32 and prec 64. Now tree_nonzero_bits (rhs) is 65535, so bits is 64-bit wide_int 65535, stmt is BIT_AND_EXPR, but we ICE on the wi::to_wide (gimple_assign_rhs2 (stmt)) == wi::mask (hprec, false, prec) comparison because wi::to_wide on gimple_assign_rhs2 (stmt) - unsigned int 65535 gives 32-bit wide_int 65535, while wi::mask (hprec, false, prec) gives 64-bit wide_int 0xffffffff and comparison between different precision wide_ints is forbidden. The following patch fixes it the same way how bits is computed earlier, by calling wide_int::from on the wi::to_wide (gimple_assign_rhs2 (stmt)), so we compare 64-bit 65535 with 64-bit 0xffffffff. 2024-02-02 Jakub Jelinek PR middle-end/113705 * tree-ssa-math-opts.cc (is_widening_mult_rhs_p): Use wide_int_from around wi::to_wide in order to compare value in prec precision. * g++.dg/opt/pr113705.C: New test. --- gcc/testsuite/g++.dg/opt/pr113705.C | 68 +++++++++++++++++++++++++++++++++++++ gcc/tree-ssa-math-opts.cc | 3 +- 2 files changed, 70 insertions(+), 1 deletion(-) create mode 100644 gcc/testsuite/g++.dg/opt/pr113705.C (limited to 'gcc') diff --git a/gcc/testsuite/g++.dg/opt/pr113705.C b/gcc/testsuite/g++.dg/opt/pr113705.C new file mode 100644 index 0000000..39fb047 --- /dev/null +++ b/gcc/testsuite/g++.dg/opt/pr113705.C @@ -0,0 +1,68 @@ +// PR middle-end/113705 +// { dg-do compile { target c++17 } } +// { dg-options "-O2 -w" } + +void foo (); +template struct A : T { long bar () const; }; +int a; + +template +long +A::bar () const +{ + return this->baz ()[a]; +} + +struct B { + struct { long b[1]; long c; } u; + unsigned d; + int e; + B (const B &); + ~B (); + const long *baz () const; + unsigned qux () const; +}; + +B::B (const B &) +{ + if (__builtin_expect (e, 0)) + u.c = 0; +} + +B::~B () +{ + if (__builtin_expect (e, 0)) + foo (); +} + +const long * +B::baz () const +{ + return u.b; +} + +unsigned +B::qux () const +{ + return d; +} + +struct C { A corge () const; A *f; }; + +A +C::corge () const +{ + return f[1]; +} + +void +test (C r, long *h, unsigned short *d) +{ + for (int j = 0; j < 8; ++j) + { + A g = r.corge (); + *d = g.qux (); + for (unsigned i = 0; i < *d; ++i) + *h++ = g.bar (); + } +} diff --git a/gcc/tree-ssa-math-opts.cc b/gcc/tree-ssa-math-opts.cc index cffe757..aa9f7b5 100644 --- a/gcc/tree-ssa-math-opts.cc +++ b/gcc/tree-ssa-math-opts.cc @@ -2572,7 +2572,8 @@ is_widening_mult_rhs_p (tree type, tree rhs, tree *type_out, if (is_gimple_assign (stmt) && gimple_assign_rhs_code (stmt) == BIT_AND_EXPR && TREE_CODE (gimple_assign_rhs2 (stmt)) == INTEGER_CST - && wi::to_wide (gimple_assign_rhs2 (stmt)) + && wide_int::from (wi::to_wide (gimple_assign_rhs2 (stmt)), + prec, TYPE_SIGN (TREE_TYPE (rhs))) == wi::mask (hprec, false, prec)) *new_rhs_out = gimple_assign_rhs1 (stmt); else -- cgit v1.1 From 49e75666c592d23dfa17f062974e660edd01d5fb Mon Sep 17 00:00:00 2001 From: Jakub Jelinek Date: Fri, 2 Feb 2024 11:27:37 +0100 Subject: lower-bitint: Handle uninitialized large/huge SSA_NAMEs as inline asm inputs [PR113699] Similar problem to calls with uninitialized large/huge _BitInt SSA_NAME arguments, var_to_partition will not work for those, but unlike calls where we just create a new uninitialized SSA_NAME here we need to change the inline asm input to be an uninitialized VAR_DECL. 2024-02-02 Jakub Jelinek PR middle-end/113699 * gimple-lower-bitint.cc (bitint_large_huge::lower_asm): Handle uninitialized large/huge _BitInt SSA_NAME inputs. * gcc.dg/bitint-81.c: New test. --- gcc/gimple-lower-bitint.cc | 15 ++++++++++++--- gcc/testsuite/gcc.dg/bitint-81.c | 12 ++++++++++++ 2 files changed, 24 insertions(+), 3 deletions(-) create mode 100644 gcc/testsuite/gcc.dg/bitint-81.c (limited to 'gcc') diff --git a/gcc/gimple-lower-bitint.cc b/gcc/gimple-lower-bitint.cc index a3802c6..7588150 100644 --- a/gcc/gimple-lower-bitint.cc +++ b/gcc/gimple-lower-bitint.cc @@ -5200,9 +5200,18 @@ bitint_large_huge::lower_asm (gimple *stmt) && TREE_CODE (TREE_TYPE (s)) == BITINT_TYPE && bitint_precision_kind (TREE_TYPE (s)) >= bitint_prec_large) { - int part = var_to_partition (m_map, s); - gcc_assert (m_vars[part] != NULL_TREE); - TREE_VALUE (t) = m_vars[part]; + if (SSA_NAME_IS_DEFAULT_DEF (s) + && (!SSA_NAME_VAR (s) || VAR_P (SSA_NAME_VAR (s)))) + { + TREE_VALUE (t) = create_tmp_var (TREE_TYPE (s), "bitint"); + mark_addressable (TREE_VALUE (t)); + } + else + { + int part = var_to_partition (m_map, s); + gcc_assert (m_vars[part] != NULL_TREE); + TREE_VALUE (t) = m_vars[part]; + } } } update_stmt (stmt); diff --git a/gcc/testsuite/gcc.dg/bitint-81.c b/gcc/testsuite/gcc.dg/bitint-81.c new file mode 100644 index 0000000..33162fd --- /dev/null +++ b/gcc/testsuite/gcc.dg/bitint-81.c @@ -0,0 +1,12 @@ +/* PR middle-end/113699 */ +/* { dg-do compile { target bitint } } */ +/* { dg-options "-O2 -std=c23" } */ + +void +foo (void) +{ +#if __BITINT_MAXWIDTH__ >= 129 + _BitInt(129) i; + __asm__ ("" : : "rm" (i)); +#endif +} -- cgit v1.1 From fb28d5cdae149f08f0d472c210a5143a64771410 Mon Sep 17 00:00:00 2001 From: Jakub Jelinek Date: Fri, 2 Feb 2024 11:28:31 +0100 Subject: lower-bitint: Handle casts from large/huge _BitInt to pointer/reference types [PR113692] I thought one needs to cast first to pointer-sized integer before casting to pointer, but apparently that is not the case. So the following patch arranges for the large/huge _BitInt to pointer/reference conversions to use the same code as for conversions of them to small integral types. 2024-02-02 Jakub Jelinek PR tree-optimization/113692 * gimple-lower-bitint.cc (bitint_large_huge::lower_stmt): Handle casts from large/huge BITINT_TYPEs to POINTER_TYPE/REFERENCE_TYPE as final_cast_p. * gcc.dg/bitint-82.c: New test. --- gcc/gimple-lower-bitint.cc | 8 +++++--- gcc/testsuite/gcc.dg/bitint-82.c | 18 ++++++++++++++++++ 2 files changed, 23 insertions(+), 3 deletions(-) create mode 100644 gcc/testsuite/gcc.dg/bitint-82.c (limited to 'gcc') diff --git a/gcc/gimple-lower-bitint.cc b/gcc/gimple-lower-bitint.cc index 7588150..a7cc5ce 100644 --- a/gcc/gimple-lower-bitint.cc +++ b/gcc/gimple-lower-bitint.cc @@ -5264,7 +5264,8 @@ bitint_large_huge::lower_stmt (gimple *stmt) mergeable_cast_p = true; else if (TREE_CODE (TREE_TYPE (rhs1)) == BITINT_TYPE && bitint_precision_kind (TREE_TYPE (rhs1)) >= bitint_prec_large - && INTEGRAL_TYPE_P (TREE_TYPE (lhs))) + && (INTEGRAL_TYPE_P (TREE_TYPE (lhs)) + || POINTER_TYPE_P (TREE_TYPE (lhs)))) { final_cast_p = true; if (TREE_CODE (rhs1) == SSA_NAME @@ -5393,8 +5394,9 @@ bitint_large_huge::lower_stmt (gimple *stmt) be needed. */ gcc_assert (TYPE_PRECISION (lhs_type) <= 2 * limb_prec); gimple *g; - if (TREE_CODE (lhs_type) == BITINT_TYPE - && bitint_precision_kind (lhs_type) == bitint_prec_middle) + if ((TREE_CODE (lhs_type) == BITINT_TYPE + && bitint_precision_kind (lhs_type) == bitint_prec_middle) + || POINTER_TYPE_P (lhs_type)) lhs_type = build_nonstandard_integer_type (TYPE_PRECISION (lhs_type), TYPE_UNSIGNED (lhs_type)); m_data_cnt = 0; diff --git a/gcc/testsuite/gcc.dg/bitint-82.c b/gcc/testsuite/gcc.dg/bitint-82.c new file mode 100644 index 0000000..4ea86f0 --- /dev/null +++ b/gcc/testsuite/gcc.dg/bitint-82.c @@ -0,0 +1,18 @@ +/* PR tree-optimization/113692 */ +/* { dg-do compile { target bitint } } */ +/* { dg-options "-O2 -std=c23" } */ + +#if __BITINT_MAXWIDTH__ >= 135 +_BitInt(135) i; +#else +_BitInt(63) i; +#endif + +void * +foo (void) +{ + void *ret = 0; + if (i & 1) + ret = (void *) 1; + return ret; +} -- cgit v1.1 From a049acabcb11d6ae9e54c81e5835e4f3372e80fb Mon Sep 17 00:00:00 2001 From: Jakub Jelinek Date: Fri, 2 Feb 2024 11:29:25 +0100 Subject: testsuite: Add another bitint testcase [PR113691] This is fixed by the PR113692 patch. 2024-02-02 Jakub Jelinek PR tree-optimization/113691 * gcc.dg/bitint-83.c: New test. --- gcc/testsuite/gcc.dg/bitint-83.c | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) create mode 100644 gcc/testsuite/gcc.dg/bitint-83.c (limited to 'gcc') diff --git a/gcc/testsuite/gcc.dg/bitint-83.c b/gcc/testsuite/gcc.dg/bitint-83.c new file mode 100644 index 0000000..96d3f71 --- /dev/null +++ b/gcc/testsuite/gcc.dg/bitint-83.c @@ -0,0 +1,23 @@ +/* PR tree-optimization/113691 */ +/* { dg-do compile { target bitint } } */ +/* { dg-options "-O2 -std=gnu11 -w" } */ + +#if __BITINT_MAXWIDTH__ >= 944 +_BitInt (944) i; +#else +_BitInt (63) i; +#endif + +void foo (); + +void +bar () +{ + foo (i); +} + +void +foo (int *p) +{ + *p = 0; +} -- cgit v1.1 From cc13e60ba74a092ddc3a9492c721afa766118375 Mon Sep 17 00:00:00 2001 From: Jonathan Wakely Date: Thu, 1 Feb 2024 22:16:36 +0000 Subject: doc: Fix typo in description of hardbool attribute gcc/ChangeLog: * doc/extend.texi (Common Type Attributes): Fix typo in description of hardbool. --- gcc/doc/extend.texi | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'gcc') diff --git a/gcc/doc/extend.texi b/gcc/doc/extend.texi index 142e41a..2b8ba19 100644 --- a/gcc/doc/extend.texi +++ b/gcc/doc/extend.texi @@ -8960,7 +8960,7 @@ This attribute may only be applied to integral types in C, to introduce hardened boolean types. It turns the integral type into a boolean-like type with the same size and precision, that uses the specified values as representations for @code{false} and @code{true}. Underneath, it is -actually an enumerate type, but its observable behavior is like that of +actually an enumerated type, but its observable behavior is like that of @code{_Bool}, except for the strict internal representations, verified by runtime checks. -- cgit v1.1 From a6afa0d06b0559b22be829ff197495d5c8653b96 Mon Sep 17 00:00:00 2001 From: Iain Sandoe Date: Fri, 26 Jan 2024 15:22:44 +0000 Subject: testsuite, asan, hwsan: Add libstdc++ deps where required. We use the shared asan/hwasan rom both C,C++,D and Fortran. The sanitizer libraries link to libstdc++. When we are using the C/gdc/gfortran driver, and the target might require a path to the libstdc++ (e.g. for handing -static-xxxx or for embedded runpaths), we need to add a suitable option (or we get fails at execution time because of the missing paths). Conversely, we do not want to add multiple instances of these paths (since that leads to failures on tools that report warnings for duplicate runpaths). This patch modifies the _init function to allow a single parameter that determines whether the *asan_init should add a path for libstdc++ (yes for C driver, no for C++ driver). gcc/testsuite/ChangeLog: * g++.dg/asan/asan.exp: Add a parameter to init to say that we expect the C++ driver to provide paths for libstdc++. * g++.dg/hwasan/hwasan.exp: Likewise * gcc.dg/asan/asan.exp: Add a parameter to init to say that we need a path added for libstdc++. * gcc.dg/hwasan/hwasan.exp: Likewise. * gdc.dg/asan/asan.exp: Likewise. * gfortran.dg/asan/asan.exp: Likewise. * lib/asan-dg.exp: Handle a single parameter to init that requests addition of a path to libstdc++ to link flags. * lib/hwasan-dg.exp: Likewise. --- gcc/testsuite/g++.dg/asan/asan.exp | 3 ++- gcc/testsuite/g++.dg/hwasan/hwasan.exp | 3 ++- gcc/testsuite/gcc.dg/asan/asan.exp | 3 ++- gcc/testsuite/gcc.dg/hwasan/hwasan.exp | 3 ++- gcc/testsuite/gdc.dg/asan/asan.exp | 3 ++- gcc/testsuite/gfortran.dg/asan/asan.exp | 3 ++- gcc/testsuite/lib/asan-dg.exp | 21 ++++++++++++++++----- gcc/testsuite/lib/hwasan-dg.exp | 9 +++++---- 8 files changed, 33 insertions(+), 15 deletions(-) (limited to 'gcc') diff --git a/gcc/testsuite/g++.dg/asan/asan.exp b/gcc/testsuite/g++.dg/asan/asan.exp index 9297bb5..f078bc3 100644 --- a/gcc/testsuite/g++.dg/asan/asan.exp +++ b/gcc/testsuite/g++.dg/asan/asan.exp @@ -22,7 +22,8 @@ load_lib asan-dg.exp # Initialize `dg'. dg-init -asan_init +# libasan uses libstdc++ but we assume that's added by the g++ impl. +asan_init 0 # Main loop. if [check_effective_target_fsanitize_address] { diff --git a/gcc/testsuite/g++.dg/hwasan/hwasan.exp b/gcc/testsuite/g++.dg/hwasan/hwasan.exp index 597033e..12a7a35 100644 --- a/gcc/testsuite/g++.dg/hwasan/hwasan.exp +++ b/gcc/testsuite/g++.dg/hwasan/hwasan.exp @@ -22,7 +22,8 @@ load_lib hwasan-dg.exp # Initialize `dg'. dg-init -hwasan_init +# libhwasan uses libstdc++ but we assume that's added by the g++ impl. +hwasan_init 0 # Main loop. if [check_effective_target_fsanitize_hwaddress] { diff --git a/gcc/testsuite/gcc.dg/asan/asan.exp b/gcc/testsuite/gcc.dg/asan/asan.exp index 10c6973..6b8ebf0 100644 --- a/gcc/testsuite/gcc.dg/asan/asan.exp +++ b/gcc/testsuite/gcc.dg/asan/asan.exp @@ -24,7 +24,8 @@ load_lib asan-dg.exp # Initialize `dg'. dg-init -asan_init +# libasan uses libstdc++ so make sure we provide paths for it. +asan_init 1 # Main loop. if [check_effective_target_fsanitize_address] { diff --git a/gcc/testsuite/gcc.dg/hwasan/hwasan.exp b/gcc/testsuite/gcc.dg/hwasan/hwasan.exp index 802f171..88327d3 100644 --- a/gcc/testsuite/gcc.dg/hwasan/hwasan.exp +++ b/gcc/testsuite/gcc.dg/hwasan/hwasan.exp @@ -24,7 +24,8 @@ load_lib hwasan-dg.exp # Initialize `dg'. dg-init -hwasan_init +# libhwasan uses libstdc++ so make sure we provide paths for it. +hwasan_init 1 # Main loop. if [check_effective_target_fsanitize_hwaddress] { diff --git a/gcc/testsuite/gdc.dg/asan/asan.exp b/gcc/testsuite/gdc.dg/asan/asan.exp index 72b3669..89c6bf3 100644 --- a/gcc/testsuite/gdc.dg/asan/asan.exp +++ b/gcc/testsuite/gdc.dg/asan/asan.exp @@ -20,7 +20,8 @@ load_lib asan-dg.exp # Initialize `dg'. dg-init -asan_init +# libasan uses libstdc++ so make sure we provide paths for it. +asan_init 1 # Main loop. if [check_effective_target_fsanitize_address] { diff --git a/gcc/testsuite/gfortran.dg/asan/asan.exp b/gcc/testsuite/gfortran.dg/asan/asan.exp index 25cd19f..a157638 100644 --- a/gcc/testsuite/gfortran.dg/asan/asan.exp +++ b/gcc/testsuite/gfortran.dg/asan/asan.exp @@ -27,7 +27,8 @@ load_lib asan-dg.exp # Initialize `dg'. dg-init -asan_init +# libasan uses libstdc++ so make sure we provide paths for it. +asan_init 1 # Main loop. if [check_effective_target_fsanitize_address] { diff --git a/gcc/testsuite/lib/asan-dg.exp b/gcc/testsuite/lib/asan-dg.exp index beb49e5..6bd3c21 100644 --- a/gcc/testsuite/lib/asan-dg.exp +++ b/gcc/testsuite/lib/asan-dg.exp @@ -61,7 +61,7 @@ proc asan_include_flags {} { # (originally from g++.exp) # -proc asan_link_flags_1 { paths lib } { +proc asan_link_flags_1 { paths lib need_stdcxx} { global srcdir global ld_library_path global shlib_ext @@ -73,6 +73,10 @@ proc asan_link_flags_1 { paths lib } { set shlib_ext [get_shlib_extension] set ${lib}_saved_library_path $ld_library_path + # Providing -B instead of -L means that it works for targets that use + # spec substitution for handling -static-xxxxx, it also works for targets + # the use the startfile paths to provide a runpath for uninstalled test. + # Each -B option will produce a -L on the link line (for paths that exist). if { $gccpath != "" } { if { [file exists "${gccpath}/libsanitizer/${lib}/.libs/lib${lib}.a"] || [file exists "${gccpath}/libsanitizer/${lib}/.libs/lib${lib}.${shlib_ext}"] } { @@ -81,6 +85,12 @@ proc asan_link_flags_1 { paths lib } { append flags " -B${gccpath}/libsanitizer/${lib}/.libs " append ld_library_path ":${gccpath}/libsanitizer/${lib}/.libs" } + # libasan links to libstdc++, so we must include it for C testcases. + if { $need_stdcxx && ( [file exists "${gccpath}/libstdc++-v3/src/.libs/libstdc++.a"] + || [file exists "${gccpath}/libstdc++-v3/src/.libs/libstdc++.${shlib_ext}"] ) } { + append flags " -B${gccpath}/libstdc++-v3/src/.libs " + append ld_library_path ":${gccpath}/libstdc++-v3/src/.libs" + } } else { global tool_root_dir @@ -96,8 +106,8 @@ proc asan_link_flags_1 { paths lib } { return "$flags" } -proc asan_link_flags { paths } { - return [asan_link_flags_1 $paths asan] +proc asan_link_flags { paths need_stdcxx } { + return [asan_link_flags_1 $paths asan $need_stdcxx] } # @@ -113,12 +123,13 @@ proc asan_init { args } { setenv ASAN_OPTIONS "color=never" + set needs_cxx [lindex $args 0] set link_flags "" if ![is_remote host] { if [info exists TOOL_OPTIONS] { - set link_flags "[asan_link_flags [get_multilibs ${TOOL_OPTIONS}]]" + set link_flags "[asan_link_flags [get_multilibs ${TOOL_OPTIONS}] $needs_cxx]" } else { - set link_flags "[asan_link_flags [get_multilibs]]" + set link_flags "[asan_link_flags [get_multilibs] $needs_cxx]" } } diff --git a/gcc/testsuite/lib/hwasan-dg.exp b/gcc/testsuite/lib/hwasan-dg.exp index 8d66b4d..33c9a7c 100644 --- a/gcc/testsuite/lib/hwasan-dg.exp +++ b/gcc/testsuite/lib/hwasan-dg.exp @@ -100,8 +100,8 @@ proc hwasan_include_flags {} { # (implementation in asan-dg.exp) # -proc hwasan_link_flags { paths } { - return [asan_link_flags_1 $paths hwasan] +proc hwasan_link_flags { paths needs_cxx } { + return [asan_link_flags_1 $paths hwasan $needs_cxx] } # @@ -114,6 +114,7 @@ proc hwasan_init { args } { global TOOL_OPTIONS global hwasan_saved_TEST_ALWAYS_FLAGS global hwasan_saved_ALWAYS_CXXFLAGS + set needs_cxx [lindex $args 0] setenv HWASAN_OPTIONS "random_tags=0" @@ -126,9 +127,9 @@ proc hwasan_init { args } { set link_flags "" if ![is_remote host] { if [info exists TOOL_OPTIONS] { - set link_flags "[hwasan_link_flags [get_multilibs ${TOOL_OPTIONS}]]" + set link_flags "[hwasan_link_flags [get_multilibs ${TOOL_OPTIONS}] $needs_cxx]" } else { - set link_flags "[hwasan_link_flags [get_multilibs]]" + set link_flags "[hwasan_link_flags [get_multilibs] $needs_cxx]" } } -- cgit v1.1 From ae061a1757b2c76ddf4cc2c84b433fe1cd6dd7f7 Mon Sep 17 00:00:00 2001 From: Iain Sandoe Date: Fri, 26 Jan 2024 15:23:19 +0000 Subject: testsuite, ubsan: Add libstdc++ deps where required. We use the ubsan tests from both C, C++, D and Fortran. thee sanitizer libraries link to libstdc++. When we are using the C/gdc/gfortran driver, and the target might require a path to the libstdc++ (e.g. for handing -static-xxxx or for embedded runpaths), we need to add a suitable option (or we get fails at execution time because of the missing paths). Conversely, we do not want to add multiple instances of these paths (since that leads to failures on tools that report warnings for duplicate runpaths). This patch modifies the _init function to allow a sigle parameter that determines whether the *asan_init should add a path for libstdc++ (yes for C driver, no for C++ driver). gcc/testsuite/ChangeLog: * g++.dg/ubsan/ubsan.exp:Add a parameter to init to say that we expect the C++ driver to provide paths for libstdc++. * gcc.dg/ubsan/ubsan.exp: Add a parameter to init to say that we need a path added for libstdc++. * gdc.dg/ubsan/ubsan.exp: Likewise. * gfortran.dg/ubsan/ubsan.exp: Likewise. * lib/ubsan-dg.exp: Handle a single parameter to init that requests addition of a path to libstdc++ to link flags. --- gcc/testsuite/g++.dg/ubsan/ubsan.exp | 3 ++- gcc/testsuite/gcc.dg/ubsan/ubsan.exp | 3 ++- gcc/testsuite/gdc.dg/ubsan/ubsan.exp | 3 ++- gcc/testsuite/gfortran.dg/ubsan/ubsan.exp | 4 ++-- gcc/testsuite/lib/ubsan-dg.exp | 20 +++++++++++++++----- 5 files changed, 23 insertions(+), 10 deletions(-) (limited to 'gcc') diff --git a/gcc/testsuite/g++.dg/ubsan/ubsan.exp b/gcc/testsuite/g++.dg/ubsan/ubsan.exp index d719707..4bab1b8 100644 --- a/gcc/testsuite/g++.dg/ubsan/ubsan.exp +++ b/gcc/testsuite/g++.dg/ubsan/ubsan.exp @@ -22,7 +22,8 @@ load_lib ubsan-dg.exp # Initialize `dg'. dg-init -ubsan_init +# libubsan uses libstdc++ but we assume that's added by the g++ impl. +ubsan_init 0 # Main loop. if [check_effective_target_fsanitize_undefined] { diff --git a/gcc/testsuite/gcc.dg/ubsan/ubsan.exp b/gcc/testsuite/gcc.dg/ubsan/ubsan.exp index 8417049..560e584 100644 --- a/gcc/testsuite/gcc.dg/ubsan/ubsan.exp +++ b/gcc/testsuite/gcc.dg/ubsan/ubsan.exp @@ -24,7 +24,8 @@ load_lib ubsan-dg.exp # Initialize `dg'. dg-init -ubsan_init +# libubsan uses libstdc++ so make sure we provide paths for it. +ubsan_init 1 # Main loop. if [check_effective_target_fsanitize_undefined] { diff --git a/gcc/testsuite/gdc.dg/ubsan/ubsan.exp b/gcc/testsuite/gdc.dg/ubsan/ubsan.exp index 6ad665a..7613a3b 100644 --- a/gcc/testsuite/gdc.dg/ubsan/ubsan.exp +++ b/gcc/testsuite/gdc.dg/ubsan/ubsan.exp @@ -20,7 +20,8 @@ load_lib ubsan-dg.exp # Initialize `dg'. dg-init -ubsan_init +# libubsan uses libstdc++ so make sure we provide paths for it. +ubsan_init 1 # Main loop. if [check_effective_target_fsanitize_undefined] { diff --git a/gcc/testsuite/gfortran.dg/ubsan/ubsan.exp b/gcc/testsuite/gfortran.dg/ubsan/ubsan.exp index 0c61153..b236078 100644 --- a/gcc/testsuite/gfortran.dg/ubsan/ubsan.exp +++ b/gcc/testsuite/gfortran.dg/ubsan/ubsan.exp @@ -22,10 +22,10 @@ load_lib gfortran-dg.exp load_lib ubsan-dg.exp - # Initialize `dg'. dg-init -ubsan_init +# libubsan uses libstdc++ so make sure we provide paths for it. +ubsan_init 1 # Main loop. if [check_effective_target_fsanitize_undefined] { diff --git a/gcc/testsuite/lib/ubsan-dg.exp b/gcc/testsuite/lib/ubsan-dg.exp index 108b998..860e78f 100644 --- a/gcc/testsuite/lib/ubsan-dg.exp +++ b/gcc/testsuite/lib/ubsan-dg.exp @@ -31,7 +31,7 @@ proc check_effective_target_fsanitize_undefined {} { # (originally from g++.exp) # -proc ubsan_link_flags { paths } { +proc ubsan_link_flags { paths needs_cxx } { global srcdir global ld_library_path global shlib_ext @@ -43,15 +43,24 @@ proc ubsan_link_flags { paths } { set shlib_ext [get_shlib_extension] set ubsan_saved_library_path $ld_library_path + # Providing -B instead of -L means that it works for targets that use + # spec substitution for handling -static-xxxxx, it also works for targets + # the use the startfile paths to provide a runpath for uninstalled test. + # Each -B option will produce a -L on the link line (for paths that exist). if { $gccpath != "" } { if { [file exists "${gccpath}/libsanitizer/ubsan/.libs/libubsan.a"] || [file exists "${gccpath}/libsanitizer/ubsan/.libs/libubsan.${shlib_ext}"] } { append flags " -B${gccpath}/libsanitizer/ " append flags " -B${gccpath}/libsanitizer/ubsan/ " - append flags " -L${gccpath}/libsanitizer/ubsan/.libs" + append flags " -B${gccpath}/libsanitizer/ubsan/.libs" append ld_library_path ":${gccpath}/libsanitizer/ubsan/.libs" - append ld_library_path ":${gccpath}/libstdc++-v3/src/.libs" } + # libasan links to libstdc++, so we must include it for C testcases. + if { $needs_cxx && ( [file exists "${gccpath}/libstdc++-v3/src/.libs/libstdc++.a"] + || [file exists "${gccpath}/libstdc++-v3/src/.libs/libstdc++.${shlib_ext}"] ) } { + append flags " -B${gccpath}/libstdc++-v3/src/.libs " + append ld_library_path ":${gccpath}/libstdc++-v3/src/.libs" + } } else { global tool_root_dir @@ -79,6 +88,7 @@ proc ubsan_init { args } { global ubsan_saved_ALWAYS_CXXFLAGS global orig_ubsan_options_saved global orig_ubsan_options + set needs_cxx [lindex $args 0] if { $orig_ubsan_options_saved == 0 } { # Save the original environment. @@ -92,9 +102,9 @@ proc ubsan_init { args } { set link_flags "" if ![is_remote host] { if [info exists TOOL_OPTIONS] { - set link_flags "[ubsan_link_flags [get_multilibs ${TOOL_OPTIONS}]]" + set link_flags "[ubsan_link_flags [get_multilibs ${TOOL_OPTIONS}] $needs_cxx]" } else { - set link_flags "[ubsan_link_flags [get_multilibs]]" + set link_flags "[ubsan_link_flags [get_multilibs] $needs_cxx]" } } -- cgit v1.1 From 639bd5e9b759a6d733fadbd5f956889d965e9368 Mon Sep 17 00:00:00 2001 From: Iain Sandoe Date: Mon, 29 Jan 2024 10:09:25 +0000 Subject: testsuite, Darwin: Allow for undefined symbols in shared test. Darwin's linker defaults to error on undefined (which makes it look as if we do not support shared, leading to tests being marked incorrectly as unsupported). This fixes the issue by allowing the symbols used in the target supports test to be undefined. gcc/testsuite/ChangeLog: * lib/target-supports.exp (check_effective_target_shared): Allow the external symbols referenced in the test to be undefined. --- gcc/testsuite/lib/target-supports.exp | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) (limited to 'gcc') diff --git a/gcc/testsuite/lib/target-supports.exp b/gcc/testsuite/lib/target-supports.exp index 8aefb32..f66dcaa 100644 --- a/gcc/testsuite/lib/target-supports.exp +++ b/gcc/testsuite/lib/target-supports.exp @@ -1385,6 +1385,13 @@ proc check_effective_target_aarch64_tlsle32 { } { # emitted, 0 otherwise. proc check_effective_target_shared { } { + # Darwin's linker defaults to error on undefined (which makes it look as + # if we do not support shared) but we can tell it to allow the symbols used + # here to be undefined. + set extra_flags "" + if { [istarget *-*-darwin\[912\]*] } { + set extra_flags "-Wl,-U,_foo,-U,_bar" + } # Note that M68K has a multilib that supports -fpic but not # -fPIC, so we need to check both. We test with a program that # requires GOT references, and with a libc symbol that would @@ -1397,7 +1404,7 @@ proc check_effective_target_shared { } { char *baz (void) { return foo () + (char*) malloc (bar); } - } "-shared -fpic"] + } "-shared -fpic $extra_flags"] } # Return 1 if -pie, -fpie and -fPIE are supported, 0 otherwise. -- cgit v1.1 From 922e4599e6261644d336b009b6901cd221ec95fd Mon Sep 17 00:00:00 2001 From: Juzhe-Zhong Date: Fri, 2 Feb 2024 09:56:59 +0800 Subject: RISC-V: Expand VLMAX scalar move in reduction This patch fixes the following: vsetvli a5,a1,e32,m1,tu,ma slli a4,a5,2 sub a1,a1,a5 vle32.v v2,0(a0) add a0,a0,a4 vadd.vv v1,v2,v1 bne a1,zero,.L3 vsetivli zero,1,e32,m1,ta,ma vmv.s.x v2,zero vsetvli a5,zero,e32,m1,ta,ma ---> Redundant vsetvl. vredsum.vs v1,v1,v2 vmv.x.s a0,v1 ret VSETVL PASS is able to fuse avl = 1 of scalar move and VLMAX avl of reduction. However, this following RTL blocks the fusion in dependence analysis in VSETVL PASS: (insn 49 24 50 5 (set (reg:RVVM1SI 98 v2 [148]) (if_then_else:RVVM1SI (unspec:RVVMF32BI [ (const_vector:RVVMF32BI [ (const_int 1 [0x1]) repeat [ (const_int 0 [0]) ] ]) (const_int 1 [0x1]) (const_int 2 [0x2]) repeated x2 (const_int 0 [0]) (reg:SI 66 vl) (reg:SI 67 vtype) ] UNSPEC_VPREDICATE) (const_vector:RVVM1SI repeat [ (const_int 0 [0]) ]) (unspec:RVVM1SI [ (reg:DI 0 zero) ] UNSPEC_VUNDEF))) 3813 {*pred_broadcastrvvm1si_zero} (nil)) (insn 50 49 51 5 (set (reg:DI 15 a5 [151]) ----> It set a5, blocks the following VLMAX into the scalar move above. (unspec:DI [ (const_int 32 [0x20]) ] UNSPEC_VLMAX)) 2566 {vlmax_avldi} (expr_list:REG_EQUIV (unspec:DI [ (const_int 32 [0x20]) ] UNSPEC_VLMAX) (nil))) (insn 51 50 52 5 (set (reg:RVVM1SI 97 v1 [150]) (unspec:RVVM1SI [ (unspec:RVVMF32BI [ (const_vector:RVVMF32BI repeat [ (const_int 1 [0x1]) ]) (reg:DI 15 a5 [151]) (const_int 2 [0x2]) (const_int 1 [0x1]) (reg:SI 66 vl) (reg:SI 67 vtype) ] UNSPEC_VPREDICATE) (unspec:RVVM1SI [ (reg:RVVM1SI 97 v1 [orig:134 vect_result_14.6 ] [134]) (reg:RVVM1SI 98 v2 [148]) ] UNSPEC_REDUC_SUM) (unspec:RVVM1SI [ (reg:DI 0 zero) ] UNSPEC_VUNDEF) ] UNSPEC_REDUC)) 17541 {pred_redsumrvvm1si} (expr_list:REG_DEAD (reg:RVVM1SI 98 v2 [148]) (expr_list:REG_DEAD (reg:SI 66 vl) (expr_list:REG_DEAD (reg:DI 15 a5 [151]) (expr_list:REG_DEAD (reg:DI 0 zero) (nil)))))) Such situation can only happen on auto-vectorization, never happen on intrinsic codes. Since the reduction is passed VLMAX AVL, it should be more natural to pass VLMAX to the scalar move which initial the value of the reduction. After this patch: vsetvli a5,a1,e32,m1,tu,ma slli a4,a5,2 sub a1,a1,a5 vle32.v v2,0(a0) add a0,a0,a4 vadd.vv v1,v2,v1 bne a1,zero,.L3 vsetvli a5,zero,e32,m1,ta,ma vmv.s.x v2,zero vredsum.vs v1,v1,v2 vmv.x.s a0,v1 ret Tested on both RV32/RV64 no regression. PR target/113697 gcc/ChangeLog: * config/riscv/riscv-v.cc (expand_reduction): Pass VLMAX avl to scalar move. gcc/testsuite/ChangeLog: * gcc.target/riscv/rvv/autovec/pr113697.c: New test. --- gcc/config/riscv/riscv-v.cc | 12 +++++++----- gcc/testsuite/gcc.target/riscv/rvv/autovec/pr113697.c | 14 ++++++++++++++ 2 files changed, 21 insertions(+), 5 deletions(-) create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/autovec/pr113697.c (limited to 'gcc') diff --git a/gcc/config/riscv/riscv-v.cc b/gcc/config/riscv/riscv-v.cc index 4bacb7f..0cfbd21 100644 --- a/gcc/config/riscv/riscv-v.cc +++ b/gcc/config/riscv/riscv-v.cc @@ -4151,13 +4151,15 @@ expand_reduction (unsigned unspec, unsigned insn_flags, rtx *ops, rtx init) rtx m1_tmp = gen_reg_rtx (m1_mode); rtx scalar_move_ops[] = {m1_tmp, init}; - emit_nonvlmax_insn (code_for_pred_broadcast (m1_mode), SCALAR_MOVE_OP, - scalar_move_ops, - need_mask_operand_p (insn_flags) ? ops[3] - : CONST1_RTX (Pmode)); + insn_code icode = code_for_pred_broadcast (m1_mode); + if (need_mask_operand_p (insn_flags)) + emit_nonvlmax_insn (icode, SCALAR_MOVE_OP, scalar_move_ops, ops[3]); + else + emit_vlmax_insn (icode, SCALAR_MOVE_OP, scalar_move_ops); + rtx m1_tmp2 = gen_reg_rtx (m1_mode); rtx reduc_ops[] = {m1_tmp2, vector_src, m1_tmp}; - insn_code icode = code_for_pred (unspec, vmode); + icode = code_for_pred (unspec, vmode); if (need_mask_operand_p (insn_flags)) { diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/pr113697.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/pr113697.c new file mode 100644 index 0000000..588b86c --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/pr113697.c @@ -0,0 +1,14 @@ +/* { dg-do compile } */ +/* { dg-options "-O3 -march=rv64gcv -mabi=lp64d -fno-schedule-insns" } */ + +int +foo (int *__restrict a, int n) +{ + int result = 0; + for (int i = 0; i < n; i++) + result += a[i]; + return result; +} + +/* { dg-final { scan-assembler-times {vsetvli} 3 } } */ +/* { dg-final { scan-assembler-not {vsetivli} } } */ -- cgit v1.1 From 1c3cfb5a95dcc7f797ec2815690a6291878580c4 Mon Sep 17 00:00:00 2001 From: John David Anglin Date: Fri, 2 Feb 2024 18:05:06 +0000 Subject: hppa: Implement TARGET_ATOMIC_ASSIGN_EXPAND_FENV This change implements __builtin_get_fpsr() and __builtin_set_fpsr(x) to get and set the floating-point status register. They are used to implement pa_atomic_assign_expand_fenv(). 2024-02-02 John David Anglin gcc/ChangeLog: PR target/59778 * config/pa/pa.cc (enum pa_builtins): Add PA_BUILTIN_GET_FPSR and PA_BUILTIN_SET_FPSR builtins. * (pa_builtins_icode): Declare. * (def_builtin, pa_fpu_init_builtins): New. * (pa_init_builtins): Initialize FPU builtins. * (pa_builtin_decl, pa_expand_builtin_1): New. * (pa_expand_builtin): Handle PA_BUILTIN_GET_FPSR and PA_BUILTIN_SET_FPSR builtins. * (pa_atomic_assign_expand_fenv): New. * config/pa/pa.md (UNSPECV_GET_FPSR, UNSPECV_SET_FPSR): New UNSPECV constants. (get_fpsr, put_fpsr): New expanders. (get_fpsr_32, get_fpsr_64, set_fpsr_32, set_fpsr_64): New insn patterns. --- gcc/config/pa/pa.cc | 215 +++++++++++++++++++++++++++++++++++++++++++++++++++- gcc/config/pa/pa.md | 84 ++++++++++++++++++++ 2 files changed, 298 insertions(+), 1 deletion(-) (limited to 'gcc') diff --git a/gcc/config/pa/pa.cc b/gcc/config/pa/pa.cc index c58b0a0..694123e 100644 --- a/gcc/config/pa/pa.cc +++ b/gcc/config/pa/pa.cc @@ -28,6 +28,7 @@ along with GCC; see the file COPYING3. If not see #include "target.h" #include "rtl.h" #include "tree.h" +#include "gimple.h" #include "df.h" #include "tm_p.h" #include "stringpool.h" @@ -142,6 +143,7 @@ static void pa_asm_out_destructor (rtx, int); #endif static void pa_init_builtins (void); static rtx pa_expand_builtin (tree, rtx, rtx, machine_mode mode, int); +static tree pa_builtin_decl (unsigned, bool); static rtx hppa_builtin_saveregs (void); static void hppa_va_start (tree, rtx); static tree hppa_gimplify_va_arg_expr (tree, tree, gimple_seq *, gimple_seq *); @@ -205,6 +207,7 @@ static bool pa_modes_tieable_p (machine_mode, machine_mode); static bool pa_can_change_mode_class (machine_mode, machine_mode, reg_class_t); static HOST_WIDE_INT pa_starting_frame_offset (void); static section* pa_elf_select_rtx_section(machine_mode, rtx, unsigned HOST_WIDE_INT) ATTRIBUTE_UNUSED; +static void pa_atomic_assign_expand_fenv (tree *, tree *, tree *); /* The following extra sections are only used for SOM. */ static GTY(()) section *som_readonly_data_section; @@ -314,9 +317,10 @@ static size_t n_deferred_plabels = 0; #undef TARGET_INIT_BUILTINS #define TARGET_INIT_BUILTINS pa_init_builtins - #undef TARGET_EXPAND_BUILTIN #define TARGET_EXPAND_BUILTIN pa_expand_builtin +#undef TARGET_BUILTIN_DECL +#define TARGET_BUILTIN_DECL pa_builtin_decl #undef TARGET_REGISTER_MOVE_COST #define TARGET_REGISTER_MOVE_COST hppa_register_move_cost @@ -426,6 +430,9 @@ static size_t n_deferred_plabels = 0; #undef TARGET_HAVE_SPECULATION_SAFE_VALUE #define TARGET_HAVE_SPECULATION_SAFE_VALUE speculation_safe_value_not_needed +#undef TARGET_ATOMIC_ASSIGN_EXPAND_FENV +#define TARGET_ATOMIC_ASSIGN_EXPAND_FENV pa_atomic_assign_expand_fenv + struct gcc_target targetm = TARGET_INITIALIZER; /* Parse the -mfixed-range= option string. */ @@ -592,6 +599,10 @@ pa_option_override (void) enum pa_builtins { + /* FPU builtins. */ + PA_BUILTIN_GET_FPSR, + PA_BUILTIN_SET_FPSR, + PA_BUILTIN_COPYSIGNQ, PA_BUILTIN_FABSQ, PA_BUILTIN_INFQ, @@ -600,10 +611,48 @@ enum pa_builtins }; static GTY(()) tree pa_builtins[(int) PA_BUILTIN_max]; +static GTY(()) enum insn_code pa_builtins_icode[(int) PA_BUILTIN_max]; + +/* Add a PA builtin function with NAME, ICODE, CODE and TYPE. Return the + function decl or NULL_TREE if the builtin was not added. */ + +static tree +def_builtin (const char *name, enum insn_code icode, enum pa_builtins code, + tree type) +{ + tree t + = add_builtin_function (name, type, code, BUILT_IN_MD, NULL, NULL_TREE); + + if (t) + { + pa_builtins[code] = t; + pa_builtins_icode[code] = icode; + } + + return t; +} + +/* Create builtin functions for FPU instructions. */ + +static void +pa_fpu_init_builtins (void) +{ + tree ftype; + + ftype = build_function_type_list (unsigned_type_node, 0); + def_builtin ("__builtin_get_fpsr", CODE_FOR_get_fpsr, + PA_BUILTIN_GET_FPSR, ftype); + ftype = build_function_type_list (void_type_node, unsigned_type_node, 0); + def_builtin ("__builtin_set_fpsr", CODE_FOR_set_fpsr, + PA_BUILTIN_SET_FPSR, ftype); +} static void pa_init_builtins (void) { + if (!TARGET_SOFT_FLOAT) + pa_fpu_init_builtins (); + #ifdef DONT_HAVE_FPUTC_UNLOCKED { tree decl = builtin_decl_explicit (BUILT_IN_PUTC_UNLOCKED); @@ -663,6 +712,92 @@ pa_init_builtins (void) } } +/* Implement TARGET_BUILTIN_DECL. */ + +static tree +pa_builtin_decl (unsigned int code, bool initialize_p ATTRIBUTE_UNUSED) +{ + if (code >= PA_BUILTIN_max) + return error_mark_node; + return pa_builtins[code]; +} + +static rtx +pa_expand_builtin_1 (tree exp, rtx target, + rtx subtarget ATTRIBUTE_UNUSED, + machine_mode tmode ATTRIBUTE_UNUSED, + int ignore ATTRIBUTE_UNUSED) +{ + tree fndecl = TREE_OPERAND (CALL_EXPR_FN (exp), 0); + enum pa_builtins code + = (enum pa_builtins) DECL_MD_FUNCTION_CODE (fndecl); + enum insn_code icode = pa_builtins_icode[code]; + bool nonvoid = TREE_TYPE (TREE_TYPE (fndecl)) != void_type_node; + call_expr_arg_iterator iter; + int arg_count = 0; + rtx pat, op[4]; + tree arg; + + if (nonvoid) + { + machine_mode tmode = insn_data[icode].operand[0].mode; + if (!target + || GET_MODE (target) != tmode + || ! (*insn_data[icode].operand[0].predicate) (target, tmode)) + op[0] = gen_reg_rtx (tmode); + else + op[0] = target; + } + else + op[0] = NULL_RTX; + + FOR_EACH_CALL_EXPR_ARG (arg, iter, exp) + { + const struct insn_operand_data *insn_op; + int idx; + + if (arg == error_mark_node) + return NULL_RTX; + + arg_count++; + idx = arg_count - !nonvoid; + insn_op = &insn_data[icode].operand[idx]; + op[arg_count] = expand_normal (arg); + + if (! (*insn_data[icode].operand[idx].predicate) (op[arg_count], + insn_op->mode)) + op[arg_count] = copy_to_mode_reg (insn_op->mode, op[arg_count]); + } + + switch (arg_count) + { + case 0: + pat = GEN_FCN (icode) (op[0]); + break; + case 1: + if (nonvoid) + pat = GEN_FCN (icode) (op[0], op[1]); + else + pat = GEN_FCN (icode) (op[1]); + break; + case 2: + pat = GEN_FCN (icode) (op[0], op[1], op[2]); + break; + case 3: + pat = GEN_FCN (icode) (op[0], op[1], op[2], op[3]); + break; + default: + gcc_unreachable (); + } + + if (!pat) + return NULL_RTX; + + emit_insn (pat); + + return (nonvoid ? op[0] : const0_rtx); +} + static rtx pa_expand_builtin (tree exp, rtx target, rtx subtarget ATTRIBUTE_UNUSED, machine_mode mode ATTRIBUTE_UNUSED, @@ -673,6 +808,10 @@ pa_expand_builtin (tree exp, rtx target, rtx subtarget ATTRIBUTE_UNUSED, switch (fcode) { + case PA_BUILTIN_GET_FPSR: + case PA_BUILTIN_SET_FPSR: + return pa_expand_builtin_1 (exp, target, subtarget, mode, ignore); + case PA_BUILTIN_FABSQ: case PA_BUILTIN_COPYSIGNQ: return expand_call (exp, target, ignore); @@ -11099,4 +11238,78 @@ pa_function_arg_size (machine_mode mode, const_tree type) return (int) CEIL (size, UNITS_PER_WORD); } +/* Implement TARGET_ATOMIC_ASSIGN_EXPAND_FENV. */ + +static void +pa_atomic_assign_expand_fenv (tree *hold, tree *clear, tree *update) +{ + const unsigned PA_FE_INEXACT = 1; + const unsigned PA_FE_UNDERFLOW = 2; + const unsigned PA_FE_OVERFLOW = 4; + const unsigned PA_FE_DIVBYZERO = 8; + const unsigned PA_FE_INVALID = 16; + const unsigned HOST_WIDE_INT PA_FE_ALL_EXCEPT = (PA_FE_INVALID + | PA_FE_DIVBYZERO + | PA_FE_OVERFLOW + | PA_FE_UNDERFLOW + | PA_FE_INEXACT); + const unsigned HOST_WIDE_INT PA_FE_EXCEPT_SHIFT = 27; + tree fenv_var, get_fpsr, set_fpsr, mask, ld_fenv, masked_fenv; + tree hold_all, new_fenv_var, reload_fenv, restore_fnenv; + tree get_fpsr_call, set_fpsr_call, update_call, atomic_feraiseexcept; + + if (TARGET_SOFT_FLOAT) + return; + + /* Generate the equivalent of : + unsigned int fenv_var; + fenv_var = __builtin_get_fpsr (); + + unsigned int masked_fenv; + masked_fenv = fenv_var & mask; + + __builtin_set_fpsr (masked_fenv); */ + + fenv_var = create_tmp_var_raw (unsigned_type_node); + get_fpsr = pa_builtins[PA_BUILTIN_GET_FPSR]; + set_fpsr = pa_builtins[PA_BUILTIN_SET_FPSR]; + mask = build_int_cst (unsigned_type_node, + ~((PA_FE_ALL_EXCEPT << PA_FE_EXCEPT_SHIFT) + | PA_FE_ALL_EXCEPT)); + + get_fpsr_call = build_call_expr (get_fpsr, 0); + ld_fenv = build4 (TARGET_EXPR, unsigned_type_node, + fenv_var, get_fpsr_call, + NULL_TREE, NULL_TREE); + masked_fenv = build2 (BIT_AND_EXPR, unsigned_type_node, fenv_var, mask); + hold_all = build2 (COMPOUND_EXPR, void_type_node, masked_fenv, ld_fenv); + set_fpsr_call = build_call_expr (set_fpsr, 1, masked_fenv); + *hold = build2 (COMPOUND_EXPR, void_type_node, hold_all, set_fpsr_call); + + /* Store the value of masked_fenv to clear the exceptions: + __builtin_set_fpsr (masked_fenv); */ + + *clear = set_fpsr_call; + + /* Generate the equivalent of : + unsigned int new_fenv_var; + new_fenv_var = __builtin_get_fpsr (); + + __builtin_set_fpsr (fenv_var); + + __atomic_feraiseexcept (new_fenv_var); */ + + new_fenv_var = create_tmp_var_raw (unsigned_type_node); + reload_fenv = build4 (TARGET_EXPR, unsigned_type_node, new_fenv_var, + get_fpsr_call, NULL_TREE, NULL_TREE); + restore_fnenv = build_call_expr (set_fpsr, 1, fenv_var); + atomic_feraiseexcept = builtin_decl_implicit (BUILT_IN_ATOMIC_FERAISEEXCEPT); + update_call = build_call_expr (atomic_feraiseexcept, 1, + fold_convert (integer_type_node, + new_fenv_var)); + *update = build2 (COMPOUND_EXPR, void_type_node, + build2 (COMPOUND_EXPR, void_type_node, + reload_fenv, restore_fnenv), update_call); +} + #include "gt-pa.h" diff --git a/gcc/config/pa/pa.md b/gcc/config/pa/pa.md index aecdcc9..b0f29a4 100644 --- a/gcc/config/pa/pa.md +++ b/gcc/config/pa/pa.md @@ -96,6 +96,8 @@ UNSPECV_OPC ; outline_prologue_call UNSPECV_OEC ; outline_epilogue_call UNSPECV_LONGJMP ; builtin_longjmp + UNSPECV_GET_FPSR ; get floating-point status register + UNSPECV_SET_FPSR ; set floating-point status register ]) ;; Maximum pc-relative branch offsets. @@ -10784,3 +10786,85 @@ add,l %2,%3,%3\;bv,n %%r0(%3)" "ldo 15(%%sp),%1\n\t{dep|depw} %%r0,31,3,%1\n\t{ldcw|ldcw,co} 0(%1),%1" [(set_attr "type" "binary") (set_attr "length" "12")]) + +;; Get floating-point status register. + +(define_expand "get_fpsr" + [(set (match_operand:SI 0 "register_operand" "=r") + (unspec_volatile:SI [(const_int 0)] UNSPECV_GET_FPSR))] + "" +{ + if (TARGET_SOFT_FLOAT) + FAIL; + + if (TARGET_64BIT) + emit_insn (gen_get_fpsr_64 (operands[0])); + else + emit_insn (gen_get_fpsr_32 (operands[0])); + DONE; +}) + +;; The floating-point status register is stored to an unused slot in +;; the frame marker and then loaded to register operand 0. The final +;; floating-point load restores the T bit in the status register. + +;; The final load might be avoided if a word mode store was used to +;; store the status register. It is unclear why we need a double-word +;; store. I suspect PA 1.0 didn't support single-word stores of the +;; status register. + +(define_insn "get_fpsr_32" + [(set (match_operand:SI 0 "register_operand" "=r") + (unspec_volatile:SI [(const_int 0)] UNSPECV_GET_FPSR))] + "!TARGET_SOFT_FLOAT && !TARGET_64BIT" + "{fstds|fstd} %%fr0,-16(%%sp)\n\tldw -16(%%sp),%0\n\t{fldds|fldd} -16(%%sp),%%fr0" + [(set_attr "type" "fpstore_load") + (set_attr "length" "12")]) + +;; The 64-bit pattern is similar to the 32-bit pattern except we need +;; compute the address of the frame location as long displacements aren't +;; supported on Linux targets. + +(define_insn "get_fpsr_64" + [(set (match_operand:SI 0 "register_operand" "=r") + (unspec_volatile:SI [(const_int 0)] UNSPECV_GET_FPSR)) + (clobber (match_scratch:DI 1 "=&r"))] + "!TARGET_SOFT_FLOAT && TARGET_64BIT" + "ldo -40(%%sp),%1\n\tfstd %%fr0,0(%1)\n\tldw 0(%1),%0\n\tfldd 0(%1),%%fr0" + [(set_attr "type" "fpstore_load") + (set_attr "length" "16")]) + +;; Set floating-point status register. + +(define_expand "set_fpsr" + [(unspec_volatile [(match_operand:SI 0 "register_operand" "r")] UNSPECV_SET_FPSR)] + "" +{ + if (TARGET_SOFT_FLOAT) + FAIL; + + if (TARGET_64BIT) + emit_insn (gen_set_fpsr_64 (operands[0])); + else + emit_insn (gen_set_fpsr_32 (operands[0])); + DONE; +}) + +;; The old T bit is extracted and stored in the new status register. + +(define_insn "set_fpsr_32" + [(unspec_volatile [(match_operand:SI 0 "register_operand" "r")] UNSPECV_SET_FPSR) + (clobber (match_scratch:SI 1 "=&r"))] + "!TARGET_SOFT_FLOAT && !TARGET_64BIT" + "{fstds|fstd} %%fr0,-16(%%sp)\n\tldw -16(%%sp),%1\n\t{extru|extrw,u} %1,25,1,%1\n\t{dep|depw} %1,25,1,%0\n\tstw %0,-16(%%sp)\n\t{fldds|fldd} -16(%%sp),%%fr0" + [(set_attr "type" "store_fpload") + (set_attr "length" "24")]) + +(define_insn "set_fpsr_64" + [(unspec_volatile [(match_operand:SI 0 "register_operand" "r")] UNSPECV_SET_FPSR) + (clobber (match_scratch:DI 1 "=&r")) + (clobber (match_scratch:SI 2 "=&r"))] + "!TARGET_SOFT_FLOAT && TARGET_64BIT" + "ldo -40(%%sp),%1\n\tfstd %%fr0,0(%1)\n\tldw 0(%1),%2\n\textrw,u %2,25,1,%2\n\tdepw %2,25,1,%0\n\tstw %0,0(%1)\n\tfldd 0(%1),%%fr0" + [(set_attr "type" "store_fpload") + (set_attr "length" "28")]) -- cgit v1.1 From e17a122d417fc0d606bcb3a3705b93ee81745cab Mon Sep 17 00:00:00 2001 From: Jason Merrill Date: Fri, 2 Feb 2024 12:04:11 -0500 Subject: c++: op== defaulted outside class [PR110084] defaulted_late_check is for checks that need to happen after the class is complete; we shouldn't call it sooner. PR c++/110084 gcc/cp/ChangeLog: * pt.cc (tsubst_function_decl): Only check a function defaulted outside the class if the class is complete. gcc/testsuite/ChangeLog: * g++.dg/cpp2a/spaceship-synth-neg3.C: Check error message. * g++.dg/cpp2a/spaceship-eq16.C: New test. --- gcc/cp/pt.cc | 1 + gcc/testsuite/g++.dg/cpp2a/spaceship-eq16.C | 11 +++++++++++ gcc/testsuite/g++.dg/cpp2a/spaceship-synth-neg3.C | 2 +- 3 files changed, 13 insertions(+), 1 deletion(-) create mode 100644 gcc/testsuite/g++.dg/cpp2a/spaceship-eq16.C (limited to 'gcc') diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc index 9d30a27..355e960 100644 --- a/gcc/cp/pt.cc +++ b/gcc/cp/pt.cc @@ -14812,6 +14812,7 @@ tsubst_function_decl (tree t, tree args, tsubst_flags_t complain, if (DECL_SECTION_NAME (t)) set_decl_section_name (r, t); if (DECL_DEFAULTED_OUTSIDE_CLASS_P (r) + && COMPLETE_TYPE_P (DECL_CONTEXT (r)) && !processing_template_decl) defaulted_late_check (r); diff --git a/gcc/testsuite/g++.dg/cpp2a/spaceship-eq16.C b/gcc/testsuite/g++.dg/cpp2a/spaceship-eq16.C new file mode 100644 index 0000000..e5538ea --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp2a/spaceship-eq16.C @@ -0,0 +1,11 @@ +// PR c++/110084 +// { dg-do compile { target c++20 } } + +template +class BadTuple { + constexpr bool operator==(const BadTuple&) const; +}; +template +constexpr bool BadTuple::operator==(const BadTuple&) const = default; + +BadTuple a; diff --git a/gcc/testsuite/g++.dg/cpp2a/spaceship-synth-neg3.C b/gcc/testsuite/g++.dg/cpp2a/spaceship-synth-neg3.C index a4d8b32..aaa0264 100644 --- a/gcc/testsuite/g++.dg/cpp2a/spaceship-synth-neg3.C +++ b/gcc/testsuite/g++.dg/cpp2a/spaceship-synth-neg3.C @@ -5,7 +5,7 @@ template struct A {}; struct B { - constexpr auto operator<=>(const B&) const = default; // { dg-error "" } + constexpr auto operator<=>(const B&) const = default; // { dg-error "strong_ordering" } int value; }; -- cgit v1.1 From 5d534a214bf96605d1eeff44d41ced3a7d4397f6 Mon Sep 17 00:00:00 2001 From: Antoni Boucher Date: Tue, 19 Sep 2023 22:10:47 -0400 Subject: libgccjit: Implement sizeof operator gcc/jit/ChangeLog: * docs/topics/compatibility.rst (LIBGCCJIT_ABI_27): New ABI tag. * docs/topics/expressions.rst: Document gcc_jit_context_new_sizeof. * jit-playback.cc (new_sizeof): New method. * jit-playback.h (new_sizeof): New method. * jit-recording.cc (recording::context::new_sizeof, recording::memento_of_sizeof::replay_into, recording::memento_of_sizeof::make_debug_string, recording::memento_of_sizeof::write_reproducer): New methods. * jit-recording.h (class memento_of_sizeof): New class. * libgccjit.cc (gcc_jit_context_new_sizeof): New function. * libgccjit.h (gcc_jit_context_new_sizeof): New function. * libgccjit.map: New function. gcc/testsuite/ChangeLog: * jit.dg/all-non-failing-tests.h: New test. * jit.dg/test-sizeof.c: New test. --- gcc/jit/docs/topics/compatibility.rst | 7 ++++ gcc/jit/docs/topics/expressions.rst | 14 ++++++++ gcc/jit/jit-playback.cc | 10 ++++++ gcc/jit/jit-playback.h | 3 ++ gcc/jit/jit-recording.cc | 52 ++++++++++++++++++++++++++++ gcc/jit/jit-recording.h | 28 +++++++++++++++ gcc/jit/libgccjit.cc | 18 ++++++++++ gcc/jit/libgccjit.h | 12 +++++++ gcc/jit/libgccjit.map | 5 +++ gcc/testsuite/jit.dg/all-non-failing-tests.h | 10 ++++++ gcc/testsuite/jit.dg/test-sizeof.c | 50 ++++++++++++++++++++++++++ 11 files changed, 209 insertions(+) create mode 100644 gcc/testsuite/jit.dg/test-sizeof.c (limited to 'gcc') diff --git a/gcc/jit/docs/topics/compatibility.rst b/gcc/jit/docs/topics/compatibility.rst index cbf5b41..9cfb054 100644 --- a/gcc/jit/docs/topics/compatibility.rst +++ b/gcc/jit/docs/topics/compatibility.rst @@ -390,3 +390,10 @@ on functions and variables: * :func:`gcc_jit_function_add_string_attribute` * :func:`gcc_jit_function_add_integer_array_attribute` * :func:`gcc_jit_lvalue_add_string_attribute` + +.. _LIBGCCJIT_ABI_27: + +``LIBGCCJIT_ABI_27`` +-------------------- +``LIBGCCJIT_ABI_27`` covers the addition of +:func:`gcc_jit_context_new_sizeof` diff --git a/gcc/jit/docs/topics/expressions.rst b/gcc/jit/docs/topics/expressions.rst index 35ee05c..c3f4f61 100644 --- a/gcc/jit/docs/topics/expressions.rst +++ b/gcc/jit/docs/topics/expressions.rst @@ -126,6 +126,20 @@ Simple expressions underlying string, so it is valid to pass in a pointer to an on-stack buffer. +.. function:: gcc_jit_rvalue *\ + gcc_jit_context_new_sizeof (gcc_jit_context *ctxt, \ + gcc_jit_type *type) + + Generate an rvalue that is equal to the size of ``type``. + + The parameter ``type`` must be non-NULL. + + This is equivalent to this C code: + + .. code-block:: c + + sizeof (type) + Constructor expressions *********************** diff --git a/gcc/jit/jit-playback.cc b/gcc/jit/jit-playback.cc index 84df6c1..e277b01 100644 --- a/gcc/jit/jit-playback.cc +++ b/gcc/jit/jit-playback.cc @@ -1112,6 +1112,16 @@ new_rvalue_from_const (type *type, playback::rvalue * playback::context:: +new_sizeof (type *type) +{ + tree inner = TYPE_SIZE_UNIT (type->as_tree ()); + return new rvalue (this, inner); +} + +/* Construct a playback::rvalue instance (wrapping a tree). */ + +playback::rvalue * +playback::context:: new_string_literal (const char *value) { /* Compare with c-family/c-common.cc: fix_string_type. */ diff --git a/gcc/jit/jit-playback.h b/gcc/jit/jit-playback.h index 05bafcd..aa6a086 100644 --- a/gcc/jit/jit-playback.h +++ b/gcc/jit/jit-playback.h @@ -163,6 +163,9 @@ public: HOST_TYPE value); rvalue * + new_sizeof (type *type); + + rvalue * new_string_literal (const char *value); rvalue * diff --git a/gcc/jit/jit-recording.cc b/gcc/jit/jit-recording.cc index 6ffadbe..68a2e86 100644 --- a/gcc/jit/jit-recording.cc +++ b/gcc/jit/jit-recording.cc @@ -1077,6 +1077,21 @@ recording::context::new_global_init_rvalue (lvalue *variable, gbl->set_rvalue_init (init); /* Needed by the global for write dump. */ } +/* Create a recording::memento_of_sizeof instance and add it + to this context's list of mementos. + + Implements the post-error-checking part of + gcc_jit_context_new_sizeof. */ + +recording::rvalue * +recording::context::new_sizeof (recording::type *type) +{ + recording::rvalue *result = + new memento_of_sizeof (this, NULL, type); + record (result); + return result; +} + /* Create a recording::memento_of_new_string_literal instance and add it to this context's list of mementos. @@ -5457,6 +5472,43 @@ memento_of_new_rvalue_from_const ::write_reproducer (reproducer &r) } // namespace recording +/* The implementation of class gcc::jit::recording::memento_of_sizeof. */ + +/* Implementation of pure virtual hook recording::memento::replay_into + for recording::memento_of_sizeof. */ + +void +recording::memento_of_sizeof::replay_into (replayer *r) +{ + set_playback_obj (r->new_sizeof (m_type->playback_type ())); +} + +/* Implementation of recording::memento::make_debug_string for + sizeof expressions. */ + +recording::string * +recording::memento_of_sizeof::make_debug_string () +{ + return string::from_printf (m_ctxt, + "sizeof (%s)", + m_type->get_debug_string ()); +} + +/* Implementation of recording::memento::write_reproducer for sizeof + expressions. */ + +void +recording::memento_of_sizeof::write_reproducer (reproducer &r) +{ + const char *id = r.make_identifier (this, "rvalue"); + r.write (" gcc_jit_rvalue *%s =\n" + " gcc_jit_context_new_sizeof (%s, /* gcc_jit_context *ctxt */\n" + " %s); /* gcc_jit_type *type */\n", + id, + r.get_identifier (get_context ()), + r.get_identifier (m_type)); +} + /* The implementation of class gcc::jit::recording::memento_of_new_string_literal. */ /* Implementation of pure virtual hook recording::memento::replay_into diff --git a/gcc/jit/jit-recording.h b/gcc/jit/jit-recording.h index ab5ba6c..d8d16f4 100644 --- a/gcc/jit/jit-recording.h +++ b/gcc/jit/jit-recording.h @@ -170,6 +170,9 @@ public: HOST_TYPE value); rvalue * + new_sizeof (type *type); + + rvalue * new_string_literal (const char *value); rvalue * @@ -1605,6 +1608,31 @@ private: HOST_TYPE m_value; }; +class memento_of_sizeof : public rvalue +{ +public: + memento_of_sizeof (context *ctxt, + location *loc, + type *type) + : rvalue (ctxt, loc, ctxt->get_type (GCC_JIT_TYPE_INT)), + m_type (type) {} + + void replay_into (replayer *r) final override; + + void visit_children (rvalue_visitor *) final override {} + +private: + string * make_debug_string () final override; + void write_reproducer (reproducer &r) final override; + enum precedence get_precedence () const final override + { + return PRECEDENCE_PRIMARY; + } + +private: + type *m_type; +}; + class memento_of_new_string_literal : public rvalue { public: diff --git a/gcc/jit/libgccjit.cc b/gcc/jit/libgccjit.cc index bf0150f..f40a978 100644 --- a/gcc/jit/libgccjit.cc +++ b/gcc/jit/libgccjit.cc @@ -2076,6 +2076,24 @@ gcc_jit_context_null (gcc_jit_context *ctxt, /* Public entrypoint. See description in libgccjit.h. After error-checking, the real work is done by the + gcc::jit::recording::context::new_sizeof method in + jit-recording.cc. */ + +gcc_jit_rvalue * +gcc_jit_context_new_sizeof (gcc_jit_context *ctxt, + gcc_jit_type *type) +{ + RETURN_NULL_IF_FAIL (ctxt, NULL, NULL, "NULL context"); + RETURN_NULL_IF_FAIL (type, ctxt, NULL, "NULL type"); + JIT_LOG_FUNC (ctxt->get_logger ()); + + return ((gcc_jit_rvalue *)ctxt + ->new_sizeof (type)); +} + +/* Public entrypoint. See description in libgccjit.h. + + After error-checking, the real work is done by the gcc::jit::recording::context::new_string_literal method in jit-recording.cc. */ diff --git a/gcc/jit/libgccjit.h b/gcc/jit/libgccjit.h index 235cab0..74e847b 100644 --- a/gcc/jit/libgccjit.h +++ b/gcc/jit/libgccjit.h @@ -1093,6 +1093,18 @@ extern gcc_jit_rvalue * gcc_jit_context_null (gcc_jit_context *ctxt, gcc_jit_type *pointer_type); +#define LIBGCCJIT_HAVE_gcc_jit_context_new_sizeof + +/* Generates an rvalue that is equal to the size of type. + + This API entrypoint was added in LIBGCCJIT_ABI_27; you can test for its + presence using + #ifdef LIBGCCJIT_HAVE_gcc_jit_context_new_sizeof */ + +extern gcc_jit_rvalue * +gcc_jit_context_new_sizeof (gcc_jit_context *ctxt, + gcc_jit_type *type); + /* String literals. */ extern gcc_jit_rvalue * gcc_jit_context_new_string_literal (gcc_jit_context *ctxt, diff --git a/gcc/jit/libgccjit.map b/gcc/jit/libgccjit.map index dfb8a9d..99aa597 100644 --- a/gcc/jit/libgccjit.map +++ b/gcc/jit/libgccjit.map @@ -284,3 +284,8 @@ LIBGCCJIT_ABI_26 { gcc_jit_lvalue_add_string_attribute; gcc_jit_function_add_integer_array_attribute; } LIBGCCJIT_ABI_25; + +LIBGCCJIT_ABI_27 { + global: + gcc_jit_context_new_sizeof; +} LIBGCCJIT_ABI_26; diff --git a/gcc/testsuite/jit.dg/all-non-failing-tests.h b/gcc/testsuite/jit.dg/all-non-failing-tests.h index d09a31e..14a0a32 100644 --- a/gcc/testsuite/jit.dg/all-non-failing-tests.h +++ b/gcc/testsuite/jit.dg/all-non-failing-tests.h @@ -353,6 +353,13 @@ /* test-setting-alignment.c: This can't be in the testcases array as it is target-specific. */ +/* test-sizeof.c */ +#define create_code create_code_sizeof +#define verify_code verify_code_sizeof +#include "test-sizeof.c" +#undef create_code +#undef verify_code + /* test-string-literal.c */ #define create_code create_code_string_literal #define verify_code verify_code_string_literal @@ -553,6 +560,9 @@ const struct testcase testcases[] = { {"reflection", create_code_reflection , verify_code_reflection }, + {"sizeof", + create_code_sizeof, + verify_code_sizeof}, {"string_literal", create_code_string_literal, verify_code_string_literal}, diff --git a/gcc/testsuite/jit.dg/test-sizeof.c b/gcc/testsuite/jit.dg/test-sizeof.c new file mode 100644 index 0000000..6aef902 --- /dev/null +++ b/gcc/testsuite/jit.dg/test-sizeof.c @@ -0,0 +1,50 @@ +#include +#include +#include +#include + +#include "libgccjit.h" + +#include "harness.h" + +void +create_code (gcc_jit_context *ctxt, void *user_data) +{ + /* Let's try to inject the equivalent of: +int +my_sizeof () +{ + return sizeof(int32_t); +} + */ + gcc_jit_type *int32 = + gcc_jit_context_get_int_type (ctxt, 4, 1); + gcc_jit_type *int_type = + gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_INT); + + gcc_jit_function *func = + gcc_jit_context_new_function (ctxt, + NULL, + GCC_JIT_FUNCTION_EXPORTED, + int_type, + "my_sizeof", + 0, NULL, 0); + + gcc_jit_block *initial = + gcc_jit_function_new_block (func, "initial"); + + gcc_jit_block_end_with_return(initial, NULL, + gcc_jit_context_new_sizeof(ctxt, int32)); +} + +void +verify_code (gcc_jit_context *ctxt, gcc_jit_result *result) +{ + typedef int (*my_sizeof_type) (); + CHECK_NON_NULL (result); + my_sizeof_type my_sizeof = + (my_sizeof_type)gcc_jit_result_get_code (result, "my_sizeof"); + CHECK_NON_NULL (my_sizeof); + int val = my_sizeof (); + CHECK_VALUE (val, 4); +} -- cgit v1.1 From fbb569315a291d2d5b32ad0fdaf0c42da9f5e93b Mon Sep 17 00:00:00 2001 From: Jakub Jelinek Date: Fri, 2 Feb 2024 22:14:33 +0100 Subject: libgcc: Fix up _BitInt division [PR113604] The following testcase ends up with SIGFPE in __divmodbitint4. The problem is a thinko in my attempt to implement Knuth's algorithm. The algorithm does (where b is 65536, i.e. one larger than what fits in their unsigned short word): // Compute estimate qhat of q[j]. qhat = (un[j+n]*b + un[j+n-1])/vn[n-1]; rhat = (un[j+n]*b + un[j+n-1]) - qhat*vn[n-1]; again: if (qhat >= b || qhat*vn[n-2] > b*rhat + un[j+n-2]) { qhat = qhat - 1; rhat = rhat + vn[n-1]; if (rhat < b) goto again; } The problem is that it uses a double-word / word -> double-word division (and modulo), while all we have is udiv_qrnnd unless we'd want to do further library calls, and udiv_qrnnd is a double-word / word -> word division and modulo. Now, as the algorithm description says, it can produce at most word bits + 1 bit quotient. And I believe that actually the highest qhat the original algorithm can produce is (1 << word_bits) + 1. The algorithm performs earlier canonicalization where both the divisor and dividend are shifted left such that divisor has msb set. If it has msb set already before, no shifting occurs but we start with added 0 limb, so in the first uv1:uv0 double-word uv1 is 0 and so we can't get too high qhat, if shifting occurs, the first limb of dividend is shifted right by UWtype bits - shift count into a new limb, so again in the first iteration in the uv1:uv0 double-word uv1 doesn't have msb set while vv1 does and qhat has to fit into word. In the following iterations, previous iteration should guarantee that the previous quotient digit is correct. Even if the divisor was the maximal possible vv1:all_ones_in_all_lower_limbs, if the old uv0:lower_limbs would be larger or equal to the divisor, the previous quotient digit would increase and another divisor would be subtracted, which I think implies that in the next iteration in uv1:uv0 double-word uv1 <= vv1, but uv0 could be up to all ones, e.g. in case of all lower limbs of divisor being all ones and at least one dividend limb below uv0 being not all ones. So, we can e.g. for 64-bit UWtype see uv1:uv0 / vv1 0x8000000000000000UL:0xffffffffffffffffUL / 0x8000000000000000UL or 0xffffffffffffffffUL:0xffffffffffffffffUL / 0xffffffffffffffffUL In all these cases (when uv1 == vv1 && uv0 >= uv1), qhat is 0x10000000000000001UL, i.e. 2 more than fits into UWtype result, if uv1 == vv1 && uv0 < uv1 it would be 0x10000000000000000UL, i.e. 1 more than fits into UWtype result. Because we only have udiv_qrnnd which can't deal with those too large cases (SIGFPEs or otherwise invokes undefined behavior on those), I've tried to handle the uv1 >= vv1 case separately, but for one thing I thought it would be at most 1 larger than what fits, and for two have actually subtracted vv1:vv1 from uv1:uv0 instead of subtracting 0:vv1 from uv1:uv0. For the uv1 < vv1 case, the implementation already performs roughly what the algorithm does. Now, let's see what happens with the two possible extra cases in the original algorithm. If uv1 == vv1 && uv0 < uv1, qhat above would be b, so we take if (qhat >= b, decrement qhat by 1 (it becomes b - 1), add vn[n-1] aka vv1 to rhat and goto again if rhat < b (but because qhat already fits we can goto to the again label in the uv1 < vv1 code). rhat in this case is uv0 and rhat + vv1 can but doesn't have to overflow, say for uv0 42UL and vv1 0x8000000000000000UL it will not (and so we should goto again), while for uv0 0x8000000000000000UL and vv1 0x8000000000000001UL it will (and we shouldn't goto again). If uv1 == vv1 && uv0 >= uv1, qhat above would be b + 1, so we take if (qhat >= b, decrement qhat by 1 (it becomes b), add vn[n-1] aka vv1 to rhat. But because vv1 has msb set and rhat in this case is uv0 - vv1, the rhat + vv1 addition certainly doesn't overflow, because (uv0 - vv1) + vv1 is uv0, so in the algorithm we goto again, again take if (qhat >= b and decrement qhat so it finally becomes b - 1, and add vn[n-1] aka vv1 to rhat again. But this time I believe it must always overflow, simply because we added (uv0 - vv1) + vv1 + vv1 and vv1 has msb set, so already vv1 + vv1 must overflow. And because it overflowed, it will not goto again. So, I believe the following patch implements this correctly, by subtracting vv1 from uv1:uv0 double-word once, then comparing again if uv1 >= vv1. If that is true, subtract vv1 from uv1:uv0 again and add 2 * vv1 to rhat, no __builtin_add_overflow is needed as we know it always overflowed and so won't goto again. If after the first subtraction uv1 < vv1, use __builtin_add_overflow when adding vv1 to rhat, because it can but doesn't have to overflow. I've added an extra testcase which tests the behavior of all the changed cases, so it has a case where uv1:uv0 / vv1 is 1:1, where it is 1:0 and rhat + vv1 overflows and where it is 1:0 and rhat + vv1 does not overflow, and includes tests also from Zdenek's other failing tests. 2024-02-02 Jakub Jelinek PR libgcc/113604 * libgcc2.c (__divmodbitint4): If uv1 >= vv1, subtract vv1 from uv1:uv0 once or twice as needed, rather than subtracting vv1:vv1. * gcc.dg/torture/bitint-53.c: New test. * gcc.dg/torture/bitint-55.c: New test. --- gcc/testsuite/gcc.dg/torture/bitint-53.c | 26 +++++++++++++ gcc/testsuite/gcc.dg/torture/bitint-55.c | 66 ++++++++++++++++++++++++++++++++ 2 files changed, 92 insertions(+) create mode 100644 gcc/testsuite/gcc.dg/torture/bitint-53.c create mode 100644 gcc/testsuite/gcc.dg/torture/bitint-55.c (limited to 'gcc') diff --git a/gcc/testsuite/gcc.dg/torture/bitint-53.c b/gcc/testsuite/gcc.dg/torture/bitint-53.c new file mode 100644 index 0000000..8ead40e --- /dev/null +++ b/gcc/testsuite/gcc.dg/torture/bitint-53.c @@ -0,0 +1,26 @@ +/* PR libgcc/113604 */ +/* { dg-do run { target bitint } } */ +/* { dg-options "-std=c23 -pedantic-errors" } */ +/* { dg-skip-if "" { ! run_expensive_tests } { "*" } { "-O0" "-O2" } } */ +/* { dg-skip-if "" { ! run_expensive_tests } { "-flto" } { "" } } */ + +#if __BITINT_MAXWIDTH__ >= 256 +unsigned _BitInt (256) x; + +void +foo (unsigned _BitInt (256) a, unsigned _BitInt (128) b) +{ + x = a / b; +} +#endif + +int +main () +{ +#if __BITINT_MAXWIDTH__ >= 256 + foo (0xfffffffffffffffffffffc0000000000000000000004uwb, 0x7ffffffffffffffffffffffffffuwb); + if (x != 0x1fffffffffffffffffuwb) + __builtin_abort (); +#endif + return 0; +} diff --git a/gcc/testsuite/gcc.dg/torture/bitint-55.c b/gcc/testsuite/gcc.dg/torture/bitint-55.c new file mode 100644 index 0000000..7d4bff3 --- /dev/null +++ b/gcc/testsuite/gcc.dg/torture/bitint-55.c @@ -0,0 +1,66 @@ +/* PR libgcc/113604 */ +/* { dg-do run { target bitint } } */ +/* { dg-options "-std=c23 -pedantic-errors" } */ +/* { dg-skip-if "" { ! run_expensive_tests } { "*" } { "-O0" "-O2" } } */ +/* { dg-skip-if "" { ! run_expensive_tests } { "-flto" } { "" } } */ + +#if __BITINT_MAXWIDTH__ >= 513 +signed _BitInt(513) +foo (signed _BitInt(513) x, signed _BitInt(513) y) +{ + return x % y; +} +#endif + +#if __BITINT_MAXWIDTH__ >= 512 +unsigned _BitInt(512) +bar (unsigned _BitInt(512) x, unsigned _BitInt(512) y) +{ + return x % y; +} +#endif + +#if __BITINT_MAXWIDTH__ >= 256 +unsigned _BitInt(256) +baz (unsigned _BitInt(256) x, unsigned _BitInt(256) y) +{ + return x % y; +} +#endif + +int +main () +{ +#if __BITINT_MAXWIDTH__ >= 513 + if (foo (11155754932722990178552651944728825929130437979239421228991532051555943675wb, + 32783817256434357484609367438786815wb) != 0wb) + __builtin_abort (); + if (foo (542904728531209767665756029992981529373473101602268731408384wb, + 235447394450476261134537147263765988105wb) + != 235447394450476261116090403190056436489wb) + __builtin_abort (); + if (foo (542904728531209767665690117878483036079552477922114364506112wb, + 235447394450476261134537147263765988105wb) + != 169535279951982967195466723035689534217wb) + __builtin_abort (); + if (foo (542904728531209767665690117878483036079534031178040654954496wb, + 235447394450476261134537147263765988105wb) + != 169535279951982967177019978961979982601wb) + __builtin_abort (); + if (foo (542904728531209767665454670484032559818581851459155356811264wb, + 235447394450476261134537147263765988105wb) + != 169535279951982967359377407340447827474wb) + __builtin_abort (); +#endif +#if __BITINT_MAXWIDTH__ >= 512 + if (bar (6703903964971298549787012499102923063739682910296196688861780721860882015036773488400937149083451713845015929093243025426876941405973284973216824503042048uwb, + 170141183460469231731687303715884105735uwb) != 19208uwb) + __builtin_abort (); +#endif +#if __BITINT_MAXWIDTH__ >= 256 + if (baz (115792089237316195423570985008687907853269984665640564039457584007913129639926uwb, + 68056473384187692692674921486353642292uwb) != 6uwb) + __builtin_abort (); +#endif + return 0; +} -- cgit v1.1 From e52d31804a910642c9817bdd400c290a593c98ef Mon Sep 17 00:00:00 2001 From: Ian Lance Taylor Date: Fri, 20 Oct 2023 10:11:48 -0700 Subject: compiler: export the type "any" as a builtin Otherwise we can't tell the difference between builtin type "any" and a locally defined type "any". This will require updates to the gccgo export data parsers in the main Go repo and the x/tools repo. These updates are https://go.dev/cl/537195 and https://go.dev/cl/537215. Reviewed-on: https://go-review.googlesource.com/c/gofrontend/+/536715 --- gcc/go/gofrontend/MERGE | 2 +- gcc/go/gofrontend/export.cc | 1 + gcc/go/gofrontend/export.h | 3 ++- gcc/go/gofrontend/import.cc | 1 + 4 files changed, 5 insertions(+), 2 deletions(-) (limited to 'gcc') diff --git a/gcc/go/gofrontend/MERGE b/gcc/go/gofrontend/MERGE index c2a6032..18281c6 100644 --- a/gcc/go/gofrontend/MERGE +++ b/gcc/go/gofrontend/MERGE @@ -1,4 +1,4 @@ -ddf3758e4a45ca2816fb68f3e4224501a3c4c438 +7ab229670f7dad1d79f33929f9a4f8e6e4a71526 The first line of this file holds the git revision number of the last merge done from the gofrontend repository. diff --git a/gcc/go/gofrontend/export.cc b/gcc/go/gofrontend/export.cc index 7373dee..40f6d5d 100644 --- a/gcc/go/gofrontend/export.cc +++ b/gcc/go/gofrontend/export.cc @@ -1661,6 +1661,7 @@ Export::register_builtin_types(Gogo* gogo) this->register_builtin_type(gogo, "error", BUILTIN_ERROR); this->register_builtin_type(gogo, "byte", BUILTIN_BYTE); this->register_builtin_type(gogo, "rune", BUILTIN_RUNE); + this->register_builtin_type(gogo, "any", BUILTIN_ANY); } // Register one builtin type in the export table. diff --git a/gcc/go/gofrontend/export.h b/gcc/go/gofrontend/export.h index 1f61343..be117ec 100644 --- a/gcc/go/gofrontend/export.h +++ b/gcc/go/gofrontend/export.h @@ -51,8 +51,9 @@ enum Builtin_code BUILTIN_ERROR = -19, BUILTIN_BYTE = -20, BUILTIN_RUNE = -21, + BUILTIN_ANY = -22, - SMALLEST_BUILTIN_CODE = -21 + SMALLEST_BUILTIN_CODE = -22 }; // Export data version number. New export data is written with the diff --git a/gcc/go/gofrontend/import.cc b/gcc/go/gofrontend/import.cc index 21691fa..3cc8a72 100644 --- a/gcc/go/gofrontend/import.cc +++ b/gcc/go/gofrontend/import.cc @@ -1408,6 +1408,7 @@ Import::register_builtin_types(Gogo* gogo) this->register_builtin_type(gogo, "error", BUILTIN_ERROR); this->register_builtin_type(gogo, "byte", BUILTIN_BYTE); this->register_builtin_type(gogo, "rune", BUILTIN_RUNE); + this->register_builtin_type(gogo, "any", BUILTIN_ANY); } // Register a single builtin type. -- cgit v1.1 From cfc6d9ae8143cf0e903384bc63e8d659ca1c9fe7 Mon Sep 17 00:00:00 2001 From: Ian Lance Taylor Date: Mon, 22 Jan 2024 17:26:23 -0800 Subject: libgo: better error messages for unknown GOARCH/GOOS PR go/113530 Reviewed-on: https://go-review.googlesource.com/c/gofrontend/+/557655 --- gcc/go/gofrontend/MERGE | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'gcc') diff --git a/gcc/go/gofrontend/MERGE b/gcc/go/gofrontend/MERGE index 18281c6..429904a 100644 --- a/gcc/go/gofrontend/MERGE +++ b/gcc/go/gofrontend/MERGE @@ -1,4 +1,4 @@ -7ab229670f7dad1d79f33929f9a4f8e6e4a71526 +8c056e335cecec67d1d223a329b7ba4dac778a65 The first line of this file holds the git revision number of the last merge done from the gofrontend repository. -- cgit v1.1 From 838e706fa55b1798fb5f0242dbd90cd4d9817bbe Mon Sep 17 00:00:00 2001 From: Iain Buclaw Date: Tue, 16 Jan 2024 19:57:40 +0100 Subject: d: Merge upstream dmd, druntime f1a045928e D front-end changes: - Import dmd v2.106.1-rc.1. - Unrecognized pragmas are no longer an error by default. D runtime changes: - Import druntime v2.106.1-rc.1. gcc/d/ChangeLog: * dmd/MERGE: Merge upstream dmd f1a045928e. * dmd/VERSION: Bump version to v2.106.1-rc.1. * gdc.texi (fignore-unknown-pragmas): Update documentation. * d-builtins.cc (covariant_with_builtin_type_p): Update for new front-end interface. * d-lang.cc (d_parse_file): Likewise. * typeinfo.cc (make_frontend_typeinfo): Likewise. libphobos/ChangeLog: * libdruntime/MERGE: Merge upstream druntime f1a045928e. * libdruntime/Makefile.am (DRUNTIME_DSOURCES): Add core/stdc/stdatomic.d. * libdruntime/Makefile.in: Regenerate. --- gcc/d/d-builtins.cc | 2 +- gcc/d/d-lang.cc | 3 +- gcc/d/dmd/MERGE | 2 +- gcc/d/dmd/VERSION | 2 +- gcc/d/dmd/aliasthis.d | 166 +--- gcc/d/dmd/astcodegen.d | 2 +- gcc/d/dmd/attrib.d | 103 --- gcc/d/dmd/attrib.h | 5 - gcc/d/dmd/cparse.d | 113 ++- gcc/d/dmd/ctfeexpr.d | 3 + gcc/d/dmd/dcast.d | 1 + gcc/d/dmd/dclass.d | 5 +- gcc/d/dmd/declaration.d | 287 ------- gcc/d/dmd/declaration.h | 1 - gcc/d/dmd/dimport.d | 42 -- gcc/d/dmd/dmodule.d | 118 ++- gcc/d/dmd/doc.d | 11 +- gcc/d/dmd/dscope.d | 37 +- gcc/d/dmd/dstruct.d | 2 +- gcc/d/dmd/dsymbol.d | 75 +- gcc/d/dmd/dsymbol.h | 35 +- gcc/d/dmd/dsymbolsem.d | 749 +++++++++++++++++- gcc/d/dmd/dtemplate.d | 11 +- gcc/d/dmd/dtoh.d | 2 +- gcc/d/dmd/errorsink.d | 14 + gcc/d/dmd/expression.d | 3 +- gcc/d/dmd/expressionsem.d | 32 +- gcc/d/dmd/func.d | 5 + gcc/d/dmd/globals.d | 2 +- gcc/d/dmd/import.h | 1 - gcc/d/dmd/init.d | 6 - gcc/d/dmd/initsem.d | 77 +- gcc/d/dmd/lambdacomp.d | 2 +- gcc/d/dmd/lexer.d | 35 +- gcc/d/dmd/module.h | 5 +- gcc/d/dmd/mtype.d | 834 +-------------------- gcc/d/dmd/mtype.h | 4 +- gcc/d/dmd/nspace.d | 16 - gcc/d/dmd/nspace.h | 1 - gcc/d/dmd/scope.h | 2 +- gcc/d/dmd/semantic3.d | 3 +- gcc/d/dmd/statement.d | 8 +- gcc/d/dmd/statement.h | 2 +- gcc/d/dmd/statementsem.d | 22 +- gcc/d/dmd/staticassert.d | 3 - gcc/d/dmd/template.h | 1 - gcc/d/dmd/traits.d | 6 +- gcc/d/dmd/typesem.d | 802 +++++++++++++++++++- gcc/d/gdc.texi | 6 +- gcc/d/typeinfo.cc | 3 +- .../gdc.test/compilable/imports/defines.c | 4 + gcc/testsuite/gdc.test/compilable/test9565.d | 86 --- gcc/testsuite/gdc.test/compilable/testdefines.d | 3 + .../gdc.test/fail_compilation/fail19890a.d | 2 +- .../gdc.test/fail_compilation/fail19890b.d | 2 +- gcc/testsuite/gdc.test/fail_compilation/fail4611.d | 2 +- gcc/testsuite/gdc.test/fail_compilation/pragmas.d | 3 +- 57 files changed, 1901 insertions(+), 1873 deletions(-) delete mode 100644 gcc/testsuite/gdc.test/compilable/test9565.d (limited to 'gcc') diff --git a/gcc/d/d-builtins.cc b/gcc/d/d-builtins.cc index 59a1b4c..9d60497 100644 --- a/gcc/d/d-builtins.cc +++ b/gcc/d/d-builtins.cc @@ -724,7 +724,7 @@ static bool covariant_with_builtin_type_p (Type *t1, Type *t2) { /* Check whether the declared function matches the built-in. */ - if (same_type_p (t1, t2) || t1->covariant (t2) == Covariant::yes) + if (same_type_p (t1, t2) || covariant (t1, t2) == Covariant::yes) return true; /* May not be covariant because of D attributes applied on t1. diff --git a/gcc/d/d-lang.cc b/gcc/d/d-lang.cc index 7840cf8..a25d031 100644 --- a/gcc/d/d-lang.cc +++ b/gcc/d/d-lang.cc @@ -23,6 +23,7 @@ along with GCC; see the file COPYING3. If not see #include "dmd/cond.h" #include "dmd/declaration.h" #include "dmd/doc.h" +#include "dmd/dsymbol.h" #include "dmd/errors.h" #include "dmd/expression.h" #include "dmd/hdrgen.h" @@ -1226,7 +1227,7 @@ d_parse_file (void) if (global.params.v.verbose) message ("importall %s", m->toChars ()); - m->importAll (NULL); + importAll (m, NULL); } if (global.errors) diff --git a/gcc/d/dmd/MERGE b/gcc/d/dmd/MERGE index 5edcee1..fa7004b 100644 --- a/gcc/d/dmd/MERGE +++ b/gcc/d/dmd/MERGE @@ -1,4 +1,4 @@ -2bbf64907cbbb483d003e0a8fcf8b502e4883799 +f1a045928e03239b9477f9497f43f2cf0e61e959 The first line of this file holds the git revision number of the last merge done from the dlang/dmd repository. diff --git a/gcc/d/dmd/VERSION b/gcc/d/dmd/VERSION index 8c95cd0..9d7be5b 100644 --- a/gcc/d/dmd/VERSION +++ b/gcc/d/dmd/VERSION @@ -1 +1 @@ -v2.106.0 +v2.106.1-rc.1 diff --git a/gcc/d/dmd/aliasthis.d b/gcc/d/dmd/aliasthis.d index a8933f6..0c15636 100644 --- a/gcc/d/dmd/aliasthis.d +++ b/gcc/d/dmd/aliasthis.d @@ -14,16 +14,10 @@ module dmd.aliasthis; import core.stdc.stdio; -import dmd.aggregate; -import dmd.dscope; + import dmd.dsymbol; -import dmd.expression; -import dmd.expressionsem; -import dmd.globals; import dmd.identifier; import dmd.location; -import dmd.mtype; -import dmd.tokens; import dmd.visitor; /*********************************************************** @@ -71,161 +65,3 @@ extern (C++) final class AliasThis : Dsymbol return this.isDeprecated_; } } - -/************************************* - * Find the `alias this` symbol of e's type. - * Params: - * sc = context - * e = expression forming the `this` - * gag = do not print errors, return `null` instead - * findOnly = don't do further processing like resolving properties, - * i.e. just return plain dotExp() result. - * Returns: - * Expression that is `e.aliasthis` - */ -Expression resolveAliasThis(Scope* sc, Expression e, bool gag = false, bool findOnly = false) -{ - import dmd.typesem : dotExp; - for (AggregateDeclaration ad = isAggregate(e.type); ad;) - { - if (ad.aliasthis) - { - Loc loc = e.loc; - Type tthis = (e.op == EXP.type ? e.type : null); - const flags = cast(DotExpFlag) (DotExpFlag.noAliasThis | (gag * DotExpFlag.gag)); - uint olderrors = gag ? global.startGagging() : 0; - e = dotExp(ad.type, sc, e, ad.aliasthis.ident, flags); - if (!e || findOnly) - return gag && global.endGagging(olderrors) ? null : e; - - if (tthis && ad.aliasthis.sym.needThis()) - { - if (auto ve = e.isVarExp()) - { - if (auto fd = ve.var.isFuncDeclaration()) - { - // https://issues.dlang.org/show_bug.cgi?id=13009 - // Support better match for the overloaded alias this. - bool hasOverloads; - if (auto f = fd.overloadModMatch(loc, tthis, hasOverloads)) - { - if (!hasOverloads) - fd = f; // use exact match - e = new VarExp(loc, fd, hasOverloads); - e.type = f.type; - e = new CallExp(loc, e); - goto L1; - } - } - } - /* non-@property function is not called inside typeof(), - * so resolve it ahead. - */ - { - int save = sc.intypeof; - sc.intypeof = 1; // bypass "need this" error check - e = resolveProperties(sc, e); - sc.intypeof = save; - } - L1: - e = new TypeExp(loc, new TypeTypeof(loc, e)); - e = e.expressionSemantic(sc); - } - e = resolveProperties(sc, e); - if (!gag) - ad.aliasthis.checkDeprecatedAliasThis(loc, sc); - else if (global.endGagging(olderrors)) - e = null; - } - - import dmd.dclass : ClassDeclaration; - auto cd = ad.isClassDeclaration(); - if ((!e || !ad.aliasthis) && cd && cd.baseClass && cd.baseClass != ClassDeclaration.object) - { - ad = cd.baseClass; - continue; - } - break; - } - return e; -} - -/** - * Check if an `alias this` is deprecated - * - * Usually one would use `expression.checkDeprecated(scope, aliasthis)` to - * check if `expression` uses a deprecated `aliasthis`, but this calls - * `toPrettyChars` which lead to the following message: - * "Deprecation: alias this `fullyqualified.aggregate.__anonymous` is deprecated" - * - * Params: - * at = The `AliasThis` object to check - * loc = `Loc` of the expression triggering the access to `at` - * sc = `Scope` of the expression - * (deprecations do not trigger in deprecated scopes) - * - * Returns: - * Whether the alias this was reported as deprecated. - */ -bool checkDeprecatedAliasThis(AliasThis at, const ref Loc loc, Scope* sc) -{ - import dmd.errors : deprecation, Classification; - import dmd.dsymbolsem : getMessage; - - if (global.params.useDeprecated != DiagnosticReporting.off - && at.isDeprecated() && !sc.isDeprecated()) - { - const(char)* message = null; - for (Dsymbol p = at; p; p = p.parent) - { - message = p.depdecl ? p.depdecl.getMessage() : null; - if (message) - break; - } - if (message) - deprecation(loc, "`alias %s this` is deprecated - %s", - at.sym.toChars(), message); - else - deprecation(loc, "`alias %s this` is deprecated", - at.sym.toChars()); - - if (auto ti = sc.parent ? sc.parent.isInstantiated() : null) - ti.printInstantiationTrace(Classification.deprecation); - - return true; - } - return false; -} - -/************************************** - * Check and set 'att' if 't' is a recursive 'alias this' type - * - * The goal is to prevent endless loops when there is a cycle in the alias this chain. - * Since there is no multiple `alias this`, the chain either ends in a leaf, - * or it loops back on itself as some point. - * - * Example: S0 -> (S1 -> S2 -> S3 -> S1) - * - * `S0` is not a recursive alias this, so this returns `false`, and a rewrite to `S1` can be tried. - * `S1` is a recursive alias this type, but since `att` is initialized to `null`, - * this still returns `false`, but `att1` is set to `S1`. - * A rewrite to `S2` and `S3` can be tried, but when we want to try a rewrite to `S1` again, - * we notice `att == t`, so we're back at the start of the loop, and this returns `true`. - * - * Params: - * att = type reference used to detect recursion. Should be initialized to `null`. - * t = type of 'alias this' rewrite to attempt - * - * Returns: - * `false` if the rewrite is safe, `true` if it would loop back around - */ -bool isRecursiveAliasThis(ref Type att, Type t) -{ - //printf("+isRecursiveAliasThis(att = %s, t = %s)\n", att ? att.toChars() : "null", t.toChars()); - auto tb = t.toBasetype(); - if (att && tb.equivalent(att)) - return true; - else if (!att && tb.checkAliasThisRec()) - att = tb; - return false; -} diff --git a/gcc/d/dmd/astcodegen.d b/gcc/d/dmd/astcodegen.d index d40f836..f179077 100644 --- a/gcc/d/dmd/astcodegen.d +++ b/gcc/d/dmd/astcodegen.d @@ -97,6 +97,6 @@ struct ASTCodegen alias isExpression = dmd.dtemplate.isExpression; alias isTuple = dmd.dtemplate.isTuple; - alias IgnoreErrors = dmd.dsymbol.IgnoreErrors; + alias SearchOpt = dmd.dsymbol.SearchOpt; alias PASS = dmd.dsymbol.PASS; } diff --git a/gcc/d/dmd/attrib.d b/gcc/d/dmd/attrib.d index faf0489..cc6ef9c 100644 --- a/gcc/d/dmd/attrib.d +++ b/gcc/d/dmd/attrib.d @@ -123,19 +123,6 @@ extern (C++) abstract class AttribDeclaration : Dsymbol return sc; } - override void importAll(Scope* sc) - { - Dsymbols* d = include(sc); - //printf("\tAttribDeclaration::importAll '%s', d = %p\n", toChars(), d); - if (d) - { - Scope* sc2 = newScope(sc); - d.foreachDsymbol( s => s.importAll(sc2) ); - if (sc2 != sc) - sc2.pop(); - } - } - override void addComment(const(char)* comment) { //printf("AttribDeclaration::addComment %s\n", comment); @@ -156,11 +143,6 @@ extern (C++) abstract class AttribDeclaration : Dsymbol return Dsymbol.oneMembers(d, ps, ident); } - override void setFieldOffset(AggregateDeclaration ad, ref FieldState fieldState, bool isunion) - { - include(null).foreachDsymbol( s => s.setFieldOffset(ad, fieldState, isunion) ); - } - override final bool hasPointers() { return include(null).foreachDsymbol( (s) { return s.hasPointers(); } ) != 0; @@ -675,81 +657,6 @@ extern (C++) final class AnonDeclaration : AttribDeclaration return new AnonDeclaration(loc, isunion, Dsymbol.arraySyntaxCopy(decl)); } - override void setFieldOffset(AggregateDeclaration ad, ref FieldState fieldState, bool isunion) - { - //printf("\tAnonDeclaration::setFieldOffset %s %p\n", isunion ? "union" : "struct", this); - if (decl) - { - /* This works by treating an AnonDeclaration as an aggregate 'member', - * so in order to place that member we need to compute the member's - * size and alignment. - */ - size_t fieldstart = ad.fields.length; - - /* Hackishly hijack ad's structsize and alignsize fields - * for use in our fake anon aggregate member. - */ - uint savestructsize = ad.structsize; - uint savealignsize = ad.alignsize; - ad.structsize = 0; - ad.alignsize = 0; - - FieldState fs; - decl.foreachDsymbol( (s) - { - s.setFieldOffset(ad, fs, this.isunion); - if (this.isunion) - fs.offset = 0; - }); - - /* https://issues.dlang.org/show_bug.cgi?id=13613 - * If the fields in this.members had been already - * added in ad.fields, just update *poffset for the subsequent - * field offset calculation. - */ - if (fieldstart == ad.fields.length) - { - ad.structsize = savestructsize; - ad.alignsize = savealignsize; - fieldState.offset = ad.structsize; - return; - } - - anonstructsize = ad.structsize; - anonalignsize = ad.alignsize; - ad.structsize = savestructsize; - ad.alignsize = savealignsize; - - // 0 sized structs are set to 1 byte - if (anonstructsize == 0) - { - anonstructsize = 1; - anonalignsize = 1; - } - - assert(_scope); - auto alignment = _scope.alignment(); - - /* Given the anon 'member's size and alignment, - * go ahead and place it. - */ - anonoffset = placeField( - fieldState.offset, - anonstructsize, anonalignsize, alignment, - ad.structsize, ad.alignsize, - isunion); - - // Add to the anon fields the base offset of this anonymous aggregate - //printf("anon fields, anonoffset = %d\n", anonoffset); - foreach (const i; fieldstart .. ad.fields.length) - { - VarDeclaration v = ad.fields[i]; - //printf("\t[%d] %s %d\n", i, v.toChars(), v.offset); - v.offset += anonoffset; - } - } - } - override const(char)* kind() const { return (isunion ? "anonymous union" : "anonymous struct"); @@ -943,11 +850,6 @@ extern (C++) final class StaticIfDeclaration : ConditionalDeclaration } } - override void importAll(Scope* sc) - { - // do not evaluate condition before semantic pass - } - override const(char)* kind() const { return "static if"; @@ -1057,11 +959,6 @@ extern (C++) final class StaticForeachDeclaration : AttribDeclaration // change this to give semantics to documentation comments on static foreach declarations } - override void importAll(Scope* sc) - { - // do not evaluate aggregate before semantic pass - } - override const(char)* kind() const { return "static foreach"; diff --git a/gcc/d/dmd/attrib.h b/gcc/d/dmd/attrib.h index 98c5e52..35628e2 100644 --- a/gcc/d/dmd/attrib.h +++ b/gcc/d/dmd/attrib.h @@ -26,11 +26,9 @@ public: virtual Dsymbols *include(Scope *sc); virtual Scope *newScope(Scope *sc); - void importAll(Scope *sc) override; void addComment(const utf8_t *comment) override; const char *kind() const override; bool oneMember(Dsymbol **ps, Identifier *ident) override; - void setFieldOffset(AggregateDeclaration *ad, FieldState& fieldState, bool isunion) override; bool hasPointers() override final; bool hasStaticCtorOrDtor() override final; void checkCtorConstInit() override final; @@ -132,7 +130,6 @@ public: unsigned anonalignsize; // size of anonymous struct for alignment purposes AnonDeclaration *syntaxCopy(Dsymbol *s) override; - void setFieldOffset(AggregateDeclaration *ad, FieldState& fieldState, bool isunion) override; const char *kind() const override; AnonDeclaration *isAnonDeclaration() override { return this; } void accept(Visitor *v) override { v->visit(this); } @@ -171,7 +168,6 @@ public: StaticIfDeclaration *syntaxCopy(Dsymbol *s) override; Dsymbols *include(Scope *sc) override; - void importAll(Scope *sc) override; StaticIfDeclaration *isStaticIfDeclaration() override { return this; } const char *kind() const override; void accept(Visitor *v) override { v->visit(this); } @@ -190,7 +186,6 @@ public: bool oneMember(Dsymbol **ps, Identifier *ident) override; Dsymbols *include(Scope *sc) override; void addComment(const utf8_t *comment) override; - void importAll(Scope *sc) override; const char *kind() const override; void accept(Visitor *v) override { v->visit(this); } }; diff --git a/gcc/d/dmd/cparse.d b/gcc/d/dmd/cparse.d index 89a5948..4c0b96a 100644 --- a/gcc/d/dmd/cparse.d +++ b/gcc/d/dmd/cparse.d @@ -247,6 +247,8 @@ final class CParser(AST) : Parser!AST break; case TOK.charLiteral: + case TOK.wcharLiteral: + case TOK.dcharLiteral: case TOK.int32Literal: case TOK.uns32Literal: case TOK.int64Literal: @@ -725,6 +727,12 @@ final class CParser(AST) : Parser!AST nextToken(); break; + case TOK.wcharLiteral: + e = new AST.IntegerExp(loc, token.intvalue, AST.Type.tuns16); + nextToken(); + break; + + case TOK.dcharLiteral: case TOK.uns32Literal: e = new AST.IntegerExp(loc, token.unsvalue, AST.Type.tuns32); nextToken(); @@ -1899,6 +1907,7 @@ final class CParser(AST) : Parser!AST } bool isalias = true; + Identifier idt; if (auto ts = dt.isTypeStruct()) { if (ts.sym.isAnonymous()) @@ -1908,6 +1917,7 @@ final class CParser(AST) : Parser!AST ts.sym.ident = id; isalias = false; } + idt = ts.sym.ident; } else if (auto te = dt.isTypeEnum()) { @@ -1917,6 +1927,7 @@ final class CParser(AST) : Parser!AST te.sym.ident = id; isalias = false; } + idt = te.sym.ident; } else if (auto tt = dt.isTypeTag()) { @@ -1930,11 +1941,13 @@ final class CParser(AST) : Parser!AST Specifier spec; declareTag(tt, spec); } + idt = tt.id; } if (isalias) { auto ad = new AST.AliasDeclaration(token.loc, id, dt); - ad.adFlags |= ad.hidden; // do not print when generating .di files + if (id == idt) + ad.adFlags |= ad.hidden; // do not print when generating .di files s = ad; } @@ -4272,6 +4285,7 @@ final class CParser(AST) : Parser!AST case TOK.rightParenthesis: case TOK.rightBracket: case TOK.endOfFile: + case TOK.endOfLine: if (!any) return false; break; @@ -4940,6 +4954,8 @@ final class CParser(AST) : Parser!AST { case TOK.identifier: case TOK.charLiteral: + case TOK.wcharLiteral: + case TOK.dcharLiteral: case TOK.int32Literal: case TOK.uns32Literal: case TOK.int64Literal: @@ -5794,6 +5810,9 @@ final class CParser(AST) : Parser!AST buf.writeByte(0); auto slice = buf.peekChars()[0 .. length]; resetDefineLines(slice); // reset lexer + auto save = eSink; + auto eLatch = new ErrorSinkLatch(); + eSink = eLatch; const(char)* endp = &slice[length - 7]; @@ -5801,40 +5820,40 @@ final class CParser(AST) : Parser!AST // indexed by Identifier, returns index into symbols[] // The memory for this is leaked - void addVar(AST.VarDeclaration v) + void addVar(AST.Dsymbol s) { - //printf("addVar() %s\n", v.toChars()); - v.isCmacro(true); // mark it as coming from a C #define + //printf("addVar() %s\n", s.toChars()); + if (auto v = s.isVarDeclaration()) + v.isCmacro(true); // mark it as coming from a C #define /* If it's already defined, replace the earlier * definition */ - if (size_t* pd = cast(void*)v.ident in defineTab) + if (size_t* pd = cast(void*)s.ident in defineTab) { //printf("replacing %s\n", v.toChars()); - (*symbols)[*pd] = v; + (*symbols)[*pd] = s; return; } - defineTab[cast(void*)v.ident] = symbols.length; - symbols.push(v); + defineTab[cast(void*)s.ident] = symbols.length; + symbols.push(s); } - Token n; - while (p < endp) { if (p[0 .. 7] == "#define") { p += 7; - scan(&n); - //printf("%s\n", n.toChars()); - if (n.value == TOK.identifier) + nextToken(); + //printf("define %s\n", token.toChars()); + if (token.value == TOK.identifier) { - auto id = n.ident; - scan(&n); + auto id = token.ident; + const params = *p == '('; + nextToken(); AST.Type t; - switch (n.value) + switch (token.value) { case TOK.endOfLine: // #define identifier nextDefineLine(); @@ -5842,14 +5861,16 @@ final class CParser(AST) : Parser!AST case TOK.int32Literal: case TOK.charLiteral: t = AST.Type.tint32; goto Linteger; + case TOK.wcharLiteral: t = AST.Type.tuns16; goto Linteger; + case TOK.dcharLiteral: case TOK.uns32Literal: t = AST.Type.tuns32; goto Linteger; case TOK.int64Literal: t = AST.Type.tint64; goto Linteger; case TOK.uns64Literal: t = AST.Type.tuns64; goto Linteger; Linteger: - const intvalue = n.intvalue; - scan(&n); - if (n.value == TOK.endOfLine) + const intvalue = token.intvalue; + nextToken(); + if (token.value == TOK.endOfLine) { /* Declare manifest constant: * enum id = intvalue; @@ -5870,9 +5891,9 @@ final class CParser(AST) : Parser!AST case TOK.imaginary80Literal: t = AST.Type.timaginary80; goto Lfloat; Lfloat: - const floatvalue = n.floatvalue; - scan(&n); - if (n.value == TOK.endOfLine) + const floatvalue = token.floatvalue; + nextToken(); + if (token.value == TOK.endOfLine) { /* Declare manifest constant: * enum id = floatvalue; @@ -5886,11 +5907,11 @@ final class CParser(AST) : Parser!AST break; case TOK.string_: - const str = n.ustring; - const len = n.len; - const postfix = n.postfix; - scan(&n); - if (n.value == TOK.endOfLine) + const str = token.ustring; + const len = token.len; + const postfix = token.postfix; + nextToken(); + if (token.value == TOK.endOfLine) { /* Declare manifest constant: * enum id = "string"; @@ -5903,6 +5924,39 @@ final class CParser(AST) : Parser!AST } break; + case TOK.leftParenthesis: + /* Look for: + * #define ID ( expression ) + * and rewrite it to a template function: + * auto ID()() { return expression; } + */ + if (params) + break; // no parameters + nextToken(); + eLatch.sawErrors = false; + auto exp = cparseExpression(); + if (eLatch.sawErrors) // parsing errors + break; // abandon this #define + if (token.value != TOK.rightParenthesis) + break; + nextToken(); + if (token.value != TOK.endOfLine) + break; + auto ret = new AST.ReturnStatement(exp.loc, exp); + auto parameterList = AST.ParameterList(new AST.Parameters(), VarArg.none, 0); + StorageClass stc = STC.auto_; + auto tf = new AST.TypeFunction(parameterList, null, LINK.d, stc); + auto fd = new AST.FuncDeclaration(exp.loc, exp.loc, id, stc, tf, 0); + fd.fbody = ret; + AST.Dsymbols* decldefs = new AST.Dsymbols(); + decldefs.push(fd); + AST.TemplateParameters* tpl = new AST.TemplateParameters(); + AST.Expression constraint = null; + auto tempdecl = new AST.TemplateDeclaration(exp.loc, id, tpl, constraint, decldefs, false); + addVar(tempdecl); + nextDefineLine(); + continue; + default: break; } @@ -5911,8 +5965,8 @@ final class CParser(AST) : Parser!AST } else { - scan(&n); - if (n.value != TOK.endOfLine) + scan(&token); + if (token.value != TOK.endOfLine) { skipToNextLine(); } @@ -5920,6 +5974,7 @@ final class CParser(AST) : Parser!AST nextDefineLine(); } + eSink = save; defines = buf; } diff --git a/gcc/d/dmd/ctfeexpr.d b/gcc/d/dmd/ctfeexpr.d index 43efc05..993bab0 100644 --- a/gcc/d/dmd/ctfeexpr.d +++ b/gcc/d/dmd/ctfeexpr.d @@ -636,8 +636,11 @@ bool isSafePointerCast(Type srcPointee, Type destPointee) // It's OK if function pointers differ only in safe/pure/nothrow if (srcPointee.ty == Tfunction && destPointee.ty == Tfunction) + { + import dmd.typesem : covariant; return srcPointee.covariant(destPointee) == Covariant.yes || destPointee.covariant(srcPointee) == Covariant.yes; + } // it's OK to cast to void* if (destPointee.ty == Tvoid) return true; diff --git a/gcc/d/dmd/dcast.d b/gcc/d/dmd/dcast.d index bb86b08..cfa374c 100644 --- a/gcc/d/dmd/dcast.d +++ b/gcc/d/dmd/dcast.d @@ -24,6 +24,7 @@ import dmd.dinterpret; import dmd.dscope; import dmd.dstruct; import dmd.dsymbol; +import dmd.dsymbolsem; import dmd.errors; import dmd.escape; import dmd.expression; diff --git a/gcc/d/dmd/dclass.d b/gcc/d/dmd/dclass.d index 72b85cf..e066d87 100644 --- a/gcc/d/dmd/dclass.d +++ b/gcc/d/dmd/dclass.d @@ -594,7 +594,7 @@ extern (C++) class ClassDeclaration : AggregateDeclaration fieldState.offset = structsize; foreach (s; *members) { - s.setFieldOffset(this, fieldState, false); + s.setFieldOffset(this, &fieldState, false); } sizeok = Sizeok.done; @@ -614,7 +614,7 @@ extern (C++) class ClassDeclaration : AggregateDeclaration final bool isFuncHidden(FuncDeclaration fd) { //printf("ClassDeclaration.isFuncHidden(class = %s, fd = %s)\n", toChars(), fd.toPrettyChars()); - Dsymbol s = this.search(Loc.initial, fd.ident, IgnoreAmbiguous | IgnoreErrors); + Dsymbol s = this.search(Loc.initial, fd.ident, SearchOpt.ignoreAmbiguous | SearchOpt.ignoreErrors); if (!s) { //printf("not found\n"); @@ -670,6 +670,7 @@ extern (C++) class ClassDeclaration : AggregateDeclaration void searchVtbl(ref Dsymbols vtbl) { + import dmd.typesem : covariant; bool seenInterfaceVirtual; foreach (s; vtbl) { diff --git a/gcc/d/dmd/declaration.d b/gcc/d/dmd/declaration.d index 0e125fd..bdc91f4 100644 --- a/gcc/d/dmd/declaration.d +++ b/gcc/d/dmd/declaration.d @@ -1214,88 +1214,6 @@ extern (C++) class VarDeclaration : Declaration return v; } - override void setFieldOffset(AggregateDeclaration ad, ref FieldState fieldState, bool isunion) - { - //printf("VarDeclaration::setFieldOffset(ad = %s) %s\n", ad.toChars(), toChars()); - - if (aliasTuple) - { - // If this variable was really a tuple, set the offsets for the tuple fields - aliasTuple.foreachVar((s) { s.setFieldOffset(ad, fieldState, isunion); }); - return; - } - - if (!isField()) - return; - assert(!(storage_class & (STC.static_ | STC.extern_ | STC.parameter))); - - //printf("+VarDeclaration::setFieldOffset(ad = %s) %s\n", ad.toChars(), toChars()); - - /* Fields that are tuples appear both as part of TupleDeclarations and - * as members. That means ignore them if they are already a field. - */ - if (offset) - { - // already a field - fieldState.offset = ad.structsize; // https://issues.dlang.org/show_bug.cgi?id=13613 - return; - } - for (size_t i = 0; i < ad.fields.length; i++) - { - if (ad.fields[i] == this) - { - // already a field - fieldState.offset = ad.structsize; // https://issues.dlang.org/show_bug.cgi?id=13613 - return; - } - } - - // Check for forward referenced types which will fail the size() call - Type t = type.toBasetype(); - if (storage_class & STC.ref_) - { - // References are the size of a pointer - t = Type.tvoidptr; - } - Type tv = t.baseElemOf(); - if (tv.ty == Tstruct) - { - auto ts = cast(TypeStruct)tv; - assert(ts.sym != ad); // already checked in ad.determineFields() - if (!ts.sym.determineSize(loc)) - { - type = Type.terror; - errors = true; - return; - } - } - - // List in ad.fields. Even if the type is error, it's necessary to avoid - // pointless error diagnostic "more initializers than fields" on struct literal. - ad.fields.push(this); - - if (t.ty == Terror) - return; - - /* If coming after a bit field in progress, - * advance past the field - */ - fieldState.inFlight = false; - - const sz = t.size(loc); - assert(sz != SIZE_INVALID && sz < uint.max); - uint memsize = cast(uint)sz; // size of member - uint memalignsize = target.fieldalign(t); // size of member for alignment purposes - offset = placeField( - fieldState.offset, - memsize, memalignsize, alignment, - ad.structsize, ad.alignsize, - isunion); - - //printf("\t%s: memalignsize = %d\n", toChars(), memalignsize); - //printf(" addField '%s' to '%s' at offset %d, size = %d\n", toChars(), ad.toChars(), offset, memsize); - } - override const(char)* kind() const { return "variable"; @@ -1803,211 +1721,6 @@ extern (C++) class BitFieldDeclaration : VarDeclaration : (1L << (width - 1)) - 1); return v; } - - override final void setFieldOffset(AggregateDeclaration ad, ref FieldState fieldState, bool isunion) - { - enum log = false; - static if (log) - { - printf("BitFieldDeclaration::setFieldOffset(ad: %s, field: %s)\n", ad.toChars(), toChars()); - void print(const ref FieldState fieldState) - { - fieldState.print(); - printf(" fieldWidth = %d bits\n", fieldWidth); - } - print(fieldState); - } - - Type t = type.toBasetype(); - const bool anon = isAnonymous(); - - // List in ad.fields. Even if the type is error, it's necessary to avoid - // pointless error diagnostic "more initializers than fields" on struct literal. - if (!anon) - ad.fields.push(this); - - if (t.ty == Terror) - return; - - const sz = t.size(loc); - assert(sz != SIZE_INVALID && sz < uint.max); - uint memsize = cast(uint)sz; // size of member - uint memalignsize = target.fieldalign(t); // size of member for alignment purposes - if (log) printf(" memsize: %u memalignsize: %u\n", memsize, memalignsize); - - if (fieldWidth == 0 && !anon) - error(loc, "named bit fields cannot have 0 width"); - if (fieldWidth > memsize * 8) - error(loc, "bit field width %d is larger than type", fieldWidth); - - const style = target.c.bitFieldStyle; - - void startNewField() - { - if (log) printf("startNewField()\n"); - uint alignsize; - if (style == TargetC.BitFieldStyle.Gcc_Clang) - { - if (fieldWidth > 32) - alignsize = memalignsize; - else if (fieldWidth > 16) - alignsize = 4; - else if (fieldWidth > 8) - alignsize = 2; - else - alignsize = 1; - } - else - alignsize = memsize; // not memalignsize - - uint dummy; - offset = placeField( - fieldState.offset, - memsize, alignsize, alignment, - ad.structsize, - (anon && style == TargetC.BitFieldStyle.Gcc_Clang) ? dummy : ad.alignsize, - isunion); - - fieldState.inFlight = true; - fieldState.fieldOffset = offset; - fieldState.bitOffset = 0; - fieldState.fieldSize = memsize; - } - - if (style == TargetC.BitFieldStyle.Gcc_Clang) - { - if (fieldWidth == 0) - { - if (!isunion) - { - // Use type of zero width field to align to next field - fieldState.offset = (fieldState.offset + memalignsize - 1) & ~(memalignsize - 1); - ad.structsize = fieldState.offset; - } - - fieldState.inFlight = false; - return; - } - - if (ad.alignsize == 0) - ad.alignsize = 1; - if (!anon && - ad.alignsize < memalignsize) - ad.alignsize = memalignsize; - } - else if (style == TargetC.BitFieldStyle.MS) - { - if (ad.alignsize == 0) - ad.alignsize = 1; - if (fieldWidth == 0) - { - if (fieldState.inFlight && !isunion) - { - // documentation says align to next int - //const alsz = cast(uint)Type.tint32.size(); - const alsz = memsize; // but it really does this - fieldState.offset = (fieldState.offset + alsz - 1) & ~(alsz - 1); - ad.structsize = fieldState.offset; - } - - fieldState.inFlight = false; - return; - } - } - else if (style == TargetC.BitFieldStyle.DM) - { - if (anon && fieldWidth && (!fieldState.inFlight || fieldState.bitOffset == 0)) - return; // this probably should be a bug in DMC - if (ad.alignsize == 0) - ad.alignsize = 1; - if (fieldWidth == 0) - { - if (fieldState.inFlight && !isunion) - { - const alsz = memsize; - fieldState.offset = (fieldState.offset + alsz - 1) & ~(alsz - 1); - ad.structsize = fieldState.offset; - } - - fieldState.inFlight = false; - return; - } - } - - if (!fieldState.inFlight) - { - //printf("not in flight\n"); - startNewField(); - } - else if (style == TargetC.BitFieldStyle.Gcc_Clang) - { - // If the bit-field spans more units of alignment than its type, - // start a new field at the next alignment boundary. - if (fieldState.bitOffset == fieldState.fieldSize * 8 && - fieldState.bitOffset + fieldWidth > memalignsize * 8) - { - if (log) printf("more units of alignment than its type\n"); - startNewField(); // the bit field is full - } - else - { - // if alignment boundary is crossed - uint start = fieldState.fieldOffset * 8 + fieldState.bitOffset; - uint end = start + fieldWidth; - //printf("%s start: %d end: %d memalignsize: %d\n", ad.toChars(), start, end, memalignsize); - if (start / (memalignsize * 8) != (end - 1) / (memalignsize * 8)) - { - if (log) printf("alignment is crossed\n"); - startNewField(); - } - } - } - else if (style == TargetC.BitFieldStyle.DM || - style == TargetC.BitFieldStyle.MS) - { - if (memsize != fieldState.fieldSize || - fieldState.bitOffset + fieldWidth > fieldState.fieldSize * 8) - { - //printf("new field\n"); - startNewField(); - } - } - else - assert(0); - - offset = fieldState.fieldOffset; - bitOffset = fieldState.bitOffset; - - const pastField = bitOffset + fieldWidth; - if (style == TargetC.BitFieldStyle.Gcc_Clang) - { - auto size = (pastField + 7) / 8; - fieldState.fieldSize = size; - //printf(" offset: %d, size: %d\n", offset, size); - if (isunion) - { - const newstructsize = offset + size; - if (newstructsize > ad.structsize) - ad.structsize = newstructsize; - } - else - ad.structsize = offset + size; - } - else - fieldState.fieldSize = memsize; - //printf("at end: ad.structsize = %d\n", cast(int)ad.structsize); - //print(fieldState); - - if (!isunion) - { - fieldState.offset = offset + fieldState.fieldSize; - fieldState.bitOffset = pastField; - } - - //printf("\t%s: offset = %d bitOffset = %d fieldWidth = %d memsize = %d\n", toChars(), offset, bitOffset, fieldWidth, memsize); - //printf("\t%s: memalignsize = %d\n", toChars(), memalignsize); - //printf(" addField '%s' to '%s' at offset %d, size = %d\n", toChars(), ad.toChars(), offset, memsize); - } } /*********************************************************** diff --git a/gcc/d/dmd/declaration.h b/gcc/d/dmd/declaration.h index a65fb44..adbc26b 100644 --- a/gcc/d/dmd/declaration.h +++ b/gcc/d/dmd/declaration.h @@ -281,7 +281,6 @@ public: bool systemInferred(bool v); static VarDeclaration *create(const Loc &loc, Type *t, Identifier *id, Initializer *init, StorageClass storage_class = STCundefined); VarDeclaration *syntaxCopy(Dsymbol *) override; - void setFieldOffset(AggregateDeclaration *ad, FieldState& fieldState, bool isunion) override final; const char *kind() const override; AggregateDeclaration *isThis() override final; bool needThis() override final; diff --git a/gcc/d/dmd/dimport.d b/gcc/d/dmd/dimport.d index 5c01a9f..51b9220 100644 --- a/gcc/d/dmd/dimport.d +++ b/gcc/d/dmd/dimport.d @@ -222,48 +222,6 @@ extern (C++) final class Import : Dsymbol return global.errors != errors; } - override void importAll(Scope* sc) - { - if (mod) return; // Already done - - /* - * https://issues.dlang.org/show_bug.cgi?id=15525 - * - * Loading the import has failed, - * most likely because of parsing errors. - * Therefore we cannot trust the resulting AST. - */ - if (load(sc)) - { - // https://issues.dlang.org/show_bug.cgi?id=23873 - // For imports that are not at module or function level, - // e.g. aggregate level, the import symbol is added to the - // symbol table and later semantic is performed on it. - // This leads to semantic analysis on an malformed AST - // which causes all kinds of segfaults. - // The fix is to note that the module has errors and avoid - // semantic analysis on it. - if(mod) - mod.errors = true; - return; - } - - if (!mod) return; // Failed - - if (sc.stc & STC.static_) - isstatic = true; - mod.importAll(null); - mod.checkImportDeprecation(loc, sc); - if (sc.explicitVisibility) - visibility = sc.visibility; - if (!isstatic && !aliasId && !names.length) - sc.scopesym.importScope(mod, visibility); - // Enable access to pkgs/mod as soon as posible, because compiler - // can traverse them before the import gets semantic (Issue: 21501) - if (!aliasId && !names.length) - addPackageAccess(sc.scopesym); - } - /******************************* * Mark the imported packages as accessible from the current * scope. This access check is necessary when using FQN b/c diff --git a/gcc/d/dmd/dmodule.d b/gcc/d/dmd/dmodule.d index d096e43..6c9e90a 100644 --- a/gcc/d/dmd/dmodule.d +++ b/gcc/d/dmd/dmodule.d @@ -401,7 +401,7 @@ extern (C++) final class Module : Package Identifier searchCacheIdent; Dsymbol searchCacheSymbol; // cached value of search - int searchCacheFlags; // cached flags + SearchOptFlags searchCacheFlags; // cached flags bool insearch; /** @@ -921,70 +921,6 @@ extern (C++) final class Module : Package return this; } - override void importAll(Scope* prevsc) - { - //printf("+Module::importAll(this = %p, '%s'): parent = %p\n", this, toChars(), parent); - if (_scope) - return; // already done - if (filetype == FileType.ddoc) - { - error(loc, "%s `%s` is a Ddoc file, cannot import it", kind, toPrettyChars); - return; - } - - /* Note that modules get their own scope, from scratch. - * This is so regardless of where in the syntax a module - * gets imported, it is unaffected by context. - * Ignore prevsc. - */ - Scope* sc = Scope.createGlobal(this, global.errorSink); // create root scope - - if (md && md.msg) - md.msg = semanticString(sc, md.msg, "deprecation message"); - - // Add import of "object", even for the "object" module. - // If it isn't there, some compiler rewrites, like - // classinst == classinst -> .object.opEquals(classinst, classinst) - // would fail inside object.d. - if (filetype != FileType.c && - (members.length == 0 || - (*members)[0].ident != Id.object || - (*members)[0].isImport() is null)) - { - auto im = new Import(Loc.initial, null, Id.object, null, 0); - members.shift(im); - } - if (!symtab) - { - // Add all symbols into module's symbol table - symtab = new DsymbolTable(); - for (size_t i = 0; i < members.length; i++) - { - Dsymbol s = (*members)[i]; - s.addMember(sc, sc.scopesym); - } - } - // anything else should be run after addMember, so version/debug symbols are defined - /* Set scope for the symbols so that if we forward reference - * a symbol, it can possibly be resolved on the spot. - * If this works out well, it can be extended to all modules - * before any semantic() on any of them. - */ - this.setScope(sc); // remember module scope for semantic - for (size_t i = 0; i < members.length; i++) - { - Dsymbol s = (*members)[i]; - s.setScope(sc); - } - for (size_t i = 0; i < members.length; i++) - { - Dsymbol s = (*members)[i]; - s.importAll(sc); - } - sc = sc.pop(); - sc.pop(); // 2 pops because Scope.createGlobal() created 2 - } - /********************************** * Determine if we need to generate an instance of ModuleInfo * for this Module. @@ -1021,14 +957,14 @@ extern (C++) final class Module : Package } } - override bool isPackageAccessible(Package p, Visibility visibility, int flags = 0) + override bool isPackageAccessible(Package p, Visibility visibility, SearchOptFlags flags = SearchOpt.all) { if (insearch) // don't follow import cycles return false; insearch = true; scope (exit) insearch = false; - if (flags & IgnorePrivateImports) + if (flags & SearchOpt.ignorePrivateImports) visibility = Visibility(Visibility.Kind.public_); // only consider public imports return super.isPackageAccessible(p, visibility); } @@ -1384,7 +1320,53 @@ extern (C++) void getLocalClasses(Module mod, ref ClassDeclarations aclasses) return 0; } - ScopeDsymbol._foreach(null, mod.members, &pushAddClassDg); + _foreach(null, mod.members, &pushAddClassDg); +} + + +alias ForeachDg = int delegate(size_t idx, Dsymbol s); + +/*************************************** + * Expands attribute declarations in members in depth first + * order. Calls dg(size_t symidx, Dsymbol *sym) for each + * member. + * If dg returns !=0, stops and returns that value else returns 0. + * Use this function to avoid the O(N + N^2/2) complexity of + * calculating dim and calling N times getNth. + * Returns: + * last value returned by dg() + */ +int _foreach(Scope* sc, Dsymbols* members, scope ForeachDg dg, size_t* pn = null) +{ + assert(dg); + if (!members) + return 0; + size_t n = pn ? *pn : 0; // take over index + int result = 0; + foreach (size_t i; 0 .. members.length) + { + import dmd.attrib : AttribDeclaration; + import dmd.dtemplate : TemplateMixin; + + Dsymbol s = (*members)[i]; + if (AttribDeclaration a = s.isAttribDeclaration()) + result = _foreach(sc, a.include(sc), dg, &n); + else if (TemplateMixin tm = s.isTemplateMixin()) + result = _foreach(sc, tm.members, dg, &n); + else if (s.isTemplateInstance()) + { + } + else if (s.isUnitTestDeclaration()) + { + } + else + result = dg(n++, s); + if (result) + break; + } + if (pn) + *pn = n; // update index + return result; } /** diff --git a/gcc/d/dmd/doc.d b/gcc/d/dmd/doc.d index 5488d5a..03848c0 100644 --- a/gcc/d/dmd/doc.d +++ b/gcc/d/dmd/doc.d @@ -748,7 +748,8 @@ void emitAnchor(ref OutBuffer buf, Dsymbol s, Scope* sc, bool forHeader = false) auto a = imp.aliases[i]; auto id = a ? a : imp.names[i]; auto loc = Loc.init; - if (auto symFromId = sc.search(loc, id, null)) + Dsymbol pscopesym; + if (auto symFromId = sc.search(loc, id, pscopesym)) { emitAnchor(buf, symFromId, sc, forHeader); } @@ -3636,11 +3637,12 @@ struct MarkdownLinkReferences if (id) { auto loc = Loc(); - auto symbol = _scope.search(loc, id, null, IgnoreErrors); + Dsymbol pscopesym; + auto symbol = _scope.search(loc, id, pscopesym, SearchOpt.ignoreErrors); for (size_t i = 1; symbol && i < ids.length; ++i) { id = Identifier.lookup(ids[i].ptr, ids[i].length); - symbol = id !is null ? symbol.search(loc, id, IgnoreErrors) : null; + symbol = id !is null ? symbol.search(loc, id, SearchOpt.ignoreErrors) : null; } if (symbol) link = MarkdownLink(createHref(symbol), null, name, symbol); @@ -4997,7 +4999,8 @@ void highlightCode(Scope* sc, Dsymbol s, ref OutBuffer buf, size_t offset) auto a = imp.aliases[i]; auto id = a ? a : imp.names[i]; auto loc = Loc.init; - if (auto symFromId = sc.search(loc, id, null)) + Dsymbol pscopesym; + if (auto symFromId = sc.search(loc, id, pscopesym)) { highlightCode(sc, symFromId, buf, offset); } diff --git a/gcc/d/dmd/dscope.d b/gcc/d/dmd/dscope.d index d68bcda..cd177a6 100644 --- a/gcc/d/dmd/dscope.d +++ b/gcc/d/dmd/dscope.d @@ -344,13 +344,13 @@ extern (C++) struct Scope * Params: * loc = location to use for error messages * ident = name to look up - * pscopesym = if supplied and name is found, set to scope that ident was found in + * pscopesym = if supplied and name is found, set to scope that ident was found in, otherwise set to null * flags = modify search based on flags * * Returns: * symbol if found, null if not */ - extern (C++) Dsymbol search(const ref Loc loc, Identifier ident, Dsymbol* pscopesym, int flags = IgnoreNone) + extern (C++) Dsymbol search(const ref Loc loc, Identifier ident, out Dsymbol pscopesym, SearchOptFlags flags = SearchOpt.all) { version (LOGSEARCH) { @@ -371,7 +371,7 @@ extern (C++) struct Scope } // This function is called only for unqualified lookup - assert(!(flags & (SearchLocalsOnly | SearchImportsOnly))); + assert(!(flags & (SearchOpt.localsOnly | SearchOpt.importsOnly))); /* If ident is "start at module scope", only look at module scope */ @@ -386,15 +386,14 @@ extern (C++) struct Scope if (Dsymbol s = sc.scopesym.isModule()) { //printMsg("\tfound", s); - if (pscopesym) - *pscopesym = sc.scopesym; + pscopesym = sc.scopesym; return s; } } return null; } - Dsymbol checkAliasThis(AggregateDeclaration ad, Identifier ident, int flags, Expression* exp) + Dsymbol checkAliasThis(AggregateDeclaration ad, Identifier ident, SearchOptFlags flags, Expression* exp) { import dmd.mtype; if (!ad || !ad.aliasthis) @@ -458,7 +457,7 @@ extern (C++) struct Scope return s; } - Dsymbol searchScopes(int flags) + Dsymbol searchScopes(SearchOptFlags flags) { for (Scope* sc = &this; sc; sc = sc.enclosing) { @@ -468,13 +467,13 @@ extern (C++) struct Scope //printf("\tlooking in scopesym '%s', kind = '%s', flags = x%x\n", sc.scopesym.toChars(), sc.scopesym.kind(), flags); if (sc.scopesym.isModule()) - flags |= SearchUnqualifiedModule; // tell Module.search() that SearchLocalsOnly is to be obeyed + flags |= SearchOpt.unqualifiedModule; // tell Module.search() that SearchOpt.localsOnly is to be obeyed else if (sc.flags & SCOPE.Cfile && sc.scopesym.isStructDeclaration()) continue; // C doesn't have struct scope if (Dsymbol s = sc.scopesym.search(loc, ident, flags)) { - if (flags & TagNameSpace) + if (flags & SearchOpt.tagNameSpace) { // ImportC: if symbol is not a tag, look for it in tag table if (!s.isScopeDsymbol()) @@ -486,8 +485,7 @@ extern (C++) struct Scope } } //printMsg("\tfound local", s); - if (pscopesym) - *pscopesym = sc.scopesym; + pscopesym = sc.scopesym; return s; } @@ -499,8 +497,7 @@ extern (C++) struct Scope if (aliasSym) { //printf("found aliassym: %s\n", aliasSym.toChars()); - if (pscopesym) - *pscopesym = new ExpressionDsymbol(exp); + pscopesym = new ExpressionDsymbol(exp); return aliasSym; } } @@ -513,15 +510,15 @@ extern (C++) struct Scope } if (this.flags & SCOPE.ignoresymbolvisibility) - flags |= IgnoreSymbolVisibility; + flags |= SearchOpt.ignoreVisibility; // First look in local scopes - Dsymbol s = searchScopes(flags | SearchLocalsOnly); + Dsymbol s = searchScopes(flags | SearchOpt.localsOnly); version (LOGSEARCH) if (s) printMsg("-Scope.search() found local", s); if (!s) { // Second look in imported modules - s = searchScopes(flags | SearchImportsOnly); + s = searchScopes(flags | SearchOpt.importsOnly); version (LOGSEARCH) if (s) printMsg("-Scope.search() found import", s); } return s; @@ -554,8 +551,8 @@ extern (C++) struct Scope return null; Scope* sc = &this; Module.clearCache(); - Dsymbol scopesym = null; - Dsymbol s = sc.search(Loc.initial, id, &scopesym, IgnoreErrors); + Dsymbol scopesym; + Dsymbol s = sc.search(Loc.initial, id, scopesym, SearchOpt.ignoreErrors); if (!s) return null; @@ -579,9 +576,9 @@ extern (C++) struct Scope return s; } - Dsymbol scopesym = null; + Dsymbol scopesym; // search for exact name first - if (auto s = search(Loc.initial, ident, &scopesym, IgnoreErrors)) + if (auto s = search(Loc.initial, ident, scopesym, SearchOpt.ignoreErrors)) return s; return speller!scope_search_fp(ident.toString()); } diff --git a/gcc/d/dmd/dstruct.d b/gcc/d/dmd/dstruct.d index 36e847c..0e0a1f5 100644 --- a/gcc/d/dmd/dstruct.d +++ b/gcc/d/dmd/dstruct.d @@ -289,7 +289,7 @@ extern (C++) class StructDeclaration : AggregateDeclaration for (size_t i = 0; i < members.length; i++) { Dsymbol s = (*members)[i]; - s.setFieldOffset(this, fieldState, isunion); + s.setFieldOffset(this, &fieldState, isunion); } if (type.ty == Terror) { diff --git a/gcc/d/dmd/dsymbol.d b/gcc/d/dmd/dsymbol.d index 8f5a292..6613c2b 100644 --- a/gcc/d/dmd/dsymbol.d +++ b/gcc/d/dmd/dsymbol.d @@ -203,20 +203,21 @@ enum PASS : ubyte } // Search options -enum : int +alias SearchOptFlags = uint; +enum SearchOpt : SearchOptFlags { - IgnoreNone = 0x00, // default - IgnorePrivateImports = 0x01, // don't search private imports - IgnoreErrors = 0x02, // don't give error messages - IgnoreAmbiguous = 0x04, // return NULL if ambiguous - SearchLocalsOnly = 0x08, // only look at locals (don't search imports) - SearchImportsOnly = 0x10, // only look in imports - SearchUnqualifiedModule = 0x20, // the module scope search is unqualified, + all = 0x00, // search for all symbols + ignorePrivateImports = 0x01, // don't search private imports + ignoreErrors = 0x02, // don't give error messages + ignoreAmbiguous = 0x04, // return NULL if ambiguous + localsOnly = 0x08, // only look at locals (don't search imports) + importsOnly = 0x10, // only look in imports + unqualifiedModule = 0x20, // the module scope search is unqualified, // meaning don't search imports in that scope, // because qualified module searches search // their imports - IgnoreSymbolVisibility = 0x80, // also find private and package protected symbols - TagNameSpace = 0x100, // search ImportC tag symbol table + tagNameSpace = 0x40, // search ImportC tag symbol table + ignoreVisibility = 0x80, // also find private and package protected symbols } /*********************************************************** @@ -712,10 +713,6 @@ extern (C++) class Dsymbol : ASTNode return toAlias(); } - void importAll(Scope* sc) - { - } - bool overloadInsert(Dsymbol s) { //printf("Dsymbol::overloadInsert('%s')\n", s.toChars()); @@ -922,10 +919,6 @@ extern (C++) class Dsymbol : ASTNode return true; } - void setFieldOffset(AggregateDeclaration ad, ref FieldState fieldState, bool isunion) - { - } - /***************************************** * Is Dsymbol a variable that contains pointers? */ @@ -1263,7 +1256,7 @@ public: (*pary)[p.tag] = true; } - bool isPackageAccessible(Package p, Visibility visibility, int flags = 0) nothrow + bool isPackageAccessible(Package p, Visibility visibility, SearchOptFlags flags = SearchOpt.all) nothrow { if (p.tag < accessiblePackages.length && accessiblePackages[p.tag] || visibility.kind == Visibility.Kind.private_ && p.tag < privateAccessiblePackages.length && privateAccessiblePackages[p.tag]) @@ -1272,7 +1265,7 @@ public: { // only search visible scopes && imported modules should ignore private imports if (visibility.kind <= visibilities[i] && - ss.isScopeDsymbol.isPackageAccessible(p, visibility, IgnorePrivateImports)) + ss.isScopeDsymbol.isPackageAccessible(p, visibility, SearchOpt.ignorePrivateImports)) return true; } return false; @@ -1371,48 +1364,6 @@ public: return false; } - extern (D) alias ForeachDg = int delegate(size_t idx, Dsymbol s); - - /*************************************** - * Expands attribute declarations in members in depth first - * order. Calls dg(size_t symidx, Dsymbol *sym) for each - * member. - * If dg returns !=0, stops and returns that value else returns 0. - * Use this function to avoid the O(N + N^2/2) complexity of - * calculating dim and calling N times getNth. - * Returns: - * last value returned by dg() - */ - extern (D) static int _foreach(Scope* sc, Dsymbols* members, scope ForeachDg dg, size_t* pn = null) - { - assert(dg); - if (!members) - return 0; - size_t n = pn ? *pn : 0; // take over index - int result = 0; - foreach (size_t i; 0 .. members.length) - { - Dsymbol s = (*members)[i]; - if (AttribDeclaration a = s.isAttribDeclaration()) - result = _foreach(sc, a.include(sc), dg, &n); - else if (TemplateMixin tm = s.isTemplateMixin()) - result = _foreach(sc, tm.members, dg, &n); - else if (s.isTemplateInstance()) - { - } - else if (s.isUnitTestDeclaration()) - { - } - else - result = dg(n++, s); - if (result) - break; - } - if (pn) - *pn = n; // update index - return result; - } - override final inout(ScopeDsymbol) isScopeDsymbol() inout { return this; diff --git a/gcc/d/dmd/dsymbol.h b/gcc/d/dmd/dsymbol.h index 15c9970..d029c00 100644 --- a/gcc/d/dmd/dsymbol.h +++ b/gcc/d/dmd/dsymbol.h @@ -147,20 +147,21 @@ enum /* Flags for symbol search */ -enum +typedef uint SearchOptFlags; +enum class SearchOpt : SearchOptFlags { - IgnoreNone = 0x00, // default - IgnorePrivateImports = 0x01, // don't search private imports - IgnoreErrors = 0x02, // don't give error messages - IgnoreAmbiguous = 0x04, // return NULL if ambiguous - SearchLocalsOnly = 0x08, // only look at locals (don't search imports) - SearchImportsOnly = 0x10, // only look in imports - SearchUnqualifiedModule = 0x20, // the module scope search is unqualified, - // meaning don't search imports in that scope, - // because qualified module searches search - // their imports - IgnoreSymbolVisibility = 0x80, // also find private and package protected symbols - TagNameSpace = 0x100, // search ImportC tag symbol table + all = 0x00, // default + ignorePrivateImports = 0x01, // don't search private imports + ignoreErrors = 0x02, // don't give error messages + ignoreAmbiguous = 0x04, // return NULL if ambiguous + localsOnly = 0x08, // only look at locals (don't search imports) + importsOnly = 0x10, // only look in imports + unqualifiedModule = 0x20, // the module scope search is unqualified, + // meaning don't search imports in that scope, + // because qualified module searches search + // their imports + tagNameSpace = 0x40, // search ImportC tag symbol table + ignoreVisibility = 0x80, // also find private and package protected symbols }; struct FieldState @@ -227,7 +228,6 @@ public: virtual const char *kind() const; virtual Dsymbol *toAlias(); // resolve real symbol virtual Dsymbol *toAlias2(); - virtual void importAll(Scope *sc); virtual bool overloadInsert(Dsymbol *s); virtual uinteger_t size(const Loc &loc); virtual bool isforwardRef(); @@ -247,7 +247,6 @@ public: virtual Visibility visible(); virtual Dsymbol *syntaxCopy(Dsymbol *s); // copy only syntax trees virtual bool oneMember(Dsymbol **ps, Identifier *ident); - virtual void setFieldOffset(AggregateDeclaration *ad, FieldState& fieldState, bool isunion); virtual bool hasPointers(); virtual bool hasStaticCtorOrDtor(); virtual void addObjcSymbols(ClassDeclarations *, ClassDeclarations *) { } @@ -336,7 +335,7 @@ private: public: ScopeDsymbol *syntaxCopy(Dsymbol *s) override; virtual void importScope(Dsymbol *s, Visibility visibility); - virtual bool isPackageAccessible(Package *p, Visibility visibility, int flags = 0); + virtual bool isPackageAccessible(Package *p, Visibility visibility, SearchOptFlags flags = (SearchOptFlags)SearchOpt::all); bool isforwardRef() override final; static void multiplyDefined(const Loc &loc, Dsymbol *s1, Dsymbol *s2); const char *kind() const override; @@ -427,6 +426,8 @@ public: }; void addMember(Dsymbol *dsym, Scope *sc, ScopeDsymbol *sds); -Dsymbol *search(Dsymbol *d, const Loc &loc, Identifier *ident, int flags = SearchLocalsOnly); +Dsymbol *search(Dsymbol *d, const Loc &loc, Identifier *ident, SearchOptFlags flags = (SearchOptFlags)SearchOpt::localsOnly); bool checkDeprecated(Dsymbol *d, const Loc &loc, Scope *sc); void setScope(Dsymbol *d, Scope *sc); +void importAll(Dsymbol *d, Scope *sc); +void setFieldOffset(Dsymbol *d, AggregateDeclaration *ad, FieldState& fieldState, bool isunion); diff --git a/gcc/d/dmd/dsymbolsem.d b/gcc/d/dmd/dsymbolsem.d index 060abfe..df0a9a5 100644 --- a/gcc/d/dmd/dsymbolsem.d +++ b/gcc/d/dmd/dsymbolsem.d @@ -246,6 +246,20 @@ bool checkDeprecated(Dsymbol d, const ref Loc loc, Scope* sc) return true; } +/********************************* + * Check type to see if it is based on a deprecated symbol. + */ +private void checkDeprecated(Type type, const ref Loc loc, Scope* sc) +{ + if (Dsymbol s = type.toDsymbol(sc)) + { + s.checkDeprecated(loc, sc); + } + + if (auto tn = type.nextOf()) + tn.checkDeprecated(loc, sc); +} + // Returns true if a contract can appear without a function body. package bool allowsContractWithoutBody(FuncDeclaration funcdecl) { @@ -304,6 +318,128 @@ bool checkHasBothRvalueAndCpCtor(StructDeclaration sd, CtorDeclaration ctor, Tem return false; } +/************************************* + * Find the `alias this` symbol of e's type. + * Params: + * sc = context + * e = expression forming the `this` + * gag = do not print errors, return `null` instead + * findOnly = don't do further processing like resolving properties, + * i.e. just return plain dotExp() result. + * Returns: + * Expression that is `e.aliasthis` + */ +Expression resolveAliasThis(Scope* sc, Expression e, bool gag = false, bool findOnly = false) +{ + import dmd.typesem : dotExp; + for (AggregateDeclaration ad = isAggregate(e.type); ad;) + { + if (ad.aliasthis) + { + Loc loc = e.loc; + Type tthis = (e.op == EXP.type ? e.type : null); + const flags = cast(DotExpFlag) (DotExpFlag.noAliasThis | (gag * DotExpFlag.gag)); + uint olderrors = gag ? global.startGagging() : 0; + e = dotExp(ad.type, sc, e, ad.aliasthis.ident, flags); + if (!e || findOnly) + return gag && global.endGagging(olderrors) ? null : e; + + if (tthis && ad.aliasthis.sym.needThis()) + { + if (auto ve = e.isVarExp()) + { + if (auto fd = ve.var.isFuncDeclaration()) + { + // https://issues.dlang.org/show_bug.cgi?id=13009 + // Support better match for the overloaded alias this. + bool hasOverloads; + if (auto f = fd.overloadModMatch(loc, tthis, hasOverloads)) + { + if (!hasOverloads) + fd = f; // use exact match + e = new VarExp(loc, fd, hasOverloads); + e.type = f.type; + e = new CallExp(loc, e); + goto L1; + } + } + } + /* non-@property function is not called inside typeof(), + * so resolve it ahead. + */ + { + int save = sc.intypeof; + sc.intypeof = 1; // bypass "need this" error check + e = resolveProperties(sc, e); + sc.intypeof = save; + } + L1: + e = new TypeExp(loc, new TypeTypeof(loc, e)); + e = e.expressionSemantic(sc); + } + e = resolveProperties(sc, e); + if (!gag) + ad.aliasthis.checkDeprecatedAliasThis(loc, sc); + else if (global.endGagging(olderrors)) + e = null; + } + + import dmd.dclass : ClassDeclaration; + auto cd = ad.isClassDeclaration(); + if ((!e || !ad.aliasthis) && cd && cd.baseClass && cd.baseClass != ClassDeclaration.object) + { + ad = cd.baseClass; + continue; + } + break; + } + return e; +} + +/** + * Check if an `alias this` is deprecated + * + * Usually one would use `expression.checkDeprecated(scope, aliasthis)` to + * check if `expression` uses a deprecated `aliasthis`, but this calls + * `toPrettyChars` which lead to the following message: + * "Deprecation: alias this `fullyqualified.aggregate.__anonymous` is deprecated" + * + * Params: + * at = The `AliasThis` object to check + * loc = `Loc` of the expression triggering the access to `at` + * sc = `Scope` of the expression + * (deprecations do not trigger in deprecated scopes) + * + * Returns: + * Whether the alias this was reported as deprecated. + */ +private bool checkDeprecatedAliasThis(AliasThis at, const ref Loc loc, Scope* sc) +{ + if (global.params.useDeprecated != DiagnosticReporting.off + && at.isDeprecated() && !sc.isDeprecated()) + { + const(char)* message = null; + for (Dsymbol p = at; p; p = p.parent) + { + message = p.depdecl ? p.depdecl.getMessage() : null; + if (message) + break; + } + if (message) + deprecation(loc, "`alias %s this` is deprecated - %s", + at.sym.toChars(), message); + else + deprecation(loc, "`alias %s this` is deprecated", + at.sym.toChars()); + + if (auto ti = sc.parent ? sc.parent.isInstantiated() : null) + ti.printInstantiationTrace(Classification.deprecation); + + return true; + } + return false; +} + private extern(C++) final class DsymbolSemanticVisitor : Visitor { alias visit = Visitor.visit; @@ -359,7 +495,8 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor Dsymbol s = ad.search(dsym.loc, dsym.ident); if (!s) { - s = sc.search(dsym.loc, dsym.ident, null); + Dsymbol pscopesym; + s = sc.search(dsym.loc, dsym.ident, pscopesym); if (s) error(dsym.loc, "`%s` is not a member of `%s`", s.toChars(), ad.toChars()); else @@ -449,7 +586,7 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor printf(" type = %s\n", dsym.type ? dsym.type.toChars() : "null"); printf(" stc = x%llx\n", dsym.storage_class); printf(" storage_class = x%llx\n", dsym.storage_class); - printf("linkage = %d\n", dsym.linkage); + printf("linkage = %d\n", dsym._linkage); //if (strcmp(toChars(), "mul") == 0) assert(0); } //if (semanticRun > PASS.initial) @@ -1494,7 +1631,7 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor { AliasDeclaration ad = imp.aliasdecls[i]; //printf("\tImport %s alias %s = %s, scope = %p\n", toPrettyChars(), aliases[i].toChars(), names[i].toChars(), ad._scope); - Dsymbol sym = imp.mod.search(imp.loc, imp.names[i], IgnorePrivateImports); + Dsymbol sym = imp.mod.search(imp.loc, imp.names[i], SearchOpt.ignorePrivateImports); if (sym) { import dmd.access : symbolIsVisible; @@ -4121,7 +4258,8 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor // check if `_d_cmain` is defined bool cmainTemplateExists() { - auto rootSymbol = sc.search(funcdecl.loc, Id.empty, null); + Dsymbol pscopesym; + auto rootSymbol = sc.search(funcdecl.loc, Id.empty, pscopesym); if (auto moduleSymbol = rootSymbol.search(funcdecl.loc, Id.object)) if (moduleSymbol.search(funcdecl.loc, Id.CMain)) return true; @@ -7206,7 +7344,7 @@ private void aliasAssignSemantic(AliasAssign ds, Scope* sc) AliasDeclaration findAliasDeclaration(AliasAssign ds, Scope* sc) { Dsymbol scopesym; - Dsymbol as = sc.search(ds.loc, ds.ident, &scopesym); + Dsymbol as = sc.search(ds.loc, ds.ident, scopesym); if (!as) { .error(ds.loc, "%s `%s` undefined identifier `%s`", ds.kind, ds.toPrettyChars, ds.ident.toChars()); @@ -7833,11 +7971,11 @@ void checkPrintfScanfSignature(FuncDeclaration funcdecl, TypeFunction f, Scope* * d = dsymbol where ident is searched for * loc = location to print for error messages * ident = identifier to search for - * flags = IgnoreXXXX + * flags = search options * Returns: * null if not found */ -extern(C++) Dsymbol search(Dsymbol d, const ref Loc loc, Identifier ident, int flags = IgnoreNone) +extern(C++) Dsymbol search(Dsymbol d, const ref Loc loc, Identifier ident, SearchOptFlags flags = SearchOpt.all) { scope v = new SearchVisitor(loc, ident, flags); d.accept(v); @@ -7862,13 +8000,13 @@ Dsymbol search_correct(Dsymbol d, Identifier ident) cost = 0; // all the same cost Dsymbol s = d; Module.clearCache(); - return s.search(Loc.initial, id, IgnoreErrors); + return s.search(Loc.initial, id, SearchOpt.ignoreErrors); } if (global.gag) return null; // don't do it for speculative compiles; too time consuming // search for exact name first - if (auto s = d.search(Loc.initial, ident, IgnoreErrors)) + if (auto s = d.search(Loc.initial, ident, SearchOpt.ignoreErrors)) return s; import dmd.root.speller : speller; @@ -7881,10 +8019,10 @@ private extern(C++) class SearchVisitor : Visitor const Loc loc; Identifier ident; - int flags; + SearchOptFlags flags; Dsymbol result; - this(const ref Loc loc, Identifier ident, int flags) + this(const ref Loc loc, Identifier ident, SearchOptFlags flags) { this.loc = loc; this.ident = ident; @@ -7908,7 +8046,7 @@ private extern(C++) class SearchVisitor : Visitor //if (strcmp(ident.toChars(),"c") == 0) *(char*)0=0; // Look in symbols declared in this module - if (sds.symtab && !(flags & SearchImportsOnly)) + if (sds.symtab && !(flags & SearchOpt.importsOnly)) { //printf(" look in locals\n"); auto s1 = sds.symtab.lookup(ident); @@ -7931,30 +8069,30 @@ private extern(C++) class SearchVisitor : Visitor for (size_t i = 0; i < sds.importedScopes.length; i++) { // If private import, don't search it - if ((flags & IgnorePrivateImports) && sds.visibilities[i] == Visibility.Kind.private_) + if ((flags & SearchOpt.ignorePrivateImports) && sds.visibilities[i] == Visibility.Kind.private_) continue; - int sflags = flags & (IgnoreErrors | IgnoreAmbiguous); // remember these in recursive searches + SearchOptFlags sflags = flags & (SearchOpt.ignoreErrors | SearchOpt.ignoreAmbiguous); // remember these in recursive searches Dsymbol ss = (*sds.importedScopes)[i]; //printf("\tscanning import '%s', visibilities = %d, isModule = %p, isImport = %p\n", ss.toChars(), visibilities[i], ss.isModule(), ss.isImport()); if (ss.isModule()) { - if (flags & SearchLocalsOnly) + if (flags & SearchOpt.localsOnly) continue; } else // mixin template { - if (flags & SearchImportsOnly) + if (flags & SearchOpt.importsOnly) continue; - sflags |= SearchLocalsOnly; + sflags |= SearchOpt.localsOnly; } /* Don't find private members if ss is a module */ - Dsymbol s2 = ss.search(loc, ident, sflags | (ss.isModule() ? IgnorePrivateImports : IgnoreNone)); + Dsymbol s2 = ss.search(loc, ident, sflags | (ss.isModule() ? SearchOpt.ignorePrivateImports : SearchOpt.all)); import dmd.access : symbolIsVisible; - if (!s2 || !(flags & IgnoreSymbolVisibility) && !symbolIsVisible(sds, s2)) + if (!s2 || !(flags & SearchOpt.ignoreVisibility) && !symbolIsVisible(sds, s2)) continue; if (!s) { @@ -8025,7 +8163,7 @@ private extern(C++) class SearchVisitor : Visitor } } - if (flags & IgnoreAmbiguous) // if return NULL on ambiguity + if (flags & SearchOpt.ignoreAmbiguous) // if return NULL on ambiguity return setResult(null); /* If two imports from C import files, pick first one, as C has global name space @@ -8033,7 +8171,7 @@ private extern(C++) class SearchVisitor : Visitor if (s.isCsymbol() && s2.isCsymbol()) continue; - if (!(flags & IgnoreErrors)) + if (!(flags & SearchOpt.ignoreErrors)) ScopeDsymbol.multiplyDefined(loc, s, s2); break; } @@ -8060,7 +8198,7 @@ private extern(C++) class SearchVisitor : Visitor override void visit(WithScopeSymbol ws) { //printf("WithScopeSymbol.search(%s)\n", ident.toChars()); - if (flags & SearchImportsOnly) + if (flags & SearchOpt.importsOnly) return setResult(null); // Acts as proxy to the with class declaration Dsymbol s = null; @@ -8301,7 +8439,7 @@ private extern(C++) class SearchVisitor : Visitor if (!ns.members || !ns.symtab) // opaque or semantic() is not yet called { - if (!(flags & IgnoreErrors)) + if (!(flags & SearchOpt.ignoreErrors)) .error(loc, "%s `%s` is forward referenced when looking for `%s`", ns.kind, ns.toPrettyChars, ident.toChars()); return setResult(null); } @@ -8324,7 +8462,7 @@ private extern(C++) class SearchVisitor : Visitor override void visit(Package pkg) { //printf("%s Package.search('%s', flags = x%x)\n", pkg.toChars(), ident.toChars(), flags); - flags &= ~SearchLocalsOnly; // searching an import is always transitive + flags &= ~cast(int)SearchOpt.localsOnly; // searching an import is always transitive if (!pkg.isModule() && pkg.mod) { // Prefer full package name. @@ -8351,8 +8489,8 @@ private extern(C++) class SearchVisitor : Visitor /* Qualified module searches always search their imports, * even if SearchLocalsOnly */ - if (!(flags & SearchUnqualifiedModule)) - flags &= ~(SearchUnqualifiedModule | SearchLocalsOnly); + if (!(flags & SearchOpt.unqualifiedModule)) + flags &= ~(SearchOpt.unqualifiedModule | SearchOpt.localsOnly); if (m.searchCacheIdent == ident && m.searchCacheFlags == flags) { @@ -8401,7 +8539,7 @@ private extern(C++) class SearchVisitor : Visitor if (!sd.members || !sd.symtab) // opaque or semantic() is not yet called { // .stringof is always defined (but may be hidden by some other symbol) - if(ident != Id.stringof && !(flags & IgnoreErrors) && sd.semanticRun < PASS.semanticdone) + if(ident != Id.stringof && !(flags & SearchOpt.ignoreErrors) && sd.semanticRun < PASS.semanticdone) .error(loc, "%s `%s` is forward referenced when looking for `%s`", sd.kind, sd.toPrettyChars, ident.toChars()); return setResult(null); } @@ -8427,7 +8565,7 @@ private extern(C++) class SearchVisitor : Visitor if (!cd.members || !cd.symtab) // opaque or addMember is not yet done { // .stringof is always defined (but may be hidden by some other symbol) - if (ident != Id.stringof && !(flags & IgnoreErrors) && cd.semanticRun < PASS.semanticdone) + if (ident != Id.stringof && !(flags & SearchOpt.ignoreErrors) && cd.semanticRun < PASS.semanticdone) cd.classError("%s `%s` is forward referenced when looking for `%s`", ident.toChars()); //*(char*)0=0; return setResult(null); @@ -8437,7 +8575,7 @@ private extern(C++) class SearchVisitor : Visitor auto s = result; // don't search imports of base classes - if (flags & SearchImportsOnly) + if (flags & SearchOpt.importsOnly) return setResult(s); if (s) @@ -8462,7 +8600,7 @@ private extern(C++) class SearchVisitor : Visitor continue; else if (s == cd) // happens if s is nested in this and derives from this s = null; - else if (!(flags & IgnoreSymbolVisibility) && !(s.visible().kind == Visibility.Kind.protected_) && !symbolIsVisible(cd, s)) + else if (!(flags & SearchOpt.ignoreVisibility) && !(s.visible().kind == Visibility.Kind.protected_) && !symbolIsVisible(cd, s)) s = null; else break; @@ -8621,3 +8759,554 @@ private extern(C++) class SetScopeVisitor : Visitor visit(cast(AttribDeclaration)uad); } } + +extern(C++) void importAll(Dsymbol d, Scope* sc) +{ + scope iav = new ImportAllVisitor(sc); + d.accept(iav); +} + +extern(C++) class ImportAllVisitor : Visitor +{ + alias visit = typeof(super).visit; + Scope* sc; + + this(Scope* sc) + { + this.sc = sc; + } + + override void visit(Dsymbol d) {} + + override void visit(Import imp) + { + if (imp.mod) return; // Already done + + /* + * https://issues.dlang.org/show_bug.cgi?id=15525 + * + * Loading the import has failed, + * most likely because of parsing errors. + * Therefore we cannot trust the resulting AST. + */ + if (imp.load(sc)) + { + // https://issues.dlang.org/show_bug.cgi?id=23873 + // For imports that are not at module or function level, + // e.g. aggregate level, the import symbol is added to the + // symbol table and later semantic is performed on it. + // This leads to semantic analysis on an malformed AST + // which causes all kinds of segfaults. + // The fix is to note that the module has errors and avoid + // semantic analysis on it. + if(imp.mod) + imp.mod.errors = true; + return; + } + + if (!imp.mod) return; // Failed + + if (sc.stc & STC.static_) + imp.isstatic = true; + imp.mod.importAll(null); + imp.mod.checkImportDeprecation(imp.loc, sc); + if (sc.explicitVisibility) + imp.visibility = sc.visibility; + if (!imp.isstatic && !imp.aliasId && !imp.names.length) + sc.scopesym.importScope(imp.mod, imp.visibility); + // Enable access to pkgs/mod as soon as posible, because compiler + // can traverse them before the import gets semantic (Issue: 21501) + if (!imp.aliasId && !imp.names.length) + imp.addPackageAccess(sc.scopesym); + } + + override void visit(Module m) + { + //printf("+Module::importAll(this = %p, '%s'): parent = %p\n", m, m.toChars(), m.parent); + if (m._scope) + return; // already done + if (m.filetype == FileType.ddoc) + { + error(m.loc, "%s `%s` is a Ddoc file, cannot import it", m.kind, m.toPrettyChars); + return; + } + + /* Note that modules get their own scope, from scratch. + * This is so regardless of where in the syntax a module + * gets imported, it is unaffected by context. + * Ignore prevsc. + */ + Scope* sc = Scope.createGlobal(m, global.errorSink); // create root scope + + if (m.md && m.md.msg) + m.md.msg = semanticString(sc, m.md.msg, "deprecation message"); + + // Add import of "object", even for the "object" module. + // If it isn't there, some compiler rewrites, like + // classinst == classinst -> .object.opEquals(classinst, classinst) + // would fail inside object.d. + if (m.filetype != FileType.c && + (m.members.length == 0 || + (*m.members)[0].ident != Id.object || + (*m.members)[0].isImport() is null)) + { + auto im = new Import(Loc.initial, null, Id.object, null, 0); + m.members.shift(im); + } + if (!m.symtab) + { + // Add all symbols into module's symbol table + m.symtab = new DsymbolTable(); + for (size_t i = 0; i < m.members.length; i++) + { + Dsymbol s = (*m.members)[i]; + s.addMember(sc, sc.scopesym); + } + } + // anything else should be run after addMember, so version/debug symbols are defined + /* Set scope for the symbols so that if we forward reference + * a symbol, it can possibly be resolved on the spot. + * If this works out well, it can be extended to all modules + * before any semantic() on any of them. + */ + m.setScope(sc); // remember module scope for semantic + for (size_t i = 0; i < m.members.length; i++) + { + Dsymbol s = (*m.members)[i]; + s.setScope(sc); + } + for (size_t i = 0; i < m.members.length; i++) + { + Dsymbol s = (*m.members)[i]; + s.importAll(sc); + } + sc = sc.pop(); + sc.pop(); // 2 pops because Scope.createGlobal() created 2 + } + + override void visit(AttribDeclaration atb) + { + Dsymbols* d = atb.include(sc); + //printf("\tAttribDeclaration::importAll '%s', d = %p\n", toChars(), d); + if (d) + { + Scope* sc2 = atb.newScope(sc); + d.foreachDsymbol( s => s.importAll(sc2) ); + if (sc2 != sc) + sc2.pop(); + } + } + + // do not evaluate condition before semantic pass + override void visit(StaticIfDeclaration _) {} + // do not evaluate aggregate before semantic pass + override void visit(StaticForeachDeclaration _) {} +} + +extern(C++) void setFieldOffset(Dsymbol d, AggregateDeclaration ad, FieldState* fieldState, bool isunion) +{ + scope v = new SetFieldOffsetVisitor(ad, fieldState, isunion); + d.accept(v); +} + +private extern(C++) class SetFieldOffsetVisitor : Visitor +{ + alias visit = Visitor.visit; + + AggregateDeclaration ad; + FieldState* fieldState; + bool isunion; + + this(AggregateDeclaration ad, FieldState* fieldState, bool isunion) + { + this.ad = ad; + this.fieldState = fieldState; + this.isunion = isunion; + } + + override void visit(Dsymbol d) {} + + override void visit(Nspace ns) + { + //printf("Nspace::setFieldOffset() %s\n", toChars()); + if (ns._scope) // if fwd reference + dsymbolSemantic(ns, null); // try to resolve it + ns.members.foreachDsymbol( s => s.setFieldOffset(ad, fieldState, isunion) ); + } + + override void visit(VarDeclaration vd) + { + //printf("VarDeclaration::setFieldOffset(ad = %s) %s\n", ad.toChars(), vd.toChars()); + + if (vd.aliasTuple) + { + // If this variable was really a tuple, set the offsets for the tuple fields + vd.aliasTuple.foreachVar((s) { s.setFieldOffset(ad, fieldState, isunion); }); + return; + } + + if (!vd.isField()) + return; + assert(!(vd.storage_class & (STC.static_ | STC.extern_ | STC.parameter))); + + //printf("+VarDeclaration::setFieldOffset(ad = %s) %s\n", ad.toChars(), toChars()); + + /* Fields that are tuples appear both as part of TupleDeclarations and + * as members. That means ignore them if they are already a field. + */ + if (vd.offset) + { + // already a field + fieldState.offset = ad.structsize; // https://issues.dlang.org/show_bug.cgi?id=13613 + return; + } + for (size_t i = 0; i < ad.fields.length; i++) + { + if (ad.fields[i] == vd) + { + // already a field + fieldState.offset = ad.structsize; // https://issues.dlang.org/show_bug.cgi?id=13613 + return; + } + } + + // Check for forward referenced types which will fail the size() call + Type t = vd.type.toBasetype(); + if (vd.storage_class & STC.ref_) + { + // References are the size of a pointer + t = Type.tvoidptr; + } + Type tv = t.baseElemOf(); + if (tv.ty == Tstruct) + { + auto ts = cast(TypeStruct)tv; + assert(ts.sym != ad); // already checked in ad.determineFields() + if (!ts.sym.determineSize(vd.loc)) + { + vd.type = Type.terror; + vd.errors = true; + return; + } + } + + // List in ad.fields. Even if the type is error, it's necessary to avoid + // pointless error diagnostic "more initializers than fields" on struct literal. + ad.fields.push(vd); + + if (t.ty == Terror) + return; + + /* If coming after a bit field in progress, + * advance past the field + */ + fieldState.inFlight = false; + + const sz = t.size(vd.loc); + assert(sz != SIZE_INVALID && sz < uint.max); + uint memsize = cast(uint)sz; // size of member + uint memalignsize = target.fieldalign(t); // size of member for alignment purposes + vd.offset = placeField( + fieldState.offset, + memsize, memalignsize, vd.alignment, + ad.structsize, ad.alignsize, + isunion); + + //printf("\t%s: memalignsize = %d\n", toChars(), memalignsize); + //printf(" addField '%s' to '%s' at offset %d, size = %d\n", toChars(), ad.toChars(), offset, memsize); + } + + override void visit(BitFieldDeclaration bfd) + { + enum log = false; + static if (log) + { + printf("BitFieldDeclaration::setFieldOffset(ad: %s, field: %s)\n", ad.toChars(), bfd.toChars()); + void print(const FieldState* fieldState) + { + fieldState.print(); + printf(" fieldWidth = %d bits\n", bfd.fieldWidth); + } + print(fieldState); + } + + Type t = bfd.type.toBasetype(); + const bool anon = bfd.isAnonymous(); + + // List in ad.fields. Even if the type is error, it's necessary to avoid + // pointless error diagnostic "more initializers than fields" on struct literal. + if (!anon) + ad.fields.push(bfd); + + if (t.ty == Terror) + return; + + const sz = t.size(bfd.loc); + assert(sz != SIZE_INVALID && sz < uint.max); + uint memsize = cast(uint)sz; // size of member + uint memalignsize = target.fieldalign(t); // size of member for alignment purposes + if (log) printf(" memsize: %u memalignsize: %u\n", memsize, memalignsize); + + if (bfd.fieldWidth == 0 && !anon) + error(bfd.loc, "named bit fields cannot have 0 width"); + if (bfd.fieldWidth > memsize * 8) + error(bfd.loc, "bit field width %d is larger than type", bfd.fieldWidth); + + const style = target.c.bitFieldStyle; + + void startNewField() + { + if (log) printf("startNewField()\n"); + uint alignsize; + if (style == TargetC.BitFieldStyle.Gcc_Clang) + { + if (bfd.fieldWidth > 32) + alignsize = memalignsize; + else if (bfd.fieldWidth > 16) + alignsize = 4; + else if (bfd.fieldWidth > 8) + alignsize = 2; + else + alignsize = 1; + } + else + alignsize = memsize; // not memalignsize + + uint dummy; + bfd.offset = placeField( + fieldState.offset, + memsize, alignsize, bfd.alignment, + ad.structsize, + (anon && style == TargetC.BitFieldStyle.Gcc_Clang) ? dummy : ad.alignsize, + isunion); + + fieldState.inFlight = true; + fieldState.fieldOffset = bfd.offset; + fieldState.bitOffset = 0; + fieldState.fieldSize = memsize; + } + + if (style == TargetC.BitFieldStyle.Gcc_Clang) + { + if (bfd.fieldWidth == 0) + { + if (!isunion) + { + // Use type of zero width field to align to next field + fieldState.offset = (fieldState.offset + memalignsize - 1) & ~(memalignsize - 1); + ad.structsize = fieldState.offset; + } + + fieldState.inFlight = false; + return; + } + + if (ad.alignsize == 0) + ad.alignsize = 1; + if (!anon && + ad.alignsize < memalignsize) + ad.alignsize = memalignsize; + } + else if (style == TargetC.BitFieldStyle.MS) + { + if (ad.alignsize == 0) + ad.alignsize = 1; + if (bfd.fieldWidth == 0) + { + if (fieldState.inFlight && !isunion) + { + // documentation says align to next int + //const alsz = cast(uint)Type.tint32.size(); + const alsz = memsize; // but it really does this + fieldState.offset = (fieldState.offset + alsz - 1) & ~(alsz - 1); + ad.structsize = fieldState.offset; + } + + fieldState.inFlight = false; + return; + } + } + else if (style == TargetC.BitFieldStyle.DM) + { + if (anon && bfd.fieldWidth && (!fieldState.inFlight || fieldState.bitOffset == 0)) + return; // this probably should be a bug in DMC + if (ad.alignsize == 0) + ad.alignsize = 1; + if (bfd.fieldWidth == 0) + { + if (fieldState.inFlight && !isunion) + { + const alsz = memsize; + fieldState.offset = (fieldState.offset + alsz - 1) & ~(alsz - 1); + ad.structsize = fieldState.offset; + } + + fieldState.inFlight = false; + return; + } + } + + if (!fieldState.inFlight) + { + //printf("not in flight\n"); + startNewField(); + } + else if (style == TargetC.BitFieldStyle.Gcc_Clang) + { + // If the bit-field spans more units of alignment than its type, + // start a new field at the next alignment boundary. + if (fieldState.bitOffset == fieldState.fieldSize * 8 && + fieldState.bitOffset + bfd.fieldWidth > memalignsize * 8) + { + if (log) printf("more units of alignment than its type\n"); + startNewField(); // the bit field is full + } + else + { + // if alignment boundary is crossed + uint start = fieldState.fieldOffset * 8 + fieldState.bitOffset; + uint end = start + bfd.fieldWidth; + //printf("%s start: %d end: %d memalignsize: %d\n", ad.toChars(), start, end, memalignsize); + if (start / (memalignsize * 8) != (end - 1) / (memalignsize * 8)) + { + if (log) printf("alignment is crossed\n"); + startNewField(); + } + } + } + else if (style == TargetC.BitFieldStyle.DM || + style == TargetC.BitFieldStyle.MS) + { + if (memsize != fieldState.fieldSize || + fieldState.bitOffset + bfd.fieldWidth > fieldState.fieldSize * 8) + { + //printf("new field\n"); + startNewField(); + } + } + else + assert(0); + + bfd.offset = fieldState.fieldOffset; + bfd.bitOffset = fieldState.bitOffset; + + const pastField = bfd.bitOffset + bfd.fieldWidth; + if (style == TargetC.BitFieldStyle.Gcc_Clang) + { + auto size = (pastField + 7) / 8; + fieldState.fieldSize = size; + //printf(" offset: %d, size: %d\n", offset, size); + if (isunion) + { + const newstructsize = bfd.offset + size; + if (newstructsize > ad.structsize) + ad.structsize = newstructsize; + } + else + ad.structsize = bfd.offset + size; + } + else + fieldState.fieldSize = memsize; + //printf("at end: ad.structsize = %d\n", cast(int)ad.structsize); + //print(fieldState); + + if (!isunion) + { + fieldState.offset = bfd.offset + fieldState.fieldSize; + fieldState.bitOffset = pastField; + } + + //printf("\t%s: offset = %d bitOffset = %d fieldWidth = %d memsize = %d\n", toChars(), offset, bitOffset, fieldWidth, memsize); + //printf("\t%s: memalignsize = %d\n", toChars(), memalignsize); + //printf(" addField '%s' to '%s' at offset %d, size = %d\n", toChars(), ad.toChars(), offset, memsize); + } + + override void visit(TemplateMixin tm) + { + //printf("TemplateMixin.setFieldOffset() %s\n", tm.toChars()); + if (tm._scope) // if fwd reference + dsymbolSemantic(tm, null); // try to resolve it + + tm.members.foreachDsymbol( (s) { s.setFieldOffset(ad, fieldState, isunion); } ); + } + + override void visit(AttribDeclaration atd) + { + atd.include(null).foreachDsymbol( s => s.setFieldOffset(ad, fieldState, isunion) ); + } + + override void visit(AnonDeclaration anond) + { + //printf("\tAnonDeclaration::setFieldOffset %s %p\n", isunion ? "union" : "struct", anond); + if (anond.decl) + { + /* This works by treating an AnonDeclaration as an aggregate 'member', + * so in order to place that member we need to compute the member's + * size and alignment. + */ + size_t fieldstart = ad.fields.length; + + /* Hackishly hijack ad's structsize and alignsize fields + * for use in our fake anon aggregate member. + */ + uint savestructsize = ad.structsize; + uint savealignsize = ad.alignsize; + ad.structsize = 0; + ad.alignsize = 0; + + FieldState fs; + anond.decl.foreachDsymbol( (s) + { + s.setFieldOffset(ad, &fs, anond.isunion); + if (anond.isunion) + fs.offset = 0; + }); + + /* https://issues.dlang.org/show_bug.cgi?id=13613 + * If the fields in this.members had been already + * added in ad.fields, just update *poffset for the subsequent + * field offset calculation. + */ + if (fieldstart == ad.fields.length) + { + ad.structsize = savestructsize; + ad.alignsize = savealignsize; + fieldState.offset = ad.structsize; + return; + } + + anond.anonstructsize = ad.structsize; + anond.anonalignsize = ad.alignsize; + ad.structsize = savestructsize; + ad.alignsize = savealignsize; + + // 0 sized structs are set to 1 byte + if (anond.anonstructsize == 0) + { + anond.anonstructsize = 1; + anond.anonalignsize = 1; + } + + assert(anond._scope); + auto alignment = anond._scope.alignment(); + + /* Given the anon 'member's size and alignment, + * go ahead and place it. + */ + anond.anonoffset = placeField( + fieldState.offset, + anond.anonstructsize, anond.anonalignsize, alignment, + ad.structsize, ad.alignsize, + isunion); + + // Add to the anon fields the base offset of this anonymous aggregate + //printf("anon fields, anonoffset = %d\n", anonoffset); + foreach (const i; fieldstart .. ad.fields.length) + { + VarDeclaration v = ad.fields[i]; + //printf("\t[%d] %s %d\n", i, v.toChars(), v.offset); + v.offset += anond.anonoffset; + } + } + } +} diff --git a/gcc/d/dmd/dtemplate.d b/gcc/d/dmd/dtemplate.d index 326d663..e440b9e 100644 --- a/gcc/d/dmd/dtemplate.d +++ b/gcc/d/dmd/dtemplate.d @@ -6465,7 +6465,7 @@ extern (C++) class TemplateInstance : ScopeDsymbol */ Identifier id = name; Dsymbol scopesym; - Dsymbol s = sc.search(loc, id, &scopesym); + Dsymbol s = sc.search(loc, id, scopesym); if (!s) { s = sc.search_correct(id); @@ -7831,15 +7831,6 @@ extern (C++) final class TemplateMixin : TemplateInstance return members.foreachDsymbol( (s) { return s.hasPointers(); } ) != 0; } - override void setFieldOffset(AggregateDeclaration ad, ref FieldState fieldState, bool isunion) - { - //printf("TemplateMixin.setFieldOffset() %s\n", toChars()); - if (_scope) // if fwd reference - dsymbolSemantic(this, null); // try to resolve it - - members.foreachDsymbol( (s) { s.setFieldOffset(ad, fieldState, isunion); } ); - } - override const(char)* toChars() const { OutBuffer buf; diff --git a/gcc/d/dmd/dtoh.d b/gcc/d/dmd/dtoh.d index 9f85574..ed83a8d 100644 --- a/gcc/d/dmd/dtoh.d +++ b/gcc/d/dmd/dtoh.d @@ -3284,7 +3284,7 @@ ASTCodegen.Dsymbol symbolFromType(ASTCodegen.Type t) @safe */ ASTCodegen.Dsymbol findMember(ASTCodegen.Dsymbol sym, Identifier name) { - if (auto mem = sym.search(Loc.initial, name, ASTCodegen.IgnoreErrors)) + if (auto mem = sym.search(Loc.initial, name, ASTCodegen.SearchOpt.ignoreErrors)) return mem; // search doesn't work for declarations inside of uninstantiated diff --git a/gcc/d/dmd/errorsink.d b/gcc/d/dmd/errorsink.d index ce23517..3811f1d 100644 --- a/gcc/d/dmd/errorsink.d +++ b/gcc/d/dmd/errorsink.d @@ -61,6 +61,20 @@ class ErrorSinkNull : ErrorSink } /***************************************** + * Ignores the messages, but sets `sawErrors` for any calls to `error()` + */ +class ErrorSinkLatch : ErrorSinkNull +{ + nothrow: + extern (C++): + override: + + bool sawErrors; + + void error(const ref Loc loc, const(char)* format, ...) { sawErrors = true; } +} + +/***************************************** * Simplest implementation, just sends messages to stderr. * See also: ErrorSinkCompiler. */ diff --git a/gcc/d/dmd/expression.d b/gcc/d/dmd/expression.d index cd93e54..f51a8b0 100644 --- a/gcc/d/dmd/expression.d +++ b/gcc/d/dmd/expression.d @@ -21,7 +21,6 @@ import dmd.aggregate; import dmd.arraytypes; import dmd.astenums; import dmd.ast_node; -import dmd.gluelayer; import dmd.dclass; import dmd.declaration; import dmd.dimport; @@ -2240,7 +2239,7 @@ extern (C++) final class StructLiteralExp : Expression // while `sym` is only used in `e2ir/s2ir/tocsym` which comes after union { - Symbol* sym; /// back end symbol to initialize with literal + void* sym; /// back end symbol to initialize with literal (used as a Symbol*) /// those fields need to prevent a infinite recursion when one field of struct initialized with 'this' pointer. StructLiteralExp inlinecopy; diff --git a/gcc/d/dmd/expressionsem.d b/gcc/d/dmd/expressionsem.d index 1664bf2..c21b382 100644 --- a/gcc/d/dmd/expressionsem.d +++ b/gcc/d/dmd/expressionsem.d @@ -875,7 +875,7 @@ private Expression searchUFCS(Scope* sc, UnaExp ue, Identifier ident) Loc loc = ue.loc; // TODO: merge with Scope.search.searchScopes() - Dsymbol searchScopes(int flags) + Dsymbol searchScopes(SearchOptFlags flags) { Dsymbol s = null; for (Scope* scx = sc; scx; scx = scx.enclosing) @@ -883,7 +883,7 @@ private Expression searchUFCS(Scope* sc, UnaExp ue, Identifier ident) if (!scx.scopesym) continue; if (scx.scopesym.isModule()) - flags |= SearchUnqualifiedModule; // tell Module.search() that SearchLocalsOnly is to be obeyed + flags |= SearchOpt.unqualifiedModule; // tell Module.search() that SearchOpt.localsOnly is to be obeyed s = scx.scopesym.search(loc, ident, flags); if (s) { @@ -910,18 +910,18 @@ private Expression searchUFCS(Scope* sc, UnaExp ue, Identifier ident) return s; } - int flags = 0; + SearchOptFlags flags = SearchOpt.all; Dsymbol s; if (sc.flags & SCOPE.ignoresymbolvisibility) - flags |= IgnoreSymbolVisibility; + flags |= SearchOpt.ignoreVisibility; // First look in local scopes - s = searchScopes(flags | SearchLocalsOnly); + s = searchScopes(flags | SearchOpt.localsOnly); if (!s) { // Second look in imported modules - s = searchScopes(flags | SearchImportsOnly); + s = searchScopes(flags | SearchOpt.importsOnly); } if (!s) @@ -3743,7 +3743,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor } Dsymbol scopesym; - Dsymbol s = sc.search(exp.loc, exp.ident, &scopesym); + Dsymbol s = sc.search(exp.loc, exp.ident, scopesym); if (s) { if (s.errors) @@ -6744,7 +6744,8 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor if (!sc.insert(s)) { - auto conflict = sc.search(Loc.initial, s.ident, null); + Dsymbol pscopesym; + auto conflict = sc.search(Loc.initial, s.ident, pscopesym); error(e.loc, "declaration `%s` is already defined", s.toPrettyChars()); errorSupplemental(conflict.loc, "`%s` `%s` is defined here", conflict.kind(), conflict.toChars()); @@ -6986,7 +6987,8 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor */ if (!tup && !sc.insert(s)) { - auto conflict = sc.search(Loc.initial, s.ident, null); + Dsymbol pscopesym; + auto conflict = sc.search(Loc.initial, s.ident, pscopesym); error(e.loc, "declaration `%s` is already defined", s.toPrettyChars()); errorSupplemental(conflict.loc, "`%s` `%s` is defined here", conflict.kind(), conflict.toChars()); @@ -7293,7 +7295,8 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor s.dsymbolSemantic(sc); if (!sc.insert(s)) { - auto conflict = sc.search(Loc.initial, s.ident, null); + Dsymbol pscopesym; + auto conflict = sc.search(Loc.initial, s.ident, pscopesym); error(e.loc, "declaration `%s` is already defined", s.toPrettyChars()); errorSupplemental(conflict.loc, "`%s` `%s` is defined here", conflict.kind(), conflict.toChars()); @@ -14208,15 +14211,15 @@ Expression dotIdSemanticProp(DotIdExp exp, Scope* sc, bool gag) if (auto ie = eright.isScopeExp()) // also used for template alias's { - auto flags = SearchLocalsOnly; + SearchOptFlags flags = SearchOpt.localsOnly; /* Disable access to another module's private imports. * The check for 'is sds our current module' is because * the current module should have access to its own imports. */ if (ie.sds.isModule() && ie.sds != sc._module) - flags |= IgnorePrivateImports; + flags |= SearchOpt.ignorePrivateImports; if (sc.flags & SCOPE.ignoresymbolvisibility) - flags |= IgnoreSymbolVisibility; + flags |= SearchOpt.ignoreVisibility; Dsymbol s = ie.sds.search(exp.loc, exp.ident, flags); /* Check for visibility before resolving aliases because public * aliases to private symbols are public. @@ -16038,7 +16041,8 @@ VarDeclaration makeThis2Argument(const ref Loc loc, Scope* sc, FuncDeclaration f */ bool verifyHookExist(const ref Loc loc, ref Scope sc, Identifier id, string description, Identifier module_ = Id.object) { - auto rootSymbol = sc.search(loc, Id.empty, null); + Dsymbol pscopesym; + auto rootSymbol = sc.search(loc, Id.empty, pscopesym); if (auto moduleSymbol = rootSymbol.search(loc, module_)) if (moduleSymbol.search(loc, id)) return true; diff --git a/gcc/d/dmd/func.d b/gcc/d/dmd/func.d index 351faa47..feaa5bb 100644 --- a/gcc/d/dmd/func.d +++ b/gcc/d/dmd/func.d @@ -695,6 +695,7 @@ extern (C++) class FuncDeclaration : Declaration int result = 0; if (fd.ident == ident) { + import dmd.typesem : covariant; const cov = type.covariant(fd.type); if (cov != Covariant.distinct) { @@ -721,6 +722,8 @@ extern (C++) class FuncDeclaration : Declaration final int findVtblIndex(Dsymbols* vtbl, int dim) { //printf("findVtblIndex() %s\n", toChars()); + import dmd.typesem : covariant; + FuncDeclaration mismatch = null; StorageClass mismatchstc = 0; int mismatchvi = -1; @@ -947,6 +950,7 @@ extern (C++) class FuncDeclaration : Declaration */ if (t.ty == Tfunction) { + import dmd.typesem : covariant; auto tf = cast(TypeFunction)f.type; if (tf.covariant(t) == Covariant.yes && tf.nextOf().implicitConvTo(t.nextOf()) >= MATCH.constant) @@ -1157,6 +1161,7 @@ extern (C++) class FuncDeclaration : Declaration args.push(e); } + import dmd.typesem : callMatch; MATCH m = tg.callMatch(null, ArgumentList(&args, names), 1); if (m > MATCH.nomatch) { diff --git a/gcc/d/dmd/globals.d b/gcc/d/dmd/globals.d index 8d88207..9257bc4 100644 --- a/gcc/d/dmd/globals.d +++ b/gcc/d/dmd/globals.d @@ -167,7 +167,7 @@ extern (C++) struct Param bool cov; // generate code coverage data ubyte covPercent; // 0..100 code coverage percentage required bool ctfe_cov = false; // generate coverage data for ctfe - bool ignoreUnsupportedPragmas; // rather than error on them + bool ignoreUnsupportedPragmas = true; // rather than error on them bool useModuleInfo = true; // generate runtime module information bool useTypeInfo = true; // generate runtime type information bool useExceptions = true; // support exception handling diff --git a/gcc/d/dmd/import.h b/gcc/d/dmd/import.h index 624cd74..2a02f13 100644 --- a/gcc/d/dmd/import.h +++ b/gcc/d/dmd/import.h @@ -41,7 +41,6 @@ public: const char *kind() const override; Visibility visible() override; Import *syntaxCopy(Dsymbol *s) override; // copy only syntax trees - void importAll(Scope *sc) override; Dsymbol *toAlias() override; bool overloadInsert(Dsymbol *s) override; diff --git a/gcc/d/dmd/init.d b/gcc/d/dmd/init.d index e484100..5aefb00 100644 --- a/gcc/d/dmd/init.d +++ b/gcc/d/dmd/init.d @@ -12,21 +12,15 @@ module dmd.init; import core.stdc.stdio; -import core.checkedint; import dmd.arraytypes; import dmd.astenums; import dmd.ast_node; -import dmd.dsymbol; import dmd.expression; -import dmd.globals; -import dmd.hdrgen; import dmd.identifier; import dmd.location; import dmd.mtype; -import dmd.common.outbuffer; import dmd.rootobject; -import dmd.tokens; import dmd.visitor; enum NeedInterpret : int diff --git a/gcc/d/dmd/initsem.d b/gcc/d/dmd/initsem.d index 6d31f95..19d576d 100644 --- a/gcc/d/dmd/initsem.d +++ b/gcc/d/dmd/initsem.d @@ -606,7 +606,7 @@ extern(C++) Initializer initializerSemantic(Initializer init, Scope* sc, ref Typ { import dmd.common.outbuffer; OutBuffer buf; - HdrGenStage hgs; + HdrGenState hgs; toCBuffer(ts.sym, buf, hgs); printf("%s\n", buf.peekChars()); } @@ -803,9 +803,6 @@ extern(C++) Initializer initializerSemantic(Initializer init, Scope* sc, ref Typ Loop1: for (size_t index = 0; index < ci.initializerList.length; ) { - CInitializer cprev; - size_t indexprev; - L1: DesigInit di = ci.initializerList[index]; Designators* dlist = di.designatorList; if (dlist) @@ -833,15 +830,6 @@ extern(C++) Initializer initializerSemantic(Initializer init, Scope* sc, ref Typ continue Loop1; } } - if (cprev) - { - /* The peeling didn't work, so unpeel it - */ - ci = cprev; - index = indexprev; - di = ci.initializerList[index]; - goto L2; - } error(ci.loc, "`.%s` is not a field of `%s`\n", id.toChars(), sd.toChars()); return err(); } @@ -849,18 +837,55 @@ extern(C++) Initializer initializerSemantic(Initializer init, Scope* sc, ref Typ { if (fieldi == nfields) break; - if (/*index == 0 && ci.initializerList.length == 1 &&*/ di.initializer.isCInitializer()) + + auto ix = di.initializer; + + /* If a C initializer is wrapped in a C initializer, with no designators, + * peel off the outer one + */ + if (ix.isCInitializer()) + { + CInitializer cix = ix.isCInitializer(); + if (cix.initializerList.length == 1) + { + DesigInit dix = cix.initializerList[0]; + if (!dix.designatorList) + { + Initializer inix = dix.initializer; + if (inix.isCInitializer()) + ix = inix; + } + } + } + + if (auto cix = ix.isCInitializer()) { - /* Try peeling off this set of { } and see if it works + /* ImportC loses the structure from anonymous structs, but this is retained + * by the initializer syntax. if a CInitializer has a Designator, it is probably + * a nested anonymous struct */ - cprev = ci; - ci = di.initializer.isCInitializer(); - indexprev = index; - index = 0; - goto L1; + if (cix.initializerList.length) + { + DesigInit dix = cix.initializerList[0]; + Designators* dlistx = dix.designatorList; + if (dlistx && (*dlistx).length == 1 && (*dlistx)[0].ident) + { + auto id = (*dlistx)[0].ident; + foreach (k, f; sd.fields[]) // linear search for now + { + if (f.ident == id) + { + fieldi = k; + si.addInit(id, dix.initializer); + ++fieldi; + ++index; + continue Loop1; + } + } + } + } } - L2: VarDeclaration field; while (1) // skip field if it overlaps with previously seen fields { @@ -871,10 +896,11 @@ extern(C++) Initializer initializerSemantic(Initializer init, Scope* sc, ref Typ if (fieldi == nfields) break; } + auto tn = field.type.toBasetype(); auto tnsa = tn.isTypeSArray(); auto tns = tn.isTypeStruct(); - auto ix = di.initializer; + if (tnsa && ix.isExpInitializer()) { ExpInitializer ei = ix.isExpInitializer(); @@ -1013,7 +1039,7 @@ extern(C++) Initializer initializerSemantic(Initializer init, Scope* sc, ref Typ } else { - error(ci.loc, "unrecognized C initializer `%s`", toChars(ci)); + error(ci.loc, "unrecognized C initializer `%s` for type `%s`", toChars(ci), t.toChars()); return err(); } } @@ -1548,6 +1574,11 @@ Expressions* resolveStructLiteralNamedArgs(StructDeclaration sd, Type t, Scope* cast(int) nfields, nfields != 1 ? "s".ptr : "".ptr); return null; } + if (fieldi >= nfields) + { + error(argLoc, "trying to initialize past the last field `%s` of `%s`", sd.fields[nfields - 1].toChars(), sd.toChars()); + return null; + } VarDeclaration vd = sd.fields[fieldi]; if (elems[fieldi]) diff --git a/gcc/d/dmd/lambdacomp.d b/gcc/d/dmd/lambdacomp.d index d19d435..c90c360 100644 --- a/gcc/d/dmd/lambdacomp.d +++ b/gcc/d/dmd/lambdacomp.d @@ -244,7 +244,7 @@ public: { // we must check what the identifier expression is. Dsymbol scopesym; - Dsymbol s = sc.search(exp.loc, exp.ident, &scopesym); + Dsymbol s = sc.search(exp.loc, exp.ident, scopesym); if (s) { auto v = s.isVarDeclaration(); diff --git a/gcc/d/dmd/lexer.d b/gcc/d/dmd/lexer.d index b8faec7..2c6a595 100644 --- a/gcc/d/dmd/lexer.d +++ b/gcc/d/dmd/lexer.d @@ -2008,23 +2008,17 @@ class Lexer case 'u': dchar d1; size_t idx; - auto msg = utf_decodeChar(str, idx, d1); - dchar d2 = 0; - if (idx < n && !msg) - msg = utf_decodeChar(str, idx, d2); - if (msg) - error(loc, "%.*s", cast(int)msg.length, msg.ptr); - else if (idx < n) - error(loc, "max number of chars in 16 bit character literal is 2, had %d", - cast(int)((n + 1) >> 1)); - else if (d1 > 0x1_0000) - error(loc, "%d does not fit in 16 bits", d1); - else if (d2 > 0x1_0000) - error(loc, "%d does not fit in 16 bits", d2); - u = d1; - if (d2) - u = (d1 << 16) | d2; - break; + while (idx < n) + { + string msg = utf_decodeChar(str, idx, d1); + if (msg) + error(loc, "%.*s", cast(int)msg.length, msg.ptr); + } + if (d1 >= 0x1_0000) + error(loc, "x%x does not fit in 16 bits", d1); + t.unsvalue = d1; + t.value = TOK.wcharLiteral; // C11 6.4.4.4-9 + return; case 'U': dchar d; @@ -2035,8 +2029,9 @@ class Lexer else if (idx < n) error(loc, "max number of chars in 32 bit character literal is 1, had %d", cast(int)((n + 3) >> 2)); - u = d; - break; + t.unsvalue = d; + t.value = TOK.dcharLiteral; // C11 6.4.4.4-9 + return; default: assert(0); @@ -3270,7 +3265,7 @@ class Lexer while (1) { printf("%s ", (*tk).toChars()); - if (tk.value == TOK.endOfFile) + if (tk.value == TOK.endOfFile || tk.value == TOK.endOfLine) break; tk = peek(tk); } diff --git a/gcc/d/dmd/module.h b/gcc/d/dmd/module.h index cab0b0a..80a6ea2 100644 --- a/gcc/d/dmd/module.h +++ b/gcc/d/dmd/module.h @@ -88,7 +88,7 @@ public: Identifier *searchCacheIdent; Dsymbol *searchCacheSymbol; // cached value of search - int searchCacheFlags; // cached flags + SearchOptFlags searchCacheFlags; // cached flags d_bool insearch; // module from command line we're imported from, @@ -121,9 +121,8 @@ public: const char *kind() const override; bool read(const Loc &loc); // read file, returns 'true' if succeed, 'false' otherwise. Module *parse(); // syntactic parse - void importAll(Scope *sc) override; int needModuleInfo(); - bool isPackageAccessible(Package *p, Visibility visibility, int flags = 0) override; + bool isPackageAccessible(Package *p, Visibility visibility, SearchOptFlags flags = (SearchOptFlags)SearchOpt::all) override; Dsymbol *symtabInsert(Dsymbol *s) override; static void runDeferredSemantic(); static void runDeferredSemantic2(); diff --git a/gcc/d/dmd/mtype.d b/gcc/d/dmd/mtype.d index 8860f14..626bf74 100644 --- a/gcc/d/dmd/mtype.d +++ b/gcc/d/dmd/mtype.d @@ -19,7 +19,6 @@ import core.stdc.string; import dmd.aggregate; import dmd.arraytypes; -import dmd.attrib; import dmd.astenums; import dmd.ast_node; import dmd.gluelayer; @@ -35,7 +34,6 @@ import dmd.dsymbolsem; import dmd.dtemplate; import dmd.errors; import dmd.expression; -import dmd.expressionsem; import dmd.func; import dmd.globals; import dmd.hdrgen; @@ -522,262 +520,6 @@ extern (C++) abstract class Type : ASTNode return mcache; } - /******************************* - * Covariant means that 'this' can substitute for 't', - * i.e. a pure function is a match for an impure type. - * Params: - * t = type 'this' is covariant with - * pstc = if not null, store STCxxxx which would make it covariant - * cppCovariant = true if extern(C++) function types should follow C++ covariant rules - * Returns: - * An enum value of either `Covariant.yes` or a reason it's not covariant. - */ - final Covariant covariant(Type t, StorageClass* pstc = null, bool cppCovariant = false) - { - version (none) - { - printf("Type::covariant(t = %s) %s\n", t.toChars(), toChars()); - printf("deco = %p, %p\n", deco, t.deco); - // printf("ty = %d\n", next.ty); - printf("mod = %x, %x\n", mod, t.mod); - } - if (pstc) - *pstc = 0; - StorageClass stc = 0; - - bool notcovariant = false; - - if (equals(t)) - return Covariant.yes; - - TypeFunction t1 = this.isTypeFunction(); - TypeFunction t2 = t.isTypeFunction(); - - if (!t1 || !t2) - goto Ldistinct; - - if (t1.parameterList.varargs != t2.parameterList.varargs) - goto Ldistinct; - - if (t1.parameterList.parameters && t2.parameterList.parameters) - { - if (t1.parameterList.length != t2.parameterList.length) - goto Ldistinct; - - foreach (i, fparam1; t1.parameterList) - { - Parameter fparam2 = t2.parameterList[i]; - Type tp1 = fparam1.type; - Type tp2 = fparam2.type; - - if (!tp1.equals(tp2)) - { - if (tp1.ty == tp2.ty) - { - if (auto tc1 = tp1.isTypeClass()) - { - if (tc1.sym == (cast(TypeClass)tp2).sym && MODimplicitConv(tp2.mod, tp1.mod)) - goto Lcov; - } - else if (auto ts1 = tp1.isTypeStruct()) - { - if (ts1.sym == (cast(TypeStruct)tp2).sym && MODimplicitConv(tp2.mod, tp1.mod)) - goto Lcov; - } - else if (tp1.ty == Tpointer) - { - if (tp2.implicitConvTo(tp1)) - goto Lcov; - } - else if (tp1.ty == Tarray) - { - if (tp2.implicitConvTo(tp1)) - goto Lcov; - } - else if (tp1.ty == Tdelegate) - { - if (tp2.implicitConvTo(tp1)) - goto Lcov; - } - } - goto Ldistinct; - } - Lcov: - notcovariant |= !fparam1.isCovariant(t1.isref, fparam2); - - /* https://issues.dlang.org/show_bug.cgi?id=23135 - * extern(C++) mutable parameters are not covariant with const. - */ - if (t1.linkage == LINK.cpp && cppCovariant) - { - notcovariant |= tp1.isNaked() != tp2.isNaked(); - if (auto tpn1 = tp1.nextOf()) - notcovariant |= tpn1.isNaked() != tp2.nextOf().isNaked(); - } - } - } - else if (t1.parameterList.parameters != t2.parameterList.parameters) - { - if (t1.parameterList.length || t2.parameterList.length) - goto Ldistinct; - } - - // The argument lists match - if (notcovariant) - goto Lnotcovariant; - if (t1.linkage != t2.linkage) - goto Lnotcovariant; - - { - // Return types - Type t1n = t1.next; - Type t2n = t2.next; - - if (!t1n || !t2n) // happens with return type inference - goto Lnotcovariant; - - if (t1n.equals(t2n)) - goto Lcovariant; - if (t1n.ty == Tclass && t2n.ty == Tclass) - { - /* If same class type, but t2n is const, then it's - * covariant. Do this test first because it can work on - * forward references. - */ - if ((cast(TypeClass)t1n).sym == (cast(TypeClass)t2n).sym && MODimplicitConv(t1n.mod, t2n.mod)) - goto Lcovariant; - - // If t1n is forward referenced: - ClassDeclaration cd = (cast(TypeClass)t1n).sym; - if (cd.semanticRun < PASS.semanticdone && !cd.isBaseInfoComplete()) - cd.dsymbolSemantic(null); - if (!cd.isBaseInfoComplete()) - { - return Covariant.fwdref; - } - } - if (t1n.ty == Tstruct && t2n.ty == Tstruct) - { - if ((cast(TypeStruct)t1n).sym == (cast(TypeStruct)t2n).sym && MODimplicitConv(t1n.mod, t2n.mod)) - goto Lcovariant; - } - else if (t1n.ty == t2n.ty && t1n.implicitConvTo(t2n)) - { - if (t1.isref && t2.isref) - { - // Treat like pointers to t1n and t2n - if (t1n.constConv(t2n) < MATCH.constant) - goto Lnotcovariant; - } - goto Lcovariant; - } - else if (t1n.ty == Tnull) - { - // NULL is covariant with any pointer type, but not with any - // dynamic arrays, associative arrays or delegates. - // https://issues.dlang.org/show_bug.cgi?id=8589 - // https://issues.dlang.org/show_bug.cgi?id=19618 - Type t2bn = t2n.toBasetype(); - if (t2bn.ty == Tnull || t2bn.ty == Tpointer || t2bn.ty == Tclass) - goto Lcovariant; - } - // bottom type is covariant to any type - else if (t1n.ty == Tnoreturn) - goto Lcovariant; - } - goto Lnotcovariant; - - Lcovariant: - if (t1.isref != t2.isref) - goto Lnotcovariant; - - if (!t1.isref && (t1.isScopeQual || t2.isScopeQual)) - { - StorageClass stc1 = t1.isScopeQual ? STC.scope_ : 0; - StorageClass stc2 = t2.isScopeQual ? STC.scope_ : 0; - if (t1.isreturn) - { - stc1 |= STC.return_; - if (!t1.isScopeQual) - stc1 |= STC.ref_; - } - if (t2.isreturn) - { - stc2 |= STC.return_; - if (!t2.isScopeQual) - stc2 |= STC.ref_; - } - if (!Parameter.isCovariantScope(t1.isref, stc1, stc2)) - goto Lnotcovariant; - } - - // We can subtract 'return ref' from 'this', but cannot add it - else if (t1.isreturn && !t2.isreturn) - goto Lnotcovariant; - - /* https://issues.dlang.org/show_bug.cgi?id=23135 - * extern(C++) mutable member functions are not covariant with const. - */ - if (t1.linkage == LINK.cpp && cppCovariant && t1.isNaked() != t2.isNaked()) - goto Lnotcovariant; - - /* Can convert mutable to const - */ - if (!MODimplicitConv(t2.mod, t1.mod)) - { - version (none) - { - //stop attribute inference with const - // If adding 'const' will make it covariant - if (MODimplicitConv(t2.mod, MODmerge(t1.mod, MODFlags.const_))) - stc |= STC.const_; - else - goto Lnotcovariant; - } - else - { - goto Ldistinct; - } - } - - /* Can convert pure to impure, nothrow to throw, and nogc to gc - */ - if (!t1.purity && t2.purity) - stc |= STC.pure_; - - if (!t1.isnothrow && t2.isnothrow) - stc |= STC.nothrow_; - - if (!t1.isnogc && t2.isnogc) - stc |= STC.nogc; - - /* Can convert safe/trusted to system - */ - if (t1.trust <= TRUST.system && t2.trust >= TRUST.trusted) - { - // Should we infer trusted or safe? Go with safe. - stc |= STC.safe; - } - - if (stc) - { - if (pstc) - *pstc = stc; - goto Lnotcovariant; - } - - //printf("\tcovaraint: 1\n"); - return Covariant.yes; - - Ldistinct: - //printf("\tcovaraint: 0\n"); - return Covariant.distinct; - - Lnotcovariant: - //printf("\tcovaraint: 2\n"); - return Covariant.no; - } - /******************************** * For pretty-printing a type. */ @@ -1061,17 +803,6 @@ extern (C++) abstract class Type : ASTNode return isscalar(); } - /********************************* - * Check type to see if it is based on a deprecated symbol. - */ - void checkDeprecated(const ref Loc loc, Scope* sc) - { - if (Dsymbol s = toDsymbol(sc)) - { - s.checkDeprecated(loc, sc); - } - } - final bool isConst() const nothrow pure @nogc @safe { return (mod & MODFlags.const_) != 0; @@ -2825,13 +2556,6 @@ extern (C++) abstract class TypeNext : Type this.next = next; } - override final void checkDeprecated(const ref Loc loc, Scope* sc) - { - Type.checkDeprecated(loc, sc); - if (next) // next can be NULL if TypeFunction and auto return type - next.checkDeprecated(loc, sc); - } - override final int hasWild() const { if (ty == Tfunction) @@ -4612,27 +4336,7 @@ extern (C++) final class TypeFunction : TypeNext return t.merge(); } - // arguments get specially formatted - private const(char)* getParamError(Expression arg, Parameter par) - { - if (global.gag && !global.params.v.showGaggedErrors) - return null; - // show qualification when toChars() is the same but types are different - // https://issues.dlang.org/show_bug.cgi?id=19948 - // when comparing the type with strcmp, we need to drop the qualifier - bool qual = !arg.type.mutableOf().equals(par.type.mutableOf()) && - strcmp(arg.type.mutableOf().toChars(), par.type.mutableOf().toChars()) == 0; - auto at = qual ? arg.type.toPrettyChars(true) : arg.type.toChars(); - OutBuffer buf; - // only mention rvalue if it's relevant - const rv = !arg.isLvalue() && par.isReference(); - buf.printf("cannot pass %sargument `%s` of type `%s` to parameter `%s`", - rv ? "rvalue ".ptr : "".ptr, arg.toChars(), at, - parameterToChars(par, this, qual)); - return buf.extractChars(); - } - - private extern(D) const(char)* getMatchError(A...)(const(char)* format, A args) + extern(D) static const(char)* getMatchError(A...)(const(char)* format, A args) { if (global.gag && !global.params.v.showGaggedErrors) return null; @@ -4642,185 +4346,6 @@ extern (C++) final class TypeFunction : TypeNext } /******************************** - * 'args' are being matched to function 'this' - * Determine match level. - * Params: - * tthis = type of `this` pointer, null if not member function - * argumentList = arguments to function call - * flag = 1: performing a partial ordering match - * pMessage = address to store error message, or null - * sc = context - * Returns: - * MATCHxxxx - */ - extern (D) MATCH callMatch(Type tthis, ArgumentList argumentList, int flag = 0, const(char)** pMessage = null, Scope* sc = null) - { - //printf("TypeFunction::callMatch() %s\n", toChars()); - MATCH match = MATCH.exact; // assume exact match - ubyte wildmatch = 0; - - if (tthis) - { - Type t = tthis; - if (t.toBasetype().ty == Tpointer) - t = t.toBasetype().nextOf(); // change struct* to struct - if (t.mod != mod) - { - if (MODimplicitConv(t.mod, mod)) - match = MATCH.constant; - else if ((mod & MODFlags.wild) && MODimplicitConv(t.mod, (mod & ~MODFlags.wild) | MODFlags.const_)) - { - match = MATCH.constant; - } - else - return MATCH.nomatch; - } - if (isWild()) - { - if (t.isWild()) - wildmatch |= MODFlags.wild; - else if (t.isConst()) - wildmatch |= MODFlags.const_; - else if (t.isImmutable()) - wildmatch |= MODFlags.immutable_; - else - wildmatch |= MODFlags.mutable; - } - } - - const nparams = parameterList.length; - if (argumentList.length > nparams) - { - if (parameterList.varargs == VarArg.none) - { - // suppress early exit if an error message is wanted, - // so we can check any matching args are valid - if (!pMessage) - return MATCH.nomatch; - } - // too many args; no match - match = MATCH.convert; // match ... with a "conversion" match level - } - - // https://issues.dlang.org/show_bug.cgi?id=22997 - if (parameterList.varargs == VarArg.none && nparams > argumentList.length && !parameterList.hasDefaultArgs) - { - OutBuffer buf; - buf.printf("too few arguments, expected %d, got %d", cast(int)nparams, cast(int)argumentList.length); - if (pMessage) - *pMessage = buf.extractChars(); - return MATCH.nomatch; - } - auto resolvedArgs = resolveNamedArgs(argumentList, pMessage); - Expression[] args; - if (!resolvedArgs) - { - if (!pMessage || *pMessage) - return MATCH.nomatch; - - // if no message was provided, it was because of overflow which will be diagnosed below - match = MATCH.nomatch; - args = argumentList.arguments ? (*argumentList.arguments)[] : null; - } - else - { - args = (*resolvedArgs)[]; - } - - foreach (u, p; parameterList) - { - if (u >= args.length) - break; - - Expression arg = args[u]; - if (!arg) - continue; // default argument - - Type tprm = p.type; - Type targ = arg.type; - - if (!(p.isLazy() && tprm.ty == Tvoid && targ.ty != Tvoid)) - { - const isRef = p.isReference(); - wildmatch |= targ.deduceWild(tprm, isRef); - } - } - if (wildmatch) - { - /* Calculate wild matching modifier - */ - if (wildmatch & MODFlags.const_ || wildmatch & (wildmatch - 1)) - wildmatch = MODFlags.const_; - else if (wildmatch & MODFlags.immutable_) - wildmatch = MODFlags.immutable_; - else if (wildmatch & MODFlags.wild) - wildmatch = MODFlags.wild; - else - { - assert(wildmatch & MODFlags.mutable); - wildmatch = MODFlags.mutable; - } - } - - foreach (u, p; parameterList) - { - MATCH m; - - assert(p); - - // One or more arguments remain - if (u < args.length) - { - Expression arg = args[u]; - if (!arg) - continue; // default argument - m = argumentMatchParameter(this, p, arg, wildmatch, flag, sc, pMessage); - } - else if (p.defaultArg) - continue; - - /* prefer matching the element type rather than the array - * type when more arguments are present with T[]... - */ - if (parameterList.varargs == VarArg.typesafe && u + 1 == nparams && args.length > nparams) - goto L1; - - //printf("\tm = %d\n", m); - if (m == MATCH.nomatch) // if no match - { - L1: - if (parameterList.varargs == VarArg.typesafe && u + 1 == nparams) // if last varargs param - { - auto trailingArgs = args[u .. $]; - if (auto vmatch = matchTypeSafeVarArgs(this, p, trailingArgs, pMessage)) - return vmatch < match ? vmatch : match; - // Error message was already generated in `matchTypeSafeVarArgs` - return MATCH.nomatch; - } - if (pMessage && u >= args.length) - *pMessage = getMatchError("missing argument for parameter #%d: `%s`", - u + 1, parameterToChars(p, this, false)); - // If an error happened previously, `pMessage` was already filled - else if (pMessage && !*pMessage) - *pMessage = getParamError(args[u], p); - - return MATCH.nomatch; - } - if (m < match) - match = m; // pick worst match - } - - if (pMessage && !parameterList.varargs && args.length > nparams) - { - // all parameters had a match, but there are surplus args - *pMessage = getMatchError("expected %d argument(s), not %d", nparams, args.length); - return MATCH.nomatch; - } - //printf("match = %d\n", match); - return match; - } - - /******************************** * Convert an `argumentList`, which may contain named arguments, into * a list of arguments in the order of the parameter list. * @@ -6935,7 +6460,7 @@ extern (C++) final class Parameter : ASTNode return isCovariantScope(returnByRef, thisSTC, otherSTC); } - extern (D) private static bool isCovariantScope(bool returnByRef, StorageClass from, StorageClass to) pure nothrow @nogc @safe + extern (D) static bool isCovariantScope(bool returnByRef, StorageClass from, StorageClass to) pure nothrow @nogc @safe { // Workaround for failing covariance when finding a common type of delegates, // some of which have parameters with inferred scope @@ -7235,328 +6760,6 @@ const(char)* toChars(ScopeRef sr) pure nothrow @nogc @safe } /** - * Used by `callMatch` to check if the copy constructor may be called to - * copy the argument - * - * This is done by seeing if a call to the copy constructor can be made: - * ``` - * typeof(tprm) __copytmp; - * copytmp.__copyCtor(arg); - * ``` - */ -private extern(D) bool isCopyConstructorCallable (StructDeclaration argStruct, - Expression arg, Type tprm, Scope* sc, const(char)** pMessage) -{ - auto tmp = new VarDeclaration(arg.loc, tprm, Identifier.generateId("__copytmp"), null); - tmp.storage_class = STC.rvalue | STC.temp | STC.ctfe; - tmp.dsymbolSemantic(sc); - Expression ve = new VarExp(arg.loc, tmp); - Expression e = new DotIdExp(arg.loc, ve, Id.ctor); - e = new CallExp(arg.loc, e, arg); - //printf("e = %s\n", e.toChars()); - if (.trySemantic(e, sc)) - return true; - - if (pMessage) - { - /* https://issues.dlang.org/show_bug.cgi?id=22202 - * - * If a function was deduced by semantic on the CallExp, - * it means that resolveFuncCall completed succesfully. - * Therefore, there exists a callable copy constructor, - * however, it cannot be called because scope constraints - * such as purity, safety or nogc. - */ - OutBuffer buf; - auto callExp = e.isCallExp(); - if (auto f = callExp.f) - { - char[] s; - if (!f.isPure && sc.func.setImpure()) - s ~= "pure "; - if (!f.isSafe() && !f.isTrusted() && sc.setUnsafe()) - s ~= "@safe "; - if (!f.isNogc && sc.func.setGC(arg.loc, null)) - s ~= "nogc "; - if (s) - { - s[$-1] = '\0'; - buf.printf("`%s` copy constructor cannot be called from a `%s` context", f.type.toChars(), s.ptr); - } - else if (f.isGenerated() && f.isDisabled()) - { - /* https://issues.dlang.org/show_bug.cgi?id=23097 - * Compiler generated copy constructor failed. - */ - buf.printf("generating a copy constructor for `struct %s` failed, therefore instances of it are uncopyable", - argStruct.toChars()); - } - else - { - /* Although a copy constructor may exist, no suitable match was found. - * i.e: `inout` constructor creates `const` object, not mutable. - * Fallback to using the original generic error before https://issues.dlang.org/show_bug.cgi?id=22202. - */ - goto Lnocpctor; - } - } - else - { - Lnocpctor: - buf.printf("`struct %s` does not define a copy constructor for `%s` to `%s` copies", - argStruct.toChars(), arg.type.toChars(), tprm.toChars()); - } - - *pMessage = buf.extractChars(); - } - return false; -} - -/** - * Match a single parameter to an argument. - * - * This function is called by `TypeFunction.callMatch` while iterating over - * the list of parameter. Here we check if `arg` is a match for `p`, - * which is mostly about checking if `arg.type` converts to `p`'s type - * and some check about value reference. - * - * Params: - * tf = The `TypeFunction`, only used for error reporting - * p = The parameter of `tf` being matched - * arg = Argument being passed (bound) to `p` - * wildmatch = Wild (`inout`) matching level, derived from the full argument list - * flag = A non-zero value means we're doing a partial ordering check - * (no value semantic check) - * sc = Scope we are in - * pMessage = A buffer to write the error in, or `null` - * - * Returns: Whether `trailingArgs` match `p`. - */ -private extern(D) MATCH argumentMatchParameter (TypeFunction tf, Parameter p, - Expression arg, ubyte wildmatch, int flag, Scope* sc, const(char)** pMessage) -{ - //printf("arg: %s, type: %s\n", arg.toChars(), arg.type.toChars()); - MATCH m; - Type targ = arg.type; - Type tprm = wildmatch ? p.type.substWildTo(wildmatch) : p.type; - - if (p.isLazy() && tprm.ty == Tvoid && targ.ty != Tvoid) - m = MATCH.convert; - else if (flag) - { - // for partial ordering, value is an irrelevant mockup, just look at the type - m = targ.implicitConvTo(tprm); - } - else - { - const isRef = p.isReference(); - StructDeclaration argStruct, prmStruct; - - // first look for a copy constructor - if (arg.isLvalue() && !isRef && targ.ty == Tstruct && tprm.ty == Tstruct) - { - // if the argument and the parameter are of the same unqualified struct type - argStruct = (cast(TypeStruct)targ).sym; - prmStruct = (cast(TypeStruct)tprm).sym; - } - - // check if the copy constructor may be called to copy the argument - if (argStruct && argStruct == prmStruct && argStruct.hasCopyCtor) - { - if (!isCopyConstructorCallable(argStruct, arg, tprm, sc, pMessage)) - return MATCH.nomatch; - m = MATCH.exact; - } - else - { - import dmd.dcast : cimplicitConvTo; - m = (sc && sc.flags & SCOPE.Cfile) ? arg.cimplicitConvTo(tprm) : arg.implicitConvTo(tprm); - } - } - - // Non-lvalues do not match ref or out parameters - if (p.isReference()) - { - // https://issues.dlang.org/show_bug.cgi?id=13783 - // Don't use toBasetype() to handle enum types. - Type ta = targ; - Type tp = tprm; - //printf("fparam[%d] ta = %s, tp = %s\n", u, ta.toChars(), tp.toChars()); - - if (m && !arg.isLvalue()) - { - if (p.storageClass & STC.out_) - { - if (pMessage) *pMessage = tf.getParamError(arg, p); - return MATCH.nomatch; - } - - if (arg.op == EXP.string_ && tp.ty == Tsarray) - { - if (ta.ty != Tsarray) - { - Type tn = tp.nextOf().castMod(ta.nextOf().mod); - dinteger_t dim = (cast(StringExp)arg).len; - ta = tn.sarrayOf(dim); - } - } - else if (arg.op == EXP.slice && tp.ty == Tsarray) - { - // Allow conversion from T[lwr .. upr] to ref T[upr-lwr] - if (ta.ty != Tsarray) - { - Type tn = ta.nextOf(); - dinteger_t dim = (cast(TypeSArray)tp).dim.toUInteger(); - ta = tn.sarrayOf(dim); - } - } - else if ((p.storageClass & STC.in_) && global.params.previewIn) - { - // Allow converting a literal to an `in` which is `ref` - if (arg.op == EXP.arrayLiteral && tp.ty == Tsarray) - { - Type tn = tp.nextOf(); - dinteger_t dim = (cast(TypeSArray)tp).dim.toUInteger(); - ta = tn.sarrayOf(dim); - } - - // Need to make this a rvalue through a temporary - m = MATCH.convert; - } - else if (global.params.rvalueRefParam != FeatureState.enabled || - p.storageClass & STC.out_ || - !arg.type.isCopyable()) // can't copy to temp for ref parameter - { - if (pMessage) *pMessage = tf.getParamError(arg, p); - return MATCH.nomatch; - } - else - { - /* in functionParameters() we'll convert this - * rvalue into a temporary - */ - m = MATCH.convert; - } - } - - /* If the match is not already perfect or if the arg - is not a lvalue then try the `alias this` chain - see https://issues.dlang.org/show_bug.cgi?id=15674 - and https://issues.dlang.org/show_bug.cgi?id=21905 - */ - if (ta != tp || !arg.isLvalue()) - { - Type firsttab = ta.toBasetype(); - while (1) - { - Type tab = ta.toBasetype(); - Type tat = tab.aliasthisOf(); - if (!tat || !tat.implicitConvTo(tprm)) - break; - if (tat == tab || tat == firsttab) - break; - ta = tat; - } - } - - /* A ref variable should work like a head-const reference. - * e.g. disallows: - * ref T <- an lvalue of const(T) argument - * ref T[dim] <- an lvalue of const(T[dim]) argument - */ - if (!ta.constConv(tp)) - { - if (pMessage) *pMessage = tf.getParamError(arg, p); - return MATCH.nomatch; - } - } - return m; -} - -/** - * Match the remaining arguments `trailingArgs` with parameter `p`. - * - * Assume we already checked that `p` is the last parameter of `tf`, - * and we want to know whether the arguments would match `p`. - * - * Params: - * tf = The `TypeFunction`, only used for error reporting - * p = The last parameter of `tf` which is variadic - * trailingArgs = The remaining arguments that should match `p` - * pMessage = A buffer to write the error in, or `null` - * - * Returns: Whether `trailingArgs` match `p`. - */ -private extern(D) MATCH matchTypeSafeVarArgs(TypeFunction tf, Parameter p, - Expression[] trailingArgs, const(char)** pMessage) -{ - Type tb = p.type.toBasetype(); - - switch (tb.ty) - { - case Tsarray: - TypeSArray tsa = cast(TypeSArray)tb; - dinteger_t sz = tsa.dim.toInteger(); - if (sz != trailingArgs.length) - { - if (pMessage) - *pMessage = tf.getMatchError("expected %llu variadic argument(s), not %zu", - sz, trailingArgs.length); - return MATCH.nomatch; - } - goto case Tarray; - case Tarray: - { - MATCH match = MATCH.exact; - TypeArray ta = cast(TypeArray)tb; - foreach (arg; trailingArgs) - { - MATCH m; - assert(arg); - - /* If lazy array of delegates, - * convert arg(s) to delegate(s) - */ - Type tret = p.isLazyArray(); - if (tret) - { - if (ta.next.equals(arg.type)) - m = MATCH.exact; - else if (tret.toBasetype().ty == Tvoid) - m = MATCH.convert; - else - { - m = arg.implicitConvTo(tret); - if (m == MATCH.nomatch) - m = arg.implicitConvTo(ta.next); - } - } - else - m = arg.implicitConvTo(ta.next); - - if (m == MATCH.nomatch) - { - if (pMessage) *pMessage = tf.getParamError(arg, p); - return MATCH.nomatch; - } - if (m < match) - match = m; - } - return match; - } - case Tclass: - // We leave it up to the actual constructor call to do the matching. - return MATCH.exact; - - default: - // We can have things as `foo(int[int] wat...)` but they only match - // with an associative array proper. - if (pMessage && trailingArgs.length) *pMessage = tf.getParamError(trailingArgs[0], p); - return MATCH.nomatch; - } -} - -/** * Creates an appropriate vector type for `tv` that will hold one boolean * result for each element of the vector type. The result of vector comparisons * is a single or doubleword mask of all 1s (comparison true) or all 0s @@ -7738,3 +6941,36 @@ TypeIdentifier getException() tid.addIdent(Id.Exception); return tid; } + +/************************************** + * Check and set 'att' if 't' is a recursive 'alias this' type + * + * The goal is to prevent endless loops when there is a cycle in the alias this chain. + * Since there is no multiple `alias this`, the chain either ends in a leaf, + * or it loops back on itself as some point. + * + * Example: S0 -> (S1 -> S2 -> S3 -> S1) + * + * `S0` is not a recursive alias this, so this returns `false`, and a rewrite to `S1` can be tried. + * `S1` is a recursive alias this type, but since `att` is initialized to `null`, + * this still returns `false`, but `att1` is set to `S1`. + * A rewrite to `S2` and `S3` can be tried, but when we want to try a rewrite to `S1` again, + * we notice `att == t`, so we're back at the start of the loop, and this returns `true`. + * + * Params: + * att = type reference used to detect recursion. Should be initialized to `null`. + * t = type of 'alias this' rewrite to attempt + * + * Returns: + * `false` if the rewrite is safe, `true` if it would loop back around + */ +bool isRecursiveAliasThis(ref Type att, Type t) +{ + //printf("+isRecursiveAliasThis(att = %s, t = %s)\n", att ? att.toChars() : "null", t.toChars()); + auto tb = t.toBasetype(); + if (att && tb.equivalent(att)) + return true; + else if (!att && tb.checkAliasThisRec()) + att = tb; + return false; +} diff --git a/gcc/d/dmd/mtype.h b/gcc/d/dmd/mtype.h index 675e944..ef1ce10 100644 --- a/gcc/d/dmd/mtype.h +++ b/gcc/d/dmd/mtype.h @@ -225,7 +225,6 @@ public: // kludge for template.isType() DYNCAST dyncast() const override final { return DYNCAST_TYPE; } size_t getUniqueID() const; - Covariant covariant(Type *, StorageClass * = NULL, bool = false); const char *toChars() const override; char *toPrettyChars(bool QualifyTypes = false); static void _init(); @@ -249,7 +248,6 @@ public: virtual bool isString(); virtual bool isAssignable(); virtual bool isBoolean(); - virtual void checkDeprecated(const Loc &loc, Scope *sc); bool isConst() const { return (mod & MODconst) != 0; } bool isImmutable() const { return (mod & MODimmutable) != 0; } bool isMutable() const { return (mod & (MODconst | MODimmutable | MODwild)) == 0; } @@ -364,7 +362,6 @@ class TypeNext : public Type public: Type *next; - void checkDeprecated(const Loc &loc, Scope *sc) override final; int hasWild() const override final; Type *nextOf() override final; Type *makeConst() override final; @@ -929,3 +926,4 @@ public: // If the type is a class or struct, returns the symbol for it, else null. AggregateDeclaration *isAggregate(Type *t); +Covariant covariant(Type *, Type *, StorageClass * = NULL, bool = false); diff --git a/gcc/d/dmd/nspace.d b/gcc/d/dmd/nspace.d index 22c6e63..65f7d29 100644 --- a/gcc/d/dmd/nspace.d +++ b/gcc/d/dmd/nspace.d @@ -46,22 +46,14 @@ module dmd.nspace; -import dmd.aggregate; import dmd.arraytypes; -import dmd.astenums; -import dmd.dscope; import dmd.dsymbol; -import dmd.dsymbolsem; -import dmd.errors; import dmd.expression; -import dmd.globals; import dmd.identifier; import dmd.location; import dmd.visitor; import core.stdc.stdio; -private enum LOG = false; - /// Ditto extern (C++) final class Nspace : ScopeDsymbol { @@ -91,14 +83,6 @@ extern (C++) final class Nspace : ScopeDsymbol return members.foreachDsymbol( (s) { return s.hasPointers(); } ) != 0; } - override void setFieldOffset(AggregateDeclaration ad, ref FieldState fieldState, bool isunion) - { - //printf("Nspace::setFieldOffset() %s\n", toChars()); - if (_scope) // if fwd reference - dsymbolSemantic(this, null); // try to resolve it - members.foreachDsymbol( s => s.setFieldOffset(ad, fieldState, isunion) ); - } - override const(char)* kind() const { return "namespace"; diff --git a/gcc/d/dmd/nspace.h b/gcc/d/dmd/nspace.h index 701cc93..4a1bd91 100644 --- a/gcc/d/dmd/nspace.h +++ b/gcc/d/dmd/nspace.h @@ -22,7 +22,6 @@ class Nspace final : public ScopeDsymbol Expression *identExp; Nspace *syntaxCopy(Dsymbol *s) override; bool hasPointers() override; - void setFieldOffset(AggregateDeclaration *ad, FieldState& fieldState, bool isunion) override; const char *kind() const override; Nspace *isNspace() override { return this; } void accept(Visitor *v) override { v->visit(this); } diff --git a/gcc/d/dmd/scope.h b/gcc/d/dmd/scope.h index 2cac5f2..cceb5a7 100644 --- a/gcc/d/dmd/scope.h +++ b/gcc/d/dmd/scope.h @@ -130,5 +130,5 @@ struct Scope AliasDeclaration *aliasAsg; // if set, then aliasAsg is being assigned a new value, // do not set wasRead for it - Dsymbol *search(const Loc &loc, Identifier *ident, Dsymbol **pscopesym, int flags = IgnoreNone); + Dsymbol *search(const Loc &loc, Identifier *ident, Dsymbol **pscopesym, SearchOptFlags flags = (SearchOptFlags)SearchOpt::all); }; diff --git a/gcc/d/dmd/semantic3.d b/gcc/d/dmd/semantic3.d index c255701..7498eaf 100644 --- a/gcc/d/dmd/semantic3.d +++ b/gcc/d/dmd/semantic3.d @@ -520,7 +520,8 @@ private extern(C++) final class Semantic3Visitor : Visitor { Parameter narg = Parameter.getNth(t.arguments, j); assert(narg.ident); - VarDeclaration v = sc2.search(Loc.initial, narg.ident, null).isVarDeclaration(); + Dsymbol pscopesym; + VarDeclaration v = sc2.search(Loc.initial, narg.ident, pscopesym).isVarDeclaration(); assert(v); (*exps)[j] = new VarExp(v.loc, v); } diff --git a/gcc/d/dmd/statement.d b/gcc/d/dmd/statement.d index b5906c8..4304544 100644 --- a/gcc/d/dmd/statement.d +++ b/gcc/d/dmd/statement.d @@ -20,19 +20,15 @@ import dmd.arraytypes; import dmd.astenums; import dmd.ast_node; import dmd.errors; -import dmd.gluelayer; import dmd.cond; import dmd.declaration; import dmd.dsymbol; import dmd.expression; import dmd.func; -import dmd.globals; -import dmd.hdrgen; import dmd.id; import dmd.identifier; import dmd.location; import dmd.mtype; -import dmd.common.outbuffer; import dmd.rootobject; import dmd.sapply; import dmd.staticassert; @@ -333,6 +329,8 @@ extern (C++) final class ErrorStatement : Statement extern (D) this() { super(Loc.initial, STMT.Error); + + import dmd.globals; assert(global.gaggedErrors || global.errors); } @@ -1773,7 +1771,7 @@ extern (C++) class AsmStatement : Statement */ extern (C++) final class InlineAsmStatement : AsmStatement { - code* asmcode; + void* asmcode; uint asmalign; // alignment of this statement uint regs; // mask of registers modified (must match regm_t in back end) bool refparam; // true if function parameter is referenced diff --git a/gcc/d/dmd/statement.h b/gcc/d/dmd/statement.h index ef8423f..1e493f0 100644 --- a/gcc/d/dmd/statement.h +++ b/gcc/d/dmd/statement.h @@ -716,7 +716,7 @@ public: class InlineAsmStatement final : public AsmStatement { public: - code *asmcode; + void *asmcode; unsigned asmalign; // alignment of this statement unsigned regs; // mask of registers modified (must match regm_t in back end) d_bool refparam; // true if function parameter is referenced diff --git a/gcc/d/dmd/statementsem.d b/gcc/d/dmd/statementsem.d index 3873adc..fcc606b 100644 --- a/gcc/d/dmd/statementsem.d +++ b/gcc/d/dmd/statementsem.d @@ -2261,7 +2261,8 @@ Statement statementSemanticVisit(Statement s, Scope* sc) continue; assert(scx.sw == sw); - if (!scx.search(cs.exp.loc, v.ident, null)) + Dsymbol pscopesym; + if (!scx.search(cs.exp.loc, v.ident, pscopesym)) { error(cs.loc, "`case` variable `%s` declared at %s cannot be declared in `switch` body", v.toChars(), v.loc.toChars()); @@ -2525,10 +2526,9 @@ Statement statementSemanticVisit(Statement s, Scope* sc) if (fd.fes) fd = fd.fes.func; // fd is now function enclosing foreach - TypeFunction tf = cast(TypeFunction)fd.type; - assert(tf.ty == Tfunction); + auto tf = fd.type.isTypeFunction(); - if (rs.exp && rs.exp.op == EXP.variable && (cast(VarExp)rs.exp).var == fd.vresult) + if (rs.exp && rs.exp.isVarExp() && rs.exp.isVarExp().var == fd.vresult) { // return vresult; if (sc.fes) @@ -2616,7 +2616,7 @@ Statement statementSemanticVisit(Statement s, Scope* sc) rs.exp.checkSharedAccess(sc, returnSharedRef); // for static alias this: https://issues.dlang.org/show_bug.cgi?id=17684 - if (rs.exp.op == EXP.type) + if (rs.exp.isTypeExp()) rs.exp = resolveAliasThis(sc, rs.exp); rs.exp = resolveProperties(sc, rs.exp); @@ -2632,14 +2632,14 @@ Statement statementSemanticVisit(Statement s, Scope* sc) // Extract side-effect part rs.exp = Expression.extractLast(rs.exp, e0); - if (rs.exp.op == EXP.call) + if (rs.exp.isCallExp()) rs.exp = valueNoDtor(rs.exp); /* Void-return function can have void / noreturn typed expression * on return statement. */ auto texp = rs.exp.type; - const convToVoid = texp.ty == Tvoid || texp.ty == Tnoreturn; + const convToVoid = texp.ty == Tvoid || texp.isTypeNoreturn(); if (tbret && tbret.ty == Tvoid || convToVoid) { @@ -2688,7 +2688,7 @@ Statement statementSemanticVisit(Statement s, Scope* sc) { tf.next = rs.exp.type; } - else if (tret.ty != Terror && !rs.exp.type.equals(tret)) + else if (!tret.isTypeError() && !rs.exp.type.equals(tret)) { int m1 = rs.exp.type.implicitConvTo(tret); int m2 = tret.implicitConvTo(rs.exp.type); @@ -2789,7 +2789,7 @@ Statement statementSemanticVisit(Statement s, Scope* sc) // Found an actual return value before else if (tf.next.ty != Tvoid && !resType.toBasetype().isTypeNoreturn()) { - if (tf.next.ty != Terror) + if (!tf.next.isTypeError()) { error(rs.loc, "mismatched function return type inference of `void` and `%s`", tf.next.toChars()); } @@ -2807,7 +2807,7 @@ Statement statementSemanticVisit(Statement s, Scope* sc) if (tbret.ty != Tvoid && !resType.isTypeNoreturn()) // if non-void return { - if (tbret.ty != Terror) + if (!tbret.isTypeError()) { if (e0) error(rs.loc, "expected return type of `%s`, not `%s`", tret.toChars(), resType.toChars()); @@ -2901,7 +2901,7 @@ Statement statementSemanticVisit(Statement s, Scope* sc) } if (e0) { - if (e0.op == EXP.declaration || e0.op == EXP.comma) + if (e0.isDeclarationExp() || e0.isCommaExp()) { rs.exp = Expression.combine(e0, rs.exp); } diff --git a/gcc/d/dmd/staticassert.d b/gcc/d/dmd/staticassert.d index 7f22c4c..760c66a 100644 --- a/gcc/d/dmd/staticassert.d +++ b/gcc/d/dmd/staticassert.d @@ -14,14 +14,11 @@ module dmd.staticassert; import dmd.arraytypes; -import dmd.dscope; import dmd.dsymbol; import dmd.expression; -import dmd.globals; import dmd.location; import dmd.id; import dmd.identifier; -import dmd.mtype; import dmd.visitor; /*********************************************************** diff --git a/gcc/d/dmd/template.h b/gcc/d/dmd/template.h index 44f95ec..4be1361 100644 --- a/gcc/d/dmd/template.h +++ b/gcc/d/dmd/template.h @@ -311,7 +311,6 @@ public: const char *kind() const override; bool oneMember(Dsymbol **ps, Identifier *ident) override; bool hasPointers() override; - void setFieldOffset(AggregateDeclaration *ad, FieldState& fieldState, bool isunion) override; const char *toChars() const override; TemplateMixin *isTemplateMixin() override { return this; } diff --git a/gcc/d/dmd/traits.d b/gcc/d/dmd/traits.d index 0acadbb..aebc0b5 100644 --- a/gcc/d/dmd/traits.d +++ b/gcc/d/dmd/traits.d @@ -1665,12 +1665,12 @@ Expression semanticTraits(TraitsExp e, Scope* sc) } else if (auto ed = sm.isEnumDeclaration()) { - ScopeDsymbol._foreach(null, ed.members, &pushIdentsDg); + _foreach(null, ed.members, &pushIdentsDg); } return 0; } - ScopeDsymbol._foreach(sc, sds.members, &pushIdentsDg); + _foreach(sc, sds.members, &pushIdentsDg); auto cd = sds.isClassDeclaration(); if (cd && e.ident == Id.allMembers) { @@ -1684,7 +1684,7 @@ Expression semanticTraits(TraitsExp e, Scope* sc) { auto cb = (*cd.baseclasses)[i].sym; assert(cb); - ScopeDsymbol._foreach(null, cb.members, &pushIdentsDg); + _foreach(null, cb.members, &pushIdentsDg); if (cb.baseclasses.length) pushBaseMembersDg(cb); } diff --git a/gcc/d/dmd/typesem.d b/gcc/d/dmd/typesem.d index 2063a95..b0e45f4 100644 --- a/gcc/d/dmd/typesem.d +++ b/gcc/d/dmd/typesem.d @@ -228,7 +228,7 @@ private void resolveHelper(TypeQualified mt, const ref Loc loc, Scope* sc, Dsymb Type t = s.getType(); // type symbol, type alias, or type tuple? uint errorsave = global.errors; - int flags = t is null ? SearchLocalsOnly : IgnorePrivateImports; + SearchOptFlags flags = t is null ? SearchOpt.localsOnly : SearchOpt.ignorePrivateImports; Dsymbol sm = s.searchX(loc, sc, id, flags); if (sm) @@ -380,12 +380,12 @@ private void resolveHelper(TypeQualified mt, const ref Loc loc, Scope* sc, Dsymb * loc = location to print the error messages * sc = the scope where the symbol is located * id = the id of the symbol - * flags = the search flags which can be `SearchLocalsOnly` or `IgnorePrivateImports` + * flags = the search flags which can be `SearchLocalsOnly` or `SearchOpt.ignorePrivateImports` * * Returns: * symbol found, NULL if not */ -private Dsymbol searchX(Dsymbol dsym, const ref Loc loc, Scope* sc, RootObject id, int flags) +private Dsymbol searchX(Dsymbol dsym, const ref Loc loc, Scope* sc, RootObject id, SearchOptFlags flags) { //printf("Dsymbol::searchX(this=%p,%s, ident='%s')\n", this, toChars(), ident.toChars()); Dsymbol s = dsym.toAlias(); @@ -486,6 +486,529 @@ Expression typeToExpression(Type t) } } +/******************************** + * 'args' are being matched to function type 'tf' + * Determine match level. + * Params: + * tf = function type + * tthis = type of `this` pointer, null if not member function + * argumentList = arguments to function call + * flag = 1: performing a partial ordering match + * pMessage = address to store error message, or null + * sc = context + * Returns: + * MATCHxxxx + */ +extern (D) MATCH callMatch(TypeFunction tf, Type tthis, ArgumentList argumentList, int flag = 0, const(char)** pMessage = null, Scope* sc = null) +{ + //printf("TypeFunction::callMatch() %s\n", tf.toChars()); + MATCH match = MATCH.exact; // assume exact match + ubyte wildmatch = 0; + + if (tthis) + { + Type t = tthis; + if (t.toBasetype().ty == Tpointer) + t = t.toBasetype().nextOf(); // change struct* to struct + if (t.mod != tf.mod) + { + if (MODimplicitConv(t.mod, tf.mod)) + match = MATCH.constant; + else if ((tf.mod & MODFlags.wild) && MODimplicitConv(t.mod, (tf.mod & ~MODFlags.wild) | MODFlags.const_)) + { + match = MATCH.constant; + } + else + return MATCH.nomatch; + } + if (tf.isWild()) + { + if (t.isWild()) + wildmatch |= MODFlags.wild; + else if (t.isConst()) + wildmatch |= MODFlags.const_; + else if (t.isImmutable()) + wildmatch |= MODFlags.immutable_; + else + wildmatch |= MODFlags.mutable; + } + } + + ParameterList* parameterList = &tf.parameterList; + const nparams = parameterList.length; + if (argumentList.length > nparams) + { + if (parameterList.varargs == VarArg.none) + { + // suppress early exit if an error message is wanted, + // so we can check any matching args are valid + if (!pMessage) + return MATCH.nomatch; + } + // too many args; no match + match = MATCH.convert; // match ... with a "conversion" match level + } + + // https://issues.dlang.org/show_bug.cgi?id=22997 + if (parameterList.varargs == VarArg.none && nparams > argumentList.length && !parameterList.hasDefaultArgs) + { + OutBuffer buf; + buf.printf("too few arguments, expected %d, got %d", cast(int)nparams, cast(int)argumentList.length); + if (pMessage) + *pMessage = buf.extractChars(); + return MATCH.nomatch; + } + auto resolvedArgs = tf.resolveNamedArgs(argumentList, pMessage); + Expression[] args; + if (!resolvedArgs) + { + if (!pMessage || *pMessage) + return MATCH.nomatch; + + // if no message was provided, it was because of overflow which will be diagnosed below + match = MATCH.nomatch; + args = argumentList.arguments ? (*argumentList.arguments)[] : null; + } + else + { + args = (*resolvedArgs)[]; + } + + foreach (u, p; *parameterList) + { + if (u >= args.length) + break; + + Expression arg = args[u]; + if (!arg) + continue; // default argument + + Type tprm = p.type; + Type targ = arg.type; + + if (!(p.isLazy() && tprm.ty == Tvoid && targ.ty != Tvoid)) + { + const isRef = p.isReference(); + wildmatch |= targ.deduceWild(tprm, isRef); + } + } + if (wildmatch) + { + /* Calculate wild matching modifier + */ + if (wildmatch & MODFlags.const_ || wildmatch & (wildmatch - 1)) + wildmatch = MODFlags.const_; + else if (wildmatch & MODFlags.immutable_) + wildmatch = MODFlags.immutable_; + else if (wildmatch & MODFlags.wild) + wildmatch = MODFlags.wild; + else + { + assert(wildmatch & MODFlags.mutable); + wildmatch = MODFlags.mutable; + } + } + + foreach (u, p; *parameterList) + { + MATCH m; + + assert(p); + + // One or more arguments remain + if (u < args.length) + { + Expression arg = args[u]; + if (!arg) + continue; // default argument + m = argumentMatchParameter(tf, p, arg, wildmatch, flag, sc, pMessage); + } + else if (p.defaultArg) + continue; + + /* prefer matching the element type rather than the array + * type when more arguments are present with T[]... + */ + if (parameterList.varargs == VarArg.typesafe && u + 1 == nparams && args.length > nparams) + goto L1; + + //printf("\tm = %d\n", m); + if (m == MATCH.nomatch) // if no match + { + L1: + if (parameterList.varargs == VarArg.typesafe && u + 1 == nparams) // if last varargs param + { + auto trailingArgs = args[u .. $]; + if (auto vmatch = matchTypeSafeVarArgs(tf, p, trailingArgs, pMessage)) + return vmatch < match ? vmatch : match; + // Error message was already generated in `matchTypeSafeVarArgs` + return MATCH.nomatch; + } + if (pMessage && u >= args.length) + *pMessage = tf.getMatchError("missing argument for parameter #%d: `%s`", + u + 1, parameterToChars(p, tf, false)); + // If an error happened previously, `pMessage` was already filled + else if (pMessage && !*pMessage) + *pMessage = tf.getParamError(args[u], p); + + return MATCH.nomatch; + } + if (m < match) + match = m; // pick worst match + } + + if (pMessage && !parameterList.varargs && args.length > nparams) + { + // all parameters had a match, but there are surplus args + *pMessage = tf.getMatchError("expected %d argument(s), not %d", nparams, args.length); + return MATCH.nomatch; + } + //printf("match = %d\n", match); + return match; +} + +/** + * Used by `callMatch` to check if the copy constructor may be called to + * copy the argument + * + * This is done by seeing if a call to the copy constructor can be made: + * ``` + * typeof(tprm) __copytmp; + * copytmp.__copyCtor(arg); + * ``` + */ +private extern(D) bool isCopyConstructorCallable (StructDeclaration argStruct, + Expression arg, Type tprm, Scope* sc, const(char)** pMessage) +{ + auto tmp = new VarDeclaration(arg.loc, tprm, Identifier.generateId("__copytmp"), null); + tmp.storage_class = STC.rvalue | STC.temp | STC.ctfe; + tmp.dsymbolSemantic(sc); + Expression ve = new VarExp(arg.loc, tmp); + Expression e = new DotIdExp(arg.loc, ve, Id.ctor); + e = new CallExp(arg.loc, e, arg); + //printf("e = %s\n", e.toChars()); + if (.trySemantic(e, sc)) + return true; + + if (pMessage) + { + /* https://issues.dlang.org/show_bug.cgi?id=22202 + * + * If a function was deduced by semantic on the CallExp, + * it means that resolveFuncCall completed succesfully. + * Therefore, there exists a callable copy constructor, + * however, it cannot be called because scope constraints + * such as purity, safety or nogc. + */ + OutBuffer buf; + auto callExp = e.isCallExp(); + if (auto f = callExp.f) + { + char[] s; + if (!f.isPure && sc.func.setImpure()) + s ~= "pure "; + if (!f.isSafe() && !f.isTrusted() && sc.setUnsafe()) + s ~= "@safe "; + if (!f.isNogc && sc.func.setGC(arg.loc, null)) + s ~= "nogc "; + if (s) + { + s[$-1] = '\0'; + buf.printf("`%s` copy constructor cannot be called from a `%s` context", f.type.toChars(), s.ptr); + } + else if (f.isGenerated() && f.isDisabled()) + { + /* https://issues.dlang.org/show_bug.cgi?id=23097 + * Compiler generated copy constructor failed. + */ + buf.printf("generating a copy constructor for `struct %s` failed, therefore instances of it are uncopyable", + argStruct.toChars()); + } + else + { + /* Although a copy constructor may exist, no suitable match was found. + * i.e: `inout` constructor creates `const` object, not mutable. + * Fallback to using the original generic error before https://issues.dlang.org/show_bug.cgi?id=22202. + */ + goto Lnocpctor; + } + } + else + { + Lnocpctor: + buf.printf("`struct %s` does not define a copy constructor for `%s` to `%s` copies", + argStruct.toChars(), arg.type.toChars(), tprm.toChars()); + } + + *pMessage = buf.extractChars(); + } + return false; +} + +/** + * Match a single parameter to an argument. + * + * This function is called by `TypeFunction.callMatch` while iterating over + * the list of parameter. Here we check if `arg` is a match for `p`, + * which is mostly about checking if `arg.type` converts to `p`'s type + * and some check about value reference. + * + * Params: + * tf = The `TypeFunction`, only used for error reporting + * p = The parameter of `tf` being matched + * arg = Argument being passed (bound) to `p` + * wildmatch = Wild (`inout`) matching level, derived from the full argument list + * flag = A non-zero value means we're doing a partial ordering check + * (no value semantic check) + * sc = Scope we are in + * pMessage = A buffer to write the error in, or `null` + * + * Returns: Whether `trailingArgs` match `p`. + */ +private extern(D) MATCH argumentMatchParameter (TypeFunction tf, Parameter p, + Expression arg, ubyte wildmatch, int flag, Scope* sc, const(char)** pMessage) +{ + //printf("arg: %s, type: %s\n", arg.toChars(), arg.type.toChars()); + MATCH m; + Type targ = arg.type; + Type tprm = wildmatch ? p.type.substWildTo(wildmatch) : p.type; + + if (p.isLazy() && tprm.ty == Tvoid && targ.ty != Tvoid) + m = MATCH.convert; + else if (flag) + { + // for partial ordering, value is an irrelevant mockup, just look at the type + m = targ.implicitConvTo(tprm); + } + else + { + const isRef = p.isReference(); + StructDeclaration argStruct, prmStruct; + + // first look for a copy constructor + if (arg.isLvalue() && !isRef && targ.ty == Tstruct && tprm.ty == Tstruct) + { + // if the argument and the parameter are of the same unqualified struct type + argStruct = (cast(TypeStruct)targ).sym; + prmStruct = (cast(TypeStruct)tprm).sym; + } + + // check if the copy constructor may be called to copy the argument + if (argStruct && argStruct == prmStruct && argStruct.hasCopyCtor) + { + if (!isCopyConstructorCallable(argStruct, arg, tprm, sc, pMessage)) + return MATCH.nomatch; + m = MATCH.exact; + } + else + { + import dmd.dcast : cimplicitConvTo; + m = (sc && sc.flags & SCOPE.Cfile) ? arg.cimplicitConvTo(tprm) : arg.implicitConvTo(tprm); + } + } + + // Non-lvalues do not match ref or out parameters + if (p.isReference()) + { + // https://issues.dlang.org/show_bug.cgi?id=13783 + // Don't use toBasetype() to handle enum types. + Type ta = targ; + Type tp = tprm; + //printf("fparam[%d] ta = %s, tp = %s\n", u, ta.toChars(), tp.toChars()); + + if (m && !arg.isLvalue()) + { + if (p.storageClass & STC.out_) + { + if (pMessage) *pMessage = tf.getParamError(arg, p); + return MATCH.nomatch; + } + + if (arg.op == EXP.string_ && tp.ty == Tsarray) + { + if (ta.ty != Tsarray) + { + Type tn = tp.nextOf().castMod(ta.nextOf().mod); + dinteger_t dim = (cast(StringExp)arg).len; + ta = tn.sarrayOf(dim); + } + } + else if (arg.op == EXP.slice && tp.ty == Tsarray) + { + // Allow conversion from T[lwr .. upr] to ref T[upr-lwr] + if (ta.ty != Tsarray) + { + Type tn = ta.nextOf(); + dinteger_t dim = (cast(TypeSArray)tp).dim.toUInteger(); + ta = tn.sarrayOf(dim); + } + } + else if ((p.storageClass & STC.in_) && global.params.previewIn) + { + // Allow converting a literal to an `in` which is `ref` + if (arg.op == EXP.arrayLiteral && tp.ty == Tsarray) + { + Type tn = tp.nextOf(); + dinteger_t dim = (cast(TypeSArray)tp).dim.toUInteger(); + ta = tn.sarrayOf(dim); + } + + // Need to make this a rvalue through a temporary + m = MATCH.convert; + } + else if (global.params.rvalueRefParam != FeatureState.enabled || + p.storageClass & STC.out_ || + !arg.type.isCopyable()) // can't copy to temp for ref parameter + { + if (pMessage) *pMessage = tf.getParamError(arg, p); + return MATCH.nomatch; + } + else + { + /* in functionParameters() we'll convert this + * rvalue into a temporary + */ + m = MATCH.convert; + } + } + + /* If the match is not already perfect or if the arg + is not a lvalue then try the `alias this` chain + see https://issues.dlang.org/show_bug.cgi?id=15674 + and https://issues.dlang.org/show_bug.cgi?id=21905 + */ + if (ta != tp || !arg.isLvalue()) + { + Type firsttab = ta.toBasetype(); + while (1) + { + Type tab = ta.toBasetype(); + Type tat = tab.aliasthisOf(); + if (!tat || !tat.implicitConvTo(tprm)) + break; + if (tat == tab || tat == firsttab) + break; + ta = tat; + } + } + + /* A ref variable should work like a head-const reference. + * e.g. disallows: + * ref T <- an lvalue of const(T) argument + * ref T[dim] <- an lvalue of const(T[dim]) argument + */ + if (!ta.constConv(tp)) + { + if (pMessage) *pMessage = tf.getParamError(arg, p); + return MATCH.nomatch; + } + } + return m; +} + +// arguments get specially formatted +private const(char)* getParamError(TypeFunction tf, Expression arg, Parameter par) +{ + if (global.gag && !global.params.v.showGaggedErrors) + return null; + // show qualification when toChars() is the same but types are different + // https://issues.dlang.org/show_bug.cgi?id=19948 + // when comparing the type with strcmp, we need to drop the qualifier + bool qual = !arg.type.mutableOf().equals(par.type.mutableOf()) && + strcmp(arg.type.mutableOf().toChars(), par.type.mutableOf().toChars()) == 0; + auto at = qual ? arg.type.toPrettyChars(true) : arg.type.toChars(); + OutBuffer buf; + // only mention rvalue if it's relevant + const rv = !arg.isLvalue() && par.isReference(); + buf.printf("cannot pass %sargument `%s` of type `%s` to parameter `%s`", + rv ? "rvalue ".ptr : "".ptr, arg.toChars(), at, + parameterToChars(par, tf, qual)); + return buf.extractChars(); +} + +/** + * Match the remaining arguments `trailingArgs` with parameter `p`. + * + * Assume we already checked that `p` is the last parameter of `tf`, + * and we want to know whether the arguments would match `p`. + * + * Params: + * tf = The `TypeFunction`, only used for error reporting + * p = The last parameter of `tf` which is variadic + * trailingArgs = The remaining arguments that should match `p` + * pMessage = A buffer to write the error in, or `null` + * + * Returns: Whether `trailingArgs` match `p`. + */ +private extern(D) MATCH matchTypeSafeVarArgs(TypeFunction tf, Parameter p, + Expression[] trailingArgs, const(char)** pMessage) +{ + Type tb = p.type.toBasetype(); + + switch (tb.ty) + { + case Tsarray: + TypeSArray tsa = cast(TypeSArray)tb; + dinteger_t sz = tsa.dim.toInteger(); + if (sz != trailingArgs.length) + { + if (pMessage) + *pMessage = tf.getMatchError("expected %llu variadic argument(s), not %zu", + sz, trailingArgs.length); + return MATCH.nomatch; + } + goto case Tarray; + case Tarray: + { + MATCH match = MATCH.exact; + TypeArray ta = cast(TypeArray)tb; + foreach (arg; trailingArgs) + { + MATCH m; + assert(arg); + + /* If lazy array of delegates, + * convert arg(s) to delegate(s) + */ + Type tret = p.isLazyArray(); + if (tret) + { + if (ta.next.equals(arg.type)) + m = MATCH.exact; + else if (tret.toBasetype().ty == Tvoid) + m = MATCH.convert; + else + { + m = arg.implicitConvTo(tret); + if (m == MATCH.nomatch) + m = arg.implicitConvTo(ta.next); + } + } + else + m = arg.implicitConvTo(ta.next); + + if (m == MATCH.nomatch) + { + if (pMessage) *pMessage = tf.getParamError(arg, p); + return MATCH.nomatch; + } + if (m < match) + match = m; + } + return match; + } + case Tclass: + // We leave it up to the actual constructor call to do the matching. + return MATCH.exact; + + default: + // We can have things as `foo(int[int] wat...)` but they only match + // with an associative array proper. + if (pMessage && trailingArgs.length) *pMessage = tf.getParamError(trailingArgs[0], p); + return MATCH.nomatch; + } +} + /****************************************** * Perform semantic analysis on a type. * Params: @@ -1878,7 +2401,7 @@ extern(C++) Type typeSemantic(Type type, const ref Loc loc, Scope* sc) /* look for pre-existing declaration */ Dsymbol scopesym; - auto s = sc2.search(mtype.loc, mtype.id, &scopesym, IgnoreErrors | TagNameSpace); + auto s = sc2.search(mtype.loc, mtype.id, scopesym, SearchOpt.ignoreErrors | SearchOpt.tagNameSpace); if (!s || s.isModule()) { // no pre-existing declaration, so declare it @@ -2753,7 +3276,7 @@ void resolve(Type mt, const ref Loc loc, Scope* sc, out Expression pe, out Type } Dsymbol scopesym; - Dsymbol s = sc.search(loc, mt.ident, &scopesym); + Dsymbol s = sc.search(loc, mt.ident, scopesym); /* * https://issues.dlang.org/show_bug.cgi?id=1170 * https://issues.dlang.org/show_bug.cgi?id=10739 @@ -2776,7 +3299,7 @@ void resolve(Type mt, const ref Loc loc, Scope* sc, out Expression pe, out Type mixinTempl.dsymbolSemantic(sc); } sds.members.foreachDsymbol( s => semanticOnMixin(s) ); - s = sc.search(loc, mt.ident, &scopesym); + s = sc.search(loc, mt.ident, scopesym); } } @@ -3794,8 +4317,8 @@ Expression dotExp(Type mt, Scope* sc, Expression e, Identifier ident, DotExpFlag return e; } - immutable flags = sc.flags & SCOPE.ignoresymbolvisibility ? IgnoreSymbolVisibility : 0; - s = mt.sym.search(e.loc, ident, flags | IgnorePrivateImports); + immutable flags = sc.flags & SCOPE.ignoresymbolvisibility ? SearchOpt.ignoreVisibility : 0; + s = mt.sym.search(e.loc, ident, flags | SearchOpt.ignorePrivateImports); L1: if (!s) { @@ -4074,8 +4597,8 @@ Expression dotExp(Type mt, Scope* sc, Expression e, Identifier ident, DotExpFlag return e; } - int flags = sc.flags & SCOPE.ignoresymbolvisibility ? IgnoreSymbolVisibility : 0; - s = mt.sym.search(e.loc, ident, flags | IgnorePrivateImports); + SearchOptFlags flags = sc.flags & SCOPE.ignoresymbolvisibility ? SearchOpt.ignoreVisibility : SearchOpt.all; + s = mt.sym.search(e.loc, ident, flags | SearchOpt.ignorePrivateImports); L1: if (!s) @@ -4723,7 +5246,7 @@ Type getComplexLibraryType(const ref Loc loc, Scope* sc, TY ty) return *pt; } - Dsymbol s = mConfig.searchX(Loc.initial, sc, id, IgnorePrivateImports); + Dsymbol s = mConfig.searchX(Loc.initial, sc, id, SearchOpt.ignorePrivateImports); if (!s) { error(loc, "`%s` not found in core.stdc.config", id.toChars()); @@ -4748,6 +5271,263 @@ Type getComplexLibraryType(const ref Loc loc, Scope* sc, TY ty) return *pt; } +/******************************* + * Covariant means that 'src' can substitute for 't', + * i.e. a pure function is a match for an impure type. + * Params: + * src = source type + * t = type 'src' is covariant with + * pstc = if not null, store STCxxxx which would make it covariant + * cppCovariant = true if extern(C++) function types should follow C++ covariant rules + * Returns: + * An enum value of either `Covariant.yes` or a reason it's not covariant. + */ +extern (C++) Covariant covariant(Type src, Type t, StorageClass* pstc = null, bool cppCovariant = false) +{ + version (none) + { + printf("Type::covariant(t = %s) %s\n", t.toChars(), src.toChars()); + printf("deco = %p, %p\n", src.deco, t.deco); + // printf("ty = %d\n", next.ty); + printf("mod = %x, %x\n", src.mod, t.mod); + } + if (pstc) + *pstc = 0; + StorageClass stc = 0; + + bool notcovariant = false; + + if (src.equals(t)) + return Covariant.yes; + + TypeFunction t1 = src.isTypeFunction(); + TypeFunction t2 = t.isTypeFunction(); + + if (!t1 || !t2) + goto Ldistinct; + + if (t1.parameterList.varargs != t2.parameterList.varargs) + goto Ldistinct; + + if (t1.parameterList.parameters && t2.parameterList.parameters) + { + if (t1.parameterList.length != t2.parameterList.length) + goto Ldistinct; + + foreach (i, fparam1; t1.parameterList) + { + Parameter fparam2 = t2.parameterList[i]; + Type tp1 = fparam1.type; + Type tp2 = fparam2.type; + + if (!tp1.equals(tp2)) + { + if (tp1.ty == tp2.ty) + { + if (auto tc1 = tp1.isTypeClass()) + { + if (tc1.sym == (cast(TypeClass)tp2).sym && MODimplicitConv(tp2.mod, tp1.mod)) + goto Lcov; + } + else if (auto ts1 = tp1.isTypeStruct()) + { + if (ts1.sym == (cast(TypeStruct)tp2).sym && MODimplicitConv(tp2.mod, tp1.mod)) + goto Lcov; + } + else if (tp1.ty == Tpointer) + { + if (tp2.implicitConvTo(tp1)) + goto Lcov; + } + else if (tp1.ty == Tarray) + { + if (tp2.implicitConvTo(tp1)) + goto Lcov; + } + else if (tp1.ty == Tdelegate) + { + if (tp2.implicitConvTo(tp1)) + goto Lcov; + } + } + goto Ldistinct; + } + Lcov: + notcovariant |= !fparam1.isCovariant(t1.isref, fparam2); + + /* https://issues.dlang.org/show_bug.cgi?id=23135 + * extern(C++) mutable parameters are not covariant with const. + */ + if (t1.linkage == LINK.cpp && cppCovariant) + { + notcovariant |= tp1.isNaked() != tp2.isNaked(); + if (auto tpn1 = tp1.nextOf()) + notcovariant |= tpn1.isNaked() != tp2.nextOf().isNaked(); + } + } + } + else if (t1.parameterList.parameters != t2.parameterList.parameters) + { + if (t1.parameterList.length || t2.parameterList.length) + goto Ldistinct; + } + + // The argument lists match + if (notcovariant) + goto Lnotcovariant; + if (t1.linkage != t2.linkage) + goto Lnotcovariant; + + { + // Return types + Type t1n = t1.next; + Type t2n = t2.next; + + if (!t1n || !t2n) // happens with return type inference + goto Lnotcovariant; + + if (t1n.equals(t2n)) + goto Lcovariant; + if (t1n.ty == Tclass && t2n.ty == Tclass) + { + /* If same class type, but t2n is const, then it's + * covariant. Do this test first because it can work on + * forward references. + */ + if ((cast(TypeClass)t1n).sym == (cast(TypeClass)t2n).sym && MODimplicitConv(t1n.mod, t2n.mod)) + goto Lcovariant; + + // If t1n is forward referenced: + ClassDeclaration cd = (cast(TypeClass)t1n).sym; + if (cd.semanticRun < PASS.semanticdone && !cd.isBaseInfoComplete()) + cd.dsymbolSemantic(null); + if (!cd.isBaseInfoComplete()) + { + return Covariant.fwdref; + } + } + if (t1n.ty == Tstruct && t2n.ty == Tstruct) + { + if ((cast(TypeStruct)t1n).sym == (cast(TypeStruct)t2n).sym && MODimplicitConv(t1n.mod, t2n.mod)) + goto Lcovariant; + } + else if (t1n.ty == t2n.ty && t1n.implicitConvTo(t2n)) + { + if (t1.isref && t2.isref) + { + // Treat like pointers to t1n and t2n + if (t1n.constConv(t2n) < MATCH.constant) + goto Lnotcovariant; + } + goto Lcovariant; + } + else if (t1n.ty == Tnull) + { + // NULL is covariant with any pointer type, but not with any + // dynamic arrays, associative arrays or delegates. + // https://issues.dlang.org/show_bug.cgi?id=8589 + // https://issues.dlang.org/show_bug.cgi?id=19618 + Type t2bn = t2n.toBasetype(); + if (t2bn.ty == Tnull || t2bn.ty == Tpointer || t2bn.ty == Tclass) + goto Lcovariant; + } + // bottom type is covariant to any type + else if (t1n.ty == Tnoreturn) + goto Lcovariant; + } + goto Lnotcovariant; + +Lcovariant: + if (t1.isref != t2.isref) + goto Lnotcovariant; + + if (!t1.isref && (t1.isScopeQual || t2.isScopeQual)) + { + StorageClass stc1 = t1.isScopeQual ? STC.scope_ : 0; + StorageClass stc2 = t2.isScopeQual ? STC.scope_ : 0; + if (t1.isreturn) + { + stc1 |= STC.return_; + if (!t1.isScopeQual) + stc1 |= STC.ref_; + } + if (t2.isreturn) + { + stc2 |= STC.return_; + if (!t2.isScopeQual) + stc2 |= STC.ref_; + } + if (!Parameter.isCovariantScope(t1.isref, stc1, stc2)) + goto Lnotcovariant; + } + + // We can subtract 'return ref' from 'this', but cannot add it + else if (t1.isreturn && !t2.isreturn) + goto Lnotcovariant; + + /* https://issues.dlang.org/show_bug.cgi?id=23135 + * extern(C++) mutable member functions are not covariant with const. + */ + if (t1.linkage == LINK.cpp && cppCovariant && t1.isNaked() != t2.isNaked()) + goto Lnotcovariant; + + /* Can convert mutable to const + */ + if (!MODimplicitConv(t2.mod, t1.mod)) + { + version (none) + { + //stop attribute inference with const + // If adding 'const' will make it covariant + if (MODimplicitConv(t2.mod, MODmerge(t1.mod, MODFlags.const_))) + stc |= STC.const_; + else + goto Lnotcovariant; + } + else + { + goto Ldistinct; + } + } + + /* Can convert pure to impure, nothrow to throw, and nogc to gc + */ + if (!t1.purity && t2.purity) + stc |= STC.pure_; + + if (!t1.isnothrow && t2.isnothrow) + stc |= STC.nothrow_; + + if (!t1.isnogc && t2.isnogc) + stc |= STC.nogc; + + /* Can convert safe/trusted to system + */ + if (t1.trust <= TRUST.system && t2.trust >= TRUST.trusted) + { + // Should we infer trusted or safe? Go with safe. + stc |= STC.safe; + } + + if (stc) + { + if (pstc) + *pstc = stc; + goto Lnotcovariant; + } + + //printf("\tcovaraint: 1\n"); + return Covariant.yes; + +Ldistinct: + //printf("\tcovaraint: 0\n"); + return Covariant.distinct; + +Lnotcovariant: + //printf("\tcovaraint: 2\n"); + return Covariant.no; +} + /******************************* Private *****************************************/ private: diff --git a/gcc/d/gdc.texi b/gcc/d/gdc.texi index e6a8a90..fe1c625 100644 --- a/gcc/d/gdc.texi +++ b/gcc/d/gdc.texi @@ -740,8 +740,10 @@ arguments like @code{va_start}. @opindex fignore-unknown-pragmas @opindex fno-ignore-unknown-pragmas -@item -fignore-unknown-pragmas -Turns off errors for unsupported pragmas. +@item -fno-ignore-unknown-pragmas +Do not recognize unsupported pragmas. Any @code{pragma()} encountered that is +not part of the D language will result in an error. This option is now +deprecated and will be removed in a future release. @opindex fmax-errors @item -fmax-errors=@var{n} diff --git a/gcc/d/typeinfo.cc b/gcc/d/typeinfo.cc index f67113141..257a2ab 100644 --- a/gcc/d/typeinfo.cc +++ b/gcc/d/typeinfo.cc @@ -20,6 +20,7 @@ along with GCC; see the file COPYING3. If not see #include "coretypes.h" #include "dmd/aggregate.h" +#include "dmd/dsymbol.h" #include "dmd/enum.h" #include "dmd/errors.h" #include "dmd/expression.h" @@ -205,7 +206,7 @@ make_frontend_typeinfo (Identifier *ident, ClassDeclaration *base = NULL) /* Create object module in order to complete the semantic. */ if (!object_module->_scope) - object_module->importAll (NULL); + importAll (object_module, NULL); /* Object class doesn't exist, create a stub one that will cause an error if used. */ diff --git a/gcc/testsuite/gdc.test/compilable/imports/defines.c b/gcc/testsuite/gdc.test/compilable/imports/defines.c index 6bd0736..8a5601a 100644 --- a/gcc/testsuite/gdc.test/compilable/imports/defines.c +++ b/gcc/testsuite/gdc.test/compilable/imports/defines.c @@ -26,3 +26,7 @@ _Static_assert(F80 == 9.0L, "9"); #define SSS "hello" _Static_assert(SSS[0] == 'h', "10"); + +#define ABC 12 +#define GHI (size) abbadabba +#define DEF (ABC + 5) diff --git a/gcc/testsuite/gdc.test/compilable/test9565.d b/gcc/testsuite/gdc.test/compilable/test9565.d deleted file mode 100644 index 9e3ee6a..0000000 --- a/gcc/testsuite/gdc.test/compilable/test9565.d +++ /dev/null @@ -1,86 +0,0 @@ -// REQUIRED_ARGS: -o- -// PERMUTE_ARGS: - -template TypeTuple(T...) { alias TypeTuple = T; } - -bool startsWith(string s, string m) { return s[0 .. m.length] == m; } - -void main() -{ - enum string castPrefix = "cast(" ~ size_t.stringof ~ ")"; - - // TypeSArray - static assert((int[10]).stringof == "int[10]", T.stringof); - - int[] arr; - - // IndexExp - { - // index == IntegerExp - static assert((arr[ 4 ]).stringof == "arr[4]"); - static assert((arr[ 4U ]).stringof == "arr[4]"); - static assert((arr[ 4L ]).stringof == "arr[4]"); - static assert((arr[ 4LU]).stringof == "arr[4]"); - - // index == UAddExp - static assert((arr[+4 ]).stringof == "arr[4]"); - static assert((arr[+4U ]).stringof == "arr[4]"); - static assert((arr[+4L ]).stringof == "arr[4]"); - static assert((arr[+4LU]).stringof == "arr[4]"); - - // index == NegExp - static assert((arr[-4 ]).stringof == "arr[" ~ castPrefix ~ "-4]"); - static assert((arr[-4U ]).stringof == "arr[4294967292]"); - static assert((arr[int.min] ).stringof == "arr[" ~ castPrefix ~ "-2147483648]"); - static if (is(size_t == ulong)) - { - static assert((arr[-4L ]).stringof == "arr[" ~ castPrefix ~ "-4L]"); - static assert((arr[-4LU]).stringof == "arr[-4LU]"); - - // IntegerLiteral needs suffix if the value is greater than long.max - static assert((arr[long.max + 0]).stringof == "arr[9223372036854775807]"); - static assert((arr[long.max + 1]).stringof == "arr[" ~ castPrefix ~ "(9223372036854775807L + 1L)]"); - } - - foreach (Int; TypeTuple!(byte, ubyte, short, ushort, int, uint, long, ulong)) - { - enum Int p4 = +4; - enum string result1 = (arr[p4]).stringof; - static assert(result1 == "arr[4]"); - - enum string result2 = (arr[cast(Int)+4]).stringof; - static assert(result2 == "arr[4]"); - } - foreach (Int; TypeTuple!(byte, short, int, long)) - { - // keep "cast(Type)" in the string representation - - enum Int m4 = -4; - static if (is(typeof({ size_t x = m4; }))) - { - enum string result1 = (arr[m4]).stringof; - static assert(result1.startsWith("arr[" ~ castPrefix)); - } - else - static assert(!__traits(compiles, arr[m4])); - - enum string result2 = (arr[cast(Int)-4]).stringof; - static assert(result2.startsWith("arr[" ~ castPrefix)); - } - } - - // SliceExp - { - // lwr,upr == IntegerExp - static assert((arr[4 .. 8 ]).stringof == "arr[4..8]"); - static assert((arr[4U .. 8U ]).stringof == "arr[4..8]"); - static assert((arr[4L .. 8L ]).stringof == "arr[4..8]"); - static assert((arr[4LU .. 8LU]).stringof == "arr[4..8]"); - - // lwr,upr == UAddExp - static assert((arr[+4 .. +8 ]).stringof == "arr[4..8]"); - static assert((arr[+4U .. +8U ]).stringof == "arr[4..8]"); - static assert((arr[+4L .. +8L ]).stringof == "arr[4..8]"); - static assert((arr[+4LU .. +8LU]).stringof == "arr[4..8]"); - } -} diff --git a/gcc/testsuite/gdc.test/compilable/testdefines.d b/gcc/testsuite/gdc.test/compilable/testdefines.d index 4507266..9dd8cf2 100644 --- a/gcc/testsuite/gdc.test/compilable/testdefines.d +++ b/gcc/testsuite/gdc.test/compilable/testdefines.d @@ -12,3 +12,6 @@ static assert(F64 == 8.0); static assert(F80 == 9.0L); static assert(SSS == "hello"); + +static assert(ABC == 12); +static assert(DEF == 17); diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail19890a.d b/gcc/testsuite/gdc.test/fail_compilation/fail19890a.d index d4da116..9b98496 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/fail19890a.d +++ b/gcc/testsuite/gdc.test/fail_compilation/fail19890a.d @@ -1,7 +1,7 @@ /* TEST_OUTPUT: --- -fail_compilation/fail19890a.d(8): Error: `void[$n$$?:64=LU$]` size 1 * $n$ exceeds $?:windows+32=0x1000000|0x7fffffff$ size limit for static array +fail_compilation/fail19890a.d(8): Error: `void[$n$$?:64=LU$]` size 1 * $n$ exceeds $?:windows+32omf=0x1000000|0x7fffffff$ size limit for static array --- */ diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail19890b.d b/gcc/testsuite/gdc.test/fail_compilation/fail19890b.d index f4a5dad..19081d9 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/fail19890b.d +++ b/gcc/testsuite/gdc.test/fail_compilation/fail19890b.d @@ -1,7 +1,7 @@ /* TEST_OUTPUT: --- -fail_compilation/fail19890b.d(8): Error: `void[$n$$?:64=LU$]` size 1 * $n$ exceeds $?:windows+32=0x1000000|0x7fffffff$ size limit for static array +fail_compilation/fail19890b.d(8): Error: `void[$n$$?:64=LU$]` size 1 * $n$ exceeds $?:windows+32omf=0x1000000|0x7fffffff$ size limit for static array --- */ diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail4611.d b/gcc/testsuite/gdc.test/fail_compilation/fail4611.d index 030c47c..04adf13 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/fail4611.d +++ b/gcc/testsuite/gdc.test/fail_compilation/fail4611.d @@ -1,7 +1,7 @@ /* TEST_OUTPUT: --- -fail_compilation/fail4611.d(15): Error: `Vec[$n$]` size 4 * $n$ exceeds $?:windows+32=0x1000000|0x7fffffff$ size limit for static array +fail_compilation/fail4611.d(15): Error: `Vec[$n$]` size 4 * $n$ exceeds $?:windows+32omf=0x1000000|0x7fffffff$ size limit for static array --- */ diff --git a/gcc/testsuite/gdc.test/fail_compilation/pragmas.d b/gcc/testsuite/gdc.test/fail_compilation/pragmas.d index 5a4b5d9..d967ab5 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/pragmas.d +++ b/gcc/testsuite/gdc.test/fail_compilation/pragmas.d @@ -5,7 +5,6 @@ TEST_OUTPUT: --- fail_compilation/pragmas.d(103): Error: one boolean expression expected for `pragma(inline)`, not 2 fail_compilation/pragmas.d(108): Error: one boolean expression expected for `pragma(inline)`, not 2 -fail_compilation/pragmas.d(118): Error: unrecognized `pragma(unrecognized)` --- */ @@ -28,5 +27,5 @@ void test3() void test4() { - pragma(unrecognized, "string"); + pragma(unrecognized, "string"); // permitted, just ignored } -- cgit v1.1 From 5470a9b176c2b3030ff3891c7e9403db2b0685b8 Mon Sep 17 00:00:00 2001 From: Iain Buclaw Date: Wed, 17 Jan 2024 23:49:05 +0100 Subject: d: Merge dmd, druntime d8e3976a58, phobos 7a6e95688 D front-end changes: - Import dmd v2.107.0-beta.1. - A string literal as an assert condition is deprecated. - Added `@standalone` for module constructors. D runtime changes: - Import druntime v2.107.0-beta.1. Phobos changes: - Import phobos v2.107.0-beta.1. gcc/d/ChangeLog: * dmd/MERGE: Merge upstream dmd d8e3976a58. * dmd/VERSION: Bump version to v2.107.0-beta.1. * d-lang.cc (d_parse_file): Update for new front-end interface. * modules.cc (struct module_info): Add standalonectors. (build_module_tree): Implement @standalone. (register_module_decl): Likewise. libphobos/ChangeLog: * libdruntime/MERGE: Merge upstream druntime d8e3976a58. * src/MERGE: Merge upstream phobos 7a6e95688. --- gcc/d/d-lang.cc | 4 +- gcc/d/dmd/MERGE | 2 +- gcc/d/dmd/VERSION | 2 +- gcc/d/dmd/access.d | 2 +- gcc/d/dmd/aggregate.d | 4 +- gcc/d/dmd/aggregate.h | 2 +- gcc/d/dmd/aliasthis.d | 2 +- gcc/d/dmd/aliasthis.h | 2 +- gcc/d/dmd/arrayop.d | 2 +- gcc/d/dmd/arraytypes.d | 2 +- gcc/d/dmd/arraytypes.h | 2 +- gcc/d/dmd/ast_node.d | 2 +- gcc/d/dmd/ast_node.h | 2 +- gcc/d/dmd/astenums.d | 6 +- gcc/d/dmd/attrib.d | 44 ++- gcc/d/dmd/attrib.h | 10 +- gcc/d/dmd/blockexit.d | 2 +- gcc/d/dmd/builtin.d | 2 +- gcc/d/dmd/canthrow.d | 2 +- gcc/d/dmd/chkformat.d | 2 +- gcc/d/dmd/clone.d | 4 +- gcc/d/dmd/common/bitfields.d | 2 +- gcc/d/dmd/common/file.d | 2 +- gcc/d/dmd/common/outbuffer.d | 2 +- gcc/d/dmd/common/outbuffer.h | 2 +- gcc/d/dmd/common/smallbuffer.d | 6 +- gcc/d/dmd/compiler.d | 2 +- gcc/d/dmd/compiler.h | 2 +- gcc/d/dmd/cond.d | 2 +- gcc/d/dmd/cond.h | 2 +- gcc/d/dmd/constfold.d | 2 +- gcc/d/dmd/cparse.d | 44 ++- gcc/d/dmd/cppmangle.d | 2 +- gcc/d/dmd/ctfe.h | 2 +- gcc/d/dmd/ctfeexpr.d | 2 +- gcc/d/dmd/ctorflow.d | 2 +- gcc/d/dmd/dcast.d | 2 +- gcc/d/dmd/dclass.d | 2 +- gcc/d/dmd/declaration.d | 4 +- gcc/d/dmd/declaration.h | 6 +- gcc/d/dmd/delegatize.d | 2 +- gcc/d/dmd/denum.d | 4 +- gcc/d/dmd/dimport.d | 2 +- gcc/d/dmd/dinterpret.d | 2 +- gcc/d/dmd/dmacro.d | 2 +- gcc/d/dmd/dmangle.d | 4 +- gcc/d/dmd/dmodule.d | 2 +- gcc/d/dmd/doc.d | 4 +- gcc/d/dmd/doc.h | 2 +- gcc/d/dmd/dscope.d | 2 +- gcc/d/dmd/dstruct.d | 8 +- gcc/d/dmd/dsymbol.d | 32 +- gcc/d/dmd/dsymbol.h | 4 +- gcc/d/dmd/dsymbolsem.d | 42 ++- gcc/d/dmd/dtemplate.d | 12 +- gcc/d/dmd/dtoh.d | 2 +- gcc/d/dmd/dversion.d | 2 +- gcc/d/dmd/entity.d | 2 +- gcc/d/dmd/enum.h | 4 +- gcc/d/dmd/errors.d | 2 +- gcc/d/dmd/errors.h | 2 +- gcc/d/dmd/errorsink.d | 2 +- gcc/d/dmd/escape.d | 4 +- gcc/d/dmd/expression.d | 7 +- gcc/d/dmd/expression.h | 4 +- gcc/d/dmd/expressionsem.d | 17 +- gcc/d/dmd/file_manager.d | 135 ++++++--- gcc/d/dmd/foreachvar.d | 2 +- gcc/d/dmd/func.d | 5 +- gcc/d/dmd/globals.d | 4 +- gcc/d/dmd/globals.h | 2 +- gcc/d/dmd/gluelayer.d | 2 +- gcc/d/dmd/hdrgen.d | 323 +++++++++++---------- gcc/d/dmd/hdrgen.h | 6 +- gcc/d/dmd/iasm.d | 2 +- gcc/d/dmd/iasmgcc.d | 2 +- gcc/d/dmd/id.d | 3 +- gcc/d/dmd/id.h | 2 +- gcc/d/dmd/identifier.d | 2 +- gcc/d/dmd/identifier.h | 2 +- gcc/d/dmd/impcnvtab.d | 2 +- gcc/d/dmd/imphint.d | 2 +- gcc/d/dmd/import.h | 2 +- gcc/d/dmd/importc.d | 2 +- gcc/d/dmd/init.d | 2 +- gcc/d/dmd/init.h | 2 +- gcc/d/dmd/initsem.d | 2 +- gcc/d/dmd/inline.d | 2 +- gcc/d/dmd/intrange.d | 2 +- gcc/d/dmd/json.d | 2 +- gcc/d/dmd/json.h | 2 +- gcc/d/dmd/lambdacomp.d | 2 +- gcc/d/dmd/lexer.d | 2 +- gcc/d/dmd/location.d | 2 +- gcc/d/dmd/mangle.h | 2 +- gcc/d/dmd/module.h | 2 +- gcc/d/dmd/mtype.d | 32 +- gcc/d/dmd/mtype.h | 3 +- gcc/d/dmd/mustuse.d | 19 +- gcc/d/dmd/nogc.d | 2 +- gcc/d/dmd/nspace.d | 2 +- gcc/d/dmd/nspace.h | 2 +- gcc/d/dmd/ob.d | 6 +- gcc/d/dmd/objc.d | 2 +- gcc/d/dmd/objc.h | 2 +- gcc/d/dmd/opover.d | 2 +- gcc/d/dmd/optimize.d | 2 +- gcc/d/dmd/parse.d | 10 +- gcc/d/dmd/postordervisitor.d | 2 +- gcc/d/dmd/printast.d | 2 +- gcc/d/dmd/root/aav.d | 2 +- gcc/d/dmd/root/array.d | 2 +- gcc/d/dmd/root/array.h | 2 +- gcc/d/dmd/root/bitarray.d | 2 +- gcc/d/dmd/root/bitarray.h | 2 +- gcc/d/dmd/root/complex.d | 2 +- gcc/d/dmd/root/complex_t.h | 2 +- gcc/d/dmd/root/ctfloat.d | 2 +- gcc/d/dmd/root/ctfloat.h | 2 +- gcc/d/dmd/root/dcompat.h | 2 +- gcc/d/dmd/root/file.d | 2 +- gcc/d/dmd/root/filename.d | 2 +- gcc/d/dmd/root/filename.h | 2 +- gcc/d/dmd/root/hash.d | 2 +- gcc/d/dmd/root/object.h | 2 +- gcc/d/dmd/root/optional.d | 2 +- gcc/d/dmd/root/optional.h | 2 +- gcc/d/dmd/root/port.d | 2 +- gcc/d/dmd/root/port.h | 2 +- gcc/d/dmd/root/region.d | 2 +- gcc/d/dmd/root/rmem.d | 2 +- gcc/d/dmd/root/rmem.h | 2 +- gcc/d/dmd/root/speller.d | 2 +- gcc/d/dmd/root/string.d | 2 +- gcc/d/dmd/root/stringtable.d | 2 +- gcc/d/dmd/root/utf.d | 2 +- gcc/d/dmd/rootobject.d | 2 +- gcc/d/dmd/safe.d | 2 +- gcc/d/dmd/sapply.d | 2 +- gcc/d/dmd/scope.h | 2 +- gcc/d/dmd/semantic2.d | 9 +- gcc/d/dmd/semantic3.d | 2 +- gcc/d/dmd/sideeffect.d | 2 +- gcc/d/dmd/statement.d | 2 +- gcc/d/dmd/statement.h | 2 +- gcc/d/dmd/statement_rewrite_walker.d | 2 +- gcc/d/dmd/statementsem.d | 69 +++-- gcc/d/dmd/staticassert.d | 6 +- gcc/d/dmd/staticassert.h | 4 +- gcc/d/dmd/staticcond.d | 2 +- gcc/d/dmd/stmtstate.d | 2 +- gcc/d/dmd/target.d | 2 +- gcc/d/dmd/target.h | 2 +- gcc/d/dmd/template.h | 6 +- gcc/d/dmd/templateparamsem.d | 2 +- gcc/d/dmd/tokens.d | 154 +++++----- gcc/d/dmd/tokens.h | 2 +- gcc/d/dmd/traits.d | 2 +- gcc/d/dmd/typesem.d | 37 ++- gcc/d/dmd/typinf.d | 2 +- gcc/d/dmd/typinf.h | 2 +- gcc/d/dmd/utils.d | 2 +- gcc/d/dmd/version.h | 2 +- gcc/d/dmd/visitor.d | 2 +- gcc/d/dmd/visitor.h | 2 +- gcc/d/modules.cc | 22 +- gcc/testsuite/gdc.test/compilable/issue20339.d | 44 +++ .../gdc.test/fail_compilation/array_bool.d | 22 ++ .../gdc.test/fail_compilation/diag11425.d | 3 +- gcc/testsuite/gdc.test/fail_compilation/diagin.d | 2 +- gcc/testsuite/gdc.test/fail_compilation/fail110.d | 9 +- .../gdc.test/fail_compilation/fail19890a.d | 4 +- .../gdc.test/fail_compilation/fail19890b.d | 4 +- gcc/testsuite/gdc.test/fail_compilation/fail2195.d | 3 +- .../gdc.test/fail_compilation/fail24301.d | 19 ++ gcc/testsuite/gdc.test/fail_compilation/fail4611.d | 4 +- gcc/testsuite/gdc.test/fail_compilation/fail93.d | 3 +- .../gdc.test/fail_compilation/standalone_modctor.d | 15 + .../fail_compilation/staticarrayoverflow.d | 6 +- .../gdc.test/runnable/imports/standalone_b.d | 11 + .../gdc.test/runnable/standalone_modctor.d | 19 ++ .../runnable_cxx/extra-files/test24292.cpp | 46 +++ gcc/testsuite/gdc.test/runnable_cxx/test24292.d | 50 ++++ 183 files changed, 1025 insertions(+), 618 deletions(-) create mode 100644 gcc/testsuite/gdc.test/compilable/issue20339.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/array_bool.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fail24301.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/standalone_modctor.d create mode 100644 gcc/testsuite/gdc.test/runnable/imports/standalone_b.d create mode 100644 gcc/testsuite/gdc.test/runnable/standalone_modctor.d create mode 100644 gcc/testsuite/gdc.test/runnable_cxx/extra-files/test24292.cpp create mode 100644 gcc/testsuite/gdc.test/runnable_cxx/test24292.d (limited to 'gcc') diff --git a/gcc/d/d-lang.cc b/gcc/d/d-lang.cc index a25d031..71f8473 100644 --- a/gcc/d/d-lang.cc +++ b/gcc/d/d-lang.cc @@ -1209,7 +1209,7 @@ d_parse_file (void) message ("import %s", m->toChars ()); OutBuffer buf; - genhdrfile (m, buf); + genhdrfile (m, global.params.dihdr.fullOutput, buf); d_write_file (m->hdrfile.toChars (), buf.peekChars ()); } @@ -1373,7 +1373,7 @@ d_parse_file (void) OutBuffer buf; buf.doindent = 1; - moduleToBuffer (buf, m); + moduleToBuffer (buf, true, m); message ("%s", buf.peekChars ()); } } diff --git a/gcc/d/dmd/MERGE b/gcc/d/dmd/MERGE index fa7004b..2b4400f 100644 --- a/gcc/d/dmd/MERGE +++ b/gcc/d/dmd/MERGE @@ -1,4 +1,4 @@ -f1a045928e03239b9477f9497f43f2cf0e61e959 +d8e3976a58d6aef7c2c9371028a2ca4460b5b2ce The first line of this file holds the git revision number of the last merge done from the dlang/dmd repository. diff --git a/gcc/d/dmd/VERSION b/gcc/d/dmd/VERSION index 9d7be5b..b9813c7 100644 --- a/gcc/d/dmd/VERSION +++ b/gcc/d/dmd/VERSION @@ -1 +1 @@ -v2.106.1-rc.1 +v2.107.0-beta.1 diff --git a/gcc/d/dmd/access.d b/gcc/d/dmd/access.d index 1010c14..8d02203 100644 --- a/gcc/d/dmd/access.d +++ b/gcc/d/dmd/access.d @@ -3,7 +3,7 @@ * * Specification: $(LINK2 https://dlang.org/spec/attribute.html#visibility_attributes, Visibility Attributes) * - * Copyright: Copyright (C) 1999-2023 by The D Language Foundation, All Rights Reserved + * Copyright: Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved * Authors: $(LINK2 https://www.digitalmars.com, Walter Bright) * License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/access.d, _access.d) diff --git a/gcc/d/dmd/aggregate.d b/gcc/d/dmd/aggregate.d index 352ca88..2d32042 100644 --- a/gcc/d/dmd/aggregate.d +++ b/gcc/d/dmd/aggregate.d @@ -4,7 +4,7 @@ * Specification: $(LINK2 https://dlang.org/spec/struct.html, Structs, Unions), * $(LINK2 https://dlang.org/spec/class.html, Class). * - * Copyright: Copyright (C) 1999-2023 by The D Language Foundation, All Rights Reserved + * Copyright: Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved * Authors: $(LINK2 https://www.digitalmars.com, Walter Bright) * License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/aggregate.d, _aggregate.d) @@ -65,7 +65,7 @@ enum ClassKind : ubyte * Returns: * 0-terminated string for `c` */ -const(char)* toChars(ClassKind c) @safe +const(char)* ClassKindToChars(ClassKind c) @safe { final switch (c) { diff --git a/gcc/d/dmd/aggregate.h b/gcc/d/dmd/aggregate.h index 98fa6bd..9abdd09 100644 --- a/gcc/d/dmd/aggregate.h +++ b/gcc/d/dmd/aggregate.h @@ -1,6 +1,6 @@ /* Compiler implementation of the D programming language - * Copyright (C) 1999-2023 by The D Language Foundation, All Rights Reserved + * Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved * written by Walter Bright * https://www.digitalmars.com * Distributed under the Boost Software License, Version 1.0. diff --git a/gcc/d/dmd/aliasthis.d b/gcc/d/dmd/aliasthis.d index 0c15636..0e063ca 100644 --- a/gcc/d/dmd/aliasthis.d +++ b/gcc/d/dmd/aliasthis.d @@ -3,7 +3,7 @@ * * Specification: $(LINK2 https://dlang.org/spec/class.html#alias-this, Alias This) * - * Copyright: Copyright (C) 1999-2023 by The D Language Foundation, All Rights Reserved + * Copyright: Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved * Authors: $(LINK2 https://www.digitalmars.com, Walter Bright) * License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/aliasthis.d, _aliasthis.d) diff --git a/gcc/d/dmd/aliasthis.h b/gcc/d/dmd/aliasthis.h index 092490f..88ba353 100644 --- a/gcc/d/dmd/aliasthis.h +++ b/gcc/d/dmd/aliasthis.h @@ -1,6 +1,6 @@ /* Compiler implementation of the D programming language - * Copyright (C) 2009-2023 by The D Language Foundation, All Rights Reserved + * Copyright (C) 2009-2024 by The D Language Foundation, All Rights Reserved * written by Walter Bright * https://www.digitalmars.com * Distributed under the Boost Software License, Version 1.0. diff --git a/gcc/d/dmd/arrayop.d b/gcc/d/dmd/arrayop.d index c3b8526..afe6054 100644 --- a/gcc/d/dmd/arrayop.d +++ b/gcc/d/dmd/arrayop.d @@ -3,7 +3,7 @@ * * Specification: $(LINK2 https://dlang.org/spec/arrays.html#array-operations, Array Operations) * - * Copyright: Copyright (C) 1999-2023 by The D Language Foundation, All Rights Reserved + * Copyright: Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved * Authors: $(LINK2 https://www.digitalmars.com, Walter Bright) * License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/arrayop.d, _arrayop.d) diff --git a/gcc/d/dmd/arraytypes.d b/gcc/d/dmd/arraytypes.d index 6634a6a..feab9a4 100644 --- a/gcc/d/dmd/arraytypes.d +++ b/gcc/d/dmd/arraytypes.d @@ -1,7 +1,7 @@ /** * Provide aliases for arrays of certain declarations or statements. * - * Copyright: Copyright (C) 1999-2023 by The D Language Foundation, All Rights Reserved + * Copyright: Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved * Authors: $(LINK2 https://www.digitalmars.com, Walter Bright) * License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/arraytypes.d, _arraytypes.d) diff --git a/gcc/d/dmd/arraytypes.h b/gcc/d/dmd/arraytypes.h index 05126a5..7796428 100644 --- a/gcc/d/dmd/arraytypes.h +++ b/gcc/d/dmd/arraytypes.h @@ -1,6 +1,6 @@ /* Compiler implementation of the D programming language - * Copyright (C) 2006-2023 by The D Language Foundation, All Rights Reserved + * Copyright (C) 2006-2024 by The D Language Foundation, All Rights Reserved * written by Walter Bright * https://www.digitalmars.com * Distributed under the Boost Software License, Version 1.0. diff --git a/gcc/d/dmd/ast_node.d b/gcc/d/dmd/ast_node.d index 313c2bd..c8c95fa 100644 --- a/gcc/d/dmd/ast_node.d +++ b/gcc/d/dmd/ast_node.d @@ -1,7 +1,7 @@ /** * Defines the base class for all nodes which are part of the AST. * - * Copyright: Copyright (C) 1999-2023 by The D Language Foundation, All Rights Reserved + * Copyright: Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved * Authors: $(LINK2 https://www.digitalmars.com, Walter Bright) * License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/ast_node.d, _ast_node.d) diff --git a/gcc/d/dmd/ast_node.h b/gcc/d/dmd/ast_node.h index 6154c6d..a24218a 100644 --- a/gcc/d/dmd/ast_node.h +++ b/gcc/d/dmd/ast_node.h @@ -1,6 +1,6 @@ /* Compiler implementation of the D programming language - * Copyright (C) 1999-2023 by The D Language Foundation, All Rights Reserved + * Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved * written by Walter Bright * https://www.digitalmars.com * Distributed under the Boost Software License, Version 1.0. diff --git a/gcc/d/dmd/astenums.d b/gcc/d/dmd/astenums.d index 6a9c010..f19edb9 100644 --- a/gcc/d/dmd/astenums.d +++ b/gcc/d/dmd/astenums.d @@ -1,7 +1,7 @@ /** * Defines enums common to dmd and dmd as parse library. * - * Copyright: Copyright (C) 1999-2023 by The D Language Foundation, All Rights Reserved + * Copyright: Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved * License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/astenums.d, _astenums.d) * Documentation: https://dlang.org/phobos/dmd_astenums.html @@ -63,7 +63,7 @@ enum STC : ulong // transfer changes to declaration.h foreach_ = 0x4000, /// variable for foreach loop variadic = 0x8000, /// the `variadic` parameter in: T foo(T a, U b, V variadic...) - // = 0x1_0000, + constscoperef = 0x1_0000, /// when `in` means const|scope|ref templateparameter = 0x2_0000, /// template parameter ref_ = 0x4_0000, /// `ref` scope_ = 0x8_0000, /// `scope` @@ -112,7 +112,7 @@ enum STC : ulong // transfer changes to declaration.h volatile_ = 0x40_0000_0000_0000, /// destined for volatile in the back end safeGroup = STC.safe | STC.trusted | STC.system, - IOR = STC.in_ | STC.ref_ | STC.out_, + IOR = STC.constscoperef | STC.in_ | STC.ref_ | STC.out_, TYPECTOR = (STC.const_ | STC.immutable_ | STC.shared_ | STC.wild), FUNCATTR = (STC.ref_ | STC.nothrow_ | STC.nogc | STC.pure_ | STC.property | STC.live | safeGroup), diff --git a/gcc/d/dmd/attrib.d b/gcc/d/dmd/attrib.d index cc6ef9c..d7d3eca6 100644 --- a/gcc/d/dmd/attrib.d +++ b/gcc/d/dmd/attrib.d @@ -14,7 +14,7 @@ * - Protection (`private`, `public`) * - Deprecated declarations (`@deprecated`) * - * Copyright: Copyright (C) 1999-2023 by The D Language Foundation, All Rights Reserved + * Copyright: Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved * Authors: $(LINK2 https://www.digitalmars.com, Walter Bright) * License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/attrib.d, _attrib.d) @@ -137,7 +137,7 @@ extern (C++) abstract class AttribDeclaration : Dsymbol return "attribute"; } - override bool oneMember(Dsymbol* ps, Identifier ident) + override bool oneMember(out Dsymbol ps, Identifier ident) { Dsymbols* d = include(null); return Dsymbol.oneMembers(d, ps, ident); @@ -225,10 +225,10 @@ extern (C++) class StorageClassDeclaration : AttribDeclaration sc.visibility, sc.explicitVisibility, sc.aligndecl, sc.inlining); } - override final bool oneMember(Dsymbol* ps, Identifier ident) + override final bool oneMember(out Dsymbol ps, Identifier ident) { bool t = Dsymbol.oneMembers(decl, ps, ident); - if (t && *ps) + if (t && ps) { /* This is to deal with the following case: * struct Tick { @@ -238,7 +238,7 @@ extern (C++) class StorageClassDeclaration : AttribDeclaration * before the semantic analysis of 'to', so that template overloading based on the * 'this' pointer can be successful. */ - FuncDeclaration fd = (*ps).isFuncDeclaration(); + FuncDeclaration fd = ps.isFuncDeclaration(); if (fd) { /* Use storage_class2 instead of storage_class otherwise when we do .di generation @@ -743,7 +743,7 @@ extern (C++) class ConditionalDeclaration : AttribDeclaration return new ConditionalDeclaration(loc, condition.syntaxCopy(), Dsymbol.arraySyntaxCopy(decl), Dsymbol.arraySyntaxCopy(elsedecl)); } - override final bool oneMember(Dsymbol* ps, Identifier ident) + override final bool oneMember(out Dsymbol ps, Identifier ident) { //printf("ConditionalDeclaration::oneMember(), inc = %d\n", condition.inc); if (condition.inc != Include.notComputed) @@ -753,8 +753,8 @@ extern (C++) class ConditionalDeclaration : AttribDeclaration } else { - bool res = (Dsymbol.oneMembers(decl, ps, ident) && *ps is null && Dsymbol.oneMembers(elsedecl, ps, ident) && *ps is null); - *ps = null; + bool res = (Dsymbol.oneMembers(decl, ps, ident) && ps is null && Dsymbol.oneMembers(elsedecl, ps, ident) && ps is null); + ps = null; return res; } } @@ -901,7 +901,7 @@ extern (C++) final class StaticForeachDeclaration : AttribDeclaration Dsymbol.arraySyntaxCopy(decl)); } - override bool oneMember(Dsymbol* ps, Identifier ident) + override bool oneMember(out Dsymbol ps, Identifier ident) { // Required to support IFTI on a template that contains a // `static foreach` declaration. `super.oneMember` calls @@ -912,7 +912,7 @@ extern (C++) final class StaticForeachDeclaration : AttribDeclaration { return super.oneMember(ps, ident); } - *ps = null; // a `static foreach` declaration may in general expand to multiple symbols + ps = null; // a `static foreach` declaration may in general expand to multiple symbols return false; } @@ -1296,3 +1296,27 @@ int foreachUdaNoSemantic(Dsymbol sym, int delegate(Expression) dg) return 0; } + + +/** + * Returns: true if the given expression is an enum from `core.attribute` named `id` + */ +bool isEnumAttribute(Expression e, Identifier id) +{ + import dmd.attrib : isCoreUda; + import dmd.id : Id; + + // Logic based on dmd.objc.Supported.declaredAsOptionalCount + auto typeExp = e.isTypeExp; + if (!typeExp) + return false; + + auto typeEnum = typeExp.type.isTypeEnum(); + if (!typeEnum) + return false; + + if (isCoreUda(typeEnum.sym, id)) + return true; + + return false; +} diff --git a/gcc/d/dmd/attrib.h b/gcc/d/dmd/attrib.h index 35628e2..344a7e9 100644 --- a/gcc/d/dmd/attrib.h +++ b/gcc/d/dmd/attrib.h @@ -1,6 +1,6 @@ /* Compiler implementation of the D programming language - * Copyright (C) 1999-2023 by The D Language Foundation, All Rights Reserved + * Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved * written by Walter Bright * https://www.digitalmars.com * Distributed under the Boost Software License, Version 1.0. @@ -28,7 +28,7 @@ public: virtual Scope *newScope(Scope *sc); void addComment(const utf8_t *comment) override; const char *kind() const override; - bool oneMember(Dsymbol **ps, Identifier *ident) override; + bool oneMember(Dsymbol *&ps, Identifier *ident) override; bool hasPointers() override final; bool hasStaticCtorOrDtor() override final; void checkCtorConstInit() override final; @@ -44,7 +44,7 @@ public: StorageClassDeclaration *syntaxCopy(Dsymbol *s) override; Scope *newScope(Scope *sc) override; - bool oneMember(Dsymbol **ps, Identifier *ident) override final; + bool oneMember(Dsymbol *&ps, Identifier *ident) override final; StorageClassDeclaration *isStorageClassDeclaration() override { return this; } void accept(Visitor *v) override { v->visit(this); } @@ -153,7 +153,7 @@ public: Dsymbols *elsedecl; // array of Dsymbol's for else block ConditionalDeclaration *syntaxCopy(Dsymbol *s) override; - bool oneMember(Dsymbol **ps, Identifier *ident) override final; + bool oneMember(Dsymbol *&ps, Identifier *ident) override final; Dsymbols *include(Scope *sc) override; void addComment(const utf8_t *comment) override final; void accept(Visitor *v) override { v->visit(this); } @@ -183,7 +183,7 @@ public: Dsymbols *cache; StaticForeachDeclaration *syntaxCopy(Dsymbol *s) override; - bool oneMember(Dsymbol **ps, Identifier *ident) override; + bool oneMember(Dsymbol *&ps, Identifier *ident) override; Dsymbols *include(Scope *sc) override; void addComment(const utf8_t *comment) override; const char *kind() const override; diff --git a/gcc/d/dmd/blockexit.d b/gcc/d/dmd/blockexit.d index 5108ecf..d77af7e 100644 --- a/gcc/d/dmd/blockexit.d +++ b/gcc/d/dmd/blockexit.d @@ -1,7 +1,7 @@ /** * Find out in what ways control flow can exit a statement block. * - * Copyright: Copyright (C) 1999-2023 by The D Language Foundation, All Rights Reserved + * Copyright: Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved * Authors: $(LINK2 https://www.digitalmars.com, Walter Bright) * License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/blockexit.d, _blockexit.d) diff --git a/gcc/d/dmd/builtin.d b/gcc/d/dmd/builtin.d index 27ba1e0..d29092b 100644 --- a/gcc/d/dmd/builtin.d +++ b/gcc/d/dmd/builtin.d @@ -3,7 +3,7 @@ * * Currently includes functions from `std.math`, `core.math` and `core.bitop`. * - * Copyright: Copyright (C) 1999-2023 by The D Language Foundation, All Rights Reserved + * Copyright: Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved * Authors: $(LINK2 https://www.digitalmars.com, Walter Bright) * License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/builtin.d, _builtin.d) diff --git a/gcc/d/dmd/canthrow.d b/gcc/d/dmd/canthrow.d index 5a608a9..31155f1 100644 --- a/gcc/d/dmd/canthrow.d +++ b/gcc/d/dmd/canthrow.d @@ -3,7 +3,7 @@ * * Specification: $(LINK2 https://dlang.org/spec/function.html#nothrow-functions, Nothrow Functions) * - * Copyright: Copyright (C) 1999-2023 by The D Language Foundation, All Rights Reserved + * Copyright: Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved * Authors: $(LINK2 https://www.digitalmars.com, Walter Bright) * License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/canthrow.d, _canthrow.d) diff --git a/gcc/d/dmd/chkformat.d b/gcc/d/dmd/chkformat.d index 8cfad59..5024f9b 100644 --- a/gcc/d/dmd/chkformat.d +++ b/gcc/d/dmd/chkformat.d @@ -1,7 +1,7 @@ /** * Check the arguments to `printf` and `scanf` against the `format` string. * - * Copyright: Copyright (C) 1999-2023 by The D Language Foundation, All Rights Reserved + * Copyright: Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved * Authors: $(LINK2 https://www.digitalmars.com, Walter Bright) * License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/chkformat.d, _chkformat.d) diff --git a/gcc/d/dmd/clone.d b/gcc/d/dmd/clone.d index ca7f398..6fbf8e2 100644 --- a/gcc/d/dmd/clone.d +++ b/gcc/d/dmd/clone.d @@ -2,7 +2,7 @@ * Builds struct member functions if needed and not defined by the user. * Includes `opEquals`, `opAssign`, post blit, copy constructor and destructor. * - * Copyright: Copyright (C) 1999-2023 by The D Language Foundation, All Rights Reserved + * Copyright: Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved * Authors: $(LINK2 https://www.digitalmars.com, Walter Bright) * License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/clone.d, _clone.d) @@ -1571,7 +1571,7 @@ private Statement generateCopyCtorBody(StructDeclaration sd) * `true` if one needs to be generated * `false` otherwise */ -private bool needCopyCtor(StructDeclaration sd, out bool hasCpCtor) +bool needCopyCtor(StructDeclaration sd, out bool hasCpCtor) { if (global.errors) return false; diff --git a/gcc/d/dmd/common/bitfields.d b/gcc/d/dmd/common/bitfields.d index b9fcb09..01aa56d 100644 --- a/gcc/d/dmd/common/bitfields.d +++ b/gcc/d/dmd/common/bitfields.d @@ -1,7 +1,7 @@ /** * A library bitfields utility * - * Copyright: Copyright (C) 1999-2023 by The D Language Foundation, All Rights Reserved + * Copyright: Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved * Authors: Dennis Korpel * License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/common/bitfields.d, common/bitfields.d) diff --git a/gcc/d/dmd/common/file.d b/gcc/d/dmd/common/file.d index 704110f..8a28424 100644 --- a/gcc/d/dmd/common/file.d +++ b/gcc/d/dmd/common/file.d @@ -4,7 +4,7 @@ * Functions and objects dedicated to file I/O and management. TODO: Move here artifacts * from places such as root/ so both the frontend and the backend have access to them. * - * Copyright: Copyright (C) 1999-2023 by The D Language Foundation, All Rights Reserved + * Copyright: Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved * Authors: Walter Bright, https://www.digitalmars.com * License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/common/file.d, common/_file.d) diff --git a/gcc/d/dmd/common/outbuffer.d b/gcc/d/dmd/common/outbuffer.d index 4e7a82f..cff08ec 100644 --- a/gcc/d/dmd/common/outbuffer.d +++ b/gcc/d/dmd/common/outbuffer.d @@ -1,7 +1,7 @@ /** * An expandable buffer in which you can write text or binary data. * - * Copyright: Copyright (C) 1999-2023 by The D Language Foundation, All Rights Reserved + * Copyright: Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved * Authors: Walter Bright, https://www.digitalmars.com * License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/root/outbuffer.d, root/_outbuffer.d) diff --git a/gcc/d/dmd/common/outbuffer.h b/gcc/d/dmd/common/outbuffer.h index 4c1dcee..2250497 100644 --- a/gcc/d/dmd/common/outbuffer.h +++ b/gcc/d/dmd/common/outbuffer.h @@ -1,5 +1,5 @@ -/* Copyright (C) 1999-2023 by The D Language Foundation, All Rights Reserved +/* Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved * written by Walter Bright * https://www.digitalmars.com * Distributed under the Boost Software License, Version 1.0. diff --git a/gcc/d/dmd/common/smallbuffer.d b/gcc/d/dmd/common/smallbuffer.d index ec0eaae..c6aa7ab 100644 --- a/gcc/d/dmd/common/smallbuffer.d +++ b/gcc/d/dmd/common/smallbuffer.d @@ -1,7 +1,7 @@ /** * Common string functions including filename manipulation. * - * Copyright: Copyright (C) 1999-2023 by The D Language Foundation, All Rights Reserved + * Copyright: Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved * Authors: Walter Bright, https://www.digitalmars.com * License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/common/smallbuffer.d, common/_smallbuffer.d) @@ -48,7 +48,7 @@ struct SmallBuffer(Element) } else { - assert(len < sizeof.max / (2 * Element.sizeof)); + assert(len < size_t.max / (2 * Element.sizeof)); _extent = (cast(typeof(_extent.ptr)) malloc(len * Element.sizeof))[0 .. len]; _extent.ptr || assert(0, "Out of memory."); needsFree = true; @@ -76,7 +76,7 @@ struct SmallBuffer(Element) else { __dtor(); - assert(len < sizeof.max / Element.sizeof); + assert(len < size_t.max / Element.sizeof); _extent = (cast(typeof(_extent.ptr)) malloc(len * Element.sizeof))[0 .. len]; _extent.ptr || assert(0, "Out of memory."); needsFree = true; diff --git a/gcc/d/dmd/compiler.d b/gcc/d/dmd/compiler.d index 8b8a453..65330cf 100644 --- a/gcc/d/dmd/compiler.d +++ b/gcc/d/dmd/compiler.d @@ -1,7 +1,7 @@ /** * Describes a back-end compiler and implements compiler-specific actions. * - * Copyright: Copyright (C) 1999-2023 by The D Language Foundation, All Rights Reserved + * Copyright: Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved * Authors: $(LINK2 https://www.digitalmars.com, Walter Bright) * License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/compiler.d, _compiler.d) diff --git a/gcc/d/dmd/compiler.h b/gcc/d/dmd/compiler.h index c7cbce3..74351ed 100644 --- a/gcc/d/dmd/compiler.h +++ b/gcc/d/dmd/compiler.h @@ -1,6 +1,6 @@ /* Compiler implementation of the D programming language - * Copyright (C) 1999-2023 by The D Language Foundation, All Rights Reserved + * Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved * written by Walter Bright * https://www.digitalmars.com * Distributed under the Boost Software License, Version 1.0. diff --git a/gcc/d/dmd/cond.d b/gcc/d/dmd/cond.d index 568b639..1b32ff7 100644 --- a/gcc/d/dmd/cond.d +++ b/gcc/d/dmd/cond.d @@ -3,7 +3,7 @@ * * Specification: $(LINK2 https://dlang.org/spec/version.html, Conditional Compilation) * - * Copyright: Copyright (C) 1999-2023 by The D Language Foundation, All Rights Reserved + * Copyright: Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved * Authors: $(LINK2 https://www.digitalmars.com, Walter Bright) * License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/cond.d, _cond.d) diff --git a/gcc/d/dmd/cond.h b/gcc/d/dmd/cond.h index d02ae13..fe497c2d 100644 --- a/gcc/d/dmd/cond.h +++ b/gcc/d/dmd/cond.h @@ -1,6 +1,6 @@ /* Compiler implementation of the D programming language - * Copyright (C) 1999-2023 by The D Language Foundation, All Rights Reserved + * Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved * written by Walter Bright * https://www.digitalmars.com * Distributed under the Boost Software License, Version 1.0. diff --git a/gcc/d/dmd/constfold.d b/gcc/d/dmd/constfold.d index fc3fd3b..7bd9691 100644 --- a/gcc/d/dmd/constfold.d +++ b/gcc/d/dmd/constfold.d @@ -5,7 +5,7 @@ * * Specification: $(LINK2 https://dlang.org/spec/float.html#fp_const_folding, Floating Point Constant Folding) * - * Copyright: Copyright (C) 1999-2023 by The D Language Foundation, All Rights Reserved + * Copyright: Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved * Authors: $(LINK2 https://www.digitalmars.com, Walter Bright) * License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/constfold.d, _constfold.d) diff --git a/gcc/d/dmd/cparse.d b/gcc/d/dmd/cparse.d index 4c0b96a..e0cdc87 100644 --- a/gcc/d/dmd/cparse.d +++ b/gcc/d/dmd/cparse.d @@ -3,7 +3,7 @@ * * Specification: C11 * - * Copyright: Copyright (C) 1999-2023 by The D Language Foundation, All Rights Reserved + * Copyright: Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved * Authors: $(LINK2 https://www.digitalmars.com, Walter Bright) * License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/cparse.d, _cparse.d) @@ -605,15 +605,23 @@ final class CParser(AST) : Parser!AST { Identifier ident; nextToken(); - if (token.value != TOK.identifier) + if (token.value == TOK.identifier) { - error("identifier expected following `goto`"); + ident = token.ident; + nextToken(); + } + else if (token.value == TOK.mul) + { + /* https://gcc.gnu.org/onlinedocs/gcc/Labels-as-Values.html + */ + error("`goto *` computed goto extension is not supported"); ident = null; + cparseUnaryExp(); // parse and throw away } else { - ident = token.ident; - nextToken(); + error("identifier expected following `goto`"); + ident = null; } s = new AST.GotoStatement(loc, ident); check(TOK.semicolon, "`goto` statement"); @@ -1056,6 +1064,14 @@ final class CParser(AST) : Parser!AST break; } + case TOK.andAnd: + /* https://gcc.gnu.org/onlinedocs/gcc/Labels-as-Values.html + */ + error("unary `&&` computed goto extension is not supported"); + nextToken(); + e = cparseCastExp(); + break; + case TOK._Alignof: { nextToken(); @@ -1931,20 +1947,18 @@ final class CParser(AST) : Parser!AST } else if (auto tt = dt.isTypeTag()) { - if (tt.id || tt.tok == TOK.enum_) - { - if (!tt.id && id) - /* This applies for enums declared as - * typedef enum {A} E; - */ - tt.id = id; - Specifier spec; - declareTag(tt, spec); - } + if (!tt.id && id) + /* This applies for enums declared as + * typedef enum {A} E; + */ + tt.id = id; + Specifier spec; + declareTag(tt, spec); idt = tt.id; } if (isalias) { + //printf("AliasDeclaration %s %s\n", id.toChars(), dt.toChars()); auto ad = new AST.AliasDeclaration(token.loc, id, dt); if (id == idt) ad.adFlags |= ad.hidden; // do not print when generating .di files diff --git a/gcc/d/dmd/cppmangle.d b/gcc/d/dmd/cppmangle.d index 55844dd..90b6295 100644 --- a/gcc/d/dmd/cppmangle.d +++ b/gcc/d/dmd/cppmangle.d @@ -4,7 +4,7 @@ * This is the POSIX side of the implementation. * It exports two functions to C++, `toCppMangleItanium` and `cppTypeInfoMangleItanium`. * - * Copyright: Copyright (C) 1999-2023 by The D Language Foundation, All Rights Reserved + * Copyright: Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved * Authors: Walter Bright, https://www.digitalmars.com * License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/cppmangle.d, _cppmangle.d) diff --git a/gcc/d/dmd/ctfe.h b/gcc/d/dmd/ctfe.h index bb92778..72d895c 100644 --- a/gcc/d/dmd/ctfe.h +++ b/gcc/d/dmd/ctfe.h @@ -1,6 +1,6 @@ /* Compiler implementation of the D programming language - * Copyright (C) 1999-2023 by The D Language Foundation, All Rights Reserved + * Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved * written by Walter Bright * https://www.digitalmars.com * Distributed under the Boost Software License, Version 1.0. diff --git a/gcc/d/dmd/ctfeexpr.d b/gcc/d/dmd/ctfeexpr.d index 993bab0..5fe1e7d 100644 --- a/gcc/d/dmd/ctfeexpr.d +++ b/gcc/d/dmd/ctfeexpr.d @@ -1,7 +1,7 @@ /** * CTFE for expressions involving pointers, slices, array concatenation etc. * - * Copyright: Copyright (C) 1999-2023 by The D Language Foundation, All Rights Reserved + * Copyright: Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved * Authors: $(LINK2 https://www.digitalmars.com, Walter Bright) * License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/ctfeexpr.d, _ctfeexpr.d) diff --git a/gcc/d/dmd/ctorflow.d b/gcc/d/dmd/ctorflow.d index 128c698..ba5240e 100644 --- a/gcc/d/dmd/ctorflow.d +++ b/gcc/d/dmd/ctorflow.d @@ -1,7 +1,7 @@ /** * Manage flow analysis for constructors. * - * Copyright: Copyright (C) 1999-2023 by The D Language Foundation, All Rights Reserved + * Copyright: Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved * Authors: $(LINK2 https://www.digitalmars.com, Walter Bright) * License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/ctorflow.d, _ctorflow.d) diff --git a/gcc/d/dmd/dcast.d b/gcc/d/dmd/dcast.d index cfa374c..628c6889 100644 --- a/gcc/d/dmd/dcast.d +++ b/gcc/d/dmd/dcast.d @@ -1,7 +1,7 @@ /** * Semantic analysis for cast-expressions. * - * Copyright: Copyright (C) 1999-2023 by The D Language Foundation, All Rights Reserved + * Copyright: Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved * Authors: $(LINK2 https://www.digitalmars.com, Walter Bright) * License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/dcast.d, _dcast.d) diff --git a/gcc/d/dmd/dclass.d b/gcc/d/dmd/dclass.d index e066d87..405e817 100644 --- a/gcc/d/dmd/dclass.d +++ b/gcc/d/dmd/dclass.d @@ -3,7 +3,7 @@ * * Specification: $(LINK2 https://dlang.org/spec/class.html, Classes) * - * Copyright: Copyright (C) 1999-2023 by The D Language Foundation, All Rights Reserved + * Copyright: Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved * Authors: $(LINK2 https://www.digitalmars.com, Walter Bright) * License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/dclass.d, _dclass.d) diff --git a/gcc/d/dmd/declaration.d b/gcc/d/dmd/declaration.d index bdc91f4..5869a22 100644 --- a/gcc/d/dmd/declaration.d +++ b/gcc/d/dmd/declaration.d @@ -2,7 +2,7 @@ * Miscellaneous declarations, including typedef, alias, variable declarations including the * implicit this declaration, type tuples, ClassInfo, ModuleInfo and various TypeInfos. * - * Copyright: Copyright (C) 1999-2023 by The D Language Foundation, All Rights Reserved + * Copyright: Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved * Authors: $(LINK2 https://www.digitalmars.com, Walter Bright) * License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/declaration.d, _declaration.d) @@ -246,8 +246,6 @@ extern (C++) abstract class Declaration : Dsymbol enum nounderscore = 4; // don't prepend _ to mangled name enum hidden = 8; // don't print this in .di files - Symbol* isym; // import version of csym - // overridden symbol with pragma(mangle, "...") const(char)[] mangleOverride; diff --git a/gcc/d/dmd/declaration.h b/gcc/d/dmd/declaration.h index adbc26b..0e327be 100644 --- a/gcc/d/dmd/declaration.h +++ b/gcc/d/dmd/declaration.h @@ -1,6 +1,6 @@ /* Compiler implementation of the D programming language - * Copyright (C) 1999-2023 by The D Language Foundation, All Rights Reserved + * Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved * written by Walter Bright * https://www.digitalmars.com * Distributed under the Boost Software License, Version 1.0. @@ -54,7 +54,7 @@ struct AttributeViolation; #define STCforeach 0x4000ULL /// variable for foreach loop #define STCvariadic 0x8000ULL /// the `variadic` parameter in: T foo(T a, U b, V variadic...) - // 0x10000ULL + #define STCconstscoperef 0x10000ULL /// when `in` means const|scope|ref #define STCtemplateparameter 0x20000ULL /// template parameter #define STCref 0x40000ULL /// `ref` #define STCscope 0x80000ULL /// `scope` @@ -118,7 +118,6 @@ public: LINK _linkage; // may be `LINK::system`; use `resolvedLinkage()` to resolve it short inuse; // used to detect cycles uint8_t adFlags; - Symbol* isym; // import version of csym DString mangleOverride; // overridden symbol with pragma(mangle, "...") const char *kind() const override; @@ -843,6 +842,7 @@ public: class SharedStaticCtorDeclaration final : public StaticCtorDeclaration { public: + bool standalone; SharedStaticCtorDeclaration *syntaxCopy(Dsymbol *) override; SharedStaticCtorDeclaration *isSharedStaticCtorDeclaration() override { return this; } diff --git a/gcc/d/dmd/delegatize.d b/gcc/d/dmd/delegatize.d index 490ef56..62800d3 100644 --- a/gcc/d/dmd/delegatize.d +++ b/gcc/d/dmd/delegatize.d @@ -3,7 +3,7 @@ * * Specification: $(LINK2 https://dlang.org/spec/function.html#lazy-params, Lazy Parameters) * - * Copyright: Copyright (C) 1999-2023 by The D Language Foundation, All Rights Reserved + * Copyright: Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved * Authors: $(LINK2 https://www.digitalmars.com, Walter Bright) * License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/delegatize.d, _delegatize.d) diff --git a/gcc/d/dmd/denum.d b/gcc/d/dmd/denum.d index 5713be1..5464ff9 100644 --- a/gcc/d/dmd/denum.d +++ b/gcc/d/dmd/denum.d @@ -3,7 +3,7 @@ * * Specification: $(LINK2 https://dlang.org/spec/enum.html, Enums) * - * Copyright: Copyright (C) 1999-2023 by The D Language Foundation, All Rights Reserved + * Copyright: Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved * Authors: $(LINK2 https://www.digitalmars.com, Walter Bright) * License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/denum.d, _denum.d) @@ -83,7 +83,7 @@ extern (C++) final class EnumDeclaration : ScopeDsymbol return ed; } - override bool oneMember(Dsymbol* ps, Identifier ident) + override bool oneMember(out Dsymbol ps, Identifier ident) { if (isAnonymous()) return Dsymbol.oneMembers(members, ps, ident); diff --git a/gcc/d/dmd/dimport.d b/gcc/d/dmd/dimport.d index 51b9220..b083c03 100644 --- a/gcc/d/dmd/dimport.d +++ b/gcc/d/dmd/dimport.d @@ -1,7 +1,7 @@ /** * A `Dsymbol` representing a renamed import. * - * Copyright: Copyright (C) 1999-2023 by The D Language Foundation, All Rights Reserved + * Copyright: Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved * Authors: $(LINK2 https://www.digitalmars.com, Walter Bright) * License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/dimport.d, _dimport.d) diff --git a/gcc/d/dmd/dinterpret.d b/gcc/d/dmd/dinterpret.d index 90352e3..eda91d1 100644 --- a/gcc/d/dmd/dinterpret.d +++ b/gcc/d/dmd/dinterpret.d @@ -3,7 +3,7 @@ * * Specification: ($LINK2 https://dlang.org/spec/function.html#interpretation, Compile Time Function Execution (CTFE)) * - * Copyright: Copyright (C) 1999-2023 by The D Language Foundation, All Rights Reserved + * Copyright: Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved * Authors: $(LINK2 https://www.digitalmars.com, Walter Bright) * License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/dinterpret.d, _dinterpret.d) diff --git a/gcc/d/dmd/dmacro.d b/gcc/d/dmd/dmacro.d index 6e6c4b1..c04fbec 100644 --- a/gcc/d/dmd/dmacro.d +++ b/gcc/d/dmd/dmacro.d @@ -1,7 +1,7 @@ /** * Text macro processor for Ddoc. * - * Copyright: Copyright (C) 1999-2023 by The D Language Foundation, All Rights Reserved + * Copyright: Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved * Authors: $(LINK2 https://www.digitalmars.com, Walter Bright) * License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/dmacro.d, _dmacro.d) diff --git a/gcc/d/dmd/dmangle.d b/gcc/d/dmd/dmangle.d index 2bedccb..15b77ea 100644 --- a/gcc/d/dmd/dmangle.d +++ b/gcc/d/dmd/dmangle.d @@ -3,7 +3,7 @@ * * Specification: $(LINK2 https://dlang.org/spec/abi.html#name_mangling, Name Mangling) * - * Copyright: Copyright (C) 1999-2023 by The D Language Foundation, All Rights Reserved + * Copyright: Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved * Authors: Walter Bright, https://www.digitalmars.com * License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/dmangle.d, _dmangle.d) @@ -528,7 +528,7 @@ void mangleParameter(Parameter p, ref OutBuffer buf, ref Backref backref) if (stc & STC.return_) buf.writestring("Nk"); // return - switch (stc & (STC.IOR | STC.lazy_)) + switch (stc & ((STC.IOR | STC.lazy_) & ~STC.constscoperef)) { case 0: break; diff --git a/gcc/d/dmd/dmodule.d b/gcc/d/dmd/dmodule.d index 6c9e90a..022231c 100644 --- a/gcc/d/dmd/dmodule.d +++ b/gcc/d/dmd/dmodule.d @@ -3,7 +3,7 @@ * * Specification: $(LINK2 https://dlang.org/spec/module.html, Modules) * - * Copyright: Copyright (C) 1999-2023 by The D Language Foundation, All Rights Reserved + * Copyright: Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved * Authors: $(LINK2 https://www.digitalmars.com, Walter Bright) * License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/dmodule.d, _dmodule.d) diff --git a/gcc/d/dmd/doc.d b/gcc/d/dmd/doc.d index 03848c0..810642f 100644 --- a/gcc/d/dmd/doc.d +++ b/gcc/d/dmd/doc.d @@ -3,7 +3,7 @@ * * Specification: $(LINK2 https://dlang.org/spec/ddoc.html, Documentation Generator) * - * Copyright: Copyright (C) 1999-2023 by The D Language Foundation, All Rights Reserved + * Copyright: Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved * Authors: $(LINK2 https://www.digitalmars.com, Walter Bright) * License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/doc.d, _doc.d) @@ -1296,7 +1296,7 @@ void toDocBuffer(Dsymbol s, ref OutBuffer buf, Scope* sc) Type origType = d.originalType ? d.originalType : d.type; if (origType.ty == Tfunction) { - functionToBufferFull(cast(TypeFunction)origType, *buf, d.ident, &hgs, td); + functionToBufferFull(cast(TypeFunction)origType, *buf, d.ident, hgs, td); } else toCBuffer(origType, *buf, d.ident, hgs); diff --git a/gcc/d/dmd/doc.h b/gcc/d/dmd/doc.h index ebd3094..71a66b9 100644 --- a/gcc/d/dmd/doc.h +++ b/gcc/d/dmd/doc.h @@ -1,6 +1,6 @@ /* Compiler implementation of the D programming language - * Copyright (C) 1999-2023 by The D Language Foundation, All Rights Reserved + * Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved * written by Walter Bright * https://www.digitalmars.com * Distributed under the Boost Software License, Version 1.0. diff --git a/gcc/d/dmd/dscope.d b/gcc/d/dmd/dscope.d index cd177a6..7e9499f 100644 --- a/gcc/d/dmd/dscope.d +++ b/gcc/d/dmd/dscope.d @@ -3,7 +3,7 @@ * * Not to be confused with the `scope` storage class. * - * Copyright: Copyright (C) 1999-2023 by The D Language Foundation, All Rights Reserved + * Copyright: Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved * Authors: $(LINK2 https://www.digitalmars.com, Walter Bright) * License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/dscope.d, _dscope.d) diff --git a/gcc/d/dmd/dstruct.d b/gcc/d/dmd/dstruct.d index 0e0a1f5..5683d5f 100644 --- a/gcc/d/dmd/dstruct.d +++ b/gcc/d/dmd/dstruct.d @@ -3,7 +3,7 @@ * * Specification: $(LINK2 https://dlang.org/spec/struct.html, Structs, Unions) * - * Copyright: Copyright (C) 1999-2023 by The D Language Foundation, All Rights Reserved + * Copyright: Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved * Authors: $(LINK2 https://www.digitalmars.com, Walter Bright) * License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/dstruct.d, _dstruct.d) @@ -434,7 +434,11 @@ extern (C++) class StructDeclaration : AggregateDeclaration ispod = ThreeState.yes; - if (enclosing || postblit || dtor || hasCopyCtor) + import dmd.clone; + bool hasCpCtorLocal; + needCopyCtor(this, hasCpCtorLocal); + + if (enclosing || search(this, loc, Id.postblit) || search(this, loc, Id.dtor) || hasCpCtorLocal) { ispod = ThreeState.no; return false; diff --git a/gcc/d/dmd/dsymbol.d b/gcc/d/dmd/dsymbol.d index 6613c2b..5e7922e 100644 --- a/gcc/d/dmd/dsymbol.d +++ b/gcc/d/dmd/dsymbol.d @@ -1,7 +1,7 @@ /** * The base class for a D symbol, which can be a module, variable, function, enum, etc. * - * Copyright: Copyright (C) 1999-2023 by The D Language Foundation, All Rights Reserved + * Copyright: Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved * Authors: $(LINK2 https://www.digitalmars.com, Walter Bright) * License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/dsymbol.d, _dsymbol.d) @@ -845,27 +845,27 @@ extern (C++) class Dsymbol : ASTNode /************************************** * Determine if this symbol is only one. * Returns: - * false, *ps = NULL: There are 2 or more symbols - * true, *ps = NULL: There are zero symbols - * true, *ps = symbol: The one and only one symbol + * false, ps = null: There are 2 or more symbols + * true, ps = null: There are zero symbols + * true, ps = symbol: The one and only one symbol */ - bool oneMember(Dsymbol* ps, Identifier ident) + bool oneMember(out Dsymbol ps, Identifier ident) { //printf("Dsymbol::oneMember()\n"); - *ps = this; + ps = this; return true; } /***************************************** * Same as Dsymbol::oneMember(), but look at an array of Dsymbols. */ - extern (D) static bool oneMembers(Dsymbols* members, Dsymbol* ps, Identifier ident) + extern (D) static bool oneMembers(Dsymbols* members, out Dsymbol ps, Identifier ident) { //printf("Dsymbol::oneMembers() %d\n", members ? members.length : 0); Dsymbol s = null; if (!members) { - *ps = null; + ps = null; return true; } @@ -877,21 +877,21 @@ extern (C++) class Dsymbol : ASTNode if (!x) { //printf("\tfalse 1\n"); - assert(*ps is null); + assert(ps is null); return false; } - if (*ps) + if (ps) { assert(ident); - if (!(*ps).ident || !(*ps).ident.equals(ident)) + if (!ps.ident || !ps.ident.equals(ident)) continue; if (!s) - s = *ps; - else if (s.isOverloadable() && (*ps).isOverloadable()) + s = ps; + else if (s.isOverloadable() && ps.isOverloadable()) { // keep head of overload set FuncDeclaration f1 = s.isFuncDeclaration(); - FuncDeclaration f2 = (*ps).isFuncDeclaration(); + FuncDeclaration f2 = ps.isFuncDeclaration(); if (f1 && f2) { assert(!f1.isFuncAliasDeclaration()); @@ -908,13 +908,13 @@ extern (C++) class Dsymbol : ASTNode } else // more than one symbol { - *ps = null; + ps = null; //printf("\tfalse 2\n"); return false; } } } - *ps = s; // s is the one symbol, null if none + ps = s; // s is the one symbol, null if none //printf("\ttrue\n"); return true; } diff --git a/gcc/d/dmd/dsymbol.h b/gcc/d/dmd/dsymbol.h index d029c00..7d715b4 100644 --- a/gcc/d/dmd/dsymbol.h +++ b/gcc/d/dmd/dsymbol.h @@ -1,6 +1,6 @@ /* Compiler implementation of the D programming language - * Copyright (C) 1999-2023 by The D Language Foundation, All Rights Reserved + * Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved * written by Walter Bright * https://www.digitalmars.com * Distributed under the Boost Software License, Version 1.0. @@ -246,7 +246,7 @@ public: virtual bool needThis(); // need a 'this' pointer? virtual Visibility visible(); virtual Dsymbol *syntaxCopy(Dsymbol *s); // copy only syntax trees - virtual bool oneMember(Dsymbol **ps, Identifier *ident); + virtual bool oneMember(Dsymbol *&ps, Identifier *ident); virtual bool hasPointers(); virtual bool hasStaticCtorOrDtor(); virtual void addObjcSymbols(ClassDeclarations *, ClassDeclarations *) { } diff --git a/gcc/d/dmd/dsymbolsem.d b/gcc/d/dmd/dsymbolsem.d index df0a9a5..23f0bc5 100644 --- a/gcc/d/dmd/dsymbolsem.d +++ b/gcc/d/dmd/dsymbolsem.d @@ -2,7 +2,7 @@ * Does the semantic 1 pass on the AST, which looks at symbol declarations but not initializers * or function bodies. * - * Copyright: Copyright (C) 1999-2023 by The D Language Foundation, All Rights Reserved + * Copyright: Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved * Authors: $(LINK2 https://www.digitalmars.com, Walter Bright) * License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/dsymbolsem.d, _dsymbolsem.d) @@ -947,7 +947,7 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor // At this point we can add `scope` to the STC instead of `in`, // because we are never going to use this variable's STC for user messages - if (dsym.storage_class & STC.in_ && global.params.previewIn) + if (dsym.storage_class & STC.constscoperef) dsym.storage_class |= STC.scope_; if (dsym.storage_class & STC.scope_) @@ -2964,7 +2964,7 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor if (tempdecl.members) { Dsymbol s; - if (Dsymbol.oneMembers(tempdecl.members, &s, tempdecl.ident) && s) + if (Dsymbol.oneMembers(tempdecl.members, s, tempdecl.ident) && s) { tempdecl.onemember = s; s.parent = tempdecl; @@ -4096,7 +4096,7 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor auto fd = s.isFuncDeclaration(); functionToBufferFull(cast(TypeFunction)(funcdecl.type), buf, - new Identifier(funcdecl.toPrettyChars()), &hgs, null); + new Identifier(funcdecl.toPrettyChars()), hgs, null); const(char)* funcdeclToChars = buf.peekChars(); if (fd) @@ -4119,7 +4119,7 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor else { functionToBufferFull(cast(TypeFunction)(fd.type), buf1, - new Identifier(fd.toPrettyChars()), &hgs, null); + new Identifier(fd.toPrettyChars()), hgs, null); error(funcdecl.loc, "function `%s` does not override any function, did you mean to override `%s`?", funcdeclToChars, buf1.peekChars()); @@ -4592,6 +4592,24 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor m.needmoduleinfo = 1; //printf("module1 %s needs moduleinfo\n", m.toChars()); } + + foreachUda(scd, sc, (Expression e) { + import dmd.attrib : isEnumAttribute; + if (!isEnumAttribute(e, Id.udaStandalone)) + return 0; + + if (auto sharedCtor = scd.isSharedStaticCtorDeclaration()) + { + auto trust = sharedCtor.type.isTypeFunction().trust; + if (trust != TRUST.system && trust != TRUST.trusted) + error(e.loc, "a module constructor using `@%s` must be `@system` or `@trusted`", Id.udaStandalone.toChars()); + sharedCtor.standalone = true; + } + else + .error(e.loc, "`@%s` can only be used on shared static constructors", Id.udaStandalone.toChars()); + + return 1; + }); } override void visit(StaticDtorDeclaration sdd) @@ -4831,9 +4849,15 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor { if (ts.sym != sd) { - auto ti = ts.sym.isInstantiated(); + TemplateInstance ti = ts.sym.isInstantiated(); if (ti && isError(ti)) ts.sym = sd; + /* For C modules, if module A contains `struct S;` and + * module B contains `struct S { members...}` then replace + * the former with the latter + */ + else if (!ts.sym.members && sd.members) + ts.sym = sd; } } @@ -5357,7 +5381,7 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor cldec.classKind = ClassKind.cpp; if (cldec.classKind != cldec.baseClass.classKind) .error(cldec.loc, "%s `%s` with %s linkage cannot inherit from class `%s` with %s linkage", cldec.kind, cldec.toPrettyChars, - cldec.classKind.toChars(), cldec.baseClass.toChars(), cldec.baseClass.classKind.toChars()); + ClassKindToChars(cldec.classKind), cldec.baseClass.toChars(), ClassKindToChars(cldec.baseClass.classKind)); if (cldec.baseClass.stack) cldec.stack = true; @@ -6807,7 +6831,7 @@ void templateInstanceSemantic(TemplateInstance tempinst, Scope* sc, ArgumentList if (tempinst.members.length) { Dsymbol s; - if (Dsymbol.oneMembers(tempinst.members, &s, tempdecl.ident) && s) + if (Dsymbol.oneMembers(tempinst.members, s, tempdecl.ident) && s) { //printf("tempdecl.ident = %s, s = `%s %s`\n", tempdecl.ident.toChars(), s.kind(), s.toPrettyChars()); //printf("setting aliasdecl\n"); @@ -6852,7 +6876,7 @@ void templateInstanceSemantic(TemplateInstance tempinst, Scope* sc, ArgumentList if (tempinst.members.length) { Dsymbol s; - if (Dsymbol.oneMembers(tempinst.members, &s, tempdecl.ident) && s) + if (Dsymbol.oneMembers(tempinst.members, s, tempdecl.ident) && s) { if (!tempinst.aliasdecl || tempinst.aliasdecl != s) { diff --git a/gcc/d/dmd/dtemplate.d b/gcc/d/dmd/dtemplate.d index e440b9e..1d84ccd 100644 --- a/gcc/d/dmd/dtemplate.d +++ b/gcc/d/dmd/dtemplate.d @@ -28,7 +28,7 @@ * arguments, and uses it if found. * - Otherwise, the rest of semantic is run on the `TemplateInstance`. * - * Copyright: Copyright (C) 1999-2023 by The D Language Foundation, All Rights Reserved + * Copyright: Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved * Authors: $(LINK2 https://www.digitalmars.com, Walter Bright) * License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/dtemplate.d, _dtemplate.d) @@ -615,7 +615,7 @@ extern (C++) final class TemplateDeclaration : ScopeDsymbol return; Dsymbol s; - if (!Dsymbol.oneMembers(members, &s, ident) || !s) + if (!Dsymbol.oneMembers(members, s, ident) || !s) return; onemember = s; @@ -6029,9 +6029,9 @@ extern (C++) class TemplateInstance : ScopeDsymbol return "template instance"; } - override bool oneMember(Dsymbol* ps, Identifier ident) + override bool oneMember(out Dsymbol ps, Identifier ident) { - *ps = null; + ps = null; return true; } @@ -7599,7 +7599,7 @@ extern (C++) class TemplateInstance : ScopeDsymbol if (members.length) { Dsymbol sa; - if (Dsymbol.oneMembers(members, &sa, tempdecl.ident) && sa) + if (Dsymbol.oneMembers(members, sa, tempdecl.ident) && sa) aliasdecl = sa; } done = true; @@ -7820,7 +7820,7 @@ extern (C++) final class TemplateMixin : TemplateInstance return "mixin"; } - override bool oneMember(Dsymbol* ps, Identifier ident) + override bool oneMember(out Dsymbol ps, Identifier ident) { return Dsymbol.oneMember(ps, ident); } diff --git a/gcc/d/dmd/dtoh.d b/gcc/d/dmd/dtoh.d index ed83a8d..30991c9 100644 --- a/gcc/d/dmd/dtoh.d +++ b/gcc/d/dmd/dtoh.d @@ -2,7 +2,7 @@ * This module contains the implementation of the C++ header generation available through * the command line switch -Hc. * - * Copyright: Copyright (C) 1999-2023 by The D Language Foundation, All Rights Reserved + * Copyright: Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved * Authors: $(LINK2 https://www.digitalmars.com, Walter Bright) * License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/dtohd, _dtoh.d) diff --git a/gcc/d/dmd/dversion.d b/gcc/d/dmd/dversion.d index 31725c8..2e3b352 100644 --- a/gcc/d/dmd/dversion.d +++ b/gcc/d/dmd/dversion.d @@ -4,7 +4,7 @@ * Specification: $(LINK2 https://dlang.org/spec/version.html#version-specification, Version Specification), * $(LINK2 https://dlang.org/spec/version.html#debug_specification, Debug Specification). * - * Copyright: Copyright (C) 1999-2023 by The D Language Foundation, All Rights Reserved + * Copyright: Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved * Authors: $(LINK2 https://www.digitalmars.com, Walter Bright) * License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/dversion.d, _dversion.d) diff --git a/gcc/d/dmd/entity.d b/gcc/d/dmd/entity.d index c31883f..af74c3b 100644 --- a/gcc/d/dmd/entity.d +++ b/gcc/d/dmd/entity.d @@ -3,7 +3,7 @@ * * Specification $(LINK2 https://dlang.org/spec/entity.html, Named Character Entities) * - * Copyright: Copyright (C) 1999-2023 by The D Language Foundation, All Rights Reserved + * Copyright: Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved * Authors: $(LINK2 https://www.digitalmars.com, Walter Bright) * License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/entity.d, _entity.d) diff --git a/gcc/d/dmd/enum.h b/gcc/d/dmd/enum.h index 5f91ead..a4bb588 100644 --- a/gcc/d/dmd/enum.h +++ b/gcc/d/dmd/enum.h @@ -1,6 +1,6 @@ /* Compiler implementation of the D programming language - * Copyright (C) 1999-2023 by The D Language Foundation, All Rights Reserved + * Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved * written by Walter Bright * https://www.digitalmars.com * Distributed under the Boost Software License, Version 1.0. @@ -46,7 +46,7 @@ public: bool inuse(bool v); EnumDeclaration *syntaxCopy(Dsymbol *s) override; - bool oneMember(Dsymbol **ps, Identifier *ident) override; + bool oneMember(Dsymbol *&ps, Identifier *ident) override; Type *getType() override; const char *kind() const override; bool isDeprecated() const override; // is Dsymbol deprecated? diff --git a/gcc/d/dmd/errors.d b/gcc/d/dmd/errors.d index 542b97b..79efc6e 100644 --- a/gcc/d/dmd/errors.d +++ b/gcc/d/dmd/errors.d @@ -1,7 +1,7 @@ /** * Functions for raising errors. * - * Copyright: Copyright (C) 1999-2023 by The D Language Foundation, All Rights Reserved + * Copyright: Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved * Authors: $(LINK2 https://www.digitalmars.com, Walter Bright) * License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/errors.d, _errors.d) diff --git a/gcc/d/dmd/errors.h b/gcc/d/dmd/errors.h index 759ad27..308e81e 100644 --- a/gcc/d/dmd/errors.h +++ b/gcc/d/dmd/errors.h @@ -1,6 +1,6 @@ /* Compiler implementation of the D programming language - * Copyright (C) 1999-2023 by The D Language Foundation, All Rights Reserved + * Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved * written by Walter Bright * https://www.digitalmars.com * Distributed under the Boost Software License, Version 1.0. diff --git a/gcc/d/dmd/errorsink.d b/gcc/d/dmd/errorsink.d index 3811f1d..afea689 100644 --- a/gcc/d/dmd/errorsink.d +++ b/gcc/d/dmd/errorsink.d @@ -1,7 +1,7 @@ /** * Provides an abstraction for what to do with error messages. * - * Copyright: Copyright (C) 2023 by The D Language Foundation, All Rights Reserved + * Copyright: Copyright (C) 2023-2024 by The D Language Foundation, All Rights Reserved * Authors: $(LINK2 https://www.digitalmars.com, Walter Bright) * License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/errorsink.d, _errorsink.d) diff --git a/gcc/d/dmd/escape.d b/gcc/d/dmd/escape.d index f928b08..433907a 100644 --- a/gcc/d/dmd/escape.d +++ b/gcc/d/dmd/escape.d @@ -1,7 +1,7 @@ /** * Most of the logic to implement scoped pointers and scoped references is here. * - * Copyright: Copyright (C) 1999-2023 by The D Language Foundation, All Rights Reserved + * Copyright: Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved * Authors: $(LINK2 https://www.digitalmars.com, Walter Bright) * License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/escape.d, _escape.d) @@ -1296,7 +1296,7 @@ private bool checkReturnEscapeImpl(Scope* sc, Expression e, bool refs, bool gag) { if (log) { - printf("byref `%s` %s\n", v.toChars(), toChars(buildScopeRef(v.storage_class))); + printf("byref `%s` %s\n", v.toChars(), ScopeRefToChars(buildScopeRef(v.storage_class))); } // 'featureState' tells us whether to emit an error or a deprecation, diff --git a/gcc/d/dmd/expression.d b/gcc/d/dmd/expression.d index f51a8b0..41eeff9 100644 --- a/gcc/d/dmd/expression.d +++ b/gcc/d/dmd/expression.d @@ -3,7 +3,7 @@ * * Specification: ($LINK2 https://dlang.org/spec/expression.html, Expressions) * - * Copyright: Copyright (C) 1999-2023 by The D Language Foundation, All Rights Reserved + * Copyright: Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved * Authors: $(LINK2 https://www.digitalmars.com, Walter Bright) * License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/expression.d, _expression.d) @@ -420,10 +420,7 @@ extern (C++) abstract class Expression : ASTNode override const(char)* toChars() const { - OutBuffer buf; - HdrGenState hgs; - toCBuffer(this, buf, hgs); - return buf.extractChars(); + return .toChars(this); } /********************************** diff --git a/gcc/d/dmd/expression.h b/gcc/d/dmd/expression.h index b4ace74b..f57f6a4 100644 --- a/gcc/d/dmd/expression.h +++ b/gcc/d/dmd/expression.h @@ -1,6 +1,6 @@ /* Compiler implementation of the D programming language - * Copyright (C) 1999-2023 by The D Language Foundation, All Rights Reserved + * Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved * written by Walter Bright * https://www.digitalmars.com * Distributed under the Boost Software License, Version 1.0. @@ -434,7 +434,7 @@ public: union { - Symbol *sym; // back end symbol to initialize with literal + Symbol *sym; // back end symbol to initialize with literal (used as a Symbol*) // those fields need to prevent a infinite recursion when one field of struct initialized with 'this' pointer. StructLiteralExp *inlinecopy; diff --git a/gcc/d/dmd/expressionsem.d b/gcc/d/dmd/expressionsem.d index c21b382..9ce6f4d 100644 --- a/gcc/d/dmd/expressionsem.d +++ b/gcc/d/dmd/expressionsem.d @@ -3,7 +3,7 @@ * * Specification: ($LINK2 https://dlang.org/spec/expression.html, Expressions) * - * Copyright: Copyright (C) 1999-2023 by The D Language Foundation, All Rights Reserved + * Copyright: Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved * Authors: $(LINK2 https://www.digitalmars.com, Walter Bright) * License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/expressionsem.d, _expressionsem.d) @@ -6813,11 +6813,14 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor { if (sc.func.fes) { - deprecation(e.loc, "%s `%s` is shadowing %s `%s`. Rename the `foreach` variable.", s.kind(), s.ident.toChars(), s2.kind(), s2.toPrettyChars()); + deprecation(e.loc, "%s `%s` is shadowing %s `%s`", s.kind(), s.ident.toChars(), s2.kind(), s2.toPrettyChars()); + deprecationSupplemental(s2.loc, "declared here"); + } else { error(e.loc, "%s `%s` is shadowing %s `%s`", s.kind(), s.ident.toChars(), s2.kind(), s2.toPrettyChars()); + errorSupplemental(s2.loc, "declared here"); return setError(); } } @@ -7592,6 +7595,13 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor { printf("AssertExp::semantic('%s')\n", exp.toChars()); } + if (auto e = exp.e1.isStringExp()) + { + // deprecated in 2.107 + deprecation(e.loc, "assert condition cannot be a string literal"); + deprecationSupplemental(e.loc, "If intentional, use `%s !is null` instead to preserve behaviour", + e.toChars()); + } const generateMsg = !exp.msg && sc.needsCodegen() && // let ctfe interpreter handle the error message @@ -15037,6 +15047,8 @@ bool checkSharedAccess(Expression e, Scope* sc, bool returnRef = false) */ Expression resolveLoc(Expression exp, const ref Loc loc, Scope* sc) { + exp.loc = loc; + Expression visit(Expression exp) { if (auto unaExp = exp.isUnaExp()) @@ -15044,7 +15056,6 @@ Expression resolveLoc(Expression exp, const ref Loc loc, Scope* sc) unaExp.e1 = unaExp.e1.resolveLoc(loc, sc); return unaExp; } - exp.loc = loc; return exp; } diff --git a/gcc/d/dmd/file_manager.d b/gcc/d/dmd/file_manager.d index a0e5d05..eaef8d5 100644 --- a/gcc/d/dmd/file_manager.d +++ b/gcc/d/dmd/file_manager.d @@ -1,7 +1,7 @@ /** * Read a file from disk and store it in memory. * - * Copyright: Copyright (C) 1999-2023 by The D Language Foundation, All Rights Reserved + * Copyright: Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved * License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/file_manager.d, _file_manager.d) * Documentation: https://dlang.org/phobos/dmd_file_manager.html @@ -10,6 +10,7 @@ module dmd.file_manager; +import core.stdc.stdio; import dmd.root.stringtable : StringTable; import dmd.root.file : File, Buffer; import dmd.root.filename : FileName, isDirSeparator; @@ -281,63 +282,103 @@ nothrow: return fb; } - /** - * Looks up the given filename from the internal file buffer table, and returns the lines within the file. - * If the file does not already exist within the table, it will be read from the filesystem. - * If it has been read before, - * - * Returns: the loaded source file if it was found in memory, - * otherwise `null` + /********************************** + * Take `text` and turn it into an InputRange that emits + * slices into `text` for each line. + * Params: + * text = array of characters + * Returns: + * InputRange accessing `text` as a sequence of lines + * Reference: + * `std.string.splitLines()` */ - const(char)[][] getLines(FileName file) + auto splitLines(const char[] text) { - const(char)[][] lines; - if (const buffer = lookup(file)) + struct Range { - const slice = buffer; - size_t start, end; - for (auto i = 0; i < slice.length; i++) + @safe: + @nogc: + nothrow: + pure: + private: + + const char[] text; + size_t index; // index of start of line + size_t eolIndex; // index of end of line before newline characters + size_t nextIndex; // index past end of line + + public this(const char[] text) + { + this.text = text; + } + + public bool empty() { return index == text.length; } + + public void popFront() { advance(); index = nextIndex; } + + public const(char)[] front() { advance(); return text[index .. eolIndex]; } + + private void advance() { - const c = slice[i]; - if (c == '\n' || c == '\r') + if (index != nextIndex) // if already advanced + return; + + for (size_t i = index; i < text.length; ++i) { - if (i != 0) - { - end = i; - // Appending lines one at a time will certainly be slow - lines ~= cast(const(char)[])slice[start .. end]; - } - // Check for Windows-style CRLF newlines - if (c == '\r') + switch (text[i]) { - if (slice.length > i + 1 && slice[i + 1] == '\n') - { - // This is a CRLF sequence, skip over two characters - start = i + 2; - i++; - } - else - { - // Just a CR sequence - start = i + 1; - } - } - else - { - // The next line should start after the LF sequence - start = i + 1; + case '\v', '\f', '\n': + eolIndex = i; + nextIndex = i + 1; + return; + + case '\r': + if (i + 1 < text.length && text[i + 1] == '\n') // decode "\r\n" + { + eolIndex = i; + nextIndex = i + 2; + return; + } + eolIndex = i; + nextIndex = i + 1; + return; + + /* Manually decode: + * NEL is C2 85 + */ + case 0xC2: + if (i + 1 < text.length && text[i + 1] == 0x85) + { + eolIndex = i; + nextIndex = i + 2; + return; + } + break; + + /* Manually decode: + * lineSep is E2 80 A8 + * paraSep is E2 80 A9 + */ + case 0xE2: + if (i + 2 < text.length && + text[i + 1] == 0x80 && + (text[i + 2] == 0xA8 || text[i + 2] == 0xA9) + ) + { + eolIndex = i; + nextIndex = i + 3; + return; + } + break; + + default: + break; } } } - - if (slice[$ - 1] != '\r' && slice[$ - 1] != '\n') - { - end = slice.length; - lines ~= cast(const(char)[])slice[start .. end]; - } } - return lines; + return Range(text); } /** diff --git a/gcc/d/dmd/foreachvar.d b/gcc/d/dmd/foreachvar.d index dc4b20b..53b3c04 100644 --- a/gcc/d/dmd/foreachvar.d +++ b/gcc/d/dmd/foreachvar.d @@ -1,7 +1,7 @@ /** * Utility to visit every variable in an expression. * - * Copyright: Copyright (C) 1999-2023 by The D Language Foundation, All Rights Reserved + * Copyright: Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved * Authors: $(LINK2 https://www.digitalmars.com, Walter Bright) * License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/foreachvar.d, _foreachvar.d) diff --git a/gcc/d/dmd/func.d b/gcc/d/dmd/func.d index feaa5bb..242b4dc 100644 --- a/gcc/d/dmd/func.d +++ b/gcc/d/dmd/func.d @@ -8,7 +8,7 @@ * - `invariant` * - `unittest` * - * Copyright: Copyright (C) 1999-2023 by The D Language Foundation, All Rights Reserved + * Copyright: Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved * Authors: $(LINK2 https://www.digitalmars.com, Walter Bright) * License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/func.d, _func.d) @@ -4253,6 +4253,9 @@ extern (C++) class StaticCtorDeclaration : FuncDeclaration */ extern (C++) final class SharedStaticCtorDeclaration : StaticCtorDeclaration { + /// Exclude this constructor from cyclic dependency check + bool standalone; + extern (D) this(const ref Loc loc, const ref Loc endloc, StorageClass stc) { super(loc, endloc, "_sharedStaticCtor", stc); diff --git a/gcc/d/dmd/globals.d b/gcc/d/dmd/globals.d index 9257bc4..b60a3f8 100644 --- a/gcc/d/dmd/globals.d +++ b/gcc/d/dmd/globals.d @@ -1,7 +1,7 @@ /** * Stores command line options and contains other miscellaneous declarations. * - * Copyright: Copyright (C) 1999-2023 by The D Language Foundation, All Rights Reserved + * Copyright: Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved * Authors: $(LINK2 https://www.digitalmars.com, Walter Bright) * License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/globals.d, _globals.d) @@ -275,7 +275,7 @@ extern (C++) struct Global { const(char)[] inifilename; /// filename of configuration file as given by `-conf=`, or default value - string copyright = "Copyright (C) 1999-2023 by The D Language Foundation, All Rights Reserved"; + string copyright = "Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved"; string written = "written by Walter Bright"; Array!(const(char)*)* path; /// Array of char*'s which form the import lookup path diff --git a/gcc/d/dmd/globals.h b/gcc/d/dmd/globals.h index 4284f85..c71d2f0 100644 --- a/gcc/d/dmd/globals.h +++ b/gcc/d/dmd/globals.h @@ -1,6 +1,6 @@ /* Compiler implementation of the D programming language - * Copyright (C) 1999-2023 by The D Language Foundation, All Rights Reserved + * Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved * written by Walter Bright * https://www.digitalmars.com * Distributed under the Boost Software License, Version 1.0. diff --git a/gcc/d/dmd/gluelayer.d b/gcc/d/dmd/gluelayer.d index 756c0e5..b3980eb 100644 --- a/gcc/d/dmd/gluelayer.d +++ b/gcc/d/dmd/gluelayer.d @@ -3,7 +3,7 @@ * * This 'glues' either the DMC or GCC back-end to the front-end. * - * Copyright: Copyright (C) 1999-2023 by The D Language Foundation, All Rights Reserved + * Copyright: Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved * Authors: $(LINK2 https://www.digitalmars.com, Walter Bright) * License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/gluelayer.d, _gluelayer.d) diff --git a/gcc/d/dmd/hdrgen.d b/gcc/d/dmd/hdrgen.d index 0944ade..570c662 100644 --- a/gcc/d/dmd/hdrgen.d +++ b/gcc/d/dmd/hdrgen.d @@ -3,7 +3,7 @@ * * Also used to convert AST nodes to D code in general, e.g. for error messages or `printf` debugging. * - * Copyright: Copyright (C) 1999-2023 by The D Language Foundation, All Rights Reserved + * Copyright: Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved * Authors: $(LINK2 https://www.digitalmars.com, Walter Bright) * License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/hdrgen.d, _hdrgen.d) @@ -35,7 +35,6 @@ import dmd.dtemplate; import dmd.dversion; import dmd.expression; import dmd.func; -import dmd.globals; import dmd.id; import dmd.identifier; import dmd.init; @@ -50,7 +49,6 @@ import dmd.rootobject; import dmd.root.string; import dmd.statement; import dmd.staticassert; -import dmd.target; import dmd.tokens; import dmd.visitor; @@ -60,6 +58,8 @@ struct HdrGenState bool ddoc; /// true if generating Ddoc file bool fullDump; /// true if generating a full AST dump file bool importcHdr; /// true if generating a .di file from an ImportC file + bool doFuncBodies; /// include function bodies in output + bool vcg_ast; /// write out codegen-ast bool fullQual; /// fully qualify types when printing int tpltMember; @@ -78,9 +78,10 @@ enum TEST_EMIT_ALL = 0; * Generate a header (.di) file for Module m. * Params: * m = Module to generate header for + * doFuncBodies = generate function definitions rather than just declarations * buf = buffer to write the data to */ -extern (C++) void genhdrfile(Module m, ref OutBuffer buf) +extern (C++) void genhdrfile(Module m, bool doFuncBodies, ref OutBuffer buf) { buf.doindent = 1; buf.printf("// D import file generated from '%s'", m.srcfile.toChars()); @@ -88,6 +89,7 @@ extern (C++) void genhdrfile(Module m, ref OutBuffer buf) HdrGenState hgs; hgs.hdrgen = true; hgs.importcHdr = (m.filetype == FileType.c); + hgs.doFuncBodies = doFuncBodies; toCBuffer(m, buf, hgs); } @@ -108,6 +110,14 @@ public extern (C++) const(char)* toChars(const Statement s) return buf.extractSlice().ptr; } +public extern (C++) const(char)* toChars(const Expression e) +{ + HdrGenState hgs; + OutBuffer buf; + toCBuffer(e, buf, hgs); + return buf.extractChars(); +} + public extern (C++) const(char)* toChars(const Initializer i) { OutBuffer buf; @@ -116,6 +126,17 @@ public extern (C++) const(char)* toChars(const Initializer i) return buf.extractChars(); } +public extern (C++) const(char)* toChars(const Type t) +{ + OutBuffer buf; + buf.reserve(16); + HdrGenState hgs; + hgs.fullQual = (t.ty == Tclass && !t.mod); + + toCBuffer(t, buf, null, hgs); + return buf.extractChars(); +} + public const(char)[] toString(const Initializer i) { OutBuffer buf; @@ -128,16 +149,18 @@ public const(char)[] toString(const Initializer i) * Dumps the full contents of module `m` to `buf`. * Params: * buf = buffer to write to. + * vcg_ast = write out codegen ast * m = module to visit all members of. */ -extern (C++) void moduleToBuffer(ref OutBuffer buf, Module m) +extern (C++) void moduleToBuffer(ref OutBuffer buf, bool vcg_ast, Module m) { HdrGenState hgs; hgs.fullDump = true; + hgs.vcg_ast = vcg_ast; toCBuffer(m, buf, hgs); } -void moduleToBuffer2(Module m, ref OutBuffer buf, HdrGenState* hgs) +void moduleToBuffer2(Module m, ref OutBuffer buf, ref HdrGenState hgs) { if (m.md) { @@ -171,7 +194,7 @@ void moduleToBuffer2(Module m, ref OutBuffer buf, HdrGenState* hgs) } } -private void statementToBuffer(Statement s, ref OutBuffer buf, HdrGenState* hgs) +private void statementToBuffer(Statement s, ref OutBuffer buf, ref HdrGenState hgs) { void visitDefaultCase(Statement s) { @@ -240,7 +263,7 @@ private void statementToBuffer(Statement s, ref OutBuffer buf, HdrGenState* hgs) auto d = ds.exp.isDeclarationExp().declaration; if (auto v = d.isVarDeclaration()) { - visitVarDecl(v, anywritten, buf, *hgs); + visitVarDecl(v, anywritten, buf, hgs); } else d.dsymbolToBuffer(buf, hgs); @@ -803,7 +826,7 @@ private void statementToBuffer(Statement s, ref OutBuffer buf, HdrGenState* hgs) buf.level++; while (t) { - buf.writestring(t.toChars()); + buf.writestring(t.toString()); if (t.next && t.value != TOK.min && t.value != TOK.comma && t.next.value != TOK.comma && @@ -844,9 +867,9 @@ private void statementToBuffer(Statement s, ref OutBuffer buf, HdrGenState* hgs) visit.VisitStatement(s); } -private void dsymbolToBuffer(Dsymbol s, ref OutBuffer buf, HdrGenState* hgs) +private void dsymbolToBuffer(Dsymbol s, ref OutBuffer buf, ref HdrGenState hgs) { - toCBuffer(s, buf, *hgs); + toCBuffer(s, buf, hgs); } void toCBuffer(Dsymbol s, ref OutBuffer buf, ref HdrGenState hgs) @@ -860,13 +883,13 @@ void toCBuffer(Dsymbol s, ref OutBuffer buf, ref HdrGenState hgs) { buf.writestring(s.kind()); buf.writeByte('('); - s.exp.expressionToBuffer(buf, &hgs); + s.exp.expressionToBuffer(buf, hgs); if (s.msgs) { foreach (m; (*s.msgs)[]) { buf.writestring(", "); - m.expressionToBuffer(buf, &hgs); + m.expressionToBuffer(buf, hgs); } } buf.writestring(");"); @@ -898,13 +921,13 @@ void toCBuffer(Dsymbol s, ref OutBuffer buf, ref HdrGenState hgs) void visitEnumMember(EnumMember em) { if (em.type) - typeToBuffer(em.type, em.ident, buf, &hgs); + typeToBuffer(em.type, em.ident, buf, hgs); else buf.writestring(em.ident.toString()); if (em.value) { buf.writestring(" = "); - em.value.expressionToBuffer(buf, &hgs); + em.value.expressionToBuffer(buf, hgs); } } @@ -921,7 +944,8 @@ void toCBuffer(Dsymbol s, ref OutBuffer buf, ref HdrGenState hgs) } foreach (const pid; imp.packages) { - buf.printf("%s.", pid.toChars()); + buf.write(pid.toString()); + buf.writeByte('.'); } buf.writestring(imp.id.toString()); if (imp.names.length) @@ -997,7 +1021,7 @@ void toCBuffer(Dsymbol s, ref OutBuffer buf, ref HdrGenState hgs) void visitDeprecatedDeclaration(DeprecatedDeclaration d) { buf.writestring("deprecated("); - d.msg.expressionToBuffer(buf, &hgs); + d.msg.expressionToBuffer(buf, hgs); buf.writestring(") "); visitAttribDeclaration(d); } @@ -1050,7 +1074,9 @@ void toCBuffer(Dsymbol s, ref OutBuffer buf, ref HdrGenState hgs) { if (i) buf.writeByte(' '); - buf.printf("align (%s)", exp.toChars()); + buf.writestring("align ("); + toCBuffer(exp, buf, hgs); + buf.writeByte(')'); } if (d.decl && d.decl.length < 2) buf.writeByte(' '); @@ -1085,7 +1111,7 @@ void toCBuffer(Dsymbol s, ref OutBuffer buf, ref HdrGenState hgs) if (d.args && d.args.length) { buf.writestring(", "); - argsToBuffer(d.args, buf, &hgs); + argsToBuffer(d.args, buf, hgs); } buf.writeByte(')'); @@ -1093,17 +1119,17 @@ void toCBuffer(Dsymbol s, ref OutBuffer buf, ref HdrGenState hgs) // https://issues.dlang.org/show_bug.cgi?id=14690 // Unconditionally perform a full output dump // for `pragma(inline)` declarations. - bool savedFullDump = global.params.dihdr.fullOutput; + const saved = hgs.doFuncBodies; if (d.ident == Id.Pinline) - global.params.dihdr.fullOutput = true; + hgs.doFuncBodies = true; visitAttribDeclaration(d); - global.params.dihdr.fullOutput = savedFullDump; + hgs.doFuncBodies = saved; } void visitConditionalDeclaration(ConditionalDeclaration d) { - d.condition.conditionToBuffer(buf, &hgs); + d.condition.conditionToBuffer(buf, hgs); if (d.decl || d.elsedecl) { buf.writenl(); @@ -1149,12 +1175,12 @@ void toCBuffer(Dsymbol s, ref OutBuffer buf, ref HdrGenState hgs) if (stcToBuffer(buf, p.storageClass)) buf.writeByte(' '); if (p.type) - typeToBuffer(p.type, p.ident, buf, &hgs); + typeToBuffer(p.type, p.ident, buf, hgs); else buf.writestring(p.ident.toString()); } buf.writestring("; "); - s.aggr.expressionToBuffer(buf, &hgs); + s.aggr.expressionToBuffer(buf, hgs); buf.writeByte(')'); buf.writenl(); } @@ -1166,13 +1192,13 @@ void toCBuffer(Dsymbol s, ref OutBuffer buf, ref HdrGenState hgs) buf.writestring(Token.toString(s.op)); buf.writestring(" ("); if (s.prm.type) - typeToBuffer(s.prm.type, s.prm.ident, buf, &hgs); + typeToBuffer(s.prm.type, s.prm.ident, buf, hgs); else buf.writestring(s.prm.ident.toString()); buf.writestring("; "); - s.lwr.expressionToBuffer(buf, &hgs); + s.lwr.expressionToBuffer(buf, hgs); buf.writestring(" .. "); - s.upr.expressionToBuffer(buf, &hgs); + s.upr.expressionToBuffer(buf, hgs); buf.writeByte(')'); buf.writenl(); } @@ -1200,7 +1226,7 @@ void toCBuffer(Dsymbol s, ref OutBuffer buf, ref HdrGenState hgs) void visitMixinDeclaration(MixinDeclaration d) { buf.writestring("mixin("); - argsToBuffer(d.exps, buf, &hgs, null); + argsToBuffer(d.exps, buf, hgs, null); buf.writestring(");"); buf.writenl(); } @@ -1208,7 +1234,7 @@ void toCBuffer(Dsymbol s, ref OutBuffer buf, ref HdrGenState hgs) void visitUserAttributeDeclaration(UserAttributeDeclaration d) { buf.writestring("@("); - argsToBuffer(d.atts, buf, &hgs); + argsToBuffer(d.atts, buf, hgs); buf.writeByte(')'); visitAttribDeclaration(d); } @@ -1218,7 +1244,7 @@ void toCBuffer(Dsymbol s, ref OutBuffer buf, ref HdrGenState hgs) if (!constraint) return; buf.writestring(" if ("); - constraint.expressionToBuffer(buf, &hgs); + constraint.expressionToBuffer(buf, hgs); buf.writeByte(')'); } @@ -1236,7 +1262,7 @@ void toCBuffer(Dsymbol s, ref OutBuffer buf, ref HdrGenState hgs) { assert(es.exp && es.exp.op == EXP.assert_); buf.writestring(" ("); - (cast(AssertExp)es.exp).e1.expressionToBuffer(buf, &hgs); + (cast(AssertExp)es.exp).e1.expressionToBuffer(buf, hgs); buf.writeByte(')'); buf.writenl(); requireDo = false; @@ -1244,7 +1270,7 @@ void toCBuffer(Dsymbol s, ref OutBuffer buf, ref HdrGenState hgs) else { buf.writenl(); - frequire.statementToBuffer(buf, &hgs); + frequire.statementToBuffer(buf, hgs); requireDo = true; } } @@ -1264,7 +1290,7 @@ void toCBuffer(Dsymbol s, ref OutBuffer buf, ref HdrGenState hgs) buf.writestring(fensure.id.toString()); } buf.writestring("; "); - (cast(AssertExp)es.exp).e1.expressionToBuffer(buf, &hgs); + (cast(AssertExp)es.exp).e1.expressionToBuffer(buf, hgs); buf.writeByte(')'); buf.writenl(); requireDo = false; @@ -1278,7 +1304,7 @@ void toCBuffer(Dsymbol s, ref OutBuffer buf, ref HdrGenState hgs) buf.writeByte(')'); } buf.writenl(); - fensure.ensure.statementToBuffer(buf, &hgs); + fensure.ensure.statementToBuffer(buf, hgs); requireDo = true; } } @@ -1288,7 +1314,7 @@ void toCBuffer(Dsymbol s, ref OutBuffer buf, ref HdrGenState hgs) void bodyToBuffer(FuncDeclaration f) { - if (!f.fbody || (hgs.hdrgen && global.params.dihdr.fullOutput == false && !hgs.autoMember && !hgs.tpltMember && !hgs.insideFuncBody)) + if (!f.fbody || (hgs.hdrgen && hgs.doFuncBodies == false && !hgs.autoMember && !hgs.tpltMember && !hgs.insideFuncBody)) { if (!f.fbody && (f.fensures || f.frequires)) { @@ -1326,7 +1352,7 @@ void toCBuffer(Dsymbol s, ref OutBuffer buf, ref HdrGenState hgs) buf.writeByte('{'); buf.writenl(); buf.level++; - f.fbody.statementToBuffer(buf, &hgs); + f.fbody.statementToBuffer(buf, hgs); buf.level--; buf.writeByte('}'); buf.writenl(); @@ -1344,7 +1370,7 @@ void toCBuffer(Dsymbol s, ref OutBuffer buf, ref HdrGenState hgs) { if (i) buf.writestring(", "); - typeToBuffer(b.type, null, buf, &hgs); + typeToBuffer(b.type, null, buf, hgs); } } @@ -1360,7 +1386,7 @@ void toCBuffer(Dsymbol s, ref OutBuffer buf, ref HdrGenState hgs) assert(fd.type); if (stcToBuffer(buf, fd.storage_class)) buf.writeByte(' '); - functionToBufferFull(cast(TypeFunction)fd.type, buf, d.ident, &hgs, d); + functionToBufferFull(cast(TypeFunction)fd.type, buf, d.ident, hgs, d); visitTemplateConstraint(d.constraint); hgs.tpltMember++; bodyToBuffer(fd); @@ -1402,7 +1428,7 @@ void toCBuffer(Dsymbol s, ref OutBuffer buf, ref HdrGenState hgs) if (stcToBuffer(buf, vd.storage_class)) buf.writeByte(' '); if (vd.type) - typeToBuffer(vd.type, vd.ident, buf, &hgs); + typeToBuffer(vd.type, vd.ident, buf, hgs); else buf.writestring(vd.ident.toString()); buf.writeByte('('); @@ -1413,9 +1439,9 @@ void toCBuffer(Dsymbol s, ref OutBuffer buf, ref HdrGenState hgs) buf.writestring(" = "); ExpInitializer ie = vd._init.isExpInitializer(); if (ie && (ie.exp.op == EXP.construct || ie.exp.op == EXP.blit)) - (cast(AssignExp)ie.exp).e2.expressionToBuffer(buf, &hgs); + (cast(AssignExp)ie.exp).e2.expressionToBuffer(buf, hgs); else - vd._init.initializerToBuffer(buf, &hgs); + vd._init.initializerToBuffer(buf, hgs); } buf.writeByte(';'); buf.writenl(); @@ -1463,21 +1489,21 @@ void toCBuffer(Dsymbol s, ref OutBuffer buf, ref HdrGenState hgs) void visitTemplateInstance(TemplateInstance ti) { buf.writestring(ti.name.toChars()); - tiargsToBuffer(ti, buf, &hgs); + tiargsToBuffer(ti, buf, hgs); if (hgs.fullDump) { buf.writenl(); - dumpTemplateInstance(ti, buf, &hgs); + dumpTemplateInstance(ti, buf, hgs); } } void visitTemplateMixin(TemplateMixin tm) { buf.writestring("mixin "); - typeToBuffer(tm.tqual, null, buf, &hgs); - tiargsToBuffer(tm, buf, &hgs); - if (tm.ident && memcmp(tm.ident.toChars(), cast(const(char)*)"__mixin", 7) != 0) + typeToBuffer(tm.tqual, null, buf, hgs); + tiargsToBuffer(tm, buf, hgs); + if (tm.ident && memcmp(tm.ident.toString().ptr, cast(const(char)*) "__mixin", 7) != 0) { buf.writeByte(' '); buf.writestring(tm.ident.toString()); @@ -1485,7 +1511,7 @@ void toCBuffer(Dsymbol s, ref OutBuffer buf, ref HdrGenState hgs) buf.writeByte(';'); buf.writenl(); if (hgs.fullDump) - dumpTemplateInstance(tm, buf, &hgs); + dumpTemplateInstance(tm, buf, hgs); } void visitEnumDeclaration(EnumDeclaration d) @@ -1501,7 +1527,7 @@ void toCBuffer(Dsymbol s, ref OutBuffer buf, ref HdrGenState hgs) if (d.memtype) { buf.writestring(" : "); - typeToBuffer(d.memtype, null, buf, &hgs); + typeToBuffer(d.memtype, null, buf, hgs); } if (!d.members) { @@ -1649,7 +1675,7 @@ void toCBuffer(Dsymbol s, ref OutBuffer buf, ref HdrGenState hgs) { if (stcToBuffer(buf, d.storage_class)) buf.writeByte(' '); - typeToBuffer(d.type, d.ident, buf, &hgs); + typeToBuffer(d.type, d.ident, buf, hgs); } else if (d.ident) { @@ -1658,7 +1684,7 @@ void toCBuffer(Dsymbol s, ref OutBuffer buf, ref HdrGenState hgs) buf.writestring(" = "); if (stcToBuffer(buf, d.storage_class)) buf.writeByte(' '); - typeToBuffer(d.type, null, buf, &hgs); + typeToBuffer(d.type, null, buf, hgs); hgs.declstring = false; } buf.writeByte(';'); @@ -1672,7 +1698,7 @@ void toCBuffer(Dsymbol s, ref OutBuffer buf, ref HdrGenState hgs) if (d.aliassym) toCBuffer(d.aliassym, buf, hgs); else // d.type - typeToBuffer(d.type, null, buf, &hgs); + typeToBuffer(d.type, null, buf, hgs); buf.writeByte(';'); buf.writenl(); } @@ -1692,7 +1718,7 @@ void toCBuffer(Dsymbol s, ref OutBuffer buf, ref HdrGenState hgs) if (stcToBuffer(buf, f.storage_class)) buf.writeByte(' '); auto tf = f.type.isTypeFunction(); - typeToBuffer(tf, f.ident, buf, &hgs); + typeToBuffer(tf, f.ident, buf, hgs); if (hgs.hdrgen) { @@ -1706,7 +1732,7 @@ void toCBuffer(Dsymbol s, ref OutBuffer buf, ref HdrGenState hgs) bodyToBuffer(f); hgs.autoMember--; } - else if (hgs.tpltMember == 0 && global.params.dihdr.fullOutput == false && !hgs.insideFuncBody) + else if (hgs.tpltMember == 0 && hgs.doFuncBodies == false && !hgs.insideFuncBody) { if (!f.fbody) { @@ -1740,8 +1766,8 @@ void toCBuffer(Dsymbol s, ref OutBuffer buf, ref HdrGenState hgs) TypeFunction tf = cast(TypeFunction)f.type; if (!f.inferRetType && tf.next) - typeToBuffer(tf.next, null, buf, &hgs); - parametersToBuffer(tf.parameterList, buf, &hgs); + typeToBuffer(tf.next, null, buf, hgs); + parametersToBuffer(tf.parameterList, buf, hgs); // https://issues.dlang.org/show_bug.cgi?id=20074 void printAttribute(string str) @@ -1764,7 +1790,7 @@ void toCBuffer(Dsymbol s, ref OutBuffer buf, ref HdrGenState hgs) if (rs && rs.exp) { buf.writestring(" => "); - rs.exp.expressionToBuffer(buf, &hgs); + rs.exp.expressionToBuffer(buf, hgs); } else { @@ -1833,7 +1859,7 @@ void toCBuffer(Dsymbol s, ref OutBuffer buf, ref HdrGenState hgs) { assert(es.exp && es.exp.op == EXP.assert_); buf.writestring(" ("); - (cast(AssertExp)es.exp).e1.expressionToBuffer(buf, &hgs); + (cast(AssertExp)es.exp).e1.expressionToBuffer(buf, hgs); buf.writestring(");"); buf.writenl(); } @@ -1858,9 +1884,9 @@ void toCBuffer(Dsymbol s, ref OutBuffer buf, ref HdrGenState hgs) if (stcToBuffer(buf, d.storage_class)) buf.writeByte(' '); Identifier id = d.isAnonymous() ? null : d.ident; - typeToBuffer(d.type, id, buf, &hgs); + typeToBuffer(d.type, id, buf, hgs); buf.writestring(" : "); - d.width.expressionToBuffer(buf, &hgs); + d.width.expressionToBuffer(buf, hgs); buf.writeByte(';'); buf.writenl(); } @@ -1874,7 +1900,7 @@ void toCBuffer(Dsymbol s, ref OutBuffer buf, ref HdrGenState hgs) void visitModule(Module m) { - moduleToBuffer2(m, buf, &hgs); + moduleToBuffer2(m, buf, hgs); } extern (C++) @@ -1963,9 +1989,9 @@ private void visitVarDecl(VarDeclaration v, bool anywritten, ref OutBuffer buf, { auto ie = v._init.isExpInitializer(); if (ie && (ie.exp.op == EXP.construct || ie.exp.op == EXP.blit)) - (cast(AssignExp)ie.exp).e2.expressionToBuffer(buf, &hgs); + (cast(AssignExp)ie.exp).e2.expressionToBuffer(buf, hgs); else - v._init.initializerToBuffer(buf, &hgs); + v._init.initializerToBuffer(buf, hgs); } const commentIt = hgs.importcHdr && isSpecialCName(v.ident); @@ -1988,7 +2014,7 @@ private void visitVarDecl(VarDeclaration v, bool anywritten, ref OutBuffer buf, if (stcToBuffer(buf, stc)) buf.writeByte(' '); if (v.type) - typeToBuffer(v.type, v.ident, buf, &hgs); + typeToBuffer(v.type, v.ident, buf, hgs); else if (useTypeof) { buf.writestring("typeof("); @@ -2033,7 +2059,7 @@ private bool isSpecialCName(Identifier id) /********************************************* * Print expression to buffer. */ -private void expressionPrettyPrint(Expression e, ref OutBuffer buf, HdrGenState* hgs) +private void expressionPrettyPrint(Expression e, ref OutBuffer buf, ref HdrGenState hgs) { void visit(Expression e) { @@ -2042,7 +2068,7 @@ private void expressionPrettyPrint(Expression e, ref OutBuffer buf, HdrGenState* void visitInteger(IntegerExp e) { - const dinteger_t v = e.toInteger(); + const ulong v = e.toInteger(); if (e.type) { Type t = e.type; @@ -2059,7 +2085,8 @@ private void expressionPrettyPrint(Expression e, ref OutBuffer buf, HdrGenState* { if ((cast(EnumMember)em).value.toInteger == v) { - buf.printf("%s.%s", sym.toChars(), em.ident.toChars()); + const id = em.ident.toString(); + buf.printf("%s.%.*s", sym.toChars(), cast(int)id.length, id.ptr); return ; } } @@ -2119,15 +2146,13 @@ private void expressionPrettyPrint(Expression e, ref OutBuffer buf, HdrGenState* break; case Tpointer: buf.writestring("cast("); - buf.writestring(t.toChars()); - buf.writeByte(')'); - if (target.ptrsize == 8) - goto case Tuns64; - else if (target.ptrsize == 4 || - target.ptrsize == 2) - goto case Tuns32; - else - assert(0); + + HdrGenState hgs2; // should re-examine need for new hgs + hgs2.fullQual = (t.ty == Tclass && !t.mod); + toCBuffer(t, buf, null, hgs2); + + buf.writestring(")cast(size_t)"); + goto case Tuns64; case Tvoid: buf.writestring("cast(void)0"); @@ -2136,11 +2161,8 @@ private void expressionPrettyPrint(Expression e, ref OutBuffer buf, HdrGenState* default: /* This can happen if errors, such as * the type is painted on like in fromConstInitializer(). + * Just ignore */ - if (!global.errors) - { - assert(0); - } break; } } @@ -2286,7 +2308,7 @@ private void expressionPrettyPrint(Expression e, ref OutBuffer buf, HdrGenState* { e.sds.dsymbolToBuffer(buf, hgs); } - else if (hgs !is null && hgs.ddoc) + else if (hgs.ddoc) { // fixes bug 6491 if (auto m = e.sds.isModule()) @@ -2403,7 +2425,7 @@ private void expressionPrettyPrint(Expression e, ref OutBuffer buf, HdrGenState* // which isn't correct as regular D code. buf.writeByte('('); - visitVarDecl(var, false, buf, *hgs); + visitVarDecl(var, false, buf, hgs); buf.writeByte(';'); buf.writeByte(')'); @@ -2446,7 +2468,10 @@ private void expressionPrettyPrint(Expression e, ref OutBuffer buf, HdrGenState* typeToBuffer(e.targ, e.id, buf, hgs); if (e.tok2 != TOK.reserved) { - buf.printf(" %s %s", Token.toChars(e.tok), Token.toChars(e.tok2)); + buf.writeByte(' '); + buf.writestring(Token.toString(e.tok)); + buf.writeByte(' '); + buf.writestring(Token.toString(e.tok2)); } else if (e.tspec) { @@ -2459,7 +2484,7 @@ private void expressionPrettyPrint(Expression e, ref OutBuffer buf, HdrGenState* if (e.parameters && e.parameters.length) { buf.writestring(", "); - visitTemplateParameters(e.parameters, buf, *hgs); + visitTemplateParameters(e.parameters, buf, hgs); } buf.writeByte(')'); } @@ -2472,7 +2497,7 @@ private void expressionPrettyPrint(Expression e, ref OutBuffer buf, HdrGenState* void visitLoweredAssignExp(LoweredAssignExp e) { - if (global.params.vcg_ast) + if (hgs.vcg_ast) { expressionToBuffer(e.lowering, buf, hgs); return; @@ -2937,12 +2962,12 @@ public: if (tp.specType) { buf.writestring(" : "); - typeToBuffer(tp.specType, null, *buf, hgs); + typeToBuffer(tp.specType, null, *buf, *hgs); } if (tp.defaultType) { buf.writestring(" = "); - typeToBuffer(tp.defaultType, null, *buf, hgs); + typeToBuffer(tp.defaultType, null, *buf, *hgs); } } @@ -2956,33 +2981,33 @@ public: { buf.writestring("alias "); if (tp.specType) - typeToBuffer(tp.specType, tp.ident, *buf, hgs); + typeToBuffer(tp.specType, tp.ident, *buf, *hgs); else buf.writestring(tp.ident.toString()); if (tp.specAlias) { buf.writestring(" : "); - objectToBuffer(tp.specAlias, *buf, hgs); + objectToBuffer(tp.specAlias, *buf, *hgs); } if (tp.defaultAlias) { buf.writestring(" = "); - objectToBuffer(tp.defaultAlias, *buf, hgs); + objectToBuffer(tp.defaultAlias, *buf, *hgs); } } override void visit(TemplateValueParameter tp) { - typeToBuffer(tp.valType, tp.ident, *buf, hgs); + typeToBuffer(tp.valType, tp.ident, *buf, *hgs); if (tp.specValue) { buf.writestring(" : "); - tp.specValue.expressionToBuffer(*buf, hgs); + tp.specValue.expressionToBuffer(*buf, *hgs); } if (tp.defaultValue) { buf.writestring(" = "); - tp.defaultValue.expressionToBuffer(*buf, hgs); + tp.defaultValue.expressionToBuffer(*buf, *hgs); } } @@ -2993,9 +3018,9 @@ public: } } -private void conditionToBuffer(Condition c, ref OutBuffer buf, HdrGenState* hgs) +private void conditionToBuffer(Condition c, ref OutBuffer buf, ref HdrGenState hgs) { - scope v = new ConditionPrettyPrintVisitor(&buf, hgs); + scope v = new ConditionPrettyPrintVisitor(&buf, &hgs); c.accept(v); } @@ -3035,19 +3060,19 @@ public: override void visit(StaticIfCondition c) { buf.writestring("static if ("); - c.exp.expressionToBuffer(*buf, hgs); + c.exp.expressionToBuffer(*buf, *hgs); buf.writeByte(')'); } } void toCBuffer(const Statement s, ref OutBuffer buf, ref HdrGenState hgs) { - (cast()s).statementToBuffer(buf, &hgs); + (cast()s).statementToBuffer(buf, hgs); } void toCBuffer(const Type t, ref OutBuffer buf, const Identifier ident, ref HdrGenState hgs) { - typeToBuffer(cast() t, ident, buf, &hgs); + typeToBuffer(cast() t, ident, buf, hgs); } // used from TemplateInstance::toChars() and TemplateMixin::toChars() @@ -3057,12 +3082,12 @@ void toCBufferInstance(const TemplateInstance ti, ref OutBuffer buf, bool qualif hgs.fullQual = qualifyTypes; buf.writestring(ti.name.toChars()); - tiargsToBuffer(cast() ti, buf, &hgs); + tiargsToBuffer(cast() ti, buf, hgs); } void toCBuffer(const Initializer iz, ref OutBuffer buf, ref HdrGenState hgs) { - initializerToBuffer(cast() iz, buf, &hgs); + initializerToBuffer(cast() iz, buf, hgs); } bool stcToBuffer(ref OutBuffer buf, StorageClass stc) @safe @@ -3255,7 +3280,7 @@ extern (D) string visibilityToString(Visibility.Kind kind) nothrow pure @safe } // Print the full function signature with correct ident, attributes and template args -void functionToBufferFull(TypeFunction tf, ref OutBuffer buf, const Identifier ident, HdrGenState* hgs, TemplateDeclaration td) +void functionToBufferFull(TypeFunction tf, ref OutBuffer buf, const Identifier ident, ref HdrGenState hgs, TemplateDeclaration td) { //printf("TypeFunction::toCBuffer() this = %p\n", this); visitFuncIdentWithPrefix(tf, ident, td, buf, hgs); @@ -3265,12 +3290,12 @@ void functionToBufferFull(TypeFunction tf, ref OutBuffer buf, const Identifier i void functionToBufferWithIdent(TypeFunction tf, ref OutBuffer buf, const(char)* ident, bool isStatic) { HdrGenState hgs; - visitFuncIdentWithPostfix(tf, ident.toDString(), buf, &hgs, isStatic); + visitFuncIdentWithPostfix(tf, ident.toDString(), buf, hgs, isStatic); } void toCBuffer(const Expression e, ref OutBuffer buf, ref HdrGenState hgs) { - expressionPrettyPrint(cast()e, buf, &hgs); + expressionPrettyPrint(cast()e, buf, hgs); } /************************************************** @@ -3285,7 +3310,7 @@ void argExpTypesToCBuffer(ref OutBuffer buf, Expressions* arguments) { if (i) buf.writestring(", "); - typeToBuffer(arg.type, null, buf, &hgs); + typeToBuffer(arg.type, null, buf, hgs); } } @@ -3298,7 +3323,7 @@ void arrayObjectsToBuffer(ref OutBuffer buf, Objects* objects) { if (i) buf.writestring(", "); - objectToBuffer(o, buf, &hgs); + objectToBuffer(o, buf, hgs); } } @@ -3312,7 +3337,7 @@ extern (C++) const(char)* parametersTypeToChars(ParameterList pl) { OutBuffer buf; HdrGenState hgs; - parametersToBuffer(pl, buf, &hgs); + parametersToBuffer(pl, buf, hgs); return buf.extractChars(); } @@ -3330,7 +3355,7 @@ const(char)* parameterToChars(Parameter parameter, TypeFunction tf, bool fullQua HdrGenState hgs; hgs.fullQual = fullQual; - parameterToBuffer(parameter, buf, &hgs); + parameterToBuffer(parameter, buf, hgs); if (tf.parameterList.varargs == VarArg.typesafe && parameter == tf.parameterList[tf.parameterList.parameters.length - 1]) { @@ -3348,7 +3373,7 @@ const(char)* parameterToChars(Parameter parameter, TypeFunction tf, bool fullQua * hgs = context */ -private void parametersToBuffer(ParameterList pl, ref OutBuffer buf, HdrGenState* hgs) +private void parametersToBuffer(ParameterList pl, ref OutBuffer buf, ref HdrGenState hgs) { buf.writeByte('('); foreach (i; 0 .. pl.length) @@ -3386,7 +3411,7 @@ private void parametersToBuffer(ParameterList pl, ref OutBuffer buf, HdrGenState * buf = buffer to write it to * hgs = context */ -private void parameterToBuffer(Parameter p, ref OutBuffer buf, HdrGenState* hgs) +private void parameterToBuffer(Parameter p, ref OutBuffer buf, ref HdrGenState hgs) { if (p.userAttribDecl) { @@ -3409,7 +3434,7 @@ private void parameterToBuffer(Parameter p, ref OutBuffer buf, HdrGenState* hgs) if (p.storageClass & STC.in_) { buf.writestring("in "); - if (global.params.previewIn && p.storageClass & STC.ref_) + if ((p.storageClass & (STC.constscoperef | STC.ref_)) == (STC.constscoperef | STC.ref_)) stc &= ~STC.ref_; } else if (p.storageClass & STC.lazy_) @@ -3424,14 +3449,15 @@ private void parameterToBuffer(Parameter p, ref OutBuffer buf, HdrGenState* hgs) STC.return_ | STC.returninferred | STC.scope_ | STC.scopeinferred | STC.out_ | STC.ref_ | STC.returnScope))) buf.writeByte(' '); + const(char)[] s; if (p.storageClass & STC.alias_) { if (p.ident) buf.writestring(p.ident.toString()); } - else if (p.type.ty == Tident && - (cast(TypeIdentifier)p.type).ident.toString().length > 3 && - strncmp((cast(TypeIdentifier)p.type).ident.toChars(), "__T", 3) == 0) + else if (p.type.isTypeIdentifier() && + (s = p.type.isTypeIdentifier().ident.toString()).length > 3 && + s[0..3] == "__T") { // print parameter name, instead of undetermined type parameter buf.writestring(p.ident.toString()); @@ -3458,7 +3484,7 @@ private void parameterToBuffer(Parameter p, ref OutBuffer buf, HdrGenState* hgs) * basis = replace `null`s in argument list with this expression (for sparse array literals) * names = if non-null, use these as the names for the arguments */ -private void argsToBuffer(Expressions* expressions, ref OutBuffer buf, HdrGenState* hgs, Expression basis = null, Identifiers* names = null) +private void argsToBuffer(Expressions* expressions, ref OutBuffer buf, ref HdrGenState hgs, Expression basis = null, Identifiers* names = null) { if (!expressions || !expressions.length) return; @@ -3509,26 +3535,23 @@ private void argsToBuffer(Expressions* expressions, ref OutBuffer buf, HdrGenSta } } -private void sizeToBuffer(Expression e, ref OutBuffer buf, HdrGenState* hgs) +private void sizeToBuffer(Expression e, ref OutBuffer buf, ref HdrGenState hgs) { if (e.type == Type.tsize_t) { Expression ex = (e.op == EXP.cast_ ? (cast(CastExp)e).e1 : e); ex = ex.optimize(WANTvalue); - const dinteger_t uval = ex.op == EXP.int64 ? ex.toInteger() : cast(dinteger_t)-1; - if (cast(sinteger_t)uval >= 0) - { - dinteger_t sizemax = void; - if (target.ptrsize == 8) - sizemax = 0xFFFFFFFFFFFFFFFFUL; - else if (target.ptrsize == 4) - sizemax = 0xFFFFFFFFU; - else if (target.ptrsize == 2) - sizemax = 0xFFFFU; - else - assert(0); - if (uval <= sizemax && uval <= 0x7FFFFFFFFFFFFFFFUL) + const ulong uval = ex.op == EXP.int64 ? ex.toInteger() : cast(ulong)-1; + if (cast(long)uval >= 0) + { + if (uval <= 0xFFFFU) + { + buf.print(uval); + return; + } + if (uval <= 0x7FFF_FFFF_FFFF_FFFFUL) { + buf.writestring("cast(size_t)"); buf.print(uval); return; } @@ -3537,7 +3560,7 @@ private void sizeToBuffer(Expression e, ref OutBuffer buf, HdrGenState* hgs) expToBuffer(e, PREC.assign, buf, hgs); } -private void expressionToBuffer(Expression e, ref OutBuffer buf, HdrGenState* hgs) +private void expressionToBuffer(Expression e, ref OutBuffer buf, ref HdrGenState hgs) { expressionPrettyPrint(e, buf, hgs); } @@ -3546,7 +3569,7 @@ private void expressionToBuffer(Expression e, ref OutBuffer buf, HdrGenState* hg * Write expression out to buf, but wrap it * in ( ) if its precedence is less than pr. */ -private void expToBuffer(Expression e, PREC pr, ref OutBuffer buf, HdrGenState* hgs) +private void expToBuffer(Expression e, PREC pr, ref OutBuffer buf, ref HdrGenState hgs) { debug { @@ -3580,7 +3603,7 @@ private void expToBuffer(Expression e, PREC pr, ref OutBuffer buf, HdrGenState* /************************************************** * An entry point to pretty-print type. */ -private void typeToBuffer(Type t, const Identifier ident, ref OutBuffer buf, HdrGenState* hgs, +private void typeToBuffer(Type t, const Identifier ident, ref OutBuffer buf, ref HdrGenState hgs, ubyte modMask = 0) { if (auto tf = t.isTypeFunction()) @@ -3596,7 +3619,7 @@ private void typeToBuffer(Type t, const Identifier ident, ref OutBuffer buf, Hdr } } -private void visitWithMask(Type t, ubyte modMask, ref OutBuffer buf, HdrGenState* hgs) +private void visitWithMask(Type t, ubyte modMask, ref OutBuffer buf, ref HdrGenState hgs) { // Tuples and functions don't use the type constructor syntax if (modMask == t.mod || t.ty == Tfunction || t.ty == Ttuple) @@ -3632,7 +3655,7 @@ private void visitWithMask(Type t, ubyte modMask, ref OutBuffer buf, HdrGenState } -private void dumpTemplateInstance(TemplateInstance ti, ref OutBuffer buf, HdrGenState* hgs) +private void dumpTemplateInstance(TemplateInstance ti, ref OutBuffer buf, ref HdrGenState hgs) { buf.writeByte('{'); buf.writenl(); @@ -3655,7 +3678,7 @@ private void dumpTemplateInstance(TemplateInstance ti, ref OutBuffer buf, HdrGen } -private void tiargsToBuffer(TemplateInstance ti, ref OutBuffer buf, HdrGenState* hgs) +private void tiargsToBuffer(TemplateInstance ti, ref OutBuffer buf, ref HdrGenState hgs) { buf.writeByte('!'); if (ti.nest) @@ -3675,7 +3698,9 @@ private void tiargsToBuffer(TemplateInstance ti, ref OutBuffer buf, HdrGenState* { if (t.equals(Type.tstring) || t.equals(Type.twstring) || t.equals(Type.tdstring) || t.mod == 0 && (t.isTypeBasic() || t.ty == Tident && (cast(TypeIdentifier)t).idents.length == 0)) { - buf.writestring(t.toChars()); + HdrGenState hgs2; // re-examine need for new hgs + hgs2.fullQual = (t.ty == Tclass && !t.mod); + toCBuffer(t, buf, null, hgs2); return; } } @@ -3683,7 +3708,7 @@ private void tiargsToBuffer(TemplateInstance ti, ref OutBuffer buf, HdrGenState* { if (e.op == EXP.int64 || e.op == EXP.float64 || e.op == EXP.null_ || e.op == EXP.string_ || e.op == EXP.this_) { - buf.writestring(e.toChars()); + toCBuffer(e, buf, hgs); return; } } @@ -3704,7 +3729,7 @@ private void tiargsToBuffer(TemplateInstance ti, ref OutBuffer buf, HdrGenState* * This makes a 'pretty' version of the template arguments. * It's analogous to genIdent() which makes a mangled version. */ -private void objectToBuffer(RootObject oarg, ref OutBuffer buf, HdrGenState* hgs) +private void objectToBuffer(RootObject oarg, ref OutBuffer buf, ref HdrGenState hgs) { //printf("objectToBuffer()\n"); /* The logic of this should match what genIdent() does. The _dynamic_cast() @@ -3725,8 +3750,10 @@ private void objectToBuffer(RootObject oarg, ref OutBuffer buf, HdrGenState* hgs } else if (Dsymbol s = isDsymbol(oarg)) { - const p = s.ident ? s.ident.toChars() : s.toChars(); - buf.writestring(p); + if (s.ident) + buf.writestring(s.ident.toString()); + else + buf.writestring(s.toChars()); } else if (auto v = isTuple(oarg)) { @@ -3757,7 +3784,7 @@ private void objectToBuffer(RootObject oarg, ref OutBuffer buf, HdrGenState* hgs } -private void visitFuncIdentWithPostfix(TypeFunction t, const char[] ident, ref OutBuffer buf, HdrGenState* hgs, bool isStatic) +private void visitFuncIdentWithPostfix(TypeFunction t, const char[] ident, ref OutBuffer buf, ref HdrGenState hgs, bool isStatic) { if (t.inuse) { @@ -3802,7 +3829,7 @@ private void visitFuncIdentWithPostfix(TypeFunction t, const char[] ident, ref O } private void visitFuncIdentWithPrefix(TypeFunction t, const Identifier ident, TemplateDeclaration td, - ref OutBuffer buf, HdrGenState* hgs) + ref OutBuffer buf, ref HdrGenState hgs) { if (t.inuse) { @@ -3858,7 +3885,7 @@ private void visitFuncIdentWithPrefix(TypeFunction t, const Identifier ident, Te { if (i) buf.writestring(", "); - toCBuffer(p, buf, *hgs); + toCBuffer(p, buf, hgs); } buf.writeByte(')'); } @@ -3871,7 +3898,7 @@ private void visitFuncIdentWithPrefix(TypeFunction t, const Identifier ident, Te } -private void initializerToBuffer(Initializer inx, ref OutBuffer buf, HdrGenState* hgs) +private void initializerToBuffer(Initializer inx, ref OutBuffer buf, ref HdrGenState hgs) { void visitError(ErrorInitializer iz) { @@ -3944,7 +3971,7 @@ private void initializerToBuffer(Initializer inx, ref OutBuffer buf, HdrGenState if (d.exp) { buf.writeByte('['); - toCBuffer(d.exp, buf, *hgs); + toCBuffer(d.exp, buf, hgs); buf.writeByte(']'); } else @@ -3965,7 +3992,7 @@ private void initializerToBuffer(Initializer inx, ref OutBuffer buf, HdrGenState } -private void typeToBufferx(Type t, ref OutBuffer buf, HdrGenState* hgs) +private void typeToBufferx(Type t, ref OutBuffer buf, ref HdrGenState hgs) { void visitType(Type t) { @@ -4155,13 +4182,13 @@ private void typeToBufferx(Type t, ref OutBuffer buf, HdrGenState* hgs) buf.writestring("const "); if (hgs.importcHdr && t.id) { - buf.writestring(t.id.toChars()); + buf.writestring(t.id.toString()); return; } - buf.writestring(Token.toChars(t.tok)); + buf.writestring(Token.toString(t.tok)); buf.writeByte(' '); if (t.id) - buf.writestring(t.id.toChars()); + buf.writestring(t.id.toString()); if (t.tok == TOK.enum_ && t.base && t.base.ty != TY.Tint32) { buf.writestring(" : "); diff --git a/gcc/d/dmd/hdrgen.h b/gcc/d/dmd/hdrgen.h index e43a355..e38ca56 100644 --- a/gcc/d/dmd/hdrgen.h +++ b/gcc/d/dmd/hdrgen.h @@ -1,6 +1,6 @@ /* Compiler implementation of the D programming language - * Copyright (C) 1999-2023 by The D Language Foundation, All Rights Reserved + * Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved * written by Dave Fladebo * https://www.digitalmars.com * Distributed under the Boost Software License, Version 1.0. @@ -15,7 +15,7 @@ class Module; -void genhdrfile(Module *m, OutBuffer &buf); +void genhdrfile(Module *m, bool doFuncBodies, OutBuffer &buf); void genCppHdrFiles(Modules &ms); -void moduleToBuffer(OutBuffer& buf, Module *m); +void moduleToBuffer(OutBuffer& buf, bool vcg_ast, Module *m); const char *parametersTypeToChars(ParameterList pl); diff --git a/gcc/d/dmd/iasm.d b/gcc/d/dmd/iasm.d index c58224f..24a4513 100644 --- a/gcc/d/dmd/iasm.d +++ b/gcc/d/dmd/iasm.d @@ -3,7 +3,7 @@ * * Specification: $(LINK2 https://dlang.org/spec/iasm.html, Inline Assembler) * - * Copyright (C) 2018-2023 by The D Language Foundation, All Rights Reserved + * Copyright (C) 2018-2024 by The D Language Foundation, All Rights Reserved * Authors: $(LINK2 https://www.digitalmars.com, Walter Bright) * License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/iasm.d, _iasm.d) diff --git a/gcc/d/dmd/iasmgcc.d b/gcc/d/dmd/iasmgcc.d index 92837b4..db51e73 100644 --- a/gcc/d/dmd/iasmgcc.d +++ b/gcc/d/dmd/iasmgcc.d @@ -1,7 +1,7 @@ /** * Inline assembler for the GCC D compiler. * - * Copyright (C) 2018-2023 by The D Language Foundation, All Rights Reserved + * Copyright (C) 2018-2024 by The D Language Foundation, All Rights Reserved * Authors: Iain Buclaw * License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/iasmgcc.d, _iasmgcc.d) diff --git a/gcc/d/dmd/id.d b/gcc/d/dmd/id.d index 32221d9..a66f2af4 100644 --- a/gcc/d/dmd/id.d +++ b/gcc/d/dmd/id.d @@ -1,7 +1,7 @@ /** * Contains the `Id` struct with a list of predefined symbols the compiler knows about. * - * Copyright: Copyright (C) 1999-2023 by The D Language Foundation, All Rights Reserved + * Copyright: Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved * Authors: $(LINK2 https://www.digitalmars.com, Walter Bright) * License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/id.d, _id.d) @@ -521,6 +521,7 @@ immutable Msgtable[] msgtable = { "udaSelector", "selector" }, { "udaOptional", "optional"}, { "udaMustUse", "mustuse" }, + { "udaStandalone", "standalone" }, // C names, for undefined identifier error messages { "NULL" }, diff --git a/gcc/d/dmd/id.h b/gcc/d/dmd/id.h index f6cf6e5..ddc8da2 100644 --- a/gcc/d/dmd/id.h +++ b/gcc/d/dmd/id.h @@ -1,6 +1,6 @@ /* Compiler implementation of the D programming language - * Copyright (C) 2017-2023 by The D Language Foundation, All Rights Reserved + * Copyright (C) 2017-2024 by The D Language Foundation, All Rights Reserved * written by Walter Bright * https://www.digitalmars.com * Distributed under the Boost Software License, Version 1.0. diff --git a/gcc/d/dmd/identifier.d b/gcc/d/dmd/identifier.d index c2b2fba..8ace310 100644 --- a/gcc/d/dmd/identifier.d +++ b/gcc/d/dmd/identifier.d @@ -1,7 +1,7 @@ /** * Defines an identifier, which is the name of a `Dsymbol`. * - * Copyright: Copyright (C) 1999-2023 by The D Language Foundation, All Rights Reserved + * Copyright: Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved * Authors: $(LINK2 https://www.digitalmars.com, Walter Bright) * License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/identifier.d, _identifier.d) diff --git a/gcc/d/dmd/identifier.h b/gcc/d/dmd/identifier.h index e7b3ba6..afd3664 100644 --- a/gcc/d/dmd/identifier.h +++ b/gcc/d/dmd/identifier.h @@ -1,6 +1,6 @@ /* Compiler implementation of the D programming language - * Copyright (C) 1999-2023 by The D Language Foundation, All Rights Reserved + * Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved * written by Walter Bright * https://www.digitalmars.com * Distributed under the Boost Software License, Version 1.0. diff --git a/gcc/d/dmd/impcnvtab.d b/gcc/d/dmd/impcnvtab.d index b45880a..b899f81 100644 --- a/gcc/d/dmd/impcnvtab.d +++ b/gcc/d/dmd/impcnvtab.d @@ -6,7 +6,7 @@ * Specification: $(LINK2 https://dlang.org/spec/type.html#integer-promotions, Integer Promotions), * $(LINK2 https://dlang.org/spec/type.html#usual-arithmetic-conversions, Usual Arithmetic Conversions). * - * Copyright: Copyright (C) 1999-2023 by The D Language Foundation, All Rights Reserved + * Copyright: Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved * Authors: $(LINK2 https://www.digitalmars.com, Walter Bright) * License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/impcnvtab.d, _impcnvtab.d) diff --git a/gcc/d/dmd/imphint.d b/gcc/d/dmd/imphint.d index 9e9466a..ea2f13d 100644 --- a/gcc/d/dmd/imphint.d +++ b/gcc/d/dmd/imphint.d @@ -3,7 +3,7 @@ * * For example, prompt to `import std.stdio` when using `writeln`. * - * Copyright: Copyright (C) 1999-2023 by The D Language Foundation, All Rights Reserved + * Copyright: Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved * Authors: $(LINK2 https://www.digitalmars.com, Walter Bright) * License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/imphint.d, _imphint.d) diff --git a/gcc/d/dmd/import.h b/gcc/d/dmd/import.h index 2a02f13..bfbb551 100644 --- a/gcc/d/dmd/import.h +++ b/gcc/d/dmd/import.h @@ -1,6 +1,6 @@ /* Compiler implementation of the D programming language - * Copyright (C) 1999-2023 by The D Language Foundation, All Rights Reserved + * Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved * written by Walter Bright * https://www.digitalmars.com * Distributed under the Boost Software License, Version 1.0. diff --git a/gcc/d/dmd/importc.d b/gcc/d/dmd/importc.d index 2c7699b..69a85ce 100644 --- a/gcc/d/dmd/importc.d +++ b/gcc/d/dmd/importc.d @@ -3,7 +3,7 @@ * * Specification: C11 * - * Copyright: Copyright (C) 2021-2023 by The D Language Foundation, All Rights Reserved + * Copyright: Copyright (C) 2021-2024 by The D Language Foundation, All Rights Reserved * Authors: $(LINK2 https://www.digitalmars.com, Walter Bright) * License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/importc.d, _importc.d) diff --git a/gcc/d/dmd/init.d b/gcc/d/dmd/init.d index 5aefb00..62bd41e 100644 --- a/gcc/d/dmd/init.d +++ b/gcc/d/dmd/init.d @@ -1,7 +1,7 @@ /** * Defines initializers of variables, e.g. the array literal in `int[3] x = [0, 1, 2]`. * - * Copyright: Copyright (C) 1999-2023 by The D Language Foundation, All Rights Reserved + * Copyright: Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved * Authors: $(LINK2 https://www.digitalmars.com, Walter Bright) * License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/init.d, _init.d) diff --git a/gcc/d/dmd/init.h b/gcc/d/dmd/init.h index 21bd07f..b4e15e3 100644 --- a/gcc/d/dmd/init.h +++ b/gcc/d/dmd/init.h @@ -1,6 +1,6 @@ /* Compiler implementation of the D programming language - * Copyright (C) 1999-2023 by The D Language Foundation, All Rights Reserved + * Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved * written by Walter Bright * https://www.digitalmars.com * Distributed under the Boost Software License, Version 1.0. diff --git a/gcc/d/dmd/initsem.d b/gcc/d/dmd/initsem.d index 19d576d..5fe3b93 100644 --- a/gcc/d/dmd/initsem.d +++ b/gcc/d/dmd/initsem.d @@ -1,7 +1,7 @@ /** * Semantic analysis of initializers. * - * Copyright: Copyright (C) 1999-2023 by The D Language Foundation, All Rights Reserved + * Copyright: Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved * Authors: $(LINK2 https://www.digitalmars.com, Walter Bright) * License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/initsem.d, _initsem.d) diff --git a/gcc/d/dmd/inline.d b/gcc/d/dmd/inline.d index afab831..3e163ae 100644 --- a/gcc/d/dmd/inline.d +++ b/gcc/d/dmd/inline.d @@ -4,7 +4,7 @@ * The AST is traversed, and every function call is considered for inlining using `inlinecost.d`. * The function call is then inlined if this cost is below a threshold. * - * Copyright: Copyright (C) 1999-2023 by The D Language Foundation, All Rights Reserved + * Copyright: Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved * Authors: $(LINK2 https://www.digitalmars.com, Walter Bright) * License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/inline.d, _inline.d) diff --git a/gcc/d/dmd/intrange.d b/gcc/d/dmd/intrange.d index 442668f..29c8b50 100644 --- a/gcc/d/dmd/intrange.d +++ b/gcc/d/dmd/intrange.d @@ -1,7 +1,7 @@ /** * Implement $(LINK2 https://digitalmars.com/articles/b62.html, Value Range Propagation). * - * Copyright: Copyright (C) 1999-2023 by The D Language Foundation, All Rights Reserved + * Copyright: Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved * Authors: $(LINK2 https://www.digitalmars.com, Walter Bright) * License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/intrange.d, _intrange.d) diff --git a/gcc/d/dmd/json.d b/gcc/d/dmd/json.d index 11ab816..9819c3a 100644 --- a/gcc/d/dmd/json.d +++ b/gcc/d/dmd/json.d @@ -1,7 +1,7 @@ /** * Code for generating .json descriptions of the module when passing the `-X` flag to dmd. * - * Copyright: Copyright (C) 1999-2023 by The D Language Foundation, All Rights Reserved + * Copyright: Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved * Authors: $(LINK2 https://www.digitalmars.com, Walter Bright) * License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/json.d, _json.d) diff --git a/gcc/d/dmd/json.h b/gcc/d/dmd/json.h index 09fdecd..8a94911 100644 --- a/gcc/d/dmd/json.h +++ b/gcc/d/dmd/json.h @@ -1,6 +1,6 @@ /* Compiler implementation of the D programming language - * Copyright (C) 1999-2023 by The D Language Foundation, All Rights Reserved + * Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved * written by Walter Bright * https://www.digitalmars.com * Distributed under the Boost Software License, Version 1.0. diff --git a/gcc/d/dmd/lambdacomp.d b/gcc/d/dmd/lambdacomp.d index c90c360..a1db8d5 100644 --- a/gcc/d/dmd/lambdacomp.d +++ b/gcc/d/dmd/lambdacomp.d @@ -5,7 +5,7 @@ * The serialization is a string which contains the type of the parameters and the string * represantation of the lambda expression. * - * Copyright: Copyright (C) 1999-2023 by The D Language Foundation, All Rights Reserved + * Copyright: Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved * Authors: $(LINK2 https://www.digitalmars.com, Walter Bright) * License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/lamdbacomp.d, _lambdacomp.d) diff --git a/gcc/d/dmd/lexer.d b/gcc/d/dmd/lexer.d index 2c6a595..5eadd72 100644 --- a/gcc/d/dmd/lexer.d +++ b/gcc/d/dmd/lexer.d @@ -3,7 +3,7 @@ * * Specification: $(LINK2 https://dlang.org/spec/lex.html, Lexical) * - * Copyright: Copyright (C) 1999-2023 by The D Language Foundation, All Rights Reserved + * Copyright: Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved * Authors: $(LINK2 https://www.digitalmars.com, Walter Bright) * License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/lexer.d, _lexer.d) diff --git a/gcc/d/dmd/location.d b/gcc/d/dmd/location.d index 9fe48b8..d71ea58 100644 --- a/gcc/d/dmd/location.d +++ b/gcc/d/dmd/location.d @@ -1,7 +1,7 @@ /** * Encapsulates file/line/column locations. * - * Copyright: Copyright (C) 1999-2023 by The D Language Foundation, All Rights Reserved + * Copyright: Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved * Authors: $(LINK2 https://www.digitalmars.com, Walter Bright) * License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/location.d, _location.d) diff --git a/gcc/d/dmd/mangle.h b/gcc/d/dmd/mangle.h index aa24698..68064a9 100644 --- a/gcc/d/dmd/mangle.h +++ b/gcc/d/dmd/mangle.h @@ -1,6 +1,6 @@ /* Compiler implementation of the D programming language - * Copyright (C) 1999-2023 by The D Language Foundation, All Rights Reserved + * Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved * written by Walter Bright * https://www.digitalmars.com * Distributed under the Boost Software License, Version 1.0. diff --git a/gcc/d/dmd/module.h b/gcc/d/dmd/module.h index 80a6ea2..d09e873 100644 --- a/gcc/d/dmd/module.h +++ b/gcc/d/dmd/module.h @@ -1,6 +1,6 @@ /* Compiler implementation of the D programming language - * Copyright (C) 1999-2023 by The D Language Foundation, All Rights Reserved + * Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved * written by Walter Bright * https://www.digitalmars.com * Distributed under the Boost Software License, Version 1.0. diff --git a/gcc/d/dmd/mtype.d b/gcc/d/dmd/mtype.d index 626bf74..4c741cd 100644 --- a/gcc/d/dmd/mtype.d +++ b/gcc/d/dmd/mtype.d @@ -1,7 +1,7 @@ /** * Defines a D type. * - * Copyright: Copyright (C) 1999-2023 by The D Language Foundation, All Rights Reserved + * Copyright: Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved * Authors: $(LINK2 https://www.digitalmars.com, Walter Bright) * License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/mtype.d, _mtype.d) @@ -525,13 +525,7 @@ extern (C++) abstract class Type : ASTNode */ final override const(char)* toChars() const { - OutBuffer buf; - buf.reserve(16); - HdrGenState hgs; - hgs.fullQual = (ty == Tclass && !mod); - - toCBuffer(this, buf, null, hgs); - return buf.extractChars(); + return dmd.hdrgen.toChars(this); } /// ditto @@ -4141,7 +4135,7 @@ extern (C++) final class TypeFunction : TypeNext auto stc = p.storageClass; // When the preview switch is enable, `in` parameters are `scope` - if (stc & STC.in_ && global.params.previewIn) + if (stc & STC.constscoperef) return stc | STC.scope_; if (stc & (STC.scope_ | STC.return_ | STC.lazy_) || purity == PURE.impure) @@ -6433,28 +6427,22 @@ extern (C++) final class Parameter : ASTNode * Params: * returnByRef = true if the function returns by ref * p = Parameter to compare with - * previewIn = Whether `-preview=in` is being used, and thus if - * `in` means `scope [ref]`. - * * Returns: * true = `this` can be used in place of `p` * false = nope */ - bool isCovariant(bool returnByRef, const Parameter p, bool previewIn = global.params.previewIn) + bool isCovariant(bool returnByRef, const Parameter p) const pure nothrow @nogc @safe { ulong thisSTC = this.storageClass; ulong otherSTC = p.storageClass; - if (previewIn) - { - if (thisSTC & STC.in_) - thisSTC |= STC.scope_; - if (otherSTC & STC.in_) - otherSTC |= STC.scope_; - } + if (thisSTC & STC.constscoperef) + thisSTC |= STC.scope_; + if (otherSTC & STC.constscoperef) + otherSTC |= STC.scope_; - const mask = STC.ref_ | STC.out_ | STC.lazy_ | (previewIn ? STC.in_ : 0); + const mask = STC.ref_ | STC.out_ | STC.lazy_ | (((thisSTC | otherSTC) & STC.constscoperef) ? STC.in_ : 0); if ((thisSTC & mask) != (otherSTC & mask)) return false; return isCovariantScope(returnByRef, thisSTC, otherSTC); @@ -6739,7 +6727,7 @@ enum ScopeRef * Returns: * corresponding string */ -const(char)* toChars(ScopeRef sr) pure nothrow @nogc @safe +const(char)* ScopeRefToChars(ScopeRef sr) pure nothrow @nogc @safe { with (ScopeRef) { diff --git a/gcc/d/dmd/mtype.h b/gcc/d/dmd/mtype.h index ef1ce10..97a7ae3 100644 --- a/gcc/d/dmd/mtype.h +++ b/gcc/d/dmd/mtype.h @@ -1,6 +1,6 @@ /* Compiler implementation of the D programming language - * Copyright (C) 1999-2023 by The D Language Foundation, All Rights Reserved + * Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved * written by Walter Bright * https://www.digitalmars.com * Distributed under the Boost Software License, Version 1.0. @@ -39,6 +39,7 @@ typedef union tree_node type; typedef struct TYPE type; #endif +extern const char* toChars(const Type* const t); Type *typeSemantic(Type *t, const Loc &loc, Scope *sc); Type *merge(Type *type); diff --git a/gcc/d/dmd/mustuse.d b/gcc/d/dmd/mustuse.d index 6934649..b5601a2 100644 --- a/gcc/d/dmd/mustuse.d +++ b/gcc/d/dmd/mustuse.d @@ -1,7 +1,7 @@ /** * Compile-time checks associated with the @mustuse attribute. * - * Copyright: Copyright (C) 2022-2023 by The D Language Foundation, All Rights Reserved + * Copyright: Copyright (C) 2022-2024 by The D Language Foundation, All Rights Reserved * License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/mustuse.d, _mustuse.d) * Documentation: https://dlang.org/phobos/dmd_mustuse.html @@ -222,20 +222,7 @@ private bool hasMustUseAttribute(Dsymbol sym, Scope* sc) */ private bool isMustUseAttribute(Expression e) { - import dmd.attrib : isCoreUda; + import dmd.attrib : isEnumAttribute; import dmd.id : Id; - - // Logic based on dmd.objc.Supported.declaredAsOptionalCount - auto typeExp = e.isTypeExp; - if (!typeExp) - return false; - - auto typeEnum = typeExp.type.isTypeEnum(); - if (!typeEnum) - return false; - - if (isCoreUda(typeEnum.sym, Id.udaMustUse)) - return true; - - return false; + return isEnumAttribute(e, Id.udaMustUse); } diff --git a/gcc/d/dmd/nogc.d b/gcc/d/dmd/nogc.d index e59b010..9e45e45 100644 --- a/gcc/d/dmd/nogc.d +++ b/gcc/d/dmd/nogc.d @@ -3,7 +3,7 @@ * * Specification: $(LINK2 https://dlang.org/spec/function.html#nogc-functions, No-GC Functions) * - * Copyright: Copyright (C) 1999-2023 by The D Language Foundation, All Rights Reserved + * Copyright: Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved * Authors: $(LINK2 https://www.digitalmars.com, Walter Bright) * License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/nogc.d, _nogc.d) diff --git a/gcc/d/dmd/nspace.d b/gcc/d/dmd/nspace.d index 65f7d29..52c2b79 100644 --- a/gcc/d/dmd/nspace.d +++ b/gcc/d/dmd/nspace.d @@ -36,7 +36,7 @@ * are valid D identifier. * * See_Also: https://github.com/dlang/dmd/pull/10031 - * Copyright: Copyright (C) 1999-2023 by The D Language Foundation, All Rights Reserved + * Copyright: Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved * Authors: $(LINK2 https://www.digitalmars.com, Walter Bright) * License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/nspace.d, _nspace.d) diff --git a/gcc/d/dmd/nspace.h b/gcc/d/dmd/nspace.h index 4a1bd91..cbee2fb 100644 --- a/gcc/d/dmd/nspace.h +++ b/gcc/d/dmd/nspace.h @@ -1,6 +1,6 @@ /* Compiler implementation of the D programming language - * Copyright (C) 1999-2023 by The D Language Foundation, All Rights Reserved + * Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved * written by Walter Bright * https://www.digitalmars.com * Distributed under the Boost Software License, Version 1.0. diff --git a/gcc/d/dmd/ob.d b/gcc/d/dmd/ob.d index dc94aec..785912e 100644 --- a/gcc/d/dmd/ob.d +++ b/gcc/d/dmd/ob.d @@ -1,7 +1,7 @@ /** * Flow analysis for Ownership/Borrowing * - * Copyright: Copyright (C) 1999-2023 by The D Language Foundation, All Rights Reserved + * Copyright: Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved * Authors: $(LINK2 https://www.digitalmars.com, Walter Bright) * License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/ob.d, _ob.d) @@ -197,7 +197,7 @@ enum PtrState : ubyte /************ */ -const(char)* toChars(PtrState state) +const(char)* PtrStateToChars(PtrState state) { return toString(state).ptr; } @@ -2490,7 +2490,7 @@ void checkObErrors(ref ObState obstate) if (s1 != s2 && (s1 == PtrState.Owner || s2 == PtrState.Owner)) { auto v = obstate.vars[i]; - .error(ob.exp ? ob.exp.loc : v.loc, "%s `%s` is both %s and %s", v.kind, v.toPrettyChars, s1.toChars(), s2.toChars()); + .error(ob.exp ? ob.exp.loc : v.loc, "%s `%s` is both %s and %s", v.kind, v.toPrettyChars, PtrStateToChars(s1), PtrStateToChars(s2)); } pvs1.combine(*pvs2, i, ob.gen); } diff --git a/gcc/d/dmd/objc.d b/gcc/d/dmd/objc.d index 359474c..2f36d5d 100644 --- a/gcc/d/dmd/objc.d +++ b/gcc/d/dmd/objc.d @@ -3,7 +3,7 @@ * * Specification: $(LINK2 https://dlang.org/spec/objc_interface.html, Interfacing to Objective-C) * - * Copyright: Copyright (C) 1999-2023 by The D Language Foundation, All Rights Reserved + * Copyright: Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved * Authors: $(LINK2 https://www.digitalmars.com, Walter Bright) * License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/objc.d, _objc.d) diff --git a/gcc/d/dmd/objc.h b/gcc/d/dmd/objc.h index 40f634e..0390115 100644 --- a/gcc/d/dmd/objc.h +++ b/gcc/d/dmd/objc.h @@ -1,6 +1,6 @@ /* Compiler implementation of the D programming language - * Copyright (C) 2015-2023 by The D Language Foundation, All Rights Reserved + * Copyright (C) 2015-2024 by The D Language Foundation, All Rights Reserved * written by Michel Fortin * https://www.digitalmars.com * Distributed under the Boost Software License, Version 1.0. diff --git a/gcc/d/dmd/opover.d b/gcc/d/dmd/opover.d index b7bc925..d596b84 100644 --- a/gcc/d/dmd/opover.d +++ b/gcc/d/dmd/opover.d @@ -3,7 +3,7 @@ * * Specification: $(LINK2 https://dlang.org/spec/operatoroverloading.html, Operator Overloading) * - * Copyright: Copyright (C) 1999-2023 by The D Language Foundation, All Rights Reserved + * Copyright: Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved * Authors: $(LINK2 https://www.digitalmars.com, Walter Bright) * License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/opover.d, _opover.d) diff --git a/gcc/d/dmd/optimize.d b/gcc/d/dmd/optimize.d index a979168..f86abde 100644 --- a/gcc/d/dmd/optimize.d +++ b/gcc/d/dmd/optimize.d @@ -1,7 +1,7 @@ /** * Perform constant folding. * - * Copyright: Copyright (C) 1999-2023 by The D Language Foundation, All Rights Reserved + * Copyright: Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved * Authors: $(LINK2 https://www.digitalmars.com, Walter Bright) * License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/optimize.d, _optimize.d) diff --git a/gcc/d/dmd/parse.d b/gcc/d/dmd/parse.d index b6f30b9..a012e0c 100644 --- a/gcc/d/dmd/parse.d +++ b/gcc/d/dmd/parse.d @@ -3,7 +3,7 @@ * * Specification: $(LINK2 https://dlang.org/spec/grammar.html, D Grammar) * - * Copyright: Copyright (C) 1999-2023 by The D Language Foundation, All Rights Reserved + * Copyright: Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved * Authors: $(LINK2 https://www.digitalmars.com, Walter Bright) * License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/parse.d, _parse.d) @@ -2899,6 +2899,8 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer if (transitionIn) eSink.message(scanloc, "Usage of 'in' on parameter"); stc = STC.in_; + if (compileEnv.previewIn) + stc |= STC.constscoperef; goto L2; case TOK.out_: @@ -2936,9 +2938,9 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer default: { - stc = storageClass & (STC.IOR | STC.lazy_); - // if stc is not a power of 2 - if (stc & (stc - 1) && !(stc == (STC.in_ | STC.ref_))) + const stcx = storageClass & (STC.in_ | STC.ref_ | STC.out_ | STC.lazy_); + // if stcx is not a power of 2 + if (stcx & (stcx - 1) && !(stcx == (STC.in_ | STC.ref_))) error("incompatible parameter storage classes"); //if ((storageClass & STC.scope_) && (storageClass & (STC.ref_ | STC.out_))) //error("scope cannot be ref or out"); diff --git a/gcc/d/dmd/postordervisitor.d b/gcc/d/dmd/postordervisitor.d index 70bd130..fe189d4 100644 --- a/gcc/d/dmd/postordervisitor.d +++ b/gcc/d/dmd/postordervisitor.d @@ -1,7 +1,7 @@ /** * A depth-first visitor for expressions. * - * Copyright: Copyright (C) 1999-2023 by The D Language Foundation, All Rights Reserved + * Copyright: Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved * Authors: $(LINK2 https://www.digitalmars.com, Walter Bright) * License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/apply.d, _apply.d) diff --git a/gcc/d/dmd/printast.d b/gcc/d/dmd/printast.d index e1deb2c..02dc653 100644 --- a/gcc/d/dmd/printast.d +++ b/gcc/d/dmd/printast.d @@ -1,7 +1,7 @@ /** * Provides an AST printer for debugging. * - * Copyright: Copyright (C) 1999-2023 by The D Language Foundation, All Rights Reserved + * Copyright: Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved * Authors: $(LINK2 https://www.digitalmars.com, Walter Bright) * License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/printast.d, _printast.d) diff --git a/gcc/d/dmd/root/aav.d b/gcc/d/dmd/root/aav.d index 1d45050..8929679 100644 --- a/gcc/d/dmd/root/aav.d +++ b/gcc/d/dmd/root/aav.d @@ -1,7 +1,7 @@ /** * Associative array implementation. * - * Copyright: Copyright (C) 1999-2023 by The D Language Foundation, All Rights Reserved + * Copyright: Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved * Authors: Walter Bright, https://www.digitalmars.com * License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/root/aav.d, root/_aav.d) diff --git a/gcc/d/dmd/root/array.d b/gcc/d/dmd/root/array.d index f36ddb4..8135577 100644 --- a/gcc/d/dmd/root/array.d +++ b/gcc/d/dmd/root/array.d @@ -2,7 +2,7 @@ /** * Dynamic array implementation. * - * Copyright: Copyright (C) 1999-2023 by The D Language Foundation, All Rights Reserved + * Copyright: Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved * Authors: $(LINK2 https://www.digitalmars.com, Walter Bright) * License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/root/array.d, root/_array.d) diff --git a/gcc/d/dmd/root/array.h b/gcc/d/dmd/root/array.h index ebe2c47..1033b22 100644 --- a/gcc/d/dmd/root/array.h +++ b/gcc/d/dmd/root/array.h @@ -1,4 +1,4 @@ -/* Copyright (C) 2011-2023 by The D Language Foundation, All Rights Reserved +/* Copyright (C) 2011-2024 by The D Language Foundation, All Rights Reserved * written by Walter Bright * https://www.digitalmars.com * Distributed under the Boost Software License, Version 1.0. diff --git a/gcc/d/dmd/root/bitarray.d b/gcc/d/dmd/root/bitarray.d index 66adab6..c32d59e 100644 --- a/gcc/d/dmd/root/bitarray.d +++ b/gcc/d/dmd/root/bitarray.d @@ -1,7 +1,7 @@ /** * Implementation of a bit array. * - * Copyright: Copyright (C) 1999-2023 by The D Language Foundation, All Rights Reserved + * Copyright: Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved * Authors: $(LINK2 https://www.digitalmars.com, Walter Bright) * License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/root/bitarray.d, root/_bitarray.d) diff --git a/gcc/d/dmd/root/bitarray.h b/gcc/d/dmd/root/bitarray.h index 617cc9e..2cd7152 100644 --- a/gcc/d/dmd/root/bitarray.h +++ b/gcc/d/dmd/root/bitarray.h @@ -1,4 +1,4 @@ -/* Copyright (C) 2011-2023 by The D Language Foundation, All Rights Reserved +/* Copyright (C) 2011-2024 by The D Language Foundation, All Rights Reserved * written by Walter Bright * https://www.digitalmars.com * Distributed under the Boost Software License, Version 1.0. diff --git a/gcc/d/dmd/root/complex.d b/gcc/d/dmd/root/complex.d index 57d1e34..de4c8d34 100644 --- a/gcc/d/dmd/root/complex.d +++ b/gcc/d/dmd/root/complex.d @@ -1,7 +1,7 @@ /** * Implements a complex number type. * - * Copyright: Copyright (C) 1999-2023 by The D Language Foundation, All Rights Reserved + * Copyright: Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved * Authors: $(LINK2 https://www.digitalmars.com, Walter Bright) * License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/root/complex.d, _complex.d) diff --git a/gcc/d/dmd/root/complex_t.h b/gcc/d/dmd/root/complex_t.h index de2040b..8134f9e 100644 --- a/gcc/d/dmd/root/complex_t.h +++ b/gcc/d/dmd/root/complex_t.h @@ -1,6 +1,6 @@ /* Compiler implementation of the D programming language - * Copyright (C) 1999-2023 by The D Language Foundation, All Rights Reserved + * Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved * written by Walter Bright * https://www.digitalmars.com * Distributed under the Boost Software License, Version 1.0. diff --git a/gcc/d/dmd/root/ctfloat.d b/gcc/d/dmd/root/ctfloat.d index aae56fa..70446066 100644 --- a/gcc/d/dmd/root/ctfloat.d +++ b/gcc/d/dmd/root/ctfloat.d @@ -1,7 +1,7 @@ /** * Collects functions for compile-time floating-point calculations. * - * Copyright: Copyright (C) 1999-2023 by The D Language Foundation, All Rights Reserved + * Copyright: Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved * Authors: $(LINK2 https://www.digitalmars.com, Walter Bright) * License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/root/ctfloat.d, root/_ctfloat.d) diff --git a/gcc/d/dmd/root/ctfloat.h b/gcc/d/dmd/root/ctfloat.h index d2f795b..ba8b447 100644 --- a/gcc/d/dmd/root/ctfloat.h +++ b/gcc/d/dmd/root/ctfloat.h @@ -1,5 +1,5 @@ -/* Copyright (C) 1999-2023 by The D Language Foundation, All Rights Reserved +/* Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved * written by Walter Bright * https://www.digitalmars.com * Distributed under the Boost Software License, Version 1.0. diff --git a/gcc/d/dmd/root/dcompat.h b/gcc/d/dmd/root/dcompat.h index 1a49688..db2b2c6 100644 --- a/gcc/d/dmd/root/dcompat.h +++ b/gcc/d/dmd/root/dcompat.h @@ -1,5 +1,5 @@ -/* Copyright (C) 1999-2023 by The D Language Foundation, All Rights Reserved +/* Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved * written by Walter Bright * https://www.digitalmars.com * Distributed under the Boost Software License, Version 1.0. diff --git a/gcc/d/dmd/root/file.d b/gcc/d/dmd/root/file.d index fdf13d4..a4362e1 100644 --- a/gcc/d/dmd/root/file.d +++ b/gcc/d/dmd/root/file.d @@ -1,7 +1,7 @@ /** * Read a file from disk and store it in memory. * - * Copyright: Copyright (C) 1999-2023 by The D Language Foundation, All Rights Reserved + * Copyright: Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved * Authors: Walter Bright, https://www.digitalmars.com * License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/root/file.d, root/_file.d) diff --git a/gcc/d/dmd/root/filename.d b/gcc/d/dmd/root/filename.d index 8f31f21..5b0bba4 100644 --- a/gcc/d/dmd/root/filename.d +++ b/gcc/d/dmd/root/filename.d @@ -1,7 +1,7 @@ /** * Encapsulate path and file names. * - * Copyright: Copyright (C) 1999-2023 by The D Language Foundation, All Rights Reserved + * Copyright: Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved * Authors: Walter Bright, https://www.digitalmars.com * License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/root/filename.d, root/_filename.d) diff --git a/gcc/d/dmd/root/filename.h b/gcc/d/dmd/root/filename.h index 6214233..d8834a1 100644 --- a/gcc/d/dmd/root/filename.h +++ b/gcc/d/dmd/root/filename.h @@ -1,5 +1,5 @@ -/* Copyright (C) 1999-2023 by The D Language Foundation, All Rights Reserved +/* Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved * written by Walter Bright * https://www.digitalmars.com * Distributed under the Boost Software License, Version 1.0. diff --git a/gcc/d/dmd/root/hash.d b/gcc/d/dmd/root/hash.d index 2acee35..441620e 100644 --- a/gcc/d/dmd/root/hash.d +++ b/gcc/d/dmd/root/hash.d @@ -1,7 +1,7 @@ /** * Hash functions for arbitrary binary data. * - * Copyright: Copyright (C) 1999-2023 by The D Language Foundation, All Rights Reserved + * Copyright: Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved * Authors: Martin Nowak, Walter Bright, https://www.digitalmars.com * License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/root/hash.d, root/_hash.d) diff --git a/gcc/d/dmd/root/object.h b/gcc/d/dmd/root/object.h index 8e505f0..f56cb17 100644 --- a/gcc/d/dmd/root/object.h +++ b/gcc/d/dmd/root/object.h @@ -1,5 +1,5 @@ -/* Copyright (C) 1999-2023 by The D Language Foundation, All Rights Reserved +/* Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved * written by Walter Bright * https://www.digitalmars.com * Distributed under the Boost Software License, Version 1.0. diff --git a/gcc/d/dmd/root/optional.d b/gcc/d/dmd/root/optional.d index bc1016b..e7d0e1e 100644 --- a/gcc/d/dmd/root/optional.d +++ b/gcc/d/dmd/root/optional.d @@ -1,7 +1,7 @@ /** * Implementation of an 'Optional' type * - * Copyright: Copyright (C) 1999-2023 by The D Language Foundation, All Rights Reserved + * Copyright: Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved * Authors: $(LINK2 https://www.digitalmars.com, Walter Bright) * License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/root/optional.d, root/_optional.d) diff --git a/gcc/d/dmd/root/optional.h b/gcc/d/dmd/root/optional.h index 353332c..a92dedd 100644 --- a/gcc/d/dmd/root/optional.h +++ b/gcc/d/dmd/root/optional.h @@ -3,7 +3,7 @@ /** * Optional implementation. * - * Copyright: Copyright (C) 1999-2023 by The D Language Foundation, All Rights Reserved + * Copyright: Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved * Authors: $(LINK2 https://www.digitalmars.com, Walter Bright) * License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/root/optional.h, root/_optional.h) diff --git a/gcc/d/dmd/root/port.d b/gcc/d/dmd/root/port.d index 290280f..ee846bd 100644 --- a/gcc/d/dmd/root/port.d +++ b/gcc/d/dmd/root/port.d @@ -1,7 +1,7 @@ /** * Portable routines for functions that have different implementations on different platforms. * - * Copyright: Copyright (C) 1999-2023 by The D Language Foundation, All Rights Reserved + * Copyright: Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved * Authors: Walter Bright, https://www.digitalmars.com * License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/root/port.d, root/_port.d) diff --git a/gcc/d/dmd/root/port.h b/gcc/d/dmd/root/port.h index 6fa3c00..6c7dddd 100644 --- a/gcc/d/dmd/root/port.h +++ b/gcc/d/dmd/root/port.h @@ -1,5 +1,5 @@ -/* Copyright (C) 1999-2023 by The D Language Foundation, All Rights Reserved +/* Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved * written by Walter Bright * https://www.digitalmars.com * Distributed under the Boost Software License, Version 1.0. diff --git a/gcc/d/dmd/root/region.d b/gcc/d/dmd/root/region.d index 9fc57f1..a9fab16 100644 --- a/gcc/d/dmd/root/region.d +++ b/gcc/d/dmd/root/region.d @@ -1,7 +1,7 @@ /** * Region storage allocator implementation. * - * Copyright: Copyright (C) 2019-2023 by The D Language Foundation, All Rights Reserved + * Copyright: Copyright (C) 2019-2024 by The D Language Foundation, All Rights Reserved * Authors: $(LINK2 https://www.digitalmars.com, Walter Bright) * License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/root/region.d, root/_region.d) diff --git a/gcc/d/dmd/root/rmem.d b/gcc/d/dmd/root/rmem.d index cff5c4c..1965207 100644 --- a/gcc/d/dmd/root/rmem.d +++ b/gcc/d/dmd/root/rmem.d @@ -1,7 +1,7 @@ /** * Allocate memory using `malloc` or the GC depending on the configuration. * - * Copyright: Copyright (C) 1999-2023 by The D Language Foundation, All Rights Reserved + * Copyright: Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved * Authors: Walter Bright, https://www.digitalmars.com * License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/root/rmem.d, root/_rmem.d) diff --git a/gcc/d/dmd/root/rmem.h b/gcc/d/dmd/root/rmem.h index 36aa264..09c0fc0 100644 --- a/gcc/d/dmd/root/rmem.h +++ b/gcc/d/dmd/root/rmem.h @@ -1,5 +1,5 @@ -/* Copyright (C) 1999-2023 by The D Language Foundation, All Rights Reserved +/* Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved * written by Walter Bright * https://www.digitalmars.com * Distributed under the Boost Software License, Version 1.0. diff --git a/gcc/d/dmd/root/speller.d b/gcc/d/dmd/root/speller.d index 7ad08b7..ae09cba 100644 --- a/gcc/d/dmd/root/speller.d +++ b/gcc/d/dmd/root/speller.d @@ -3,7 +3,7 @@ * * Does not have any dependencies on the rest of DMD. * - * Copyright: Copyright (C) 1999-2023 by The D Language Foundation, All Rights Reserved + * Copyright: Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved * Authors: Walter Bright, https://www.digitalmars.com * License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/root/speller.d, root/_speller.d) diff --git a/gcc/d/dmd/root/string.d b/gcc/d/dmd/root/string.d index 5ee81a9..e82b0d2 100644 --- a/gcc/d/dmd/root/string.d +++ b/gcc/d/dmd/root/string.d @@ -1,7 +1,7 @@ /** * Contains various string related functions. * - * Copyright: Copyright (C) 1999-2023 by The D Language Foundation, All Rights Reserved + * Copyright: Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved * Authors: Walter Bright, https://www.digitalmars.com * License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/root/string.d, root/_string.d) diff --git a/gcc/d/dmd/root/stringtable.d b/gcc/d/dmd/root/stringtable.d index de293eb..1fba919 100644 --- a/gcc/d/dmd/root/stringtable.d +++ b/gcc/d/dmd/root/stringtable.d @@ -1,7 +1,7 @@ /** * A specialized associative array with string keys stored in a variable length structure. * - * Copyright: Copyright (C) 1999-2023 by The D Language Foundation, All Rights Reserved + * Copyright: Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved * Authors: Walter Bright, https://www.digitalmars.com * License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/root/stringtable.d, root/_stringtable.d) diff --git a/gcc/d/dmd/root/utf.d b/gcc/d/dmd/root/utf.d index d7ba17f..7d732f2 100644 --- a/gcc/d/dmd/root/utf.d +++ b/gcc/d/dmd/root/utf.d @@ -1,7 +1,7 @@ /** * Functions related to UTF encoding. * - * Copyright: Copyright (C) 1999-2023 by The D Language Foundation, All Rights Reserved + * Copyright: Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved * Authors: $(LINK2 https://www.digitalmars.com, Walter Bright) * License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/root/utf.d, _utf.d) diff --git a/gcc/d/dmd/rootobject.d b/gcc/d/dmd/rootobject.d index 7867ad5..7c926fe 100644 --- a/gcc/d/dmd/rootobject.d +++ b/gcc/d/dmd/rootobject.d @@ -1,7 +1,7 @@ /** * Provide the root object that AST classes in dmd inherit from. * - * Copyright: Copyright (C) 1999-2023 by The D Language Foundation, All Rights Reserved + * Copyright: Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved * Authors: Walter Bright, https://www.digitalmars.com * License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/rootobject.d, _rootobject.d) diff --git a/gcc/d/dmd/safe.d b/gcc/d/dmd/safe.d index bd531c0..af81bff 100644 --- a/gcc/d/dmd/safe.d +++ b/gcc/d/dmd/safe.d @@ -3,7 +3,7 @@ * * Specification: $(LINK2 https://dlang.org/spec/function.html#function-safety, Function Safety) * - * Copyright: Copyright (C) 1999-2023 by The D Language Foundation, All Rights Reserved + * Copyright: Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved * Authors: $(LINK2 https://www.digitalmars.com, Walter Bright) * License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/safe.d, _safe.d) diff --git a/gcc/d/dmd/sapply.d b/gcc/d/dmd/sapply.d index 13fe691..340fbad 100644 --- a/gcc/d/dmd/sapply.d +++ b/gcc/d/dmd/sapply.d @@ -1,7 +1,7 @@ /** * Provides a depth-first statement visitor. * - * Copyright: Copyright (C) 1999-2023 by The D Language Foundation, All Rights Reserved + * Copyright: Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved * Authors: $(LINK2 https://www.digitalmars.com, Walter Bright) * License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/sparse.d, _sparse.d) diff --git a/gcc/d/dmd/scope.h b/gcc/d/dmd/scope.h index cceb5a7..1535fd0 100644 --- a/gcc/d/dmd/scope.h +++ b/gcc/d/dmd/scope.h @@ -1,6 +1,6 @@ /* Compiler implementation of the D programming language - * Copyright (C) 1999-2023 by The D Language Foundation, All Rights Reserved + * Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved * written by Walter Bright * https://www.digitalmars.com * Distributed under the Boost Software License, Version 1.0. diff --git a/gcc/d/dmd/semantic2.d b/gcc/d/dmd/semantic2.d index 036560b..937e746 100644 --- a/gcc/d/dmd/semantic2.d +++ b/gcc/d/dmd/semantic2.d @@ -1,7 +1,7 @@ /** * Performs the semantic2 stage, which deals with initializer expressions. * - * Copyright: Copyright (C) 1999-2023 by The D Language Foundation, All Rights Reserved + * Copyright: Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved * Authors: $(LINK2 https://www.digitalmars.com, Walter Bright) * License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/semantic2.d, _semantic2.d) @@ -93,6 +93,13 @@ private extern(C++) final class Semantic2Visitor : Visitor override void visit(StaticAssert sa) { //printf("StaticAssert::semantic2() %s\n", sa.toChars()); + if (const e = sa.exp.isStringExp()) + { + // deprecated in 2.107 + deprecation(e.loc, "static assert condition cannot be a string literal"); + deprecationSupplemental(e.loc, "If intentional, use `%s !is null` instead to preserve behaviour", + e.toChars()); + } auto sds = new ScopeDsymbol(); sc = sc.push(sds); sc.tinst = null; diff --git a/gcc/d/dmd/semantic3.d b/gcc/d/dmd/semantic3.d index 7498eaf..520e05f 100644 --- a/gcc/d/dmd/semantic3.d +++ b/gcc/d/dmd/semantic3.d @@ -1,7 +1,7 @@ /** * Performs the semantic3 stage, which deals with function bodies. * - * Copyright: Copyright (C) 1999-2023 by The D Language Foundation, All Rights Reserved + * Copyright: Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved * Authors: $(LINK2 https://www.digitalmars.com, Walter Bright) * License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/semantic3.d, _semantic3.d) diff --git a/gcc/d/dmd/sideeffect.d b/gcc/d/dmd/sideeffect.d index 80c9a46..59398a7 100644 --- a/gcc/d/dmd/sideeffect.d +++ b/gcc/d/dmd/sideeffect.d @@ -1,7 +1,7 @@ /** * Find side-effects of expressions. * - * Copyright: Copyright (C) 1999-2023 by The D Language Foundation, All Rights Reserved + * Copyright: Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved * Authors: $(LINK2 https://www.digitalmars.com, Walter Bright) * License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/sideeffect.d, _sideeffect.d) diff --git a/gcc/d/dmd/statement.d b/gcc/d/dmd/statement.d index 4304544..a79b78a 100644 --- a/gcc/d/dmd/statement.d +++ b/gcc/d/dmd/statement.d @@ -3,7 +3,7 @@ * * Specification: $(LINK2 https://dlang.org/spec/statement.html, Statements) * - * Copyright: Copyright (C) 1999-2023 by The D Language Foundation, All Rights Reserved + * Copyright: Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved * Authors: $(LINK2 https://www.digitalmars.com, Walter Bright) * License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/statement.d, _statement.d) diff --git a/gcc/d/dmd/statement.h b/gcc/d/dmd/statement.h index 1e493f0..ee03d49 100644 --- a/gcc/d/dmd/statement.h +++ b/gcc/d/dmd/statement.h @@ -1,6 +1,6 @@ /* Compiler implementation of the D programming language - * Copyright (C) 1999-2023 by The D Language Foundation, All Rights Reserved + * Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved * written by Walter Bright * https://www.digitalmars.com * Distributed under the Boost Software License, Version 1.0. diff --git a/gcc/d/dmd/statement_rewrite_walker.d b/gcc/d/dmd/statement_rewrite_walker.d index dcdd963..221c502 100644 --- a/gcc/d/dmd/statement_rewrite_walker.d +++ b/gcc/d/dmd/statement_rewrite_walker.d @@ -1,7 +1,7 @@ /** * Provides a visitor for statements that allows rewriting the currently visited node. * - * Copyright: Copyright (C) 1999-2023 by The D Language Foundation, All Rights Reserved + * Copyright: Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved * Authors: $(LINK2 https://www.digitalmars.com, Walter Bright) * License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/statement_rewrite_walker.d, _statement_rewrite_walker.d) diff --git a/gcc/d/dmd/statementsem.d b/gcc/d/dmd/statementsem.d index fcc606b..229cf17 100644 --- a/gcc/d/dmd/statementsem.d +++ b/gcc/d/dmd/statementsem.d @@ -3,7 +3,7 @@ * * Specification: $(LINK2 https://dlang.org/spec/statement.html, Statements) * - * Copyright: Copyright (C) 1999-2023 by The D Language Foundation, All Rights Reserved + * Copyright: Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved * Authors: $(LINK2 https://www.digitalmars.com, Walter Bright) * License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/statementsem.d, _statementsem.d) @@ -568,8 +568,8 @@ Statement statementSemanticVisit(Statement s, Scope* sc) ds._body = ds._body.semanticScope(sc, ds, ds, null); sc.inLoop = inLoopSave; - if (ds.condition.op == EXP.dotIdentifier) - (cast(DotIdExp)ds.condition).noderef = true; + if (auto dotid = ds.condition.isDotIdExp()) + dotid.noderef = true; // check in syntax level ds.condition = checkAssignmentAsCondition(ds.condition, sc); @@ -641,8 +641,8 @@ Statement statementSemanticVisit(Statement s, Scope* sc) if (fs.condition) { - if (fs.condition.op == EXP.dotIdentifier) - (cast(DotIdExp)fs.condition).noderef = true; + if (auto dotid = fs.condition.isDotIdExp()) + dotid.noderef = true; // check in syntax level fs.condition = checkAssignmentAsCondition(fs.condition, sc); @@ -729,8 +729,8 @@ Statement statementSemanticVisit(Statement s, Scope* sc) if (fs.aggr.op == EXP.error) return setError(); Expression oaggr = fs.aggr; // remember original for error messages - if (fs.aggr.type && fs.aggr.type.toBasetype().ty == Tstruct && - (cast(TypeStruct)(fs.aggr.type.toBasetype())).sym.dtor && + if (fs.aggr.type && fs.aggr.type.toBasetype().isTypeStruct() && + fs.aggr.type.toBasetype().isTypeStruct().sym.dtor && !fs.aggr.isTypeExp() && !fs.aggr.isLvalue()) { // https://issues.dlang.org/show_bug.cgi?id=14653 @@ -804,9 +804,9 @@ Statement statementSemanticVisit(Statement s, Scope* sc) Parameter fparam = fparameters[0]; if ((fparam.type.ty == Tpointer || fparam.type.ty == Tdelegate) && - fparam.type.nextOf().ty == Tfunction) + fparam.type.nextOf().isTypeFunction()) { - TypeFunction tf = cast(TypeFunction)fparam.type.nextOf(); + auto tf = fparam.type.nextOf().isTypeFunction(); foreachParamCount = tf.parameterList.length; foundMismatch = true; } @@ -1644,8 +1644,8 @@ Statement statementSemanticVisit(Statement s, Scope* sc) } else { - if (ifs.condition.op == EXP.dotIdentifier) - (cast(DotIdExp)ifs.condition).noderef = true; + if (auto dotid = ifs.condition.isDotIdExp()) + dotid.noderef = true; ifs.condition = ifs.condition.expressionSemantic(scd); ifs.condition = resolveProperties(scd, ifs.condition); @@ -1910,8 +1910,8 @@ Statement statementSemanticVisit(Statement s, Scope* sc) while (!ss.condition.isErrorExp()) { // preserve enum type for final switches - if (ss.condition.type.ty == Tenum) - te = cast(TypeEnum)ss.condition.type; + if (auto tenum = ss.condition.type.isTypeEnum()) + te = tenum; if (ss.condition.type.isString()) { // If it's not an array, cast it to one @@ -2222,14 +2222,13 @@ Statement statementSemanticVisit(Statement s, Scope* sc) Expression e = cs.exp; // Remove all the casts the user and/or implicitCastTo may introduce // otherwise we'd sometimes fail the check below. - while (e.op == EXP.cast_) - e = (cast(CastExp)e).e1; + while (e.isCastExp()) + e = e.isCastExp().e1; /* This is where variables are allowed as case expressions. */ - if (e.op == EXP.variable) + if (auto ve = e.isVarExp()) { - VarExp ve = cast(VarExp)e; VarDeclaration v = ve.var.isVarDeclaration(); Type t = cs.exp.type.toBasetype(); if (v && (t.isintegral() || t.ty == Tclass)) @@ -3227,9 +3226,9 @@ Statement statementSemanticVisit(Statement s, Scope* sc) sym.parent = sc.scopesym; sym.endlinnum = ws.endloc.linnum; } - else if (ws.exp.op == EXP.type) + else if (auto et = ws.exp.isTypeExp()) { - Dsymbol s = (cast(TypeExp)ws.exp).type.toDsymbol(sc); + Dsymbol s = et.type.toDsymbol(sc); if (!s || !s.isScopeDsymbol()) { error(ws.loc, "`with` type `%s` has no members", ws.exp.toChars()); @@ -3767,16 +3766,15 @@ public bool throwSemantic(const ref Loc loc, ref Expression exp, Scope* sc) if (FuncDeclaration fd = sc.parent.isFuncDeclaration()) fd.hasReturnExp |= 2; - if (exp.op == EXP.new_) + if (auto ne = exp.isNewExp()) { - NewExp ne = cast(NewExp) exp; ne.thrownew = true; } exp = exp.expressionSemantic(sc); exp = resolveProperties(sc, exp); exp = checkGC(sc, exp); - if (exp.op == EXP.error) + if (exp.isErrorExp()) return false; if (!exp.type.isNaked()) { @@ -3805,12 +3803,12 @@ private extern(D) Expression applyOpApply(ForeachStatement fs, Expression flde, { message(loc, "To enforce `@safe`, the compiler allocates a closure unless `opApply()` uses `scope`"); } - (cast(FuncExp)flde).fd.tookAddressOf = 1; + flde.isFuncExp().fd.tookAddressOf = 1; } else { if (sc2.useDIP1000 == FeatureState.enabled) - ++(cast(FuncExp)flde).fd.tookAddressOf; // allocate a closure unless the opApply() uses 'scope' + ++flde.isFuncExp().fd.tookAddressOf; // allocate a closure unless the opApply() uses 'scope' } assert(tab.ty == Tstruct || tab.ty == Tclass); assert(sapply); @@ -3821,7 +3819,7 @@ private extern(D) Expression applyOpApply(ForeachStatement fs, Expression flde, ec = new DotIdExp(fs.loc, fs.aggr, sapply.ident); ec = new CallExp(fs.loc, ec, flde); ec = ec.expressionSemantic(sc2); - if (ec.op == EXP.error) + if (ec.isErrorExp()) return null; if (ec.type != Type.tint32) { @@ -3838,11 +3836,12 @@ private extern(D) Expression applyDelegate(ForeachStatement fs, Expression flde, /* Call: * aggr(flde) */ - if (fs.aggr.op == EXP.delegate_ && (cast(DelegateExp)fs.aggr).func.isNested() && - !(cast(DelegateExp)fs.aggr).func.needThis()) + if (auto de = fs.aggr.isDelegateExp()) + if (de.func.isNested() && + !de.func.needThis()) { // https://issues.dlang.org/show_bug.cgi?id=3560 - fs.aggr = (cast(DelegateExp)fs.aggr).e1; + fs.aggr = de.e1; } ec = new CallExp(fs.loc, fs.aggr, flde); ec = ec.expressionSemantic(sc2); @@ -4099,7 +4098,7 @@ private FuncExp foreachBodyToFunction(Scope* sc, ForeachStatement fs, TypeFuncti fld.tookAddressOf = 0; if (flde.op == EXP.error) return null; - return cast(FuncExp)flde; + return flde.isFuncExp(); } @@ -4273,9 +4272,9 @@ Statement scopeCode(Statement statement, Scope* sc, out Statement sentry, out St { if (auto es = statement.isExpStatement()) { - if (es.exp && es.exp.op == EXP.declaration) + if (es.exp && es.exp.isDeclarationExp()) { - auto de = cast(DeclarationExp)es.exp; + auto de = es.exp.isDeclarationExp(); auto v = de.declaration.isVarDeclaration(); if (v && !v.isDataseg()) { @@ -4401,7 +4400,7 @@ public auto makeTupleForeach(Scope* sc, bool isStatic, bool isDecl, ForeachState } Type tab = fs.aggr.type.toBasetype(); - TypeTuple tuple = cast(TypeTuple)tab; + TypeTuple tuple = tab.isTypeTuple(); Statements* statements; Dsymbols* declarations; @@ -4413,12 +4412,12 @@ public auto makeTupleForeach(Scope* sc, bool isStatic, bool isDecl, ForeachState //printf("aggr: op = %d, %s\n", fs.aggr.op, fs.aggr.toChars()); size_t n; TupleExp te = null; - if (fs.aggr.op == EXP.tuple) // expression tuple + if (auto ate = fs.aggr.isTupleExp()) // expression tuple { - te = cast(TupleExp)fs.aggr; + te = ate; n = te.exps.length; } - else if (fs.aggr.op == EXP.type) // type tuple + else if (fs.aggr.isTypeExp()) // type tuple { n = Parameter.dim(tuple.arguments); } diff --git a/gcc/d/dmd/staticassert.d b/gcc/d/dmd/staticassert.d index 760c66a..08780ca 100644 --- a/gcc/d/dmd/staticassert.d +++ b/gcc/d/dmd/staticassert.d @@ -3,7 +3,7 @@ * * Specification: $(LINK2 https://dlang.org/spec/version.html#static-assert, Static Assert) * - * Copyright: Copyright (C) 1999-2023 by The D Language Foundation, All Rights Reserved + * Copyright: Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved * Authors: $(LINK2 https://www.digitalmars.com, Walter Bright) * License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/staticassert.d, _staticassert.d) @@ -49,10 +49,10 @@ extern (C++) final class StaticAssert : Dsymbol return new StaticAssert(loc, exp.syntaxCopy(), msgs ? Expression.arraySyntaxCopy(msgs) : null); } - override bool oneMember(Dsymbol* ps, Identifier ident) + override bool oneMember(out Dsymbol ps, Identifier ident) { //printf("StaticAssert::oneMember())\n"); - *ps = null; + ps = null; return true; } diff --git a/gcc/d/dmd/staticassert.h b/gcc/d/dmd/staticassert.h index c0d5363..ed76de0 100644 --- a/gcc/d/dmd/staticassert.h +++ b/gcc/d/dmd/staticassert.h @@ -1,6 +1,6 @@ /* Compiler implementation of the D programming language - * Copyright (C) 1999-2023 by The D Language Foundation, All Rights Reserved + * Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved * written by Walter Bright * https://www.digitalmars.com * Distributed under the Boost Software License, Version 1.0. @@ -21,7 +21,7 @@ public: Expressions *msg; StaticAssert *syntaxCopy(Dsymbol *s) override; - bool oneMember(Dsymbol **ps, Identifier *ident) override; + bool oneMember(Dsymbol *&ps, Identifier *ident) override; const char *kind() const override; StaticAssert *isStaticAssert() override { return this; } void accept(Visitor *v) override { v->visit(this); } diff --git a/gcc/d/dmd/staticcond.d b/gcc/d/dmd/staticcond.d index 1d18de3..72afe02 100644 --- a/gcc/d/dmd/staticcond.d +++ b/gcc/d/dmd/staticcond.d @@ -1,7 +1,7 @@ /** * Lazily evaluate static conditions for `static if`, `static assert` and template constraints. * - * Copyright: Copyright (C) 1999-2023 by The D Language Foundation, All Rights Reserved + * Copyright: Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved * Authors: $(LINK2 https://www.digitalmars.com, Walter Bright) * License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/staticcond.d, _staticcond.d) diff --git a/gcc/d/dmd/stmtstate.d b/gcc/d/dmd/stmtstate.d index 7b2ea97..e1ed165 100644 --- a/gcc/d/dmd/stmtstate.d +++ b/gcc/d/dmd/stmtstate.d @@ -1,7 +1,7 @@ /** * Used to help transform statement AST into flow graph. * - * Copyright: Copyright (C) 1999-2023 by The D Language Foundation, All Rights Reserved + * Copyright: Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved * Authors: $(LINK2 https://www.digitalmars.com, Walter Bright) * License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/stmtstate.d, _stmtstate.d) diff --git a/gcc/d/dmd/target.d b/gcc/d/dmd/target.d index aba3319..e63bf17 100644 --- a/gcc/d/dmd/target.d +++ b/gcc/d/dmd/target.d @@ -15,7 +15,7 @@ * - $(LINK2 https://github.com/ldc-developers/ldc, LDC repository) * - $(LINK2 https://github.com/D-Programming-GDC/gcc, GDC repository) * - * Copyright: Copyright (C) 1999-2023 by The D Language Foundation, All Rights Reserved + * Copyright: Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved * Authors: $(LINK2 https://www.digitalmars.com, Walter Bright) * License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/target.d, _target.d) diff --git a/gcc/d/dmd/target.h b/gcc/d/dmd/target.h index ca0e09c..1209505 100644 --- a/gcc/d/dmd/target.h +++ b/gcc/d/dmd/target.h @@ -1,6 +1,6 @@ /* Compiler implementation of the D programming language - * Copyright (C) 2013-2023 by The D Language Foundation, All Rights Reserved + * Copyright (C) 2013-2024 by The D Language Foundation, All Rights Reserved * written by Iain Buclaw * https://www.digitalmars.com * Distributed under the Boost Software License, Version 1.0. diff --git a/gcc/d/dmd/template.h b/gcc/d/dmd/template.h index 4be1361..09c4912 100644 --- a/gcc/d/dmd/template.h +++ b/gcc/d/dmd/template.h @@ -1,6 +1,6 @@ /* Compiler implementation of the D programming language - * Copyright (C) 1999-2023 by The D Language Foundation, All Rights Reserved + * Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved * written by Walter Bright * https://www.digitalmars.com * Distributed under the Boost Software License, Version 1.0. @@ -290,7 +290,7 @@ public: TemplateInstance *syntaxCopy(Dsymbol *) override; Dsymbol *toAlias() override final; // resolve real symbol const char *kind() const override; - bool oneMember(Dsymbol **ps, Identifier *ident) override; + bool oneMember(Dsymbol *&ps, Identifier *ident) override; const char *toChars() const override; const char* toPrettyCharsHelper() override final; Identifier *getIdent() override final; @@ -309,7 +309,7 @@ public: TemplateMixin *syntaxCopy(Dsymbol *s) override; const char *kind() const override; - bool oneMember(Dsymbol **ps, Identifier *ident) override; + bool oneMember(Dsymbol *&ps, Identifier *ident) override; bool hasPointers() override; const char *toChars() const override; diff --git a/gcc/d/dmd/templateparamsem.d b/gcc/d/dmd/templateparamsem.d index 7762363..89749d6 100644 --- a/gcc/d/dmd/templateparamsem.d +++ b/gcc/d/dmd/templateparamsem.d @@ -1,7 +1,7 @@ /** * Semantic analysis of template parameters. * - * Copyright: Copyright (C) 1999-2023 by The D Language Foundation, All Rights Reserved + * Copyright: Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved * Authors: $(LINK2 https://www.digitalmars.com, Walter Bright) * License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/templateparamsem.d, _templateparamsem.d) diff --git a/gcc/d/dmd/tokens.d b/gcc/d/dmd/tokens.d index 317a6e6..589bc2b 100644 --- a/gcc/d/dmd/tokens.d +++ b/gcc/d/dmd/tokens.d @@ -3,7 +3,7 @@ * * Specification: $(LINK2 https://dlang.org/spec/lex.html#tokens, Tokens) * - * Copyright: Copyright (C) 1999-2023 by The D Language Foundation, All Rights Reserved + * Copyright: Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved * Authors: $(LINK2 https://www.digitalmars.com, Walter Bright) * License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/tokens.d, _tokens.d) @@ -948,92 +948,110 @@ nothrow: extern (C++) const(char)* toChars() const { + return toString().ptr; + } + + /********************************* + * Returns: + * a zero-terminated string representation of the token, + * sometimes reusing a static buffer, sometimes leaking memory + */ + extern (D) const(char)[] toString() const + { const bufflen = 3 + 3 * floatvalue.sizeof + 1; - __gshared char[bufflen] buffer; - const(char)* p = &buffer[0]; + __gshared char[bufflen + 2] buffer; // extra 2 for suffixes + char* p = &buffer[0]; switch (value) { case TOK.int32Literal: - snprintf(&buffer[0], bufflen, "%d", cast(int)intvalue); - break; + const length = snprintf(p, bufflen, "%d", cast(int)intvalue); + return p[0 .. length]; + case TOK.uns32Literal: case TOK.wchar_tLiteral: - snprintf(&buffer[0], bufflen, "%uU", cast(uint)unsvalue); - break; + const length = snprintf(p, bufflen, "%uU", cast(uint)unsvalue); + return p[0 .. length]; + case TOK.wcharLiteral: case TOK.dcharLiteral: case TOK.charLiteral: - { - OutBuffer buf; - buf.writeSingleCharLiteral(cast(dchar) intvalue); - buf.writeByte('\0'); - p = buf.extractChars(); - } - break; + OutBuffer buf; + buf.writeSingleCharLiteral(cast(dchar) intvalue); + return buf.extractSlice(true); + case TOK.int64Literal: - snprintf(&buffer[0], bufflen, "%lldL", cast(long)intvalue); - break; + const length = snprintf(p, bufflen, "%lldL", cast(long)intvalue); + return p[0 .. length]; + case TOK.uns64Literal: - snprintf(&buffer[0], bufflen, "%lluUL", cast(ulong)unsvalue); - break; + const length = snprintf(p, bufflen, "%lluUL", cast(ulong)unsvalue); + return p[0 .. length]; + case TOK.float32Literal: - CTFloat.sprint(&buffer[0], bufflen, 'g', floatvalue); - strcat(&buffer[0], "f"); - break; + const length = CTFloat.sprint(p, bufflen, 'g', floatvalue); + p[length] = 'f'; + p[length + 1] = 0; + return p[0 .. length + 1]; + case TOK.float64Literal: - CTFloat.sprint(&buffer[0], bufflen, 'g', floatvalue); - break; + const length = CTFloat.sprint(p, bufflen, 'g', floatvalue); + return p[0 .. length]; + case TOK.float80Literal: - CTFloat.sprint(&buffer[0], bufflen, 'g', floatvalue); - strcat(&buffer[0], "L"); - break; + const length = CTFloat.sprint(p, bufflen, 'g', floatvalue); + p[length] = 'L'; + p[length + 1] = 0; + return p[0 .. length + 1]; + case TOK.imaginary32Literal: - CTFloat.sprint(&buffer[0], bufflen, 'g', floatvalue); - strcat(&buffer[0], "fi"); - break; + const length = CTFloat.sprint(p, bufflen, 'g', floatvalue); + p[length ] = 'f'; + p[length + 1] = 'i'; + p[length + 2] = 0; + return p[0 .. length + 2]; + case TOK.imaginary64Literal: - CTFloat.sprint(&buffer[0], bufflen, 'g', floatvalue); - strcat(&buffer[0], "i"); - break; + const length = CTFloat.sprint(p, bufflen, 'g', floatvalue); + p[length] = 'i'; + p[length + 1] = 0; + return p[0 .. length + 1]; + case TOK.imaginary80Literal: - CTFloat.sprint(&buffer[0], bufflen, 'g', floatvalue); - strcat(&buffer[0], "Li"); - break; + const length = CTFloat.sprint(p, bufflen, 'g', floatvalue); + p[length ] = 'L'; + p[length + 1] = 'i'; + p[length + 2] = 0; + return p[0 .. length + 2]; + case TOK.string_: + OutBuffer buf; + buf.writeByte('"'); + for (size_t i = 0; i < len;) { - OutBuffer buf; - buf.writeByte('"'); - for (size_t i = 0; i < len;) - { - dchar c; - utf_decodeChar(ustring[0 .. len], i, c); - writeCharLiteral(buf, c); - } - buf.writeByte('"'); - if (postfix) - buf.writeByte(postfix); - buf.writeByte(0); - p = buf.extractChars(); + dchar c; + utf_decodeChar(ustring[0 .. len], i, c); + writeCharLiteral(buf, c); } - break; + buf.writeByte('"'); + if (postfix) + buf.writeByte(postfix); + return buf.extractSlice(true); + case TOK.hexadecimalString: + OutBuffer buf; + buf.writeByte('x'); + buf.writeByte('"'); + foreach (size_t i; 0 .. len) { - OutBuffer buf; - buf.writeByte('x'); - buf.writeByte('"'); - foreach (size_t i; 0 .. len) - { - if (i) - buf.writeByte(' '); - buf.printf("%02x", ustring[i]); - } - buf.writeByte('"'); - if (postfix) - buf.writeByte(postfix); - buf.writeByte(0); - p = buf.extractData(); - break; + if (i) + buf.writeByte(' '); + buf.printf("%02x", ustring[i]); } + buf.writeByte('"'); + if (postfix) + buf.writeByte(postfix); + return buf.extractSlice(true); + case TOK.identifier: case TOK.enum_: case TOK.struct_: @@ -1062,13 +1080,11 @@ nothrow: case TOK.complex64: case TOK.complex80: case TOK.void_: - p = ident.toChars(); - break; + return ident.toString(); + default: - p = toChars(value); - break; + return tochars[value]; } - return p; } static const(char)* toChars(TOK value) diff --git a/gcc/d/dmd/tokens.h b/gcc/d/dmd/tokens.h index 560942d..f944663 100644 --- a/gcc/d/dmd/tokens.h +++ b/gcc/d/dmd/tokens.h @@ -1,6 +1,6 @@ /* Compiler implementation of the D programming language - * Copyright (C) 1999-2023 by The D Language Foundation, All Rights Reserved + * Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved * written by Walter Bright * https://www.digitalmars.com * Distributed under the Boost Software License, Version 1.0. diff --git a/gcc/d/dmd/traits.d b/gcc/d/dmd/traits.d index aebc0b5..c67ee81 100644 --- a/gcc/d/dmd/traits.d +++ b/gcc/d/dmd/traits.d @@ -3,7 +3,7 @@ * * Specification: $(LINK2 https://dlang.org/spec/traits.html, Traits) * - * Copyright: Copyright (C) 1999-2023 by The D Language Foundation, All Rights Reserved + * Copyright: Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved * Authors: $(LINK2 https://www.digitalmars.com, Walter Bright) * License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/traits.d, _traits.d) diff --git a/gcc/d/dmd/typesem.d b/gcc/d/dmd/typesem.d index b0e45f4..51b4ef8 100644 --- a/gcc/d/dmd/typesem.d +++ b/gcc/d/dmd/typesem.d @@ -1,7 +1,7 @@ /** * Semantic analysis for D types. * - * Copyright: Copyright (C) 1999-2023 by The D Language Foundation, All Rights Reserved + * Copyright: Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved * Authors: $(LINK2 https://www.digitalmars.com, Walter Bright) * License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/typesem.d, _typesem.d) @@ -711,7 +711,15 @@ private extern(D) bool isCopyConstructorCallable (StructDeclaration argStruct, s ~= "@safe "; if (!f.isNogc && sc.func.setGC(arg.loc, null)) s ~= "nogc "; - if (s) + if (f.isDisabled() && !f.isGenerated()) + { + /* https://issues.dlang.org/show_bug.cgi?id=24301 + * Copy constructor is explicitly disabled + */ + buf.printf("`%s` copy constructor cannot be used because it is annotated with `@disable`", + f.type.toChars()); + } + else if (s) { s[$-1] = '\0'; buf.printf("`%s` copy constructor cannot be called from a `%s` context", f.type.toChars(), s.ptr); @@ -843,7 +851,7 @@ private extern(D) MATCH argumentMatchParameter (TypeFunction tf, Parameter p, ta = tn.sarrayOf(dim); } } - else if ((p.storageClass & STC.in_) && global.params.previewIn) + else if (p.storageClass & STC.constscoperef) { // Allow converting a literal to an `in` which is `ref` if (arg.op == EXP.arrayLiteral && tp.ty == Tsarray) @@ -1678,7 +1686,7 @@ extern(C++) Type typeSemantic(Type type, const ref Loc loc, Scope* sc) // default arg must be an lvalue if (isRefOrOut && !isAuto && - !(global.params.previewIn && (fparam.storageClass & STC.in_)) && + !(fparam.storageClass & STC.constscoperef) && global.params.rvalueRefParam != FeatureState.enabled) e = e.toLvalue(sc, "create default argument for `ref` / `out` parameter from"); @@ -1784,13 +1792,13 @@ extern(C++) Type typeSemantic(Type type, const ref Loc loc, Scope* sc) switch (tf.linkage) { case LINK.cpp: - if (global.params.previewIn) + if (fparam.storageClass & STC.constscoperef) fparam.storageClass |= STC.ref_; break; case LINK.default_, LINK.d: break; default: - if (global.params.previewIn) + if (fparam.storageClass & STC.constscoperef) { .error(loc, "cannot use `in` parameters with `extern(%s)` functions", linkageToChars(tf.linkage)); @@ -1820,7 +1828,7 @@ extern(C++) Type typeSemantic(Type type, const ref Loc loc, Scope* sc) if (tb2.ty == Tstruct && !tb2.isTypeStruct().sym.members || tb2.ty == Tenum && !tb2.isTypeEnum().sym.memtype) { - if (global.params.previewIn && (fparam.storageClass & STC.in_)) + if (fparam.storageClass & STC.constscoperef) { .error(loc, "cannot infer `ref` for `in` parameter `%s` of opaque type `%s`", fparam.toChars(), fparam.type.toChars()); @@ -1902,7 +1910,7 @@ extern(C++) Type typeSemantic(Type type, const ref Loc loc, Scope* sc) fparam.storageClass &= ~(STC.TYPECTOR); // -preview=in: add `ref` storage class to suited `in` params - if (global.params.previewIn && (fparam.storageClass & (STC.in_ | STC.ref_)) == STC.in_) + if ((fparam.storageClass & (STC.constscoperef | STC.ref_)) == STC.constscoperef) { auto ts = t.baseElemOf().isTypeStruct(); const isPOD = !ts || ts.sym.isPOD(); @@ -2318,11 +2326,16 @@ extern(C++) Type typeSemantic(Type type, const ref Loc loc, Scope* sc) Type visitTag(TypeTag mtype) { //printf("TypeTag.semantic() %s\n", mtype.toChars()); + Type returnType(Type t) + { + return t.deco ? t : t.merge(); + } + if (mtype.resolved) { /* struct S s, *p; */ - return mtype.resolved.addSTC(mtype.mod); + return returnType(mtype.resolved.addSTC(mtype.mod)); } /* Find the current scope by skipping tag scopes. @@ -2395,7 +2408,7 @@ extern(C++) Type typeSemantic(Type type, const ref Loc loc, Scope* sc) { mtype.id = Identifier.generateId("__tag"[]); declareTag(); - return mtype.resolved.addSTC(mtype.mod); + return returnType(mtype.resolved.addSTC(mtype.mod)); } /* look for pre-existing declaration @@ -2408,7 +2421,7 @@ extern(C++) Type typeSemantic(Type type, const ref Loc loc, Scope* sc) if (mtype.tok == TOK.enum_ && !mtype.members) .error(mtype.loc, "`enum %s` is incomplete without members", mtype.id.toChars()); // C11 6.7.2.3-3 declareTag(); - return mtype.resolved.addSTC(mtype.mod); + return returnType(mtype.resolved.addSTC(mtype.mod)); } /* A redeclaration only happens if both declarations are in @@ -2508,7 +2521,7 @@ extern(C++) Type typeSemantic(Type type, const ref Loc loc, Scope* sc) declareTag(); } } - return mtype.resolved.addSTC(mtype.mod); + return returnType(mtype.resolved.addSTC(mtype.mod)); } switch (type.ty) diff --git a/gcc/d/dmd/typinf.d b/gcc/d/dmd/typinf.d index 485ca3f..9e062bd 100644 --- a/gcc/d/dmd/typinf.d +++ b/gcc/d/dmd/typinf.d @@ -1,7 +1,7 @@ /** * Generate `TypeInfo` objects, which are needed for run-time introspection of types. * - * Copyright: Copyright (C) 1999-2023 by The D Language Foundation, All Rights Reserved + * Copyright: Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved * Authors: $(LINK2 https://www.digitalmars.com, Walter Bright) * License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/typinf.d, _typinf.d) diff --git a/gcc/d/dmd/typinf.h b/gcc/d/dmd/typinf.h index 76f623a..fe80b94 100644 --- a/gcc/d/dmd/typinf.h +++ b/gcc/d/dmd/typinf.h @@ -1,6 +1,6 @@ /* Compiler implementation of the D programming language - * Copyright (C) 1999-2023 by The D Language Foundation, All Rights Reserved + * Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved * written by Walter Bright * https://www.digitalmars.com * Distributed under the Boost Software License, Version 1.0. diff --git a/gcc/d/dmd/utils.d b/gcc/d/dmd/utils.d index bb389b6..75ee78c 100644 --- a/gcc/d/dmd/utils.d +++ b/gcc/d/dmd/utils.d @@ -1,7 +1,7 @@ /** * This module defines some utility functions for DMD. * - * Copyright: Copyright (C) 1999-2023 by The D Language Foundation, All Rights Reserved + * Copyright: Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved * Authors: $(LINK2 https://www.digitalmars.com, Walter Bright) * License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/utils.d, _utils.d) diff --git a/gcc/d/dmd/version.h b/gcc/d/dmd/version.h index c268bc9..dd83fd6 100644 --- a/gcc/d/dmd/version.h +++ b/gcc/d/dmd/version.h @@ -1,6 +1,6 @@ /* Compiler implementation of the D programming language - * Copyright (C) 1999-2023 by The D Language Foundation, All Rights Reserved + * Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved * written by Walter Bright * https://www.digitalmars.com * Distributed under the Boost Software License, Version 1.0. diff --git a/gcc/d/dmd/visitor.d b/gcc/d/dmd/visitor.d index 5722e10..abfd8ca 100644 --- a/gcc/d/dmd/visitor.d +++ b/gcc/d/dmd/visitor.d @@ -1,7 +1,7 @@ /** * Provides a visitor class visiting all AST nodes present in the compiler. * - * Copyright: Copyright (C) 1999-2023 by The D Language Foundation, All Rights Reserved + * Copyright: Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved * Authors: $(LINK2 https://www.digitalmars.com, Walter Bright) * License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/visitor.d, _visitor.d) diff --git a/gcc/d/dmd/visitor.h b/gcc/d/dmd/visitor.h index 360784a..7fa08cb0 100644 --- a/gcc/d/dmd/visitor.h +++ b/gcc/d/dmd/visitor.h @@ -1,6 +1,6 @@ /* Compiler implementation of the D programming language - * Copyright (C) 2013-2023 by The D Language Foundation, All Rights Reserved + * Copyright (C) 2013-2024 by The D Language Foundation, All Rights Reserved * https://www.digitalmars.com * Distributed under the Boost Software License, Version 1.0. * https://www.boost.org/LICENSE_1_0.txt diff --git a/gcc/d/modules.cc b/gcc/d/modules.cc index 16b6733..58b15be 100644 --- a/gcc/d/modules.cc +++ b/gcc/d/modules.cc @@ -84,6 +84,7 @@ struct module_info vec *sharedctors; vec *shareddtors; vec *sharedctorgates; + vec *standalonectors; vec *unitTests; }; @@ -763,6 +764,11 @@ build_module_tree (Module *decl) tm->sdtor = build_funcs_gates_fn (get_identifier ("*__modtestdtor"), mitest.dtors, NULL); + if (mi.standalonectors) + tm->sictor + = build_funcs_gates_fn (get_identifier ("*__modtestsharedictor"), + mi.standalonectors, NULL); + if (mitest.sharedctors || mitest.sharedctorgates) tm->ssharedctor = build_funcs_gates_fn (get_identifier ("*__modtestsharedctor"), @@ -793,6 +799,11 @@ build_module_tree (Module *decl) decl->sdtor = build_funcs_gates_fn (get_identifier ("*__moddtor"), mi.dtors, NULL); + if (mi.standalonectors) + decl->sictor + = build_funcs_gates_fn (get_identifier ("*__modsharedictor"), + mi.standalonectors, NULL); + if (mi.sharedctors || mi.sharedctorgates) decl->ssharedctor = build_funcs_gates_fn (get_identifier ("*__modsharedctor"), @@ -858,8 +869,15 @@ register_module_decl (Declaration *d) /* If a static constructor, push into the current ModuleInfo. Checks for `shared' first because it derives from the non-shared constructor type in the front-end. */ - if (fd->isSharedStaticCtorDeclaration ()) - vec_safe_push (minfo->sharedctors, decl); + if (SharedStaticCtorDeclaration *sctor + = fd->isSharedStaticCtorDeclaration ()) + { + /* The `shared' static constructor was marked `@standalone'. */ + if (sctor->standalone) + vec_safe_push (minfo->standalonectors, decl); + else + vec_safe_push (minfo->sharedctors, decl); + } else if (fd->isStaticCtorDeclaration ()) vec_safe_push (minfo->ctors, decl); diff --git a/gcc/testsuite/gdc.test/compilable/issue20339.d b/gcc/testsuite/gdc.test/compilable/issue20339.d new file mode 100644 index 0000000..3d5bdd8 --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/issue20339.d @@ -0,0 +1,44 @@ +/* +TEST_OUTPUT: +--- +4 +false +false +--- +*/ + +// https://issues.dlang.org/show_bug.cgi?id=20339 + +struct S +{ + pragma(msg, cast(int)S.sizeof); + + this(this){} + ~this(){} + + int f; +} + +static assert(__traits(isPOD, S) == false); + + +pragma(msg, __traits(isPOD, T)); + +struct T +{ + this(this){} + ~this(){} +} + +static assert(__traits(isPOD, T) == false); + + +struct U +{ + pragma(msg, __traits(isPOD, U)); + + this(this){} + ~this(){} +} + +static assert(__traits(isPOD, U) == false); diff --git a/gcc/testsuite/gdc.test/fail_compilation/array_bool.d b/gcc/testsuite/gdc.test/fail_compilation/array_bool.d new file mode 100644 index 0000000..923766a --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/array_bool.d @@ -0,0 +1,22 @@ +/* +REQUIRED_ARGS: -de +TEST_OUTPUT: +--- +fail_compilation/array_bool.d(13): Deprecation: assert condition cannot be a string literal +fail_compilation/array_bool.d(13): If intentional, use `"foo" !is null` instead to preserve behaviour +fail_compilation/array_bool.d(14): Deprecation: static assert condition cannot be a string literal +fail_compilation/array_bool.d(14): If intentional, use `"foo" !is null` instead to preserve behaviour +--- +*/ +void main() +{ + assert("foo"); + static assert("foo"); + + assert("foo".ptr); // OK + static assert("foo".ptr); // OK + + enum e = "bar"; + static assert(e); // OK + assert(e); // OK +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/diag11425.d b/gcc/testsuite/gdc.test/fail_compilation/diag11425.d index f8edc5c..dfcddaa 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/diag11425.d +++ b/gcc/testsuite/gdc.test/fail_compilation/diag11425.d @@ -1,7 +1,8 @@ /* TEST_OUTPUT: --- -fail_compilation/diag11425.d(13): Error: variable `x` is shadowing variable `diag11425.main.x` +fail_compilation/diag11425.d(14): Error: variable `x` is shadowing variable `diag11425.main.x` +fail_compilation/diag11425.d(11): declared here --- */ diff --git a/gcc/testsuite/gdc.test/fail_compilation/diagin.d b/gcc/testsuite/gdc.test/fail_compilation/diagin.d index 1748e92..5b8e331 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/diagin.d +++ b/gcc/testsuite/gdc.test/fail_compilation/diagin.d @@ -1,5 +1,5 @@ /* -PERMUTE_ARGS: -preview=in +REQUIRED_ARGS: -preview=in TEST_OUTPUT: --- fail_compilation/diagin.d(14): Error: function `diagin.foo(in int)` is not callable using argument types `()` diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail110.d b/gcc/testsuite/gdc.test/fail_compilation/fail110.d index a13922b..4ba2a8c 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/fail110.d +++ b/gcc/testsuite/gdc.test/fail_compilation/fail110.d @@ -1,9 +1,12 @@ /* TEST_OUTPUT: --- -fail_compilation/fail110.d(16): Error: variable `i` is shadowing variable `fail110.main.i` -fail_compilation/fail110.d(17): Error: variable `i` is shadowing variable `fail110.main.i` -fail_compilation/fail110.d(18): Error: variable `i` is shadowing variable `fail110.main.i` +fail_compilation/fail110.d(19): Error: variable `i` is shadowing variable `fail110.main.i` +fail_compilation/fail110.d(17): declared here +fail_compilation/fail110.d(20): Error: variable `i` is shadowing variable `fail110.main.i` +fail_compilation/fail110.d(17): declared here +fail_compilation/fail110.d(21): Error: variable `i` is shadowing variable `fail110.main.i` +fail_compilation/fail110.d(17): declared here --- */ diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail19890a.d b/gcc/testsuite/gdc.test/fail_compilation/fail19890a.d index 9b98496..2e8e4e6a 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/fail19890a.d +++ b/gcc/testsuite/gdc.test/fail_compilation/fail19890a.d @@ -1,7 +1,7 @@ -/* +/* REQUIRED_ARGS: -m32 TEST_OUTPUT: --- -fail_compilation/fail19890a.d(8): Error: `void[$n$$?:64=LU$]` size 1 * $n$ exceeds $?:windows+32omf=0x1000000|0x7fffffff$ size limit for static array +fail_compilation/fail19890a.d(8): Error: `void[cast(size_t)4294967295]` size 1 * 4294967295 exceeds 0x7fffffff size limit for static array --- */ diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail19890b.d b/gcc/testsuite/gdc.test/fail_compilation/fail19890b.d index 19081d9..f9cfb45 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/fail19890b.d +++ b/gcc/testsuite/gdc.test/fail_compilation/fail19890b.d @@ -1,7 +1,7 @@ -/* +/* REQUIRED_ARGS: -m32 TEST_OUTPUT: --- -fail_compilation/fail19890b.d(8): Error: `void[$n$$?:64=LU$]` size 1 * $n$ exceeds $?:windows+32omf=0x1000000|0x7fffffff$ size limit for static array +fail_compilation/fail19890b.d(8): Error: `void[cast(size_t)4294967294]` size 1 * 4294967294 exceeds 0x7fffffff size limit for static array --- */ diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail2195.d b/gcc/testsuite/gdc.test/fail_compilation/fail2195.d index 0eff066..6f6cd53 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/fail2195.d +++ b/gcc/testsuite/gdc.test/fail_compilation/fail2195.d @@ -3,7 +3,8 @@ /* TEST_OUTPUT: --- -fail_compilation/fail2195.d(16): Deprecation: variable `variable` is shadowing variable `fail2195.main.variable`. Rename the `foreach` variable. +fail_compilation/fail2195.d(17): Deprecation: variable `variable` is shadowing variable `fail2195.main.variable` +fail_compilation/fail2195.d(14): declared here --- */ diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail24301.d b/gcc/testsuite/gdc.test/fail_compilation/fail24301.d new file mode 100644 index 0000000..be09c88 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail24301.d @@ -0,0 +1,19 @@ +/+ +TEST_OUTPUT: +--- +fail_compilation/fail24301.d(18): Error: function `fail24301.fun(S __param_0)` is not callable using argument types `(S)` +fail_compilation/fail24301.d(18): `ref S(ref S)` copy constructor cannot be used because it is annotated with `@disable` +--- ++/ +struct S +{ + @disable this(ref S); +} + +@safe void fun(S) {} + +@safe void main() +{ + S s; + fun(s); +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail4611.d b/gcc/testsuite/gdc.test/fail_compilation/fail4611.d index 04adf13..259a6da 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/fail4611.d +++ b/gcc/testsuite/gdc.test/fail_compilation/fail4611.d @@ -1,7 +1,7 @@ -/* +/* REQUIRED_ARGS: -m32 TEST_OUTPUT: --- -fail_compilation/fail4611.d(15): Error: `Vec[$n$]` size 4 * $n$ exceeds $?:windows+32omf=0x1000000|0x7fffffff$ size limit for static array +fail_compilation/fail4611.d(15): Error: `Vec[cast(size_t)2147483647]` size 4 * 2147483647 exceeds 0x7fffffff size limit for static array --- */ diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail93.d b/gcc/testsuite/gdc.test/fail_compilation/fail93.d index b9ad294..2989395 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/fail93.d +++ b/gcc/testsuite/gdc.test/fail_compilation/fail93.d @@ -1,7 +1,8 @@ /* TEST_OUTPUT: --- -fail_compilation/fail93.d(13): Error: variable `i` is shadowing variable `fail93.main.i` +fail_compilation/fail93.d(14): Error: variable `i` is shadowing variable `fail93.main.i` +fail_compilation/fail93.d(13): declared here --- */ diff --git a/gcc/testsuite/gdc.test/fail_compilation/standalone_modctor.d b/gcc/testsuite/gdc.test/fail_compilation/standalone_modctor.d new file mode 100644 index 0000000..cb36ed6 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/standalone_modctor.d @@ -0,0 +1,15 @@ +/** +TEST_OUTPUT: +--- +fail_compilation/standalone_modctor.d(11): Error: `@standalone` can only be used on shared static constructors +fail_compilation/standalone_modctor.d(12): Error: a module constructor using `@standalone` must be `@system` or `@trusted` +fail_compilation/standalone_modctor.d(13): Error: a module constructor using `@standalone` must be `@system` or `@trusted` +--- +*/ +import core.attribute : standalone; + +@standalone static this() {} +@standalone shared static this() {} +@standalone shared static this() @safe {} +@standalone shared static this() @trusted {} +@standalone shared static this() @system {} diff --git a/gcc/testsuite/gdc.test/fail_compilation/staticarrayoverflow.d b/gcc/testsuite/gdc.test/fail_compilation/staticarrayoverflow.d index 1305bc5..028f8e1 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/staticarrayoverflow.d +++ b/gcc/testsuite/gdc.test/fail_compilation/staticarrayoverflow.d @@ -2,13 +2,13 @@ REQUIRED_ARGS: -m64 TEST_OUTPUT: --- -fail_compilation/staticarrayoverflow.d(23): Error: static array `S[1879048192]` size overflowed to 7516192768000 +fail_compilation/staticarrayoverflow.d(23): Error: static array `S[cast(size_t)1879048192]` size overflowed to 7516192768000 fail_compilation/staticarrayoverflow.d(23): Error: variable `staticarrayoverflow.y` size overflow -fail_compilation/staticarrayoverflow.d(25): Error: static array `S[8070450532247928832]` size overflowed to 8070450532247928832 +fail_compilation/staticarrayoverflow.d(25): Error: static array `S[cast(size_t)8070450532247928832]` size overflowed to 8070450532247928832 fail_compilation/staticarrayoverflow.d(25): Error: variable `staticarrayoverflow.a` size overflow fail_compilation/staticarrayoverflow.d(26): Error: static array `S[0][18446744073709551615LU]` size overflowed to 18446744073709551615 fail_compilation/staticarrayoverflow.d(26): Error: variable `staticarrayoverflow.b` size overflow -fail_compilation/staticarrayoverflow.d(27): Error: static array `S[0][4294967295]` size overflowed to 4294967295 +fail_compilation/staticarrayoverflow.d(27): Error: static array `S[0][cast(size_t)4294967295]` size overflowed to 4294967295 fail_compilation/staticarrayoverflow.d(27): Error: variable `staticarrayoverflow.c` size overflow --- */ diff --git a/gcc/testsuite/gdc.test/runnable/imports/standalone_b.d b/gcc/testsuite/gdc.test/runnable/imports/standalone_b.d new file mode 100644 index 0000000..bc5500b --- /dev/null +++ b/gcc/testsuite/gdc.test/runnable/imports/standalone_b.d @@ -0,0 +1,11 @@ +module standalone_b; + +import standalone_modctor; +import core.attribute : standalone; + +immutable int* y; + +@standalone @system shared static this() +{ + y = new int(2); +} diff --git a/gcc/testsuite/gdc.test/runnable/standalone_modctor.d b/gcc/testsuite/gdc.test/runnable/standalone_modctor.d new file mode 100644 index 0000000..2654407 --- /dev/null +++ b/gcc/testsuite/gdc.test/runnable/standalone_modctor.d @@ -0,0 +1,19 @@ +// REQUIRED_ARGS: -Irunnable/imports +// EXTRA_SOURCES: imports/standalone_b.d +// PERMUTE_ARGS: -cov + +import standalone_b; +import core.attribute : standalone; + +immutable int* x; + +@standalone @system shared static this() +{ + x = new int(1); +} + +void main() +{ + assert(*x == 1); + assert(*y == 2); +} diff --git a/gcc/testsuite/gdc.test/runnable_cxx/extra-files/test24292.cpp b/gcc/testsuite/gdc.test/runnable_cxx/extra-files/test24292.cpp new file mode 100644 index 0000000..2fab9af --- /dev/null +++ b/gcc/testsuite/gdc.test/runnable_cxx/extra-files/test24292.cpp @@ -0,0 +1,46 @@ +template +struct List +{ + T* begin; +}; + +struct StructWithDestructor +{ + ~StructWithDestructor(); + + int i; +}; + +struct StructWithCopyCtor +{ + StructWithCopyCtor(); + StructWithCopyCtor(const StructWithCopyCtor &other); + + int i; +}; + +StructWithDestructor::~StructWithDestructor() +{ +} + +StructWithCopyCtor::StructWithCopyCtor() +{ +} + +StructWithCopyCtor::StructWithCopyCtor(const StructWithCopyCtor &other) : i(other.i) +{ +} + +StructWithDestructor getStructWithDestructor() +{ + StructWithDestructor r; + r.i = 12345; + return r; +} + +StructWithCopyCtor getStructWithCopyCtor() +{ + StructWithCopyCtor r; + r.i = 54321; + return r; +} diff --git a/gcc/testsuite/gdc.test/runnable_cxx/test24292.d b/gcc/testsuite/gdc.test/runnable_cxx/test24292.d new file mode 100644 index 0000000..b71f925 --- /dev/null +++ b/gcc/testsuite/gdc.test/runnable_cxx/test24292.d @@ -0,0 +1,50 @@ +// EXTRA_CPP_SOURCES: test24292.cpp + +extern(C++) struct List(T) +{ + // Any of the following static ifs can trigger the problem. + static if (T.sizeof > 4) {} + static if (__traits(isZeroInit, T)) {} + static if (__traits(isPOD, T)) {} + + T* begin; +} + +extern(C++) struct StructWithDestructor +{ + ~this(); + + alias L = List!StructWithDestructor; + int i; +} + +extern(C++) struct StructWithCopyCtor +{ + this(ref const(StructWithCopyCtor)); + + alias L = List!StructWithCopyCtor; + int i; +} + +extern(D) struct StructWithPostblit +{ + this(this) {} + + alias L = List!StructWithPostblit; + int i; +} + +static assert(!__traits(isPOD, StructWithDestructor)); +static assert(!__traits(isPOD, StructWithCopyCtor)); +static assert(!__traits(isPOD, StructWithPostblit)); + +extern(C++) StructWithDestructor getStructWithDestructor(); +extern(C++) StructWithCopyCtor getStructWithCopyCtor(); + +void main() +{ + StructWithDestructor structWithDestructor = getStructWithDestructor(); + assert(structWithDestructor.i == 12345); + StructWithCopyCtor structWithCopyCtor = getStructWithCopyCtor(); + assert(structWithCopyCtor.i == 54321); +} -- cgit v1.1 From f204359931866b917856fc959c70dbf55f28c14d Mon Sep 17 00:00:00 2001 From: Iain Buclaw Date: Thu, 18 Jan 2024 02:39:20 +0100 Subject: d: Merge dmd, druntime bce5c1f7b5, phobos e4d0dd513. D front-end changes: - Import latest changes from dmd v2.107.0-beta.1. - Keywords like `__FILE__' are now always evaluated at the callsite. D runtime changes: - Import latest changes from druntime v2.107.0-beta.1. - Added `nameSig' field to TypeInfo_Class in object.d. Phobos changes: - Import latest changes from phobos v2.107.0-beta.1. gcc/d/ChangeLog: * dmd/MERGE: Merge upstream dmd bce5c1f7b5. * d-attribs.cc (build_attributes): Update for new front-end interface. * d-lang.cc (d_parse_file): Likewise. * decl.cc (DeclVisitor::visit (VarDeclaration *)): Likewise. * expr.cc (build_lambda_tree): New function. (ExprVisitor::visit (FuncExp *)): Use build_lambda_tree. (ExprVisitor::visit (SymOffExp *)): Likewise. (ExprVisitor::visit (VarExp *)): Likewise. * typeinfo.cc (create_tinfo_types): Add two ulong fields to internal TypeInfo representation. (TypeInfoVisitor::visit (TypeInfoClassDeclaration *)): Emit stub data for TypeInfo_Class.nameSig. (TypeInfoVisitor::visit (TypeInfoStructDeclaration *)): Update for new front-end interface. libphobos/ChangeLog: * libdruntime/MERGE: Merge upstream druntime bce5c1f7b5. * src/MERGE: Merge upstream phobos e4d0dd513. --- gcc/d/d-attribs.cc | 2 +- gcc/d/d-lang.cc | 5 +- gcc/d/decl.cc | 2 +- gcc/d/dmd/MERGE | 2 +- gcc/d/dmd/astenums.d | 6 + gcc/d/dmd/constfold.d | 1 + gcc/d/dmd/declaration.d | 29 + gcc/d/dmd/dinterpret.d | 132 +-- gcc/d/dmd/dmodule.d | 18 +- gcc/d/dmd/doc.d | 1 + gcc/d/dmd/dscope.d | 1 + gcc/d/dmd/dsymbolsem.d | 6 +- gcc/d/dmd/dtemplate.d | 964 +++++++++++---------- gcc/d/dmd/dtoh.d | 11 + gcc/d/dmd/escape.d | 1 + gcc/d/dmd/expression.d | 33 - gcc/d/dmd/expressionsem.d | 243 +++++- gcc/d/dmd/file_manager.d | 30 +- gcc/d/dmd/func.d | 33 +- gcc/d/dmd/globals.d | 4 +- gcc/d/dmd/globals.h | 2 +- gcc/d/dmd/mtype.d | 573 +----------- gcc/d/dmd/mtype.h | 35 +- gcc/d/dmd/mustuse.d | 1 + gcc/d/dmd/ob.d | 1 + gcc/d/dmd/parse.d | 61 +- gcc/d/dmd/safe.d | 1 + gcc/d/dmd/scope.h | 1 + gcc/d/dmd/semantic3.d | 6 +- gcc/d/dmd/sideeffect.d | 1 + gcc/d/dmd/statementsem.d | 5 +- gcc/d/dmd/template.h | 2 +- gcc/d/dmd/typesem.d | 564 +++++++++++- gcc/d/expr.cc | 49 +- gcc/d/typeinfo.cc | 14 +- gcc/testsuite/gdc.test/compilable/b18242.d | 2 +- gcc/testsuite/gdc.test/compilable/issue24316.d | 13 + .../gdc.test/fail_compilation/test24295.d | 13 + .../gdc.test/runnable/imports/issue18919b.d | 250 ++++++ gcc/testsuite/gdc.test/runnable/issue18919.d | 47 + gcc/testsuite/gdc.test/runnable/test18916.d | 4 +- gcc/testsuite/gdc.test/runnable/testptrref.d | 5 +- gcc/testsuite/gdc.test/runnable/xtest46.d | 28 +- 43 files changed, 1843 insertions(+), 1359 deletions(-) create mode 100644 gcc/testsuite/gdc.test/compilable/issue24316.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/test24295.d create mode 100644 gcc/testsuite/gdc.test/runnable/imports/issue18919b.d create mode 100644 gcc/testsuite/gdc.test/runnable/issue18919.d (limited to 'gcc') diff --git a/gcc/d/d-attribs.cc b/gcc/d/d-attribs.cc index 8b66cf2..36a139b 100644 --- a/gcc/d/d-attribs.cc +++ b/gcc/d/d-attribs.cc @@ -327,7 +327,7 @@ build_attributes (Expressions *eattrs) for (size_t i = 0; i < eattrs->length; i++) { Expression *attr = (*eattrs)[i]; - Dsymbol *sym = attr->type->toDsymbol (0); + Dsymbol *sym = toDsymbol (attr->type, NULL); if (!sym) { diff --git a/gcc/d/d-lang.cc b/gcc/d/d-lang.cc index 71f8473..aabe1ad 100644 --- a/gcc/d/d-lang.cc +++ b/gcc/d/d-lang.cc @@ -1344,7 +1344,10 @@ d_parse_file (void) } if (global.params.v.templates) - printTemplateStats (); + { + printTemplateStats (global.params.v.templatesListInstances, + global.errorSink); + } /* Generate JSON files. */ if (global.params.json.doOutput) diff --git a/gcc/d/decl.cc b/gcc/d/decl.cc index 2374931..4ca85bb 100644 --- a/gcc/d/decl.cc +++ b/gcc/d/decl.cc @@ -782,7 +782,7 @@ public: { /* Do not store variables we cannot take the address of, but keep the values for purposes of debugging. */ - if (d->type->isscalar () && !d->type->hasPointers ()) + if (d->type->isscalar () && !hasPointers (d->type)) { tree decl = get_symbol_decl (d); d_pushdecl (decl); diff --git a/gcc/d/dmd/MERGE b/gcc/d/dmd/MERGE index 2b4400f..138b0b6 100644 --- a/gcc/d/dmd/MERGE +++ b/gcc/d/dmd/MERGE @@ -1,4 +1,4 @@ -d8e3976a58d6aef7c2c9371028a2ca4460b5b2ce +bce5c1f7b521d22dcf1ea4e2bc3f76d9d28274fa The first line of this file holds the git revision number of the last merge done from the dlang/dmd repository. diff --git a/gcc/d/dmd/astenums.d b/gcc/d/dmd/astenums.d index f19edb9..77940b8 100644 --- a/gcc/d/dmd/astenums.d +++ b/gcc/d/dmd/astenums.d @@ -459,3 +459,9 @@ extern (C++) struct structalign_t bool isPack() const { return pack; } void setPack(bool pack) { this.pack = pack; } } + +/// Use to return D arrays from C++ functions +extern (C++) struct DArray(T) +{ + T[] data; +} diff --git a/gcc/d/dmd/constfold.d b/gcc/d/dmd/constfold.d index 7bd9691..cee1f63 100644 --- a/gcc/d/dmd/constfold.d +++ b/gcc/d/dmd/constfold.d @@ -1038,6 +1038,7 @@ UnionExp Cast(const ref Loc loc, Type type, Type to, Expression e1) else if (tb.ty == Tstruct && e1.op == EXP.int64) { // Struct = 0; + import dmd.typesem : toDsymbol; StructDeclaration sd = tb.toDsymbol(null).isStructDeclaration(); assert(sd); auto elements = new Expressions(); diff --git a/gcc/d/dmd/declaration.d b/gcc/d/dmd/declaration.d index 5869a22..93ef63f 100644 --- a/gcc/d/dmd/declaration.d +++ b/gcc/d/dmd/declaration.d @@ -1749,6 +1749,35 @@ extern (C++) final class SymbolDeclaration : Declaration /*********************************************************** */ +private Identifier getTypeInfoIdent(Type t) +{ + import dmd.dmangle; + import core.stdc.stdlib; + import dmd.root.rmem; + // _init_10TypeInfo_%s + OutBuffer buf; + buf.reserve(32); + mangleToBuffer(t, buf); + + const slice = buf[]; + + // Allocate buffer on stack, fail over to using malloc() + char[128] namebuf; + const namelen = 19 + size_t.sizeof * 3 + slice.length + 1; + auto name = namelen <= namebuf.length ? namebuf.ptr : cast(char*)Mem.check(malloc(namelen)); + + const length = snprintf(name, namelen, "_D%lluTypeInfo_%.*s6__initZ", + cast(ulong)(9 + slice.length), cast(int)slice.length, slice.ptr); + //printf("%p %s, deco = %s, name = %s\n", this, toChars(), deco, name); + assert(0 < length && length < namelen); // don't overflow the buffer + + auto id = Identifier.idPool(name[0 .. length]); + + if (name != namebuf.ptr) + free(name); + return id; +} + extern (C++) class TypeInfoDeclaration : VarDeclaration { Type tinfo; diff --git a/gcc/d/dmd/dinterpret.d b/gcc/d/dmd/dinterpret.d index eda91d1..a3b38d9 100644 --- a/gcc/d/dmd/dinterpret.d +++ b/gcc/d/dmd/dinterpret.d @@ -1416,6 +1416,7 @@ Expression interpretStatement(UnionExp* pue, Statement s, InterState* istate) foreach (ca; *s.catches) { Type catype = ca.type; + import dmd.typesem : isBaseOf; if (!catype.equals(extype) && !catype.isBaseOf(extype, null)) continue; @@ -6237,6 +6238,11 @@ public: { if (soe.offset == 0 && soe.var.isFuncDeclaration()) return; + if (soe.offset == 0 && soe.var.isVarDeclaration() && soe.var.isImmutable()) + { + result = getVarExp(e.loc, istate, soe.var, CTFEGoal.RValue); + return; + } error(e.loc, "cannot dereference pointer to static variable `%s` at compile time", soe.var.toChars()); result = CTFEExp.cantexp; return; @@ -6359,6 +6365,7 @@ public: { if (auto t = isType(ex.isTypeidExp().obj)) { + import dmd.typesem : toDsymbol; auto sym = t.toDsymbol(null); if (auto ident = (sym ? sym.ident : null)) { @@ -6643,6 +6650,7 @@ Expressions* copyArrayOnWrite(Expressions* exps, Expressions* original) private bool stopPointersEscaping(const ref Loc loc, Expression e) { + import dmd.typesem : hasPointers; if (!e.type.hasPointers()) return true; if (isPointer(e.type)) @@ -6706,7 +6714,7 @@ Statement findGotoTarget(InterState* istate, Identifier ident) Statement target = null; if (ident) { - LabelDsymbol label = istate.fd.searchLabel(ident); + LabelDsymbol label = istate.fd.searchLabel(ident, Loc.initial); assert(label && label.statement); LabelStatement ls = label.statement; target = ls.gotoTarget ? ls.gotoTarget : ls.statement; @@ -7263,6 +7271,33 @@ private Expression interpret_aaApply(UnionExp* pue, InterState* istate, Expressi return eresult; } +/// Returns: equivalent `StringExp` from `ArrayLiteralExp ale` containing only `IntegerExp` elements +StringExp arrayLiteralToString(ArrayLiteralExp ale) +{ + const len = ale.elements ? ale.elements.length : 0; + const size = ale.type.nextOf().size(); + + StringExp impl(T)() + { + T[] result = new T[len]; + foreach (i; 0 .. len) + result[i] = cast(T) (*ale.elements)[i].isIntegerExp().getInteger(); + return new StringExp(ale.loc, result[], len, cast(ubyte) size); + } + + switch (size) + { + case 1: + return impl!char(); + case 2: + return impl!wchar(); + case 4: + return impl!dchar(); + default: + assert(0); + } +} + /* Decoding UTF strings for foreach loops. Duplicates the functionality of * the twelve _aApplyXXn functions in aApply.d in the runtime. */ @@ -7299,8 +7334,10 @@ private Expression foreachApplyUtf(UnionExp* pue, InterState* istate, Expression str = resolveSlice(str, &strTmp); auto se = str.isStringExp(); - auto ale = str.isArrayLiteralExp(); - if (!se && !ale) + if (auto ale = str.isArrayLiteralExp()) + se = arrayLiteralToString(ale); + + if (!se) { error(str.loc, "CTFE internal error: cannot foreach `%s`", str.toChars()); return CTFEExp.cantexp; @@ -7309,7 +7346,7 @@ private Expression foreachApplyUtf(UnionExp* pue, InterState* istate, Expression Expression eresult = null; // ded-store to prevent spurious warning - // Buffers for encoding; also used for decoding array literals + // Buffers for encoding char[4] utf8buf = void; wchar[2] utf16buf = void; @@ -7323,90 +7360,11 @@ private Expression foreachApplyUtf(UnionExp* pue, InterState* istate, Expression dchar rawvalue; // Holds the decoded dchar size_t currentIndex = indx; // The index of the decoded character - if (ale) - { - // If it is an array literal, copy the code points into the buffer - size_t buflen = 1; // #code points in the buffer - size_t n = 1; // #code points in this char - size_t sz = cast(size_t)ale.type.nextOf().size(); + // String literals + size_t saveindx; // used for reverse iteration - switch (sz) - { - case 1: - if (rvs) - { - // find the start of the string - --indx; - buflen = 1; - while (indx > 0 && buflen < 4) - { - Expression r = (*ale.elements)[indx]; - char x = cast(char)r.isIntegerExp().getInteger(); - if ((x & 0xC0) != 0x80) - break; - --indx; - ++buflen; - } - } - else - buflen = (indx + 4 > len) ? len - indx : 4; - for (size_t i = 0; i < buflen; ++i) - { - Expression r = (*ale.elements)[indx + i]; - utf8buf[i] = cast(char)r.isIntegerExp().getInteger(); - } - n = 0; - errmsg = utf_decodeChar(utf8buf[0 .. buflen], n, rawvalue); - break; - - case 2: - if (rvs) - { - // find the start of the string - --indx; - buflen = 1; - Expression r = (*ale.elements)[indx]; - ushort x = cast(ushort)r.isIntegerExp().getInteger(); - if (indx > 0 && x >= 0xDC00 && x <= 0xDFFF) - { - --indx; - ++buflen; - } - } - else - buflen = (indx + 2 > len) ? len - indx : 2; - for (size_t i = 0; i < buflen; ++i) - { - Expression r = (*ale.elements)[indx + i]; - utf16buf[i] = cast(ushort)r.isIntegerExp().getInteger(); - } - n = 0; - errmsg = utf_decodeWchar(utf16buf[0 .. buflen], n, rawvalue); - break; - - case 4: - { - if (rvs) - --indx; - Expression r = (*ale.elements)[indx]; - rawvalue = cast(dchar)r.isIntegerExp().getInteger(); - n = 1; - } - break; - - default: - assert(0); - } - if (!rvs) - indx += n; - } - else + switch (se.sz) { - // String literals - size_t saveindx; // used for reverse iteration - - switch (se.sz) - { case 1: { if (rvs) @@ -7450,8 +7408,8 @@ private Expression foreachApplyUtf(UnionExp* pue, InterState* istate, Expression default: assert(0); - } } + if (errmsg) { error(deleg.loc, "`%.*s`", cast(int)errmsg.length, errmsg.ptr); diff --git a/gcc/d/dmd/dmodule.d b/gcc/d/dmd/dmodule.d index 022231c..59d4065 100644 --- a/gcc/d/dmd/dmodule.d +++ b/gcc/d/dmd/dmodule.d @@ -679,23 +679,23 @@ extern (C++) final class Module : Package /* Preprocess the file if it's a .c file */ FileName filename = srcfile; - bool ifile = false; // did we generate a .i file - scope (exit) - { - if (ifile) - File.remove(filename.toChars()); // remove generated file - } + const(ubyte)[] srctext; if (global.preprocess && FileName.equalsExt(srcfile.toString(), c_ext) && FileName.exists(srcfile.toString())) { - filename = global.preprocess(srcfile, loc, ifile, &defines); // run C preprocessor + /* Apply C preprocessor to the .c file, returning the contents + * after preprocessing + */ + srctext = global.preprocess(srcfile, loc, defines).data; } + else + srctext = global.fileManager.getFileContents(filename); + this.src = srctext; - if (auto result = global.fileManager.lookup(filename)) + if (srctext) { - this.src = result; if (global.params.makeDeps.doOutput) global.params.makeDeps.files.push(srcfile.toChars()); return true; diff --git a/gcc/d/dmd/doc.d b/gcc/d/dmd/doc.d index 810642f..ec3cc91 100644 --- a/gcc/d/dmd/doc.d +++ b/gcc/d/dmd/doc.d @@ -1355,6 +1355,7 @@ void toDocBuffer(Dsymbol s, ref OutBuffer buf, Scope* sc) { if (type.ty == Tclass || type.ty == Tstruct || type.ty == Tenum) { + import dmd.typesem : toDsymbol; if (Dsymbol s = type.toDsymbol(null)) // elaborate type prettyPrintDsymbol(s, ad.parent); else diff --git a/gcc/d/dmd/dscope.d b/gcc/d/dmd/dscope.d index 7e9499f..e02ba9a 100644 --- a/gcc/d/dmd/dscope.d +++ b/gcc/d/dmd/dscope.d @@ -97,6 +97,7 @@ extern (C++) struct Scope Dsymbol inunion; /// != null if processing members of a union bool nofree; /// true if shouldn't free it bool inLoop; /// true if inside a loop (where constructor calls aren't allowed) + bool inDefaultArg; /// true if inside a default argument (where __FILE__, etc are evaluated at the call site) int intypeof; /// in typeof(exp) VarDeclaration lastVar; /// Previous symbol used to prevent goto-skips-init ErrorSink eSink; /// sink for error messages diff --git a/gcc/d/dmd/dsymbolsem.d b/gcc/d/dmd/dsymbolsem.d index 23f0bc5..e9cdb94 100644 --- a/gcc/d/dmd/dsymbolsem.d +++ b/gcc/d/dmd/dsymbolsem.d @@ -6553,7 +6553,8 @@ void templateInstanceSemantic(TemplateInstance tempinst, Scope* sc, ArgumentList TemplateDeclaration tempdecl = tempinst.tempdecl.isTemplateDeclaration(); assert(tempdecl); - TemplateStats.incInstance(tempdecl, tempinst); + if (global.params.v.templates) + TemplateStats.incInstance(tempdecl, tempinst, global.params.v.templatesListInstances); tempdecl.checkDeprecated(tempinst.loc, sc); @@ -6746,7 +6747,8 @@ void templateInstanceSemantic(TemplateInstance tempinst, Scope* sc, ArgumentList tempinst.parent = tempinst.enclosing ? tempinst.enclosing : tempdecl.parent; //printf("parent = '%s'\n", parent.kind()); - TemplateStats.incUnique(tempdecl, tempinst); + if (global.params.v.templates) + TemplateStats.incUnique(tempdecl, tempinst); TemplateInstance tempdecl_instance_idx = tempdecl.addInstance(tempinst); diff --git a/gcc/d/dmd/dtemplate.d b/gcc/d/dmd/dtemplate.d index 1d84ccd..13cc32f 100644 --- a/gcc/d/dmd/dtemplate.d +++ b/gcc/d/dmd/dtemplate.d @@ -56,6 +56,7 @@ import dmd.dscope; import dmd.dsymbol; import dmd.dsymbolsem; import dmd.errors; +import dmd.errorsink; import dmd.expression; import dmd.expressionsem; import dmd.func; @@ -150,7 +151,7 @@ extern (C++) bool isError(const RootObject o) if (const e = isExpression(o)) return (e.op == EXP.error || !e.type || e.type.ty == Terror); if (const v = isTuple(o)) - return arrayObjectIsError(&v.objects); + return arrayObjectIsError(v.objects); const s = isDsymbol(o); assert(s); if (s.errors) @@ -161,9 +162,9 @@ extern (C++) bool isError(const RootObject o) /************************************** * Are any of the Objects an error? */ -bool arrayObjectIsError(const Objects* args) +bool arrayObjectIsError(const ref Objects args) { - foreach (const o; *args) + foreach (const o; args) { if (isError(o)) return true; @@ -187,6 +188,13 @@ inout(Type) getType(inout RootObject o) } +/*********************************** + * If oarg represents a Dsymbol, return that Dsymbol + * Params: + * oarg = argument to check + * Returns: + * Dsymbol if a symbol, null if not + */ Dsymbol getDsymbol(RootObject oarg) { //printf("getDsymbol()\n"); @@ -256,8 +264,11 @@ private Expression getExpression(RootObject o) } /****************************** - * If o1 matches o2, return true. - * Else, return false. + * See if two objects match + * Params: + * o1 = first object + * o2 = second object + * Returns: true if they match */ private bool match(RootObject o1, RootObject o2) { @@ -343,7 +354,7 @@ private bool match(RootObject o1, RootObject o2) printf("\tu1 = %s\n", u1.toChars()); printf("\tu2 = %s\n", u2.toChars()); } - if (!arrayObjectMatch(&u1.objects, &u2.objects)) + if (!arrayObjectMatch(u1.objects, u2.objects)) goto Lnomatch; goto Lmatch; @@ -362,15 +373,15 @@ Lnomatch: /************************************ * Match an array of them. */ -private bool arrayObjectMatch(Objects* oa1, Objects* oa2) +private bool arrayObjectMatch(ref Objects oa1, ref Objects oa2) { - if (oa1 == oa2) + if (&oa1 == &oa2) return true; if (oa1.length != oa2.length) return false; immutable oa1dim = oa1.length; - auto oa1d = (*oa1)[].ptr; - auto oa2d = (*oa2)[].ptr; + auto oa1d = oa1[].ptr; + auto oa2d = oa2[].ptr; foreach (j; 0 .. oa1dim) { RootObject o1 = oa1d[j]; @@ -386,12 +397,12 @@ private bool arrayObjectMatch(Objects* oa1, Objects* oa2) /************************************ * Return hash of Objects. */ -private size_t arrayObjectHash(Objects* oa1) +private size_t arrayObjectHash(ref Objects oa1) { import dmd.root.hash : mixHash; size_t hash = 0; - foreach (o1; *oa1) + foreach (o1; oa1) { /* Must follow the logic of match() */ @@ -407,7 +418,7 @@ private size_t arrayObjectHash(Objects* oa1) hash = mixHash(hash, mixHash(cast(size_t)cast(void*)s1.getIdent(), cast(size_t)cast(void*)s1.parent)); } else if (auto u1 = isTuple(o1)) - hash = mixHash(hash, arrayObjectHash(&u1.objects)); + hash = mixHash(hash, arrayObjectHash(u1.objects)); } return hash; } @@ -672,7 +683,9 @@ extern (C++) final class TemplateDeclaration : ScopeDsymbol /********************************** * Overload existing TemplateDeclaration 'this' with the new one 's'. - * Return true if successful; i.e. no conflict. + * Params: + * s = symbol to be inserted + * Return: true if successful; i.e. no conflict. */ override bool overloadInsert(Dsymbol s) { @@ -741,6 +754,8 @@ extern (C++) final class TemplateDeclaration : ScopeDsymbol return toCharsMaybeConstraints(false); } + // Note: this function is not actually `const`, because iterating the + // function parameter list may run dsymbolsemantic on enum types const(char)* toCharsMaybeConstraints(bool includeConstraints) const { OutBuffer buf; @@ -758,15 +773,17 @@ extern (C++) final class TemplateDeclaration : ScopeDsymbol if (onemember) { - const FuncDeclaration fd = onemember.isFuncDeclaration(); - if (fd && fd.type) + if (const fd = onemember.isFuncDeclaration()) { - TypeFunction tf = cast(TypeFunction)fd.type; - buf.writestring(parametersTypeToChars(tf.parameterList)); - if (tf.mod) + if (TypeFunction tf = cast(TypeFunction)fd.type.isTypeFunction()) { - buf.writeByte(' '); - buf.MODtoBuffer(tf.mod); + // !! Casted away const + buf.writestring(parametersTypeToChars(tf.parameterList)); + if (tf.mod) + { + buf.writeByte(' '); + buf.MODtoBuffer(tf.mod); + } } } } @@ -790,7 +807,7 @@ extern (C++) final class TemplateDeclaration : ScopeDsymbol /**************************** * Check to see if constraint is satisfied. */ - extern (D) bool evaluateConstraint(TemplateInstance ti, Scope* sc, Scope* paramscope, Objects* dedargs, FuncDeclaration fd) + private bool evaluateConstraint(TemplateInstance ti, Scope* sc, Scope* paramscope, Objects* dedargs, FuncDeclaration fd) { /* Detect recursive attempts to instantiate this template declaration, * https://issues.dlang.org/show_bug.cgi?id=4072 @@ -807,7 +824,7 @@ extern (C++) final class TemplateDeclaration : ScopeDsymbol for (TemplatePrevious* p = previous; p; p = p.prev) { - if (!arrayObjectMatch(p.dedargs, dedargs)) + if (!arrayObjectMatch(*p.dedargs, *dedargs)) continue; //printf("recursive, no match p.sc=%p %p %s\n", p.sc, this, this.toChars()); /* It must be a subscope of p.sc, other scope chains are not recursive @@ -1055,7 +1072,7 @@ extern (C++) final class TemplateDeclaration : ScopeDsymbol * dedtypes deduced arguments * Return match level. */ - extern (D) MATCH matchWithInstance(Scope* sc, TemplateInstance ti, Objects* dedtypes, ArgumentList argumentList, int flag) + private MATCH matchWithInstance(Scope* sc, TemplateInstance ti, ref Objects dedtypes, ArgumentList argumentList, int flag) { enum LOGM = 0; static if (LOGM) @@ -1151,7 +1168,7 @@ extern (C++) final class TemplateDeclaration : ScopeDsymbol /* Any parameter left without a type gets the type of * its corresponding arg */ - foreach (i, ref dedtype; *dedtypes) + foreach (i, ref dedtype; dedtypes) { if (!dedtype) { @@ -1202,7 +1219,7 @@ extern (C++) final class TemplateDeclaration : ScopeDsymbol } // TODO: dedtypes => ti.tiargs ? - if (!evaluateConstraint(ti, sc, paramscope, dedtypes, fd)) + if (!evaluateConstraint(ti, sc, paramscope, &dedtypes, fd)) return nomatch(); } @@ -1283,7 +1300,7 @@ extern (C++) final class TemplateDeclaration : ScopeDsymbol Objects dedtypes = Objects(td2.parameters.length); // Attempt a type deduction - MATCH m = td2.matchWithInstance(sc, ti, &dedtypes, argumentList, 1); + MATCH m = td2.matchWithInstance(sc, ti, dedtypes, argumentList, 1); if (m > MATCH.nomatch) { /* A non-variadic template is more specialized than a @@ -1425,7 +1442,7 @@ extern (C++) final class TemplateDeclaration : ScopeDsymbol { assert(i < parameters.length); Declaration sparam = null; - MATCH m = (*parameters)[i].matchArg(instLoc, paramscope, dedargs, i, parameters, dedtypes, &sparam); + MATCH m = (*parameters)[i].matchArg(instLoc, paramscope, dedargs, i, parameters, *dedtypes, &sparam); //printf("\tdeduceType m = %d\n", m); if (m == MATCH.nomatch) return nomatch(); @@ -1458,10 +1475,9 @@ extern (C++) final class TemplateDeclaration : ScopeDsymbol ParameterList fparameters = fd.getParameterList(); // function parameter list const nfparams = fparameters.length; // number of function parameters - const nfargs = argumentList.length; // number of function arguments if (argumentList.hasNames) return matcherror(); // TODO: resolve named args - Expressions* fargs = argumentList.arguments; // TODO: resolve named args + Expression[] fargs = argumentList.arguments ? (*argumentList.arguments)[] : null; /* Check for match of function arguments with variadic template * parameter, such as: @@ -1475,7 +1491,7 @@ extern (C++) final class TemplateDeclaration : ScopeDsymbol // TemplateTupleParameter always makes most lesser matching. matchTiargs = MATCH.convert; - if (nfparams == 0 && nfargs != 0) // if no function parameters + if (nfparams == 0 && argumentList.length != 0) // if no function parameters { if (!declaredTuple) { @@ -1498,7 +1514,7 @@ extern (C++) final class TemplateDeclaration : ScopeDsymbol auto fparam = (*fparameters.parameters)[fptupindex]; // fparameters[fptupindex] ? if (fparam.type.ty != Tident) continue; - TypeIdentifier tid = cast(TypeIdentifier)fparam.type; + TypeIdentifier tid = fparam.type.isTypeIdentifier(); if (!tp.ident.equals(tid.ident) || tid.idents.length) continue; @@ -1527,7 +1543,7 @@ extern (C++) final class TemplateDeclaration : ScopeDsymbol hasttp = true; Type t = new TypeIdentifier(Loc.initial, ttp.ident); - MATCH m = deduceType(tthis, paramscope, t, parameters, dedtypes); + MATCH m = deduceType(tthis, paramscope, t, *parameters, *dedtypes); if (m == MATCH.nomatch) return nomatch(); if (m < match) @@ -1576,7 +1592,7 @@ extern (C++) final class TemplateDeclaration : ScopeDsymbol //printf("%s\n\tnfargs = %d, nfparams = %d, tuple_dim = %d\n", toChars(), nfargs, nfparams, declaredTuple ? declaredTuple.objects.length : 0); //printf("\ttp = %p, fptupindex = %d, found = %d, declaredTuple = %s\n", tp, fptupindex, fptupindex != IDX_NOTFOUND, declaredTuple ? declaredTuple.toChars() : NULL); size_t argi = 0; - size_t nfargs2 = nfargs; // nfargs + supplied defaultArgs + size_t nfargs2 = fargs.length; // nfargs + supplied defaultArgs uint inoutMatch = 0; // for debugging only for (size_t parami = 0; parami < nfparams; parami++) { @@ -1592,8 +1608,8 @@ extern (C++) final class TemplateDeclaration : ScopeDsymbol */ if (fptupindex != IDX_NOTFOUND && parami == fptupindex) { - assert(prmtype.ty == Tident); - TypeIdentifier tid = cast(TypeIdentifier)prmtype; + TypeIdentifier tid = prmtype.isTypeIdentifier(); + assert(tid); if (!declaredTuple) { /* The types of the function arguments @@ -1606,7 +1622,7 @@ extern (C++) final class TemplateDeclaration : ScopeDsymbol * void foo(U, T...)(int y, T, U, double, int bar = 0) {} // rem == 2 (U, double) */ size_t rem = 0; - for (size_t j = parami + 1; j < nfparams; j++) + foreach (j; parami + 1 .. nfparams) { Parameter p = fparameters[j]; if (p.defaultArg) @@ -1616,7 +1632,10 @@ extern (C++) final class TemplateDeclaration : ScopeDsymbol if (!reliesOnTemplateParameters(p.type, (*parameters)[inferStart .. parameters.length])) { Type pt = p.type.syntaxCopy().typeSemantic(fd.loc, paramscope); - rem += pt.ty == Ttuple ? (cast(TypeTuple)pt).arguments.length : 1; + if (auto ptt = pt.isTypeTuple()) + rem += ptt.arguments.length; + else + rem += 1; } else { @@ -1627,9 +1646,9 @@ extern (C++) final class TemplateDeclaration : ScopeDsymbol if (nfargs2 - argi < rem) return nomatch(); declaredTuple.objects.setDim(nfargs2 - argi - rem); - for (size_t i = 0; i < declaredTuple.objects.length; i++) + foreach (i; 0 .. declaredTuple.objects.length) { - farg = (*fargs)[argi + i]; + farg = fargs[argi + i]; // Check invalid arguments to detect errors early. if (farg.op == EXP.error || farg.type.ty == Terror) @@ -1647,7 +1666,7 @@ extern (C++) final class TemplateDeclaration : ScopeDsymbol } else { - m = deduceTypeHelper(farg.type, &tt, tid); + m = deduceTypeHelper(farg.type, tt, tid); } if (m == MATCH.nomatch) return nomatch(); @@ -1687,20 +1706,19 @@ extern (C++) final class TemplateDeclaration : ScopeDsymbol // should copy prmtype to avoid affecting semantic result prmtype = prmtype.syntaxCopy().typeSemantic(fd.loc, paramscope); - if (prmtype.ty == Ttuple) + if (TypeTuple tt = prmtype.isTypeTuple()) { - TypeTuple tt = cast(TypeTuple)prmtype; - size_t tt_dim = tt.arguments.length; + const tt_dim = tt.arguments.length; for (size_t j = 0; j < tt_dim; j++, ++argi) { Parameter p = (*tt.arguments)[j]; if (j == tt_dim - 1 && fparameters.varargs == VarArg.typesafe && - parami + 1 == nfparams && argi < nfargs) + parami + 1 == nfparams && argi < fargs.length) { prmtype = p.type; goto Lvarargs; } - if (argi >= nfargs) + if (argi >= fargs.length) { if (p.defaultArg) continue; @@ -1711,7 +1729,7 @@ extern (C++) final class TemplateDeclaration : ScopeDsymbol return nomatch(); } - farg = (*fargs)[argi]; + farg = fargs[argi]; if (!farg.implicitConvTo(p.type)) return nomatch(); } @@ -1719,7 +1737,7 @@ extern (C++) final class TemplateDeclaration : ScopeDsymbol } } - if (argi >= nfargs) // if not enough arguments + if (argi >= fargs.length) // if not enough arguments { if (!fparam.defaultArg) goto Lvarargs; @@ -1741,7 +1759,7 @@ extern (C++) final class TemplateDeclaration : ScopeDsymbol * // at fparam `N start = 0`, N should be 'size_t' before * // the deduction result from fparam.defaultArg. */ - if (argi == nfargs) + if (argi == fargs.length) { foreach (ref dedtype; *dedtypes) { @@ -1769,7 +1787,7 @@ extern (C++) final class TemplateDeclaration : ScopeDsymbol * the oded == oarg */ (*dedargs)[i] = oded; - MATCH m2 = tparam.matchArg(instLoc, paramscope, dedargs, i, parameters, dedtypes, null); + MATCH m2 = tparam.matchArg(instLoc, paramscope, dedargs, i, parameters, *dedtypes, null); //printf("m2 = %d\n", m2); if (m2 == MATCH.nomatch) return nomatch(); @@ -1822,7 +1840,7 @@ extern (C++) final class TemplateDeclaration : ScopeDsymbol } else { - farg = (*fargs)[argi]; + farg = fargs[argi]; } { // Check invalid arguments to detect errors early. @@ -1851,8 +1869,15 @@ extern (C++) final class TemplateDeclaration : ScopeDsymbol { /* Allow expressions that have CT-known boundaries and type [] to match with [dim] */ - Type taai; - if (argtype.ty == Tarray && (prmtype.ty == Tsarray || prmtype.ty == Taarray && (taai = (cast(TypeAArray)prmtype).index).ty == Tident && (cast(TypeIdentifier)taai).idents.length == 0)) + bool inferIndexType = (argtype.ty == Tarray) && (prmtype.ty == Tsarray || prmtype.ty == Taarray); + if (auto aaType = prmtype.isTypeAArray()) + { + if (auto indexType = aaType.index.isTypeIdentifier()) + { + inferIndexType = indexType.idents.length == 0; + } + } + if (inferIndexType) { if (StringExp se = farg.isStringExp()) { @@ -1871,7 +1896,7 @@ extern (C++) final class TemplateDeclaration : ScopeDsymbol oarg = argtype; } - else if ((fparam.storageClass & STC.out_) == 0 && (argtype.ty == Tarray || argtype.ty == Tpointer) && templateParameterLookup(prmtype, parameters) != IDX_NOTFOUND && (cast(TypeIdentifier)prmtype).idents.length == 0) + else if ((fparam.storageClass & STC.out_) == 0 && (argtype.ty == Tarray || argtype.ty == Tpointer) && templateParameterLookup(prmtype, parameters) != IDX_NOTFOUND && prmtype.isTypeIdentifier().idents.length == 0) { /* The farg passing to the prmtype always make a copy. Therefore, * we can shrink the set of the deduced type arguments for prmtype @@ -1892,11 +1917,11 @@ extern (C++) final class TemplateDeclaration : ScopeDsymbol } } - if (fparameters.varargs == VarArg.typesafe && parami + 1 == nfparams && argi + 1 < nfargs) + if (fparameters.varargs == VarArg.typesafe && parami + 1 == nfparams && argi + 1 < fargs.length) goto Lvarargs; uint im = 0; - MATCH m = deduceType(oarg, paramscope, prmtype, parameters, dedtypes, &im, inferStart); + MATCH m = deduceType(oarg, paramscope, prmtype, *parameters, *dedtypes, &im, inferStart); //printf("\tL%d deduceType m = %d, im = x%x, inoutMatch = x%x\n", __LINE__, m, im, inoutMatch); inoutMatch |= im; @@ -1984,17 +2009,15 @@ extern (C++) final class TemplateDeclaration : ScopeDsymbol case Taarray: { // Perhaps we can do better with this, see TypeFunction.callMatch() - if (tb.ty == Tsarray) + if (TypeSArray tsa = tb.isTypeSArray()) { - TypeSArray tsa = cast(TypeSArray)tb; dinteger_t sz = tsa.dim.toInteger(); - if (sz != nfargs - argi) + if (sz != fargs.length - argi) return nomatch(); } - else if (tb.ty == Taarray) + else if (TypeAArray taa = tb.isTypeAArray()) { - TypeAArray taa = cast(TypeAArray)tb; - Expression dim = new IntegerExp(instLoc, nfargs - argi, Type.tsize_t); + Expression dim = new IntegerExp(instLoc, fargs.length - argi, Type.tsize_t); size_t i = templateParameterLookup(taa.index, parameters); if (i == IDX_NOTFOUND) @@ -2057,9 +2080,9 @@ extern (C++) final class TemplateDeclaration : ScopeDsymbol { TypeArray ta = cast(TypeArray)tb; Type tret = fparam.isLazyArray(); - for (; argi < nfargs; argi++) + for (; argi < fargs.length; argi++) { - Expression arg = (*fargs)[argi]; + Expression arg = fargs[argi]; assert(arg); MATCH m; @@ -2085,7 +2108,7 @@ extern (C++) final class TemplateDeclaration : ScopeDsymbol else { uint wm = 0; - m = deduceType(arg, paramscope, ta.next, parameters, dedtypes, &wm, inferStart); + m = deduceType(arg, paramscope, ta.next, *parameters, *dedtypes, &wm, inferStart); inoutMatch |= wm; } if (m == MATCH.nomatch) @@ -2112,8 +2135,7 @@ extern (C++) final class TemplateDeclaration : ScopeDsymbol Lmatch: foreach (ref dedtype; *dedtypes) { - Type at = isType(dedtype); - if (at) + if (Type at = isType(dedtype)) { if (at.ty == Tnone) { @@ -2147,7 +2169,7 @@ extern (C++) final class TemplateDeclaration : ScopeDsymbol * the oded == oarg */ (*dedargs)[i] = oded; - MATCH m2 = tparam.matchArg(instLoc, paramscope, dedargs, i, parameters, dedtypes, null); + MATCH m2 = tparam.matchArg(instLoc, paramscope, dedargs, i, parameters, *dedtypes, null); //printf("m2 = %d\n", m2); if (m2 == MATCH.nomatch) return nomatch(); @@ -2194,7 +2216,7 @@ extern (C++) final class TemplateDeclaration : ScopeDsymbol if (tparam.specialization()) { (*dedargs)[i] = oded; - MATCH m2 = tparam.matchArg(instLoc, paramscope, dedargs, i, parameters, dedtypes, null); + MATCH m2 = tparam.matchArg(instLoc, paramscope, dedargs, i, parameters, *dedtypes, null); //printf("m2 = %d\n", m2); if (m2 == MATCH.nomatch) return nomatch(); @@ -2233,7 +2255,7 @@ extern (C++) final class TemplateDeclaration : ScopeDsymbol sc2.minst = sc.minst; sc2.stc |= fd.storage_class & STC.deprecated_; - fd = doHeaderInstantiation(ti, sc2, fd, tthis, fargs); + fd = doHeaderInstantiation(ti, sc2, fd, tthis, argumentList.arguments); sc2 = sc2.pop(); sc2 = sc2.pop(); @@ -2396,7 +2418,7 @@ extern (C++) final class TemplateDeclaration : ScopeDsymbol } if (hasttp) { - tf = cast(TypeFunction)tf.addSTC(ModToStc(tthis.mod)); + tf = tf.addSTC(ModToStc(tthis.mod)).isTypeFunction(); assert(!tf.deco); } } @@ -2602,10 +2624,10 @@ extern (C++) final class TypeDeduced : Type * tiargs = initial list of template arguments * tthis = if !NULL, the 'this' pointer argument * argumentList= arguments to function - * pMessage = address to store error message, or null + * errorHelper = delegate to send error message to if not null */ void functionResolve(ref MatchAccumulator m, Dsymbol dstart, Loc loc, Scope* sc, Objects* tiargs, - Type tthis, ArgumentList argumentList, const(char)** pMessage = null) + Type tthis, ArgumentList argumentList, void delegate(const(char)*) scope errorHelper = null) { version (none) { @@ -2662,7 +2684,7 @@ void functionResolve(ref MatchAccumulator m, Dsymbol dstart, Loc loc, Scope* sc, return 1; } //printf("fd = %s %s, fargs = %s\n", fd.toChars(), fd.type.toChars(), fargs.toChars()); - auto tf = cast(TypeFunction)fd.type; + auto tf = fd.type.isTypeFunction(); int prop = tf.isproperty ? 1 : 2; if (property == 0) @@ -2711,8 +2733,12 @@ void functionResolve(ref MatchAccumulator m, Dsymbol dstart, Loc loc, Scope* sc, else if (shared_this && !shared_dtor && tthis_fd !is null) tf.mod = tthis_fd.mod; } - MATCH mfa = tf.callMatch(tthis_fd, argumentList, 0, pMessage, sc); + const(char)* failMessage; + const(char)** pMessage = errorHelper ? &failMessage : null; + MATCH mfa = tf.callMatch(tthis_fd, argumentList, 0, errorHelper, sc); //printf("test1: mfa = %d\n", mfa); + if (failMessage) + errorHelper(failMessage); if (mfa == MATCH.nomatch) return 0; @@ -2850,7 +2876,7 @@ void functionResolve(ref MatchAccumulator m, Dsymbol dstart, Loc loc, Scope* sc, auto ti = new TemplateInstance(loc, td, tiargs); Objects dedtypes = Objects(td.parameters.length); assert(td.semanticRun != PASS.initial); - MATCH mta = td.matchWithInstance(sc, ti, &dedtypes, argumentList, 0); + MATCH mta = td.matchWithInstance(sc, ti, dedtypes, argumentList, 0); //printf("matchWithInstance = %d\n", mta); if (mta == MATCH.nomatch || mta < ta_last) // no match or less match return 0; @@ -2869,7 +2895,7 @@ void functionResolve(ref MatchAccumulator m, Dsymbol dstart, Loc loc, Scope* sc, // Check for recursive instantiation of tdx. for (TemplatePrevious* p = tdx.previous; p; p = p.prev) { - if (arrayObjectMatch(p.dedargs, &dedtypesX)) + if (arrayObjectMatch(*p.dedargs, dedtypesX)) { //printf("recursive, no match p.sc=%p %p %s\n", p.sc, this, this.toChars()); /* It must be a subscope of p.sc, other scope chains are not recursive @@ -2918,7 +2944,7 @@ void functionResolve(ref MatchAccumulator m, Dsymbol dstart, Loc loc, Scope* sc, Type tthis_fd = fd.needThis() && !fd.isCtorDeclaration() ? tthis : null; - auto tf = cast(TypeFunction)fd.type; + auto tf = fd.type.isTypeFunction(); MATCH mfa = tf.callMatch(tthis_fd, argumentList, 0, null, sc); if (mfa < m.last) return 0; @@ -2979,7 +3005,7 @@ void functionResolve(ref MatchAccumulator m, Dsymbol dstart, Loc loc, Scope* sc, if (isCtorCall) { // Constructor call requires additional check. - auto tf = cast(TypeFunction)fd.type; + auto tf = fd.type.isTypeFunction(); assert(tf.next); if (MODimplicitConv(tf.mod, tthis_fd.mod) || tf.isWild() && tf.isShared() == tthis_fd.isShared() || @@ -3175,9 +3201,8 @@ private size_t templateIdentifierLookup(Identifier id, TemplateParameters* param private size_t templateParameterLookup(Type tparam, TemplateParameters* parameters) { - if (tparam.ty == Tident) + if (TypeIdentifier tident = tparam.isTypeIdentifier()) { - TypeIdentifier tident = cast(TypeIdentifier)tparam; //printf("\ttident = '%s'\n", tident.toChars()); return templateIdentifierLookup(tident.ident, parameters); } @@ -3267,7 +3292,7 @@ private Type rawTypeMerge(Type t1, Type t2) return null; } -private MATCH deduceTypeHelper(Type t, Type* at, Type tparam) +private MATCH deduceTypeHelper(Type t, out Type at, Type tparam) { // 9*9 == 81 cases @@ -3297,7 +3322,7 @@ private MATCH deduceTypeHelper(Type t, Type* at, Type tparam) // foo(U) shared(inout(const(T))) => shared(inout(const(T))) // foo(U) immutable(T) => immutable(T) { - *at = t; + at = t; return MATCH.exact; } case X(MODFlags.const_, MODFlags.const_): @@ -3317,7 +3342,7 @@ private MATCH deduceTypeHelper(Type t, Type* at, Type tparam) // foo(shared(inout(const(U)))) shared(inout(const(T))) => T // foo(immutable(U)) immutable(T) => T { - *at = t.mutableOf().unSharedOf(); + at = t.mutableOf().unSharedOf(); return MATCH.exact; } case X(MODFlags.const_, MODFlags.shared_ | MODFlags.const_): @@ -3327,7 +3352,7 @@ private MATCH deduceTypeHelper(Type t, Type* at, Type tparam) // foo(inout(U)) shared(inout(T)) => shared(T) // foo(inout(const(U))) shared(inout(const(T))) => shared(T) { - *at = t.mutableOf(); + at = t.mutableOf(); return MATCH.exact; } case X(MODFlags.const_, 0): @@ -3345,13 +3370,13 @@ private MATCH deduceTypeHelper(Type t, Type* at, Type tparam) // foo(const(U)) immutable(T) => T // foo(shared(const(U))) immutable(T) => T { - *at = t.mutableOf(); + at = t.mutableOf(); return MATCH.constant; } case X(MODFlags.const_, MODFlags.shared_): // foo(const(U)) shared(T) => shared(T) { - *at = t; + at = t; return MATCH.constant; } case X(MODFlags.shared_, MODFlags.shared_ | MODFlags.const_): @@ -3361,13 +3386,13 @@ private MATCH deduceTypeHelper(Type t, Type* at, Type tparam) // foo(shared(U)) shared(inout(T)) => inout(T) // foo(shared(U)) shared(inout(const(T))) => inout(const(T)) { - *at = t.unSharedOf(); + at = t.unSharedOf(); return MATCH.exact; } case X(MODFlags.shared_ | MODFlags.const_, MODFlags.shared_): // foo(shared(const(U))) shared(T) => T { - *at = t.unSharedOf(); + at = t.unSharedOf(); return MATCH.constant; } case X(MODFlags.wildconst, MODFlags.immutable_): @@ -3379,13 +3404,13 @@ private MATCH deduceTypeHelper(Type t, Type* at, Type tparam) // foo(shared(inout(const(U)))) immutable(T) => T // foo(shared(inout(const(U)))) shared(inout(T)) => T { - *at = t.unSharedOf().mutableOf(); + at = t.unSharedOf().mutableOf(); return MATCH.constant; } case X(MODFlags.shared_ | MODFlags.const_, MODFlags.shared_ | MODFlags.wild): // foo(shared(const(U))) shared(inout(T)) => T { - *at = t.unSharedOf().mutableOf(); + at = t.unSharedOf().mutableOf(); return MATCH.constant; } case X(MODFlags.wild, 0): @@ -3499,30 +3524,16 @@ __gshared Expression emptyArrayElement = null; * Output: * dedtypes = [ int ] // Array of Expression/Type's */ -MATCH deduceType(RootObject o, Scope* sc, Type tparam, TemplateParameters* parameters, Objects* dedtypes, uint* wm = null, size_t inferStart = 0, bool ignoreAliasThis = false) +MATCH deduceType(RootObject o, Scope* sc, Type tparam, ref TemplateParameters parameters, ref Objects dedtypes, uint* wm = null, size_t inferStart = 0, bool ignoreAliasThis = false) { extern (C++) final class DeduceType : Visitor { alias visit = Visitor.visit; public: - Scope* sc; - Type tparam; - TemplateParameters* parameters; - Objects* dedtypes; - uint* wm; - size_t inferStart; - bool ignoreAliasThis; MATCH result; - extern (D) this(Scope* sc, Type tparam, TemplateParameters* parameters, Objects* dedtypes, uint* wm, size_t inferStart, bool ignoreAliasThis) @safe + extern (D) this() @safe { - this.sc = sc; - this.tparam = tparam; - this.parameters = parameters; - this.dedtypes = dedtypes; - this.wm = wm; - this.inferStart = inferStart; - this.ignoreAliasThis = ignoreAliasThis; result = MATCH.nomatch; } @@ -3537,7 +3548,7 @@ MATCH deduceType(RootObject o, Scope* sc, Type tparam, TemplateParameters* param if (tparam.ty == Tident) { // Determine which parameter tparam is - size_t i = templateParameterLookup(tparam, parameters); + size_t i = templateParameterLookup(tparam, ¶meters); if (i == IDX_NOTFOUND) { if (!sc) @@ -3548,7 +3559,7 @@ MATCH deduceType(RootObject o, Scope* sc, Type tparam, TemplateParameters* param Loc loc; if (parameters.length) { - TemplateParameter tp = (*parameters)[0]; + TemplateParameter tp = parameters[0]; loc = tp.loc; } @@ -3561,9 +3572,9 @@ MATCH deduceType(RootObject o, Scope* sc, Type tparam, TemplateParameters* param return; } - TemplateParameter tp = (*parameters)[i]; + TemplateParameter tp = parameters[i]; - TypeIdentifier tident = cast(TypeIdentifier)tparam; + TypeIdentifier tident = tparam.isTypeIdentifier(); if (tident.idents.length > 0) { //printf("matching %s to %s\n", tparam.toChars(), t.toChars()); @@ -3601,21 +3612,21 @@ MATCH deduceType(RootObject o, Scope* sc, Type tparam, TemplateParameters* param Type tt = s.getType(); if (!tt) goto Lnomatch; - Type at = cast(Type)(*dedtypes)[i]; + Type at = cast(Type)dedtypes[i]; if (at && at.ty == Tnone) at = (cast(TypeDeduced)at).tded; if (!at || tt.equals(at)) { - (*dedtypes)[i] = tt; + dedtypes[i] = tt; goto Lexact; } } if (tp.isTemplateAliasParameter()) { - Dsymbol s2 = cast(Dsymbol)(*dedtypes)[i]; + Dsymbol s2 = cast(Dsymbol)dedtypes[i]; if (!s2 || s == s2) { - (*dedtypes)[i] = s; + dedtypes[i] = s; goto Lexact; } } @@ -3637,7 +3648,7 @@ MATCH deduceType(RootObject o, Scope* sc, Type tparam, TemplateParameters* param +/ if (auto ta = tp.isTemplateAliasParameter()) { - (*dedtypes)[i] = t; + dedtypes[i] = t; goto Lexact; } // (23578) - ensure previous behaviour for non-alias template params @@ -3646,14 +3657,14 @@ MATCH deduceType(RootObject o, Scope* sc, Type tparam, TemplateParameters* param goto Lnomatch; } - Type at = cast(Type)(*dedtypes)[i]; + Type at = cast(Type)dedtypes[i]; Type tt; if (ubyte wx = wm ? deduceWildHelper(t, &tt, tparam) : 0) { // type vs (none) if (!at) { - (*dedtypes)[i] = tt; + dedtypes[i] = tt; *wm |= wx; result = MATCH.constant; return; @@ -3662,11 +3673,11 @@ MATCH deduceType(RootObject o, Scope* sc, Type tparam, TemplateParameters* param // type vs expressions if (at.ty == Tnone) { - TypeDeduced xt = cast(TypeDeduced)at; + auto xt = cast(TypeDeduced)at; result = xt.matchAll(tt); if (result > MATCH.nomatch) { - (*dedtypes)[i] = tt; + dedtypes[i] = tt; if (result > MATCH.constant) result = MATCH.constant; // limit level for inout matches } @@ -3676,29 +3687,29 @@ MATCH deduceType(RootObject o, Scope* sc, Type tparam, TemplateParameters* param // type vs type if (tt.equals(at)) { - (*dedtypes)[i] = tt; // Prefer current type match + dedtypes[i] = tt; // Prefer current type match goto Lconst; } if (tt.implicitConvTo(at.constOf())) { - (*dedtypes)[i] = at.constOf().mutableOf(); + dedtypes[i] = at.constOf().mutableOf(); *wm |= MODFlags.const_; goto Lconst; } if (at.implicitConvTo(tt.constOf())) { - (*dedtypes)[i] = tt.constOf().mutableOf(); + dedtypes[i] = tt.constOf().mutableOf(); *wm |= MODFlags.const_; goto Lconst; } goto Lnomatch; } - else if (MATCH m = deduceTypeHelper(t, &tt, tparam)) + else if (MATCH m = deduceTypeHelper(t, tt, tparam)) { // type vs (none) if (!at) { - (*dedtypes)[i] = tt; + dedtypes[i] = tt; result = m; return; } @@ -3706,11 +3717,11 @@ MATCH deduceType(RootObject o, Scope* sc, Type tparam, TemplateParameters* param // type vs expressions if (at.ty == Tnone) { - TypeDeduced xt = cast(TypeDeduced)at; + auto xt = cast(TypeDeduced)at; result = xt.matchAll(tt); if (result > MATCH.nomatch) { - (*dedtypes)[i] = tt; + dedtypes[i] = tt; } return; } @@ -3740,7 +3751,7 @@ MATCH deduceType(RootObject o, Scope* sc, Type tparam, TemplateParameters* param Loc loc; if (parameters.length) { - TemplateParameter tp = (*parameters)[0]; + TemplateParameter tp = parameters[0]; loc = tp.loc; } @@ -3757,9 +3768,8 @@ MATCH deduceType(RootObject o, Scope* sc, Type tparam, TemplateParameters* param MATCH m = t.implicitConvTo(tparam); if (m == MATCH.nomatch && !ignoreAliasThis) { - if (t.ty == Tclass) + if (auto tc = t.isTypeClass()) { - TypeClass tc = cast(TypeClass)t; if (tc.sym.aliasthis && !(tc.att & AliasThisRec.tracingDT)) { if (auto ato = t.aliasthisOf()) @@ -3770,9 +3780,8 @@ MATCH deduceType(RootObject o, Scope* sc, Type tparam, TemplateParameters* param } } } - else if (t.ty == Tstruct) + else if (auto ts = t.isTypeStruct()) { - TypeStruct ts = cast(TypeStruct)t; if (ts.sym.aliasthis && !(ts.att & AliasThisRec.tracingDT)) { if (auto ato = t.aliasthisOf()) @@ -3822,9 +3831,8 @@ MATCH deduceType(RootObject o, Scope* sc, Type tparam, TemplateParameters* param override void visit(TypeVector t) { - if (tparam.ty == Tvector) + if (auto tp = tparam.isTypeVector()) { - TypeVector tp = cast(TypeVector)tparam; result = deduceType(t.basetype, sc, tp.basetype, parameters, dedtypes, wm); return; } @@ -3851,25 +3859,23 @@ MATCH deduceType(RootObject o, Scope* sc, Type tparam, TemplateParameters* param TemplateParameter tp = null; Expression edim = null; size_t i; - if (tparam.ty == Tsarray) + if (auto tsa = tparam.isTypeSArray()) { - TypeSArray tsa = cast(TypeSArray)tparam; if (tsa.dim.isVarExp() && tsa.dim.isVarExp().var.storage_class & STC.templateparameter) { Identifier id = tsa.dim.isVarExp().var.ident; - i = templateIdentifierLookup(id, parameters); + i = templateIdentifierLookup(id, ¶meters); assert(i != IDX_NOTFOUND); - tp = (*parameters)[i]; + tp = parameters[i]; } else edim = tsa.dim; } - else if (tparam.ty == Taarray) + else if (auto taa = tparam.isTypeAArray()) { - TypeAArray taa = cast(TypeAArray)tparam; - i = templateParameterLookup(taa.index, parameters); + i = templateParameterLookup(taa.index, ¶meters); if (i != IDX_NOTFOUND) - tp = (*parameters)[i]; + tp = parameters[i]; else { Loc loc; @@ -3878,7 +3884,7 @@ MATCH deduceType(RootObject o, Scope* sc, Type tparam, TemplateParameters* param // so we use that for the resolution (better error message). if (inferStart < parameters.length) { - TemplateParameter loctp = (*parameters)[inferStart]; + TemplateParameter loctp = parameters[inferStart]; loc = loctp.loc; } @@ -3889,7 +3895,7 @@ MATCH deduceType(RootObject o, Scope* sc, Type tparam, TemplateParameters* param edim = s ? getValue(s) : getValue(e); } } - if (tp && tp.matchArg(sc, t.dim, i, parameters, dedtypes, null) || edim && edim.toInteger() == t.dim.toInteger()) + if (tp && tp.matchArg(sc, t.dim, i, ¶meters, dedtypes, null) || edim && edim.toInteger() == t.dim.toInteger()) { result = deduceType(t.next, sc, tparam.nextOf(), parameters, dedtypes, wm); return; @@ -3903,7 +3909,7 @@ MATCH deduceType(RootObject o, Scope* sc, Type tparam, TemplateParameters* param // Extra check that index type must match if (tparam && tparam.ty == Taarray) { - TypeAArray tp = cast(TypeAArray)tparam; + TypeAArray tp = tparam.isTypeAArray(); if (!deduceType(t.index, sc, tp.index, parameters, dedtypes)) { result = MATCH.nomatch; @@ -3936,7 +3942,7 @@ MATCH deduceType(RootObject o, Scope* sc, Type tparam, TemplateParameters* param // https://issues.dlang.org/show_bug.cgi?id=15243 // Resolve parameter type if it's not related with template parameters - if (!reliesOnTemplateParameters(fparam.type, (*parameters)[inferStart .. parameters.length])) + if (!reliesOnTemplateParameters(fparam.type, parameters[inferStart .. parameters.length])) { auto tx = fparam.type.typeSemantic(Loc.initial, sc); if (tx.ty == Terror) @@ -3948,7 +3954,7 @@ MATCH deduceType(RootObject o, Scope* sc, Type tparam, TemplateParameters* param } } - size_t nfargs = t.parameterList.length; + const size_t nfargs = t.parameterList.length; size_t nfparams = tp.parameterList.length; /* See if tuple match @@ -3963,7 +3969,7 @@ MATCH deduceType(RootObject o, Scope* sc, Type tparam, TemplateParameters* param assert(fparam.type); if (fparam.type.ty != Tident) goto L1; - TypeIdentifier tid = cast(TypeIdentifier)fparam.type; + TypeIdentifier tid = fparam.type.isTypeIdentifier(); if (tid.idents.length) goto L1; @@ -3974,7 +3980,7 @@ MATCH deduceType(RootObject o, Scope* sc, Type tparam, TemplateParameters* param { if (tupi == parameters.length) goto L1; - TemplateParameter tx = (*parameters)[tupi]; + TemplateParameter tx = parameters[tupi]; TemplateTupleParameter tup = tx.isTemplateTupleParameter(); if (tup && tup.ident.equals(tid.ident)) break; @@ -3987,7 +3993,7 @@ MATCH deduceType(RootObject o, Scope* sc, Type tparam, TemplateParameters* param /* See if existing tuple, and whether it matches or not */ - RootObject o = (*dedtypes)[tupi]; + RootObject o = dedtypes[tupi]; if (o) { // Existing deduced argument must be a tuple, and must match @@ -4016,7 +4022,7 @@ MATCH deduceType(RootObject o, Scope* sc, Type tparam, TemplateParameters* param Parameter arg = t.parameterList[nfparams - 1 + i]; tup.objects[i] = arg.type; } - (*dedtypes)[tupi] = tup; + dedtypes[tupi] = tup; } nfparams--; // don't consider the last parameter for type deduction goto L2; @@ -4053,7 +4059,7 @@ MATCH deduceType(RootObject o, Scope* sc, Type tparam, TemplateParameters* param // Extra check if (tparam && tparam.ty == Tident) { - TypeIdentifier tp = cast(TypeIdentifier)tparam; + TypeIdentifier tp = tparam.isTypeIdentifier(); for (size_t i = 0; i < t.idents.length; i++) { RootObject id1 = t.idents[i]; @@ -4076,7 +4082,7 @@ MATCH deduceType(RootObject o, Scope* sc, Type tparam, TemplateParameters* param TemplateDeclaration tempdecl = t.tempinst.tempdecl.isTemplateDeclaration(); assert(tempdecl); - TypeInstance tp = cast(TypeInstance)tparam; + TypeInstance tp = tparam.isTypeInstance(); //printf("tempinst.tempdecl = %p\n", tempdecl); //printf("tp.tempinst.tempdecl = %p\n", tp.tempinst.tempdecl); @@ -4087,7 +4093,7 @@ MATCH deduceType(RootObject o, Scope* sc, Type tparam, TemplateParameters* param /* Handle case of: * template Foo(T : sa!(T), alias sa) */ - size_t i = templateIdentifierLookup(tp.tempinst.name, parameters); + size_t i = templateIdentifierLookup(tp.tempinst.name, ¶meters); if (i == IDX_NOTFOUND) { /* Didn't find it as a parameter identifier. Try looking @@ -4132,15 +4138,15 @@ MATCH deduceType(RootObject o, Scope* sc, Type tparam, TemplateParameters* param goto Lnomatch; } - TemplateParameter tpx = (*parameters)[i]; - if (!tpx.matchArg(sc, tempdecl, i, parameters, dedtypes, null)) + TemplateParameter tpx = parameters[i]; + if (!tpx.matchArg(sc, tempdecl, i, ¶meters, dedtypes, null)) goto Lnomatch; } else if (tempdecl != tp.tempinst.tempdecl) goto Lnomatch; L2: - if (!resolveTemplateInstantiation(t.tempinst.tiargs, &t.tempinst.tdtypes, tempdecl, tp, dedtypes)) + if (!resolveTemplateInstantiation(sc, ¶meters, t.tempinst.tiargs, &t.tempinst.tdtypes, tempdecl, tp, &dedtypes)) goto Lnomatch; } visit(cast(Type)t); @@ -4151,198 +4157,6 @@ MATCH deduceType(RootObject o, Scope* sc, Type tparam, TemplateParameters* param result = MATCH.nomatch; } - /******************** - * Match template `parameters` to the target template instance. - * Example: - * struct Temp(U, int Z) {} - * void foo(T)(Temp!(T, 3)); - * foo(Temp!(int, 3)()); - * Input: - * this.parameters = template params of foo -> [T] - * tiargs = .tiargs -> [int, 3] - * tdtypes = .tdtypes -> [int, 3] - * tempdecl = -> [T, Z] - * tp = - * Output: - * dedtypes = deduced params of `foo(Temp!(int, 3)())` -> [int] - */ - private bool resolveTemplateInstantiation(Objects* tiargs, Objects* tdtypes, TemplateDeclaration tempdecl, TypeInstance tp, Objects* dedtypes) - { - for (size_t i = 0; 1; i++) - { - //printf("\ttest: tempinst.tiargs[%zu]\n", i); - RootObject o1 = null; - if (i < tiargs.length) - o1 = (*tiargs)[i]; - else if (i < tdtypes.length && i < tp.tempinst.tiargs.length) - { - // Pick up default arg - o1 = (*tdtypes)[i]; - } - else if (i >= tp.tempinst.tiargs.length) - break; - //printf("\ttest: o1 = %s\n", o1.toChars()); - if (i >= tp.tempinst.tiargs.length) - { - size_t dim = tempdecl.parameters.length - (tempdecl.isVariadic() ? 1 : 0); - while (i < dim && ((*tempdecl.parameters)[i].dependent || (*tempdecl.parameters)[i].hasDefaultArg())) - { - i++; - } - if (i >= dim) - break; // match if all remained parameters are dependent - return false; - } - - RootObject o2 = (*tp.tempinst.tiargs)[i]; - Type t2 = isType(o2); - //printf("\ttest: o2 = %s\n", o2.toChars()); - size_t j = (t2 && t2.ty == Tident && i == tp.tempinst.tiargs.length - 1) - ? templateParameterLookup(t2, parameters) : IDX_NOTFOUND; - if (j != IDX_NOTFOUND && j == parameters.length - 1 && - (*parameters)[j].isTemplateTupleParameter()) - { - /* Given: - * struct A(B...) {} - * alias A!(int, float) X; - * static if (is(X Y == A!(Z), Z...)) {} - * deduce that Z is a tuple(int, float) - */ - - /* Create tuple from remaining args - */ - size_t vtdim = (tempdecl.isVariadic() ? tiargs.length : tdtypes.length) - i; - auto vt = new Tuple(vtdim); - for (size_t k = 0; k < vtdim; k++) - { - RootObject o; - if (k < tiargs.length) - o = (*tiargs)[i + k]; - else // Pick up default arg - o = (*tdtypes)[i + k]; - vt.objects[k] = o; - } - - Tuple v = cast(Tuple)(*dedtypes)[j]; - if (v) - { - if (!match(v, vt)) - return false; - } - else - (*dedtypes)[j] = vt; - break; - } - else if (!o1) - break; - - Type t1 = isType(o1); - Dsymbol s1 = isDsymbol(o1); - Dsymbol s2 = isDsymbol(o2); - Expression e1 = s1 ? getValue(s1) : getValue(isExpression(o1)); - Expression e2 = isExpression(o2); - version (none) - { - Tuple v1 = isTuple(o1); - Tuple v2 = isTuple(o2); - if (t1) - printf("t1 = %s\n", t1.toChars()); - if (t2) - printf("t2 = %s\n", t2.toChars()); - if (e1) - printf("e1 = %s\n", e1.toChars()); - if (e2) - printf("e2 = %s\n", e2.toChars()); - if (s1) - printf("s1 = %s\n", s1.toChars()); - if (s2) - printf("s2 = %s\n", s2.toChars()); - if (v1) - printf("v1 = %s\n", v1.toChars()); - if (v2) - printf("v2 = %s\n", v2.toChars()); - } - - if (t1 && t2) - { - if (!deduceType(t1, sc, t2, parameters, dedtypes)) - return false; - } - else if (e1 && e2) - { - Le: - e1 = e1.ctfeInterpret(); - - /* If it is one of the template parameters for this template, - * we should not attempt to interpret it. It already has a value. - */ - if (e2.op == EXP.variable && (e2.isVarExp().var.storage_class & STC.templateparameter)) - { - /* - * (T:Number!(e2), int e2) - */ - j = templateIdentifierLookup(e2.isVarExp().var.ident, parameters); - if (j != IDX_NOTFOUND) - goto L1; - // The template parameter was not from this template - // (it may be from a parent template, for example) - } - - e2 = e2.expressionSemantic(sc); // https://issues.dlang.org/show_bug.cgi?id=13417 - e2 = e2.ctfeInterpret(); - - //printf("e1 = %s, type = %s %d\n", e1.toChars(), e1.type.toChars(), e1.type.ty); - //printf("e2 = %s, type = %s %d\n", e2.toChars(), e2.type.toChars(), e2.type.ty); - if (!e1.equals(e2)) - { - if (!e2.implicitConvTo(e1.type)) - return false; - - e2 = e2.implicitCastTo(sc, e1.type); - e2 = e2.ctfeInterpret(); - if (!e1.equals(e2)) - return false; - } - } - else if (e1 && t2 && t2.ty == Tident) - { - j = templateParameterLookup(t2, parameters); - L1: - if (j == IDX_NOTFOUND) - { - t2.resolve((cast(TypeIdentifier)t2).loc, sc, e2, t2, s2); - if (e2) - goto Le; - return false; - } - if (!(*parameters)[j].matchArg(sc, e1, j, parameters, dedtypes, null)) - return false; - } - else if (s1 && s2) - { - Ls: - if (!s1.equals(s2)) - return false; - } - else if (s1 && t2 && t2.ty == Tident) - { - j = templateParameterLookup(t2, parameters); - if (j == IDX_NOTFOUND) - { - t2.resolve((cast(TypeIdentifier)t2).loc, sc, e2, t2, s2); - if (s2) - goto Ls; - return false; - } - if (!(*parameters)[j].matchArg(sc, s1, j, parameters, dedtypes, null)) - return false; - } - else - return false; - } - return true; - } - override void visit(TypeStruct t) { /* If this struct is a template struct, and we're matching @@ -4368,7 +4182,7 @@ MATCH deduceType(RootObject o, Scope* sc, Type tparam, TemplateParameters* param /* Match things like: * S!(T).foo */ - TypeInstance tpi = cast(TypeInstance)tparam; + TypeInstance tpi = tparam.isTypeInstance(); if (tpi.idents.length) { RootObject id = tpi.idents[tpi.idents.length - 1]; @@ -4391,7 +4205,7 @@ MATCH deduceType(RootObject o, Scope* sc, Type tparam, TemplateParameters* param // Extra check if (tparam && tparam.ty == Tstruct) { - TypeStruct tp = cast(TypeStruct)tparam; + TypeStruct tp = tparam.isTypeStruct(); //printf("\t%d\n", cast(MATCH) t.implicitConvTo(tp)); if (wm && t.deduceWild(tparam, false)) @@ -4410,7 +4224,7 @@ MATCH deduceType(RootObject o, Scope* sc, Type tparam, TemplateParameters* param // Extra check if (tparam && tparam.ty == Tenum) { - TypeEnum tp = cast(TypeEnum)tparam; + TypeEnum tp = tparam.isTypeEnum(); if (t.sym == tp.sym) visit(cast(Type)t); else @@ -4428,59 +4242,6 @@ MATCH deduceType(RootObject o, Scope* sc, Type tparam, TemplateParameters* param visit(cast(Type)t); } - /* Helper for TypeClass.deduceType(). - * Classes can match with implicit conversion to a base class or interface. - * This is complicated, because there may be more than one base class which - * matches. In such cases, one or more parameters remain ambiguous. - * For example, - * - * interface I(X, Y) {} - * class C : I(uint, double), I(char, double) {} - * C x; - * foo(T, U)( I!(T, U) x) - * - * deduces that U is double, but T remains ambiguous (could be char or uint). - * - * Given a baseclass b, and initial deduced types 'dedtypes', this function - * tries to match tparam with b, and also tries all base interfaces of b. - * If a match occurs, numBaseClassMatches is incremented, and the new deduced - * types are ANDed with the current 'best' estimate for dedtypes. - */ - static void deduceBaseClassParameters(ref BaseClass b, Scope* sc, Type tparam, TemplateParameters* parameters, Objects* dedtypes, Objects* best, ref int numBaseClassMatches) - { - TemplateInstance parti = b.sym ? b.sym.parent.isTemplateInstance() : null; - if (parti) - { - // Make a temporary copy of dedtypes so we don't destroy it - auto tmpdedtypes = new Objects(dedtypes.length); - memcpy(tmpdedtypes.tdata(), dedtypes.tdata(), dedtypes.length * (void*).sizeof); - - auto t = new TypeInstance(Loc.initial, parti); - MATCH m = deduceType(t, sc, tparam, parameters, tmpdedtypes); - if (m > MATCH.nomatch) - { - // If this is the first ever match, it becomes our best estimate - if (numBaseClassMatches == 0) - memcpy(best.tdata(), tmpdedtypes.tdata(), tmpdedtypes.length * (void*).sizeof); - else - for (size_t k = 0; k < tmpdedtypes.length; ++k) - { - // If we've found more than one possible type for a parameter, - // mark it as unknown. - if ((*tmpdedtypes)[k] != (*best)[k]) - (*best)[k] = (*dedtypes)[k]; - } - ++numBaseClassMatches; - } - } - - // Now recursively test the inherited interfaces - foreach (ref bi; b.baseInterfaces) - { - deduceBaseClassParameters(bi, sc, tparam, parameters, dedtypes, best, numBaseClassMatches); - } - } - override void visit(TypeClass t) { //printf("TypeClass.deduceType(this = %s)\n", t.toChars()); @@ -4509,7 +4270,7 @@ MATCH deduceType(RootObject o, Scope* sc, Type tparam, TemplateParameters* param /* Match things like: * S!(T).foo */ - TypeInstance tpi = cast(TypeInstance)tparam; + TypeInstance tpi = tparam.isTypeInstance(); if (tpi.idents.length) { RootObject id = tpi.idents[tpi.idents.length - 1]; @@ -4547,12 +4308,12 @@ MATCH deduceType(RootObject o, Scope* sc, Type tparam, TemplateParameters* param while (s && s.baseclasses.length > 0) { // Test the base class - deduceBaseClassParameters(*(*s.baseclasses)[0], sc, tparam, parameters, dedtypes, best, numBaseClassMatches); + deduceBaseClassParameters(*(*s.baseclasses)[0], sc, tparam, parameters, dedtypes, *best, numBaseClassMatches); // Test the interfaces inherited by the base class foreach (b; s.interfaces) { - deduceBaseClassParameters(*b, sc, tparam, parameters, dedtypes, best, numBaseClassMatches); + deduceBaseClassParameters(*b, sc, tparam, parameters, dedtypes, *best, numBaseClassMatches); } s = (*s.baseclasses)[0].sym; } @@ -4572,7 +4333,7 @@ MATCH deduceType(RootObject o, Scope* sc, Type tparam, TemplateParameters* param // Extra check if (tparam && tparam.ty == Tclass) { - TypeClass tp = cast(TypeClass)tparam; + TypeClass tp = tparam.isTypeClass(); //printf("\t%d\n", cast(MATCH) t.implicitConvTo(tp)); if (wm && t.deduceWild(tparam, false)) @@ -4589,8 +4350,8 @@ MATCH deduceType(RootObject o, Scope* sc, Type tparam, TemplateParameters* param override void visit(Expression e) { //printf("Expression.deduceType(e = %s)\n", e.toChars()); - size_t i = templateParameterLookup(tparam, parameters); - if (i == IDX_NOTFOUND || (cast(TypeIdentifier)tparam).idents.length > 0) + size_t i = templateParameterLookup(tparam, ¶meters); + if (i == IDX_NOTFOUND || tparam.isTypeIdentifier().idents.length > 0) { if (e == emptyArrayElement && tparam.ty == Tarray) { @@ -4602,13 +4363,13 @@ MATCH deduceType(RootObject o, Scope* sc, Type tparam, TemplateParameters* param return; } - TemplateTypeParameter tp = (*parameters)[i].isTemplateTypeParameter(); + TemplateTypeParameter tp = parameters[i].isTemplateTypeParameter(); if (!tp) return; // nomatch if (e == emptyArrayElement) { - if ((*dedtypes)[i]) + if (dedtypes[i]) { result = MATCH.exact; return; @@ -4630,14 +4391,14 @@ MATCH deduceType(RootObject o, Scope* sc, Type tparam, TemplateParameters* param tb.ty == Tstruct && tb.hasPointers(); } - Type at = cast(Type)(*dedtypes)[i]; + Type at = cast(Type)dedtypes[i]; Type tt; if (ubyte wx = deduceWildHelper(e.type, &tt, tparam)) { *wm |= wx; result = MATCH.constant; } - else if (MATCH m = deduceTypeHelper(e.type, &tt, tparam)) + else if (MATCH m = deduceTypeHelper(e.type, tt, tparam)) { result = m; } @@ -4658,7 +4419,7 @@ MATCH deduceType(RootObject o, Scope* sc, Type tparam, TemplateParameters* param // expression vs (none) if (!at) { - (*dedtypes)[i] = new TypeDeduced(tt, e, tparam); + dedtypes[i] = new TypeDeduced(tt, e, tparam); return; } @@ -4716,7 +4477,7 @@ MATCH deduceType(RootObject o, Scope* sc, Type tparam, TemplateParameters* param if (xt) xt.update(tt, e, tparam); else - (*dedtypes)[i] = tt; + dedtypes[i] = tt; result = match1; return; } @@ -4736,7 +4497,7 @@ MATCH deduceType(RootObject o, Scope* sc, Type tparam, TemplateParameters* param if (xt) xt.update(t, e, tparam); else - (*dedtypes)[i] = t; + dedtypes[i] = t; pt = tt.addMod(tparam.mod); if (*wm) @@ -4870,7 +4631,7 @@ MATCH deduceType(RootObject o, Scope* sc, Type tparam, TemplateParameters* param // Parameter types inference from 'tof' assert(e.td._scope); - TypeFunction tf = cast(TypeFunction)e.fd.type; + TypeFunction tf = e.fd.type.isTypeFunction(); //printf("\ttof = %s\n", tof.toChars()); //printf("\ttf = %s\n", tf.toChars()); const dim = tf.parameterList.length; @@ -4895,7 +4656,7 @@ MATCH deduceType(RootObject o, Scope* sc, Type tparam, TemplateParameters* param if (!pto) break; Type t = pto.type.syntaxCopy(); // https://issues.dlang.org/show_bug.cgi?id=11774 - if (reliesOnTemplateParameters(t, (*parameters)[inferStart .. parameters.length])) + if (reliesOnTemplateParameters(t, parameters[inferStart .. parameters.length])) return; t = t.typeSemantic(e.loc, sc); if (t.ty == Terror) @@ -4929,7 +4690,7 @@ MATCH deduceType(RootObject o, Scope* sc, Type tparam, TemplateParameters* param // Allow conversion from implicit function pointer to delegate if (e.tok == TOK.reserved && t.ty == Tpointer && tparam.ty == Tdelegate) { - TypeFunction tf = cast(TypeFunction)t.nextOf(); + TypeFunction tf = t.nextOf().isTypeFunction(); t = (new TypeDelegate(tf)).merge(); } //printf("tparam = %s <= e.type = %s, t = %s\n", tparam.toChars(), e.type.toChars(), t.toChars()); @@ -4959,7 +4720,7 @@ MATCH deduceType(RootObject o, Scope* sc, Type tparam, TemplateParameters* param } } - scope DeduceType v = new DeduceType(sc, tparam, parameters, dedtypes, wm, inferStart, ignoreAliasThis); + scope DeduceType v = new DeduceType(); if (Type t = isType(o)) t.accept(v); else if (Expression e = isExpression(o)) @@ -4972,6 +4733,254 @@ MATCH deduceType(RootObject o, Scope* sc, Type tparam, TemplateParameters* param return v.result; } + +/* Helper for TypeClass.deduceType(). + * Classes can match with implicit conversion to a base class or interface. + * This is complicated, because there may be more than one base class which + * matches. In such cases, one or more parameters remain ambiguous. + * For example, + * + * interface I(X, Y) {} + * class C : I(uint, double), I(char, double) {} + * C x; + * foo(T, U)( I!(T, U) x) + * + * deduces that U is double, but T remains ambiguous (could be char or uint). + * + * Given a baseclass b, and initial deduced types 'dedtypes', this function + * tries to match tparam with b, and also tries all base interfaces of b. + * If a match occurs, numBaseClassMatches is incremented, and the new deduced + * types are ANDed with the current 'best' estimate for dedtypes. + */ +private void deduceBaseClassParameters(ref BaseClass b, Scope* sc, Type tparam, ref TemplateParameters parameters, ref Objects dedtypes, ref Objects best, ref int numBaseClassMatches) +{ + TemplateInstance parti = b.sym ? b.sym.parent.isTemplateInstance() : null; + if (parti) + { + // Make a temporary copy of dedtypes so we don't destroy it + auto tmpdedtypes = new Objects(dedtypes.length); + memcpy(tmpdedtypes.tdata(), dedtypes.tdata(), dedtypes.length * (void*).sizeof); + + auto t = new TypeInstance(Loc.initial, parti); + MATCH m = deduceType(t, sc, tparam, parameters, *tmpdedtypes); + if (m > MATCH.nomatch) + { + // If this is the first ever match, it becomes our best estimate + if (numBaseClassMatches == 0) + memcpy(best.tdata(), tmpdedtypes.tdata(), tmpdedtypes.length * (void*).sizeof); + else + for (size_t k = 0; k < tmpdedtypes.length; ++k) + { + // If we've found more than one possible type for a parameter, + // mark it as unknown. + if ((*tmpdedtypes)[k] != best[k]) + best[k] = dedtypes[k]; + } + ++numBaseClassMatches; + } + } + + // Now recursively test the inherited interfaces + foreach (ref bi; b.baseInterfaces) + { + deduceBaseClassParameters(bi, sc, tparam, parameters, dedtypes, best, numBaseClassMatches); + } +} + +/******************** + * Match template `parameters` to the target template instance. + * Example: + * struct Temp(U, int Z) {} + * void foo(T)(Temp!(T, 3)); + * foo(Temp!(int, 3)()); + * Input: + * sc = context + * parameters = template params of foo -> [T] + * tiargs = .tiargs -> [int, 3] + * tdtypes = .tdtypes -> [int, 3] + * tempdecl = -> [T, Z] + * tp = + * Output: + * dedtypes = deduced params of `foo(Temp!(int, 3)())` -> [int] + */ +private bool resolveTemplateInstantiation(Scope* sc, TemplateParameters* parameters, Objects* tiargs, Objects* tdtypes, TemplateDeclaration tempdecl, TypeInstance tp, Objects* dedtypes) +{ + for (size_t i = 0; 1; i++) + { + //printf("\ttest: tempinst.tiargs[%zu]\n", i); + RootObject o1 = null; + if (i < tiargs.length) + o1 = (*tiargs)[i]; + else if (i < tdtypes.length && i < tp.tempinst.tiargs.length) + { + // Pick up default arg + o1 = (*tdtypes)[i]; + } + else if (i >= tp.tempinst.tiargs.length) + break; + //printf("\ttest: o1 = %s\n", o1.toChars()); + if (i >= tp.tempinst.tiargs.length) + { + size_t dim = tempdecl.parameters.length - (tempdecl.isVariadic() ? 1 : 0); + while (i < dim && ((*tempdecl.parameters)[i].dependent || (*tempdecl.parameters)[i].hasDefaultArg())) + { + i++; + } + if (i >= dim) + break; // match if all remained parameters are dependent + return false; + } + + RootObject o2 = (*tp.tempinst.tiargs)[i]; + Type t2 = isType(o2); + //printf("\ttest: o2 = %s\n", o2.toChars()); + size_t j = (t2 && t2.ty == Tident && i == tp.tempinst.tiargs.length - 1) + ? templateParameterLookup(t2, parameters) : IDX_NOTFOUND; + if (j != IDX_NOTFOUND && j == parameters.length - 1 && + (*parameters)[j].isTemplateTupleParameter()) + { + /* Given: + * struct A(B...) {} + * alias A!(int, float) X; + * static if (is(X Y == A!(Z), Z...)) {} + * deduce that Z is a tuple(int, float) + */ + + /* Create tuple from remaining args + */ + size_t vtdim = (tempdecl.isVariadic() ? tiargs.length : tdtypes.length) - i; + auto vt = new Tuple(vtdim); + for (size_t k = 0; k < vtdim; k++) + { + RootObject o; + if (k < tiargs.length) + o = (*tiargs)[i + k]; + else // Pick up default arg + o = (*tdtypes)[i + k]; + vt.objects[k] = o; + } + + Tuple v = cast(Tuple)(*dedtypes)[j]; + if (v) + { + if (!match(v, vt)) + return false; + } + else + (*dedtypes)[j] = vt; + break; + } + else if (!o1) + break; + + Type t1 = isType(o1); + Dsymbol s1 = isDsymbol(o1); + Dsymbol s2 = isDsymbol(o2); + Expression e1 = s1 ? getValue(s1) : getValue(isExpression(o1)); + Expression e2 = isExpression(o2); + version (none) + { + Tuple v1 = isTuple(o1); + Tuple v2 = isTuple(o2); + if (t1) + printf("t1 = %s\n", t1.toChars()); + if (t2) + printf("t2 = %s\n", t2.toChars()); + if (e1) + printf("e1 = %s\n", e1.toChars()); + if (e2) + printf("e2 = %s\n", e2.toChars()); + if (s1) + printf("s1 = %s\n", s1.toChars()); + if (s2) + printf("s2 = %s\n", s2.toChars()); + if (v1) + printf("v1 = %s\n", v1.toChars()); + if (v2) + printf("v2 = %s\n", v2.toChars()); + } + + if (t1 && t2) + { + if (!deduceType(t1, sc, t2, *parameters, *dedtypes)) + return false; + } + else if (e1 && e2) + { + Le: + e1 = e1.ctfeInterpret(); + + /* If it is one of the template parameters for this template, + * we should not attempt to interpret it. It already has a value. + */ + if (e2.op == EXP.variable && (e2.isVarExp().var.storage_class & STC.templateparameter)) + { + /* + * (T:Number!(e2), int e2) + */ + j = templateIdentifierLookup(e2.isVarExp().var.ident, parameters); + if (j != IDX_NOTFOUND) + goto L1; + // The template parameter was not from this template + // (it may be from a parent template, for example) + } + + e2 = e2.expressionSemantic(sc); // https://issues.dlang.org/show_bug.cgi?id=13417 + e2 = e2.ctfeInterpret(); + + //printf("e1 = %s, type = %s %d\n", e1.toChars(), e1.type.toChars(), e1.type.ty); + //printf("e2 = %s, type = %s %d\n", e2.toChars(), e2.type.toChars(), e2.type.ty); + if (!e1.equals(e2)) + { + if (!e2.implicitConvTo(e1.type)) + return false; + + e2 = e2.implicitCastTo(sc, e1.type); + e2 = e2.ctfeInterpret(); + if (!e1.equals(e2)) + return false; + } + } + else if (e1 && t2 && t2.ty == Tident) + { + j = templateParameterLookup(t2, parameters); + L1: + if (j == IDX_NOTFOUND) + { + t2.resolve((cast(TypeIdentifier)t2).loc, sc, e2, t2, s2); + if (e2) + goto Le; + return false; + } + if (!(*parameters)[j].matchArg(sc, e1, j, parameters, *dedtypes, null)) + return false; + } + else if (s1 && s2) + { + Ls: + if (!s1.equals(s2)) + return false; + } + else if (s1 && t2 && t2.ty == Tident) + { + j = templateParameterLookup(t2, parameters); + if (j == IDX_NOTFOUND) + { + t2.resolve((cast(TypeIdentifier)t2).loc, sc, e2, t2, s2); + if (s2) + goto Ls; + return false; + } + if (!(*parameters)[j].matchArg(sc, s1, j, parameters, *dedtypes, null)) + return false; + } + else + return false; + } + return true; +} + + /*********************************************************** * Check whether the type t representation relies on one or more the template parameters. * Params: @@ -5625,7 +5634,11 @@ extern (C++) final class TemplateValueParameter : TemplateParameter if (e) { e = e.syntaxCopy(); - if ((e = e.expressionSemantic(sc)) is null) + Scope* sc2 = sc.push(); + sc2.inDefaultArg = true; + e = e.expressionSemantic(sc2); + sc2.pop(); + if (e is null) return null; if (auto te = e.isTemplateExp()) { @@ -6176,7 +6189,7 @@ extern (C++) class TemplateInstance : ScopeDsymbol } //printf("parent = %s, ti.parent = %s\n", parent.toPrettyChars(), ti.parent.toPrettyChars()); - if (!arrayObjectMatch(&tdtypes, &ti.tdtypes)) + if (!arrayObjectMatch(tdtypes, ti.tdtypes)) goto Lnotequals; /* Template functions may have different instantiations based on @@ -6221,7 +6234,7 @@ extern (C++) class TemplateInstance : ScopeDsymbol if (!hash) { hash = cast(size_t)cast(void*)enclosing; - hash += arrayObjectHash(&tdtypes); + hash += arrayObjectHash(tdtypes); hash += hash == 0; } return hash; @@ -6691,6 +6704,12 @@ extern (C++) class TemplateInstance : ScopeDsymbol if (!tiargs) return true; bool err = false; + + // The arguments are not treated as part of a default argument, + // because they are evaluated at compile time. + sc = sc.push(); + sc.inDefaultArg = false; + for (size_t j = 0; j < tiargs.length; j++) { RootObject o = (*tiargs)[j]; @@ -6716,10 +6735,9 @@ extern (C++) class TemplateInstance : ScopeDsymbol } Ltype: - if (ta.ty == Ttuple) + if (TypeTuple tt = ta.isTypeTuple()) { // Expand tuple - TypeTuple tt = cast(TypeTuple)ta; size_t dim = tt.arguments.length; tiargs.remove(j); if (dim) @@ -6923,6 +6941,7 @@ extern (C++) class TemplateInstance : ScopeDsymbol } //printf("1: (*tiargs)[%d] = %p\n", j, (*tiargs)[j]); } + sc.pop(); version (none) { printf("-TemplateInstance.semanticTiargs()\n"); @@ -6982,7 +7001,7 @@ extern (C++) class TemplateInstance : ScopeDsymbol assert(tempdecl._scope); // Deduce tdtypes tdtypes.setDim(tempdecl.parameters.length); - if (!tempdecl.matchWithInstance(sc, this, &tdtypes, argumentList, 2)) + if (!tempdecl.matchWithInstance(sc, this, tdtypes, argumentList, 2)) { .error(loc, "%s `%s` incompatible arguments for template instantiation", kind, toPrettyChars); return false; @@ -7032,7 +7051,7 @@ extern (C++) class TemplateInstance : ScopeDsymbol dedtypes.zero(); assert(td.semanticRun != PASS.initial); - MATCH m = td.matchWithInstance(sc, this, &dedtypes, argumentList, 0); + MATCH m = td.matchWithInstance(sc, this, dedtypes, argumentList, 0); //printf("matchWithInstance = %d\n", m); if (m == MATCH.nomatch) // no match at all return 0; @@ -7158,7 +7177,7 @@ extern (C++) class TemplateInstance : ScopeDsymbol // print additional information, e.g. `foo` is not a type foreach (i, param; *tdecl.parameters) { - MATCH match = param.matchArg(loc, sc, tiargs, i, tdecl.parameters, &dedtypes, null); + MATCH match = param.matchArg(loc, sc, tiargs, i, tdecl.parameters, dedtypes, null); auto arg = (*tiargs)[i]; auto sym = arg.isDsymbol; auto exp = arg.isExpression; @@ -7262,7 +7281,7 @@ extern (C++) class TemplateInstance : ScopeDsymbol * to instantiate the template. */ //printf("tp = %p, td.parameters.length = %d, tiargs.length = %d\n", tp, td.parameters.length, tiargs.length); - auto tf = cast(TypeFunction)fd.type; + auto tf = fd.type.isTypeFunction(); if (tf.parameterList.length) { auto tp = td.isVariadic(); @@ -7308,7 +7327,7 @@ extern (C++) class TemplateInstance : ScopeDsymbol return 1; } } - MATCH m = td.matchWithInstance(sc, this, &dedtypes, ArgumentList(), 0); + MATCH m = td.matchWithInstance(sc, this, dedtypes, ArgumentList(), 0); if (m == MATCH.nomatch) return 0; } @@ -7992,7 +8011,7 @@ struct TemplateInstanceBox * dedtypes[] deduced arguments to template instance * *psparam set to symbol declared and initialized to dedtypes[i] */ -MATCH matchArg(TemplateParameter tp, Loc instLoc, Scope* sc, Objects* tiargs, size_t i, TemplateParameters* parameters, Objects* dedtypes, Declaration* psparam) +MATCH matchArg(TemplateParameter tp, Loc instLoc, Scope* sc, Objects* tiargs, size_t i, TemplateParameters* parameters, ref Objects dedtypes, Declaration* psparam) { MATCH matchArgNoMatch() { @@ -8015,7 +8034,7 @@ MATCH matchArg(TemplateParameter tp, Loc instLoc, Scope* sc, Objects* tiargs, si { assert(i < dedtypes.length); // It might have already been deduced - oarg = (*dedtypes)[i]; + oarg = dedtypes[i]; if (!oarg) return matchArgNoMatch(); } @@ -8031,7 +8050,7 @@ MATCH matchArg(TemplateParameter tp, Loc instLoc, Scope* sc, Objects* tiargs, si assert(i + 1 == dedtypes.length); // must be the last one Tuple ovar; - if (Tuple u = isTuple((*dedtypes)[i])) + if (Tuple u = isTuple(dedtypes[i])) { // It has already been deduced ovar = u; @@ -8059,7 +8078,7 @@ MATCH matchArg(TemplateParameter tp, Loc instLoc, Scope* sc, Objects* tiargs, si return matchArgParameter(); } -MATCH matchArg(TemplateParameter tp, Scope* sc, RootObject oarg, size_t i, TemplateParameters* parameters, Objects* dedtypes, Declaration* psparam) +MATCH matchArg(TemplateParameter tp, Scope* sc, RootObject oarg, size_t i, TemplateParameters* parameters, ref Objects dedtypes, Declaration* psparam) { MATCH matchArgNoMatch() { @@ -8087,7 +8106,7 @@ MATCH matchArg(TemplateParameter tp, Scope* sc, RootObject oarg, size_t i, Templ return matchArgNoMatch(); //printf("\tcalling deduceType(): ta is %s, specType is %s\n", ta.toChars(), ttp.specType.toChars()); - MATCH m2 = deduceType(ta, sc, ttp.specType, parameters, dedtypes); + MATCH m2 = deduceType(ta, sc, ttp.specType, *parameters, dedtypes); if (m2 == MATCH.nomatch) { //printf("\tfailed deduceType\n"); @@ -8096,9 +8115,9 @@ MATCH matchArg(TemplateParameter tp, Scope* sc, RootObject oarg, size_t i, Templ if (m2 < m) m = m2; - if ((*dedtypes)[i]) + if (dedtypes[i]) { - Type t = cast(Type)(*dedtypes)[i]; + Type t = cast(Type)dedtypes[i]; if (ttp.dependent && !t.equals(ta)) // https://issues.dlang.org/show_bug.cgi?id=14357 return matchArgNoMatch(); @@ -8113,10 +8132,10 @@ MATCH matchArg(TemplateParameter tp, Scope* sc, RootObject oarg, size_t i, Templ } else { - if ((*dedtypes)[i]) + if (dedtypes[i]) { // Must match already deduced type - Type t = cast(Type)(*dedtypes)[i]; + Type t = cast(Type)dedtypes[i]; if (!t.equals(ta)) { @@ -8130,7 +8149,7 @@ MATCH matchArg(TemplateParameter tp, Scope* sc, RootObject oarg, size_t i, Templ m = MATCH.convert; } } - (*dedtypes)[i] = ta; + dedtypes[i] = ta; if (psparam) *psparam = new AliasDeclaration(ttp.loc, ttp.ident, ta); @@ -8235,15 +8254,15 @@ MATCH matchArg(TemplateParameter tp, Scope* sc, RootObject oarg, size_t i, Templ } else { - if ((*dedtypes)[i]) + if (dedtypes[i]) { // Must match already deduced value - Expression e = cast(Expression)(*dedtypes)[i]; + Expression e = cast(Expression)dedtypes[i]; if (!ei || !ei.equals(e)) return matchArgNoMatch(); } } - (*dedtypes)[i] = ei; + dedtypes[i] = ei; if (psparam) { @@ -8354,7 +8373,7 @@ MATCH matchArg(TemplateParameter tp, Scope* sc, RootObject oarg, size_t i, Templ return matchArgNoMatch(); Type t = new TypeInstance(Loc.initial, ti); - MATCH m2 = deduceType(t, sc, talias, parameters, dedtypes); + MATCH m2 = deduceType(t, sc, talias, *parameters, dedtypes); if (m2 == MATCH.nomatch) return matchArgNoMatch(); } @@ -8375,14 +8394,14 @@ MATCH matchArg(TemplateParameter tp, Scope* sc, RootObject oarg, size_t i, Templ } } } - else if ((*dedtypes)[i]) + else if (dedtypes[i]) { // Must match already deduced symbol - RootObject si = (*dedtypes)[i]; + RootObject si = dedtypes[i]; if (!sa || si != sa) return matchArgNoMatch(); } - (*dedtypes)[i] = sa; + dedtypes[i] = sa; if (psparam) { @@ -8415,15 +8434,15 @@ MATCH matchArg(TemplateParameter tp, Scope* sc, RootObject oarg, size_t i, Templ Tuple ovar = isTuple(oarg); if (!ovar) return MATCH.nomatch; - if ((*dedtypes)[i]) + if (dedtypes[i]) { - Tuple tup = isTuple((*dedtypes)[i]); + Tuple tup = isTuple(dedtypes[i]); if (!tup) return MATCH.nomatch; if (!match(tup, ovar)) return MATCH.nomatch; } - (*dedtypes)[i] = ovar; + dedtypes[i] = ovar; if (psparam) *psparam = new TupleDeclaration(ttp.loc, ttp.ident, &ovar.objects); @@ -8457,21 +8476,24 @@ struct TemplateStats /******************************* * Add this instance + * Params: + * td = template declaration + * ti = instance of td + * listInstances = keep track of instances of templates */ static void incInstance(const TemplateDeclaration td, - const TemplateInstance ti) + const TemplateInstance ti, + bool listInstances) { void log(ref TemplateStats ts) { if (ts.allInstances is null) ts.allInstances = new TemplateInstances(); - if (global.params.v.templatesListInstances) + if (listInstances) ts.allInstances.push(cast() ti); } - // message(ti.loc, "incInstance %p %p", td, ti); - if (!global.params.v.templates) - return; + // message(ti.loc, "incInstance %p %p", td, ti); if (!td) return; assert(ti); @@ -8494,8 +8516,6 @@ struct TemplateStats const TemplateInstance ti) { // message(ti.loc, "incUnique %p %p", td, ti); - if (!global.params.v.templates) - return; if (!td) return; assert(ti); @@ -8506,7 +8526,13 @@ struct TemplateStats } } -extern (C++) void printTemplateStats() +/******************************** + * Print informational statistics on template instantiations. + * Params: + * listInstances = list instances of templates + * eSink = where the print is sent + */ +extern (C++) void printTemplateStats(bool listInstances, ErrorSink eSink) { static struct TemplateDeclarationStats { @@ -8523,11 +8549,12 @@ extern (C++) void printTemplateStats() } } - if (!global.params.v.templates) - return; + const stats_length = TemplateStats.stats.length; + if (!stats_length) + return; // nothing to report Array!(TemplateDeclarationStats) sortedStats; - sortedStats.reserve(TemplateStats.stats.length); + sortedStats.reserve(stats_length); foreach (td_, ref ts; TemplateStats.stats) { sortedStats.push(TemplateDeclarationStats(cast(TemplateDeclaration) td_, ts)); @@ -8537,10 +8564,9 @@ extern (C++) void printTemplateStats() foreach (const ref ss; sortedStats[]) { - if (global.params.v.templatesListInstances && - ss.ts.allInstances) + if (listInstances && ss.ts.allInstances) { - message(ss.td.loc, + eSink.message(ss.td.loc, "vtemplate: %u (%u distinct) instantiation(s) of template `%s` found, they are:", ss.ts.numInstantiations, ss.ts.uniqueInstantiations, @@ -8548,14 +8574,14 @@ extern (C++) void printTemplateStats() foreach (const ti; (*ss.ts.allInstances)[]) { if (ti.tinst) // if has enclosing instance - message(ti.loc, "vtemplate: implicit instance `%s`", ti.toChars()); + eSink.message(ti.loc, "vtemplate: implicit instance `%s`", ti.toChars()); else - message(ti.loc, "vtemplate: explicit instance `%s`", ti.toChars()); + eSink.message(ti.loc, "vtemplate: explicit instance `%s`", ti.toChars()); } } else { - message(ss.td.loc, + eSink.message(ss.td.loc, "vtemplate: %u (%u distinct) instantiation(s) of template `%s` found", ss.ts.numInstantiations, ss.ts.uniqueInstantiations, diff --git a/gcc/d/dmd/dtoh.d b/gcc/d/dmd/dtoh.d index 30991c9..2bfa96c 100644 --- a/gcc/d/dmd/dtoh.d +++ b/gcc/d/dmd/dtoh.d @@ -779,6 +779,17 @@ public: } } + if (tf && tf.next) + { + // Ensure return type is declared before a function that returns that is declared. + if (auto sty = tf.next.isTypeStruct()) + ensureDeclared(sty.sym); + //else if (auto cty = tf.next.isTypeClass()) + // includeSymbol(cty.sym); // classes are returned by pointer only need to forward declare + //else if (auto ety = tf.next.isTypeEnum()) + // ensureDeclared(ety.sym); + } + writeProtection(fd.visibility.kind); if (tf && tf.linkage == LINK.c) diff --git a/gcc/d/dmd/escape.d b/gcc/d/dmd/escape.d index 433907a..3e17ff4 100644 --- a/gcc/d/dmd/escape.d +++ b/gcc/d/dmd/escape.d @@ -34,6 +34,7 @@ import dmd.mtype; import dmd.printast; import dmd.rootobject; import dmd.tokens; +import dmd.typesem : hasPointers, parameterStorageClass; import dmd.visitor; import dmd.arraytypes; diff --git a/gcc/d/dmd/expression.d b/gcc/d/dmd/expression.d index 41eeff9..cbf0118 100644 --- a/gcc/d/dmd/expression.d +++ b/gcc/d/dmd/expression.d @@ -190,39 +190,6 @@ extern (C++) void expandTuples(Expressions* exps, Identifiers* names = null) } /**************************************** - * Expand alias this tuples. - */ -TupleDeclaration isAliasThisTuple(Expression e) -{ - if (!e.type) - return null; - - Type t = e.type.toBasetype(); - while (true) - { - if (Dsymbol s = t.toDsymbol(null)) - { - if (auto ad = s.isAggregateDeclaration()) - { - s = ad.aliasthis ? ad.aliasthis.sym : null; - if (s && s.isVarDeclaration()) - { - TupleDeclaration td = s.isVarDeclaration().toAlias().isTupleDeclaration(); - if (td && td.isexp) - return td; - } - if (Type att = t.aliasthisOf()) - { - t = att; - continue; - } - } - } - return null; - } -} - -/**************************************** * If `s` is a function template, i.e. the only member of a template * and that member is a function, return that template. * Params: diff --git a/gcc/d/dmd/expressionsem.d b/gcc/d/dmd/expressionsem.d index 9ce6f4d..d464574 100644 --- a/gcc/d/dmd/expressionsem.d +++ b/gcc/d/dmd/expressionsem.d @@ -384,7 +384,6 @@ private Expression reorderSettingAAElem(BinExp exp, Scope* sc) return Expression.combine(e0, be); } - private Expression checkOpAssignTypes(BinExp binExp, Scope* sc) { auto e1 = binExp.e1; @@ -563,6 +562,39 @@ private Expression extractOpDollarSideEffect(Scope* sc, UnaExp ue) return e0; } +/**************************************** + * Expand alias this tuples. + */ +TupleDeclaration isAliasThisTuple(Expression e) +{ + if (!e.type) + return null; + + Type t = e.type.toBasetype(); + while (true) + { + if (Dsymbol s = t.toDsymbol(null)) + { + if (auto ad = s.isAggregateDeclaration()) + { + s = ad.aliasthis ? ad.aliasthis.sym : null; + if (s && s.isVarDeclaration()) + { + TupleDeclaration td = s.isVarDeclaration().toAlias().isTupleDeclaration(); + if (td && td.isexp) + return td; + } + if (Type att = t.aliasthisOf()) + { + t = att; + continue; + } + } + } + return null; + } +} + /************************************** * Runs semantic on ae.arguments. Declares temporary variables * if '$' was used. @@ -5115,7 +5147,16 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor tb = tb.isTypeDArray().next.toBasetype(); } - if (global.params.betterC || !sc.needsCodegen()) + if (!global.params.useGC && sc.needsCodegen()) + { + version(IN_GCC) + error(exp.loc, "expression `%s` allocates with the GC and cannot be used with switch `-fno-rtti`", exp.toChars()); + else + error(exp.loc, "expression `%s` allocates with the GC and cannot be used with switch `-betterC`", exp.toChars()); + return setError(); + } + + if (!sc.needsCodegen()) goto LskipNewArrayLowering; /* Class types may inherit base classes that have errors. @@ -6432,8 +6473,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor return setError(); } - const(char)* failMessage; - if (!tf.callMatch(null, exp.argumentList, 0, &failMessage, sc)) + void errorHelper(const(char)* failMessage) scope { OutBuffer buf; buf.writeByte('('); @@ -6447,8 +6487,11 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor p, exp.e1.toChars(), parametersTypeToChars(tf.parameterList), buf.peekChars()); if (failMessage) errorSupplemental(exp.loc, "%s", failMessage); - return setError(); } + + if (tf.callMatch(null, exp.argumentList, 0, &errorHelper, sc) == MATCH.nomatch) + return setError(); + // Purity and safety check should run after testing arguments matching if (exp.f) { @@ -6505,8 +6548,8 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor { exp.f = exp.f.toAliasFunc(); TypeFunction tf = cast(TypeFunction)exp.f.type; - const(char)* failMessage; - if (!tf.callMatch(null, exp.argumentList, 0, &failMessage, sc)) + + void errorHelper2(const(char)* failMessage) scope { OutBuffer buf; buf.writeByte('('); @@ -6527,6 +6570,9 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor errorSupplemental(exp.loc, "%s", failMessage); exp.f = null; } + + if (tf.callMatch(null, exp.argumentList, 0, &errorHelper2, sc) == MATCH.nomatch) + exp.f = null; } if (!exp.f || exp.f.errors) return setError(); @@ -7041,7 +7087,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor sc2.tinst = null; sc2.minst = null; sc2.flags |= SCOPE.fullinst; - Type t = e.targ.trySemantic(e.loc, sc2); + Type t = dmd.typesem.trySemantic(e.targ, e.loc, sc2); sc2.pop(); if (!t) // errors, so condition is false return no(); @@ -7271,7 +7317,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor Objects dedtypes = Objects(e.parameters.length); dedtypes.zero(); - MATCH m = deduceType(e.targ, sc, e.tspec, e.parameters, &dedtypes, null, 0, e.tok == TOK.equal); + MATCH m = deduceType(e.targ, sc, e.tspec, *e.parameters, dedtypes, null, 0, e.tok == TOK.equal); if (m == MATCH.nomatch || (m != MATCH.exact && e.tok == TOK.equal)) { @@ -7292,7 +7338,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor TemplateParameter tp = (*e.parameters)[i]; Declaration s = null; - m = tp.matchArg(e.loc, sc, &tiargs, i, e.parameters, &dedtypes, &s); + m = tp.matchArg(e.loc, sc, &tiargs, i, e.parameters, dedtypes, &s); if (m == MATCH.nomatch) return no(); s.dsymbolSemantic(sc); @@ -7437,7 +7483,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor result = (cast(BinExp)e).reorderSettingAAElem(sc); } - private Expression compileIt(MixinExp exp) + private Expression compileIt(MixinExp exp, Scope *sc) { OutBuffer buf; if (expressionsToString(buf, sc, exp.exps)) @@ -7478,7 +7524,13 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor printf("MixinExp::semantic('%s')\n", exp.toChars()); } - auto e = compileIt(exp); + // The expression is not treated as part of a default argument, + // because it is evaluated at compile time. + Scope* sc2 = sc.push(); + sc2.inDefaultArg = false; + + auto e = compileIt(exp, sc2); + sc2.pop(); if (!e) return setError(); result = e.expressionSemantic(sc); @@ -7575,7 +7627,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor { auto fileName = FileName(resolvedNamez); - if (auto fmResult = global.fileManager.lookup(fileName)) + if (auto fmResult = global.fileManager.getFileContents(fileName)) { se = new StringExp(e.loc, fmResult); } @@ -7721,7 +7773,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor // if the assert condition is a mixin expression, try to compile it if (auto ce = exp.e1.isMixinExp()) { - if (auto e1 = compileIt(ce)) + if (auto e1 = compileIt(ce, sc)) exp.e1 = e1; } @@ -13924,45 +13976,34 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor { //printf("FileInitExp::semantic()\n"); e.type = Type.tstring; - result = e; + result = e.resolveLoc(e.loc, sc); } override void visit(LineInitExp e) { e.type = Type.tint32; - result = e; + result = e.resolveLoc(e.loc, sc); } override void visit(ModuleInitExp e) { //printf("ModuleInitExp::semantic()\n"); e.type = Type.tstring; - result = e; + result = e.resolveLoc(e.loc, sc); } override void visit(FuncInitExp e) { //printf("FuncInitExp::semantic()\n"); e.type = Type.tstring; - if (sc.func) - { - result = e.resolveLoc(Loc.initial, sc); - return; - } - result = e; + result = e.resolveLoc(e.loc, sc); } override void visit(PrettyFuncInitExp e) { //printf("PrettyFuncInitExp::semantic()\n"); e.type = Type.tstring; - if (sc.func) - { - result = e.resolveLoc(Loc.initial, sc); - return; - } - - result = e; + result = e.resolveLoc(e.loc, sc); } } @@ -15047,10 +15088,21 @@ bool checkSharedAccess(Expression e, Scope* sc, bool returnRef = false) */ Expression resolveLoc(Expression exp, const ref Loc loc, Scope* sc) { + // Don't replace the special keywords, while we are inside a default + // argument. They are replaced later when copied to the call site. + if (sc.inDefaultArg) + return exp; + exp.loc = loc; Expression visit(Expression exp) { + if (auto binExp = exp.isBinExp()) + { + binExp.e1 = binExp.e1.resolveLoc(loc, sc); + binExp.e2 = binExp.e2.resolveLoc(loc, sc); + return binExp; + } if (auto unaExp = exp.isUnaExp()) { unaExp.e1 = unaExp.e1.resolveLoc(loc, sc); @@ -15059,10 +15111,121 @@ Expression resolveLoc(Expression exp, const ref Loc loc, Scope* sc) return exp; } + Expression visitCond(CondExp exp) + { + exp.e1 = exp.e1.resolveLoc(loc, sc); + exp.e2 = exp.e2.resolveLoc(loc, sc); + exp.econd = exp.econd.resolveLoc(loc, sc); + return exp; + } + Expression visitCat(CatExp exp) { exp.e1 = exp.e1.resolveLoc(loc, sc); exp.e2 = exp.e2.resolveLoc(loc, sc); + if (exp.lowering) + exp.lowering = exp.lowering.resolveLoc(loc, sc); + return exp; + } + + Expression visitStructLiteral(StructLiteralExp exp) + { + foreach (ref element; *exp.elements) + { + if (element) + element = element.resolveLoc(loc, sc); + } + + return exp; + } + + Expression visitNew(NewExp exp) + { + if (exp.thisexp) + exp.thisexp = exp.thisexp.resolveLoc(loc, sc); + if (exp.argprefix) + exp.argprefix = exp.argprefix.resolveLoc(loc, sc); + if (exp.lowering) + exp.lowering = exp.lowering.resolveLoc(loc, sc); + + foreach (ref element; *exp.arguments) + { + if (element) + element = element.resolveLoc(loc, sc); + } + + return exp; + } + + Expression visitCall(CallExp exp) + { + foreach (ref element; *exp.arguments) + { + if (element) + element = element.resolveLoc(loc, sc); + } + + return exp; + } + + Expression visitArray(ArrayExp exp) + { + exp.e1 = exp.e1.resolveLoc(loc, sc); + + foreach (ref element; *exp.arguments) + { + if (element) + element = element.resolveLoc(loc, sc); + } + + return exp; + } + + Expression visitSlice(SliceExp exp) + { + exp.e1 = exp.e1.resolveLoc(loc, sc); + exp.lwr = exp.lwr.resolveLoc(loc, sc); + exp.upr = exp.upr.resolveLoc(loc, sc); + + return exp; + } + + Expression visitInterval(IntervalExp exp) + { + exp.lwr = exp.lwr.resolveLoc(loc, sc); + exp.upr = exp.upr.resolveLoc(loc, sc); + + return exp; + } + + Expression visitArrayLiteral(ArrayLiteralExp exp) + { + if (exp.basis) + exp.basis = exp.basis.resolveLoc(loc, sc); + + foreach (ref element; *exp.elements) + { + if (element) + element = element.resolveLoc(loc, sc); + } + + return exp; + } + + Expression visitAssocArrayLiteral(AssocArrayLiteralExp exp) + { + foreach (ref element; *exp.keys) + { + if (element) + element = element.resolveLoc(loc, sc); + } + + foreach (ref element; *exp.values) + { + if (element) + element = element.resolveLoc(loc, sc); + } + return exp; } @@ -15079,20 +15242,20 @@ Expression resolveLoc(Expression exp, const ref Loc loc, Scope* sc) return e.expressionSemantic(sc); } - Expression visitLineInit(LineInitExp _) + Expression visitLineInit(LineInitExp exp) { Expression e = new IntegerExp(loc, loc.linnum, Type.tint32); return e.expressionSemantic(sc); } - Expression visitModuleInit(ModuleInitExp _) + Expression visitModuleInit(ModuleInitExp exp) { const auto s = (sc.callsc ? sc.callsc : sc)._module.toPrettyChars().toDString(); Expression e = new StringExp(loc, s); return e.expressionSemantic(sc); } - Expression visitFuncInit(FuncInitExp _) + Expression visitFuncInit(FuncInitExp exp) { const(char)* s; if (sc.callsc && sc.callsc.func) @@ -15105,7 +15268,7 @@ Expression resolveLoc(Expression exp, const ref Loc loc, Scope* sc) return e.expressionSemantic(sc); } - Expression visitPrettyFunc(PrettyFuncInitExp _) + Expression visitPrettyFunc(PrettyFuncInitExp exp) { FuncDeclaration fd = (sc.callsc && sc.callsc.func) ? sc.callsc.func @@ -15133,7 +15296,16 @@ Expression resolveLoc(Expression exp, const ref Loc loc, Scope* sc) switch(exp.op) { default: return visit(exp); + case EXP.structLiteral: return visitStructLiteral(exp.isStructLiteralExp()); + case EXP.new_: return visitNew(exp.isNewExp()); case EXP.concatenate: return visitCat(exp.isCatExp()); + case EXP.call: return visitCall(exp.isCallExp()); + case EXP.question: return visitCond(exp.isCondExp()); + case EXP.array: return visitArray(exp.isArrayExp()); + case EXP.slice: return visitSlice(exp.isSliceExp()); + case EXP.interval: return visitInterval(exp.isIntervalExp()); + case EXP.arrayLiteral: return visitArrayLiteral(exp.isArrayLiteralExp()); + case EXP.assocArrayLiteral: return visitAssocArrayLiteral(exp.isAssocArrayLiteralExp()); case EXP.file: case EXP.fileFullPath: return visitFileInit(exp.isFileInitExp()); case EXP.line: return visitLineInit(exp.isLineInitExp); @@ -16193,7 +16365,10 @@ Expression getVarExp(EnumMember em, const ref Loc loc, Scope* sc) em.checkDisabled(loc, sc); if (em.depdecl && !em.depdecl._scope) + { em.depdecl._scope = sc; + em.depdecl._scope.setNoFree(); + } em.checkDeprecated(loc, sc); if (em.errors) diff --git a/gcc/d/dmd/file_manager.d b/gcc/d/dmd/file_manager.d index eaef8d5..c696a5c 100644 --- a/gcc/d/dmd/file_manager.d +++ b/gcc/d/dmd/file_manager.d @@ -72,7 +72,7 @@ private struct PathStack final class FileManager { - private StringTable!(const(ubyte)[]) files; + private StringTable!(const(ubyte)[]) files; // contents of files indexed by file name private StringTable!(bool) packageStatus; // check if the package path of the given path exists. The input path is @@ -247,35 +247,37 @@ nothrow: } /** - * Looks up the given filename from the internal file buffer table. - * If the file does not already exist within the table, it will be read from the filesystem. - * If it has been read before, - * - * Returns: the loaded source file if it was found in memory, - * otherwise `null` + * Retrieve the cached contents of the file given by `filename`. + * If the file has not been read before, read it and add the contents + * to the file cache. + * Params: + * filename = the name of the file + * Returns: + * the contents of the file, or `null` if it could not be read or was empty */ - const(ubyte)[] lookup(FileName filename) + const(ubyte)[] getFileContents(FileName filename) { const name = filename.toString; - if (auto val = files.lookup(name)) - return val.value; + if (auto val = files.lookup(name)) // if `name` is cached + return val.value; // return its contents - if (name == "__stdin.d") + if (name == "__stdin.d") // special name for reading from stdin { - auto buffer = readFromStdin().extractSlice(); + const ubyte[] buffer = readFromStdin().extractSlice(); if (this.files.insert(name, buffer) is null) + // this.files already contains the name assert(0, "stdin: Insert after lookup failure should never return `null`"); return buffer; } - if (FileName.exists(name) != 1) + if (FileName.exists(name) != 1) // if not an ordinary file return null; auto readResult = File.read(name); if (!readResult.success) return null; - auto fb = readResult.extractSlice(); + const ubyte[] fb = readResult.extractSlice(); if (files.insert(name, fb) is null) assert(0, "Insert after lookup failure should never return `null`"); diff --git a/gcc/d/dmd/func.d b/gcc/d/dmd/func.d index 242b4dc..370da6f 100644 --- a/gcc/d/dmd/func.d +++ b/gcc/d/dmd/func.d @@ -1195,7 +1195,7 @@ extern (C++) class FuncDeclaration : Declaration * * Returns: the `LabelDsymbol` for `ident` */ - final LabelDsymbol searchLabel(Identifier ident, const ref Loc loc = Loc.initial) + final LabelDsymbol searchLabel(Identifier ident, const ref Loc loc) { Dsymbol s; if (!labtab) @@ -1471,6 +1471,9 @@ extern (C++) class FuncDeclaration : Declaration final PURE isPure() { //printf("FuncDeclaration::isPure() '%s'\n", toChars()); + + import dmd.typesem : purityLevel; + TypeFunction tf = type.toTypeFunction(); if (purityInprocess) setImpure(); @@ -1782,6 +1785,7 @@ extern (C++) class FuncDeclaration : Declaration case Tstruct: /* Drill down and check the struct's fields */ + import dmd.typesem : toDsymbol; auto sym = t.toDsymbol(null).isStructDeclaration(); const tName = t.toChars.toDString; const entry = parentTypes.insert(tName, t); @@ -1863,6 +1867,7 @@ extern (C++) class FuncDeclaration : Declaration case Tstruct: /* Drill down and check the struct's fields */ + import dmd.typesem : toDsymbol; auto sym = tp.toDsymbol(null).isStructDeclaration(); foreach (v; sym.fields) { @@ -2727,6 +2732,7 @@ extern (C++) class FuncDeclaration : Declaration { Type t1 = fdv.type.nextOf().toBasetype(); Type t2 = this.type.nextOf().toBasetype(); + import dmd.typesem : isBaseOf; if (t1.isBaseOf(t2, null)) { /* Making temporary reference variable is necessary @@ -3294,7 +3300,7 @@ FuncDeclaration resolveFuncCall(const ref Loc loc, Scope* sc, Dsymbol s, printf("\tfnames: %s\n", fnames ? fnames.toChars() : "null"); } - if (tiargs && arrayObjectIsError(tiargs)) + if (tiargs && arrayObjectIsError(*tiargs)) return null; if (fargs !is null) foreach (arg; *fargs) @@ -3441,17 +3447,20 @@ FuncDeclaration resolveFuncCall(const ref Loc loc, Scope* sc, Dsymbol s, return null; } - const(char)* failMessage; - functionResolve(m, orig_s, loc, sc, tiargs, tthis, argumentList, &failMessage); - if (failMessage) + bool calledHelper; + void errorHelper(const(char)* failMessage) scope { .error(loc, "%s `%s%s%s` is not callable using argument types `%s`", fd.kind(), fd.toPrettyChars(), parametersTypeToChars(tf.parameterList), tf.modToChars(), fargsBuf.peekChars()); errorSupplemental(loc, failMessage); - return null; + calledHelper = true; } + functionResolve(m, orig_s, loc, sc, tiargs, tthis, argumentList, &errorHelper); + if (calledHelper) + return null; + if (fd.isCtorDeclaration()) .error(loc, "%s%s `%s` cannot construct a %sobject", funcBuf.peekChars(), fd.kind(), fd.toPrettyChars(), thisBuf.peekChars()); @@ -3505,10 +3514,13 @@ FuncDeclaration resolveFuncCall(const ref Loc loc, Scope* sc, Dsymbol s, } } } - const(char)* failMessage; - functionResolve(m, orig_s, loc, sc, tiargs, tthis, argumentList, &failMessage); - if (failMessage) + + void errorHelper2(const(char)* failMessage) scope + { errorSupplemental(loc, failMessage); + } + + functionResolve(m, orig_s, loc, sc, tiargs, tthis, argumentList, &errorHelper2); } return null; } @@ -3624,6 +3636,7 @@ if (is(Decl == TemplateDeclaration) || is(Decl == FuncDeclaration)) */ Type getIndirection(Type t) { + import dmd.typesem : hasPointers; t = t.baseElemOf(); if (t.ty == Tarray || t.ty == Tpointer) return t.nextOf().toBasetype(); @@ -3670,6 +3683,7 @@ private bool traverseIndirections(Type ta, Type tb) static bool traverse(Type ta, Type tb, ref scope AssocArray!(const(char)*, bool) table, bool reversePass) { + import dmd.typesem : hasPointers; //printf("traverse(%s, %s)\n", ta.toChars(), tb.toChars()); ta = ta.baseElemOf(); tb = tb.baseElemOf(); @@ -3706,6 +3720,7 @@ private bool traverseIndirections(Type ta, Type tb) else *found = true; + import dmd.typesem : toDsymbol; AggregateDeclaration sym = tb.toDsymbol(null).isAggregateDeclaration(); foreach (v; sym.fields) { diff --git a/gcc/d/dmd/globals.d b/gcc/d/dmd/globals.d index b60a3f8..e9e73e8 100644 --- a/gcc/d/dmd/globals.d +++ b/gcc/d/dmd/globals.d @@ -15,7 +15,9 @@ import core.stdc.stdio; import core.stdc.stdint; import core.stdc.string; +import dmd.astenums; import dmd.root.array; +import dmd.root.file; import dmd.root.filename; import dmd.common.outbuffer; import dmd.errorsink; @@ -308,7 +310,7 @@ extern (C++) struct Global ErrorSink errorSink; /// where the error messages go ErrorSink errorSinkNull; /// where the error messages are ignored - extern (C++) FileName function(FileName, ref const Loc, out bool, OutBuffer*) preprocess; + extern (C++) DArray!ubyte function(FileName, ref const Loc, ref OutBuffer) preprocess; nothrow: diff --git a/gcc/d/dmd/globals.h b/gcc/d/dmd/globals.h index c71d2f0..93e7c64 100644 --- a/gcc/d/dmd/globals.h +++ b/gcc/d/dmd/globals.h @@ -307,7 +307,7 @@ struct Global ErrorSink* errorSink; // where the error messages go ErrorSink* errorSinkNull; // where the error messages disappear - FileName (*preprocess)(FileName, const Loc&, bool&, OutBuffer&); + DArray (*preprocess)(FileName, const Loc&, OutBuffer&); /* Start gagging. Return the current number of gagged errors */ diff --git a/gcc/d/dmd/mtype.d b/gcc/d/dmd/mtype.d index 4c741cd..3d88a1d 100644 --- a/gcc/d/dmd/mtype.d +++ b/gcc/d/dmd/mtype.d @@ -21,16 +21,11 @@ import dmd.aggregate; import dmd.arraytypes; import dmd.astenums; import dmd.ast_node; -import dmd.gluelayer; import dmd.dclass; -import dmd.dcast; import dmd.declaration; import dmd.denum; -import dmd.dmangle; -import dmd.dscope; import dmd.dstruct; import dmd.dsymbol; -import dmd.dsymbolsem; import dmd.dtemplate; import dmd.errors; import dmd.expression; @@ -39,9 +34,7 @@ import dmd.globals; import dmd.hdrgen; import dmd.id; import dmd.identifier; -import dmd.init; import dmd.location; -import dmd.opover; import dmd.root.ctfloat; import dmd.common.outbuffer; import dmd.root.rmem; @@ -256,57 +249,6 @@ bool isSomeChar(TY ty) pure nothrow @nogc @safe return ty == Tchar || ty == Twchar || ty == Tdchar; } -/************************************ - * Determine mutability of indirections in (ref) t. - * - * Returns: When the type has any mutable indirections, returns 0. - * When all indirections are immutable, returns 2. - * Otherwise, when the type has const/inout indirections, returns 1. - * - * Params: - * isref = if true, check `ref t`; otherwise, check just `t` - * t = the type that is being checked - */ -int mutabilityOfType(bool isref, Type t) -{ - if (isref) - { - if (t.mod & MODFlags.immutable_) - return 2; - if (t.mod & (MODFlags.const_ | MODFlags.wild)) - return 1; - return 0; - } - - t = t.baseElemOf(); - - if (!t.hasPointers() || t.mod & MODFlags.immutable_) - return 2; - - /* Accept immutable(T)[] and immutable(T)* as being strongly pure - */ - if (t.ty == Tarray || t.ty == Tpointer) - { - Type tn = t.nextOf().toBasetype(); - if (tn.mod & MODFlags.immutable_) - return 2; - if (tn.mod & (MODFlags.const_ | MODFlags.wild)) - return 1; - } - - /* The rest of this is too strict; fix later. - * For example, the only pointer members of a struct may be immutable, - * which would maintain strong purity. - * (Just like for dynamic arrays and pointers above.) - */ - if (t.mod & (MODFlags.const_ | MODFlags.wild)) - return 1; - - /* Should catch delegates and function pointers, and fold in their purity - */ - return 0; -} - /**************** * dotExp() bit flags */ @@ -363,7 +305,7 @@ extern (C++) abstract class Type : ASTNode TypeInfoDeclaration vtinfo; // TypeInfo object for this Type - type* ctype; // for back end + void* ctype; // for back end extern (C++) __gshared Type tvoid; extern (C++) __gshared Type tint8; @@ -659,31 +601,6 @@ extern (C++) abstract class Type : ASTNode return cast(uint)size(Loc.initial); } - final Type trySemantic(const ref Loc loc, Scope* sc) - { - //printf("+trySemantic(%s) %d\n", toChars(), global.errors); - - // Needed to display any deprecations that were gagged - auto tcopy = this.syntaxCopy(); - - const errors = global.startGagging(); - Type t = typeSemantic(this, loc, sc); - if (global.endGagging(errors) || t.ty == Terror) // if any errors happened - { - t = null; - } - else - { - // If `typeSemantic` succeeded, there may have been deprecations that - // were gagged due the `startGagging` above. Run again to display - // those deprecations. https://issues.dlang.org/show_bug.cgi?id=19107 - if (global.gaggedWarnings > 0) - typeSemantic(tcopy, loc, sc); - } - //printf("-trySemantic(%s) %d\n", toChars(), global.errors); - return t; - } - /************************************* * This version does a merge even if the deco is already computed. * Necessary for types that have a deco, but are not merged. @@ -1907,11 +1824,6 @@ extern (C++) abstract class Type : ASTNode return t; } - Dsymbol toDsymbol(Scope* sc) - { - return null; - } - /******************************* * If this is a shell around another type, * get that other type. @@ -1925,11 +1837,6 @@ extern (C++) abstract class Type : ASTNode return ((te = isTypeEnum()) !is null) ? te.toBasetype2() : this; } - bool isBaseOf(Type t, int* poffset) - { - return 0; // assume not - } - /******************************** * Determine if 'this' can be implicitly converted * to type 'to'. @@ -2155,32 +2062,6 @@ extern (C++) abstract class Type : ASTNode return false; // assume not } - final Identifier getTypeInfoIdent() - { - // _init_10TypeInfo_%s - OutBuffer buf; - buf.reserve(32); - mangleToBuffer(this, buf); - - const slice = buf[]; - - // Allocate buffer on stack, fail over to using malloc() - char[128] namebuf; - const namelen = 19 + size_t.sizeof * 3 + slice.length + 1; - auto name = namelen <= namebuf.length ? namebuf.ptr : cast(char*)Mem.check(malloc(namelen)); - - const length = snprintf(name, namelen, "_D%lluTypeInfo_%.*s6__initZ", - cast(ulong)(9 + slice.length), cast(int)slice.length, slice.ptr); - //printf("%p %s, deco = %s, name = %s\n", this, toChars(), deco, name); - assert(0 < length && length < namelen); // don't overflow the buffer - - auto id = Identifier.idPool(name[0 .. length]); - - if (name != namebuf.ptr) - free(name); - return id; - } - /*************************************** * Return !=0 if the type or any of its subtypes is wild. */ @@ -2189,16 +2070,6 @@ extern (C++) abstract class Type : ASTNode return mod & MODFlags.wild; } - /*************************************** - * Return !=0 if type has pointers that need to - * be scanned by the GC during a collection cycle. - */ - bool hasPointers() - { - //printf("Type::hasPointers() %s, %d\n", toChars(), ty); - return false; - } - /************************************* * Detect if type has pointer fields that are initialized to void. * Local stack variables with such void fields can remain uninitialized, @@ -2340,76 +2211,6 @@ extern (C++) abstract class Type : ASTNode return false; } - /************************************* - * https://issues.dlang.org/show_bug.cgi?id=14488 - * Check if the inner most base type is complex or imaginary. - * Should only give alerts when set to emit transitional messages. - * Params: - * loc = The source location. - * sc = scope of the type - */ - extern (D) final bool checkComplexTransition(const ref Loc loc, Scope* sc) - { - if (sc.isDeprecated()) - return false; - // Don't complain if we're inside a template constraint - // https://issues.dlang.org/show_bug.cgi?id=21831 - if (sc.flags & SCOPE.constraint) - return false; - - Type t = baseElemOf(); - while (t.ty == Tpointer || t.ty == Tarray) - t = t.nextOf().baseElemOf(); - - // Basetype is an opaque enum, nothing to check. - if (t.ty == Tenum && !(cast(TypeEnum)t).sym.memtype) - return false; - - if (t.isimaginary() || t.iscomplex()) - { - if (sc.flags & SCOPE.Cfile) - return true; // complex/imaginary not deprecated in C code - Type rt; - switch (t.ty) - { - case Tcomplex32: - case Timaginary32: - rt = Type.tfloat32; - break; - - case Tcomplex64: - case Timaginary64: - rt = Type.tfloat64; - break; - - case Tcomplex80: - case Timaginary80: - rt = Type.tfloat80; - break; - - default: - assert(0); - } - // @@@DEPRECATED_2.117@@@ - // Deprecated in 2.097 - Can be made an error from 2.117. - // The deprecation period is longer than usual as `cfloat`, - // `cdouble`, and `creal` were quite widely used. - if (t.iscomplex()) - { - deprecation(loc, "use of complex type `%s` is deprecated, use `std.complex.Complex!(%s)` instead", - toChars(), rt.toChars()); - return true; - } - else - { - deprecation(loc, "use of imaginary type `%s` is deprecated, use `%s` instead", - toChars(), rt.toChars()); - return true; - } - } - return false; - } - // For eliminating dynamic_cast TypeBasic isTypeBasic() { @@ -3531,24 +3332,6 @@ extern (C++) final class TypeSArray : TypeArray return ae; } - override bool hasPointers() - { - /* Don't want to do this, because: - * struct S { T* array[0]; } - * may be a variable length struct. - */ - //if (dim.toInteger() == 0) - // return false; - - if (next.ty == Tvoid) - { - // Arrays of void contain arbitrary data, which may include pointers - return true; - } - else - return next.hasPointers(); - } - override bool hasSystemFields() { return next.hasSystemFields(); @@ -3673,11 +3456,6 @@ extern (C++) final class TypeDArray : TypeArray return Type.implicitConvTo(to); } - override bool hasPointers() - { - return true; - } - override void accept(Visitor v) { v.visit(this); @@ -3734,11 +3512,6 @@ extern (C++) final class TypeAArray : TypeArray return true; } - override bool hasPointers() - { - return true; - } - override MATCH implicitConvTo(Type to) { //printf("TypeAArray::implicitConvTo(to = %s) this = %s\n", to.toChars(), toChars()); @@ -3877,11 +3650,6 @@ extern (C++) final class TypePointer : TypeNext return true; } - override bool hasPointers() - { - return true; - } - override void accept(Visitor v) { v.visit(this); @@ -4059,39 +3827,6 @@ extern (C++) final class TypeFunction : TypeNext } /******************************************** - * Set 'purity' field of 'this'. - * Do this lazily, as the parameter types might be forward referenced. - */ - void purityLevel() - { - TypeFunction tf = this; - if (tf.purity != PURE.fwdref) - return; - - purity = PURE.const_; // assume strong until something weakens it - - /* Evaluate what kind of purity based on the modifiers for the parameters - */ - foreach (i, fparam; tf.parameterList) - { - Type t = fparam.type; - if (!t) - continue; - - if (fparam.storageClass & (STC.lazy_ | STC.out_)) - { - purity = PURE.weak; - break; - } - const pref = (fparam.storageClass & STC.ref_) != 0; - if (mutabilityOfType(pref, t) == 0) - purity = PURE.weak; - } - - tf.purity = purity; - } - - /******************************************** * Return true if there are lazy parameters. */ bool hasLazyParameters() @@ -4115,122 +3850,6 @@ extern (C++) final class TypeFunction : TypeNext return linkage == LINK.d && parameterList.varargs == VarArg.variadic; } - /************************************ - * Take the specified storage class for p, - * and use the function signature to infer whether - * STC.scope_ and STC.return_ should be OR'd in. - * (This will not affect the name mangling.) - * Params: - * tthis = type of `this` parameter, null if none - * p = parameter to this function - * outerVars = context variables p could escape into, if any - * indirect = is this for an indirect or virtual function call? - * Returns: - * storage class with STC.scope_ or STC.return_ OR'd in - */ - StorageClass parameterStorageClass(Type tthis, Parameter p, VarDeclarations* outerVars = null, - bool indirect = false) - { - //printf("parameterStorageClass(p: %s)\n", p.toChars()); - auto stc = p.storageClass; - - // When the preview switch is enable, `in` parameters are `scope` - if (stc & STC.constscoperef) - return stc | STC.scope_; - - if (stc & (STC.scope_ | STC.return_ | STC.lazy_) || purity == PURE.impure) - return stc; - - /* If haven't inferred the return type yet, can't infer storage classes - */ - if (!nextOf() || !isnothrow()) - return stc; - - purityLevel(); - - static bool mayHavePointers(Type t) - { - if (auto ts = t.isTypeStruct()) - { - auto sym = ts.sym; - if (sym.members && !sym.determineFields() && sym.type != Type.terror) - // struct is forward referenced, so "may have" pointers - return true; - } - return t.hasPointers(); - } - - // See if p can escape via any of the other parameters - if (purity == PURE.weak) - { - /* - * Indirect calls may escape p through a nested context - * See: - * https://issues.dlang.org/show_bug.cgi?id=24212 - * https://issues.dlang.org/show_bug.cgi?id=24213 - */ - if (indirect) - return stc; - - // Check escaping through parameters - foreach (i, fparam; parameterList) - { - Type t = fparam.type; - if (!t) - continue; - t = t.baseElemOf(); // punch thru static arrays - if (t.isMutable() && t.hasPointers()) - { - if (fparam.isReference() && fparam != p) - return stc; - - if (t.ty == Tdelegate) - return stc; // could escape thru delegate - - if (t.ty == Tclass) - return stc; - - /* if t is a pointer to mutable pointer - */ - if (auto tn = t.nextOf()) - { - if (tn.isMutable() && mayHavePointers(tn)) - return stc; // escape through pointers - } - } - } - - // Check escaping through `this` - if (tthis && tthis.isMutable()) - { - foreach (VarDeclaration v; isAggregate(tthis).fields) - { - if (v.hasPointers()) - return stc; - } - } - - // Check escaping through nested context - if (outerVars && this.isMutable()) - { - foreach (VarDeclaration v; *outerVars) - { - if (v.hasPointers()) - return stc; - } - } - } - - // Check escaping through return value - Type tret = nextOf().toBasetype(); - if (isref || tret.hasPointers()) - { - return stc | STC.scope_ | STC.return_ | STC.returnScope; - } - else - return stc | STC.scope_; - } - override Type addStorageClass(StorageClass stc) { //printf("addStorageClass(%llx) %d\n", stc, (stc & STC.scope_) != 0); @@ -4631,11 +4250,6 @@ extern (C++) final class TypeDelegate : TypeNext return true; } - override bool hasPointers() - { - return true; - } - override void accept(Visitor v) { v.visit(this); @@ -4676,20 +4290,6 @@ extern (C++) final class TypeTraits : Type return tt; } - override Dsymbol toDsymbol(Scope* sc) - { - Type t; - Expression e; - Dsymbol s; - resolve(this, loc, sc, e, t, s); - if (t && t.ty != Terror) - s = t.toDsymbol(sc); - else if (e) - s = getDsymbol(e); - - return s; - } - override void accept(Visitor v) { v.visit(this); @@ -4729,20 +4329,6 @@ extern (C++) final class TypeMixin : Type return new TypeMixin(loc, Expression.arraySyntaxCopy(exps)); } - override Dsymbol toDsymbol(Scope* sc) - { - Type t; - Expression e; - Dsymbol s; - resolve(this, loc, sc, e, t, s); - if (t) - s = t.toDsymbol(sc); - else if (e) - s = getDsymbol(e); - - return s; - } - override void accept(Visitor v) { v.visit(this); @@ -4867,28 +4453,6 @@ extern (C++) final class TypeIdentifier : TypeQualified return t; } - /***************************************** - * See if type resolves to a symbol, if so, - * return that symbol. - */ - override Dsymbol toDsymbol(Scope* sc) - { - //printf("TypeIdentifier::toDsymbol('%s')\n", toChars()); - if (!sc) - return null; - - Type t; - Expression e; - Dsymbol s; - resolve(this, loc, sc, e, t, s); - if (t && t.ty != Tident) - s = t.toDsymbol(sc); - if (e) - s = getDsymbol(e); - - return s; - } - override void accept(Visitor v) { v.visit(this); @@ -4922,18 +4486,6 @@ extern (C++) final class TypeInstance : TypeQualified return t; } - override Dsymbol toDsymbol(Scope* sc) - { - Type t; - Expression e; - Dsymbol s; - //printf("TypeInstance::semantic(%s)\n", toChars()); - resolve(this, loc, sc, e, t, s); - if (t && t.ty != Tinstance) - s = t.toDsymbol(sc); - return s; - } - override void accept(Visitor v) { v.visit(this); @@ -4967,16 +4519,6 @@ extern (C++) final class TypeTypeof : TypeQualified return t; } - override Dsymbol toDsymbol(Scope* sc) - { - //printf("TypeTypeof::toDsymbol('%s')\n", toChars()); - Expression e; - Type t; - Dsymbol s; - resolve(this, loc, sc, e, t, s); - return s; - } - override uinteger_t size(const ref Loc loc) { if (exp.type) @@ -5013,15 +4555,6 @@ extern (C++) final class TypeReturn : TypeQualified return t; } - override Dsymbol toDsymbol(Scope* sc) - { - Expression e; - Type t; - Dsymbol s; - resolve(this, loc, sc, e, t, s); - return s; - } - override void accept(Visitor v) { v.visit(this); @@ -5068,11 +4601,6 @@ extern (C++) final class TypeStruct : Type return this; } - override Dsymbol toDsymbol(Scope* sc) - { - return sym; - } - override structalign_t alignment() { if (sym.alignment.isUnknown()) @@ -5214,15 +4742,6 @@ extern (C++) final class TypeStruct : Type return false; } - override bool hasPointers() - { - if (sym.members && !sym.determineFields() && sym.type != Type.terror) - error(sym.loc, "no size because of forward references"); - - sym.determineTypeProperties(); - return sym.hasPointerField; - } - override bool hasVoidInitPointers() { sym.size(Loc.initial); // give error for forward references @@ -5393,9 +4912,9 @@ extern (C++) final class TypeEnum : Type return sym.getMemtype(loc).size(loc); } - Type memType(const ref Loc loc = Loc.initial) + Type memType() { - return sym.getMemtype(loc); + return sym.getMemtype(Loc.initial); } override uint alignsize() @@ -5406,11 +4925,6 @@ extern (C++) final class TypeEnum : Type return t.alignsize(); } - override Dsymbol toDsymbol(Scope* sc) - { - return sym; - } - override bool isintegral() { return memType().isintegral(); @@ -5511,11 +5025,6 @@ extern (C++) final class TypeEnum : Type return sym.getDefaultValue(loc).toBool().hasValue(false); } - override bool hasPointers() - { - return memType().hasPointers(); - } - override bool hasVoidInitPointers() { return memType().hasVoidInitPointers(); @@ -5571,44 +5080,14 @@ extern (C++) final class TypeClass : Type return this; } - override Dsymbol toDsymbol(Scope* sc) - { - return sym; - } - override inout(ClassDeclaration) isClassHandle() inout { return sym; } - override bool isBaseOf(Type t, int* poffset) - { - if (t && t.ty == Tclass) - { - ClassDeclaration cd = (cast(TypeClass)t).sym; - if (cd.semanticRun < PASS.semanticdone && !cd.isBaseInfoComplete()) - cd.dsymbolSemantic(null); - if (sym.semanticRun < PASS.semanticdone && !sym.isBaseInfoComplete()) - sym.dsymbolSemantic(null); - - if (sym.isBaseOf(cd, poffset)) - return true; - } - return false; - } - extern (D) MATCH implicitConvToWithoutAliasThis(Type to) { - // Run semantic before checking whether class is convertible ClassDeclaration cdto = to.isClassHandle(); - if (cdto) - { - //printf("TypeClass::implicitConvTo(to = '%s') %s, isbase = %d %d\n", to.toChars(), toChars(), cdto.isBaseInfoComplete(), sym.isBaseInfoComplete()); - if (cdto.semanticRun < PASS.semanticdone && !cdto.isBaseInfoComplete()) - cdto.dsymbolSemantic(null); - if (sym.semanticRun < PASS.semanticdone && !sym.isBaseInfoComplete()) - sym.dsymbolSemantic(null); - } MATCH m = constConv(to); if (m > MATCH.nomatch) return m; @@ -5706,11 +5185,6 @@ extern (C++) final class TypeClass : Type return true; } - override bool hasPointers() - { - return true; - } - override void accept(Visitor v) { v.visit(this); @@ -5952,14 +5426,6 @@ extern (C++) final class TypeNull : Type return MATCH.nomatch; } - override bool hasPointers() - { - /* Although null isn't dereferencable, treat it as a pointer type for - * attribute inference, generic code, etc. - */ - return true; - } - override bool isBoolean() { return true; @@ -6633,39 +6099,6 @@ bool isIndexableNonAggregate(Type t) t.ty == Ttuple || t.ty == Tvector); } -/*************************************************** - * Determine if type t is copyable. - * Params: - * t = type to check - * Returns: - * true if we can copy it - */ -bool isCopyable(Type t) -{ - //printf("isCopyable() %s\n", t.toChars()); - if (auto ts = t.isTypeStruct()) - { - if (ts.sym.postblit && - ts.sym.postblit.storage_class & STC.disable) - return false; - if (ts.sym.hasCopyCtor) - { - // check if there is a matching overload of the copy constructor and whether it is disabled or not - // `assert(ctor)` fails on Win32 and Win_32_64. See: https://auto-tester.puremagic.com/pull-history.ghtml?projectid=1&repoid=1&pullid=10575 - Dsymbol ctor = search_function(ts.sym, Id.ctor); - assert(ctor); - scope el = new IdentifierExp(Loc.initial, Id.p); // dummy lvalue - el.type = cast() ts; - Expressions* args = new Expressions(); - args.push(el); - FuncDeclaration f = resolveFuncCall(Loc.initial, null, ctor, null, cast()ts, ArgumentList(args), FuncResolveFlag.quiet); - if (!f || f.storage_class & STC.disable) - return false; - } - } - return true; -} - /*************************************** * Computes how a parameter may be returned. * Shrinking the representation is necessary because StorageClass is so wide diff --git a/gcc/d/dmd/mtype.h b/gcc/d/dmd/mtype.h index 97a7ae3..c777f35 100644 --- a/gcc/d/dmd/mtype.h +++ b/gcc/d/dmd/mtype.h @@ -233,7 +233,6 @@ public: uinteger_t size(); virtual uinteger_t size(const Loc &loc); virtual unsigned alignsize(); - Type *trySemantic(const Loc &loc, Scope *sc); Type *merge2(); void modToBuffer(OutBuffer& buf) const; char *modToChars() const; @@ -287,9 +286,7 @@ public: virtual Type *makeSharedWild(); virtual Type *makeSharedWildConst(); virtual Type *makeMutable(); - virtual Dsymbol *toDsymbol(Scope *sc); Type *toBasetype(); - virtual bool isBaseOf(Type *t, int *poffset); virtual MATCH implicitConvTo(Type *to); virtual MATCH constConv(Type *to); virtual unsigned char deduceWild(Type *t, bool isRef); @@ -302,9 +299,7 @@ public: virtual structalign_t alignment(); virtual Expression *defaultInitLiteral(const Loc &loc); virtual bool isZeroInit(const Loc &loc = Loc()); // if initializer is 0 - Identifier *getTypeInfoIdent(); virtual int hasWild() const; - virtual bool hasPointers(); virtual bool hasVoidInitPointers(); virtual bool hasSystemFields(); virtual bool hasInvariant(); @@ -451,7 +446,6 @@ public: MATCH constConv(Type *to) override; MATCH implicitConvTo(Type *to) override; Expression *defaultInitLiteral(const Loc &loc) override; - bool hasPointers() override; bool hasSystemFields() override; bool hasVoidInitPointers() override; bool hasInvariant() override; @@ -474,7 +468,6 @@ public: bool isZeroInit(const Loc &loc) override; bool isBoolean() override; MATCH implicitConvTo(Type *to) override; - bool hasPointers() override; void accept(Visitor *v) override { v->visit(this); } }; @@ -491,7 +484,6 @@ public: uinteger_t size(const Loc &loc) override; bool isZeroInit(const Loc &loc) override; bool isBoolean() override; - bool hasPointers() override; MATCH implicitConvTo(Type *to) override; MATCH constConv(Type *to) override; @@ -509,7 +501,6 @@ public: MATCH constConv(Type *to) override; bool isscalar() override; bool isZeroInit(const Loc &loc) override; - bool hasPointers() override; void accept(Visitor *v) override { v->visit(this); } }; @@ -605,10 +596,8 @@ public: static TypeFunction *create(Parameters *parameters, Type *treturn, VarArg varargs, LINK linkage, StorageClass stc = 0); const char *kind() override; TypeFunction *syntaxCopy() override; - void purityLevel(); bool hasLazyParameters(); bool isDstyleVariadic() const; - StorageClass parameterStorageClass(Type* tthis, Parameter *p, VarDeclarations* outerVars = nullptr, bool indirect = false); Type *addStorageClass(StorageClass stc) override; Type *substWildTo(unsigned mod) override; @@ -659,7 +648,6 @@ public: MATCH implicitConvTo(Type *to) override; bool isZeroInit(const Loc &loc) override; bool isBoolean() override; - bool hasPointers() override; void accept(Visitor *v) override { v->visit(this); } }; @@ -675,7 +663,6 @@ class TypeTraits final : public Type const char *kind() override; TypeTraits *syntaxCopy() override; uinteger_t size(const Loc &loc) override; - Dsymbol *toDsymbol(Scope *sc) override; void accept(Visitor *v) override { v->visit(this); } }; @@ -687,7 +674,6 @@ class TypeMixin final : public Type const char *kind() override; TypeMixin *syntaxCopy() override; - Dsymbol *toDsymbol(Scope *sc) override; void accept(Visitor *v) override { v->visit(this); } }; @@ -713,7 +699,6 @@ public: static TypeIdentifier *create(const Loc &loc, Identifier *ident); const char *kind() override; TypeIdentifier *syntaxCopy() override; - Dsymbol *toDsymbol(Scope *sc) override; void accept(Visitor *v) override { v->visit(this); } }; @@ -726,7 +711,6 @@ public: const char *kind() override; TypeInstance *syntaxCopy() override; - Dsymbol *toDsymbol(Scope *sc) override; void accept(Visitor *v) override { v->visit(this); } }; @@ -738,7 +722,6 @@ public: const char *kind() override; TypeTypeof *syntaxCopy() override; - Dsymbol *toDsymbol(Scope *sc) override; uinteger_t size(const Loc &loc) override; void accept(Visitor *v) override { v->visit(this); } }; @@ -748,7 +731,6 @@ class TypeReturn final : public TypeQualified public: const char *kind() override; TypeReturn *syntaxCopy() override; - Dsymbol *toDsymbol(Scope *sc) override; void accept(Visitor *v) override { v->visit(this); } }; @@ -776,7 +758,6 @@ public: uinteger_t size(const Loc &loc) override; unsigned alignsize() override; TypeStruct *syntaxCopy() override; - Dsymbol *toDsymbol(Scope *sc) override; structalign_t alignment() override; Expression *defaultInitLiteral(const Loc &loc) override; bool isZeroInit(const Loc &loc) override; @@ -785,7 +766,6 @@ public: bool needsDestruction() override; bool needsCopyOrPostblit() override; bool needsNested() override; - bool hasPointers() override; bool hasVoidInitPointers() override; bool hasSystemFields() override; bool hasInvariant() override; @@ -806,8 +786,7 @@ public: TypeEnum *syntaxCopy() override; uinteger_t size(const Loc &loc) override; unsigned alignsize() override; - Type *memType(const Loc &loc = Loc()); - Dsymbol *toDsymbol(Scope *sc) override; + Type *memType(const Loc &loc); bool isintegral() override; bool isfloating() override; bool isreal() override; @@ -824,7 +803,6 @@ public: MATCH implicitConvTo(Type *to) override; MATCH constConv(Type *to) override; bool isZeroInit(const Loc &loc) override; - bool hasPointers() override; bool hasVoidInitPointers() override; bool hasSystemFields() override; bool hasInvariant() override; @@ -843,9 +821,7 @@ public: const char *kind() override; uinteger_t size(const Loc &loc) override; TypeClass *syntaxCopy() override; - Dsymbol *toDsymbol(Scope *sc) override; ClassDeclaration *isClassHandle() override; - bool isBaseOf(Type *t, int *poffset) override; MATCH implicitConvTo(Type *to) override; MATCH constConv(Type *to) override; unsigned char deduceWild(Type *t, bool isRef) override; @@ -853,7 +829,6 @@ public: bool isZeroInit(const Loc &loc) override; bool isscope() override; bool isBoolean() override; - bool hasPointers() override; void accept(Visitor *v) override { v->visit(this); } }; @@ -894,7 +869,6 @@ public: TypeNull *syntaxCopy() override; MATCH implicitConvTo(Type *to) override; - bool hasPointers() override; bool isBoolean() override; uinteger_t size(const Loc &loc) override; @@ -925,6 +899,13 @@ public: /**************************************************************/ + // If the type is a class or struct, returns the symbol for it, else null. AggregateDeclaration *isAggregate(Type *t); +bool hasPointers(Type *t); +// return the symbol to which type t resolves +Dsymbol *toDsymbol(Type *t, Scope *sc); Covariant covariant(Type *, Type *, StorageClass * = NULL, bool = false); +bool isBaseOf(Type *tthis, Type *t, int *poffset); +Type *trySemantic(Type *type, const Loc &loc, Scope *sc); +void purityLevel(TypeFunction *type); diff --git a/gcc/d/dmd/mustuse.d b/gcc/d/dmd/mustuse.d index b5601a2..c2fa5fb 100644 --- a/gcc/d/dmd/mustuse.d +++ b/gcc/d/dmd/mustuse.d @@ -31,6 +31,7 @@ import dmd.location; bool checkMustUse(Expression e, Scope* sc) { import dmd.id : Id; + import dmd.typesem : toDsymbol; assert(e.type); if (auto sym = e.type.toDsymbol(sc)) diff --git a/gcc/d/dmd/ob.d b/gcc/d/dmd/ob.d index 785912e..0a59815 100644 --- a/gcc/d/dmd/ob.d +++ b/gcc/d/dmd/ob.d @@ -2566,6 +2566,7 @@ void checkObErrors(ref ObState obstate) //printf("%s: ", obstate.vars[i].toChars()); pvs.print(obstate.vars[]); if (pvs.state == PtrState.Owner) { + import dmd.typesem : hasPointers; auto v = obstate.vars[i]; if (v.type.hasPointers()) .error(v.loc, "%s `%s` is not disposed of before return", v.kind, v.toPrettyChars); diff --git a/gcc/d/dmd/parse.d b/gcc/d/dmd/parse.d index a012e0c..268622a 100644 --- a/gcc/d/dmd/parse.d +++ b/gcc/d/dmd/parse.d @@ -1675,7 +1675,7 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer if (token.value == TOK.assign) // = CondExpression { nextToken(); - tp_defaultvalue = parseDefaultInitExp(); + tp_defaultvalue = parseAssignExp(); } tp = new AST.TemplateValueParameter(loc, tp_ident, tp_valtype, tp_specvalue, tp_defaultvalue); } @@ -2969,7 +2969,7 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer if (token.value == TOK.assign) // = defaultArg { nextToken(); - ae = parseDefaultInitExp(); + ae = parseAssignExp(); } auto param = new AST.Parameter(loc, storageClass | STC.parameter, at, ai, ae, null); if (udas) @@ -6949,33 +6949,6 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer } } - /***************************************** - * Parses default argument initializer expression that is an assign expression, - * with special handling for __FILE__, __FILE_DIR__, __LINE__, __MODULE__, __FUNCTION__, and __PRETTY_FUNCTION__. - */ - private AST.Expression parseDefaultInitExp() - { - AST.Expression e = null; - const tv = peekNext(); - if (tv == TOK.comma || tv == TOK.rightParenthesis) - { - switch (token.value) - { - case TOK.file: e = new AST.FileInitExp(token.loc, EXP.file); break; - case TOK.fileFullPath: e = new AST.FileInitExp(token.loc, EXP.fileFullPath); break; - case TOK.line: e = new AST.LineInitExp(token.loc); break; - case TOK.moduleString: e = new AST.ModuleInitExp(token.loc); break; - case TOK.functionString: e = new AST.FuncInitExp(token.loc); break; - case TOK.prettyFunction: e = new AST.PrettyFuncInitExp(token.loc); break; - default: goto LExp; - } - nextToken(); - return e; - } - LExp: - return parseAssignExp(); - } - /******************** * Parse inline assembler block. * Enters with token on the `asm`. @@ -8152,33 +8125,23 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer break; case TOK.file: - { - const(char)* s = loc.filename ? loc.filename : mod.ident.toChars(); - e = new AST.StringExp(loc, s.toDString()); - nextToken(); - break; - } + e = new AST.FileInitExp(loc, EXP.file); + nextToken(); + break; case TOK.fileFullPath: - { - assert(loc.isValid(), "__FILE_FULL_PATH__ does not work with an invalid location"); - const s = FileName.toAbsolute(loc.filename); - e = new AST.StringExp(loc, s.toDString()); - nextToken(); - break; - } + e = new AST.FileInitExp(loc, EXP.fileFullPath); + nextToken(); + break; case TOK.line: - e = new AST.IntegerExp(loc, loc.linnum, AST.Type.tint32); + e = new AST.LineInitExp(loc); nextToken(); break; case TOK.moduleString: - { - const(char)* s = md ? md.toChars() : mod.toChars(); - e = new AST.StringExp(loc, s.toDString()); - nextToken(); - break; - } + e = new AST.ModuleInitExp(loc); + nextToken(); + break; case TOK.functionString: e = new AST.FuncInitExp(loc); nextToken(); diff --git a/gcc/d/dmd/safe.d b/gcc/d/dmd/safe.d index af81bff..8b57f7f 100644 --- a/gcc/d/dmd/safe.d +++ b/gcc/d/dmd/safe.d @@ -26,6 +26,7 @@ import dmd.identifier; import dmd.mtype; import dmd.target; import dmd.tokens; +import dmd.typesem : hasPointers; import dmd.func : setUnsafe, setUnsafePreview; /************************************************************* diff --git a/gcc/d/dmd/scope.h b/gcc/d/dmd/scope.h index 1535fd0..4b157cc 100644 --- a/gcc/d/dmd/scope.h +++ b/gcc/d/dmd/scope.h @@ -87,6 +87,7 @@ struct Scope Dsymbol *inunion; // !=null if processing members of a union d_bool nofree; // true if shouldn't free it d_bool inLoop; // true if inside a loop (where constructor calls aren't allowed) + d_bool inDefaultArg; // true if inside a default argument (where __FILE__, etc are evaluated at the call site) int intypeof; // in typeof(exp) VarDeclaration *lastVar; // Previous symbol used to prevent goto-skips-init ErrorSink *eSink; // sink for error messages diff --git a/gcc/d/dmd/semantic3.d b/gcc/d/dmd/semantic3.d index 520e05f..174d9b4 100644 --- a/gcc/d/dmd/semantic3.d +++ b/gcc/d/dmd/semantic3.d @@ -231,8 +231,7 @@ private extern(C++) final class Semantic3Visitor : Visitor if (sc.flags & SCOPE.Cfile && funcdecl.isCMain() && f.next.ty == Tint32) return true; - return f.next.ty == Tvoid && - (funcdecl.isMain() || global.params.betterC && funcdecl.isCMain()); + return f.next.ty == Tvoid && (funcdecl.isMain() || funcdecl.isCMain()); } VarDeclaration _arguments = null; @@ -346,6 +345,7 @@ private extern(C++) final class Semantic3Visitor : Visitor sc2.tf = null; sc2.os = null; sc2.inLoop = false; + sc2.inDefaultArg = false; sc2.userAttribDecl = null; if (sc2.intypeof == 1) sc2.intypeof = 2; @@ -570,7 +570,7 @@ private extern(C++) final class Semantic3Visitor : Visitor if ((needEnsure && global.params.useOut == CHECKENABLE.on) || fpostinv) { - funcdecl.returnLabel = funcdecl.searchLabel(Id.returnLabel); + funcdecl.returnLabel = funcdecl.searchLabel(Id.returnLabel, Loc.initial); } // scope of out contract (need for vresult.semantic) diff --git a/gcc/d/dmd/sideeffect.d b/gcc/d/dmd/sideeffect.d index 59398a7..8038770 100644 --- a/gcc/d/dmd/sideeffect.d +++ b/gcc/d/dmd/sideeffect.d @@ -24,6 +24,7 @@ import dmd.init; import dmd.mtype; import dmd.postordervisitor; import dmd.tokens; +import dmd.typesem; import dmd.visitor; /************************************************** diff --git a/gcc/d/dmd/statementsem.d b/gcc/d/dmd/statementsem.d index 229cf17..d4827ae 100644 --- a/gcc/d/dmd/statementsem.d +++ b/gcc/d/dmd/statementsem.d @@ -3753,7 +3753,10 @@ public bool throwSemantic(const ref Loc loc, ref Expression exp, Scope* sc) { if (!global.params.useExceptions) { - loc.error("cannot use `throw` statements with %s", global.params.betterC ? "-betterC".ptr : "-nothrow".ptr); + version (IN_GCC) + loc.error("cannot use `throw` statements with `-fno-exceptions`"); + else + loc.error("cannot use `throw` statements with %s", global.params.betterC ? "-betterC".ptr : "-nothrow".ptr); return false; } diff --git a/gcc/d/dmd/template.h b/gcc/d/dmd/template.h index 09c4912..153eb4e 100644 --- a/gcc/d/dmd/template.h +++ b/gcc/d/dmd/template.h @@ -324,4 +324,4 @@ Tuple *isTuple(RootObject *o); Parameter *isParameter(RootObject *o); TemplateParameter *isTemplateParameter(RootObject *o); bool isError(const RootObject *const o); -void printTemplateStats(); +void printTemplateStats(bool listInstances, ErrorSink* eSink); diff --git a/gcc/d/dmd/typesem.d b/gcc/d/dmd/typesem.d index 51b4ef8..714af8a 100644 --- a/gcc/d/dmd/typesem.d +++ b/gcc/d/dmd/typesem.d @@ -430,6 +430,123 @@ private Dsymbol searchX(Dsymbol dsym, const ref Loc loc, Scope* sc, RootObject i return sm; } +/*************************************************** + * Determine if type t is copyable. + * Params: + * t = type to check + * Returns: + * true if we can copy it + */ +bool isCopyable(Type t) +{ + //printf("isCopyable() %s\n", t.toChars()); + if (auto ts = t.isTypeStruct()) + { + if (ts.sym.postblit && + ts.sym.postblit.storage_class & STC.disable) + return false; + if (ts.sym.hasCopyCtor) + { + // check if there is a matching overload of the copy constructor and whether it is disabled or not + // `assert(ctor)` fails on Win32 and Win_32_64. See: https://auto-tester.puremagic.com/pull-history.ghtml?projectid=1&repoid=1&pullid=10575 + Dsymbol ctor = search_function(ts.sym, Id.ctor); + assert(ctor); + scope el = new IdentifierExp(Loc.initial, Id.p); // dummy lvalue + el.type = cast() ts; + Expressions* args = new Expressions(); + args.push(el); + FuncDeclaration f = resolveFuncCall(Loc.initial, null, ctor, null, cast()ts, ArgumentList(args), FuncResolveFlag.quiet); + if (!f || f.storage_class & STC.disable) + return false; + } + } + return true; +} + +/************************************ + * Determine mutability of indirections in (ref) t. + * + * Returns: When the type has any mutable indirections, returns 0. + * When all indirections are immutable, returns 2. + * Otherwise, when the type has const/inout indirections, returns 1. + * + * Params: + * isref = if true, check `ref t`; otherwise, check just `t` + * t = the type that is being checked + */ +int mutabilityOfType(bool isref, Type t) +{ + if (isref) + { + if (t.mod & MODFlags.immutable_) + return 2; + if (t.mod & (MODFlags.const_ | MODFlags.wild)) + return 1; + return 0; + } + + t = t.baseElemOf(); + + if (!t.hasPointers() || t.mod & MODFlags.immutable_) + return 2; + + /* Accept immutable(T)[] and immutable(T)* as being strongly pure + */ + if (t.ty == Tarray || t.ty == Tpointer) + { + Type tn = t.nextOf().toBasetype(); + if (tn.mod & MODFlags.immutable_) + return 2; + if (tn.mod & (MODFlags.const_ | MODFlags.wild)) + return 1; + } + + /* The rest of this is too strict; fix later. + * For example, the only pointer members of a struct may be immutable, + * which would maintain strong purity. + * (Just like for dynamic arrays and pointers above.) + */ + if (t.mod & (MODFlags.const_ | MODFlags.wild)) + return 1; + + /* Should catch delegates and function pointers, and fold in their purity + */ + return 0; +} + +/******************************************** + * Set 'purity' field of 'typeFunction'. + * Do this lazily, as the parameter types might be forward referenced. + */ +extern(C++) void purityLevel(TypeFunction typeFunction) +{ + TypeFunction tf = typeFunction; + if (tf.purity != PURE.fwdref) + return; + + typeFunction.purity = PURE.const_; // assume strong until something weakens it + + /* Evaluate what kind of purity based on the modifiers for the parameters + */ + foreach (i, fparam; tf.parameterList) + { + Type t = fparam.type; + if (!t) + continue; + + if (fparam.storageClass & (STC.lazy_ | STC.out_)) + { + typeFunction.purity = PURE.weak; + break; + } + const pref = (fparam.storageClass & STC.ref_) != 0; + if (mutabilityOfType(pref, t) == 0) + typeFunction.purity = PURE.weak; + } + + tf.purity = typeFunction.purity; +} + /****************************************** * We've mistakenly parsed `t` as a type. * Redo `t` as an Expression only if there are no type modifiers. @@ -486,6 +603,77 @@ Expression typeToExpression(Type t) } } +/************************************* + * https://issues.dlang.org/show_bug.cgi?id=14488 + * Check if the inner most base type is complex or imaginary. + * Should only give alerts when set to emit transitional messages. + * Params: + * type = type to check + * loc = The source location. + * sc = scope of the type + */ +extern (D) bool checkComplexTransition(Type type, const ref Loc loc, Scope* sc) +{ + if (sc.isDeprecated()) + return false; + // Don't complain if we're inside a template constraint + // https://issues.dlang.org/show_bug.cgi?id=21831 + if (sc.flags & SCOPE.constraint) + return false; + + Type t = type.baseElemOf(); + while (t.ty == Tpointer || t.ty == Tarray) + t = t.nextOf().baseElemOf(); + + // Basetype is an opaque enum, nothing to check. + if (t.ty == Tenum && !(cast(TypeEnum)t).sym.memtype) + return false; + + if (t.isimaginary() || t.iscomplex()) + { + if (sc.flags & SCOPE.Cfile) + return true; // complex/imaginary not deprecated in C code + Type rt; + switch (t.ty) + { + case Tcomplex32: + case Timaginary32: + rt = Type.tfloat32; + break; + + case Tcomplex64: + case Timaginary64: + rt = Type.tfloat64; + break; + + case Tcomplex80: + case Timaginary80: + rt = Type.tfloat80; + break; + + default: + assert(0); + } + // @@@DEPRECATED_2.117@@@ + // Deprecated in 2.097 - Can be made an error from 2.117. + // The deprecation period is longer than usual as `cfloat`, + // `cdouble`, and `creal` were quite widely used. + if (t.iscomplex()) + { + deprecation(loc, "use of complex type `%s` is deprecated, use `std.complex.Complex!(%s)` instead", + type.toChars(), rt.toChars()); + return true; + } + else + { + deprecation(loc, "use of imaginary type `%s` is deprecated, use `%s` instead", + type.toChars(), rt.toChars()); + return true; + } + } + return false; +} + /******************************** * 'args' are being matched to function type 'tf' * Determine match level. @@ -494,12 +682,12 @@ Expression typeToExpression(Type t) * tthis = type of `this` pointer, null if not member function * argumentList = arguments to function call * flag = 1: performing a partial ordering match - * pMessage = address to store error message, or null + * errorHelper = delegate to call for error messages * sc = context * Returns: * MATCHxxxx */ -extern (D) MATCH callMatch(TypeFunction tf, Type tthis, ArgumentList argumentList, int flag = 0, const(char)** pMessage = null, Scope* sc = null) +extern (D) MATCH callMatch(TypeFunction tf, Type tthis, ArgumentList argumentList, int flag = 0, void delegate(const(char)*) scope errorHelper = null, Scope* sc = null) { //printf("TypeFunction::callMatch() %s\n", tf.toChars()); MATCH match = MATCH.exact; // assume exact match @@ -542,7 +730,7 @@ extern (D) MATCH callMatch(TypeFunction tf, Type tthis, ArgumentList argumentLis { // suppress early exit if an error message is wanted, // so we can check any matching args are valid - if (!pMessage) + if (!errorHelper) return MATCH.nomatch; } // too many args; no match @@ -552,18 +740,25 @@ extern (D) MATCH callMatch(TypeFunction tf, Type tthis, ArgumentList argumentLis // https://issues.dlang.org/show_bug.cgi?id=22997 if (parameterList.varargs == VarArg.none && nparams > argumentList.length && !parameterList.hasDefaultArgs) { - OutBuffer buf; - buf.printf("too few arguments, expected %d, got %d", cast(int)nparams, cast(int)argumentList.length); - if (pMessage) - *pMessage = buf.extractChars(); + if (errorHelper) + { + OutBuffer buf; + buf.printf("too few arguments, expected %d, got %d", cast(int)nparams, cast(int)argumentList.length); + errorHelper(buf.peekChars()); + } return MATCH.nomatch; } + const(char)* failMessage; + const(char)** pMessage = errorHelper ? &failMessage : null; auto resolvedArgs = tf.resolveNamedArgs(argumentList, pMessage); Expression[] args; if (!resolvedArgs) { - if (!pMessage || *pMessage) + if (failMessage) + { + errorHelper(failMessage); return MATCH.nomatch; + } // if no message was provided, it was because of overflow which will be diagnosed below match = MATCH.nomatch; @@ -642,6 +837,8 @@ extern (D) MATCH callMatch(TypeFunction tf, Type tthis, ArgumentList argumentLis if (auto vmatch = matchTypeSafeVarArgs(tf, p, trailingArgs, pMessage)) return vmatch < match ? vmatch : match; // Error message was already generated in `matchTypeSafeVarArgs` + if (failMessage) + errorHelper(failMessage); return MATCH.nomatch; } if (pMessage && u >= args.length) @@ -651,16 +848,18 @@ extern (D) MATCH callMatch(TypeFunction tf, Type tthis, ArgumentList argumentLis else if (pMessage && !*pMessage) *pMessage = tf.getParamError(args[u], p); + if (errorHelper) + errorHelper(*pMessage); return MATCH.nomatch; } if (m < match) match = m; // pick worst match } - if (pMessage && !parameterList.varargs && args.length > nparams) + if (errorHelper && !parameterList.varargs && args.length > nparams) { // all parameters had a match, but there are surplus args - *pMessage = tf.getMatchError("expected %d argument(s), not %d", nparams, args.length); + errorHelper(tf.getMatchError("expected %d argument(s), not %d", nparams, args.length)); return MATCH.nomatch; } //printf("match = %d\n", match); @@ -687,7 +886,7 @@ private extern(D) bool isCopyConstructorCallable (StructDeclaration argStruct, Expression e = new DotIdExp(arg.loc, ve, Id.ctor); e = new CallExp(arg.loc, e, arg); //printf("e = %s\n", e.toChars()); - if (.trySemantic(e, sc)) + if (dmd.expressionsem.trySemantic(e, sc)) return true; if (pMessage) @@ -1017,6 +1216,70 @@ private extern(D) MATCH matchTypeSafeVarArgs(TypeFunction tf, Parameter p, } } +/*************************************** + * Return !=0 if type has pointers that need to + * be scanned by the GC during a collection cycle. + */ +extern(C++) bool hasPointers(Type t) +{ + bool visitType(Type _) { return false; } + bool visitDArray(TypeDArray _) { return true; } + bool visitAArray(TypeAArray _) { return true; } + bool visitPointer(TypePointer _) { return true; } + bool visitDelegate(TypeDelegate _) { return true; } + bool visitClass(TypeClass _) { return true; } + bool visitEnum(TypeEnum t) { return t.memType().hasPointers(); } + + /* Although null isn't dereferencable, treat it as a pointer type for + * attribute inference, generic code, etc. + */ + bool visitNull(TypeNull _) { return true; } + + bool visitSArray(TypeSArray t) + { + /* Don't want to do this, because: + * struct S { T* array[0]; } + * may be a variable length struct. + */ + //if (dim.toInteger() == 0) + // return false; + + if (t.next.ty == Tvoid) + { + // Arrays of void contain arbitrary data, which may include pointers + return true; + } + else + return t.next.hasPointers(); + } + + bool visitStruct(TypeStruct t) + { + StructDeclaration sym = t.sym; + + if (sym.members && !sym.determineFields() && sym.type != Type.terror) + error(sym.loc, "no size because of forward references"); + + sym.determineTypeProperties(); + return sym.hasPointerField; + } + + + switch(t.ty) + { + default: return visitType(t); + case Tsarray: return visitSArray(t.isTypeSArray()); + case Tarray: return visitDArray(t.isTypeDArray()); + case Taarray: return visitAArray(t.isTypeAArray()); + case Tpointer: return visitPointer(t.isTypePointer()); + case Tdelegate: return visitDelegate(t.isTypeDelegate()); + case Tstruct: return visitStruct(t.isTypeStruct()); + case Tenum: return visitEnum(t.isTypeEnum()); + case Tclass: return visitClass(t.isTypeClass()); + case Tnull: return visitNull(t.isTypeNull()); + } +} + /****************************************** * Perform semantic analysis on a type. * Params: @@ -1661,9 +1924,12 @@ extern(C++) Type typeSemantic(Type type, const ref Loc loc, Scope* sc) else { e = inferType(e, fparam.type); + Scope* sc2 = sc.push(); + sc2.inDefaultArg = true; Initializer iz = new ExpInitializer(e.loc, e); - iz = iz.initializerSemantic(sc, fparam.type, INITnointerpret); + iz = iz.initializerSemantic(sc2, fparam.type, INITnointerpret); e = iz.initializerToExpression(); + sc2.pop(); } if (e.op == EXP.function_) // https://issues.dlang.org/show_bug.cgi?id=4820 { @@ -2553,6 +2819,31 @@ extern(C++) Type typeSemantic(Type type, const ref Loc loc, Scope* sc) } } +extern(C++) Type trySemantic(Type type, const ref Loc loc, Scope* sc) +{ + //printf("+trySemantic(%s) %d\n", toChars(), global.errors); + + // Needed to display any deprecations that were gagged + auto tcopy = type.syntaxCopy(); + + const errors = global.startGagging(); + Type t = typeSemantic(type, loc, sc); + if (global.endGagging(errors) || t.ty == Terror) // if any errors happened + { + t = null; + } + else + { + // If `typeSemantic` succeeded, there may have been deprecations that + // were gagged due the `startGagging` above. Run again to display + // those deprecations. https://issues.dlang.org/show_bug.cgi?id=19107 + if (global.gaggedWarnings > 0) + typeSemantic(tcopy, loc, sc); + } + //printf("-trySemantic(%s) %d\n", toChars(), global.errors); + return t; +} + /************************************ * If an identical type to `type` is in `type.stringtable`, return * the latter one. Otherwise, add it to `type.stringtable`. @@ -5216,6 +5507,117 @@ extern (C++) Expression defaultInit(Type mt, const ref Loc loc, const bool isCfi } } +/* +If `type` resolves to a dsymbol, then that +dsymbol is returned. + +Params: + type = the type that is checked + sc = the scope where the type is used + +Returns: + The dsymbol to which the type resolve or `null` + if the type does resolve to any symbol (for example, + in the case of basic types). +*/ +extern(C++) Dsymbol toDsymbol(Type type, Scope* sc) +{ + Dsymbol visitType(Type _) { return null; } + Dsymbol visitStruct(TypeStruct type) { return type.sym; } + Dsymbol visitEnum(TypeEnum type) { return type.sym; } + Dsymbol visitClass(TypeClass type) { return type.sym; } + + Dsymbol visitTraits(TypeTraits type) + { + Type t; + Expression e; + Dsymbol s; + resolve(type, type.loc, sc, e, t, s); + if (t && t.ty != Terror) + s = t.toDsymbol(sc); + else if (e) + s = getDsymbol(e); + + return s; + } + + Dsymbol visitMixin(TypeMixin type) + { + Type t; + Expression e; + Dsymbol s; + resolve(type, type.loc, sc, e, t, s); + if (t) + s = t.toDsymbol(sc); + else if (e) + s = getDsymbol(e); + + return s; + } + + Dsymbol visitIdentifier(TypeIdentifier type) + { + //printf("TypeIdentifier::toDsymbol('%s')\n", toChars()); + if (!sc) + return null; + + Type t; + Expression e; + Dsymbol s; + resolve(type, type.loc, sc, e, t, s); + if (t && t.ty != Tident) + s = t.toDsymbol(sc); + if (e) + s = getDsymbol(e); + + return s; + } + + Dsymbol visitInstance(TypeInstance type) + { + Type t; + Expression e; + Dsymbol s; + //printf("TypeInstance::semantic(%s)\n", toChars()); + resolve(type, type.loc, sc, e, t, s); + if (t && t.ty != Tinstance) + s = t.toDsymbol(sc); + return s; + } + + Dsymbol visitTypeof(TypeTypeof type) + { + //printf("TypeTypeof::toDsymbol('%s')\n", toChars()); + Expression e; + Type t; + Dsymbol s; + resolve(type, type.loc, sc, e, t, s); + return s; + } + + Dsymbol visitReturn(TypeReturn type) + { + Expression e; + Type t; + Dsymbol s; + resolve(type, type.loc, sc, e, t, s); + return s; + } + + switch(type.ty) + { + default: return visitType(type); + case Ttraits: return visitTraits(type.isTypeTraits()); + case Tmixin: return visitMixin(type.isTypeMixin()); + case Tident: return visitIdentifier(type.isTypeIdentifier()); + case Tinstance: return visitInstance(type.isTypeInstance()); + case Ttypeof: return visitTypeof(type.isTypeTypeof()); + case Treturn: return visitReturn(type.isTypeReturn()); + case Tstruct: return visitStruct(type.isTypeStruct()); + case Tenum: return visitEnum(type.isTypeEnum()); + case Tclass: return visitClass(type.isTypeClass()); + } +} /********************************************** * Extract complex type from core.stdc.config @@ -5541,6 +5943,144 @@ Lnotcovariant: return Covariant.no; } +/************************************ + * Take the specified storage class for p, + * and use the function signature to infer whether + * STC.scope_ and STC.return_ should be OR'd in. + * (This will not affect the name mangling.) + * Params: + * tf = TypeFunction to use to get the signature from + * tthis = type of `this` parameter, null if none + * p = parameter to this function + * outerVars = context variables p could escape into, if any + * indirect = is this for an indirect or virtual function call? + * Returns: + * storage class with STC.scope_ or STC.return_ OR'd in + */ +StorageClass parameterStorageClass(TypeFunction tf, Type tthis, Parameter p, VarDeclarations* outerVars = null, + bool indirect = false) +{ + //printf("parameterStorageClass(p: %s)\n", p.toChars()); + auto stc = p.storageClass; + + // When the preview switch is enable, `in` parameters are `scope` + if (stc & STC.constscoperef) + return stc | STC.scope_; + + if (stc & (STC.scope_ | STC.return_ | STC.lazy_) || tf.purity == PURE.impure) + return stc; + + /* If haven't inferred the return type yet, can't infer storage classes + */ + if (!tf.nextOf() || !tf.isnothrow()) + return stc; + + tf.purityLevel(); + + static bool mayHavePointers(Type t) + { + if (auto ts = t.isTypeStruct()) + { + auto sym = ts.sym; + if (sym.members && !sym.determineFields() && sym.type != Type.terror) + // struct is forward referenced, so "may have" pointers + return true; + } + return t.hasPointers(); + } + + // See if p can escape via any of the other parameters + if (tf.purity == PURE.weak) + { + /* + * Indirect calls may escape p through a nested context + * See: + * https://issues.dlang.org/show_bug.cgi?id=24212 + * https://issues.dlang.org/show_bug.cgi?id=24213 + */ + if (indirect) + return stc; + + // Check escaping through parameters + foreach (i, fparam; tf.parameterList) + { + Type t = fparam.type; + if (!t) + continue; + t = t.baseElemOf(); // punch thru static arrays + if (t.isMutable() && t.hasPointers()) + { + if (fparam.isReference() && fparam != p) + return stc; + + if (t.ty == Tdelegate) + return stc; // could escape thru delegate + + if (t.ty == Tclass) + return stc; + + /* if t is a pointer to mutable pointer + */ + if (auto tn = t.nextOf()) + { + if (tn.isMutable() && mayHavePointers(tn)) + return stc; // escape through pointers + } + } + } + + // Check escaping through `this` + if (tthis && tthis.isMutable()) + { + foreach (VarDeclaration v; isAggregate(tthis).fields) + { + if (v.hasPointers()) + return stc; + } + } + + // Check escaping through nested context + if (outerVars && tf.isMutable()) + { + foreach (VarDeclaration v; *outerVars) + { + if (v.hasPointers()) + return stc; + } + } + } + + // Check escaping through return value + Type tret = tf.nextOf().toBasetype(); + if (tf.isref || tret.hasPointers()) + { + return stc | STC.scope_ | STC.return_ | STC.returnScope; + } + else + return stc | STC.scope_; +} + +extern(C++) bool isBaseOf(Type tthis, Type t, int* poffset) +{ + auto tc = tthis.isTypeClass(); + if (!tc) + return false; + + if (!t || t.ty != Tclass) + return false; + + ClassDeclaration cd = t.isTypeClass().sym; + if (cd.semanticRun < PASS.semanticdone && !cd.isBaseInfoComplete()) + cd.dsymbolSemantic(null); + if (tc.sym.semanticRun < PASS.semanticdone && !tc.sym.isBaseInfoComplete()) + tc.sym.dsymbolSemantic(null); + + if (tc.sym.isBaseOf(cd, poffset)) + return true; + + return false; +} + /******************************* Private *****************************************/ private: diff --git a/gcc/d/expr.cc b/gcc/d/expr.cc index 7e63b0b..6f596c5 100644 --- a/gcc/d/expr.cc +++ b/gcc/d/expr.cc @@ -204,6 +204,22 @@ binop_assignment (tree_code code, Expression *e1, Expression *e2) return compound_expr (lexpr, expr); } +/* Compile the function literal body. */ + +static void +build_lambda_tree (FuncLiteralDeclaration *fld, Type *type = NULL) +{ + /* This check is for lambda's, remove `vthis' as function isn't nested. */ + if (fld->tok == TOK::reserved && (type == NULL || type->ty == TY::Tpointer)) + { + fld->tok = TOK::function_; + fld->vthis = NULL; + } + + /* Compile the function literal body. */ + build_decl_tree (fld); +} + /* Implements the visitor interface to build the GCC trees of all Expression AST classes emitted from the D Front-end. All visit methods accept one parameter E, which holds the frontend AST @@ -2012,17 +2028,8 @@ public: void visit (FuncExp *e) final override { - Type *ftype = e->type->toBasetype (); - - /* This check is for lambda's, remove `vthis' as function isn't nested. */ - if (e->fd->tok == TOK::reserved && ftype->ty == TY::Tpointer) - { - e->fd->tok = TOK::function_; - e->fd->vthis = NULL; - } - - /* Compile the function literal body. */ - build_decl_tree (e->fd); + /* Compile the declaration. */ + build_lambda_tree (e->fd, e->type->toBasetype ()); /* If nested, this will be a trampoline. */ if (e->fd->isNested ()) @@ -2071,6 +2078,10 @@ public: if (e->var->isFuncDeclaration ()) result = maybe_reject_intrinsic (result); + /* Emit lambdas, same as is done in FuncExp. */ + if (FuncLiteralDeclaration *fld = e->var->isFuncLiteralDeclaration ()) + build_lambda_tree (fld); + if (declaration_reference_p (e->var)) gcc_assert (POINTER_TYPE_P (TREE_TYPE (result))); else @@ -2105,19 +2116,9 @@ public: return; } - /* This check is same as is done in FuncExp for lambdas. */ - FuncLiteralDeclaration *fld = e->var->isFuncLiteralDeclaration (); - if (fld != NULL) - { - if (fld->tok == TOK::reserved) - { - fld->tok = TOK::function_; - fld->vthis = NULL; - } - - /* Compiler the function literal body. */ - build_decl_tree (fld); - } + /* Emit lambdas, same as is done in FuncExp. */ + if (FuncLiteralDeclaration *fld = e->var->isFuncLiteralDeclaration ()) + build_lambda_tree (fld); if (this->constp_) { diff --git a/gcc/d/typeinfo.cc b/gcc/d/typeinfo.cc index 257a2ab..dfab0e6 100644 --- a/gcc/d/typeinfo.cc +++ b/gcc/d/typeinfo.cc @@ -259,7 +259,8 @@ create_tinfo_types (Module *mod) array_type_node, array_type_node, array_type_node, array_type_node, ptr_type_node, ptr_type_node, ptr_type_node, d_uint_type, ptr_type_node, - array_type_node, ptr_type_node, ptr_type_node, NULL); + array_type_node, ptr_type_node, d_ulong_type, + d_ulong_type, ptr_type_node, NULL); object_module = mod; } @@ -814,6 +815,7 @@ public: void *deallocator; OffsetTypeInfo[] m_offTi; void function(Object) defaultConstructor; + ulong[2] nameSig immutable(void)* m_RTInfo; Information relating to interfaces, and their vtables are laid out @@ -932,6 +934,10 @@ public: else this->layout_field (null_pointer_node); + /* ulong[2] nameSig; */ + this->layout_field (build_zero_cst (d_ulong_type)); + this->layout_field (build_zero_cst (d_ulong_type)); + /* immutable(void)* m_RTInfo; */ if (cd->getRTInfo) this->layout_field (build_expr (cd->getRTInfo, true)); @@ -979,6 +985,10 @@ public: this->layout_field (null_array_node); this->layout_field (null_pointer_node); + /* ulong[2] nameSig; */ + this->layout_field (build_zero_cst (d_ulong_type)); + this->layout_field (build_zero_cst (d_ulong_type)); + /* immutable(void)* m_RTInfo; */ if (cd->getRTInfo) this->layout_field (build_expr (cd->getRTInfo, true)); @@ -1084,7 +1094,7 @@ public: /* StructFlags m_flags; */ int m_flags = StructFlags::none; - if (ti->hasPointers ()) + if (hasPointers (ti)) m_flags |= StructFlags::hasPointers; this->layout_field (build_integer_cst (m_flags, d_uint_type)); diff --git a/gcc/testsuite/gdc.test/compilable/b18242.d b/gcc/testsuite/gdc.test/compilable/b18242.d index 3bc699a..9909620 100644 --- a/gcc/testsuite/gdc.test/compilable/b18242.d +++ b/gcc/testsuite/gdc.test/compilable/b18242.d @@ -7,7 +7,7 @@ class Object { } class TypeInfo { } class TypeInfo_Class : TypeInfo { - version(D_LP64) { ubyte[136] _x; } else { ubyte[68] _x; } + version(D_LP64) { ubyte[136+16] _x; } else { ubyte[68+16] _x; } } class Throwable { } diff --git a/gcc/testsuite/gdc.test/compilable/issue24316.d b/gcc/testsuite/gdc.test/compilable/issue24316.d new file mode 100644 index 0000000..16d8a8b --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/issue24316.d @@ -0,0 +1,13 @@ +struct S +{ + int i; +} + +int f(immutable S *s) +{ + return s.i; +} + +immutable S globalS = S(5); + +static assert (f(&globalS) == 5); diff --git a/gcc/testsuite/gdc.test/fail_compilation/test24295.d b/gcc/testsuite/gdc.test/fail_compilation/test24295.d new file mode 100644 index 0000000..58b6e92 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/test24295.d @@ -0,0 +1,13 @@ +// REQUIRED_ARGS: -betterC + +/* +TEST_OUTPUT: +--- +fail_compilation/test24295.d(12): Error: expression `new int[](1$?:32=u|64=LU$)` allocates with the GC and cannot be used with switch `-betterC` +--- +*/ + +void f() +{ + int[] overlaps = new int[1]; +} diff --git a/gcc/testsuite/gdc.test/runnable/imports/issue18919b.d b/gcc/testsuite/gdc.test/runnable/imports/issue18919b.d new file mode 100644 index 0000000..4278f7f --- /dev/null +++ b/gcc/testsuite/gdc.test/runnable/imports/issue18919b.d @@ -0,0 +1,250 @@ +module imports.issue18919b; + +import core.stdc.stdio; + +// Remove directories from paths. Used to make the output platform-independent. +string baseName(string path) +{ + foreach_reverse (i, char c; path) + { + if (c == '/' || c == '\\') + return path[i + 1 .. $]; + } + return path; +} +const(char)* baseName(const(char)* path) +{ + for (const(char)* ptr = path; *ptr; ptr++) + { + if (*ptr == '/' || *ptr == '\\') + path = ptr + 1; + } + return path; +} + +void func1(string file = __FILE__, size_t line = __LINE__, + string func = __FUNCTION__, + string pfunc = __PRETTY_FUNCTION__, + string mod = __MODULE__) +{ + file = baseName(file); + printf("%s: %.*s:%d %.*s %.*s %.*s\n", __FUNCTION__.ptr, + cast(int) file.length, file.ptr, cast(int) line, + cast(int) func.length, func.ptr, + cast(int) pfunc.length, pfunc.ptr, + cast(int) mod.length, mod.ptr); +} + +// https://issues.dlang.org/show_bug.cgi?id=21211 +void func2(const(char)* file = __FILE__.ptr, size_t line = __LINE__, + const(char)* func = __FUNCTION__.ptr, + const(char)* pfunc = __PRETTY_FUNCTION__.ptr, + const(char)* mod = __MODULE__.ptr) +{ + file = baseName(file); + printf("%s: %s:%d %s %s %s\n", __FUNCTION__.ptr, + file, cast(int) line, func, pfunc, mod); +} + +// https://issues.dlang.org/show_bug.cgi?id=18919 +struct Loc3 +{ + string file; + size_t line; + string func; + string pfunc; + string mod; +} +void func3(Loc3 loc = Loc3(__FILE__, __LINE__, + __FUNCTION__, __PRETTY_FUNCTION__, __MODULE__)) +{ + loc.file = baseName(loc.file); + printf("%s: %.*s:%d %.*s %.*s %.*s\n", __FUNCTION__.ptr, + cast(int) loc.file.length, loc.file.ptr, cast(int) loc.line, + cast(int) loc.func.length, loc.func.ptr, + cast(int) loc.pfunc.length, loc.pfunc.ptr, + cast(int) loc.mod.length, loc.mod.ptr); +} +Loc3 defaultLoc3(string file = __FILE__, size_t line = __LINE__, + string func = __FUNCTION__, + string pfunc = __PRETTY_FUNCTION__, + string mod = __MODULE__) +{ + return Loc3(file, line, func, pfunc, mod); +} +void func3b(Loc3 loc = defaultLoc3) +{ + loc.file = baseName(loc.file); + printf("%s: %.*s:%d %.*s %.*s %.*s\n", __FUNCTION__.ptr, + cast(int) loc.file.length, loc.file.ptr, cast(int) loc.line, + cast(int) loc.func.length, loc.func.ptr, + cast(int) loc.pfunc.length, loc.pfunc.ptr, + cast(int) loc.mod.length, loc.mod.ptr); +} +enum Loc3Mixin = q{Loc3(__FILE__, __LINE__, + __FUNCTION__, __PRETTY_FUNCTION__, __MODULE__)}; +void func3c(Loc3 loc = mixin(Loc3Mixin)) +{ + loc.file = baseName(loc.file); + printf("%s: %.*s:%d %.*s %.*s %.*s\n", __FUNCTION__.ptr, + cast(int) loc.file.length, loc.file.ptr, cast(int) loc.line, + cast(int) loc.func.length, loc.func.ptr, + cast(int) loc.pfunc.length, loc.pfunc.ptr, + cast(int) loc.mod.length, loc.mod.ptr); +} +void func3d(Loc3* loc = new Loc3(__FILE__, __LINE__, + __FUNCTION__, __PRETTY_FUNCTION__, __MODULE__)) +{ + loc.file = baseName(loc.file); + printf("%s: %.*s:%d %.*s %.*s %.*s\n", __FUNCTION__.ptr, + cast(int) loc.file.length, loc.file.ptr, cast(int) loc.line, + cast(int) loc.func.length, loc.func.ptr, + cast(int) loc.pfunc.length, loc.pfunc.ptr, + cast(int) loc.mod.length, loc.mod.ptr); +} + +struct Loc4 +{ + const(char)* file; + size_t line; + const(char)* func; + const(char)* pfunc; + const(char)* mod; +} +void func4(Loc4 loc = Loc4(__FILE__.ptr, __LINE__, + __FUNCTION__.ptr, __PRETTY_FUNCTION__.ptr, __MODULE__.ptr)) +{ + loc.file = baseName(loc.file); + printf("%s: %s:%d %s %s %s\n", __FUNCTION__.ptr, + loc.file, cast(int) loc.line, + loc.func, + loc.pfunc, + loc.mod); +} +Loc4 defaultLoc4(const(char)* file = __FILE__.ptr, size_t line = __LINE__, + const(char)* func = __FUNCTION__.ptr, + const(char)* pfunc = __PRETTY_FUNCTION__.ptr, + const(char)* mod = __MODULE__.ptr) +{ + return Loc4(file, line, func, pfunc, mod); +} +void func4b(Loc4 loc = defaultLoc4) +{ + loc.file = baseName(loc.file); + printf("%s: %s:%d %s %s %s\n", __FUNCTION__.ptr, + loc.file, cast(int) loc.line, + loc.func, + loc.pfunc, + loc.mod); +} +enum Loc4Mixin = q{Loc4(__FILE__.ptr, __LINE__, + __FUNCTION__.ptr, __PRETTY_FUNCTION__.ptr, __MODULE__.ptr)}; +void func4c(Loc4 loc = mixin(Loc4Mixin)) +{ + loc.file = baseName(loc.file); + printf("%s: %s:%d %s %s %s\n", __FUNCTION__.ptr, + loc.file, cast(int) loc.line, + loc.func, + loc.pfunc, + loc.mod); +} +void func4d(Loc4* loc = new Loc4(__FILE__.ptr, __LINE__, + __FUNCTION__.ptr, __PRETTY_FUNCTION__.ptr, __MODULE__.ptr)) +{ + loc.file = baseName(loc.file); + printf("%s: %s:%d %s %s %s\n", __FUNCTION__.ptr, + loc.file, cast(int) loc.line, + loc.func, + loc.pfunc, + loc.mod); +} + +void func5(string file = baseName(__FILE__), int line = __LINE__, + string func = __FUNCTION__, + string pfunc = __PRETTY_FUNCTION__, + string mod = __MODULE__)() +{ + printf("%s: %.*s:%d %.*s %.*s %.*s\n", __FUNCTION__.ptr, + cast(int) file.length, file.ptr, line, + cast(int) func.length, func.ptr, + cast(int) pfunc.length, pfunc.ptr, + cast(int) mod.length, mod.ptr); +} + +void func6(string file = baseName(__FILE__), int line = __LINE__, + const(char)* func = __FUNCTION__.ptr, + const(char)* pfunc = __PRETTY_FUNCTION__.ptr, + const(char)* mod = __MODULE__.ptr)() +{ + printf("%s: %.*s:%d %s %s %s\n", __FUNCTION__.ptr, + cast(int) file.length, file.ptr, line, func, pfunc, mod); +} + +void func7(int expr1 = 1000 + __LINE__ * 2, + string expr2 = "file=" ~ baseName(__FILE__) ~ " func=" ~ __FUNCTION__, + int expr3 = __LINE__ > 5 ? 1 : 2) +{ + printf("%s: expr1=%d, %.*s, expr3=%d\n", __FUNCTION__.ptr, expr1, cast(int) expr2.length, expr2.ptr, expr3); +} + +immutable string[2] constants = ["constant1", "constant2"]; +void func8(int[] expr1 = [__LINE__, __LINE__ + 1000], + int[string] expr2 = [baseName(__FILE__): __LINE__], + string expr3 = constants[__LINE__ > 5], + string expr4 = __FILE__[0 .. __FILE__.length - 2]) +{ + expr4 = baseName(expr4); + printf("%s: expr1=[", __FUNCTION__.ptr); + foreach (i, x; expr1) + printf("%d, ", x); + printf("], expr2=["); + foreach (k, v; expr2) + printf("%.*s: %d, ", cast(int) k.length, k.ptr, v); + printf("], expr3=%.*s", cast(int) expr3.length, expr3.ptr); + printf(", expr4=%.*s\n", cast(int) expr4.length, expr4.ptr); +} + +void func9(void function(string file = __FILE__, size_t line = __LINE__, string mod = __MODULE__) + fp = (string file, size_t line, string mod) + { + file = baseName(file); + printf("imports.issue18919b.func9.fp: %.*s:%d %.*s\n", + cast(int) file.length, file.ptr, cast(int) line, + cast(int) mod.length, mod.ptr); + }) +{ + fp(); +} + +void func10(string expr1 = mixin(() { return "\"expr1=" ~ __MODULE__ ~ "\""; } ()), + string expr2 = mixin("\"expr2=" ~ __MODULE__ ~ "\"")) +{ + printf("%s: %.*s, %.*s\n", __FUNCTION__.ptr, + cast(int) expr1.length, expr1.ptr, + cast(int) expr2.length, expr2.ptr); +} + +template ctLoc3(string file, int line, + string func, string pfunc, string mod) +{ + enum Loc3 ctLoc3 = Loc3(file, line, func, pfunc, mod); +} + +void func11(Loc3 loc = ctLoc3!(baseName(__FILE__), __LINE__, + __FUNCTION__, __PRETTY_FUNCTION__, __MODULE__)) +{ + printf("%s: %.*s:%d %.*s %.*s %.*s\n", __FUNCTION__.ptr, + cast(int) loc.file.length, loc.file.ptr, cast(int) loc.line, + cast(int) loc.func.length, loc.func.ptr, + cast(int) loc.pfunc.length, loc.pfunc.ptr, + cast(int) loc.mod.length, loc.mod.ptr); +} + +void func12(const(char)*[] args = [baseName(__FILE__.ptr), + __FUNCTION__.ptr, __PRETTY_FUNCTION__.ptr, __MODULE__.ptr]) +{ + printf("%s:", __FUNCTION__.ptr); + foreach (arg; args) + printf(" %s", arg); + printf("\n"); +} diff --git a/gcc/testsuite/gdc.test/runnable/issue18919.d b/gcc/testsuite/gdc.test/runnable/issue18919.d new file mode 100644 index 0000000..815e018 --- /dev/null +++ b/gcc/testsuite/gdc.test/runnable/issue18919.d @@ -0,0 +1,47 @@ +/* +EXTRA_SOURCES: imports/issue18919b.d +RUN_OUTPUT: +--- +imports.issue18919b.func1: issue18919.d:29 issue18919.main void issue18919.main() issue18919 +imports.issue18919b.func2: issue18919.d:30 issue18919.main void issue18919.main() issue18919 +imports.issue18919b.func3: issue18919.d:31 issue18919.main void issue18919.main() issue18919 +imports.issue18919b.func3b: issue18919.d:32 issue18919.main void issue18919.main() issue18919 +imports.issue18919b.func3c: issue18919.d:33 issue18919.main void issue18919.main() issue18919 +imports.issue18919b.func3d: issue18919.d:34 issue18919.main void issue18919.main() issue18919 +imports.issue18919b.func4: issue18919.d:35 issue18919.main void issue18919.main() issue18919 +imports.issue18919b.func4b: issue18919.d:36 issue18919.main void issue18919.main() issue18919 +imports.issue18919b.func4c: issue18919.d:37 issue18919.main void issue18919.main() issue18919 +imports.issue18919b.func4d: issue18919.d:38 issue18919.main void issue18919.main() issue18919 +imports.issue18919b.func5!("issue18919.d", 39, "issue18919.main", "void issue18919.main()", "issue18919").func5: issue18919.d:39 issue18919.main void issue18919.main() issue18919 +imports.issue18919b.func6!("issue18919.d", 40, "issue18919.main", "void issue18919.main()", "issue18919").func6: issue18919.d:40 issue18919.main void issue18919.main() issue18919 +imports.issue18919b.func7: expr1=1082, file=issue18919.d func=issue18919.main, expr3=1 +imports.issue18919b.func8: expr1=[42, 1042, ], expr2=[issue18919.d: 42, ], expr3=constant2, expr4=issue18919 +imports.issue18919b.func9.fp: issue18919b.d:216 imports.issue18919b +imports.issue18919b.func10: expr1=imports.issue18919b, expr2=imports.issue18919b +imports.issue18919b.func11: issue18919b.d:233 imports.issue18919b +imports.issue18919b.func12: issue18919.d issue18919.main void issue18919.main() issue18919 +--- +*/ +import imports.issue18919b; + +void main() +{ + func1(); + func2(); + func3(); + func3b(); + func3c(); + func3d(); + func4(); + func4b(); + func4c(); + func4d(); + func5(); + func6(); + func7(); + func8(); + func9(); + func10(); + func11(); + func12(); +} diff --git a/gcc/testsuite/gdc.test/runnable/test18916.d b/gcc/testsuite/gdc.test/runnable/test18916.d index 0e844ad..f14f32c 100644 --- a/gcc/testsuite/gdc.test/runnable/test18916.d +++ b/gcc/testsuite/gdc.test/runnable/test18916.d @@ -11,9 +11,9 @@ struct Line void foo(Line line1 = __LINE__, int line2 = __LINE__, int line3 = int(__LINE__)) { - assert(line1 == 12); + assert(line1 == 21); assert(line2 == 21); - assert(line3 == 12); + assert(line3 == 21); } void main() diff --git a/gcc/testsuite/gdc.test/runnable/testptrref.d b/gcc/testsuite/gdc.test/runnable/testptrref.d index 7255595..af101b9 100644 --- a/gcc/testsuite/gdc.test/runnable/testptrref.d +++ b/gcc/testsuite/gdc.test/runnable/testptrref.d @@ -3,6 +3,7 @@ version(CRuntime_Microsoft) { extern(C) { + extern __gshared void* __ImageBase; extern __gshared uint _DP_beg; extern __gshared uint _DP_end; extern __gshared uint _TP_beg; @@ -18,8 +19,8 @@ version(CRuntime_Microsoft) { import core.internal.traits : externDFunc; alias findImageSection = externDFunc!("rt.sections_win64.findImageSection", - void[] function(string name) nothrow @nogc); - dataSection = findImageSection(".data"); + void[] function(void* handle, string name) nothrow @nogc); + dataSection = findImageSection(&__ImageBase, ".data"); } void[] tlsRange; diff --git a/gcc/testsuite/gdc.test/runnable/xtest46.d b/gcc/testsuite/gdc.test/runnable/xtest46.d index aeb2aab..cbcbd1a 100644 --- a/gcc/testsuite/gdc.test/runnable/xtest46.d +++ b/gcc/testsuite/gdc.test/runnable/xtest46.d @@ -179,7 +179,7 @@ void test7() void foo8(int n1 = __LINE__ + 0, int n2 = __LINE__, string s = __FILE__) { - assert(n1 < n2); + assert(n1 == n2); printf("n1 = %d, n2 = %d, s = %.*s\n", n1, n2, cast(int)s.length, s.ptr); } @@ -192,7 +192,7 @@ void test8() void foo9(int n1 = __LINE__ + 0, int n2 = __LINE__, string s = __FILE__)() { - assert(n1 < n2); + assert(n1 == n2); printf("n1 = %d, n2 = %d, s = %.*s\n", n1, n2, cast(int)s.length, s.ptr); } @@ -8032,6 +8032,29 @@ void test18232() } /***************************************************/ +// https://issues.dlang.org/show_bug.cgi?id=24332 + +void test24332() +{ + class A {} + final class B : A {} + + auto foo(A a) { + return cast(B) a; + } + + auto a = new A(); + auto n = cast(B) a; + assert(n is null); + auto b = cast(A) new B(); + auto c = cast(B) b; + assert(c); + B e; + auto d = cast(B) cast(A) e; + assert(d is null); +} + +/***************************************************/ int main() { @@ -8352,6 +8375,7 @@ int main() test17349(); test17915(); test18232(); + test24332(); printf("Success\n"); return 0; -- cgit v1.1 From 48148a0bb6c05b68b9c8f867f5c5ee9d8f4dd996 Mon Sep 17 00:00:00 2001 From: Andrew Pinski Date: Mon, 22 Jan 2024 16:27:49 -0800 Subject: Fix some of vect-avg-*.c testcases The vect-avg-*.c testcases are trying to make sure the AVG internal function are used and not doing promotion to `vector unsigned short` but when V4QI is implemented, `vector(2) unsigned short` shows up in the detail dump file and causes the failure. To fix this checking the optimized dump instead of the vect dump for `vector unsigned short` to make sure the vectorizer does not do the promotion. Built and tested for aarch64-linux-gnu. gcc/testsuite/ChangeLog: * gcc.dg/vect/vect-avg-1.c: Check optimized dump for `vector *signed short` instead of the `vect` dump. * gcc.dg/vect/vect-avg-11.c: Likewise. * gcc.dg/vect/vect-avg-12.c: Likewise. * gcc.dg/vect/vect-avg-13.c: Likewise. * gcc.dg/vect/vect-avg-14.c: Likewise. * gcc.dg/vect/vect-avg-2.c: Likewise. * gcc.dg/vect/vect-avg-3.c: Likewise. * gcc.dg/vect/vect-avg-4.c: Likewise. * gcc.dg/vect/vect-avg-5.c: Likewise. * gcc.dg/vect/vect-avg-6.c: Likewise. * gcc.dg/vect/vect-avg-7.c: Likewise. * gcc.dg/vect/vect-avg-8.c: Likewise. Signed-off-by: Andrew Pinski --- gcc/testsuite/gcc.dg/vect/vect-avg-1.c | 3 ++- gcc/testsuite/gcc.dg/vect/vect-avg-11.c | 3 ++- gcc/testsuite/gcc.dg/vect/vect-avg-12.c | 3 ++- gcc/testsuite/gcc.dg/vect/vect-avg-13.c | 3 ++- gcc/testsuite/gcc.dg/vect/vect-avg-14.c | 3 ++- gcc/testsuite/gcc.dg/vect/vect-avg-2.c | 3 ++- gcc/testsuite/gcc.dg/vect/vect-avg-3.c | 3 ++- gcc/testsuite/gcc.dg/vect/vect-avg-4.c | 3 ++- gcc/testsuite/gcc.dg/vect/vect-avg-5.c | 3 ++- gcc/testsuite/gcc.dg/vect/vect-avg-6.c | 3 ++- gcc/testsuite/gcc.dg/vect/vect-avg-7.c | 3 ++- gcc/testsuite/gcc.dg/vect/vect-avg-8.c | 3 ++- 12 files changed, 24 insertions(+), 12 deletions(-) (limited to 'gcc') diff --git a/gcc/testsuite/gcc.dg/vect/vect-avg-1.c b/gcc/testsuite/gcc.dg/vect/vect-avg-1.c index 4a752cd..0529037 100644 --- a/gcc/testsuite/gcc.dg/vect/vect-avg-1.c +++ b/gcc/testsuite/gcc.dg/vect/vect-avg-1.c @@ -1,4 +1,5 @@ /* { dg-require-effective-target vect_int } */ +/* { dg-additional-options "-fdump-tree-optimized" } */ #include "tree-vect.h" @@ -44,5 +45,5 @@ main (void) /* { dg-final { scan-tree-dump "vect_recog_average_pattern: detected" "vect" } } */ /* { dg-final { scan-tree-dump {\.AVG_FLOOR} "vect" { target vect_avg_qi } } } */ -/* { dg-final { scan-tree-dump-not {vector\([^\n]*short} "vect" { target vect_avg_qi } } } */ +/* { dg-final { scan-tree-dump-not {vector\([^\n]*short} "optimized" { target vect_avg_qi } } } */ /* { dg-final { scan-tree-dump-times "vectorized 1 loop" 1 "vect" { target vect_avg_qi } } } */ diff --git a/gcc/testsuite/gcc.dg/vect/vect-avg-11.c b/gcc/testsuite/gcc.dg/vect/vect-avg-11.c index 0046f8c..e91be11 100644 --- a/gcc/testsuite/gcc.dg/vect/vect-avg-11.c +++ b/gcc/testsuite/gcc.dg/vect/vect-avg-11.c @@ -1,4 +1,5 @@ /* { dg-require-effective-target vect_int } */ +/* { dg-additional-options "-fdump-tree-optimized" } */ #include "tree-vect.h" @@ -54,5 +55,5 @@ main (void) /* { dg-final { scan-tree-dump "vect_recog_average_pattern: detected" "vect" } } */ /* { dg-final { scan-tree-dump {\.AVG_FLOOR} "vect" { target vect_avg_qi } } } */ -/* { dg-final { scan-tree-dump-not {vector\([^\n]*short} "vect" { target vect_avg_qi } } } */ +/* { dg-final { scan-tree-dump-not {vector\([^\n]*short} "optimized" { target vect_avg_qi } } } */ /* { dg-final { scan-tree-dump-times "vectorized 1 loop" 1 "vect" { target vect_avg_qi } } } */ diff --git a/gcc/testsuite/gcc.dg/vect/vect-avg-12.c b/gcc/testsuite/gcc.dg/vect/vect-avg-12.c index f40331e..cc64c58 100644 --- a/gcc/testsuite/gcc.dg/vect/vect-avg-12.c +++ b/gcc/testsuite/gcc.dg/vect/vect-avg-12.c @@ -1,4 +1,5 @@ /* { dg-require-effective-target vect_int } */ +/* { dg-additional-options "-fdump-tree-optimized" } */ #define SIGNEDNESS signed @@ -6,5 +7,5 @@ /* { dg-final { scan-tree-dump "vect_recog_average_pattern: detected" "vect" } } */ /* { dg-final { scan-tree-dump {\.AVG_FLOOR} "vect" { target vect_avg_qi } } } */ -/* { dg-final { scan-tree-dump-not {vector\([^\n]*short} "vect" { target vect_avg_qi } } } */ +/* { dg-final { scan-tree-dump-not {vector\([^\n]*short} "optimized" { target vect_avg_qi } } } */ /* { dg-final { scan-tree-dump-times "vectorized 1 loop" 1 "vect" { target vect_avg_qi } } } */ diff --git a/gcc/testsuite/gcc.dg/vect/vect-avg-13.c b/gcc/testsuite/gcc.dg/vect/vect-avg-13.c index 7957c0e..ff55c01 100644 --- a/gcc/testsuite/gcc.dg/vect/vect-avg-13.c +++ b/gcc/testsuite/gcc.dg/vect/vect-avg-13.c @@ -1,4 +1,5 @@ /* { dg-require-effective-target vect_int } */ +/* { dg-additional-options "-fdump-tree-optimized" } */ #define SIGNEDNESS unsigned #define BIAS 1 @@ -7,5 +8,5 @@ /* { dg-final { scan-tree-dump "vect_recog_average_pattern: detected" "vect" } } */ /* { dg-final { scan-tree-dump {\.AVG_CEIL} "vect" { target vect_avg_qi } } } */ -/* { dg-final { scan-tree-dump-not {vector\([^\n]*short} "vect" { target vect_avg_qi } } } */ +/* { dg-final { scan-tree-dump-not {vector\([^\n]*short} "optimized" { target vect_avg_qi } } } */ /* { dg-final { scan-tree-dump-times "vectorized 1 loop" 1 "vect" { target vect_avg_qi } } } */ diff --git a/gcc/testsuite/gcc.dg/vect/vect-avg-14.c b/gcc/testsuite/gcc.dg/vect/vect-avg-14.c index 8ab11f7..4161a08 100644 --- a/gcc/testsuite/gcc.dg/vect/vect-avg-14.c +++ b/gcc/testsuite/gcc.dg/vect/vect-avg-14.c @@ -1,4 +1,5 @@ /* { dg-require-effective-target vect_int } */ +/* { dg-additional-options "-fdump-tree-optimized" } */ #define SIGNEDNESS signed #define BIAS 1 @@ -7,5 +8,5 @@ /* { dg-final { scan-tree-dump "vect_recog_average_pattern: detected" "vect" } } */ /* { dg-final { scan-tree-dump {\.AVG_CEIL} "vect" { target vect_avg_qi } } } */ -/* { dg-final { scan-tree-dump-not {vector\([^\n]*short} "vect" { target vect_avg_qi } } } */ +/* { dg-final { scan-tree-dump-not {vector\([^\n]*short} "optimized" { target vect_avg_qi } } } */ /* { dg-final { scan-tree-dump-times "vectorized 1 loop" 1 "vect" { target vect_avg_qi } } } */ diff --git a/gcc/testsuite/gcc.dg/vect/vect-avg-2.c b/gcc/testsuite/gcc.dg/vect/vect-avg-2.c index b5586b5..a58122c 100644 --- a/gcc/testsuite/gcc.dg/vect/vect-avg-2.c +++ b/gcc/testsuite/gcc.dg/vect/vect-avg-2.c @@ -1,4 +1,5 @@ /* { dg-require-effective-target vect_int } */ +/* { dg-additional-options "-fdump-tree-optimized" } */ #define SIGNEDNESS signed @@ -6,5 +7,5 @@ /* { dg-final { scan-tree-dump "vect_recog_average_pattern: detected" "vect" } } */ /* { dg-final { scan-tree-dump {\.AVG_FLOOR} "vect" { target vect_avg_qi } } } */ -/* { dg-final { scan-tree-dump-not {vector\([^\n]*short} "vect" { target vect_avg_qi } } } */ +/* { dg-final { scan-tree-dump-not {vector\([^\n]*short} "optimized" { target vect_avg_qi } } } */ /* { dg-final { scan-tree-dump-times "vectorized 1 loop" 1 "vect" { target vect_avg_qi } } } */ diff --git a/gcc/testsuite/gcc.dg/vect/vect-avg-3.c b/gcc/testsuite/gcc.dg/vect/vect-avg-3.c index 104fe96..1ae6894 100644 --- a/gcc/testsuite/gcc.dg/vect/vect-avg-3.c +++ b/gcc/testsuite/gcc.dg/vect/vect-avg-3.c @@ -1,4 +1,5 @@ /* { dg-require-effective-target vect_int } */ +/* { dg-additional-options "-fdump-tree-optimized" } */ #define SIGNEDNESS unsigned #define BIAS 1 @@ -7,5 +8,5 @@ /* { dg-final { scan-tree-dump "vect_recog_average_pattern: detected" "vect" } } */ /* { dg-final { scan-tree-dump {\.AVG_CEIL} "vect" { target vect_avg_qi } } } */ -/* { dg-final { scan-tree-dump-not {vector\([^\n]*short} "vect" { target vect_avg_qi } } } */ +/* { dg-final { scan-tree-dump-not {vector\([^\n]*short} "optimized" { target vect_avg_qi } } } */ /* { dg-final { scan-tree-dump-times "vectorized 1 loop" 1 "vect" { target vect_avg_qi } } } */ diff --git a/gcc/testsuite/gcc.dg/vect/vect-avg-4.c b/gcc/testsuite/gcc.dg/vect/vect-avg-4.c index 92181d7..87fb826 100644 --- a/gcc/testsuite/gcc.dg/vect/vect-avg-4.c +++ b/gcc/testsuite/gcc.dg/vect/vect-avg-4.c @@ -1,4 +1,5 @@ /* { dg-require-effective-target vect_int } */ +/* { dg-additional-options "-fdump-tree-optimized" } */ #define SIGNEDNESS signed #define BIAS 1 @@ -7,5 +8,5 @@ /* { dg-final { scan-tree-dump "vect_recog_average_pattern: detected" "vect" } } */ /* { dg-final { scan-tree-dump {\.AVG_CEIL} "vect" { target vect_avg_qi } } } */ -/* { dg-final { scan-tree-dump-not {vector\([^\n]*short} "vect" { target vect_avg_qi } } } */ +/* { dg-final { scan-tree-dump-not {vector\([^\n]*short} "optimized" { target vect_avg_qi } } } */ /* { dg-final { scan-tree-dump-times "vectorized 1 loop" 1 "vect" { target vect_avg_qi } } } */ diff --git a/gcc/testsuite/gcc.dg/vect/vect-avg-5.c b/gcc/testsuite/gcc.dg/vect/vect-avg-5.c index 6bdaeff..73dcb36 100644 --- a/gcc/testsuite/gcc.dg/vect/vect-avg-5.c +++ b/gcc/testsuite/gcc.dg/vect/vect-avg-5.c @@ -1,4 +1,5 @@ /* { dg-require-effective-target vect_int } */ +/* { dg-additional-options "-fdump-tree-optimized" } */ #include "tree-vect.h" @@ -48,5 +49,5 @@ main (void) /* { dg-final { scan-tree-dump "vect_recog_average_pattern: detected" "vect" } } */ /* { dg-final { scan-tree-dump {\.AVG_FLOOR} "vect" { target vect_avg_qi } } } */ -/* { dg-final { scan-tree-dump-not {vector\([^\n]*short} "vect" { target vect_avg_qi } } } */ +/* { dg-final { scan-tree-dump-not {vector\([^\n]*short} "optimized" { target vect_avg_qi } } } */ /* { dg-final { scan-tree-dump-times "vectorized 1 loop" 1 "vect" { target vect_avg_qi } } } */ diff --git a/gcc/testsuite/gcc.dg/vect/vect-avg-6.c b/gcc/testsuite/gcc.dg/vect/vect-avg-6.c index efe97b8..2cf48a4 100644 --- a/gcc/testsuite/gcc.dg/vect/vect-avg-6.c +++ b/gcc/testsuite/gcc.dg/vect/vect-avg-6.c @@ -1,4 +1,5 @@ /* { dg-require-effective-target vect_int } */ +/* { dg-additional-options "-fdump-tree-optimized" } */ #define SIGNEDNESS signed @@ -6,5 +7,5 @@ /* { dg-final { scan-tree-dump "vect_recog_average_pattern: detected" "vect" } } */ /* { dg-final { scan-tree-dump {\.AVG_FLOOR} "vect" { target vect_avg_qi } } } */ -/* { dg-final { scan-tree-dump-not {vector\([^\n]*short} "vect" { target vect_avg_qi } } } */ +/* { dg-final { scan-tree-dump-not {vector\([^\n]*short} "optimized" { target vect_avg_qi } } } */ /* { dg-final { scan-tree-dump-times "vectorized 1 loop" 1 "vect" { target vect_avg_qi } } } */ diff --git a/gcc/testsuite/gcc.dg/vect/vect-avg-7.c b/gcc/testsuite/gcc.dg/vect/vect-avg-7.c index 62a8474..365ce7a 100644 --- a/gcc/testsuite/gcc.dg/vect/vect-avg-7.c +++ b/gcc/testsuite/gcc.dg/vect/vect-avg-7.c @@ -1,4 +1,5 @@ /* { dg-require-effective-target vect_int } */ +/* { dg-additional-options "-fdump-tree-optimized" } */ #define SIGNEDNESS unsigned #define BIAS 1 @@ -7,5 +8,5 @@ /* { dg-final { scan-tree-dump "vect_recog_average_pattern: detected" "vect" } } */ /* { dg-final { scan-tree-dump {\.AVG_CEIL} "vect" { target vect_avg_qi } } } */ -/* { dg-final { scan-tree-dump-not {vector\([^\n]*short} "vect" { target vect_avg_qi } } } */ +/* { dg-final { scan-tree-dump-not {vector\([^\n]*short} "optimized" { target vect_avg_qi } } } */ /* { dg-final { scan-tree-dump-times "vectorized 1 loop" 1 "vect" { target vect_avg_qi } } } */ diff --git a/gcc/testsuite/gcc.dg/vect/vect-avg-8.c b/gcc/testsuite/gcc.dg/vect/vect-avg-8.c index cc7c4cd..b8e4c04 100644 --- a/gcc/testsuite/gcc.dg/vect/vect-avg-8.c +++ b/gcc/testsuite/gcc.dg/vect/vect-avg-8.c @@ -1,4 +1,5 @@ /* { dg-require-effective-target vect_int } */ +/* { dg-additional-options "-fdump-tree-optimized" } */ #define SIGNEDNESS signed #define BIAS 1 @@ -7,5 +8,5 @@ /* { dg-final { scan-tree-dump "vect_recog_average_pattern: detected" "vect" } } */ /* { dg-final { scan-tree-dump {\.AVG_CEIL} "vect" { target vect_avg_qi } } } */ -/* { dg-final { scan-tree-dump-not {vector\([^\n]*short} "vect" { target vect_avg_qi } } } */ +/* { dg-final { scan-tree-dump-not {vector\([^\n]*short} "optimized" { target vect_avg_qi } } } */ /* { dg-final { scan-tree-dump-times "vectorized 1 loop" 1 "vect" { target vect_avg_qi } } } */ -- cgit v1.1 From 85094e2aa6dba7908f053046f02dd443e8f65d72 Mon Sep 17 00:00:00 2001 From: Tamar Christina Date: Fri, 2 Feb 2024 23:52:27 +0000 Subject: middle-end: check memory accesses in the destination block [PR113588]. When analyzing loads for early break it was always the intention that for the exit where things get moved to we only check the loads that can be reached from the condition. However the main loop checks all loads and we skip the destination BB. As such we never actually check the loads reachable from the COND in the last BB unless this BB was also the exit chosen by the vectorizer. This leads us to incorrectly vectorize the loop in the PR and in doing so access out of bounds. gcc/ChangeLog: PR tree-optimization/113588 PR tree-optimization/113467 * tree-vect-data-refs.cc (vect_analyze_data_ref_dependence): Choose correct dest and fix checks. (vect_analyze_early_break_dependences): Update comments. gcc/testsuite/ChangeLog: PR tree-optimization/113588 PR tree-optimization/113467 * gcc.dg/vect/vect-early-break_108-pr113588.c: New test. * gcc.dg/vect/vect-early-break_109-pr113588.c: New test. --- .../gcc.dg/vect/vect-early-break_108-pr113588.c | 15 ++++ .../gcc.dg/vect/vect-early-break_109-pr113588.c | 44 +++++++++++ gcc/tree-vect-data-refs.cc | 92 +++++++++++----------- 3 files changed, 104 insertions(+), 47 deletions(-) create mode 100644 gcc/testsuite/gcc.dg/vect/vect-early-break_108-pr113588.c create mode 100644 gcc/testsuite/gcc.dg/vect/vect-early-break_109-pr113588.c (limited to 'gcc') diff --git a/gcc/testsuite/gcc.dg/vect/vect-early-break_108-pr113588.c b/gcc/testsuite/gcc.dg/vect/vect-early-break_108-pr113588.c new file mode 100644 index 0000000..e488619 --- /dev/null +++ b/gcc/testsuite/gcc.dg/vect/vect-early-break_108-pr113588.c @@ -0,0 +1,15 @@ +/* { dg-do compile } */ +/* { dg-add-options vect_early_break } */ +/* { dg-require-effective-target vect_early_break } */ +/* { dg-require-effective-target vect_int } */ + +/* { dg-final { scan-tree-dump-not "LOOP VECTORIZED" "vect" } } */ + +int foo (const char *s, unsigned long n) +{ + unsigned long len = 0; + while (*s++ && n--) + ++len; + return len; +} + diff --git a/gcc/testsuite/gcc.dg/vect/vect-early-break_109-pr113588.c b/gcc/testsuite/gcc.dg/vect/vect-early-break_109-pr113588.c new file mode 100644 index 0000000..488c19d --- /dev/null +++ b/gcc/testsuite/gcc.dg/vect/vect-early-break_109-pr113588.c @@ -0,0 +1,44 @@ +/* { dg-add-options vect_early_break } */ +/* { dg-require-effective-target vect_early_break } */ +/* { dg-require-effective-target vect_int } */ +/* { dg-require-effective-target mmap } */ + +/* { dg-final { scan-tree-dump-not "LOOP VECTORIZED" "vect" } } */ + +#include +#include + +#include "tree-vect.h" + +__attribute__((noipa)) +int foo (const char *s, unsigned long n) +{ + unsigned long len = 0; + while (*s++ && n--) + ++len; + return len; +} + +int main() +{ + + check_vect (); + + long pgsz = sysconf (_SC_PAGESIZE); + void *p = mmap (NULL, pgsz * 3, PROT_READ|PROT_WRITE, + MAP_ANONYMOUS|MAP_PRIVATE, 0, 0); + if (p == MAP_FAILED) + return 0; + mprotect (p, pgsz, PROT_NONE); + mprotect (p+2*pgsz, pgsz, PROT_NONE); + char *p1 = p + pgsz; + p1[0] = 1; + p1[1] = 0; + foo (p1, 1000); + p1 = p + 2*pgsz - 2; + p1[0] = 1; + p1[1] = 0; + foo (p1, 1000); + return 0; +} + diff --git a/gcc/tree-vect-data-refs.cc b/gcc/tree-vect-data-refs.cc index e6a3035..2ca5a1b 100644 --- a/gcc/tree-vect-data-refs.cc +++ b/gcc/tree-vect-data-refs.cc @@ -619,10 +619,10 @@ vect_analyze_data_ref_dependence (struct data_dependence_relation *ddr, return opt_result::success (); } -/* Funcion vect_analyze_early_break_dependences. +/* Function vect_analyze_early_break_dependences. - Examime all the data references in the loop and make sure that if we have - mulitple exits that we are able to safely move stores such that they become + Examine all the data references in the loop and make sure that if we have + multiple exits that we are able to safely move stores such that they become safe for vectorization. The function also calculates the place where to move the instructions to and computes what the new vUSE chain should be. @@ -639,7 +639,7 @@ vect_analyze_data_ref_dependence (struct data_dependence_relation *ddr, - Multiple loads are allowed as long as they don't alias. NOTE: - This implemementation is very conservative. Any overlappig loads/stores + This implementation is very conservative. Any overlapping loads/stores that take place before the early break statement gets rejected aside from WAR dependencies. @@ -668,7 +668,6 @@ vect_analyze_early_break_dependences (loop_vec_info loop_vinfo) auto_vec bases; basic_block dest_bb = NULL; - hash_set visited; class loop *loop = LOOP_VINFO_LOOP (loop_vinfo); class loop *loop_nest = loop_outer (loop); @@ -677,19 +676,33 @@ vect_analyze_early_break_dependences (loop_vec_info loop_vinfo) "loop contains multiple exits, analyzing" " statement dependencies.\n"); + if (LOOP_VINFO_EARLY_BREAKS_VECT_PEELED (loop_vinfo)) + if (dump_enabled_p ()) + dump_printf_loc (MSG_NOTE, vect_location, + "alternate exit has been chosen as main exit.\n"); + /* Since we don't support general control flow, the location we'll move the side-effects to is always the latch connected exit. When we support - general control flow we can do better but for now this is fine. */ - dest_bb = single_pred (loop->latch); + general control flow we can do better but for now this is fine. Move + side-effects to the in-loop destination of the last early exit. For the PEELED + case we move the side-effects to the latch block as this is guaranteed to be the + last block to be executed when a vector iteration finished. */ + if (LOOP_VINFO_EARLY_BREAKS_VECT_PEELED (loop_vinfo)) + dest_bb = loop->latch; + else + dest_bb = single_pred (loop->latch); + + /* We start looking from dest_bb, for the non-PEELED case we don't want to + move any stores already present, but we do want to read and validate the + loads. */ basic_block bb = dest_bb; + /* In the peeled case we need to check all the loads in the loop since to move the + the stores we lift the stores over all loads into the latch. */ + bool check_deps = LOOP_VINFO_EARLY_BREAKS_VECT_PEELED (loop_vinfo); + do { - /* If the destination block is also the header then we have nothing to do. */ - if (!single_pred_p (bb)) - continue; - - bb = single_pred (bb); gimple_stmt_iterator gsi = gsi_last_bb (bb); /* Now analyze all the remaining statements and try to determine which @@ -707,42 +720,13 @@ vect_analyze_early_break_dependences (loop_vec_info loop_vinfo) if (!dr_ref) continue; - /* We currently only support statically allocated objects due to - not having first-faulting loads support or peeling for - alignment support. Compute the size of the referenced object - (it could be dynamically allocated). */ - tree obj = DR_BASE_ADDRESS (dr_ref); - if (!obj || TREE_CODE (obj) != ADDR_EXPR) - { - if (dump_enabled_p ()) - dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location, - "early breaks only supported on statically" - " allocated objects.\n"); - return opt_result::failure_at (stmt, - "can't safely apply code motion to " - "dependencies of %G to vectorize " - "the early exit.\n", stmt); - } - - tree refop = TREE_OPERAND (obj, 0); - tree refbase = get_base_address (refop); - if (!refbase || !DECL_P (refbase) || !DECL_SIZE (refbase) - || TREE_CODE (DECL_SIZE (refbase)) != INTEGER_CST) - { - if (dump_enabled_p ()) - dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location, - "early breaks only supported on" - " statically allocated objects.\n"); - return opt_result::failure_at (stmt, - "can't safely apply code motion to " - "dependencies of %G to vectorize " - "the early exit.\n", stmt); - } - /* Check if vector accesses to the object will be within bounds. must be a constant or assume loop will be versioned or niters - bounded by VF so accesses are within range. */ - if (!ref_within_array_bound (stmt, DR_REF (dr_ref))) + bounded by VF so accesses are within range. We only need to check the + reads since writes are moved to a safe place where if we get there we + know they are safe to perform. */ + if (DR_IS_READ (dr_ref) + && !ref_within_array_bound (stmt, DR_REF (dr_ref))) { if (dump_enabled_p ()) dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location, @@ -755,6 +739,9 @@ vect_analyze_early_break_dependences (loop_vec_info loop_vinfo) "the early exit.\n", stmt); } + if (!check_deps) + continue; + if (DR_IS_READ (dr_ref)) bases.safe_push (dr_ref); else if (DR_IS_WRITE (dr_ref)) @@ -814,8 +801,19 @@ vect_analyze_early_break_dependences (loop_vec_info loop_vinfo) "marked statement for vUSE update: %G", stmt); } } + + if (!single_pred_p (bb)) + { + gcc_assert (bb == loop->header); + break; + } + + /* For the non-PEELED case we don't want to check the loads in the IV exit block + for dependencies with the stores, but any block preceeding it we do. */ + check_deps = true; + bb = single_pred (bb); } - while (bb != loop->header); + while (1); /* We don't allow outer -> inner loop transitions which should have been trapped already during loop form analysis. */ -- cgit v1.1 From 64b0130bb6702c67a13caefaae9facef23d6ac60 Mon Sep 17 00:00:00 2001 From: Gaius Mulley Date: Sat, 3 Feb 2024 00:03:39 +0000 Subject: PR modula2/113730 Unexpected handling of mixed-precision integer arithmetic This patch fixes a bug which occurs when an expression is created with a ZType and an integer or cardinal. The resulting subexpression is incorrecly given a ZType which allows compatibility with another integer/cardinal type. The solution was to fix the subexpression type. In turn this required a minor change to SArgs.mod. gcc/m2/ChangeLog: PR modula2/113730 * gm2-compiler/M2Base.mod (IsUserType): New procedure function. (MixTypes): Use IsUserType instead of IsType before calling MixTypes. * gm2-compiler/M2GenGCC.mod (GetTypeMode): Remove and import from SymbolTable. (CodeBinaryCheck): Replace call to MixTypes with MixTypesBinary. (CodeBinary): Replace call to MixTypes with MixTypesBinary. (CodeIfLess): Replace MixTypes with ComparisonMixTypes. (CodeIfGre): Replace MixTypes with ComparisonMixTypes. (CodeIfLessEqu): Replace MixTypes with ComparisonMixTypes. (CodeIfGreEqu): Replace MixTypes with ComparisonMixTypes. (CodeIfEqu): Replace MixTypes with ComparisonMixTypes. (CodeIfNotEqu): Replace MixTypes with ComparisonMixTypes. (ComparisonMixTypes): New procedure function. * gm2-compiler/M2Quads.mod (BuildEndFor): Replace GenQuadO with GenQuadOtok and pass tokenpos for the operands to the AddOp and XIndrOp. (CheckRangeIncDec): Check etype against NulSym and dtype for a pointer and set etype to Address. (BuildAddAdrFunction): New variable opa. Convert operand to an address and save result in opa. Replace GenQuad with GenQuadOtok. (BuildSubAdrFunction): New variable opa. Convert operand to an address and save result in opa. Replace GenQuad with GenQuadOtok. (BuildDiffAdrFunction): New variable opa. Convert operand to an address and save result in opa. Replace GenQuad with GenQuadOtok. (calculateMultipicand): Replace GenQuadO with GenQuadOtok. (ConvertToAddress): New procedure function. (BuildDynamicArray): Convert index to address before adding to the base. * gm2-compiler/SymbolTable.def (GetTypeMode): New procedure function. * gm2-compiler/SymbolTable.mod (GetTypeMode): New procedure function implemented (moved from M2GenGCC.mod). * gm2-libs/SArgs.mod (GetArg): Replace cast to PtrToChar with ADDRESS. gcc/testsuite/ChangeLog: PR modula2/113730 * gm2/extensions/fail/arith1.mod: New test. * gm2/extensions/fail/arith2.mod: New test. * gm2/extensions/fail/arith3.mod: New test. * gm2/extensions/fail/arith4.mod: New test. * gm2/extensions/fail/arithpromote.mod: New test. * gm2/extensions/fail/extensions-fail.exp: New test. * gm2/linking/fail/badimp.def: New test. * gm2/linking/fail/badimp.mod: New test. * gm2/linking/fail/linking-fail.exp: New test. * gm2/linking/fail/testbadimp.mod: New test. Signed-off-by: Gaius Mulley --- gcc/m2/gm2-compiler/M2Base.mod | 19 ++++- gcc/m2/gm2-compiler/M2GenGCC.mod | 92 +++++++++++++--------- gcc/m2/gm2-compiler/M2Quads.mod | 72 ++++++++++++++--- gcc/m2/gm2-compiler/SymbolTable.def | 10 ++- gcc/m2/gm2-compiler/SymbolTable.mod | 30 +++++++ gcc/m2/gm2-libs/SArgs.mod | 4 +- gcc/testsuite/gm2/extensions/fail/arith1.mod | 36 +++++++++ gcc/testsuite/gm2/extensions/fail/arith2.mod | 36 +++++++++ gcc/testsuite/gm2/extensions/fail/arith3.mod | 36 +++++++++ gcc/testsuite/gm2/extensions/fail/arith4.mod | 36 +++++++++ gcc/testsuite/gm2/extensions/fail/arithpromote.mod | 55 +++++++++++++ .../gm2/extensions/fail/extensions-fail.exp | 36 +++++++++ gcc/testsuite/gm2/linking/fail/badimp.def | 4 + gcc/testsuite/gm2/linking/fail/badimp.mod | 8 ++ gcc/testsuite/gm2/linking/fail/linking-fail.exp | 38 +++++++++ gcc/testsuite/gm2/linking/fail/testbadimp.mod | 6 ++ 16 files changed, 463 insertions(+), 55 deletions(-) create mode 100644 gcc/testsuite/gm2/extensions/fail/arith1.mod create mode 100644 gcc/testsuite/gm2/extensions/fail/arith2.mod create mode 100644 gcc/testsuite/gm2/extensions/fail/arith3.mod create mode 100644 gcc/testsuite/gm2/extensions/fail/arith4.mod create mode 100644 gcc/testsuite/gm2/extensions/fail/arithpromote.mod create mode 100644 gcc/testsuite/gm2/extensions/fail/extensions-fail.exp create mode 100644 gcc/testsuite/gm2/linking/fail/badimp.def create mode 100644 gcc/testsuite/gm2/linking/fail/badimp.mod create mode 100644 gcc/testsuite/gm2/linking/fail/linking-fail.exp create mode 100644 gcc/testsuite/gm2/linking/fail/testbadimp.mod (limited to 'gcc') diff --git a/gcc/m2/gm2-compiler/M2Base.mod b/gcc/m2/gm2-compiler/M2Base.mod index 04a0e4e..b867769 100644 --- a/gcc/m2/gm2-compiler/M2Base.mod +++ b/gcc/m2/gm2-compiler/M2Base.mod @@ -85,7 +85,8 @@ FROM M2Size IMPORT Size, MakeSize ; FROM M2System IMPORT Address, Byte, Word, System, Loc, InitSystem, IntegerN, CardinalN, WordN, SetN, RealN, ComplexN, IsCardinalN, IsIntegerN, IsRealN, IsComplexN, - IsGenericSystemType, IsSameSizePervasiveType ; + IsGenericSystemType, IsSameSizePervasiveType, + IsSystemType ; FROM M2Options IMPORT NilChecking, WholeDivChecking, WholeValueChecking, @@ -1990,7 +1991,7 @@ BEGIN mt2 := FindMetaType(t2) ; CASE Expr[mt1, mt2] OF - no : MetaErrorT2 (NearTok, 'type incompatibility between {%1as} and {%2as}', t1, t2) ; + no : MetaErrorT2 (NearTok, 'type incompatibility between {%1asd} and {%2asd}', t1, t2) ; FlushErrors (* unrecoverable at present *) | warnfirst, first : RETURN( t1 ) | @@ -2005,6 +2006,16 @@ END MixMetaTypes ; (* + IsUserType - return TRUE if type was created by the user as a synonym. +*) + +PROCEDURE IsUserType (type: CARDINAL) : BOOLEAN ; +BEGIN + RETURN IsType (type) AND (NOT IsBaseType (type)) AND (NOT IsSystemType (type)) +END IsUserType ; + + +(* MixTypes - given types, t1 and t2, returns a type symbol that provides expression type compatibility. NearTok is used to identify the source position if a type @@ -2074,10 +2085,10 @@ BEGIN ELSE RETURN( CType ) END - ELSIF IsType(t1) + ELSIF IsUserType (t1) THEN RETURN( MixTypes(GetType(t1), t2, NearTok) ) - ELSIF IsType(t2) + ELSIF IsUserType (t2) THEN RETURN( MixTypes(t1, GetType(t2), NearTok) ) ELSIF (t1=GetLowestType(t1)) AND (t2=GetLowestType(t2)) diff --git a/gcc/m2/gm2-compiler/M2GenGCC.mod b/gcc/m2/gm2-compiler/M2GenGCC.mod index 92ca39f..25bfbf8 100644 --- a/gcc/m2/gm2-compiler/M2GenGCC.mod +++ b/gcc/m2/gm2-compiler/M2GenGCC.mod @@ -76,7 +76,7 @@ FROM SymbolTable IMPORT PushSize, PopSize, PushValue, PopValue, GetPriority, GetNeedSavePriority, PutConstString, PutConst, PutConstSet, PutConstructor, - GetSType, + GetSType, GetTypeMode, HasVarParameters, NulSym ; @@ -2944,21 +2944,6 @@ END DefaultConvertGM2 ; (* - GetTypeMode - -*) - -PROCEDURE GetTypeMode (sym: CARDINAL) : CARDINAL ; -BEGIN - IF GetMode(sym)=LeftValue - THEN - RETURN( Address ) - ELSE - RETURN( GetType(sym) ) - END -END GetTypeMode ; - - -(* FoldConstBecomes - returns a Tree containing op3. The tree will have been folded and type converted if necessary. @@ -3523,7 +3508,7 @@ BEGIN DeclareConstant (op2pos, op2) ; location := TokenToLocation (op1pos) ; - type := MixTypes (FindType (op2), FindType (op3), op3pos) ; + type := MixTypesBinary (op2, op3, op1pos, MustCheckOverflow (quad)) ; ConvertBinaryOperands (location, tl, tr, type, op2, op3) ; lowestType := GetLType (op1) ; @@ -3554,6 +3539,23 @@ END CodeBinaryCheck ; (* + MixTypesBinary - depending upon check do not check pointer arithmetic. +*) + +PROCEDURE MixTypesBinary (left, right: CARDINAL; + tokpos: CARDINAL; check: BOOLEAN) : CARDINAL ; +BEGIN + IF (NOT check) AND + (IsPointer (GetTypeMode (left)) OR IsPointer (GetTypeMode (right))) + THEN + RETURN Address + ELSE + RETURN MixTypes (FindType (left), FindType (right), tokpos) + END +END MixTypesBinary ; + + +(* CodeBinary - encode a binary arithmetic operation. *) @@ -3576,7 +3578,7 @@ BEGIN DeclareConstant (op2pos, op2) ; location := TokenToLocation (op1pos) ; - type := MixTypes (FindType (op2), FindType (op3), op1pos) ; + type := MixTypesBinary (op2, op3, op1pos, MustCheckOverflow (quad)) ; ConvertBinaryOperands (location, tl, tr, type, op2, op3) ; tv := binop (location, tl, tr, FALSE) ; @@ -6742,9 +6744,9 @@ BEGIN ELSE ConvertBinaryOperands(location, tl, tr, - MixTypes(SkipType(GetType(op1)), - SkipType(GetType(op2)), - CurrentQuadToken), + ComparisonMixTypes (SkipType (GetType (op1)), + SkipType (GetType (op2)), + CurrentQuadToken), op1, op2) ; DoJump(location, BuildLessThan(location, tl, tr), NIL, string(CreateLabelName(op3))) @@ -6839,9 +6841,9 @@ BEGIN ELSE ConvertBinaryOperands(location, tl, tr, - MixTypes(SkipType(GetType(op1)), - SkipType(GetType(op2)), - CurrentQuadToken), + ComparisonMixTypes (SkipType (GetType (op1)), + SkipType (GetType (op2)), + CurrentQuadToken), op1, op2) ; DoJump(location, BuildGreaterThan(location, tl, tr), NIL, string(CreateLabelName(op3))) END @@ -6935,9 +6937,9 @@ BEGIN ELSE ConvertBinaryOperands(location, tl, tr, - MixTypes(SkipType(GetType(op1)), - SkipType(GetType(op2)), - CurrentQuadToken), + ComparisonMixTypes (SkipType (GetType (op1)), + SkipType (GetType (op2)), + CurrentQuadToken), op1, op2) ; DoJump(location, BuildLessThanOrEqual(location, tl, tr), NIL, string(CreateLabelName(op3))) END @@ -7031,9 +7033,9 @@ BEGIN ELSE ConvertBinaryOperands(location, tl, tr, - MixTypes(SkipType(GetType(op1)), - SkipType(GetType(op2)), - CurrentQuadToken), + ComparisonMixTypes (SkipType (GetType (op1)), + SkipType (GetType (op2)), + CurrentQuadToken), op1, op2) ; DoJump(location, BuildGreaterThanOrEqual(location, tl, tr), NIL, string(CreateLabelName(op3))) END @@ -7147,6 +7149,24 @@ END CodeIfSetNotEqu ; (* + ComparisonMixTypes - +*) + +PROCEDURE ComparisonMixTypes (left, right: CARDINAL; tokpos: CARDINAL) : CARDINAL ; +BEGIN + IF IsGenericSystemType (left) + THEN + RETURN left + ELSIF IsGenericSystemType (right) + THEN + RETURN right + ELSE + RETURN MixTypes (left, right, tokpos) + END +END ComparisonMixTypes ; + + +(* CodeIfEqu - codes the quadruple if op1 = op2 then goto op3 *) @@ -7185,9 +7205,9 @@ BEGIN ELSE ConvertBinaryOperands(location, tl, tr, - MixTypes(SkipType(GetType(op1)), - SkipType(GetType(op2)), - CurrentQuadToken), + ComparisonMixTypes (SkipType (GetType (op1)), + SkipType (GetType (op2)), + CurrentQuadToken), op1, op2) ; DoJump(location, BuildEqualTo(location, tl, tr), NIL, string(CreateLabelName(op3))) END @@ -7234,9 +7254,9 @@ BEGIN ELSE ConvertBinaryOperands(location, tl, tr, - MixTypes(SkipType(GetType(op1)), - SkipType(GetType(op2)), - CurrentQuadToken), + ComparisonMixTypes (SkipType (GetType (op1)), + SkipType (GetType (op2)), + CurrentQuadToken), op1, op2) ; DoJump(location, BuildNotEqualTo(location, tl, tr), NIL, string(CreateLabelName(op3))) diff --git a/gcc/m2/gm2-compiler/M2Quads.mod b/gcc/m2/gm2-compiler/M2Quads.mod index a666a4e..a23fa32 100644 --- a/gcc/m2/gm2-compiler/M2Quads.mod +++ b/gcc/m2/gm2-compiler/M2Quads.mod @@ -132,6 +132,7 @@ FROM SymbolTable IMPORT ModeOfAddr, GetMode, PutMode, GetSymName, IsUnknown, ForeachFieldEnumerationDo, ForeachLocalSymDo, GetExported, PutImported, GetSym, GetLibName, + GetTypeMode, IsUnused, NulSym ; @@ -266,7 +267,7 @@ IMPORT M2Error ; CONST DebugStackOn = TRUE ; DebugVarients = FALSE ; - BreakAtQuad = 53 ; + BreakAtQuad = 189 ; DebugTokPos = FALSE ; TYPE @@ -4628,9 +4629,11 @@ BEGIN is counting down. The above test will generate a more precise error message, so we suppress overflow detection here. *) - GenQuadO (bytok, AddOp, tsym, tsym, BySym, FALSE) ; + GenQuadOtok (bytok, AddOp, tsym, tsym, BySym, FALSE, + bytok, bytok, bytok) ; CheckPointerThroughNil (idtok, IdSym) ; - GenQuadO (idtok, XIndrOp, IdSym, GetSType (IdSym), tsym, FALSE) + GenQuadOtok (idtok, XIndrOp, IdSym, GetSType (IdSym), tsym, FALSE, + idtok, idtok, idtok) ELSE BuildRange (InitForLoopEndRangeCheck (IdSym, BySym)) ; IncQuad := NextQuad ; @@ -4639,7 +4642,8 @@ BEGIN is counting down. The above test will generate a more precise error message, so we suppress overflow detection here. *) - GenQuadO (idtok, AddOp, IdSym, IdSym, BySym, FALSE) + GenQuadOtok (idtok, AddOp, IdSym, IdSym, BySym, FALSE, + bytok, bytok, bytok) END ; GenQuadO (endpostok, GotoOp, NulSym, NulSym, ForQuad, FALSE) ; BackPatch (PopFor (), NextQuad) ; @@ -7104,6 +7108,11 @@ VAR BEGIN dtype := GetDType(des) ; etype := GetDType(expr) ; + IF (etype = NulSym) AND IsPointer (GetTypeMode (des)) + THEN + expr := ConvertToAddress (tokenpos, expr) ; + etype := Address + END ; IF WholeValueChecking AND (NOT MustNotCheckBounds) THEN IF tok=PlusTok @@ -7966,6 +7975,7 @@ VAR combinedtok, functok, optok : CARDINAL ; + opa, ReturnVar, NoOfParam, OperandSym, @@ -7986,7 +7996,9 @@ BEGIN THEN ReturnVar := MakeTemporary (combinedtok, RightValue) ; PutVar (ReturnVar, Address) ; - GenQuad (AddOp, ReturnVar, VarSym, DereferenceLValue (optok, OperandSym)) ; + opa := ConvertToAddress (optok, DereferenceLValue (optok, OperandSym)) ; + GenQuadOtok (combinedtok, AddOp, ReturnVar, VarSym, opa, TRUE, + combinedtok, combinedtok, combinedtok) ; PushTFtok (ReturnVar, Address, combinedtok) ELSE MetaErrorT1 (functok, @@ -8041,6 +8053,7 @@ VAR ReturnVar, NoOfParam, OperandSym, + opa, VarSym : CARDINAL ; BEGIN PopT (NoOfParam) ; @@ -8059,7 +8072,9 @@ BEGIN THEN ReturnVar := MakeTemporary (combinedtok, RightValue) ; PutVar (ReturnVar, Address) ; - GenQuad (SubOp, ReturnVar, VarSym, DereferenceLValue (optok, OperandSym)) ; + opa := ConvertToAddress (optok, DereferenceLValue (optok, OperandSym)) ; + GenQuadOtok (combinedtok, SubOp, ReturnVar, VarSym, opa, TRUE, + combinedtok, combinedtok, combinedtok) ; PushTFtok (ReturnVar, Address, combinedtok) ELSE MetaErrorT1 (functok, @@ -8119,6 +8134,7 @@ VAR TempVar, NoOfParam, OperandSym, + opa, VarSym : CARDINAL ; BEGIN PopT (NoOfParam) ; @@ -8139,7 +8155,9 @@ BEGIN THEN TempVar := MakeTemporary (vartok, RightValue) ; PutVar (TempVar, Address) ; - GenQuad (SubOp, TempVar, VarSym, DereferenceLValue (optok, OperandSym)) ; + opa := ConvertToAddress (optok, DereferenceLValue (optok, OperandSym)) ; + GenQuadOtok (combinedtok, SubOp, TempVar, VarSym, opa, TRUE, + combinedtok, combinedtok, combinedtok) ; (* Build macro: CONVERT( INTEGER, TempVar ) *) @@ -10281,10 +10299,12 @@ BEGIN IF IsAModula2Type (OperandT (1)) THEN ReturnVar := MakeTemporary (resulttok, ImmediateValue) ; + PutVar (ReturnVar, Cardinal) ; GenQuadO (resulttok, SizeOp, ReturnVar, NulSym, OperandT (1), FALSE) ELSIF IsVar (OperandT (1)) THEN ReturnVar := MakeTemporary (resulttok, ImmediateValue) ; + PutVar (ReturnVar, Cardinal) ; GenQuadO (resulttok, SizeOp, ReturnVar, NulSym, GetSType (OperandT (1)), FALSE) ELSE MetaErrorT1 (resulttok, @@ -10307,6 +10327,7 @@ BEGIN paramtok := OperandTtok (1) ; resulttok := MakeVirtualTok (functok, functok, paramtok) ; ReturnVar := MakeTemporary (resulttok, ImmediateValue) ; + PutVar (ReturnVar, Cardinal) ; GenQuadO (resulttok, SizeOp, ReturnVar, NulSym, Record, FALSE) ELSE resulttok := MakeVirtualTok (functok, functok, paramtok) ; @@ -11212,7 +11233,8 @@ BEGIN GenHigh (tok, tk, dim, arraySym) ; tl := MakeTemporary (tok, RightValue) ; PutVar (tl, Cardinal) ; - GenQuadO (tok, AddOp, tl, tk, MakeConstLit (tok, MakeKey ('1'), Cardinal), TRUE) ; + GenQuadOtok (tok, AddOp, tl, tk, MakeConstLit (tok, MakeKey ('1'), Cardinal), TRUE, + tok, tok, tok) ; tj := calculateMultipicand (tok, arraySym, arrayType, dim) ; ti := MakeTemporary (tok, RightValue) ; PutVar (ti, Cardinal) ; @@ -11223,6 +11245,29 @@ END calculateMultipicand ; (* + ConvertToAddress - convert sym to an address. +*) + +PROCEDURE ConvertToAddress (tokpos: CARDINAL; sym: CARDINAL) : CARDINAL ; +VAR + adr: CARDINAL ; +BEGIN + IF GetSType (sym) = Address + THEN + RETURN sym + ELSE + PushTF (RequestSym (tokpos, MakeKey ('CONVERT')), NulSym) ; + PushT (Address) ; + PushTtok (sym, tokpos) ; + PushT(2) ; (* Two parameters *) + BuildConvertFunction ; + PopT (adr) ; + RETURN adr + END +END ConvertToAddress ; + + +(* BuildDynamicArray - Builds the array referencing for dynamic arrays. The Stack is expected to contain: @@ -11259,7 +11304,8 @@ VAR PtrToBase, Base, Dim, rw, - ti, tj, tk : CARDINAL ; + ti, tj, tk, + tka : CARDINAL ; BEGIN DisplayStack ; Sym := OperandT (2) ; @@ -11349,19 +11395,23 @@ BEGIN *) BackEndType := MakePointer (combinedTok, NulName) ; PutPointer (BackEndType, GetSType (Type)) ; + (* Create a temporary pointer for addition. *) + tka := ConvertToAddress (combinedTok, tk) ; IF Dim = GetDimension (Type) THEN PutLeftValueFrontBackType (Adr, GetSType(Type), BackEndType) ; - GenQuad (AddOp, Adr, Base, tk) ; + GenQuadOtok (combinedTok, AddOp, Adr, Base, tka, FALSE, + combinedTok, combinedTok, combinedTok) ; PopN (2) ; PushTFADrwtok (Adr, GetSType(Adr), ArraySym, Dim, rw, combinedTok) ELSE (* more to index *) PutLeftValueFrontBackType (Adr, Type, BackEndType) ; - GenQuad (AddOp, Adr, Base, tk) ; + GenQuadOtok (combinedTok, AddOp, Adr, Base, tka, FALSE, + combinedTok, combinedTok, combinedTok) ; PopN (2) ; PushTFADrwtok (Adr, GetSType(Adr), ArraySym, Dim, rw, combinedTok) END diff --git a/gcc/m2/gm2-compiler/SymbolTable.def b/gcc/m2/gm2-compiler/SymbolTable.def index 958591a..6cbc5c2 100644 --- a/gcc/m2/gm2-compiler/SymbolTable.def +++ b/gcc/m2/gm2-compiler/SymbolTable.def @@ -105,7 +105,7 @@ EXPORT QUALIFIED NulSym, AddSymToModuleScope, GetType, GetLType, GetSType, GetDType, SkipType, SkipTypeAndSubrange, - GetLowestType, + GetLowestType, GetTypeMode, GetSym, GetLocalSym, GetDeclareSym, GetRecord, FromModuleGetSym, GetOAFamily, @@ -1175,6 +1175,14 @@ PROCEDURE GetDType (sym: CARDINAL) : CARDINAL ; (* + GetTypeMode - return the type of sym, it returns Address is the + symbol is a LValue. +*) + +PROCEDURE GetTypeMode (sym: CARDINAL) : CARDINAL ; + + +(* GetSym - searches the current scope (and previous scopes if the scope tranparent allows) for a symbol with Name. *) diff --git a/gcc/m2/gm2-compiler/SymbolTable.mod b/gcc/m2/gm2-compiler/SymbolTable.mod index d939d58..7cef7ee 100644 --- a/gcc/m2/gm2-compiler/SymbolTable.mod +++ b/gcc/m2/gm2-compiler/SymbolTable.mod @@ -112,6 +112,8 @@ CONST UnboundedAddressName = "_m2_contents" ; UnboundedHighName = "_m2_high_%d" ; + BreakSym = 5293 ; + TYPE ConstLitPoolEntry = POINTER TO RECORD sym : CARDINAL ; @@ -1015,6 +1017,14 @@ END FinalSymbol ; (* + stop - a debugger convenience hook. +*) + +PROCEDURE stop ; +END stop ; + + +(* NewSym - Sets Sym to a new symbol index. *) @@ -1028,6 +1038,10 @@ BEGIN SymbolType := DummySym END ; PutIndice(Symbols, sym, pSym) ; + IF sym = BreakSym + THEN + stop + END ; INC(FreeSymbol) END NewSym ; @@ -6603,6 +6617,22 @@ END GetConstLitType ; (* + GetTypeMode - return the type of sym, it returns Address is the + symbol is a LValue. +*) + +PROCEDURE GetTypeMode (sym: CARDINAL) : CARDINAL ; +BEGIN + IF GetMode (sym) = LeftValue + THEN + RETURN( Address ) + ELSE + RETURN( GetType (sym) ) + END +END GetTypeMode ; + + +(* GetLocalSym - only searches the scope Sym for a symbol with name and returns the index to the symbol. *) diff --git a/gcc/m2/gm2-libs/SArgs.mod b/gcc/m2/gm2-libs/SArgs.mod index b1996cc..d6cb448 100644 --- a/gcc/m2/gm2-libs/SArgs.mod +++ b/gcc/m2/gm2-libs/SArgs.mod @@ -65,10 +65,8 @@ BEGIN i := VAL (INTEGER, n) ; IF i < GetArgC () THEN - (* ppc := ADDRESS (VAL (PtrToPtrToChar, ArgV) + (i * CARDINAL (TSIZE(PtrToChar)))) ; *) - ppc := ADDRESS (PtrToChar (GetArgV ()) + (n * TSIZE (PtrToChar))) ; + ppc := ADDRESS (ADDRESS (GetArgV ()) + (n * TSIZE (PtrToChar))) ; s := InitStringCharStar (ppc^) ; - RETURN TRUE ELSE s := NIL ; diff --git a/gcc/testsuite/gm2/extensions/fail/arith1.mod b/gcc/testsuite/gm2/extensions/fail/arith1.mod new file mode 100644 index 0000000..bdfb2d8 --- /dev/null +++ b/gcc/testsuite/gm2/extensions/fail/arith1.mod @@ -0,0 +1,36 @@ +MODULE arith1 ; + +IMPORT SYSTEM ; +FROM libc IMPORT exit, printf ; +FROM NumberIO IMPORT WriteCard ; +FROM StrIO IMPORT WriteLn ; + + +PROCEDURE assert (computed, result: CARDINAL; message: ARRAY OF CHAR) ; +BEGIN + IF computed # result + THEN + printf (message, computed, result) ; + exit (1) + END +END assert ; + + +PROCEDURE testCardinal ; +VAR + c64: SYSTEM.CARDINAL64 ; + c32: SYSTEM.CARDINAL32 ; + c16: SYSTEM.CARDINAL32 ; + c8 : SYSTEM.CARDINAL8 ; +BEGIN + c8 := 7 ; + c16 := 7000H ; + c32 := 7 ; + c64 := 0000000100000000H ; + c16 := c16 + c8 ; +END testCardinal ; + + +BEGIN + testCardinal +END arith1. diff --git a/gcc/testsuite/gm2/extensions/fail/arith2.mod b/gcc/testsuite/gm2/extensions/fail/arith2.mod new file mode 100644 index 0000000..fc6cb26 --- /dev/null +++ b/gcc/testsuite/gm2/extensions/fail/arith2.mod @@ -0,0 +1,36 @@ +MODULE arith2 ; + +IMPORT SYSTEM ; +FROM libc IMPORT exit, printf ; +FROM NumberIO IMPORT WriteCard ; +FROM StrIO IMPORT WriteLn ; + + +PROCEDURE assert (computed, result: CARDINAL; message: ARRAY OF CHAR) ; +BEGIN + IF computed # result + THEN + printf (message, computed, result) ; + exit (1) + END +END assert ; + + +PROCEDURE testCardinal ; +VAR + c64: SYSTEM.CARDINAL64 ; + c32: SYSTEM.CARDINAL32 ; + c16: SYSTEM.CARDINAL32 ; + c8 : SYSTEM.CARDINAL8 ; +BEGIN + c8 := 7 ; + c16 := 7000H ; + c32 := 7 ; + c64 := 0000000100000000H ; + c64 := c64 + c8 +END testCardinal ; + + +BEGIN + testCardinal +END arith2. diff --git a/gcc/testsuite/gm2/extensions/fail/arith3.mod b/gcc/testsuite/gm2/extensions/fail/arith3.mod new file mode 100644 index 0000000..6d34881 --- /dev/null +++ b/gcc/testsuite/gm2/extensions/fail/arith3.mod @@ -0,0 +1,36 @@ +MODULE arith3 ; + +IMPORT SYSTEM ; +FROM libc IMPORT exit, printf ; +FROM NumberIO IMPORT WriteCard ; +FROM StrIO IMPORT WriteLn ; + + +PROCEDURE assert (computed, result: CARDINAL; message: ARRAY OF CHAR) ; +BEGIN + IF computed # result + THEN + printf (message, computed, result) ; + exit (1) + END +END assert ; + + +PROCEDURE testCardinal ; +VAR + c64: SYSTEM.CARDINAL64 ; + c32: SYSTEM.CARDINAL32 ; + c16: SYSTEM.CARDINAL32 ; + c8 : SYSTEM.CARDINAL8 ; +BEGIN + c8 := 7 ; + c16 := 7000H ; + c32 := 7 ; + c64 := 0000000100000000H ; + c64 := c32 + c64 +END testCardinal ; + + +BEGIN + testCardinal +END arith3. diff --git a/gcc/testsuite/gm2/extensions/fail/arith4.mod b/gcc/testsuite/gm2/extensions/fail/arith4.mod new file mode 100644 index 0000000..8249452 --- /dev/null +++ b/gcc/testsuite/gm2/extensions/fail/arith4.mod @@ -0,0 +1,36 @@ +MODULE arith4 ; + +IMPORT SYSTEM ; +FROM libc IMPORT exit, printf ; +FROM NumberIO IMPORT WriteCard ; +FROM StrIO IMPORT WriteLn ; + + +PROCEDURE assert (computed, result: CARDINAL; message: ARRAY OF CHAR) ; +BEGIN + IF computed # result + THEN + printf (message, computed, result) ; + exit (1) + END +END assert ; + + +PROCEDURE testCardinal ; +VAR + c64: SYSTEM.CARDINAL64 ; + c32: SYSTEM.CARDINAL32 ; + c16: SYSTEM.CARDINAL32 ; + c8 : SYSTEM.CARDINAL8 ; +BEGIN + c8 := 7 ; + c16 := 7000H ; + c32 := 7 ; + c64 := 0000000100000000H ; + c64 := 16 * c64 + c32; (* Should fail here. *) +END testCardinal ; + + +BEGIN + testCardinal +END arith4. diff --git a/gcc/testsuite/gm2/extensions/fail/arithpromote.mod b/gcc/testsuite/gm2/extensions/fail/arithpromote.mod new file mode 100644 index 0000000..59738cb --- /dev/null +++ b/gcc/testsuite/gm2/extensions/fail/arithpromote.mod @@ -0,0 +1,55 @@ +MODULE arithpromote ; + +IMPORT SYSTEM ; +FROM libc IMPORT exit, printf ; +FROM NumberIO IMPORT WriteCard ; +FROM StrIO IMPORT WriteLn ; + + +PROCEDURE assert (computed, result: CARDINAL; message: ARRAY OF CHAR) ; +BEGIN + IF computed # result + THEN + printf (message, computed, result) ; + exit (1) + END +END assert ; + + +PROCEDURE testCardinal ; +VAR + c64: SYSTEM.CARDINAL64 ; + c32: SYSTEM.CARDINAL32 ; + c16: SYSTEM.CARDINAL32 ; + c8 : SYSTEM.CARDINAL8 ; +BEGIN + c8 := 7 ; + c16 := 7000H ; + c32 := 7 ; + c64 := 0000000100000000H ; +(* + assert (c16 + c8, 7007H, "addition between CARDINAL16 and CARDINAL8 fails: %d # %d\n") ; + c64 := 0000000100000000H ; +*) +(* + IF c64 + c8 # 0000000100000007H + THEN + printf ("failure when adding 0000000100000000H + 7\n"); + exit (1) + END +*) +(* + IF c64 + c32 # 0000000100000007H + THEN + printf ("failure when adding 0000000100000000H + 7\n"); + exit (1) + END +*) + c64 := 16 * c64 + c32; (* Should fail here. *) + c64 := c32 + c64 ; +END testCardinal ; + + +BEGIN + testCardinal +END arithpromote. diff --git a/gcc/testsuite/gm2/extensions/fail/extensions-fail.exp b/gcc/testsuite/gm2/extensions/fail/extensions-fail.exp new file mode 100644 index 0000000..3839a0a --- /dev/null +++ b/gcc/testsuite/gm2/extensions/fail/extensions-fail.exp @@ -0,0 +1,36 @@ +# Copyright (C) 2003-2024 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 +# . + +# This file was written by Gaius Mulley (gaius.mulley@southwales.ac.uk) +# for GNU Modula-2. + +if $tracelevel then { + strace $tracelevel +} + +# load support procs +load_lib gm2-torture.exp + +gm2_init_pim "${srcdir}/gm2/extensions/fail" + +foreach testcase [lsort [glob -nocomplain $srcdir/$subdir/*.mod]] { + # If we're only testing specific files and this isn't one of them, skip it. + if ![runtest_file_p $runtests $testcase] then { + continue + } + + gm2-torture-fail $testcase +} diff --git a/gcc/testsuite/gm2/linking/fail/badimp.def b/gcc/testsuite/gm2/linking/fail/badimp.def new file mode 100644 index 0000000..1b31f0b --- /dev/null +++ b/gcc/testsuite/gm2/linking/fail/badimp.def @@ -0,0 +1,4 @@ +DEFINITION MODULE badimp ; + + +END badimp. diff --git a/gcc/testsuite/gm2/linking/fail/badimp.mod b/gcc/testsuite/gm2/linking/fail/badimp.mod new file mode 100644 index 0000000..02da928 --- /dev/null +++ b/gcc/testsuite/gm2/linking/fail/badimp.mod @@ -0,0 +1,8 @@ +(* { dg-skip-if "" { *-*-* } } *) + +MODULE badimp ; + +(* User forgot the IMPLEMENTATION keyword prior to MODULE. *) + +BEGIN +END badimp. diff --git a/gcc/testsuite/gm2/linking/fail/linking-fail.exp b/gcc/testsuite/gm2/linking/fail/linking-fail.exp new file mode 100644 index 0000000..95e95d6 --- /dev/null +++ b/gcc/testsuite/gm2/linking/fail/linking-fail.exp @@ -0,0 +1,38 @@ +# Copyright (C) 2024 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 +# . + +# This file was written by Gaius Mulley (gaius.mulley@southwales.ac.uk) +# for GNU Modula-2. + +if $tracelevel then { + strace $tracelevel +} + +# load support procs +load_lib gm2-torture.exp + +gm2_init_pim "${srcdir}/gm2/linking/fail" -fscaffold-main + +foreach testcase [lsort [glob -nocomplain $srcdir/$subdir/*.mod]] { + # If we're only testing specific files and this isn't one of them, skip it. + if ![runtest_file_p $runtests $testcase] then { + continue + } + + if { $testcase != "$srcdir/$subdir/badimp.mod" } { + gm2-torture-fail $testcase + } +} diff --git a/gcc/testsuite/gm2/linking/fail/testbadimp.mod b/gcc/testsuite/gm2/linking/fail/testbadimp.mod new file mode 100644 index 0000000..cdea4fc --- /dev/null +++ b/gcc/testsuite/gm2/linking/fail/testbadimp.mod @@ -0,0 +1,6 @@ +MODULE testbadimp ; + +IMPORT badimp ; + +BEGIN +END testbadimp. -- cgit v1.1 From 686b5eb9c9ee623a604dde5c49fa11c23f384c62 Mon Sep 17 00:00:00 2001 From: Patrick Palka Date: Fri, 2 Feb 2024 19:07:08 -0500 Subject: c++: requires-exprs and partial constraint subst [PR110006] In r11-3261-gb28b621ac67bee we made tsubst_requires_expr never partially substitute into a requires-expression so as to avoid checking its requirements out of order during e.g. generic lambda regeneration. These PRs however illustrate that we still sometimes do need to partially substitute into a requires-expression, in particular when it appears in associated constraints that we're directly substituting for sake of declaration matching or dguide constraint rewriting. In these cases we're being called from tsubst_constraint during which processing_constraint_expression_p is true, so this patch checks this predicate to control whether we defer substitution or partially substitute. In turn, we now need to propagate semantic tsubst flags through tsubst_requires_expr rather than just using tf_none, notably for sake of dguide constraint rewriting which sets tf_dguide. PR c++/110006 PR c++/112769 gcc/cp/ChangeLog: * constraint.cc (subst_info::quiet): Accomodate non-diagnostic tsubst flags. (tsubst_valid_expression_requirement): Likewise. (tsubst_simple_requirement): Return a substituted _REQ node when processing_template_decl. (tsubst_type_requirement_1): Accomodate non-diagnostic tsubst flags. (tsubst_type_requirement): Return a substituted _REQ node when processing_template_decl. (tsubst_compound_requirement): Likewise. Accomodate non-diagnostic tsubst flags. (tsubst_nested_requirement): Likewise. (tsubst_requires_expr): Don't defer partial substitution when processing_constraint_expression_p is true, in which case return a substituted REQUIRES_EXPR. * pt.cc (tsubst_expr) : Accomodate non-diagnostic tsubst flags. gcc/testsuite/ChangeLog: * g++.dg/cpp2a/class-deduction-alias18.C: New test. * g++.dg/cpp2a/concepts-friend16.C: New test. Reviewed-by: Jason Merrill --- gcc/cp/constraint.cc | 56 +++++++++++++++++----- gcc/cp/pt.cc | 3 +- .../g++.dg/cpp2a/class-deduction-alias18.C | 13 +++++ gcc/testsuite/g++.dg/cpp2a/concepts-friend16.C | 25 ++++++++++ 4 files changed, 84 insertions(+), 13 deletions(-) create mode 100644 gcc/testsuite/g++.dg/cpp2a/class-deduction-alias18.C create mode 100644 gcc/testsuite/g++.dg/cpp2a/concepts-friend16.C (limited to 'gcc') diff --git a/gcc/cp/constraint.cc b/gcc/cp/constraint.cc index fef68cf..d956901 100644 --- a/gcc/cp/constraint.cc +++ b/gcc/cp/constraint.cc @@ -85,7 +85,7 @@ struct subst_info /* True if we should not diagnose errors. */ bool quiet() const { - return complain == tf_none; + return !(complain & tf_warning_or_error); } /* True if we should diagnose errors. */ @@ -1991,8 +1991,9 @@ hash_placeholder_constraint (tree c) static tree tsubst_valid_expression_requirement (tree t, tree args, sat_info info) { - tree r = tsubst_expr (t, args, tf_none, info.in_decl); - if (convert_to_void (r, ICV_STATEMENT, tf_none) != error_mark_node) + tsubst_flags_t quiet = info.complain & ~tf_warning_or_error; + tree r = tsubst_expr (t, args, quiet, info.in_decl); + if (convert_to_void (r, ICV_STATEMENT, quiet) != error_mark_node) return r; if (info.diagnose_unsatisfaction_p ()) @@ -2028,6 +2029,8 @@ tsubst_simple_requirement (tree t, tree args, sat_info info) tree expr = tsubst_valid_expression_requirement (t0, args, info); if (expr == error_mark_node) return error_mark_node; + if (processing_template_decl) + return finish_simple_requirement (EXPR_LOCATION (t), expr); return boolean_true_node; } @@ -2037,7 +2040,8 @@ tsubst_simple_requirement (tree t, tree args, sat_info info) static tree tsubst_type_requirement_1 (tree t, tree args, sat_info info, location_t loc) { - tree r = tsubst (t, args, tf_none, info.in_decl); + tsubst_flags_t quiet = info.complain & ~tf_warning_or_error; + tree r = tsubst (t, args, quiet, info.in_decl); if (r != error_mark_node) return r; @@ -2068,6 +2072,8 @@ tsubst_type_requirement (tree t, tree args, sat_info info) tree type = tsubst_type_requirement_1 (t0, args, info, EXPR_LOCATION (t)); if (type == error_mark_node) return error_mark_node; + if (processing_template_decl) + return finish_type_requirement (EXPR_LOCATION (t), type); return boolean_true_node; } @@ -2124,9 +2130,11 @@ tsubst_compound_requirement (tree t, tree args, sat_info info) location_t loc = cp_expr_loc_or_input_loc (expr); + subst_info quiet (info.complain & ~tf_warning_or_error, info.in_decl); + /* Check the noexcept condition. */ bool noexcept_p = COMPOUND_REQ_NOEXCEPT_P (t); - if (noexcept_p && !expr_noexcept_p (expr, tf_none)) + if (noexcept_p && !expr_noexcept_p (expr, quiet.complain)) { if (info.diagnose_unsatisfaction_p ()) inform (loc, "%qE is not %", expr); @@ -2139,8 +2147,6 @@ tsubst_compound_requirement (tree t, tree args, sat_info info) if (type == error_mark_node) return error_mark_node; - subst_info quiet (tf_none, info.in_decl); - /* Check expression against the result type. */ if (type) { @@ -2182,6 +2188,9 @@ tsubst_compound_requirement (tree t, tree args, sat_info info) } } + if (processing_template_decl) + return finish_compound_requirement (EXPR_LOCATION (t), + expr, type, noexcept_p); return boolean_true_node; } @@ -2190,7 +2199,16 @@ tsubst_compound_requirement (tree t, tree args, sat_info info) static tree tsubst_nested_requirement (tree t, tree args, sat_info info) { - sat_info quiet (tf_none, info.in_decl); + if (processing_template_decl) + { + tree req = TREE_OPERAND (t, 0); + req = tsubst_constraint (req, args, info.complain, info.in_decl); + if (req == error_mark_node) + return error_mark_node; + return finish_nested_requirement (EXPR_LOCATION (t), req); + } + + sat_info quiet (info.complain & ~tf_warning_or_error, info.in_decl); tree result = constraint_satisfaction_value (t, args, quiet); if (result == boolean_true_node) return boolean_true_node; @@ -2330,18 +2348,25 @@ tsubst_requires_expr (tree t, tree args, sat_info info) args = add_extra_args (REQUIRES_EXPR_EXTRA_ARGS (t), args, info.complain, info.in_decl); - if (processing_template_decl) + if (processing_template_decl + && !processing_constraint_expression_p ()) { /* We're partially instantiating a generic lambda. Substituting into this requires-expression now may cause its requirements to get checked out of order, so instead just remember the template - arguments and wait until we can substitute them all at once. */ + arguments and wait until we can substitute them all at once. + + Except if this requires-expr is part of associated constraints + that we're substituting into directly (for e.g. declaration + matching or dguide constraint rewriting), in which case we need + to partially substitute. */ t = copy_node (t); REQUIRES_EXPR_EXTRA_ARGS (t) = build_extra_args (t, args, info.complain); return t; } - if (tree parms = REQUIRES_EXPR_PARMS (t)) + tree parms = REQUIRES_EXPR_PARMS (t); + if (parms) { parms = tsubst_constraint_variables (parms, args, info); if (parms == error_mark_node) @@ -2349,10 +2374,13 @@ tsubst_requires_expr (tree t, tree args, sat_info info) } tree result = boolean_true_node; + if (processing_template_decl) + result = NULL_TREE; for (tree reqs = REQUIRES_EXPR_REQS (t); reqs; reqs = TREE_CHAIN (reqs)) { tree req = TREE_VALUE (reqs); - if (tsubst_requirement (req, args, info) == error_mark_node) + req = tsubst_requirement (req, args, info); + if (req == error_mark_node) { result = boolean_false_node; if (info.diagnose_unsatisfaction_p ()) @@ -2360,7 +2388,11 @@ tsubst_requires_expr (tree t, tree args, sat_info info) else break; } + else if (processing_template_decl) + result = tree_cons (NULL_TREE, req, result); } + if (processing_template_decl && result != boolean_false_node) + result = finish_requires_expr (EXPR_LOCATION (t), parms, nreverse (result)); return result; } diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc index 355e960..903a4a1 100644 --- a/gcc/cp/pt.cc +++ b/gcc/cp/pt.cc @@ -21706,7 +21706,8 @@ tsubst_expr (tree t, tree args, tsubst_flags_t complain, tree in_decl) case REQUIRES_EXPR: { - tree r = tsubst_requires_expr (t, args, tf_none, in_decl); + complain &= ~tf_warning_or_error; + tree r = tsubst_requires_expr (t, args, complain, in_decl); RETURN (r); } diff --git a/gcc/testsuite/g++.dg/cpp2a/class-deduction-alias18.C b/gcc/testsuite/g++.dg/cpp2a/class-deduction-alias18.C new file mode 100644 index 0000000..0bb11bb --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp2a/class-deduction-alias18.C @@ -0,0 +1,13 @@ +// PR c++/112769 +// { dg-do compile { target c++20 } } + +template +struct type +{ + type(T) requires requires { T{0}; }; +}; + +template +using alias = type<0, T>; + +alias foo{123}; diff --git a/gcc/testsuite/g++.dg/cpp2a/concepts-friend16.C b/gcc/testsuite/g++.dg/cpp2a/concepts-friend16.C new file mode 100644 index 0000000..18974ee --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp2a/concepts-friend16.C @@ -0,0 +1,25 @@ +// PR c++/110006 +// { dg-do compile { target c++20 } } + +template +class s; + +template +void constraint(s const&, int&); + +template +U function(s const x) + requires requires (U& u) { constraint(x, u); }; + +template +class s +{ + template + friend U function(s const x) + requires requires (U& u) { constraint(x, u); }; +}; + +int f(s q) +{ + return function(q); // { dg-bogus "ambiguous" } +} -- cgit v1.1 From 4b7d4d8a4af7e37cf510eaa5c705f61fefd31f2c Mon Sep 17 00:00:00 2001 From: GCC Administrator Date: Sat, 3 Feb 2024 00:18:26 +0000 Subject: Daily bump. --- gcc/ChangeLog | 166 ++++++++++++++++++++++++++++++++++ gcc/DATESTAMP | 2 +- gcc/cp/ChangeLog | 41 +++++++++ gcc/d/ChangeLog | 36 ++++++++ gcc/jit/ChangeLog | 15 ++++ gcc/m2/ChangeLog | 36 ++++++++ gcc/testsuite/ChangeLog | 231 ++++++++++++++++++++++++++++++++++++++++++++++++ 7 files changed, 526 insertions(+), 1 deletion(-) (limited to 'gcc') diff --git a/gcc/ChangeLog b/gcc/ChangeLog index c63ad2f..f6ab4fc 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,169 @@ +2024-02-02 Tamar Christina + + PR tree-optimization/113588 + PR tree-optimization/113467 + * tree-vect-data-refs.cc + (vect_analyze_data_ref_dependence): Choose correct dest and fix checks. + (vect_analyze_early_break_dependences): Update comments. + +2024-02-02 John David Anglin + + PR target/59778 + * config/pa/pa.cc (enum pa_builtins): Add PA_BUILTIN_GET_FPSR + and PA_BUILTIN_SET_FPSR builtins. + * (pa_builtins_icode): Declare. + * (def_builtin, pa_fpu_init_builtins): New. + * (pa_init_builtins): Initialize FPU builtins. + * (pa_builtin_decl, pa_expand_builtin_1): New. + * (pa_expand_builtin): Handle PA_BUILTIN_GET_FPSR and + PA_BUILTIN_SET_FPSR builtins. + * (pa_atomic_assign_expand_fenv): New. + * config/pa/pa.md (UNSPECV_GET_FPSR, UNSPECV_SET_FPSR): New + UNSPECV constants. + (get_fpsr, put_fpsr): New expanders. + (get_fpsr_32, get_fpsr_64, set_fpsr_32, set_fpsr_64): New + insn patterns. + +2024-02-02 Juzhe-Zhong + + PR target/113697 + * config/riscv/riscv-v.cc (expand_reduction): Pass VLMAX avl to scalar move. + +2024-02-02 Jonathan Wakely + + * doc/extend.texi (Common Type Attributes): Fix typo in + description of hardbool. + +2024-02-02 Jakub Jelinek + + PR tree-optimization/113692 + * gimple-lower-bitint.cc (bitint_large_huge::lower_stmt): Handle casts + from large/huge BITINT_TYPEs to POINTER_TYPE/REFERENCE_TYPE as + final_cast_p. + +2024-02-02 Jakub Jelinek + + PR middle-end/113699 + * gimple-lower-bitint.cc (bitint_large_huge::lower_asm): Handle + uninitialized large/huge _BitInt SSA_NAME inputs. + +2024-02-02 Jakub Jelinek + + PR middle-end/113705 + * tree-ssa-math-opts.cc (is_widening_mult_rhs_p): Use wide_int_from + around wi::to_wide in order to compare value in prec precision. + +2024-02-02 Lehua Ding + + Revert: + 2024-02-02 Juzhe-Zhong + + * config/riscv/riscv.cc (riscv_legitimize_move): Fix poly_int dest generation. + +2024-02-02 Juzhe-Zhong + + * config/riscv/riscv.cc (riscv_legitimize_move): Fix poly_int dest generation. + +2024-02-02 Pan Li + + * config/riscv/riscv.cc (riscv_get_arg_info): Cleanup comments. + (riscv_pass_by_reference): Ditto. + (riscv_fntype_abi): Ditto. + +2024-02-02 Juzhe-Zhong + + * config/riscv/riscv-vsetvl.cc (vsetvl_pre_insn_p): New function. + (pre_vsetvl::cleaup): Remove vsetvl_pre. + (pre_vsetvl::remove_vsetvl_pre_insns): New function. + +2024-02-02 Jiahao Xu + + * config/loongarch/larchintrin.h + (__frecipe_s): Update function return type. + (__frecipe_d): Ditto. + (__frsqrte_s): Ditto. + (__frsqrte_d): Ditto. + +2024-02-02 Li Wei + + * config/loongarch/loongarch.cc (loongarch_multiply_add_p): New. + (loongarch_vector_costs::add_stmt_cost): Adjust. + +2024-02-02 Xi Ruoyao + + * config/loongarch/loongarch.md (unspec): Add + UNSPEC_LA_PCREL_64_PART1 and UNSPEC_LA_PCREL_64_PART2. + (la_pcrel64_two_parts): New define_insn. + * config/loongarch/loongarch.cc (loongarch_tls_symbol): Fix a + typo in the comment. + (loongarch_call_tls_get_addr): If -mcmodel=extreme + -mexplicit-relocs={always,auto}, use la_pcrel64_two_parts for + addressing the TLS symbol and __tls_get_addr. Emit an REG_EQUAL + note to allow CSE addressing __tls_get_addr. + (loongarch_legitimize_tls_address): If -mcmodel=extreme + -mexplicit-relocs={always,auto}, address TLS IE symbols with + la_pcrel64_two_parts. + (loongarch_split_symbol): If -mcmodel=extreme + -mexplicit-relocs={always,auto}, address symbols with + la_pcrel64_two_parts. + (loongarch_output_mi_thunk): Clean up unreachable code. If + -mcmodel=extreme -mexplicit-relocs={always,auto}, address the MI + thunks with la_pcrel64_two_parts. + +2024-02-02 Lulu Cheng + + * config/loongarch/loongarch.cc (loongarch_call_tls_get_addr): + Add support for call36. + +2024-02-02 Lulu Cheng + + * config/loongarch/loongarch.cc (loongarch_explicit_relocs_p): + When the code model of the symbol is extreme and -mexplicit-relocs=auto, + the macro instruction loading symbol address is not applicable. + (loongarch_call_tls_get_addr): Adjust code. + (loongarch_legitimize_tls_address): Likewise. + +2024-02-02 Lulu Cheng + + * config/loongarch/loongarch-protos.h (loongarch_symbol_extreme_p): + Add function declaration. + * config/loongarch/loongarch.cc (loongarch_symbolic_constant_p): + For SYMBOL_PCREL64, non-zero addend of "la.local $rd,$rt,sym+addend" + is not allowed + (loongarch_load_tls): Added macro support in extreme mode. + (loongarch_call_tls_get_addr): Likewise. + (loongarch_legitimize_tls_address): Likewise. + (loongarch_force_address): Likewise. + (loongarch_legitimize_move): Likewise. + (loongarch_output_mi_thunk): Likewise. + (loongarch_option_override_internal): Remove the code that detects + explicit relocs status. + (loongarch_handle_model_attribute): Likewise. + * config/loongarch/loongarch.md (movdi_symbolic_off64): New template. + * config/loongarch/predicates.md (symbolic_off64_operand): New predicate. + (symbolic_off64_or_reg_operand): Likewise. + +2024-02-02 Lulu Cheng + + * config/loongarch/loongarch.cc (loongarch_load_tls): + Load all types of tls symbols through one function. + (loongarch_got_load_tls_gd): Delete. + (loongarch_got_load_tls_ld): Delete. + (loongarch_got_load_tls_ie): Delete. + (loongarch_got_load_tls_le): Delete. + (loongarch_call_tls_get_addr): Modify the called function name. + (loongarch_legitimize_tls_address): Likewise. + * config/loongarch/loongarch.md (@got_load_tls_gd): Delete. + (@load_tls): New template. + (@got_load_tls_ld): Delete. + (@got_load_tls_le): Delete. + (@got_load_tls_ie): Delete. + +2024-02-02 Lulu Cheng + + * config/loongarch/loongarch.cc (mem_shadd_or_shadd_rtx_p): New function. + (loongarch_legitimize_address): Add logical transformation code. + 2024-02-01 Marek Polacek * doc/invoke.texi: Update -Wdangling-reference documentation. diff --git a/gcc/DATESTAMP b/gcc/DATESTAMP index 656861b..f3c7b76 100644 --- a/gcc/DATESTAMP +++ b/gcc/DATESTAMP @@ -1 +1 @@ -20240202 +20240203 diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index bcc9c3a..f524ec6 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,3 +1,44 @@ +2024-02-03 Patrick Palka + + PR c++/110006 + PR c++/112769 + * constraint.cc (subst_info::quiet): Accomodate non-diagnostic + tsubst flags. + (tsubst_valid_expression_requirement): Likewise. + (tsubst_simple_requirement): Return a substituted _REQ node when + processing_template_decl. + (tsubst_type_requirement_1): Accomodate non-diagnostic tsubst + flags. + (tsubst_type_requirement): Return a substituted _REQ node when + processing_template_decl. + (tsubst_compound_requirement): Likewise. Accomodate non-diagnostic + tsubst flags. + (tsubst_nested_requirement): Likewise. + (tsubst_requires_expr): Don't defer partial substitution when + processing_constraint_expression_p is true, in which case return + a substituted REQUIRES_EXPR. + * pt.cc (tsubst_expr) : Accomodate + non-diagnostic tsubst flags. + +2024-02-02 Jason Merrill + + PR c++/110084 + * pt.cc (tsubst_function_decl): Only check a function defaulted + outside the class if the class is complete. + +2024-02-02 Jason Merrill + + PR c++/112439 + * constexpr.cc (cxx_eval_store_expression): Check empty_base + before marking a CONSTRUCTOR readonly. + +2024-02-02 Jason Merrill + + PR c++/113638 + * cp-tree.h: Adjust comment. + * pt.cc (instantiate_template): Set VAR_HAD_UNKNOWN_BOUND for + variable template. + 2024-02-01 Marek Polacek * call.cc (reference_like_class_p): Consider even non-templates for diff --git a/gcc/d/ChangeLog b/gcc/d/ChangeLog index 0741a35..1b5db29 100644 --- a/gcc/d/ChangeLog +++ b/gcc/d/ChangeLog @@ -1,3 +1,39 @@ +2024-02-02 Iain Buclaw + + * dmd/MERGE: Merge upstream dmd bce5c1f7b5. + * d-attribs.cc (build_attributes): Update for new front-end interface. + * d-lang.cc (d_parse_file): Likewise. + * decl.cc (DeclVisitor::visit (VarDeclaration *)): Likewise. + * expr.cc (build_lambda_tree): New function. + (ExprVisitor::visit (FuncExp *)): Use build_lambda_tree. + (ExprVisitor::visit (SymOffExp *)): Likewise. + (ExprVisitor::visit (VarExp *)): Likewise. + * typeinfo.cc (create_tinfo_types): Add two ulong fields to internal + TypeInfo representation. + (TypeInfoVisitor::visit (TypeInfoClassDeclaration *)): Emit stub data + for TypeInfo_Class.nameSig. + (TypeInfoVisitor::visit (TypeInfoStructDeclaration *)): Update for new + front-end interface. + +2024-02-02 Iain Buclaw + + * dmd/MERGE: Merge upstream dmd d8e3976a58. + * dmd/VERSION: Bump version to v2.107.0-beta.1. + * d-lang.cc (d_parse_file): Update for new front-end interface. + * modules.cc (struct module_info): Add standalonectors. + (build_module_tree): Implement @standalone. + (register_module_decl): Likewise. + +2024-02-02 Iain Buclaw + + * dmd/MERGE: Merge upstream dmd f1a045928e. + * dmd/VERSION: Bump version to v2.106.1-rc.1. + * gdc.texi (fignore-unknown-pragmas): Update documentation. + * d-builtins.cc (covariant_with_builtin_type_p): Update for new + front-end interface. + * d-lang.cc (d_parse_file): Likewise. + * typeinfo.cc (make_frontend_typeinfo): Likewise. + 2024-01-04 David Malcolm * lang.opt.urls: New file, autogenerated by diff --git a/gcc/jit/ChangeLog b/gcc/jit/ChangeLog index a7cb813..87f789d 100644 --- a/gcc/jit/ChangeLog +++ b/gcc/jit/ChangeLog @@ -1,3 +1,18 @@ +2024-02-02 Antoni Boucher + + * docs/topics/compatibility.rst (LIBGCCJIT_ABI_27): New ABI tag. + * docs/topics/expressions.rst: Document gcc_jit_context_new_sizeof. + * jit-playback.cc (new_sizeof): New method. + * jit-playback.h (new_sizeof): New method. + * jit-recording.cc (recording::context::new_sizeof, + recording::memento_of_sizeof::replay_into, + recording::memento_of_sizeof::make_debug_string, + recording::memento_of_sizeof::write_reproducer): New methods. + * jit-recording.h (class memento_of_sizeof): New class. + * libgccjit.cc (gcc_jit_context_new_sizeof): New function. + * libgccjit.h (gcc_jit_context_new_sizeof): New function. + * libgccjit.map: New function. + 2024-01-19 Antoni Boucher * jit-builtins.cc (ensure_optimization_builtins_exist): Add diff --git a/gcc/m2/ChangeLog b/gcc/m2/ChangeLog index abac63b..afd5bff 100644 --- a/gcc/m2/ChangeLog +++ b/gcc/m2/ChangeLog @@ -1,3 +1,39 @@ +2024-02-03 Gaius Mulley + + PR modula2/113730 + * gm2-compiler/M2Base.mod (IsUserType): New procedure function. + (MixTypes): Use IsUserType instead of IsType before calling MixTypes. + * gm2-compiler/M2GenGCC.mod (GetTypeMode): Remove and import from + SymbolTable. + (CodeBinaryCheck): Replace call to MixTypes with MixTypesBinary. + (CodeBinary): Replace call to MixTypes with MixTypesBinary. + (CodeIfLess): Replace MixTypes with ComparisonMixTypes. + (CodeIfGre): Replace MixTypes with ComparisonMixTypes. + (CodeIfLessEqu): Replace MixTypes with ComparisonMixTypes. + (CodeIfGreEqu): Replace MixTypes with ComparisonMixTypes. + (CodeIfEqu): Replace MixTypes with ComparisonMixTypes. + (CodeIfNotEqu): Replace MixTypes with ComparisonMixTypes. + (ComparisonMixTypes): New procedure function. + * gm2-compiler/M2Quads.mod (BuildEndFor): Replace GenQuadO + with GenQuadOtok and pass tokenpos for the operands to the AddOp + and XIndrOp. + (CheckRangeIncDec): Check etype against NulSym and dtype for a + pointer and set etype to Address. + (BuildAddAdrFunction): New variable opa. Convert operand to an + address and save result in opa. Replace GenQuad with GenQuadOtok. + (BuildSubAdrFunction): New variable opa. Convert operand to an + address and save result in opa. Replace GenQuad with GenQuadOtok. + (BuildDiffAdrFunction): New variable opa. Convert operand to an + address and save result in opa. Replace GenQuad with GenQuadOtok. + (calculateMultipicand): Replace GenQuadO with GenQuadOtok. + (ConvertToAddress): New procedure function. + (BuildDynamicArray): Convert index to address before adding to + the base. + * gm2-compiler/SymbolTable.def (GetTypeMode): New procedure function. + * gm2-compiler/SymbolTable.mod (GetTypeMode): New procedure + function implemented (moved from M2GenGCC.mod). + * gm2-libs/SArgs.mod (GetArg): Replace cast to PtrToChar with ADDRESS. + 2024-02-01 Gaius Mulley PR modula2/111627 diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index 8ab0cca..5dc568f 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,234 @@ +2024-02-03 Patrick Palka + + PR c++/110006 + PR c++/112769 + * g++.dg/cpp2a/class-deduction-alias18.C: New test. + * g++.dg/cpp2a/concepts-friend16.C: New test. + +2024-02-03 Gaius Mulley + + PR modula2/113730 + * gm2/extensions/fail/arith1.mod: New test. + * gm2/extensions/fail/arith2.mod: New test. + * gm2/extensions/fail/arith3.mod: New test. + * gm2/extensions/fail/arith4.mod: New test. + * gm2/extensions/fail/arithpromote.mod: New test. + * gm2/extensions/fail/extensions-fail.exp: New test. + * gm2/linking/fail/badimp.def: New test. + * gm2/linking/fail/badimp.mod: New test. + * gm2/linking/fail/linking-fail.exp: New test. + * gm2/linking/fail/testbadimp.mod: New test. + +2024-02-02 Tamar Christina + + PR tree-optimization/113588 + PR tree-optimization/113467 + * gcc.dg/vect/vect-early-break_108-pr113588.c: New test. + * gcc.dg/vect/vect-early-break_109-pr113588.c: New test. + +2024-02-02 Andrew Pinski + + * gcc.dg/vect/vect-avg-1.c: Check optimized dump + for `vector *signed short` instead of the `vect` dump. + * gcc.dg/vect/vect-avg-11.c: Likewise. + * gcc.dg/vect/vect-avg-12.c: Likewise. + * gcc.dg/vect/vect-avg-13.c: Likewise. + * gcc.dg/vect/vect-avg-14.c: Likewise. + * gcc.dg/vect/vect-avg-2.c: Likewise. + * gcc.dg/vect/vect-avg-3.c: Likewise. + * gcc.dg/vect/vect-avg-4.c: Likewise. + * gcc.dg/vect/vect-avg-5.c: Likewise. + * gcc.dg/vect/vect-avg-6.c: Likewise. + * gcc.dg/vect/vect-avg-7.c: Likewise. + * gcc.dg/vect/vect-avg-8.c: Likewise. + +2024-02-02 Jakub Jelinek + + PR libgcc/113604 + * gcc.dg/torture/bitint-53.c: New test. + * gcc.dg/torture/bitint-55.c: New test. + +2024-02-02 Antoni Boucher + + * jit.dg/all-non-failing-tests.h: New test. + * jit.dg/test-sizeof.c: New test. + +2024-02-02 Jason Merrill + + PR c++/110084 + * g++.dg/cpp2a/spaceship-synth-neg3.C: Check error message. + * g++.dg/cpp2a/spaceship-eq16.C: New test. + +2024-02-02 Juzhe-Zhong + + PR target/113697 + * gcc.target/riscv/rvv/autovec/pr113697.c: New test. + +2024-02-02 Iain Sandoe + + * lib/target-supports.exp (check_effective_target_shared): + Allow the external symbols referenced in the test to be undefined. + +2024-02-02 Iain Sandoe + + * g++.dg/ubsan/ubsan.exp:Add a parameter to init to say that + we expect the C++ driver to provide paths for libstdc++. + * gcc.dg/ubsan/ubsan.exp: Add a parameter to init to say that + we need a path added for libstdc++. + * gdc.dg/ubsan/ubsan.exp: Likewise. + * gfortran.dg/ubsan/ubsan.exp: Likewise. + * lib/ubsan-dg.exp: Handle a single parameter to init that + requests addition of a path to libstdc++ to link flags. + +2024-02-02 Iain Sandoe + + * g++.dg/asan/asan.exp: Add a parameter to init to say that + we expect the C++ driver to provide paths for libstdc++. + * g++.dg/hwasan/hwasan.exp: Likewise + * gcc.dg/asan/asan.exp: Add a parameter to init to say that + we need a path added for libstdc++. + * gcc.dg/hwasan/hwasan.exp: Likewise. + * gdc.dg/asan/asan.exp: Likewise. + * gfortran.dg/asan/asan.exp: Likewise. + * lib/asan-dg.exp: Handle a single parameter to init that + requests addition of a path to libstdc++ to link flags. + * lib/hwasan-dg.exp: Likewise. + +2024-02-02 Jakub Jelinek + + PR tree-optimization/113691 + * gcc.dg/bitint-83.c: New test. + +2024-02-02 Jakub Jelinek + + PR tree-optimization/113692 + * gcc.dg/bitint-82.c: New test. + +2024-02-02 Jakub Jelinek + + PR middle-end/113699 + * gcc.dg/bitint-81.c: New test. + +2024-02-02 Jakub Jelinek + + PR middle-end/113705 + * g++.dg/opt/pr113705.C: New test. + +2024-02-02 Rainer Orth + + * gcc.target/i386/pr71321.c (scan-assembler-not): Avoid multiline + matches. + +2024-02-02 Rainer Orth + + * gcc.target/i386/sse2-stv-1.c (dg-options): Add -mno-stackrealign. + +2024-02-02 Rainer Orth + + * gcc.target/i386/pr80569.c: Require gas. + +2024-02-02 Lehua Ding + + Revert: + 2024-02-02 Juzhe-Zhong + + * gcc.target/riscv/rvv/autovec/poly_licm-1.c: New test. + * gcc.target/riscv/rvv/autovec/poly_licm-2.c: New test. + +2024-02-02 Iain Sandoe + + PR target/112863 + * lib/obj-c++.exp: Decide on whether to present -B or -L to + reference the paths to uninstalled libobjc/libobjc-gnu and + libstdc++ and use that to generate the link flags. + +2024-02-02 Iain Sandoe + + PR target/112862 + * gfortran.dg/coarray/caf.exp: Remove duplicate additions of + libatomic handling. + * gfortran.dg/dg.exp: Likewise. + * lib/gfortran.exp: Decide on whether to present -B or -L to + reference the paths to uninstalled libgfortran, libqadmath and + libatomic and use that to generate the link flags. + +2024-02-02 Juzhe-Zhong + + * gcc.target/riscv/rvv/autovec/poly_licm-1.c: New test. + * gcc.target/riscv/rvv/autovec/poly_licm-2.c: New test. + +2024-02-02 Rainer Orth + + * gcc.target/i386/pieces-memcpy-7.c (dg-additional-options): Add + -mno-stackrealign. + * gcc.target/i386/pieces-memcpy-8.c: Likewise. + * gcc.target/i386/pieces-memcpy-9.c: Likewise. + * gcc.target/i386/pieces-memset-36.c: Likewise. + * gcc.target/i386/pieces-memset-40.c: Likewise. + * gcc.target/i386/pieces-memset-9.c: Likewise. + +2024-02-02 Rainer Orth + + * gcc.target/i386/apx-ndd-cmov.c (scan-assembler-times): Allow for + cmovl.e, cmovl.ge. + +2024-02-02 Jason Merrill + + PR c++/112439 + * g++.dg/cpp2a/no_unique_address15.C: New test. + +2024-02-02 Jason Merrill + + PR c++/113638 + * g++.dg/cpp1y/var-templ-array1.C: New test. + +2024-02-02 Juzhe-Zhong + + * gcc.target/riscv/rvv/vsetvl/vsetvl_pre-1.c: New test. + +2024-02-02 Jiahao Xu + + * gcc.target/loongarch/larch-frecipe-intrinsic.c: New test. + +2024-02-02 Li Wei + + * gfortran.dg/vect/vect-10.f90: New test. + +2024-02-02 Xi Ruoyao + + * gcc.target/loongarch/func-call-extreme-1.c (dg-options): + Use -O2 instead of -O0 to ensure the pcalau12i/addi/lu32i/lu52i + instruction sequences are not reordered by the compiler. + (NOIPA): Disallow interprocedural optimizations. + * gcc.target/loongarch/func-call-extreme-2.c: Remove the content + duplicated from func-call-extreme-1.c, include it instead. + (dg-options): Likewise. + * gcc.target/loongarch/func-call-extreme-3.c (dg-options): + Likewise. + * gcc.target/loongarch/func-call-extreme-4.c (dg-options): + Likewise. + * gcc.target/loongarch/cmodel-extreme-1.c: New test. + * gcc.target/loongarch/cmodel-extreme-2.c: New test. + * g++.target/loongarch/cmodel-extreme-mi-thunk-1.C: New test. + * g++.target/loongarch/cmodel-extreme-mi-thunk-2.C: New test. + * g++.target/loongarch/cmodel-extreme-mi-thunk-3.C: New test. + +2024-02-02 Lulu Cheng + + * gcc.target/loongarch/explicit-relocs-medium-call36-auto-tls-ld-gd.c: New test. + +2024-02-02 Lulu Cheng + + * gcc.target/loongarch/explicit-relocs-extreme-auto-tls-ld-gd.c: New test. + * gcc.target/loongarch/explicit-relocs-medium-auto-tls-ld-gd.c: New test. + +2024-02-02 Lulu Cheng + + * gcc.target/loongarch/attr-model-5.c: New test. + * gcc.target/loongarch/func-call-extreme-5.c: New test. + * gcc.target/loongarch/func-call-extreme-6.c: New test. + * gcc.target/loongarch/tls-extreme-macro.c: New test. + 2024-02-01 Marek Polacek * g++.dg/warn/Wdangling-reference21.C: New test. -- cgit v1.1 From 854b8555bd49ad97c336b8df7098e725dc196e4f Mon Sep 17 00:00:00 2001 From: Xi Ruoyao Date: Fri, 2 Feb 2024 05:37:38 +0800 Subject: LoongArch: Fix an ODR violation When bootstrapping GCC 14 with --with-build-config=bootstrap-lto, an ODR violation is detected: ../../gcc/config/loongarch/loongarch-opts.cc:57: warning: 'abi_minimal_isa' violates the C++ One Definition Rule [-Wodr] 57 | abi_minimal_isa[N_ABI_BASE_TYPES][N_ABI_EXT_TYPES]; ../../gcc/config/loongarch/loongarch-def.cc:186: note: 'abi_minimal_isa' was previously declared here 186 | abi_minimal_isa = array, ../../gcc/config/loongarch/loongarch-def.cc:186: note: code may be misoptimized unless '-fno-strict-aliasing' is used Fix it by adding a proper declaration of abi_minimal_isa into loongarch-def.h and remove the ODR-violating local declaration in loongarch-opts.cc. gcc/ChangeLog: * config/loongarch/loongarch-def.h (abi_minimal_isa): Declare. * config/loongarch/loongarch-opts.cc (abi_minimal_isa): Remove the ODR-violating locale declaration. --- gcc/config/loongarch/loongarch-def.h | 3 +++ gcc/config/loongarch/loongarch-opts.cc | 2 -- 2 files changed, 3 insertions(+), 2 deletions(-) (limited to 'gcc') diff --git a/gcc/config/loongarch/loongarch-def.h b/gcc/config/loongarch/loongarch-def.h index a1237ec..2dbf006 100644 --- a/gcc/config/loongarch/loongarch-def.h +++ b/gcc/config/loongarch/loongarch-def.h @@ -203,5 +203,8 @@ extern loongarch_def_array loongarch_cpu_align; extern loongarch_def_array loongarch_cpu_rtx_cost_data; +extern loongarch_def_array< + loongarch_def_array, + N_ABI_BASE_TYPES> abi_minimal_isa; #endif /* LOONGARCH_DEF_H */ diff --git a/gcc/config/loongarch/loongarch-opts.cc b/gcc/config/loongarch/loongarch-opts.cc index b872995..7eeac43 100644 --- a/gcc/config/loongarch/loongarch-opts.cc +++ b/gcc/config/loongarch/loongarch-opts.cc @@ -53,8 +53,6 @@ static const int tm_multilib_list[] = { TM_MULTILIB_LIST }; static int enabled_abi_types[N_ABI_BASE_TYPES][N_ABI_EXT_TYPES] = { 0 }; #define isa_required(ABI) (abi_minimal_isa[(ABI).base][(ABI).ext]) -extern "C" const struct loongarch_isa -abi_minimal_isa[N_ABI_BASE_TYPES][N_ABI_EXT_TYPES]; static inline int is_multilib_enabled (struct loongarch_abi abi) -- cgit v1.1 From 51c4eb28c192ecff4463c973a0ff089e04a80b89 Mon Sep 17 00:00:00 2001 From: Iain Buclaw Date: Sun, 28 Jan 2024 12:23:14 +0100 Subject: d: Merge dmd. druntime e770945277, phobos 6d6e0b9b9 D front-end changes: - Import latest fixes from dmd v2.107.0-beta.1. - Hex strings can now be cast to integer arrays. - Add support for Interpolated Expression Sequences. D runtime changes: - Import latest fixes from druntime v2.107.0-beta.1. - New core.interpolation module to provide run-time support for D interpolated expression sequence literals. Phobos changes: - Import latest fixes from phobos v2.107.0-beta.1. - `std.range.primitives.isBidirectionalRange', and `std.range.primitives.isRandomAccessRange' now take an optional element type. gcc/d/ChangeLog: * dmd/MERGE: Merge upstream dmd e770945277. * Make-lang.in (D_FRONTEND_OBJS): Add d/basicmangle.o, d/enumsem.o, d/funcsem.o, d/templatesem.o. * d-builtins.cc (build_frontend_type): Update for new front-end interface. * d-codegen.cc (declaration_type): Likewise. (parameter_type): Likewise. * d-incpath.cc (add_globalpaths): Likewise. (add_filepaths): Likewise. (add_import_paths): Likewise. * d-lang.cc (d_init_options): Likewise. (d_handle_option): Likewise. (d_parse_file): Likewise. * decl.cc (DeclVisitor::finish_vtable): Likewise. (DeclVisitor::visit (FuncDeclaration *)): Likewise. (get_symbol_decl): Likewise. * expr.cc (ExprVisitor::visit (StringExp *)): Likewise. Implement support for 8-byte hexadecimal strings. * typeinfo.cc (create_tinfo_types): Update internal TypeInfo representation. (TypeInfoVisitor::visit (TypeInfoConstDeclaration *)): Update for new front-end interface. (TypeInfoVisitor::visit (TypeInfoInvariantDeclaration *)): Likewise. (TypeInfoVisitor::visit (TypeInfoSharedDeclaration *)): Likewise. (TypeInfoVisitor::visit (TypeInfoWildDeclaration *)): Likewise. (TypeInfoVisitor::visit (TypeInfoClassDeclaration *)): Move data for TypeInfo_Class.nameSig to the end of the object. (create_typeinfo): Update for new front-end interface. libphobos/ChangeLog: * libdruntime/MERGE: Merge upstream druntime e770945277. * libdruntime/Makefile.am (DRUNTIME_SOURCES): Add core/interpolation.d. * libdruntime/Makefile.in: Regenerate. * src/MERGE: Merge upstream phobos 6d6e0b9b9. --- gcc/d/Make-lang.in | 4 + gcc/d/d-builtins.cc | 2 +- gcc/d/d-codegen.cc | 4 +- gcc/d/d-incpath.cc | 41 +- gcc/d/d-lang.cc | 34 +- gcc/d/decl.cc | 37 +- gcc/d/dmd/MERGE | 2 +- gcc/d/dmd/README.md | 4 + gcc/d/dmd/aggregate.h | 3 +- gcc/d/dmd/basicmangle.d | 109 ++ gcc/d/dmd/clone.d | 9 +- gcc/d/dmd/common/outbuffer.d | 27 + gcc/d/dmd/cond.d | 19 +- gcc/d/dmd/constfold.d | 6 +- gcc/d/dmd/ctfeexpr.d | 10 +- gcc/d/dmd/dclass.d | 2 + gcc/d/dmd/declaration.h | 7 +- gcc/d/dmd/denum.d | 85 - gcc/d/dmd/dinterpret.d | 68 +- gcc/d/dmd/dmangle.d | 144 +- gcc/d/dmd/dmodule.d | 6 +- gcc/d/dmd/doc.d | 3 +- gcc/d/dmd/dstruct.d | 2 +- gcc/d/dmd/dsymbolsem.d | 574 +------ gcc/d/dmd/dtemplate.d | 1646 ++------------------ gcc/d/dmd/enum.h | 2 - gcc/d/dmd/enumsem.d | 714 +++++++++ gcc/d/dmd/expression.d | 44 +- gcc/d/dmd/expression.h | 15 +- gcc/d/dmd/expressionsem.d | 103 +- gcc/d/dmd/func.d | 199 +-- gcc/d/dmd/funcsem.d | 219 +++ gcc/d/dmd/globals.d | 12 +- gcc/d/dmd/globals.h | 12 +- gcc/d/dmd/hdrgen.d | 84 + gcc/d/dmd/id.d | 6 + gcc/d/dmd/json.d | 14 +- gcc/d/dmd/lexer.d | 166 +- gcc/d/dmd/mtype.d | 56 +- gcc/d/dmd/mtype.h | 2 +- gcc/d/dmd/parse.d | 9 + gcc/d/dmd/parsetimevisitor.d | 1 + gcc/d/dmd/res/default_ddoc_theme.ddoc | 8 +- gcc/d/dmd/root/filename.d | 67 +- gcc/d/dmd/root/filename.h | 2 +- gcc/d/dmd/semantic3.d | 3 +- gcc/d/dmd/statementsem.d | 3 +- gcc/d/dmd/templatesem.d | 1497 ++++++++++++++++++ gcc/d/dmd/tokens.d | 33 +- gcc/d/dmd/tokens.h | 9 +- gcc/d/dmd/traits.d | 3 +- gcc/d/dmd/typesem.d | 26 +- gcc/d/dmd/typinf.d | 1 + gcc/d/dmd/visitor.h | 2 + gcc/d/expr.cc | 18 +- gcc/d/typeinfo.cc | 35 +- gcc/testsuite/gdc.test/compilable/test13281.d | 33 +- gcc/testsuite/gdc.test/fail_compilation/b19523.d | 11 +- gcc/testsuite/gdc.test/fail_compilation/b20011.d | 23 +- gcc/testsuite/gdc.test/fail_compilation/bug15613.d | 15 +- gcc/testsuite/gdc.test/fail_compilation/bug16165.d | 6 +- gcc/testsuite/gdc.test/fail_compilation/bug9631.d | 26 +- .../gdc.test/fail_compilation/callconst.d | 5 +- .../gdc.test/fail_compilation/constraints_aggr.d | 4 +- .../gdc.test/fail_compilation/constraints_func1.d | 26 +- .../gdc.test/fail_compilation/constraints_func2.d | 28 +- .../gdc.test/fail_compilation/constraints_func3.d | 12 +- .../gdc.test/fail_compilation/constraints_func4.d | 12 +- .../gdc.test/fail_compilation/diag13942.d | 2 +- .../gdc.test/fail_compilation/diag16977.d | 2 +- .../gdc.test/fail_compilation/diag20268.d | 2 +- .../gdc.test/fail_compilation/diag23355.d | 4 +- gcc/testsuite/gdc.test/fail_compilation/diag8101.d | 53 +- gcc/testsuite/gdc.test/fail_compilation/diag8648.d | 6 +- gcc/testsuite/gdc.test/fail_compilation/diag9004.d | 2 +- gcc/testsuite/gdc.test/fail_compilation/diagin.d | 9 +- .../gdc.test/fail_compilation/fail12744.d | 4 +- gcc/testsuite/gdc.test/fail_compilation/fail136.d | 2 +- .../gdc.test/fail_compilation/fail14669.d | 2 +- gcc/testsuite/gdc.test/fail_compilation/fail162.d | 2 +- .../gdc.test/fail_compilation/fail19948.d | 5 +- .../gdc.test/fail_compilation/fail20183.d | 3 +- .../gdc.test/fail_compilation/fail20730b.d | 2 +- .../gdc.test/fail_compilation/fail20800.d | 9 +- .../gdc.test/fail_compilation/fail22202.d | 5 +- gcc/testsuite/gdc.test/fail_compilation/fail236.d | 2 +- .../gdc.test/fail_compilation/fail24301.d | 5 +- gcc/testsuite/gdc.test/fail_compilation/fail263.d | 9 +- gcc/testsuite/gdc.test/fail_compilation/fail322.d | 14 +- gcc/testsuite/gdc.test/fail_compilation/fail332.d | 50 +- gcc/testsuite/gdc.test/fail_compilation/fail58.d | 14 +- gcc/testsuite/gdc.test/fail_compilation/fail8009.d | 2 +- gcc/testsuite/gdc.test/fail_compilation/fail95.d | 2 +- .../gdc.test/fail_compilation/hexstring.d | 57 +- gcc/testsuite/gdc.test/fail_compilation/ice10922.d | 5 +- .../gdc.test/fail_compilation/ice11856_1.d | 6 +- gcc/testsuite/gdc.test/fail_compilation/ice12501.d | 16 +- gcc/testsuite/gdc.test/fail_compilation/ice14130.d | 2 +- gcc/testsuite/gdc.test/fail_compilation/ice14907.d | 6 +- gcc/testsuite/gdc.test/fail_compilation/ice14923.d | 11 +- gcc/testsuite/gdc.test/fail_compilation/ice23097.d | 9 +- gcc/testsuite/gdc.test/fail_compilation/ice6538.d | 2 +- gcc/testsuite/gdc.test/fail_compilation/ice9284.d | 2 +- gcc/testsuite/gdc.test/fail_compilation/ice9540.d | 11 +- .../fail_compilation/iconv_interface_array.d | 51 + .../interpolatedexpressionsequence_postfix.d | 13 + .../fail_compilation/named_arguments_error.d | 37 +- .../gdc.test/fail_compilation/previewin.d | 13 +- .../gdc.test/fail_compilation/pull12941.d | 6 +- .../gdc.test/fail_compilation/test19107.d | 2 +- .../gdc.test/fail_compilation/test19971.d | 7 +- .../gdc.test/fail_compilation/test21008.d | 9 +- .../gdc.test/fail_compilation/test21025.d | 2 +- .../gdc.test/fail_compilation/test21807.d | 3 +- gcc/testsuite/gdc.test/fail_compilation/ufcs.d | 23 +- gcc/testsuite/gdc.test/fail_compilation/vararg2.d | 10 +- .../runnable/interpolatedexpressionsequence.d | 51 + gcc/testsuite/gdc.test/runnable/literal.d | 22 + 118 files changed, 4012 insertions(+), 2990 deletions(-) create mode 100644 gcc/d/dmd/basicmangle.d create mode 100644 gcc/d/dmd/enumsem.d create mode 100644 gcc/d/dmd/funcsem.d create mode 100644 gcc/d/dmd/templatesem.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/iconv_interface_array.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/interpolatedexpressionsequence_postfix.d create mode 100644 gcc/testsuite/gdc.test/runnable/interpolatedexpressionsequence.d (limited to 'gcc') diff --git a/gcc/d/Make-lang.in b/gcc/d/Make-lang.in index f0a03a1..176105b 100644 --- a/gcc/d/Make-lang.in +++ b/gcc/d/Make-lang.in @@ -87,6 +87,7 @@ D_FRONTEND_OBJS = \ d/ast_node.o \ d/astcodegen.o \ d/astenums.o \ + d/basicmangle.o \ d/blockexit.o \ d/builtin.o \ d/canthrow.o \ @@ -122,6 +123,7 @@ D_FRONTEND_OBJS = \ d/dtoh.o \ d/dversion.o \ d/entity.o \ + d/enumsem.o \ d/errors.o \ d/errorsink.o \ d/escape.o \ @@ -130,6 +132,7 @@ D_FRONTEND_OBJS = \ d/file_manager.o \ d/foreachvar.o \ d/func.o \ + d/funcsem.o \ d/globals.o \ d/gluelayer.o \ d/hdrgen.o \ @@ -192,6 +195,7 @@ D_FRONTEND_OBJS = \ d/stmtstate.o \ d/target.o \ d/templateparamsem.o \ + d/templatesem.o \ d/tokens.o \ d/traits.o \ d/transitivevisitor.o \ diff --git a/gcc/d/d-builtins.cc b/gcc/d/d-builtins.cc index 9d60497..1b5b3be 100644 --- a/gcc/d/d-builtins.cc +++ b/gcc/d/d-builtins.cc @@ -240,7 +240,7 @@ build_frontend_type (tree type) sdecl->sizeok = Sizeok::done; sdecl->type = (TypeStruct::create (sdecl))->addMod (mod); sdecl->type->ctype = type; - sdecl->type->merge2 (); + merge2 (sdecl->type); /* Add both named and anonymous fields as members of the struct. Anonymous fields still need a name in D, so call them "__pad%u". */ diff --git a/gcc/d/d-codegen.cc b/gcc/d/d-codegen.cc index 22005a4..af938dd 100644 --- a/gcc/d/d-codegen.cc +++ b/gcc/d/d-codegen.cc @@ -150,7 +150,7 @@ declaration_type (Declaration *decl) TypeFunction *tf = TypeFunction::create (NULL, decl->type, VARARGnone, LINK::d); TypeDelegate *t = TypeDelegate::create (tf); - return build_ctype (t->merge2 ()); + return build_ctype (merge2 (t)); } /* Static array va_list have array->pointer conversions applied. */ @@ -200,7 +200,7 @@ parameter_type (Parameter *arg) TypeFunction *tf = TypeFunction::create (NULL, arg->type, VARARGnone, LINK::d); TypeDelegate *t = TypeDelegate::create (tf); - return build_ctype (t->merge2 ()); + return build_ctype (merge2 (t)); } /* Static array va_list have array->pointer conversions applied. */ diff --git a/gcc/d/d-incpath.cc b/gcc/d/d-incpath.cc index e505f4e..32ab0b7 100644 --- a/gcc/d/d-incpath.cc +++ b/gcc/d/d-incpath.cc @@ -71,9 +71,6 @@ add_globalpaths (Strings *paths) { if (paths) { - if (!global.path) - global.path = d_gc_malloc (); - for (size_t i = 0; i < paths->length; i++) { const char *path = (*paths)[i]; @@ -86,7 +83,7 @@ add_globalpaths (Strings *paths) continue; } - global.path->push (target); + global.path.push (target); } } } @@ -98,9 +95,6 @@ add_filepaths (Strings *paths) { if (paths) { - if (!global.filePath) - global.filePath = d_gc_malloc (); - for (size_t i = 0; i < paths->length; i++) { const char *path = (*paths)[i]; @@ -112,7 +106,7 @@ add_filepaths (Strings *paths) continue; } - global.filePath->push (target); + global.filePath.push (target); } } } @@ -143,9 +137,9 @@ add_import_paths (const char *iprefix, const char *imultilib, bool stdinc) /* Ignore duplicate entries. */ bool found = false; - for (size_t i = 0; i < global.params.imppath->length; i++) + for (size_t i = 0; i < global.params.imppath.length; i++) { - if (strcmp (path, (*global.params.imppath)[i]) == 0) + if (strcmp (path, global.params.imppath[i]) == 0) { found = true; break; @@ -162,33 +156,26 @@ add_import_paths (const char *iprefix, const char *imultilib, bool stdinc) if (imultilib) { char *target_path = concat (path, "/", imultilib, NULL); - global.params.imppath->shift (target_path); + global.params.imppath.shift (target_path); } - global.params.imppath->shift (path); + global.params.imppath.shift (path); } } /* Add import search paths. */ - if (global.params.imppath) + for (size_t i = 0; i < global.params.imppath.length; i++) { - for (size_t i = 0; i < global.params.imppath->length; i++) - { - const char *path = (*global.params.imppath)[i]; - if (path) - add_globalpaths (FileName::splitPath (path)); - } + const char *path = global.params.imppath[i]; + if (path) + add_globalpaths (FileName::splitPath (path)); } /* Add string import search paths. */ - if (global.params.fileImppath) + for (size_t i = 0; i < global.params.fileImppath.length; i++) { - for (size_t i = 0; i < global.params.fileImppath->length; i++) - { - const char *path = (*global.params.fileImppath)[i]; - if (path) - add_filepaths (FileName::splitPath (path)); - } + const char *path = global.params.fileImppath[i]; + if (path) + add_filepaths (FileName::splitPath (path)); } } - diff --git a/gcc/d/d-lang.cc b/gcc/d/d-lang.cc index aabe1ad..138a7f9 100644 --- a/gcc/d/d-lang.cc +++ b/gcc/d/d-lang.cc @@ -306,9 +306,6 @@ d_init_options (unsigned int, cl_decoded_option *decoded_options) global.params.v.errorLimit = flag_max_errors; global.params.v.messageStyle = MessageStyle::gnu; - global.params.imppath = d_gc_malloc (); - global.params.fileImppath = d_gc_malloc (); - /* Extra GDC-specific options. */ d_option.fonly = NULL; d_option.multilib = NULL; @@ -724,11 +721,11 @@ d_handle_option (size_t scode, const char *arg, HOST_WIDE_INT value, break; case OPT_I: - global.params.imppath->push (arg); + global.params.imppath.push (arg); break; case OPT_J: - global.params.fileImppath->push (arg); + global.params.fileImppath.push (arg); break; case OPT_MM: @@ -1045,25 +1042,24 @@ d_parse_file (void) { if (global.params.v.verbose) { + /* Dump information about the D compiler and language version. */ message ("binary %s", global.params.argv0.ptr); message ("version %s", global.versionChars ()); - if (global.versionids) + /* Dump all predefined version identifiers. */ + obstack buffer; + gcc_obstack_init (&buffer); + obstack_grow (&buffer, "predefs ", 9); + for (size_t i = 0; i < global.versionids.length; i++) { - obstack buffer; - gcc_obstack_init (&buffer); - obstack_grow (&buffer, "predefs ", 9); - for (size_t i = 0; i < global.versionids->length; i++) - { - Identifier *id = (*global.versionids)[i]; - const char *str = id->toChars (); - obstack_1grow (&buffer, ' '); - obstack_grow (&buffer, str, strlen (str)); - } - - obstack_1grow (&buffer, '\0'); - message ("%s", (char *) obstack_finish (&buffer)); + Identifier *id = global.versionids[i]; + const char *str = id->toChars (); + obstack_1grow (&buffer, ' '); + obstack_grow (&buffer, str, strlen (str)); } + + obstack_1grow (&buffer, '\0'); + message ("%s", (char *) obstack_finish (&buffer)); } /* Start the main input file, if the debug writer wants it. */ diff --git a/gcc/d/decl.cc b/gcc/d/decl.cc index 4ca85bb..d2e84d3 100644 --- a/gcc/d/decl.cc +++ b/gcc/d/decl.cc @@ -539,7 +539,7 @@ public: continue; /* Ensure function has a return value. */ - if (!fd->functionSemantic ()) + if (!functionSemantic (fd)) has_errors = true; /* No name hiding to check for. */ @@ -563,20 +563,23 @@ public: if (fd2->isFuture ()) continue; - if (fd->leastAsSpecialized (fd2, NULL) != MATCH::nomatch - || fd2->leastAsSpecialized (fd, NULL) != MATCH::nomatch) - { - error_at (make_location_t (fd->loc), "use of %qs", - fd->toPrettyChars ()); - inform (make_location_t (fd2->loc), "is hidden by %qs", - fd2->toPrettyChars ()); - inform (make_location_t (d->loc), - "use % to introduce base class " - "overload set", fd->toChars (), - fd->parent->toChars (), fd->toChars ()); - has_errors = true; - break; - } + if (FuncDeclaration::leastAsSpecialized (fd, fd2, NULL) + == MATCH::nomatch + && FuncDeclaration::leastAsSpecialized (fd2, fd, NULL) + == MATCH::nomatch) + continue; + + /* Hiding detected; same name, overlapping specializations. */ + error_at (make_location_t (fd->loc), "use of %qs", + fd->toPrettyChars ()); + inform (make_location_t (fd2->loc), "is hidden by %qs", + fd2->toPrettyChars ()); + inform (make_location_t (d->loc), + "use % to introduce base class " + "overload set", fd->toChars (), + fd->parent->toChars (), fd->toChars ()); + has_errors = true; + break; } } @@ -943,7 +946,7 @@ public: gcc_assert (!doing_semantic_analysis_p); doing_semantic_analysis_p = true; - d->functionSemantic3 (); + functionSemantic3 (d); Module::runDeferredSemantic3 (); doing_semantic_analysis_p = false; } @@ -1231,7 +1234,7 @@ get_symbol_decl (Declaration *decl) if (fd) { /* Run full semantic on functions we need to know about. */ - if (!fd->functionSemantic ()) + if (!functionSemantic (fd)) { decl->csym = error_mark_node; return decl->csym; diff --git a/gcc/d/dmd/MERGE b/gcc/d/dmd/MERGE index 138b0b6..9217c65 100644 --- a/gcc/d/dmd/MERGE +++ b/gcc/d/dmd/MERGE @@ -1,4 +1,4 @@ -bce5c1f7b521d22dcf1ea4e2bc3f76d9d28274fa +e7709452775d374c1e2dfb67566668ada3dec5fc The first line of this file holds the git revision number of the last merge done from the dlang/dmd repository. diff --git a/gcc/d/dmd/README.md b/gcc/d/dmd/README.md index f8ac001..23f3333 100644 --- a/gcc/d/dmd/README.md +++ b/gcc/d/dmd/README.md @@ -110,6 +110,8 @@ Note that these groups have no strict meaning, the category assignments are a bi | File | Purpose | |-------------------------------------------------------------------------------------------|-------------------------------------------------------------------| | [dsymbolsem.d](https://github.com/dlang/dmd/blob/master/compiler/src/dmd/dsymbolsem.d) | Do semantic 1 pass (symbol identifiers/types) | +| [enumsem.d](https://github.com/dlang/dmd/blob/master/compiler/src/dmd/enumsem.d) | Enum semantics | +| [funcsem.d](https://github.com/dlang/dmd/blob/master/compiler/src/dmd/funcsem.d) | Function semantics | | [semantic2.d](https://github.com/dlang/dmd/blob/master/compiler/src/dmd/semantic2.d) | Do semantic 2 pass (symbol initializers) | | [semantic3.d](https://github.com/dlang/dmd/blob/master/compiler/src/dmd/semantic3.d) | Do semantic 3 pass (function bodies) | | [inline.d](https://github.com/dlang/dmd/blob/master/compiler/src/dmd/inline.d) | Do inline pass (optimization pass that dmd does in the front-end) | @@ -117,6 +119,7 @@ Note that these groups have no strict meaning, the category assignments are a bi | [expressionsem.d](https://github.com/dlang/dmd/blob/master/compiler/src/dmd/expressionsem.d) | Do semantic analysis for expressions | | [statementsem.d](https://github.com/dlang/dmd/blob/master/compiler/src/dmd/statementsem.d) | Do semantic analysis for statements | | [initsem.d](https://github.com/dlang/dmd/blob/master/compiler/src/dmd/initsem.d) | Do semantic analysis for initializers | +| [templatesem.d](https://github.com/dlang/dmd/blob/master/compiler/src/dmd/templatesem.d) | Do semantic analysis for templates | | [templateparamsem.d](https://github.com/dlang/dmd/blob/master/compiler/src/dmd/templateparamsem.d) | Do semantic analysis for template parameters | | [typesem.d](https://github.com/dlang/dmd/blob/master/compiler/src/dmd/typesem.d) | Do semantic analysis for types | @@ -230,6 +233,7 @@ Note that these groups have no strict meaning, the category assignments are a bi |-----------------------------------------------------------------------------------|------------------------------------------------------------------| | [cppmangle.d](https://github.com/dlang/dmd/blob/master/compiler/src/dmd/cppmangle.d) | C++ name mangling | | [cppmanglewin.d](https://github.com/dlang/dmd/blob/master/compiler/src/dmd/cppmanglewin.d) | C++ name mangling for Windows | +| [basicmangle.d](https://github.com/dlang/dmd/blob/master/compiler/src/dmd/basicmangle.d) | D name mangling for basic types | | [dmangle.d](https://github.com/dlang/dmd/blob/master/compiler/src/dmd/dmangle.d) | D [name mangling](https://dlang.org/spec/abi.html#name_mangling) | ### Linking diff --git a/gcc/d/dmd/aggregate.h b/gcc/d/dmd/aggregate.h index 9abdd09..f466ba6 100644 --- a/gcc/d/dmd/aggregate.h +++ b/gcc/d/dmd/aggregate.h @@ -234,7 +234,8 @@ struct ClassFlags hasTypeInfo = 0x20, isAbstract = 0x40, isCPPclass = 0x80, - hasDtor = 0x100 + hasDtor = 0x100, + hasNameSig = 0x200, }; }; diff --git a/gcc/d/dmd/basicmangle.d b/gcc/d/dmd/basicmangle.d new file mode 100644 index 0000000..52534fa --- /dev/null +++ b/gcc/d/dmd/basicmangle.d @@ -0,0 +1,109 @@ +/** + * Defines the building blocks for creating the mangled names for basic types. + * + * Copyright: Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved + * License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) + * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/basicmangle.d, _basicmangle.d) + * Documentation: https://dlang.org/phobos/dmd_basicmangle.html + * Coverage: https://codecov.io/gh/dlang/dmd/src/master/src/dmd/basicmangle.d + */ +module dmd.basicmangle; + +import dmd.astenums; +import dmd.common.outbuffer : OutBuffer; + +/// Type mangling mapping for basic, derived and user defined types +immutable char[TMAX] mangleChar = +[ + Tchar : 'a', + Tbool : 'b', + Tcomplex80 : 'c', + Tfloat64 : 'd', + Tfloat80 : 'e', + Tfloat32 : 'f', + Tint8 : 'g', + Tuns8 : 'h', + Tint32 : 'i', + Timaginary80 : 'j', + Tuns32 : 'k', + Tint64 : 'l', + Tuns64 : 'm', + Tnull : 'n', + Timaginary32 : 'o', + Timaginary64 : 'p', + Tcomplex32 : 'q', + Tcomplex64 : 'r', + Tint16 : 's', + Tuns16 : 't', + Twchar : 'u', + Tvoid : 'v', + Tdchar : 'w', + // x // const + // y // immutable + Tint128 : 'z', // zi + Tuns128 : 'z', // zk + + Tarray : 'A', + Ttuple : 'B', + Tclass : 'C', + Tdelegate : 'D', + Tenum : 'E', + Tfunction : 'F', // D function + Tsarray : 'G', + Taarray : 'H', + // I // in + // J // out + // K // ref + // L // lazy + // M // has this, or scope + // N // Nh:vector Ng:wild Nn:noreturn + // O // shared + Tpointer : 'P', + // Q // Type/symbol/identifier backward reference + Treference : 'R', + Tstruct : 'S', + // T // Ttypedef + // U // C function + // W // Windows function + // X // variadic T t...) + // Y // variadic T t,...) + // Z // not variadic, end of parameters + + // '@' shouldn't appear anywhere in the deco'd names + Tnone : '@', + Tident : '@', + Tinstance : '@', + Terror : '@', + Ttypeof : '@', + Tslice : '@', + Treturn : '@', + Tvector : '@', + Ttraits : '@', + Tmixin : '@', + Ttag : '@', + Tnoreturn : '@', // becomes 'Nn' +]; + +unittest +{ + foreach (i, mangle; mangleChar) + { + if (mangle == char.init) + { + import core.stdc.stdio; + fprintf(stderr, "ty = %u\n", cast(uint)i); + assert(0); + } + } +} + +/*********************** + * Mangle basic type ty to buf. + */ +void tyToDecoBuffer(ref OutBuffer buf, int ty) @safe +{ + const c = mangleChar[ty]; + buf.writeByte(c); + if (c == 'z') + buf.writeByte(ty == Tint128 ? 'i' : 'k'); +} diff --git a/gcc/d/dmd/clone.d b/gcc/d/dmd/clone.d index 6fbf8e2..46470ee 100644 --- a/gcc/d/dmd/clone.d +++ b/gcc/d/dmd/clone.d @@ -27,6 +27,7 @@ import dmd.errors; import dmd.expression; import dmd.expressionsem; import dmd.func; +import dmd.funcsem; import dmd.globals; import dmd.id; import dmd.identifier; @@ -905,7 +906,7 @@ void buildDtors(AggregateDeclaration ad, Scope* sc) a.addMember(sc, ad); // temporarily add to symbol table } - sdv.dtor.functionSemantic(); + functionSemantic(sdv.dtor); stc = mergeFuncAttrs(stc, sdv.dtor); if (stc & STC.disable) @@ -1154,7 +1155,7 @@ private DtorDeclaration buildExternDDtor(AggregateDeclaration ad, Scope* sc) ad.members.push(func); func.addMember(sc2, ad); func.dsymbolSemantic(sc2); - func.functionSemantic(); // to infer attributes + functionSemantic(func); // to infer attributes sc2.pop(); return func; @@ -1336,7 +1337,7 @@ FuncDeclaration buildPostBlit(StructDeclaration sd, Scope* sc) // perform semantic on the member postblit in order to // be able to aggregate it later on with the rest of the // postblits - sdv.postblit.functionSemantic(); + functionSemantic(sdv.postblit); stc = mergeFuncAttrs(stc, sdv.postblit); stc = mergeFuncAttrs(stc, sdv.dtor); @@ -1401,7 +1402,7 @@ FuncDeclaration buildPostBlit(StructDeclaration sd, Scope* sc) */ if (sdv.dtor) { - sdv.dtor.functionSemantic(); + functionSemantic(sdv.dtor); // keep a list of fields that need to be destroyed in case // of a future postblit failure diff --git a/gcc/d/dmd/common/outbuffer.d b/gcc/d/dmd/common/outbuffer.d index cff08ec..cb2439f 100644 --- a/gcc/d/dmd/common/outbuffer.d +++ b/gcc/d/dmd/common/outbuffer.d @@ -756,6 +756,25 @@ struct OutBuffer } /** + * Write an array as a string of hexadecimal digits + * Params: + * data = bytes to write + * upperCase = whether to upper case hex digits A-F + */ + void writeHexString(scope const(ubyte)[] data, bool upperCase) pure nothrow @safe + { + auto slice = this.allocate(2 * data.length); + const a = upperCase ? 'A' : 'a'; + foreach (i, c; data) + { + char hi = (c >> 4) & 0xF; + slice[i * 2] = cast(char)(hi < 10 ? hi + '0' : hi - 10 + a); + char lo = c & 0xF; + slice[i * 2 + 1] = cast(char)(lo < 10 ? lo + '0' : lo - 10 + a); + } + } + + /** Destructively saves the contents of `this` to `filename`. As an optimization, if the file already has identical contents with the buffer, no copying is done. This is because on SSD drives reading is often much @@ -943,3 +962,11 @@ unittest else assert(buf[] == "\nabc\n\n"); } + +unittest +{ + OutBuffer buf; + buf.writeHexString([0xAA, 0xBB], false); + buf.writeHexString([0xCC], true); + assert(buf[] == "aabbCC"); +} diff --git a/gcc/d/dmd/cond.d b/gcc/d/dmd/cond.d index 1b32ff7..e194664 100644 --- a/gcc/d/dmd/cond.d +++ b/gcc/d/dmd/cond.d @@ -548,8 +548,6 @@ extern (C++) final class DebugCondition : DVCondition /// Ditto extern(D) static void addGlobalIdent(const(char)[] ident) { - if (!global.debugids) - global.debugids = new Identifiers(); global.debugids.push(Identifier.idPool(ident)); } @@ -579,7 +577,7 @@ extern (C++) final class DebugCondition : DVCondition bool definedInModule = false; if (ident) { - if (findCondition(mod.debugids, ident)) + if (mod.debugids && findCondition(*mod.debugids, ident)) { inc = Include.yes; definedInModule = true; @@ -830,8 +828,6 @@ extern (C++) final class VersionCondition : DVCondition /// Ditto extern(D) static void addPredefinedGlobalIdent(const(char)[] ident) { - if (!global.versionids) - global.versionids = new Identifiers(); global.versionids.push(Identifier.idPool(ident)); } @@ -861,7 +857,7 @@ extern (C++) final class VersionCondition : DVCondition bool definedInModule = false; if (ident) { - if (findCondition(mod.versionids, ident)) + if (mod.versionids && findCondition(*mod.versionids, ident)) { inc = Include.yes; definedInModule = true; @@ -983,15 +979,12 @@ extern (C++) final class StaticIfCondition : Condition * Returns: * true if found */ -bool findCondition(Identifiers* ids, Identifier ident) @safe nothrow pure +bool findCondition(ref Identifiers ids, Identifier ident) @safe nothrow pure { - if (ids) + foreach (id; ids) { - foreach (id; *ids) - { - if (id == ident) - return true; - } + if (id == ident) + return true; } return false; } diff --git a/gcc/d/dmd/constfold.d b/gcc/d/dmd/constfold.d index cee1f63..41fed9c 100644 --- a/gcc/d/dmd/constfold.d +++ b/gcc/d/dmd/constfold.d @@ -711,7 +711,7 @@ UnionExp Equal(EXP op, const ref Loc loc, Type type, Expression e1, Expression e cmp = 1; // if dim1 winds up being 0 foreach (i; 0 .. dim1) { - uinteger_t c = es1.getCodeUnit(i); + uinteger_t c = es1.getIndex(i); auto ee2 = es2[i]; if (ee2.isConst() != 1) { @@ -1119,7 +1119,7 @@ UnionExp Index(Type type, Expression e1, Expression e2, bool indexIsInBounds) } else { - emplaceExp!(IntegerExp)(&ue, loc, es1.getCodeUnit(cast(size_t) i), type); + emplaceExp!(IntegerExp)(&ue, loc, es1.getIndex(cast(size_t) i), type); } } else if (e1.type.toBasetype().ty == Tsarray && e2.op == EXP.int64) @@ -1282,7 +1282,7 @@ void sliceAssignArrayLiteralFromString(ArrayLiteralExp existingAE, const StringE Type elemType = existingAE.type.nextOf(); foreach (j; 0 .. len) { - const val = newval.getCodeUnit(j); + const val = newval.getIndex(j); (*existingAE.elements)[j + firstIndex] = new IntegerExp(newval.loc, val, elemType); } } diff --git a/gcc/d/dmd/ctfeexpr.d b/gcc/d/dmd/ctfeexpr.d index 5fe1e7d..af83aad 100644 --- a/gcc/d/dmd/ctfeexpr.d +++ b/gcc/d/dmd/ctfeexpr.d @@ -568,6 +568,9 @@ StringExp createBlockDuplicatedStringLiteral(UnionExp* pue, const ref Loc loc, T case 4: (cast(dchar*)s)[elemi] = value; break; + case 8: + (cast(ulong*)s)[elemi] = value; + break; default: assert(0); } @@ -1494,7 +1497,7 @@ Expression ctfeIndex(UnionExp* pue, const ref Loc loc, Type type, Expression e1, error(loc, "string index %llu is out of bounds `[0 .. %llu]`", indx, cast(ulong)es1.len); return CTFEExp.cantexp; } - emplaceExp!IntegerExp(pue, loc, es1.getCodeUnit(cast(size_t) indx), type); + emplaceExp!IntegerExp(pue, loc, es1.getIndex(cast(size_t) indx), type); return pue.exp(); } @@ -1704,7 +1707,7 @@ Expression changeArrayLiteralLength(UnionExp* pue, const ref Loc loc, TypeArray void* s = mem.xcalloc(newlen + 1, oldse.sz); const data = oldse.peekData(); memcpy(s, data.ptr, copylen * oldse.sz); - const defaultValue = cast(uint)defaultElem.toInteger(); + const defaultValue = cast(ulong)defaultElem.toInteger(); foreach (size_t elemi; copylen .. newlen) { switch (oldse.sz) @@ -1718,6 +1721,9 @@ Expression changeArrayLiteralLength(UnionExp* pue, const ref Loc loc, TypeArray case 4: (cast(dchar*)s)[cast(size_t)(indxlo + elemi)] = cast(dchar)defaultValue; break; + case 8: + (cast(ulong*)s)[cast(size_t)(indxlo + elemi)] = cast(ulong)defaultValue; + break; default: assert(0); } diff --git a/gcc/d/dmd/dclass.d b/gcc/d/dmd/dclass.d index 405e817..7e5e7e4 100644 --- a/gcc/d/dmd/dclass.d +++ b/gcc/d/dmd/dclass.d @@ -123,6 +123,7 @@ extern (C++) struct BaseClass } } +// These must match the values in druntime/src/object.d enum ClassFlags : uint { none = 0x0, @@ -135,6 +136,7 @@ enum ClassFlags : uint isAbstract = 0x40, isCPPclass = 0x80, hasDtor = 0x100, + hasNameSig = 0x200, } /*********************************************************** diff --git a/gcc/d/dmd/declaration.h b/gcc/d/dmd/declaration.h index 0e327be..e4efbbc 100644 --- a/gcc/d/dmd/declaration.h +++ b/gcc/d/dmd/declaration.h @@ -30,6 +30,9 @@ class StructDeclaration; struct IntRange; struct AttributeViolation; +bool functionSemantic(FuncDeclaration* fd); +bool functionSemantic3(FuncDeclaration* fd); + //enum STC : ulong from astenums.d: #define STCundefined 0ULL @@ -698,14 +701,12 @@ public: FuncDeclaration *fdensure(FuncDeclaration *fde); Expressions *fdrequireParams(Expressions *fdrp); Expressions *fdensureParams(Expressions *fdep); - bool functionSemantic(); - bool functionSemantic3(); bool equals(const RootObject * const o) const override final; int findVtblIndex(Dsymbols *vtbl, int dim); bool overloadInsert(Dsymbol *s) override; bool inUnittest(); - MATCH leastAsSpecialized(FuncDeclaration *g, Identifiers *names); + static MATCH leastAsSpecialized(FuncDeclaration *f, FuncDeclaration *g, Identifiers *names); LabelDsymbol *searchLabel(Identifier *ident, const Loc &loc); const char *toPrettyChars(bool QualifyTypes = false) override; const char *toFullSignature(); // for diagnostics, e.g. 'int foo(int x, int y) pure' diff --git a/gcc/d/dmd/denum.d b/gcc/d/dmd/denum.d index 5464ff9..9abdebd 100644 --- a/gcc/d/dmd/denum.d +++ b/gcc/d/dmd/denum.d @@ -122,91 +122,6 @@ extern (C++) final class EnumDeclaration : ScopeDsymbol return isSpecialEnumIdent(ident) && memtype; } - Expression getDefaultValue(const ref Loc loc) - { - Expression handleErrors(){ - defaultval = ErrorExp.get(); - return defaultval; - } - //printf("EnumDeclaration::getDefaultValue() %p %s\n", this, toChars()); - // https://issues.dlang.org/show_bug.cgi?id=23904 - // Return defaultval only if it is not ErrorExp. - // A speculative context may set defaultval to ErrorExp; - // subsequent non-speculative contexts need to be able - // to print the error. - if (defaultval && !defaultval.isErrorExp()) - return defaultval; - - if (isCsymbol()) - return memtype.defaultInit(loc, true); - - if (_scope) - dsymbolSemantic(this, _scope); - if (errors) - return handleErrors(); - if (!members) - { - if (isSpecial()) - { - /* Allow these special enums to not need a member list - */ - return defaultval = memtype.defaultInit(loc); - } - - error(loc, "%s `%s` is opaque and has no default initializer", kind, toPrettyChars); - return handleErrors(); - } - - foreach (const i; 0 .. members.length) - { - EnumMember em = (*members)[i].isEnumMember(); - if (em) - { - if (em.semanticRun < PASS.semanticdone) - { - error(loc, "%s `%s` forward reference of `%s.init`", kind, toPrettyChars, toChars()); - return handleErrors(); - } - - defaultval = em.value; - return defaultval; - } - } - return handleErrors(); - } - - Type getMemtype(const ref Loc loc) - { - if (_scope) - { - /* Enum is forward referenced. We don't need to resolve the whole thing, - * just the base type - */ - if (memtype) - { - Loc locx = loc.isValid() ? loc : this.loc; - memtype = memtype.typeSemantic(locx, _scope); - } - else - { - // Run semantic to get the type from a possible first member value - dsymbolSemantic(this, _scope); - } - } - if (!memtype) - { - if (!isAnonymous() && (members || semanticRun >= PASS.semanticdone)) - memtype = Type.tint32; - else - { - Loc locx = loc.isValid() ? loc : this.loc; - error(locx, "is forward referenced looking for base type"); - return Type.terror; - } - } - return memtype; - } - override inout(EnumDeclaration) isEnumDeclaration() inout { return this; diff --git a/gcc/d/dmd/dinterpret.d b/gcc/d/dmd/dinterpret.d index a3b38d9..d8069c6 100644 --- a/gcc/d/dmd/dinterpret.d +++ b/gcc/d/dmd/dinterpret.d @@ -33,6 +33,7 @@ import dmd.errors; import dmd.expression; import dmd.expressionsem; import dmd.func; +import dmd.funcsem; import dmd.globals; import dmd.hdrgen; import dmd.id; @@ -440,7 +441,7 @@ private Expression interpretFunction(UnionExp* pue, FuncDeclaration fd, InterSta fdError("circular dependency. Functions cannot be interpreted while being compiled"); return CTFEExp.cantexp; } - if (!fd.functionSemantic3()) + if (!functionSemantic3(fd)) return CTFEExp.cantexp; if (fd.semanticRun < PASS.semantic3done) { @@ -6097,11 +6098,35 @@ public: result.type = e.to; return; } + // Disallow array type painting, except for conversions between built-in // types of identical size. if ((e.to.ty == Tsarray || e.to.ty == Tarray) && (e1.type.ty == Tsarray || e1.type.ty == Tarray) && !isSafePointerCast(e1.type.nextOf(), e.to.nextOf())) { + auto se = e1.isStringExp(); + // Allow casting a hex string literal to short[], int[] or long[] + if (se && se.hexString && se.postfix == StringExp.NoPostfix) + { + const sz = cast(size_t) e.to.nextOf().size; + if ((se.len % sz) != 0) + { + error(e.loc, "hex string length %d must be a multiple of %d to cast to `%s`", + cast(int) se.len, cast(int) sz, e.to.toChars()); + result = CTFEExp.cantexp; + return; + } + + auto str = arrayCastBigEndian((cast(const ubyte[]) se.peekString()), sz); + emplaceExp!(StringExp)(pue, e1.loc, str, se.len / sz, cast(ubyte) sz); + result = pue.exp(); + result.type = e.to; + return; + } error(e.loc, "array cast from `%s` to `%s` is not supported at compile time", e1.type.toChars(), e.to.toChars()); + if (se && se.hexString && se.postfix != StringExp.NoPostfix) + errorSupplemental(e.loc, "perhaps remove postfix `%s` from hex string", + (cast(char) se.postfix ~ "\0").ptr); + result = CTFEExp.cantexp; return; } @@ -7719,3 +7744,44 @@ private void removeHookTraceImpl(ref CallExp ce, ref FuncDeclaration fd) if (global.params.v.verbose) message("strip %s =>\n %s", oldCE.toChars(), ce.toChars()); } + +/** + * Cast a `ubyte[]` to an array of larger integers as if we are on a big endian architecture + * Params: + * data = array with big endian data + * size = 1 for ubyte[], 2 for ushort[], 4 for uint[], 8 for ulong[] + * Returns: copy of `data`, with bytes shuffled if compiled for `version(LittleEndian)` + */ +ubyte[] arrayCastBigEndian(const ubyte[] data, size_t size) +{ + ubyte[] impl(T)() + { + auto result = new T[](data.length / T.sizeof); + foreach (i; 0 .. result.length) + { + result[i] = 0; + foreach (j; 0 .. T.sizeof) + { + result[i] |= T(data[i * T.sizeof + j]) << ((T.sizeof - 1 - j) * 8); + } + } + return cast(ubyte[]) result; + } + switch (size) + { + case 1: return data.dup; + case 2: return impl!ushort; + case 4: return impl!uint; + case 8: return impl!ulong; + default: assert(0); + } +} + +unittest +{ + ubyte[] data = [0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0xFF, 0x11, 0x22]; + assert(cast(ulong[]) arrayCastBigEndian(data, 8) == [0xAABBCCDDEEFF1122]); + assert(cast(uint[]) arrayCastBigEndian(data, 4) == [0xAABBCCDD, 0xEEFF1122]); + assert(cast(ushort[]) arrayCastBigEndian(data, 2) == [0xAABB, 0xCCDD, 0xEEFF, 0x1122]); + assert(cast(ubyte[]) arrayCastBigEndian(data, 1) == data); +} diff --git a/gcc/d/dmd/dmangle.d b/gcc/d/dmd/dmangle.d index 15b77ea..5bd1379 100644 --- a/gcc/d/dmd/dmangle.d +++ b/gcc/d/dmd/dmangle.d @@ -137,6 +137,7 @@ import core.stdc.string; import dmd.aggregate; import dmd.arraytypes; import dmd.astenums; +import dmd.basicmangle; import dmd.dclass; import dmd.declaration; import dmd.dinterpret; @@ -161,89 +162,6 @@ import dmd.target; import dmd.tokens; import dmd.visitor; -private immutable char[TMAX] mangleChar = -[ - Tchar : 'a', - Tbool : 'b', - Tcomplex80 : 'c', - Tfloat64 : 'd', - Tfloat80 : 'e', - Tfloat32 : 'f', - Tint8 : 'g', - Tuns8 : 'h', - Tint32 : 'i', - Timaginary80 : 'j', - Tuns32 : 'k', - Tint64 : 'l', - Tuns64 : 'm', - Tnull : 'n', - Timaginary32 : 'o', - Timaginary64 : 'p', - Tcomplex32 : 'q', - Tcomplex64 : 'r', - Tint16 : 's', - Tuns16 : 't', - Twchar : 'u', - Tvoid : 'v', - Tdchar : 'w', - // x // const - // y // immutable - Tint128 : 'z', // zi - Tuns128 : 'z', // zk - - Tarray : 'A', - Ttuple : 'B', - Tclass : 'C', - Tdelegate : 'D', - Tenum : 'E', - Tfunction : 'F', // D function - Tsarray : 'G', - Taarray : 'H', - // I // in - // J // out - // K // ref - // L // lazy - // M // has this, or scope - // N // Nh:vector Ng:wild Nn:noreturn - // O // shared - Tpointer : 'P', - // Q // Type/symbol/identifier backward reference - Treference : 'R', - Tstruct : 'S', - // T // Ttypedef - // U // C function - // W // Windows function - // X // variadic T t...) - // Y // variadic T t,...) - // Z // not variadic, end of parameters - - // '@' shouldn't appear anywhere in the deco'd names - Tnone : '@', - Tident : '@', - Tinstance : '@', - Terror : '@', - Ttypeof : '@', - Tslice : '@', - Treturn : '@', - Tvector : '@', - Ttraits : '@', - Tmixin : '@', - Ttag : '@', - Tnoreturn : '@', // becomes 'Nn' -]; - -unittest -{ - foreach (i, mangle; mangleChar) - { - if (mangle == char.init) - { - fprintf(stderr, "ty = %u\n", cast(uint)i); - assert(0); - } - } -} - /************************************************ * Append the mangling of type `t` to `buf`. * Params: @@ -584,6 +502,20 @@ public: toBuffer(*buf, id.toString(), s); } + void mangleInteger(dinteger_t v) + { + if (cast(sinteger_t) v < 0) + { + buf.writeByte('N'); + buf.print(-v); + } + else + { + buf.writeByte('i'); + buf.print(v); + } + } + //////////////////////////////////////////////////////////////////////////// void mangleDecl(Declaration sthis) { @@ -991,17 +923,7 @@ public: override void visit(IntegerExp e) { - const v = e.toInteger(); - if (cast(sinteger_t)v < 0) - { - buf.writeByte('N'); - buf.print(-v); - } - else - { - buf.writeByte('i'); - buf.print(v); - } + mangleInteger(e.toInteger()); } override void visit(RealExp e) @@ -1028,6 +950,7 @@ public: char m; OutBuffer tmp; const(char)[] q; + /* Write string in UTF-8 format */ switch (e.sz) @@ -1065,7 +988,15 @@ public: q = tmp[]; break; } - + case 8: + // String of size 8 has to be hexstring cast to long[], mangle as array literal + buf.writeByte('A'); + buf.print(e.len); + foreach (i; 0 .. e.len) + { + mangleInteger(e.getIndex(i)); + } + return; default: assert(0); } @@ -1073,14 +1004,7 @@ public: buf.writeByte(m); buf.print(q.length); buf.writeByte('_'); // nbytes <= 11 - auto slice = buf.allocate(2 * q.length); - foreach (i, c; q) - { - char hi = (c >> 4) & 0xF; - slice[i * 2] = cast(char)(hi < 10 ? hi + '0' : hi - 10 + 'a'); - char lo = c & 0xF; - slice[i * 2 + 1] = cast(char)(lo < 10 ? lo + '0' : lo - 10 + 'a'); - } + buf.writeHexString(cast(const(ubyte)[]) q, false); } override void visit(ArrayLiteralExp e) @@ -1168,6 +1092,7 @@ private struct Backref { if (t.isFunction_Delegate_PtrToFunction()) { + import dmd.typesem : merge2; t = t.merge2(); } } @@ -1213,19 +1138,6 @@ private struct Backref AssocArray!(Identifier, size_t) idents; /// Identifier => (offset+1) in buf } - -/*********************** - * Mangle basic type ty to buf. - */ - -private void tyToDecoBuffer(ref OutBuffer buf, int ty) @safe -{ - const c = mangleChar[ty]; - buf.writeByte(c); - if (c == 'z') - buf.writeByte(ty == Tint128 ? 'i' : 'k'); -} - /********************************* * Mangling for mod. */ diff --git a/gcc/d/dmd/dmodule.d b/gcc/d/dmd/dmodule.d index 59d4065..6167e2a 100644 --- a/gcc/d/dmd/dmodule.d +++ b/gcc/d/dmd/dmodule.d @@ -490,7 +490,7 @@ extern (C++) final class Module : Package extern (D) static const(char)[] find(const(char)[] filename) { - return global.fileManager.lookForSourceFile(filename, global.path ? (*global.path)[] : null); + return global.fileManager.lookForSourceFile(filename, global.path[]); } extern (C++) static Module load(const ref Loc loc, Identifiers* packages, Identifier ident) @@ -644,9 +644,9 @@ extern (C++) final class Module : Package { /* Print path */ - if (global.path) + if (global.path.length) { - foreach (i, p; *global.path) + foreach (i, p; global.path[]) fprintf(stderr, "import path[%llu] = %s\n", cast(ulong)i, p); } else diff --git a/gcc/d/dmd/doc.d b/gcc/d/dmd/doc.d index ec3cc91..bcf358c 100644 --- a/gcc/d/dmd/doc.d +++ b/gcc/d/dmd/doc.d @@ -5204,6 +5204,7 @@ void highlightCode2(Scope* sc, Dsymbols* a, ref OutBuffer buf, size_t offset) highlight = "$(D_COMMENT "; break; case TOK.string_: + case TOK.interpolated: highlight = "$(D_STRING "; break; default: @@ -5216,7 +5217,7 @@ void highlightCode2(Scope* sc, Dsymbols* a, ref OutBuffer buf, size_t offset) res.writestring(highlight); size_t o = res.length; highlightCode3(sc, res, tok.ptr, lex.p); - if (tok.value == TOK.comment || tok.value == TOK.string_) + if (tok.value == TOK.comment || tok.value == TOK.string_ || tok.value == TOK.interpolated) /* https://issues.dlang.org/show_bug.cgi?id=7656 * https://issues.dlang.org/show_bug.cgi?id=7715 * https://issues.dlang.org/show_bug.cgi?id=10519 diff --git a/gcc/d/dmd/dstruct.d b/gcc/d/dmd/dstruct.d index 5683d5f..7546fb6 100644 --- a/gcc/d/dmd/dstruct.d +++ b/gcc/d/dmd/dstruct.d @@ -616,7 +616,7 @@ bool _isZeroInit(Expression exp) foreach (i; 0 .. se.len) { - if (se.getCodeUnit(i)) + if (se.getIndex(i) != 0) return false; } return true; diff --git a/gcc/d/dmd/dsymbolsem.d b/gcc/d/dmd/dsymbolsem.d index e9cdb94..658beaf 100644 --- a/gcc/d/dmd/dsymbolsem.d +++ b/gcc/d/dmd/dsymbolsem.d @@ -38,11 +38,13 @@ import dmd.dstruct; import dmd.dsymbol; import dmd.dtemplate; import dmd.dversion; +import dmd.enumsem; import dmd.errors; import dmd.escape; import dmd.expression; import dmd.expressionsem; import dmd.func; +import dmd.funcsem; import dmd.globals; import dmd.id; import dmd.identifier; @@ -440,6 +442,15 @@ private bool checkDeprecatedAliasThis(AliasThis at, const ref Loc loc, Scope* sc return false; } +// Save the scope and defer semantic analysis on the Dsymbol. +void deferDsymbolSemantic(Scope* sc, Dsymbol s, Scope *scx) +{ + s._scope = scx ? scx : sc.copy(); + s._scope.setNoFree(); + Module.addDeferredSemantic(s); +} + + private extern(C++) final class DsymbolSemanticVisitor : Visitor { alias visit = Visitor.visit; @@ -450,14 +461,6 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor this.sc = sc; } - // Save the scope and defer semantic analysis on the Dsymbol. - private void deferDsymbolSemantic(Dsymbol s, Scope *scx) - { - s._scope = scx ? scx : sc.copy(); - s._scope.setNoFree(); - Module.addDeferredSemantic(s); - } - override void visit(Dsymbol dsym) { .error(dsym.loc, "%s `%s` %p has no semantic routine", dsym.kind, dsym.toPrettyChars, dsym); @@ -2301,543 +2304,12 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor override void visit(EnumDeclaration ed) { - //printf("EnumDeclaration::semantic(sd = %p, '%s') %s\n", sc.scopesym, sc.scopesym.toChars(), ed.toChars()); - //printf("EnumDeclaration::semantic() %p %s\n", ed, ed.toChars()); - if (ed.semanticRun >= PASS.semanticdone) - return; // semantic() already completed - if (ed.semanticRun == PASS.semantic) - { - assert(ed.memtype); - error(ed.loc, "circular reference to enum base type `%s`", ed.memtype.toChars()); - ed.errors = true; - ed.semanticRun = PASS.semanticdone; - return; - } - Scope* scx = null; - if (ed._scope) - { - sc = ed._scope; - scx = ed._scope; // save so we don't make redundant copies - ed._scope = null; - } - - if (!sc) - return; - - ed.parent = sc.parent; - ed.type = ed.type.typeSemantic(ed.loc, sc); - - ed.visibility = sc.visibility; - if (sc.stc & STC.deprecated_) - ed.isdeprecated = true; - ed.userAttribDecl = sc.userAttribDecl; - ed.cppnamespace = sc.namespace; - - ed.semanticRun = PASS.semantic; - UserAttributeDeclaration.checkGNUABITag(ed, sc.linkage); - checkMustUseReserved(ed); - - if (!ed.members && !ed.memtype) // enum ident; - { - ed.semanticRun = PASS.semanticdone; - return; - } - - if (!ed.symtab) - ed.symtab = new DsymbolTable(); - - /* The separate, and distinct, cases are: - * 1. enum { ... } - * 2. enum : memtype { ... } - * 3. enum ident { ... } - * 4. enum ident : memtype { ... } - * 5. enum ident : memtype; - * 6. enum ident; - */ - - if (ed.memtype) - { - ed.memtype = ed.memtype.typeSemantic(ed.loc, sc); - - /* Check to see if memtype is forward referenced - */ - if (auto te = ed.memtype.isTypeEnum()) - { - auto sym = te.toDsymbol(sc).isEnumDeclaration(); - // Special enums like __c_[u]long[long] are fine to forward reference - // see https://issues.dlang.org/show_bug.cgi?id=20599 - if (!sym.isSpecial() && (!sym.memtype || !sym.members || !sym.symtab || sym._scope)) - { - // memtype is forward referenced, so try again later - deferDsymbolSemantic(ed, scx); - //printf("\tdeferring %s\n", toChars()); - ed.semanticRun = PASS.initial; - return; - } - else - // Ensure that semantic is run to detect. e.g. invalid forward references - sym.dsymbolSemantic(sc); - } - if (ed.memtype.ty == Tvoid) - { - .error(ed.loc, "%s `%s` base type must not be `void`", ed.kind, ed.toPrettyChars); - ed.memtype = Type.terror; - } - if (ed.memtype.ty == Terror) - { - ed.errors = true; - // poison all the members - ed.members.foreachDsymbol( (s) { s.errors = true; } ); - ed.semanticRun = PASS.semanticdone; - return; - } - } - - if (!ed.members) // enum ident : memtype; - { - ed.semanticRun = PASS.semanticdone; - return; - } - - if (ed.members.length == 0) - { - .error(ed.loc, "%s `%s enum `%s` must have at least one member", ed.kind, ed.toPrettyChars, ed.toChars()); - ed.errors = true; - ed.semanticRun = PASS.semanticdone; - return; - } - - if (!(sc.flags & SCOPE.Cfile)) // C enum remains incomplete until members are done - ed.semanticRun = PASS.semanticdone; - - version (none) - { - // @@@DEPRECATED_2.110@@@ https://dlang.org/deprecate.html#scope%20as%20a%20type%20constraint - // Deprecated in 2.100 - // Make an error in 2.110 - if (sc.stc & STC.scope_) - deprecation(ed.loc, "`scope` as a type constraint is deprecated. Use `scope` at the usage site."); - } - - Scope* sce; - if (ed.isAnonymous()) - sce = sc; - else - { - sce = sc.push(ed); - sce.parent = ed; - } - sce = sce.startCTFE(); - sce.setNoFree(); // needed for getMaxMinValue() - - /* Each enum member gets the sce scope - */ - ed.members.foreachDsymbol( (s) - { - EnumMember em = s.isEnumMember(); - if (em) - em._scope = sce; - }); - - /* addMember() is not called when the EnumDeclaration appears as a function statement, - * so we have to do what addMember() does and install the enum members in the right symbol - * table - */ - addEnumMembersToSymtab(ed, sc, sc.getScopesym()); - - if (sc.flags & SCOPE.Cfile) - { - /* C11 6.7.2.2 - */ - Type commonType = ed.memtype; - if (!commonType) - commonType = Type.tint32; - ulong nextValue = 0; // C11 6.7.2.2-3 first member value defaults to 0 - - // C11 6.7.2.2-2 value must be representable as an int. - // The sizemask represents all values that int will fit into, - // from 0..uint.max. We want to cover int.min..uint.max. - IntRange ir = IntRange.fromType(commonType); - - void emSemantic(EnumMember em, ref ulong nextValue) - { - static void errorReturn(EnumMember em) - { - em.value = ErrorExp.get(); - em.errors = true; - em.semanticRun = PASS.semanticdone; - } - - em.semanticRun = PASS.semantic; - em.type = commonType; - em._linkage = LINK.c; - em.storage_class |= STC.manifest; - if (em.value) - { - Expression e = em.value; - assert(e.dyncast() == DYNCAST.expression); - - /* To merge the type of e with commonType, add 0 of type commonType - */ - if (!ed.memtype) - e = new AddExp(em.loc, e, new IntegerExp(em.loc, 0, commonType)); - - e = e.expressionSemantic(sc); - e = resolveProperties(sc, e); - e = e.integralPromotions(sc); - e = e.ctfeInterpret(); - if (e.op == EXP.error) - return errorReturn(em); - auto ie = e.isIntegerExp(); - if (!ie) - { - // C11 6.7.2.2-2 - .error(em.loc, "%s `%s` enum member must be an integral constant expression, not `%s` of type `%s`", em.kind, em.toPrettyChars, e.toChars(), e.type.toChars()); - return errorReturn(em); - } - if (ed.memtype && !ir.contains(getIntRange(ie))) - { - // C11 6.7.2.2-2 - .error(em.loc, "%s `%s` enum member value `%s` does not fit in `%s`", em.kind, em.toPrettyChars, e.toChars(), commonType.toChars()); - return errorReturn(em); - } - nextValue = ie.toInteger(); - if (!ed.memtype) - commonType = e.type; - em.value = new IntegerExp(em.loc, nextValue, commonType); - } - else - { - // C11 6.7.2.2-3 add 1 to value of previous enumeration constant - bool first = (em == (*em.ed.members)[0]); - if (!first) - { - Expression max = getProperty(commonType, null, em.loc, Id.max, 0); - if (nextValue == max.toInteger()) - { - .error(em.loc, "%s `%s` initialization with `%s+1` causes overflow for type `%s`", em.kind, em.toPrettyChars, max.toChars(), commonType.toChars()); - return errorReturn(em); - } - nextValue += 1; - } - em.value = new IntegerExp(em.loc, nextValue, commonType); - } - em.type = commonType; - em.semanticRun = PASS.semanticdone; - } - - ed.members.foreachDsymbol( (s) - { - if (EnumMember em = s.isEnumMember()) - emSemantic(em, nextValue); - }); - - if (!ed.memtype) - { - // cast all members to commonType - ed.members.foreachDsymbol( (s) - { - if (EnumMember em = s.isEnumMember()) - { - em.type = commonType; - em.value = em.value.castTo(sc, commonType); - } - }); - } - - ed.memtype = commonType; - ed.semanticRun = PASS.semanticdone; - return; - } - - ed.members.foreachDsymbol( (s) - { - if (EnumMember em = s.isEnumMember()) - em.dsymbolSemantic(em._scope); - }); - //printf("defaultval = %lld\n", defaultval); - - //if (defaultval) printf("defaultval: %s %s\n", defaultval.toChars(), defaultval.type.toChars()); - //printf("members = %s\n", members.toChars()); + enumSemantic(sc, ed); } override void visit(EnumMember em) { - //printf("EnumMember::semantic() %s\n", em.toChars()); - - void errorReturn() - { - em.errors = true; - em.semanticRun = PASS.semanticdone; - } - - if (em.errors || em.semanticRun >= PASS.semanticdone) - return; - if (em.semanticRun == PASS.semantic) - { - .error(em.loc, "%s `%s` circular reference to `enum` member", em.kind, em.toPrettyChars); - return errorReturn(); - } - assert(em.ed); - - em.ed.dsymbolSemantic(sc); - if (em.ed.errors) - return errorReturn(); - if (em.errors || em.semanticRun >= PASS.semanticdone) - return; - - if (em._scope) - sc = em._scope; - if (!sc) - return; - - em.semanticRun = PASS.semantic; - - em.visibility = em.ed.isAnonymous() ? em.ed.visibility : Visibility(Visibility.Kind.public_); - em._linkage = LINK.d; - em.storage_class |= STC.manifest; - - // https://issues.dlang.org/show_bug.cgi?id=9701 - if (em.ed.isAnonymous()) - { - if (em.userAttribDecl) - em.userAttribDecl.userAttribDecl = em.ed.userAttribDecl; - else - em.userAttribDecl = em.ed.userAttribDecl; - } - - // Eval UDA in this same scope. Issues 19344, 20835, 21122 - if (em.userAttribDecl) - { - // Set scope but avoid extra sc.uda attachment inside setScope() - auto inneruda = em.userAttribDecl.userAttribDecl; - em.userAttribDecl.setScope(sc); - em.userAttribDecl.userAttribDecl = inneruda; - em.userAttribDecl.dsymbolSemantic(sc); - } - - // The first enum member is special - bool first = (em == (*em.ed.members)[0]); - - if (em.origType) - { - em.origType = em.origType.typeSemantic(em.loc, sc); - em.type = em.origType; - assert(em.value); // "type id;" is not a valid enum member declaration - } - - if (em.value) - { - Expression e = em.value; - assert(e.dyncast() == DYNCAST.expression); - e = e.expressionSemantic(sc); - e = resolveProperties(sc, e); - e = e.ctfeInterpret(); - if (e.op == EXP.error) - return errorReturn(); - if (first && !em.ed.memtype && !em.ed.isAnonymous()) - { - em.ed.memtype = e.type; - if (em.ed.memtype.ty == Terror) - { - em.ed.errors = true; - return errorReturn(); - } - if (em.ed.memtype.ty != Terror) - { - /* https://issues.dlang.org/show_bug.cgi?id=11746 - * All of named enum members should have same type - * with the first member. If the following members were referenced - * during the first member semantic, their types should be unified. - */ - em.ed.members.foreachDsymbol( (s) - { - EnumMember enm = s.isEnumMember(); - if (!enm || enm == em || enm.semanticRun < PASS.semanticdone || enm.origType) - return; - - //printf("[%d] em = %s, em.semanticRun = %d\n", i, toChars(), em.semanticRun); - Expression ev = enm.value; - ev = ev.implicitCastTo(sc, em.ed.memtype); - ev = ev.ctfeInterpret(); - ev = ev.castTo(sc, em.ed.type); - if (ev.op == EXP.error) - em.ed.errors = true; - enm.value = ev; - }); - - if (em.ed.errors) - { - em.ed.memtype = Type.terror; - return errorReturn(); - } - } - } - - if (em.ed.memtype && !em.origType) - { - e = e.implicitCastTo(sc, em.ed.memtype); - e = e.ctfeInterpret(); - - // save origValue for better json output - em.origValue = e; - - if (!em.ed.isAnonymous()) - { - e = e.castTo(sc, em.ed.type.addMod(e.type.mod)); // https://issues.dlang.org/show_bug.cgi?id=12385 - e = e.ctfeInterpret(); - } - } - else if (em.origType) - { - e = e.implicitCastTo(sc, em.origType); - e = e.ctfeInterpret(); - assert(em.ed.isAnonymous()); - - // save origValue for better json output - em.origValue = e; - } - em.value = e; - } - else if (first) - { - Type t; - if (em.ed.memtype) - t = em.ed.memtype; - else - { - t = Type.tint32; - if (!em.ed.isAnonymous()) - em.ed.memtype = t; - } - const errors = global.startGagging(); - Expression e = new IntegerExp(em.loc, 0, t); - e = e.ctfeInterpret(); - if (global.endGagging(errors)) - { - error(em.loc, "cannot generate 0 value of type `%s` for `%s`", - t.toChars(), em.toChars()); - } - // save origValue for better json output - em.origValue = e; - - if (!em.ed.isAnonymous()) - { - e = e.castTo(sc, em.ed.type); - e = e.ctfeInterpret(); - } - em.value = e; - } - else - { - /* Find the previous enum member, - * and set this to be the previous value + 1 - */ - EnumMember emprev = null; - em.ed.members.foreachDsymbol( (s) - { - if (auto enm = s.isEnumMember()) - { - if (enm == em) - return 1; // found - emprev = enm; - } - return 0; // continue - }); - - assert(emprev); - if (emprev.semanticRun < PASS.semanticdone) // if forward reference - emprev.dsymbolSemantic(emprev._scope); // resolve it - if (emprev.errors) - return errorReturn(); - - auto errors = global.startGagging(); - Expression eprev = emprev.value; - assert(eprev); - // .toHeadMutable() due to https://issues.dlang.org/show_bug.cgi?id=18645 - Type tprev = eprev.type.toHeadMutable().equals(em.ed.type.toHeadMutable()) - ? em.ed.memtype - : eprev.type; - /* - https://issues.dlang.org/show_bug.cgi?id=20777 - Previously this used getProperty, which doesn't consider anything user defined, - this construct does do that and thus fixes the bug. - */ - Expression emax = DotIdExp.create(em.ed.loc, new TypeExp(em.ed.loc, tprev), Id.max); - emax = emax.expressionSemantic(sc); - emax = emax.ctfeInterpret(); - - // check that (eprev != emax) - Expression e = new EqualExp(EXP.equal, em.loc, eprev, emax); - e = e.expressionSemantic(sc); - e = e.ctfeInterpret(); - if (global.endGagging(errors)) - { - // display an introductory error before showing what actually failed - error(em.loc, "cannot check `%s` value for overflow", em.toPrettyChars()); - // rerun to show errors - Expression e2 = DotIdExp.create(em.ed.loc, new TypeExp(em.ed.loc, tprev), Id.max); - e2 = e2.expressionSemantic(sc); - e2 = e2.ctfeInterpret(); - e2 = new EqualExp(EXP.equal, em.loc, eprev, e2); - e2 = e2.expressionSemantic(sc); - e2 = e2.ctfeInterpret(); - } - // now any errors are for generating a value - if (e.toInteger()) - { - auto mt = em.ed.memtype; - if (!mt) - mt = eprev.type; - .error(em.loc, "%s `%s` initialization with `%s.%s+1` causes overflow for type `%s`", em.kind, em.toPrettyChars, - emprev.ed.toChars(), emprev.toChars(), mt.toChars()); - return errorReturn(); - } - errors = global.startGagging(); - // Now set e to (eprev + 1) - e = new AddExp(em.loc, eprev, IntegerExp.literal!1); - e = e.expressionSemantic(sc); - e = e.castTo(sc, eprev.type); - e = e.ctfeInterpret(); - if (global.endGagging(errors)) - { - error(em.loc, "cannot generate value for `%s`", em.toPrettyChars()); - // rerun to show errors - Expression e2 = new AddExp(em.loc, eprev, IntegerExp.literal!1); - e2 = e2.expressionSemantic(sc); - e2 = e2.castTo(sc, eprev.type); - e2 = e2.ctfeInterpret(); - } - // save origValue (without cast) for better json output - if (e.op != EXP.error) // avoid duplicate diagnostics - { - assert(emprev.origValue); - em.origValue = new AddExp(em.loc, emprev.origValue, IntegerExp.literal!1); - em.origValue = em.origValue.expressionSemantic(sc); - em.origValue = em.origValue.ctfeInterpret(); - } - - if (e.op == EXP.error) - return errorReturn(); - if (e.type.isfloating()) - { - // Check that e != eprev (not always true for floats) - Expression etest = new EqualExp(EXP.equal, em.loc, e, eprev); - etest = etest.expressionSemantic(sc); - etest = etest.ctfeInterpret(); - if (etest.toInteger()) - { - .error(em.loc, "%s `%s` has inexact value due to loss of precision", em.kind, em.toPrettyChars); - return errorReturn(); - } - } - em.value = e; - } - if (!em.origType) - em.type = em.value.type; - - assert(em.origValue); - em.semanticRun = PASS.semanticdone; + enumMemberSemantic(sc, em); } override void visit(TemplateDeclaration tempdecl) @@ -3026,7 +2498,7 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor if (tm.semanticRun == PASS.initial) // forward reference had occurred { //printf("forward reference - deferring\n"); - return deferDsymbolSemantic(tm, scx); + return deferDsymbolSemantic(sc, tm, scx); } tm.inst = tm; @@ -3740,7 +3212,7 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor continue; if (cbd.parent && cbd.parent.isTemplateInstance()) { - if (!f2.functionSemantic()) + if (!functionSemantic(f2)) goto Ldone; } may_override = true; @@ -4945,7 +4417,7 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor sc2.pop(); if (log) printf("\tdeferring %s\n", sd.toChars()); - return deferDsymbolSemantic(sd, scx); + return deferDsymbolSemantic(sc, sd, scx); } /* Look for special member functions. @@ -5336,7 +4808,7 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor { // Forward referencee of one or more bases, try again later //printf("\tL%d semantic('%s') failed due to forward references\n", __LINE__, toChars()); - return deferDsymbolSemantic(cldec, scx); + return deferDsymbolSemantic(sc, cldec, scx); } cldec.baseok = Baseok.done; @@ -5446,7 +4918,7 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor if (tc.sym._scope) Module.addDeferredSemantic(tc.sym); //printf("\tL%d semantic('%s') failed due to forward references\n", __LINE__, toChars()); - return deferDsymbolSemantic(cldec, scx); + return deferDsymbolSemantic(sc, cldec, scx); } } @@ -5563,7 +5035,7 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor sc2.pop(); //printf("\tdeferring %s\n", toChars()); - return deferDsymbolSemantic(cldec, scx); + return deferDsymbolSemantic(sc, cldec, scx); } /* Look for special member functions. @@ -5905,7 +5377,7 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor if (idec.baseok == Baseok.none) { // Forward referencee of one or more bases, try again later - return deferDsymbolSemantic(idec, scx); + return deferDsymbolSemantic(sc, idec, scx); } idec.baseok = Baseok.done; @@ -5942,7 +5414,7 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor // Forward referencee of one or more bases, try again later if (tc.sym._scope) Module.addDeferredSemantic(tc.sym); - return deferDsymbolSemantic(idec, scx); + return deferDsymbolSemantic(sc, idec, scx); } } @@ -6281,7 +5753,7 @@ private extern(C++) class AddMemberVisitor : Visitor } else { - if (findCondition(m.debugidsNot, ds.ident)) + if (m.debugidsNot && findCondition(*m.debugidsNot, ds.ident)) { .error(ds.loc, "%s `%s` defined after use", ds.kind, ds.toPrettyChars); ds.errors = true; @@ -6319,7 +5791,7 @@ private extern(C++) class AddMemberVisitor : Visitor } else { - if (findCondition(m.versionidsNot, vs.ident)) + if (m.versionidsNot && findCondition(*m.versionidsNot, vs.ident)) { .error(vs.loc, "%s `%s` defined after use", vs.kind, vs.toPrettyChars); vs.errors = true; diff --git a/gcc/d/dmd/dtemplate.d b/gcc/d/dmd/dtemplate.d index 13cc32f..465ae74 100644 --- a/gcc/d/dmd/dtemplate.d +++ b/gcc/d/dmd/dtemplate.d @@ -60,6 +60,7 @@ import dmd.errorsink; import dmd.expression; import dmd.expressionsem; import dmd.func; +import dmd.funcsem; import dmd.globals; import dmd.hdrgen; import dmd.id; @@ -76,6 +77,7 @@ import dmd.common.outbuffer; import dmd.rootobject; import dmd.semantic2; import dmd.semantic3; +import dmd.templatesem; import dmd.tokens; import dmd.typesem; import dmd.visitor; @@ -373,7 +375,7 @@ Lnomatch: /************************************ * Match an array of them. */ -private bool arrayObjectMatch(ref Objects oa1, ref Objects oa2) +bool arrayObjectMatch(ref Objects oa1, ref Objects oa2) { if (&oa1 == &oa2) return true; @@ -586,9 +588,9 @@ extern (C++) final class TemplateDeclaration : ScopeDsymbol // threaded list of previous instantiation attempts on stack TemplatePrevious* previous; - private Expression lastConstraint; /// the constraint after the last failed evaluation - private Array!Expression lastConstraintNegs; /// its negative parts - private Objects* lastConstraintTiargs; /// template instance arguments for `lastConstraint` + Expression lastConstraint; /// the constraint after the last failed evaluation + Array!Expression lastConstraintNegs; /// its negative parts + Objects* lastConstraintTiargs; /// template instance arguments for `lastConstraint` extern (D) this(const ref Loc loc, Identifier ident, TemplateParameters* parameters, Expression constraint, Dsymbols* decldefs, bool ismixin = false, bool literal = false) { @@ -743,1545 +745,75 @@ extern (C++) final class TemplateDeclaration : ScopeDsymbol override const(char)* toChars() const { - return toCharsMaybeConstraints(true); - } - - /**************************** - * Similar to `toChars`, but does not print the template constraints - */ - const(char)* toCharsNoConstraints() const - { - return toCharsMaybeConstraints(false); - } - - // Note: this function is not actually `const`, because iterating the - // function parameter list may run dsymbolsemantic on enum types - const(char)* toCharsMaybeConstraints(bool includeConstraints) const - { - OutBuffer buf; - HdrGenState hgs; - - buf.writestring(ident == Id.ctor ? "this" : ident.toString()); - buf.writeByte('('); - foreach (i, const tp; *parameters) - { - if (i) - buf.writestring(", "); - toCBuffer(tp, buf, hgs); - } - buf.writeByte(')'); - - if (onemember) - { - if (const fd = onemember.isFuncDeclaration()) - { - if (TypeFunction tf = cast(TypeFunction)fd.type.isTypeFunction()) - { - // !! Casted away const - buf.writestring(parametersTypeToChars(tf.parameterList)); - if (tf.mod) - { - buf.writeByte(' '); - buf.MODtoBuffer(tf.mod); - } - } - } - } - - if (includeConstraints && - constraint) - { - buf.writestring(" if ("); - toCBuffer(constraint, buf, hgs); - buf.writeByte(')'); - } - - return buf.extractChars(); - } - - override Visibility visible() pure nothrow @nogc @safe - { - return visibility; - } - - /**************************** - * Check to see if constraint is satisfied. - */ - private bool evaluateConstraint(TemplateInstance ti, Scope* sc, Scope* paramscope, Objects* dedargs, FuncDeclaration fd) - { - /* Detect recursive attempts to instantiate this template declaration, - * https://issues.dlang.org/show_bug.cgi?id=4072 - * void foo(T)(T x) if (is(typeof(foo(x)))) { } - * static assert(!is(typeof(foo(7)))); - * Recursive attempts are regarded as a constraint failure. - */ - /* There's a chicken-and-egg problem here. We don't know yet if this template - * instantiation will be a local one (enclosing is set), and we won't know until - * after selecting the correct template. Thus, function we're nesting inside - * is not on the sc scope chain, and this can cause errors in FuncDeclaration.getLevel(). - * Workaround the problem by setting a flag to relax the checking on frame errors. - */ - - for (TemplatePrevious* p = previous; p; p = p.prev) - { - if (!arrayObjectMatch(*p.dedargs, *dedargs)) - continue; - //printf("recursive, no match p.sc=%p %p %s\n", p.sc, this, this.toChars()); - /* It must be a subscope of p.sc, other scope chains are not recursive - * instantiations. - * the chain of enclosing scopes is broken by paramscope (its enclosing - * scope is _scope, but paramscope.callsc is the instantiating scope). So - * it's good enough to check the chain of callsc - */ - for (Scope* scx = paramscope.callsc; scx; scx = scx.callsc) - { - // The first scx might be identical for nested eponymeous templates, e.g. - // template foo() { void foo()() {...} } - if (scx == p.sc && scx !is paramscope.callsc) - return false; - } - /* BUG: should also check for ref param differences - */ - } - - TemplatePrevious pr; - pr.prev = previous; - pr.sc = paramscope.callsc; - pr.dedargs = dedargs; - previous = ≺ // add this to threaded list - - Scope* scx = paramscope.push(ti); - scx.parent = ti; - scx.tinst = null; - scx.minst = null; - // Set SCOPE.constraint before declaring function parameters for the static condition - // (previously, this was immediately before calling evalStaticCondition), so the - // semantic pass knows not to issue deprecation warnings for these throw-away decls. - // https://issues.dlang.org/show_bug.cgi?id=21831 - scx.flags |= SCOPE.constraint; - - assert(!ti.symtab); - if (fd) - { - /* Declare all the function parameters as variables and add them to the scope - * Making parameters is similar to FuncDeclaration.semantic3 - */ - auto tf = fd.type.isTypeFunction(); - - scx.parent = fd; - - Parameters* fparameters = tf.parameterList.parameters; - const nfparams = tf.parameterList.length; - foreach (i, fparam; tf.parameterList) - { - fparam.storageClass &= (STC.IOR | STC.lazy_ | STC.final_ | STC.TYPECTOR | STC.nodtor); - fparam.storageClass |= STC.parameter; - if (tf.parameterList.varargs == VarArg.typesafe && i + 1 == nfparams) - { - fparam.storageClass |= STC.variadic; - /* Don't need to set STC.scope_ because this will only - * be evaluated at compile time - */ - } - } - foreach (fparam; *fparameters) - { - if (!fparam.ident) - continue; - // don't add it, if it has no name - auto v = new VarDeclaration(fparam.loc, fparam.type, fparam.ident, null); - fparam.storageClass |= STC.parameter; - v.storage_class = fparam.storageClass; - v.dsymbolSemantic(scx); - if (!ti.symtab) - ti.symtab = new DsymbolTable(); - if (!scx.insert(v)) - .error(loc, "%s `%s` parameter `%s.%s` is already defined", kind, toPrettyChars, toChars(), v.toChars()); - else - v.parent = fd; - } - if (isstatic) - fd.storage_class |= STC.static_; - fd.declareThis(scx); - } - - lastConstraint = constraint.syntaxCopy(); - lastConstraintTiargs = ti.tiargs; - lastConstraintNegs.setDim(0); - - import dmd.staticcond; - - assert(ti.inst is null); - ti.inst = ti; // temporary instantiation to enable genIdent() - bool errors; - const bool result = evalStaticCondition(scx, constraint, lastConstraint, errors, &lastConstraintNegs); - if (result || errors) - { - lastConstraint = null; - lastConstraintTiargs = null; - lastConstraintNegs.setDim(0); - } - ti.inst = null; - ti.symtab = null; - scx = scx.pop(); - previous = pr.prev; // unlink from threaded list - if (errors) - return false; - return result; - } - - /**************************** - * Destructively get the error message from the last constraint evaluation - * Params: - * tip = tip to show after printing all overloads - */ - const(char)* getConstraintEvalError(ref const(char)* tip) - { - import dmd.staticcond; - - // there will be a full tree view in verbose mode, and more compact list in the usual - const full = global.params.v.verbose; - uint count; - const msg = visualizeStaticCondition(constraint, lastConstraint, lastConstraintNegs[], full, count); - scope (exit) - { - lastConstraint = null; - lastConstraintTiargs = null; - lastConstraintNegs.setDim(0); - } - if (!msg) - return null; - - OutBuffer buf; - - assert(parameters && lastConstraintTiargs); - if (parameters.length > 0) - { - formatParamsWithTiargs(*lastConstraintTiargs, buf); - buf.writenl(); - } - if (!full) - { - // choosing singular/plural - const s = (count == 1) ? - " must satisfy the following constraint:" : - " must satisfy one of the following constraints:"; - buf.writestring(s); - buf.writenl(); - // the constraints - buf.writeByte('`'); - buf.writestring(msg); - buf.writeByte('`'); - } - else - { - buf.writestring(" whose parameters have the following constraints:"); - buf.writenl(); - const sep = " `~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~`"; - buf.writestring(sep); - buf.writenl(); - // the constraints - buf.writeByte('`'); - buf.writestring(msg); - buf.writeByte('`'); - buf.writestring(sep); - tip = "not satisfied constraints are marked with `>`"; - } - return buf.extractChars(); - } - - private void formatParamsWithTiargs(ref Objects tiargs, ref OutBuffer buf) - { - buf.writestring(" with `"); - - // write usual arguments line-by-line - // skips trailing default ones - they are not present in `tiargs` - const bool variadic = isVariadic() !is null; - const end = cast(int)parameters.length - (variadic ? 1 : 0); - uint i; - for (; i < tiargs.length && i < end; i++) - { - if (i > 0) - { - buf.writeByte(','); - buf.writenl(); - buf.writestring(" "); - } - write(buf, (*parameters)[i]); - buf.writestring(" = "); - write(buf, tiargs[i]); - } - // write remaining variadic arguments on the last line - if (variadic) - { - if (i > 0) - { - buf.writeByte(','); - buf.writenl(); - buf.writestring(" "); - } - write(buf, (*parameters)[end]); - buf.writestring(" = "); - buf.writeByte('('); - if (cast(int)tiargs.length - end > 0) - { - write(buf, tiargs[end]); - foreach (j; parameters.length .. tiargs.length) - { - buf.writestring(", "); - write(buf, tiargs[j]); - } - } - buf.writeByte(')'); - } - buf.writeByte('`'); - } - - /****************************** - * Create a scope for the parameters of the TemplateInstance - * `ti` in the parent scope sc from the ScopeDsymbol paramsym. - * - * If paramsym is null a new ScopeDsymbol is used in place of - * paramsym. - * Params: - * ti = the TemplateInstance whose parameters to generate the scope for. - * sc = the parent scope of ti - * Returns: - * a scope for the parameters of ti - */ - Scope* scopeForTemplateParameters(TemplateInstance ti, Scope* sc) - { - ScopeDsymbol paramsym = new ScopeDsymbol(); - paramsym.parent = _scope.parent; - Scope* paramscope = _scope.push(paramsym); - paramscope.tinst = ti; - paramscope.minst = sc.minst; - paramscope.callsc = sc; - paramscope.stc = 0; - return paramscope; - } - - /*************************************** - * Given that ti is an instance of this TemplateDeclaration, - * deduce the types of the parameters to this, and store - * those deduced types in dedtypes[]. - * Input: - * flag 1: don't do semantic() because of dummy types - * 2: don't change types in matchArg() - * Output: - * dedtypes deduced arguments - * Return match level. - */ - private MATCH matchWithInstance(Scope* sc, TemplateInstance ti, ref Objects dedtypes, ArgumentList argumentList, int flag) - { - enum LOGM = 0; - static if (LOGM) - { - printf("\n+TemplateDeclaration.matchWithInstance(this = %s, ti = %s, flag = %d)\n", toChars(), ti.toChars(), flag); - } - version (none) - { - printf("dedtypes.length = %d, parameters.length = %d\n", dedtypes.length, parameters.length); - if (ti.tiargs.length) - printf("ti.tiargs.length = %d, [0] = %p\n", ti.tiargs.length, (*ti.tiargs)[0]); - } - MATCH nomatch() - { - static if (LOGM) - { - printf(" no match\n"); - } - return MATCH.nomatch; - } - MATCH m; - size_t dedtypes_dim = dedtypes.length; - - dedtypes.zero(); - - if (errors) - return MATCH.nomatch; - - size_t parameters_dim = parameters.length; - int variadic = isVariadic() !is null; - - // If more arguments than parameters, no match - if (ti.tiargs.length > parameters_dim && !variadic) - { - static if (LOGM) - { - printf(" no match: more arguments than parameters\n"); - } - return MATCH.nomatch; - } - - assert(dedtypes_dim == parameters_dim); - assert(dedtypes_dim >= ti.tiargs.length || variadic); - - assert(_scope); - - // Set up scope for template parameters - Scope* paramscope = scopeForTemplateParameters(ti,sc); - - // Attempt type deduction - m = MATCH.exact; - for (size_t i = 0; i < dedtypes_dim; i++) - { - MATCH m2; - TemplateParameter tp = (*parameters)[i]; - Declaration sparam; - - //printf("\targument [%d]\n", i); - static if (LOGM) - { - //printf("\targument [%d] is %s\n", i, oarg ? oarg.toChars() : "null"); - TemplateTypeParameter ttp = tp.isTemplateTypeParameter(); - if (ttp) - printf("\tparameter[%d] is %s : %s\n", i, tp.ident.toChars(), ttp.specType ? ttp.specType.toChars() : ""); - } - - m2 = tp.matchArg(ti.loc, paramscope, ti.tiargs, i, parameters, dedtypes, &sparam); - //printf("\tm2 = %d\n", m2); - if (m2 == MATCH.nomatch) - { - version (none) - { - printf("\tmatchArg() for parameter %i failed\n", i); - } - return nomatch(); - } - - if (m2 < m) - m = m2; - - if (!flag) - sparam.dsymbolSemantic(paramscope); - if (!paramscope.insert(sparam)) // TODO: This check can make more early - { - // in TemplateDeclaration.semantic, and - // then we don't need to make sparam if flags == 0 - return nomatch(); - } - } - - if (!flag) - { - /* Any parameter left without a type gets the type of - * its corresponding arg - */ - foreach (i, ref dedtype; dedtypes) - { - if (!dedtype) - { - assert(i < ti.tiargs.length); - dedtype = cast(Type)(*ti.tiargs)[i]; - } - } - } - - if (m > MATCH.nomatch && constraint && !flag) - { - if (ti.hasNestedArgs(ti.tiargs, this.isstatic)) // TODO: should gag error - ti.parent = ti.enclosing; - else - ti.parent = this.parent; - - // Similar to doHeaderInstantiation - FuncDeclaration fd = onemember ? onemember.isFuncDeclaration() : null; - if (fd) - { - TypeFunction tf = fd.type.isTypeFunction().syntaxCopy(); - if (argumentList.hasNames) - return nomatch(); - Expressions* fargs = argumentList.arguments; - // TODO: Expressions* fargs = tf.resolveNamedArgs(argumentList, null); - // if (!fargs) - // return nomatch(); - - fd = new FuncDeclaration(fd.loc, fd.endloc, fd.ident, fd.storage_class, tf); - fd.parent = ti; - fd.inferRetType = true; - - // Shouldn't run semantic on default arguments and return type. - foreach (ref param; *tf.parameterList.parameters) - param.defaultArg = null; - - tf.next = null; - tf.incomplete = true; - - // Resolve parameter types and 'auto ref's. - tf.fargs = fargs; - uint olderrors = global.startGagging(); - fd.type = tf.typeSemantic(loc, paramscope); - global.endGagging(olderrors); - if (fd.type.ty != Tfunction) - return nomatch(); - fd.originalType = fd.type; // for mangling - } - - // TODO: dedtypes => ti.tiargs ? - if (!evaluateConstraint(ti, sc, paramscope, &dedtypes, fd)) - return nomatch(); - } - - static if (LOGM) - { - // Print out the results - printf("--------------------------\n"); - printf("template %s\n", toChars()); - printf("instance %s\n", ti.toChars()); - if (m > MATCH.nomatch) - { - for (size_t i = 0; i < dedtypes_dim; i++) - { - TemplateParameter tp = (*parameters)[i]; - RootObject oarg; - printf(" [%d]", i); - if (i < ti.tiargs.length) - oarg = (*ti.tiargs)[i]; - else - oarg = null; - tp.print(oarg, (*dedtypes)[i]); - } - } - else - return nomatch(); - } - static if (LOGM) - { - printf(" match = %d\n", m); - } - - paramscope.pop(); - static if (LOGM) - { - printf("-TemplateDeclaration.matchWithInstance(this = %s, ti = %s) = %d\n", toChars(), ti.toChars(), m); - } - return m; - } - - /******************************************** - * Determine partial specialization order of 'this' vs td2. - * Returns: - * match this is at least as specialized as td2 - * 0 td2 is more specialized than this - */ - extern (D) MATCH leastAsSpecialized(Scope* sc, TemplateDeclaration td2, ArgumentList argumentList) - { - enum LOG_LEASTAS = 0; - static if (LOG_LEASTAS) - { - printf("%s.leastAsSpecialized(%s)\n", toChars(), td2.toChars()); - } - - /* This works by taking the template parameters to this template - * declaration and feeding them to td2 as if it were a template - * instance. - * If it works, then this template is at least as specialized - * as td2. - */ - - // Set type arguments to dummy template instance to be types - // generated from the parameters to this template declaration - auto tiargs = new Objects(); - tiargs.reserve(parameters.length); - foreach (tp; *parameters) - { - if (tp.dependent) - break; - RootObject p = tp.dummyArg(); - if (!p) //TemplateTupleParameter - break; - - tiargs.push(p); - } - scope TemplateInstance ti = new TemplateInstance(Loc.initial, ident, tiargs); // create dummy template instance - - // Temporary Array to hold deduced types - Objects dedtypes = Objects(td2.parameters.length); - - // Attempt a type deduction - MATCH m = td2.matchWithInstance(sc, ti, dedtypes, argumentList, 1); - if (m > MATCH.nomatch) - { - /* A non-variadic template is more specialized than a - * variadic one. - */ - TemplateTupleParameter tp = isVariadic(); - if (tp && !tp.dependent && !td2.isVariadic()) - goto L1; - - static if (LOG_LEASTAS) - { - printf(" matches %d, so is least as specialized\n", m); - } - return m; - } - L1: - static if (LOG_LEASTAS) - { - printf(" doesn't match, so is not as specialized\n"); - } - return MATCH.nomatch; - } - - /************************************************* - * Match function arguments against a specific template function. - * - * Params: - * ti = template instance. `ti.tdtypes` will be set to Expression/Type deduced template arguments - * sc = instantiation scope - * fd = Partially instantiated function declaration, which is set to an instantiated function declaration - * tthis = 'this' argument if !NULL - * argumentList = arguments to function - * - * Returns: - * match pair of initial and inferred template arguments - */ - extern (D) MATCHpair deduceFunctionTemplateMatch(TemplateInstance ti, Scope* sc, ref FuncDeclaration fd, Type tthis, ArgumentList argumentList) - { - version (none) - { - printf("\nTemplateDeclaration.deduceFunctionTemplateMatch() %s\n", toChars()); - for (size_t i = 0; i < (fargs ? fargs.length : 0); i++) - { - Expression e = (*fargs)[i]; - printf("\tfarg[%d] is %s, type is %s\n", cast(int) i, e.toChars(), e.type.toChars()); - } - printf("fd = %s\n", fd.toChars()); - printf("fd.type = %s\n", fd.type.toChars()); - if (tthis) - printf("tthis = %s\n", tthis.toChars()); - } - - assert(_scope); - - auto dedargs = new Objects(parameters.length); - dedargs.zero(); - - Objects* dedtypes = &ti.tdtypes; // for T:T*, the dedargs is the T*, dedtypes is the T - dedtypes.setDim(parameters.length); - dedtypes.zero(); - - if (errors || fd.errors) - return MATCHpair(MATCH.nomatch, MATCH.nomatch); - - // Set up scope for parameters - Scope* paramscope = scopeForTemplateParameters(ti,sc); - - MATCHpair nomatch() - { - paramscope.pop(); - //printf("\tnomatch\n"); - return MATCHpair(MATCH.nomatch, MATCH.nomatch); - } - - MATCHpair matcherror() - { - // todo: for the future improvement - paramscope.pop(); - //printf("\terror\n"); - return MATCHpair(MATCH.nomatch, MATCH.nomatch); - } - // Mark the parameter scope as deprecated if the templated - // function is deprecated (since paramscope.enclosing is the - // calling scope already) - paramscope.stc |= fd.storage_class & STC.deprecated_; - - TemplateTupleParameter tp = isVariadic(); - Tuple declaredTuple = null; - - version (none) - { - for (size_t i = 0; i < dedargs.length; i++) - { - printf("\tdedarg[%d] = ", i); - RootObject oarg = (*dedargs)[i]; - if (oarg) - printf("%s", oarg.toChars()); - printf("\n"); - } - } - - size_t ntargs = 0; // array size of tiargs - size_t inferStart = 0; // index of first parameter to infer - const Loc instLoc = ti.loc; - MATCH matchTiargs = MATCH.exact; - - if (auto tiargs = ti.tiargs) - { - // Set initial template arguments - ntargs = tiargs.length; - size_t n = parameters.length; - if (tp) - n--; - if (ntargs > n) - { - if (!tp) - return nomatch(); - - /* The extra initial template arguments - * now form the tuple argument. - */ - auto t = new Tuple(ntargs - n); - assert(parameters.length); - (*dedargs)[parameters.length - 1] = t; - - for (size_t i = 0; i < t.objects.length; i++) - { - t.objects[i] = (*tiargs)[n + i]; - } - declareParameter(paramscope, tp, t); - declaredTuple = t; - } - else - n = ntargs; - - memcpy(dedargs.tdata(), tiargs.tdata(), n * (*dedargs.tdata()).sizeof); - - for (size_t i = 0; i < n; i++) - { - assert(i < parameters.length); - Declaration sparam = null; - MATCH m = (*parameters)[i].matchArg(instLoc, paramscope, dedargs, i, parameters, *dedtypes, &sparam); - //printf("\tdeduceType m = %d\n", m); - if (m == MATCH.nomatch) - return nomatch(); - if (m < matchTiargs) - matchTiargs = m; - - sparam.dsymbolSemantic(paramscope); - if (!paramscope.insert(sparam)) - return nomatch(); - } - if (n < parameters.length && !declaredTuple) - { - inferStart = n; - } - else - inferStart = parameters.length; - //printf("tiargs matchTiargs = %d\n", matchTiargs); - } - version (none) - { - for (size_t i = 0; i < dedargs.length; i++) - { - printf("\tdedarg[%d] = ", i); - RootObject oarg = (*dedargs)[i]; - if (oarg) - printf("%s", oarg.toChars()); - printf("\n"); - } - } - - ParameterList fparameters = fd.getParameterList(); // function parameter list - const nfparams = fparameters.length; // number of function parameters - if (argumentList.hasNames) - return matcherror(); // TODO: resolve named args - Expression[] fargs = argumentList.arguments ? (*argumentList.arguments)[] : null; - - /* Check for match of function arguments with variadic template - * parameter, such as: - * - * void foo(T, A...)(T t, A a); - * void main() { foo(1,2,3); } - */ - size_t fptupindex = IDX_NOTFOUND; - if (tp) // if variadic - { - // TemplateTupleParameter always makes most lesser matching. - matchTiargs = MATCH.convert; - - if (nfparams == 0 && argumentList.length != 0) // if no function parameters - { - if (!declaredTuple) - { - auto t = new Tuple(); - //printf("t = %p\n", t); - (*dedargs)[parameters.length - 1] = t; - declareParameter(paramscope, tp, t); - declaredTuple = t; - } - } - else - { - /* Figure out which of the function parameters matches - * the tuple template parameter. Do this by matching - * type identifiers. - * Set the index of this function parameter to fptupindex. - */ - for (fptupindex = 0; fptupindex < nfparams; fptupindex++) - { - auto fparam = (*fparameters.parameters)[fptupindex]; // fparameters[fptupindex] ? - if (fparam.type.ty != Tident) - continue; - TypeIdentifier tid = fparam.type.isTypeIdentifier(); - if (!tp.ident.equals(tid.ident) || tid.idents.length) - continue; - - if (fparameters.varargs != VarArg.none) // variadic function doesn't - return nomatch(); // go with variadic template - - goto L1; - } - fptupindex = IDX_NOTFOUND; - L1: - } - } - - MATCH match = MATCH.exact; - if (toParent().isModule()) - tthis = null; - if (tthis) - { - bool hasttp = false; - - // Match 'tthis' to any TemplateThisParameter's - foreach (param; *parameters) - { - if (auto ttp = param.isTemplateThisParameter()) - { - hasttp = true; - - Type t = new TypeIdentifier(Loc.initial, ttp.ident); - MATCH m = deduceType(tthis, paramscope, t, *parameters, *dedtypes); - if (m == MATCH.nomatch) - return nomatch(); - if (m < match) - match = m; // pick worst match - } - } - - // Match attributes of tthis against attributes of fd - if (fd.type && !fd.isCtorDeclaration() && !(_scope.stc & STC.static_)) - { - StorageClass stc = _scope.stc | fd.storage_class2; - // Propagate parent storage class, https://issues.dlang.org/show_bug.cgi?id=5504 - Dsymbol p = parent; - while (p.isTemplateDeclaration() || p.isTemplateInstance()) - p = p.parent; - AggregateDeclaration ad = p.isAggregateDeclaration(); - if (ad) - stc |= ad.storage_class; - - ubyte mod = fd.type.mod; - if (stc & STC.immutable_) - mod = MODFlags.immutable_; - else - { - if (stc & (STC.shared_ | STC.synchronized_)) - mod |= MODFlags.shared_; - if (stc & STC.const_) - mod |= MODFlags.const_; - if (stc & STC.wild) - mod |= MODFlags.wild; - } - - ubyte thismod = tthis.mod; - if (hasttp) - mod = MODmerge(thismod, mod); - MATCH m = MODmethodConv(thismod, mod); - if (m == MATCH.nomatch) - return nomatch(); - if (m < match) - match = m; - } - } - - // Loop through the function parameters - { - //printf("%s\n\tnfargs = %d, nfparams = %d, tuple_dim = %d\n", toChars(), nfargs, nfparams, declaredTuple ? declaredTuple.objects.length : 0); - //printf("\ttp = %p, fptupindex = %d, found = %d, declaredTuple = %s\n", tp, fptupindex, fptupindex != IDX_NOTFOUND, declaredTuple ? declaredTuple.toChars() : NULL); - size_t argi = 0; - size_t nfargs2 = fargs.length; // nfargs + supplied defaultArgs - uint inoutMatch = 0; // for debugging only - for (size_t parami = 0; parami < nfparams; parami++) - { - Parameter fparam = fparameters[parami]; - - // Apply function parameter storage classes to parameter types - Type prmtype = fparam.type.addStorageClass(fparam.storageClass); - - Expression farg; - - /* See function parameters which wound up - * as part of a template tuple parameter. - */ - if (fptupindex != IDX_NOTFOUND && parami == fptupindex) - { - TypeIdentifier tid = prmtype.isTypeIdentifier(); - assert(tid); - if (!declaredTuple) - { - /* The types of the function arguments - * now form the tuple argument. - */ - declaredTuple = new Tuple(); - (*dedargs)[parameters.length - 1] = declaredTuple; - - /* Count function parameters with no defaults following a tuple parameter. - * void foo(U, T...)(int y, T, U, double, int bar = 0) {} // rem == 2 (U, double) - */ - size_t rem = 0; - foreach (j; parami + 1 .. nfparams) - { - Parameter p = fparameters[j]; - if (p.defaultArg) - { - break; - } - if (!reliesOnTemplateParameters(p.type, (*parameters)[inferStart .. parameters.length])) - { - Type pt = p.type.syntaxCopy().typeSemantic(fd.loc, paramscope); - if (auto ptt = pt.isTypeTuple()) - rem += ptt.arguments.length; - else - rem += 1; - } - else - { - ++rem; - } - } - - if (nfargs2 - argi < rem) - return nomatch(); - declaredTuple.objects.setDim(nfargs2 - argi - rem); - foreach (i; 0 .. declaredTuple.objects.length) - { - farg = fargs[argi + i]; - - // Check invalid arguments to detect errors early. - if (farg.op == EXP.error || farg.type.ty == Terror) - return nomatch(); - - if (!fparam.isLazy() && farg.type.ty == Tvoid) - return nomatch(); - - Type tt; - MATCH m; - if (ubyte wm = deduceWildHelper(farg.type, &tt, tid)) - { - inoutMatch |= wm; - m = MATCH.constant; - } - else - { - m = deduceTypeHelper(farg.type, tt, tid); - } - if (m == MATCH.nomatch) - return nomatch(); - if (m < match) - match = m; - - /* Remove top const for dynamic array types and pointer types - */ - if ((tt.ty == Tarray || tt.ty == Tpointer) && !tt.isMutable() && (!(fparam.storageClass & STC.ref_) || (fparam.storageClass & STC.auto_) && !farg.isLvalue())) - { - tt = tt.mutableOf(); - } - declaredTuple.objects[i] = tt; - } - declareParameter(paramscope, tp, declaredTuple); - } - else - { - // https://issues.dlang.org/show_bug.cgi?id=6810 - // If declared tuple is not a type tuple, - // it cannot be function parameter types. - for (size_t i = 0; i < declaredTuple.objects.length; i++) - { - if (!isType(declaredTuple.objects[i])) - return nomatch(); - } - } - assert(declaredTuple); - argi += declaredTuple.objects.length; - continue; - } - - // If parameter type doesn't depend on inferred template parameters, - // semantic it to get actual type. - if (!reliesOnTemplateParameters(prmtype, (*parameters)[inferStart .. parameters.length])) - { - // should copy prmtype to avoid affecting semantic result - prmtype = prmtype.syntaxCopy().typeSemantic(fd.loc, paramscope); - - if (TypeTuple tt = prmtype.isTypeTuple()) - { - const tt_dim = tt.arguments.length; - for (size_t j = 0; j < tt_dim; j++, ++argi) - { - Parameter p = (*tt.arguments)[j]; - if (j == tt_dim - 1 && fparameters.varargs == VarArg.typesafe && - parami + 1 == nfparams && argi < fargs.length) - { - prmtype = p.type; - goto Lvarargs; - } - if (argi >= fargs.length) - { - if (p.defaultArg) - continue; - - // https://issues.dlang.org/show_bug.cgi?id=19888 - if (fparam.defaultArg) - break; - - return nomatch(); - } - farg = fargs[argi]; - if (!farg.implicitConvTo(p.type)) - return nomatch(); - } - continue; - } - } - - if (argi >= fargs.length) // if not enough arguments - { - if (!fparam.defaultArg) - goto Lvarargs; - - /* https://issues.dlang.org/show_bug.cgi?id=2803 - * Before the starting of type deduction from the function - * default arguments, set the already deduced parameters into paramscope. - * It's necessary to avoid breaking existing acceptable code. Cases: - * - * 1. Already deduced template parameters can appear in fparam.defaultArg: - * auto foo(A, B)(A a, B b = A.stringof); - * foo(1); - * // at fparam == 'B b = A.string', A is equivalent with the deduced type 'int' - * - * 2. If prmtype depends on default-specified template parameter, the - * default type should be preferred. - * auto foo(N = size_t, R)(R r, N start = 0) - * foo([1,2,3]); - * // at fparam `N start = 0`, N should be 'size_t' before - * // the deduction result from fparam.defaultArg. - */ - if (argi == fargs.length) - { - foreach (ref dedtype; *dedtypes) - { - Type at = isType(dedtype); - if (at && at.ty == Tnone) - { - TypeDeduced xt = cast(TypeDeduced)at; - dedtype = xt.tded; // 'unbox' - } - } - for (size_t i = ntargs; i < dedargs.length; i++) - { - TemplateParameter tparam = (*parameters)[i]; - - RootObject oarg = (*dedargs)[i]; - RootObject oded = (*dedtypes)[i]; - if (oarg) - continue; - - if (oded) - { - if (tparam.specialization() || !tparam.isTemplateTypeParameter()) - { - /* The specialization can work as long as afterwards - * the oded == oarg - */ - (*dedargs)[i] = oded; - MATCH m2 = tparam.matchArg(instLoc, paramscope, dedargs, i, parameters, *dedtypes, null); - //printf("m2 = %d\n", m2); - if (m2 == MATCH.nomatch) - return nomatch(); - if (m2 < matchTiargs) - matchTiargs = m2; // pick worst match - if (!(*dedtypes)[i].equals(oded)) - .error(loc, "%s `%s` specialization not allowed for deduced parameter `%s`", kind, toPrettyChars, kind, toPrettyChars, tparam.ident.toChars()); - } - else - { - if (MATCH.convert < matchTiargs) - matchTiargs = MATCH.convert; - } - (*dedargs)[i] = declareParameter(paramscope, tparam, oded); - } - else - { - oded = tparam.defaultArg(instLoc, paramscope); - if (oded) - (*dedargs)[i] = declareParameter(paramscope, tparam, oded); - } - } - } - nfargs2 = argi + 1; - - /* If prmtype does not depend on any template parameters: - * - * auto foo(T)(T v, double x = 0); - * foo("str"); - * // at fparam == 'double x = 0' - * - * or, if all template parameters in the prmtype are already deduced: - * - * auto foo(R)(R range, ElementType!R sum = 0); - * foo([1,2,3]); - * // at fparam == 'ElementType!R sum = 0' - * - * Deducing prmtype from fparam.defaultArg is not necessary. - */ - if (prmtype.deco || prmtype.syntaxCopy().trySemantic(loc, paramscope)) - { - ++argi; - continue; - } - - // Deduce prmtype from the defaultArg. - farg = fparam.defaultArg.syntaxCopy(); - farg = farg.expressionSemantic(paramscope); - farg = resolveProperties(paramscope, farg); - } - else - { - farg = fargs[argi]; - } - { - // Check invalid arguments to detect errors early. - if (farg.op == EXP.error || farg.type.ty == Terror) - return nomatch(); - - Type att = null; - Lretry: - version (none) - { - printf("\tfarg.type = %s\n", farg.type.toChars()); - printf("\tfparam.type = %s\n", prmtype.toChars()); - } - Type argtype = farg.type; - - if (!fparam.isLazy() && argtype.ty == Tvoid && farg.op != EXP.function_) - return nomatch(); - - // https://issues.dlang.org/show_bug.cgi?id=12876 - // Optimize argument to allow CT-known length matching - farg = farg.optimize(WANTvalue, fparam.isReference()); - //printf("farg = %s %s\n", farg.type.toChars(), farg.toChars()); - - RootObject oarg = farg; - if ((fparam.storageClass & STC.ref_) && (!(fparam.storageClass & STC.auto_) || farg.isLvalue())) - { - /* Allow expressions that have CT-known boundaries and type [] to match with [dim] - */ - bool inferIndexType = (argtype.ty == Tarray) && (prmtype.ty == Tsarray || prmtype.ty == Taarray); - if (auto aaType = prmtype.isTypeAArray()) - { - if (auto indexType = aaType.index.isTypeIdentifier()) - { - inferIndexType = indexType.idents.length == 0; - } - } - if (inferIndexType) - { - if (StringExp se = farg.isStringExp()) - { - argtype = se.type.nextOf().sarrayOf(se.len); - } - else if (ArrayLiteralExp ae = farg.isArrayLiteralExp()) - { - argtype = ae.type.nextOf().sarrayOf(ae.elements.length); - } - else if (SliceExp se = farg.isSliceExp()) - { - if (Type tsa = toStaticArrayType(se)) - argtype = tsa; - } - } - - oarg = argtype; - } - else if ((fparam.storageClass & STC.out_) == 0 && (argtype.ty == Tarray || argtype.ty == Tpointer) && templateParameterLookup(prmtype, parameters) != IDX_NOTFOUND && prmtype.isTypeIdentifier().idents.length == 0) - { - /* The farg passing to the prmtype always make a copy. Therefore, - * we can shrink the set of the deduced type arguments for prmtype - * by adjusting top-qualifier of the argtype. - * - * prmtype argtype ta - * T <- const(E)[] const(E)[] - * T <- const(E[]) const(E)[] - * qualifier(T) <- const(E)[] const(E[]) - * qualifier(T) <- const(E[]) const(E[]) - */ - Type ta = argtype.castMod(prmtype.mod ? argtype.nextOf().mod : 0); - if (ta != argtype) - { - Expression ea = farg.copy(); - ea.type = ta; - oarg = ea; - } - } - - if (fparameters.varargs == VarArg.typesafe && parami + 1 == nfparams && argi + 1 < fargs.length) - goto Lvarargs; - - uint im = 0; - MATCH m = deduceType(oarg, paramscope, prmtype, *parameters, *dedtypes, &im, inferStart); - //printf("\tL%d deduceType m = %d, im = x%x, inoutMatch = x%x\n", __LINE__, m, im, inoutMatch); - inoutMatch |= im; - - /* If no match, see if the argument can be matched by using - * implicit conversions. - */ - if (m == MATCH.nomatch && prmtype.deco) - m = farg.implicitConvTo(prmtype); - - if (m == MATCH.nomatch) - { - AggregateDeclaration ad = isAggregate(farg.type); - if (ad && ad.aliasthis && !isRecursiveAliasThis(att, argtype)) - { - // https://issues.dlang.org/show_bug.cgi?id=12537 - // The isRecursiveAliasThis() call above - - /* If a semantic error occurs while doing alias this, - * eg purity(https://issues.dlang.org/show_bug.cgi?id=7295), - * just regard it as not a match. - * - * We also save/restore sc.func.flags to avoid messing up - * attribute inference in the evaluation. - */ - const oldflags = sc.func ? sc.func.flags : 0; - auto e = resolveAliasThis(sc, farg, true); - if (sc.func) - sc.func.flags = oldflags; - if (e) - { - farg = e; - goto Lretry; - } - } - } - - if (m > MATCH.nomatch && (fparam.storageClass & (STC.ref_ | STC.auto_)) == STC.ref_) - { - if (!farg.isLvalue()) - { - if ((farg.op == EXP.string_ || farg.op == EXP.slice) && (prmtype.ty == Tsarray || prmtype.ty == Taarray)) - { - // Allow conversion from T[lwr .. upr] to ref T[upr-lwr] - } - else if (global.params.rvalueRefParam == FeatureState.enabled) - { - // Allow implicit conversion to ref - } - else - return nomatch(); - } - } - if (m > MATCH.nomatch && (fparam.storageClass & STC.out_)) - { - if (!farg.isLvalue()) - return nomatch(); - if (!farg.type.isMutable()) // https://issues.dlang.org/show_bug.cgi?id=11916 - return nomatch(); - } - if (m == MATCH.nomatch && fparam.isLazy() && prmtype.ty == Tvoid && farg.type.ty != Tvoid) - m = MATCH.convert; - if (m != MATCH.nomatch) - { - if (m < match) - match = m; // pick worst match - argi++; - continue; - } - } - - Lvarargs: - /* The following code for variadic arguments closely - * matches TypeFunction.callMatch() - */ - if (!(fparameters.varargs == VarArg.typesafe && parami + 1 == nfparams)) - return nomatch(); - - /* Check for match with function parameter T... - */ - Type tb = prmtype.toBasetype(); - switch (tb.ty) - { - // 6764 fix - TypeAArray may be TypeSArray have not yet run semantic(). - case Tsarray: - case Taarray: - { - // Perhaps we can do better with this, see TypeFunction.callMatch() - if (TypeSArray tsa = tb.isTypeSArray()) - { - dinteger_t sz = tsa.dim.toInteger(); - if (sz != fargs.length - argi) - return nomatch(); - } - else if (TypeAArray taa = tb.isTypeAArray()) - { - Expression dim = new IntegerExp(instLoc, fargs.length - argi, Type.tsize_t); - - size_t i = templateParameterLookup(taa.index, parameters); - if (i == IDX_NOTFOUND) - { - Expression e; - Type t; - Dsymbol s; - Scope *sco; - - uint errors = global.startGagging(); - /* ref: https://issues.dlang.org/show_bug.cgi?id=11118 - * The parameter isn't part of the template - * ones, let's try to find it in the - * instantiation scope 'sc' and the one - * belonging to the template itself. */ - sco = sc; - taa.index.resolve(instLoc, sco, e, t, s); - if (!e) - { - sco = paramscope; - taa.index.resolve(instLoc, sco, e, t, s); - } - global.endGagging(errors); - - if (!e) - return nomatch(); - - e = e.ctfeInterpret(); - e = e.implicitCastTo(sco, Type.tsize_t); - e = e.optimize(WANTvalue); - if (!dim.equals(e)) - return nomatch(); - } - else - { - // This code matches code in TypeInstance.deduceType() - TemplateParameter tprm = (*parameters)[i]; - TemplateValueParameter tvp = tprm.isTemplateValueParameter(); - if (!tvp) - return nomatch(); - Expression e = cast(Expression)(*dedtypes)[i]; - if (e) - { - if (!dim.equals(e)) - return nomatch(); - } - else - { - Type vt = tvp.valType.typeSemantic(Loc.initial, sc); - MATCH m = dim.implicitConvTo(vt); - if (m == MATCH.nomatch) - return nomatch(); - (*dedtypes)[i] = dim; - } - } - } - goto case Tarray; - } - case Tarray: - { - TypeArray ta = cast(TypeArray)tb; - Type tret = fparam.isLazyArray(); - for (; argi < fargs.length; argi++) - { - Expression arg = fargs[argi]; - assert(arg); + HdrGenState hgs; + OutBuffer buf; + toCharsMaybeConstraints(this, buf, hgs); + return buf.extractChars(); + } - MATCH m; - /* If lazy array of delegates, - * convert arg(s) to delegate(s) - */ - if (tret) - { - if (ta.next.equals(arg.type)) - { - m = MATCH.exact; - } - else - { - m = arg.implicitConvTo(tret); - if (m == MATCH.nomatch) - { - if (tret.toBasetype().ty == Tvoid) - m = MATCH.convert; - } - } - } - else - { - uint wm = 0; - m = deduceType(arg, paramscope, ta.next, *parameters, *dedtypes, &wm, inferStart); - inoutMatch |= wm; - } - if (m == MATCH.nomatch) - return nomatch(); - if (m < match) - match = m; - } - goto Lmatch; - } - case Tclass: - case Tident: - goto Lmatch; + override Visibility visible() pure nothrow @nogc @safe + { + return visibility; + } - default: - return nomatch(); - } - assert(0); - } - //printf(". argi = %d, nfargs = %d, nfargs2 = %d\n", argi, nfargs, nfargs2); - if (argi != nfargs2 && fparameters.varargs == VarArg.none) - return nomatch(); - } + /**************************** + * Destructively get the error message from the last constraint evaluation + * Params: + * tip = tip to show after printing all overloads + */ + const(char)* getConstraintEvalError(ref const(char)* tip) + { + import dmd.staticcond; - Lmatch: - foreach (ref dedtype; *dedtypes) - { - if (Type at = isType(dedtype)) - { - if (at.ty == Tnone) - { - TypeDeduced xt = cast(TypeDeduced)at; - at = xt.tded; // 'unbox' - } - dedtype = at.merge2(); - } - } - for (size_t i = ntargs; i < dedargs.length; i++) + // there will be a full tree view in verbose mode, and more compact list in the usual + const full = global.params.v.verbose; + uint count; + const msg = visualizeStaticCondition(constraint, lastConstraint, lastConstraintNegs[], full, count); + scope (exit) { - TemplateParameter tparam = (*parameters)[i]; - //printf("tparam[%d] = %s\n", i, tparam.ident.toChars()); - - /* For T:T*, the dedargs is the T*, dedtypes is the T - * But for function templates, we really need them to match - */ - RootObject oarg = (*dedargs)[i]; - RootObject oded = (*dedtypes)[i]; - //printf("1dedargs[%d] = %p, dedtypes[%d] = %p\n", i, oarg, i, oded); - //if (oarg) printf("oarg: %s\n", oarg.toChars()); - //if (oded) printf("oded: %s\n", oded.toChars()); - if (oarg) - continue; - - if (oded) - { - if (tparam.specialization() || !tparam.isTemplateTypeParameter()) - { - /* The specialization can work as long as afterwards - * the oded == oarg - */ - (*dedargs)[i] = oded; - MATCH m2 = tparam.matchArg(instLoc, paramscope, dedargs, i, parameters, *dedtypes, null); - //printf("m2 = %d\n", m2); - if (m2 == MATCH.nomatch) - return nomatch(); - if (m2 < matchTiargs) - matchTiargs = m2; // pick worst match - if (!(*dedtypes)[i].equals(oded)) - .error(loc, "%s `%s` specialization not allowed for deduced parameter `%s`", kind, toPrettyChars, tparam.ident.toChars()); - } - else - { - // Discussion: https://issues.dlang.org/show_bug.cgi?id=16484 - if (MATCH.convert < matchTiargs) - matchTiargs = MATCH.convert; - } - } - else - { - oded = tparam.defaultArg(instLoc, paramscope); - if (!oded) - { - // if tuple parameter and - // tuple parameter was not in function parameter list and - // we're one or more arguments short (i.e. no tuple argument) - if (tparam == tp && - fptupindex == IDX_NOTFOUND && - ntargs <= dedargs.length - 1) - { - // make tuple argument an empty tuple - oded = new Tuple(); - } - else - return nomatch(); - } - if (isError(oded)) - return matcherror(); - ntargs++; - - /* At the template parameter T, the picked default template argument - * X!int should be matched to T in order to deduce dependent - * template parameter A. - * auto foo(T : X!A = X!int, A...)() { ... } - * foo(); // T <-- X!int, A <-- (int) - */ - if (tparam.specialization()) - { - (*dedargs)[i] = oded; - MATCH m2 = tparam.matchArg(instLoc, paramscope, dedargs, i, parameters, *dedtypes, null); - //printf("m2 = %d\n", m2); - if (m2 == MATCH.nomatch) - return nomatch(); - if (m2 < matchTiargs) - matchTiargs = m2; // pick worst match - if (!(*dedtypes)[i].equals(oded)) - .error(loc, "%s `%s` specialization not allowed for deduced parameter `%s`", kind, toPrettyChars, tparam.ident.toChars()); - } - } - oded = declareParameter(paramscope, tparam, oded); - (*dedargs)[i] = oded; + lastConstraint = null; + lastConstraintTiargs = null; + lastConstraintNegs.setDim(0); } + if (!msg) + return null; - /* https://issues.dlang.org/show_bug.cgi?id=7469 - * As same as the code for 7469 in findBestMatch, - * expand a Tuple in dedargs to normalize template arguments. - */ - if (auto d = dedargs.length) - { - if (auto va = isTuple((*dedargs)[d - 1])) - { - dedargs.setDim(d - 1); - dedargs.insert(d - 1, &va.objects); - } - } - ti.tiargs = dedargs; // update to the normalized template arguments. + OutBuffer buf; - // Partially instantiate function for constraint and fd.leastAsSpecialized() + assert(parameters && lastConstraintTiargs); + if (parameters.length > 0) { - assert(paramscope.scopesym); - Scope* sc2 = _scope; - sc2 = sc2.push(paramscope.scopesym); - sc2 = sc2.push(ti); - sc2.parent = ti; - sc2.tinst = ti; - sc2.minst = sc.minst; - sc2.stc |= fd.storage_class & STC.deprecated_; - - fd = doHeaderInstantiation(ti, sc2, fd, tthis, argumentList.arguments); - - sc2 = sc2.pop(); - sc2 = sc2.pop(); - - if (!fd) - return nomatch(); + formatParamsWithTiargs(*parameters, *lastConstraintTiargs, isVariadic() !is null, buf); + buf.writenl(); } - - if (constraint) + if (!full) { - if (!evaluateConstraint(ti, sc, paramscope, dedargs, fd)) - return nomatch(); + // choosing singular/plural + const s = (count == 1) ? + " must satisfy the following constraint:" : + " must satisfy one of the following constraints:"; + buf.writestring(s); + buf.writenl(); + // the constraints + buf.writeByte('`'); + buf.writestring(msg); + buf.writeByte('`'); } - - version (none) + else { - for (size_t i = 0; i < dedargs.length; i++) - { - RootObject o = (*dedargs)[i]; - printf("\tdedargs[%d] = %d, %s\n", i, o.dyncast(), o.toChars()); - } + buf.writestring(" whose parameters have the following constraints:"); + buf.writenl(); + const sep = " `~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~`"; + buf.writestring(sep); + buf.writenl(); + // the constraints + buf.writeByte('`'); + buf.writestring(msg); + buf.writeByte('`'); + buf.writestring(sep); + tip = "not satisfied constraints are marked with `>`"; } - - paramscope.pop(); - //printf("\tmatch %d\n", match); - return MATCHpair(matchTiargs, match); + return buf.extractChars(); } /************************************************** @@ -2770,8 +1302,8 @@ void functionResolve(ref MatchAccumulator m, Dsymbol dstart, Loc loc, Scope* sc, * This is because f() is "more specialized." */ { - MATCH c1 = fd.leastAsSpecialized(m.lastf, argumentList.names); - MATCH c2 = m.lastf.leastAsSpecialized(fd, argumentList.names); + MATCH c1 = FuncDeclaration.leastAsSpecialized(fd, m.lastf, argumentList.names); + MATCH c2 = FuncDeclaration.leastAsSpecialized(m.lastf, fd, argumentList.names); //printf("c1 = %d, c2 = %d\n", c1, c2); if (c1 > c2) return firstIsBetter(); if (c1 < c2) return 0; @@ -2876,7 +1408,7 @@ void functionResolve(ref MatchAccumulator m, Dsymbol dstart, Loc loc, Scope* sc, auto ti = new TemplateInstance(loc, td, tiargs); Objects dedtypes = Objects(td.parameters.length); assert(td.semanticRun != PASS.initial); - MATCH mta = td.matchWithInstance(sc, ti, dedtypes, argumentList, 0); + MATCH mta = matchWithInstance(sc, td, ti, dedtypes, argumentList, 0); //printf("matchWithInstance = %d\n", mta); if (mta == MATCH.nomatch || mta < ta_last) // no match or less match return 0; @@ -3036,8 +1568,8 @@ void functionResolve(ref MatchAccumulator m, Dsymbol dstart, Loc loc, Scope* sc, if (td_best) { // Disambiguate by picking the most specialized TemplateDeclaration - MATCH c1 = td.leastAsSpecialized(sc, td_best, argumentList); - MATCH c2 = td_best.leastAsSpecialized(sc, td, argumentList); + MATCH c1 = leastAsSpecialized(sc, td, td_best, argumentList); + MATCH c2 = leastAsSpecialized(sc, td_best, td, argumentList); //printf("1: c1 = %d, c2 = %d\n", c1, c2); if (c1 > c2) goto Ltd; if (c1 < c2) goto Ltd_best; @@ -3055,8 +1587,8 @@ void functionResolve(ref MatchAccumulator m, Dsymbol dstart, Loc loc, Scope* sc, } { // Disambiguate by picking the most specialized FunctionDeclaration - MATCH c1 = fd.leastAsSpecialized(m.lastf, argumentList.names); - MATCH c2 = m.lastf.leastAsSpecialized(fd, argumentList.names); + MATCH c1 = FuncDeclaration.leastAsSpecialized(fd, m.lastf, argumentList.names); + MATCH c2 = FuncDeclaration.leastAsSpecialized(m.lastf, fd, argumentList.names); //printf("3: c1 = %d, c2 = %d\n", c1, c2); if (c1 > c2) goto Ltd; if (c1 < c2) goto Ltd_best; @@ -3199,7 +1731,7 @@ private size_t templateIdentifierLookup(Identifier id, TemplateParameters* param return IDX_NOTFOUND; } -private size_t templateParameterLookup(Type tparam, TemplateParameters* parameters) +size_t templateParameterLookup(Type tparam, TemplateParameters* parameters) { if (TypeIdentifier tident = tparam.isTypeIdentifier()) { @@ -3209,7 +1741,7 @@ private size_t templateParameterLookup(Type tparam, TemplateParameters* paramete return IDX_NOTFOUND; } -private ubyte deduceWildHelper(Type t, Type* at, Type tparam) +ubyte deduceWildHelper(Type t, Type* at, Type tparam) { if ((tparam.mod & MODFlags.wild) == 0) return 0; @@ -3292,7 +1824,7 @@ private Type rawTypeMerge(Type t1, Type t2) return null; } -private MATCH deduceTypeHelper(Type t, out Type at, Type tparam) +MATCH deduceTypeHelper(Type t, out Type at, Type tparam) { // 9*9 == 81 cases @@ -5000,7 +3532,7 @@ bool reliesOnTident(Type t, TemplateParameters* tparams, size_t iStart = 0) * t = Tested type, if null, returns false. * tparams = Template parameters. */ -private bool reliesOnTemplateParameters(Type t, TemplateParameter[] tparams) +bool reliesOnTemplateParameters(Type t, TemplateParameter[] tparams) { bool visitVector(TypeVector t) { @@ -6930,7 +5462,7 @@ extern (C++) class TemplateInstance : ScopeDsymbol } FuncDeclaration fd = sa.isFuncDeclaration(); if (fd) - fd.functionSemantic(); + functionSemantic(fd); } else if (isParameter(o)) { @@ -7001,7 +5533,7 @@ extern (C++) class TemplateInstance : ScopeDsymbol assert(tempdecl._scope); // Deduce tdtypes tdtypes.setDim(tempdecl.parameters.length); - if (!tempdecl.matchWithInstance(sc, this, tdtypes, argumentList, 2)) + if (!matchWithInstance(sc, tempdecl, this, tdtypes, argumentList, 2)) { .error(loc, "%s `%s` incompatible arguments for template instantiation", kind, toPrettyChars); return false; @@ -7051,7 +5583,7 @@ extern (C++) class TemplateInstance : ScopeDsymbol dedtypes.zero(); assert(td.semanticRun != PASS.initial); - MATCH m = td.matchWithInstance(sc, this, dedtypes, argumentList, 0); + MATCH m = matchWithInstance(sc, td, this, dedtypes, argumentList, 0); //printf("matchWithInstance = %d\n", m); if (m == MATCH.nomatch) // no match at all return 0; @@ -7060,8 +5592,8 @@ extern (C++) class TemplateInstance : ScopeDsymbol // Disambiguate by picking the most specialized TemplateDeclaration { - MATCH c1 = td.leastAsSpecialized(sc, td_best, argumentList); - MATCH c2 = td_best.leastAsSpecialized(sc, td, argumentList); + MATCH c1 = leastAsSpecialized(sc, td, td_best, argumentList); + MATCH c2 = leastAsSpecialized(sc, td_best, td, argumentList); //printf("c1 = %d, c2 = %d\n", c1, c2); if (c1 > c2) goto Ltd; if (c1 < c2) goto Ltd_best; @@ -7159,7 +5691,11 @@ extern (C++) class TemplateInstance : ScopeDsymbol // Only one template, so we can give better error message const(char)* msg = "does not match template declaration"; const(char)* tip; - const tmsg = tdecl.toCharsNoConstraints(); + OutBuffer buf; + HdrGenState hgs; + hgs.skipConstraints = true; + toCharsMaybeConstraints(tdecl, buf, hgs); + const tmsg = buf.peekChars(); const cmsg = tdecl.getConstraintEvalError(tip); if (cmsg) { @@ -7327,7 +5863,7 @@ extern (C++) class TemplateInstance : ScopeDsymbol return 1; } } - MATCH m = td.matchWithInstance(sc, this, dedtypes, ArgumentList(), 0); + MATCH m = matchWithInstance(sc, td, this, dedtypes, ArgumentList(), 0); if (m == MATCH.nomatch) return 0; } @@ -8562,15 +7098,21 @@ extern (C++) void printTemplateStats(bool listInstances, ErrorSink eSink) sortedStats.sort!(TemplateDeclarationStats.compare); + OutBuffer buf; foreach (const ref ss; sortedStats[]) { + buf.reset(); + HdrGenState hgs; + hgs.skipConstraints = true; + toCharsMaybeConstraints(ss.td, buf, hgs); + const tchars = buf.peekChars(); if (listInstances && ss.ts.allInstances) { eSink.message(ss.td.loc, "vtemplate: %u (%u distinct) instantiation(s) of template `%s` found, they are:", ss.ts.numInstantiations, ss.ts.uniqueInstantiations, - ss.td.toCharsNoConstraints()); + tchars); foreach (const ti; (*ss.ts.allInstances)[]) { if (ti.tinst) // if has enclosing instance @@ -8585,13 +7127,13 @@ extern (C++) void printTemplateStats(bool listInstances, ErrorSink eSink) "vtemplate: %u (%u distinct) instantiation(s) of template `%s` found", ss.ts.numInstantiations, ss.ts.uniqueInstantiations, - ss.td.toCharsNoConstraints()); + tchars); } } } /// Pair of MATCHes -private struct MATCHpair +struct MATCHpair { MATCH mta; /// match template parameters by initial template arguments MATCH mfa; /// match template parameters by inferred template arguments @@ -8605,7 +7147,7 @@ private struct MATCHpair } } -private void write(ref OutBuffer buf, RootObject obj) +void write(ref OutBuffer buf, RootObject obj) { if (obj) { diff --git a/gcc/d/dmd/enum.h b/gcc/d/dmd/enum.h index a4bb588..650bf3e 100644 --- a/gcc/d/dmd/enum.h +++ b/gcc/d/dmd/enum.h @@ -52,8 +52,6 @@ public: bool isDeprecated() const override; // is Dsymbol deprecated? Visibility visible() override; bool isSpecial() const; - Expression *getDefaultValue(const Loc &loc); - Type *getMemtype(const Loc &loc); EnumDeclaration *isEnumDeclaration() override { return this; } diff --git a/gcc/d/dmd/enumsem.d b/gcc/d/dmd/enumsem.d new file mode 100644 index 0000000..0603960 --- /dev/null +++ b/gcc/d/dmd/enumsem.d @@ -0,0 +1,714 @@ +/** + * Does the semantic passes on enums. + * + * Copyright: Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved + * Authors: $(LINK2 https://www.digitalmars.com, Walter Bright) + * License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) + * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/enumsem.d, _enumsem.d) + * Documentation: https://dlang.org/phobos/dmd_enumsem.html + * Coverage: https://codecov.io/gh/dlang/dmd/src/master/src/dmd/enumsem.d + */ + +module dmd.enumsem; + +import core.stdc.stdio; +import core.stdc.string; + +import dmd.aggregate; +import dmd.aliasthis; +import dmd.arraytypes; +import dmd.astcodegen; +import dmd.astenums; +import dmd.attrib; +import dmd.blockexit; +import dmd.clone; +import dmd.cond; +import dmd.compiler; +import dmd.dcast; +import dmd.dclass; +import dmd.declaration; +import dmd.denum; +import dmd.dimport; +import dmd.dinterpret; +import dmd.dmangle; +import dmd.dmodule; +import dmd.dscope; +import dmd.dstruct; +import dmd.dsymbol; +import dmd.dsymbolsem; +import dmd.dtemplate; +import dmd.dversion; +import dmd.errors; +import dmd.escape; +import dmd.expression; +import dmd.expressionsem; +import dmd.func; +import dmd.funcsem; +import dmd.globals; +import dmd.id; +import dmd.identifier; +import dmd.importc; +import dmd.init; +import dmd.initsem; +import dmd.intrange; +import dmd.hdrgen; +import dmd.location; +import dmd.mtype; +import dmd.mustuse; +import dmd.nogc; +import dmd.nspace; +import dmd.objc; +import dmd.opover; +import dmd.optimize; +import dmd.parse; +import dmd.root.array; +import dmd.root.filename; +import dmd.common.outbuffer; +import dmd.root.rmem; +import dmd.rootobject; +import dmd.root.utf; +import dmd.semantic2; +import dmd.semantic3; +import dmd.sideeffect; +import dmd.statementsem; +import dmd.staticassert; +import dmd.tokens; +import dmd.utils; +import dmd.statement; +import dmd.target; +import dmd.templateparamsem; +import dmd.typesem; +import dmd.visitor; + + +/********************************* + * Perform semantic analysis on enum declaration `em` + */ +void enumSemantic(Scope* sc, EnumDeclaration ed) +{ + //printf("EnumDeclaration::semantic(sd = %p, '%s') %s\n", sc.scopesym, sc.scopesym.toChars(), ed.toChars()); + //printf("EnumDeclaration::semantic() %p %s\n", ed, ed.toChars()); + if (ed.semanticRun >= PASS.semanticdone) + return; // semantic() already completed + if (ed.semanticRun == PASS.semantic) + { + assert(ed.memtype); + error(ed.loc, "circular reference to enum base type `%s`", ed.memtype.toChars()); + ed.errors = true; + ed.semanticRun = PASS.semanticdone; + return; + } + Scope* scx = null; + if (ed._scope) + { + sc = ed._scope; + scx = ed._scope; // save so we don't make redundant copies + ed._scope = null; + } + + if (!sc) + return; + + ed.parent = sc.parent; + ed.type = ed.type.typeSemantic(ed.loc, sc); + + ed.visibility = sc.visibility; + if (sc.stc & STC.deprecated_) + ed.isdeprecated = true; + ed.userAttribDecl = sc.userAttribDecl; + ed.cppnamespace = sc.namespace; + + ed.semanticRun = PASS.semantic; + UserAttributeDeclaration.checkGNUABITag(ed, sc.linkage); + checkMustUseReserved(ed); + + if (!ed.members && !ed.memtype) // enum ident; + { + ed.semanticRun = PASS.semanticdone; + return; + } + + if (!ed.symtab) + ed.symtab = new DsymbolTable(); + + /* The separate, and distinct, cases are: + * 1. enum { ... } + * 2. enum : memtype { ... } + * 3. enum ident { ... } + * 4. enum ident : memtype { ... } + * 5. enum ident : memtype; + * 6. enum ident; + */ + + if (ed.memtype) + { + ed.memtype = ed.memtype.typeSemantic(ed.loc, sc); + + /* Check to see if memtype is forward referenced + */ + if (auto te = ed.memtype.isTypeEnum()) + { + auto sym = te.toDsymbol(sc).isEnumDeclaration(); + // Special enums like __c_[u]long[long] are fine to forward reference + // see https://issues.dlang.org/show_bug.cgi?id=20599 + if (!sym.isSpecial() && (!sym.memtype || !sym.members || !sym.symtab || sym._scope)) + { + // memtype is forward referenced, so try again later + deferDsymbolSemantic(sc, ed, scx); + //printf("\tdeferring %s\n", toChars()); + ed.semanticRun = PASS.initial; + return; + } + else + // Ensure that semantic is run to detect. e.g. invalid forward references + sym.dsymbolSemantic(sc); + } + if (ed.memtype.ty == Tvoid) + { + .error(ed.loc, "%s `%s` base type must not be `void`", ed.kind, ed.toPrettyChars); + ed.memtype = Type.terror; + } + if (ed.memtype.ty == Terror) + { + ed.errors = true; + // poison all the members + ed.members.foreachDsymbol( (s) { s.errors = true; } ); + ed.semanticRun = PASS.semanticdone; + return; + } + } + + if (!ed.members) // enum ident : memtype; + { + ed.semanticRun = PASS.semanticdone; + return; + } + + if (ed.members.length == 0) + { + .error(ed.loc, "%s `%s enum `%s` must have at least one member", ed.kind, ed.toPrettyChars, ed.toChars()); + ed.errors = true; + ed.semanticRun = PASS.semanticdone; + return; + } + + if (!(sc.flags & SCOPE.Cfile)) // C enum remains incomplete until members are done + ed.semanticRun = PASS.semanticdone; + + version (none) + { + // @@@DEPRECATED_2.110@@@ https://dlang.org/deprecate.html#scope%20as%20a%20type%20constraint + // Deprecated in 2.100 + // Make an error in 2.110 + if (sc.stc & STC.scope_) + deprecation(ed.loc, "`scope` as a type constraint is deprecated. Use `scope` at the usage site."); + } + + Scope* sce; + if (ed.isAnonymous()) + sce = sc; + else + { + sce = sc.push(ed); + sce.parent = ed; + } + sce = sce.startCTFE(); + sce.setNoFree(); // needed for getMaxMinValue() + + /* Each enum member gets the sce scope + */ + ed.members.foreachDsymbol( (s) + { + EnumMember em = s.isEnumMember(); + if (em) + em._scope = sce; + }); + + /* addMember() is not called when the EnumDeclaration appears as a function statement, + * so we have to do what addMember() does and install the enum members in the right symbol + * table + */ + addEnumMembersToSymtab(ed, sc, sc.getScopesym()); + + if (sc.flags & SCOPE.Cfile) + { + /* C11 6.7.2.2 + */ + Type commonType = ed.memtype; + if (!commonType) + commonType = Type.tint32; + ulong nextValue = 0; // C11 6.7.2.2-3 first member value defaults to 0 + + // C11 6.7.2.2-2 value must be representable as an int. + // The sizemask represents all values that int will fit into, + // from 0..uint.max. We want to cover int.min..uint.max. + IntRange ir = IntRange.fromType(commonType); + + void emSemantic(EnumMember em, ref ulong nextValue) + { + static void errorReturn(EnumMember em) + { + em.value = ErrorExp.get(); + em.errors = true; + em.semanticRun = PASS.semanticdone; + } + + em.semanticRun = PASS.semantic; + em.type = commonType; + em._linkage = LINK.c; + em.storage_class |= STC.manifest; + if (em.value) + { + Expression e = em.value; + assert(e.dyncast() == DYNCAST.expression); + + /* To merge the type of e with commonType, add 0 of type commonType + */ + if (!ed.memtype) + e = new AddExp(em.loc, e, new IntegerExp(em.loc, 0, commonType)); + + e = e.expressionSemantic(sc); + e = resolveProperties(sc, e); + e = e.integralPromotions(sc); + e = e.ctfeInterpret(); + if (e.op == EXP.error) + return errorReturn(em); + auto ie = e.isIntegerExp(); + if (!ie) + { + // C11 6.7.2.2-2 + .error(em.loc, "%s `%s` enum member must be an integral constant expression, not `%s` of type `%s`", em.kind, em.toPrettyChars, e.toChars(), e.type.toChars()); + return errorReturn(em); + } + if (ed.memtype && !ir.contains(getIntRange(ie))) + { + // C11 6.7.2.2-2 + .error(em.loc, "%s `%s` enum member value `%s` does not fit in `%s`", em.kind, em.toPrettyChars, e.toChars(), commonType.toChars()); + return errorReturn(em); + } + nextValue = ie.toInteger(); + if (!ed.memtype) + commonType = e.type; + em.value = new IntegerExp(em.loc, nextValue, commonType); + } + else + { + // C11 6.7.2.2-3 add 1 to value of previous enumeration constant + bool first = (em == (*em.ed.members)[0]); + if (!first) + { + Expression max = getProperty(commonType, null, em.loc, Id.max, 0); + if (nextValue == max.toInteger()) + { + .error(em.loc, "%s `%s` initialization with `%s+1` causes overflow for type `%s`", em.kind, em.toPrettyChars, max.toChars(), commonType.toChars()); + return errorReturn(em); + } + nextValue += 1; + } + em.value = new IntegerExp(em.loc, nextValue, commonType); + } + em.type = commonType; + em.semanticRun = PASS.semanticdone; + } + + ed.members.foreachDsymbol( (s) + { + if (EnumMember em = s.isEnumMember()) + emSemantic(em, nextValue); + }); + + if (!ed.memtype) + { + // cast all members to commonType + ed.members.foreachDsymbol( (s) + { + if (EnumMember em = s.isEnumMember()) + { + em.type = commonType; + em.value = em.value.castTo(sc, commonType); + } + }); + } + + ed.memtype = commonType; + ed.semanticRun = PASS.semanticdone; + return; + } + + ed.members.foreachDsymbol( (s) + { + if (EnumMember em = s.isEnumMember()) + em.dsymbolSemantic(em._scope); + }); + //printf("ed.defaultval = %lld\n", ed.defaultval); + + //if (ed.defaultval) printf("ed.defaultval: %s %s\n", ed.defaultval.toChars(), ed.defaultval.type.toChars()); + //printf("members = %s\n", members.toChars()); +} + +Expression getDefaultValue(EnumDeclaration ed, const ref Loc loc) +{ + Expression handleErrors(){ + ed.defaultval = ErrorExp.get(); + return ed.defaultval; + } + //printf("EnumDeclaration::getDefaultValue() %p %s\n", this, toChars()); + // https://issues.dlang.org/show_bug.cgi?id=23904 + // Return ed.defaultval only if it is not ErrorExp. + // A speculative context may set ed.defaultval to ErrorExp; + // subsequent non-speculative contexts need to be able + // to print the error. + if (ed.defaultval && !ed.defaultval.isErrorExp()) + return ed.defaultval; + + if (ed.isCsymbol()) + return ed.memtype.defaultInit(loc, true); + + if (ed._scope) + dsymbolSemantic(ed, ed._scope); + if (ed.errors) + return handleErrors(); + if (!ed.members) + { + if (ed.isSpecial()) + { + /* Allow these special enums to not need a member list + */ + return ed.defaultval = ed.memtype.defaultInit(loc); + } + + error(loc, "%s `%s` is opaque and has no default initializer", ed.kind, ed.toPrettyChars); + return handleErrors(); + } + + foreach (const i; 0 .. ed.members.length) + { + EnumMember em = (*ed.members)[i].isEnumMember(); + if (em) + { + if (em.semanticRun < PASS.semanticdone) + { + error(loc, "%s `%s` forward reference of `%s.init`", ed.kind, ed.toPrettyChars, ed.toChars()); + return handleErrors(); + } + + ed.defaultval = em.value; + return ed.defaultval; + } + } + return handleErrors(); +} + +Type getMemtype(EnumDeclaration ed, const ref Loc loc) +{ + if (ed._scope) + { + /* Enum is forward referenced. We don't need to resolve the whole thing, + * just the base type + */ + if (ed.memtype) + { + Loc locx = loc.isValid() ? loc : ed.loc; + ed.memtype = ed.memtype.typeSemantic(locx, ed._scope); + } + else + { + // Run semantic to get the type from a possible first member value + dsymbolSemantic(ed, ed._scope); + } + } + if (!ed.memtype) + { + if (!ed.isAnonymous() && (ed.members || ed.semanticRun >= PASS.semanticdone)) + ed.memtype = Type.tint32; + else + { + Loc locx = loc.isValid() ? loc : ed.loc; + error(locx, "is forward referenced looking for base type"); + return Type.terror; + } + } + return ed.memtype; +} + +/********************************* + * Perform semantic analysis on enum member `em` + */ +void enumMemberSemantic(Scope* sc, EnumMember em) +{ + //printf("EnumMember::semantic() %s\n", em.toChars()); + + void errorReturn() + { + em.errors = true; + em.semanticRun = PASS.semanticdone; + } + + if (em.errors || em.semanticRun >= PASS.semanticdone) + return; + if (em.semanticRun == PASS.semantic) + { + .error(em.loc, "%s `%s` circular reference to `enum` member", em.kind, em.toPrettyChars); + return errorReturn(); + } + assert(em.ed); + + em.ed.dsymbolSemantic(sc); + if (em.ed.errors) + return errorReturn(); + if (em.errors || em.semanticRun >= PASS.semanticdone) + return; + + if (em._scope) + sc = em._scope; + if (!sc) + return; + + em.semanticRun = PASS.semantic; + + em.visibility = em.ed.isAnonymous() ? em.ed.visibility : Visibility(Visibility.Kind.public_); + em._linkage = LINK.d; + em.storage_class |= STC.manifest; + + // https://issues.dlang.org/show_bug.cgi?id=9701 + if (em.ed.isAnonymous()) + { + if (em.userAttribDecl) + em.userAttribDecl.userAttribDecl = em.ed.userAttribDecl; + else + em.userAttribDecl = em.ed.userAttribDecl; + } + + // Eval UDA in this same scope. Issues 19344, 20835, 21122 + if (em.userAttribDecl) + { + // Set scope but avoid extra sc.uda attachment inside setScope() + auto inneruda = em.userAttribDecl.userAttribDecl; + em.userAttribDecl.setScope(sc); + em.userAttribDecl.userAttribDecl = inneruda; + em.userAttribDecl.dsymbolSemantic(sc); + } + + // The first enum member is special + bool first = (em == (*em.ed.members)[0]); + + if (em.origType) + { + em.origType = em.origType.typeSemantic(em.loc, sc); + em.type = em.origType; + assert(em.value); // "type id;" is not a valid enum member declaration + } + + if (em.value) + { + Expression e = em.value; + assert(e.dyncast() == DYNCAST.expression); + e = e.expressionSemantic(sc); + e = resolveProperties(sc, e); + e = e.ctfeInterpret(); + if (e.op == EXP.error) + return errorReturn(); + if (first && !em.ed.memtype && !em.ed.isAnonymous()) + { + em.ed.memtype = e.type; + if (em.ed.memtype.ty == Terror) + { + em.ed.errors = true; + return errorReturn(); + } + if (em.ed.memtype.ty != Terror) + { + /* https://issues.dlang.org/show_bug.cgi?id=11746 + * All of named enum members should have same type + * with the first member. If the following members were referenced + * during the first member semantic, their types should be unified. + */ + em.ed.members.foreachDsymbol( (s) + { + EnumMember enm = s.isEnumMember(); + if (!enm || enm == em || enm.semanticRun < PASS.semanticdone || enm.origType) + return; + + //printf("[%d] em = %s, em.semanticRun = %d\n", i, toChars(), em.semanticRun); + Expression ev = enm.value; + ev = ev.implicitCastTo(sc, em.ed.memtype); + ev = ev.ctfeInterpret(); + ev = ev.castTo(sc, em.ed.type); + if (ev.op == EXP.error) + em.ed.errors = true; + enm.value = ev; + }); + + if (em.ed.errors) + { + em.ed.memtype = Type.terror; + return errorReturn(); + } + } + } + + if (em.ed.memtype && !em.origType) + { + e = e.implicitCastTo(sc, em.ed.memtype); + e = e.ctfeInterpret(); + + // save origValue for better json output + em.origValue = e; + + if (!em.ed.isAnonymous()) + { + e = e.castTo(sc, em.ed.type.addMod(e.type.mod)); // https://issues.dlang.org/show_bug.cgi?id=12385 + e = e.ctfeInterpret(); + } + } + else if (em.origType) + { + e = e.implicitCastTo(sc, em.origType); + e = e.ctfeInterpret(); + assert(em.ed.isAnonymous()); + + // save origValue for better json output + em.origValue = e; + } + em.value = e; + } + else if (first) + { + Type t; + if (em.ed.memtype) + t = em.ed.memtype; + else + { + t = Type.tint32; + if (!em.ed.isAnonymous()) + em.ed.memtype = t; + } + const errors = global.startGagging(); + Expression e = new IntegerExp(em.loc, 0, t); + e = e.ctfeInterpret(); + if (global.endGagging(errors)) + { + error(em.loc, "cannot generate 0 value of type `%s` for `%s`", + t.toChars(), em.toChars()); + } + // save origValue for better json output + em.origValue = e; + + if (!em.ed.isAnonymous()) + { + e = e.castTo(sc, em.ed.type); + e = e.ctfeInterpret(); + } + em.value = e; + } + else + { + /* Find the previous enum member, + * and set this to be the previous value + 1 + */ + EnumMember emprev = null; + em.ed.members.foreachDsymbol( (s) + { + if (auto enm = s.isEnumMember()) + { + if (enm == em) + return 1; // found + emprev = enm; + } + return 0; // continue + }); + + assert(emprev); + if (emprev.semanticRun < PASS.semanticdone) // if forward reference + emprev.dsymbolSemantic(emprev._scope); // resolve it + if (emprev.errors) + return errorReturn(); + + auto errors = global.startGagging(); + Expression eprev = emprev.value; + assert(eprev); + // .toHeadMutable() due to https://issues.dlang.org/show_bug.cgi?id=18645 + Type tprev = eprev.type.toHeadMutable().equals(em.ed.type.toHeadMutable()) + ? em.ed.memtype + : eprev.type; + /* + https://issues.dlang.org/show_bug.cgi?id=20777 + Previously this used getProperty, which doesn't consider anything user defined, + this construct does do that and thus fixes the bug. + */ + Expression emax = DotIdExp.create(em.ed.loc, new TypeExp(em.ed.loc, tprev), Id.max); + emax = emax.expressionSemantic(sc); + emax = emax.ctfeInterpret(); + + // check that (eprev != emax) + Expression e = new EqualExp(EXP.equal, em.loc, eprev, emax); + e = e.expressionSemantic(sc); + e = e.ctfeInterpret(); + if (global.endGagging(errors)) + { + // display an introductory error before showing what actually failed + error(em.loc, "cannot check `%s` value for overflow", em.toPrettyChars()); + // rerun to show errors + Expression e2 = DotIdExp.create(em.ed.loc, new TypeExp(em.ed.loc, tprev), Id.max); + e2 = e2.expressionSemantic(sc); + e2 = e2.ctfeInterpret(); + e2 = new EqualExp(EXP.equal, em.loc, eprev, e2); + e2 = e2.expressionSemantic(sc); + e2 = e2.ctfeInterpret(); + } + // now any errors are for generating a value + if (e.toInteger()) + { + auto mt = em.ed.memtype; + if (!mt) + mt = eprev.type; + .error(em.loc, "%s `%s` initialization with `%s.%s+1` causes overflow for type `%s`", em.kind, em.toPrettyChars, + emprev.ed.toChars(), emprev.toChars(), mt.toChars()); + return errorReturn(); + } + errors = global.startGagging(); + // Now set e to (eprev + 1) + e = new AddExp(em.loc, eprev, IntegerExp.literal!1); + e = e.expressionSemantic(sc); + e = e.castTo(sc, eprev.type); + e = e.ctfeInterpret(); + if (global.endGagging(errors)) + { + error(em.loc, "cannot generate value for `%s`", em.toPrettyChars()); + // rerun to show errors + Expression e2 = new AddExp(em.loc, eprev, IntegerExp.literal!1); + e2 = e2.expressionSemantic(sc); + e2 = e2.castTo(sc, eprev.type); + e2 = e2.ctfeInterpret(); + } + // save origValue (without cast) for better json output + if (e.op != EXP.error) // avoid duplicate diagnostics + { + assert(emprev.origValue); + em.origValue = new AddExp(em.loc, emprev.origValue, IntegerExp.literal!1); + em.origValue = em.origValue.expressionSemantic(sc); + em.origValue = em.origValue.ctfeInterpret(); + } + + if (e.op == EXP.error) + return errorReturn(); + if (e.type.isfloating()) + { + // Check that e != eprev (not always true for floats) + Expression etest = new EqualExp(EXP.equal, em.loc, e, eprev); + etest = etest.expressionSemantic(sc); + etest = etest.ctfeInterpret(); + if (etest.toInteger()) + { + .error(em.loc, "%s `%s` has inexact value due to loss of precision", em.kind, em.toPrettyChars); + return errorReturn(); + } + } + em.value = e; + } + if (!em.origType) + em.type = em.value.type; + + assert(em.origValue); + em.semanticRun = PASS.semanticdone; +} diff --git a/gcc/d/dmd/expression.d b/gcc/d/dmd/expression.d index cbf0118..1603f2b 100644 --- a/gcc/d/dmd/expression.d +++ b/gcc/d/dmd/expression.d @@ -721,6 +721,7 @@ extern (C++) abstract class Expression : ASTNode inout(SuperExp) isSuperExp() { return op == EXP.super_ ? cast(typeof(return))this : null; } inout(NullExp) isNullExp() { return op == EXP.null_ ? cast(typeof(return))this : null; } inout(StringExp) isStringExp() { return op == EXP.string_ ? cast(typeof(return))this : null; } + inout(InterpExp) isInterpExp() { return op == EXP.interpolated ? cast(typeof(return))this : null; } inout(TupleExp) isTupleExp() { return op == EXP.tuple ? cast(typeof(return))this : null; } inout(ArrayLiteralExp) isArrayLiteralExp() { return op == EXP.arrayLiteral ? cast(typeof(return))this : null; } inout(AssocArrayLiteralExp) isAssocArrayLiteralExp() { return op == EXP.assocArrayLiteral ? cast(typeof(return))this : null; } @@ -1499,6 +1500,7 @@ extern (C++) final class StringExp : Expression char* string; // if sz == 1 wchar* wstring; // if sz == 2 dchar* dstring; // if sz == 4 + ulong* lstring; // if sz == 8 } // (const if ownedByCtfe == OwnedBy.code) size_t len; // number of code units ubyte sz = 1; // 1: char, 2: wchar, 4: dchar @@ -1662,6 +1664,13 @@ extern (C++) final class StringExp : Expression */ dchar getCodeUnit(size_t i) const pure { + assert(this.sz <= dchar.sizeof); + return cast(dchar) getIndex(i); + } + + /// Returns: integer at index `i` + dinteger_t getIndex(size_t i) const pure + { assert(i < len); final switch (sz) { @@ -1671,6 +1680,8 @@ extern (C++) final class StringExp : Expression return wstring[i]; case 4: return dstring[i]; + case 8: + return lstring[i]; } } @@ -1682,6 +1693,11 @@ extern (C++) final class StringExp : Expression */ extern (D) void setCodeUnit(size_t i, dchar c) { + return setIndex(i, c); + } + + extern (D) void setIndex(size_t i, long c) + { assert(i < len); final switch (sz) { @@ -1692,7 +1708,10 @@ extern (C++) final class StringExp : Expression wstring[i] = cast(wchar)c; break; case 4: - dstring[i] = c; + dstring[i] = cast(dchar) c; + break; + case 8: + lstring[i] = c; break; } } @@ -1847,6 +1866,28 @@ extern (C++) final class StringExp : Expression } } +extern (C++) final class InterpExp : Expression +{ + char postfix = NoPostfix; // 'c', 'w', 'd' + OwnedBy ownedByCtfe = OwnedBy.code; + InterpolatedSet* interpolatedSet; + + enum char NoPostfix = 0; + + extern (D) this(const ref Loc loc, InterpolatedSet* set, char postfix = NoPostfix) scope + { + super(loc, EXP.interpolated); + this.interpolatedSet = set; + this.postfix = postfix; + } + + override void accept(Visitor v) + { + v.visit(this); + } +} + + /*********************************************************** * A sequence of expressions * @@ -5494,6 +5535,7 @@ private immutable ubyte[EXP.max+1] expSize = [ EXP.preMinusMinus: __traits(classInstanceSize, PreExp), EXP.identifier: __traits(classInstanceSize, IdentifierExp), EXP.string_: __traits(classInstanceSize, StringExp), + EXP.interpolated: __traits(classInstanceSize, InterpExp), EXP.this_: __traits(classInstanceSize, ThisExp), EXP.super_: __traits(classInstanceSize, SuperExp), EXP.halt: __traits(classInstanceSize, HaltExp), diff --git a/gcc/d/dmd/expression.h b/gcc/d/dmd/expression.h index f57f6a4..d53cc3e 100644 --- a/gcc/d/dmd/expression.h +++ b/gcc/d/dmd/expression.h @@ -38,6 +38,7 @@ class TemplateDeclaration; class ClassDeclaration; class OverloadSet; class StringExp; +class InterpExp; class LoweredAssignExp; #ifdef IN_GCC typedef union tree_node Symbol; @@ -129,6 +130,7 @@ public: SuperExp* isSuperExp(); NullExp* isNullExp(); StringExp* isStringExp(); + InterpExp* isInterpExp(); TupleExp* isTupleExp(); ArrayLiteralExp* isArrayLiteralExp(); AssocArrayLiteralExp* isAssocArrayLiteralExp(); @@ -352,7 +354,7 @@ class StringExp final : public Expression public: utf8_t postfix; // 'c', 'w', 'd' OwnedBy ownedByCtfe; - void *string; // char, wchar, or dchar data + void *string; // char, wchar, dchar, or long data size_t len; // number of chars, wchars, or dchars unsigned char sz; // 1: char, 2: wchar, 4: dchar d_bool committed; // if type is committed @@ -362,6 +364,7 @@ public: static StringExp *create(const Loc &loc, const void *s, d_size_t len); bool equals(const RootObject * const o) const override; char32_t getCodeUnit(d_size_t i) const; + dinteger_t getIndex(d_size_t i) const; StringExp *toStringExp() override; Optional toBool() override; bool isLvalue() override; @@ -370,6 +373,16 @@ public: void writeTo(void* dest, bool zero, int tyto = 0) const; }; +class InterpExp final : public Expression +{ +public: + utf8_t postfix; // 'c', 'w', 'd' + OwnedBy ownedByCtfe; + void* interpolatedSet; + + void accept(Visitor* v) override { v->visit(this); } +}; + // Tuple class TupleExp final : public Expression diff --git a/gcc/d/dmd/expressionsem.d b/gcc/d/dmd/expressionsem.d index d464574..f213303 100644 --- a/gcc/d/dmd/expressionsem.d +++ b/gcc/d/dmd/expressionsem.d @@ -42,10 +42,12 @@ import dmd.dsymbolsem; import dmd.dtemplate; import dmd.errors; import dmd.errorsink; +import dmd.enumsem; import dmd.escape; import dmd.expression; import dmd.file_manager; import dmd.func; +import dmd.funcsem; import dmd.globals; import dmd.hdrgen; import dmd.id; @@ -1579,7 +1581,7 @@ Lagain: if (auto f = s.isFuncDeclaration()) { f = f.toAliasFunc(); - if (!f.functionSemantic()) + if (!functionSemantic(f)) return ErrorExp.get(); if (!hasOverloads && f.checkForwardRef(loc)) @@ -2866,7 +2868,7 @@ private bool functionParameters(const ref Loc loc, Scope* sc, // If inferring return type, and semantic3() needs to be run if not already run if (!tf.next && fd.inferRetType) { - fd.functionSemantic(); + functionSemantic(fd); } else if (fd && fd.parent) { @@ -4145,6 +4147,84 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor result = e; } + override void visit(InterpExp e) + { + // the lexer breaks up into an odd/even array of literals and expression code + // we need to turn that into: + /+ + tuple( + .object.imported!"core.interpolation".InterpolationHeader(), + ... + .object.imported!"core.interpolation".InterpolationFooter() + ) + + There the ... loops through them all, making the even ones + .object.imported!"core.interpolation".InterpolatedLiteral!str() + and making the odd ones + .object.imported!"core.interpolation".InterpolatedExpression!str(), + the code represented by str + + Empty string literals are skipped as they provide no additional information. + +/ + + if (e.postfix) + error(e.loc, "String postfixes on interpolated expression sequences are not allowed."); + + Expression makeNonTemplateItem(Identifier which) { + Expression id = new IdentifierExp(e.loc, Id.empty); + id = new DotIdExp(e.loc, id, Id.object); + auto moduleNameArgs = new Objects(); + moduleNameArgs.push(new StringExp(e.loc, "core.interpolation")); + id = new DotTemplateInstanceExp(e.loc, id, Id.imported, moduleNameArgs); + id = new DotIdExp(e.loc, id, which); + id = new CallExp(e.loc, id, new Expressions()); + return id; + } + + Expression makeTemplateItem(Identifier which, string arg) { + Expression id = new IdentifierExp(e.loc, Id.empty); + id = new DotIdExp(e.loc, id, Id.object); + auto moduleNameArgs = new Objects(); + moduleNameArgs.push(new StringExp(e.loc, "core.interpolation")); + id = new DotTemplateInstanceExp(e.loc, id, Id.imported, moduleNameArgs); + auto tiargs = new Objects(); + auto templateStringArg = new StringExp(e.loc, arg); + // banning those instead of forwarding them + // templateStringArg.postfix = e.postfix; // forward the postfix to these literals + tiargs.push(templateStringArg); + id = new DotTemplateInstanceExp(e.loc, id, which, tiargs); + id = new CallExp(e.loc, id, new Expressions()); + return id; + } + + auto arguments = new Expressions(); + arguments.push(makeNonTemplateItem(Id.InterpolationHeader)); + + foreach (idx, str; e.interpolatedSet.parts) + { + if (idx % 2 == 0) + { + if (str.length > 0) + arguments.push(makeTemplateItem(Id.InterpolatedLiteral, str)); + } + else + { + arguments.push(makeTemplateItem(Id.InterpolatedExpression, str)); + Expressions* mix = new Expressions(); + mix.push(new StringExp(e.loc, str)); + // FIXME: i'd rather not use MixinExp but idk how to do it lol + arguments.push(new MixinExp(e.loc, mix)); + } + } + + arguments.push(makeNonTemplateItem(Id.InterpolationFooter)); + + auto loweredTo = new TupleExp(e.loc, arguments); + visit(loweredTo); + + result = loweredTo; + } + override void visit(StringExp e) { static if (LOGSEMANTIC) @@ -5366,7 +5446,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor if (fd) { //printf("L%d fd = %s\n", __LINE__, f.toChars()); - if (!fd.functionSemantic()) + if (!functionSemantic(fd)) return setError(); } @@ -6564,10 +6644,11 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor .errorSupplemental(exp.loc, "the following error occured while looking for a UFCS match"); } - .error(exp.loc, "%s `%s%s` is not callable using argument types `%s`", - exp.f.kind(), exp.f.toPrettyChars(), parametersTypeToChars(tf.parameterList), buf.peekChars()); + .error(exp.loc, "%s `%s` is not callable using argument types `%s`", + exp.f.kind(), exp.f.toChars(), buf.peekChars()); if (failMessage) errorSupplemental(exp.loc, "%s", failMessage); + .errorSupplemental(exp.f.loc, "`%s%s` declared here", exp.f.toPrettyChars(), parametersTypeToChars(tf.parameterList)); exp.f = null; } @@ -7549,7 +7630,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor se = se.toUTF8(sc); auto namez = se.toStringz(); - if (!global.filePath) + if (!global.filePath.length) { error(e.loc, "need `-J` switch to import text file `%s`", namez.ptr); return setError(); @@ -7580,12 +7661,12 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor return setError(); } - auto resolvedNamez = FileName.searchPath(global.filePath, namez, false); + auto resolvedNamez = FileName.searchPath(global.filePath[], namez, false); if (!resolvedNamez) { error(e.loc, "file `%s` cannot be found or not in a path specified with `-J`", se.toChars()); errorSupplemental(e.loc, "Path(s) searched (as provided by `-J`):"); - foreach (idx, path; *global.filePath) + foreach (idx, path; global.filePath[]) { const attr = FileName.exists(path); const(char)* err = attr == 2 ? "" : @@ -8170,7 +8251,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor if (FuncDeclaration fd = exp.var.isFuncDeclaration()) { // for functions, do checks after overload resolution - if (!fd.functionSemantic()) + if (!functionSemantic(fd)) return setError(); /* https://issues.dlang.org/show_bug.cgi?id=13843 @@ -8937,7 +9018,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor bool err = false; if (cd.dtor) { - err |= !cd.dtor.functionSemantic(); + err |= !functionSemantic(cd.dtor); err |= cd.dtor.checkPurity(exp.loc, sc); err |= cd.dtor.checkSafety(exp.loc, sc); err |= cd.dtor.checkNogc(exp.loc, sc); @@ -14356,7 +14437,7 @@ Expression dotIdSemanticProp(DotIdExp exp, Scope* sc, bool gag) if (auto f = s.isFuncDeclaration()) { //printf("it's a function\n"); - if (!f.functionSemantic()) + if (!functionSemantic(f)) return ErrorExp.get(); Expression e; if (f.needThis()) diff --git a/gcc/d/dmd/func.d b/gcc/d/dmd/func.d index 370da6f..adfecc8 100644 --- a/gcc/d/dmd/func.d +++ b/gcc/d/dmd/func.d @@ -39,6 +39,7 @@ import dmd.dtemplate; import dmd.errors; import dmd.escape; import dmd.expression; +import dmd.funcsem; import dmd.globals; import dmd.hdrgen; import dmd.id; @@ -467,102 +468,12 @@ extern (C++) class FuncDeclaration : Declaration } /**************************************************** - * Resolve forward reference of function signature - - * parameter types, return type, and attributes. - * Returns: - * false if any errors exist in the signature. - */ - final bool functionSemantic() - { - //printf("functionSemantic() %p %s\n", this, toChars()); - if (!_scope) - return !errors; - - this.cppnamespace = _scope.namespace; - - if (!originalType) // semantic not yet run - { - TemplateInstance spec = isSpeculative(); - uint olderrs = global.errors; - uint oldgag = global.gag; - if (global.gag && !spec) - global.gag = 0; - dsymbolSemantic(this, _scope); - global.gag = oldgag; - if (spec && global.errors != olderrs) - spec.errors = (global.errors - olderrs != 0); - if (olderrs != global.errors) // if errors compiling this function - return false; - } - - // if inferring return type, sematic3 needs to be run - // - When the function body contains any errors, we cannot assume - // the inferred return type is valid. - // So, the body errors should become the function signature error. - if (inferRetType && type && !type.nextOf()) - return functionSemantic3(); - - TemplateInstance ti; - if (isInstantiated() && !isVirtualMethod() && - ((ti = parent.isTemplateInstance()) is null || ti.isTemplateMixin() || ti.tempdecl.ident == ident)) - { - AggregateDeclaration ad = isMemberLocal(); - if (ad && ad.sizeok != Sizeok.done) - { - /* Currently dmd cannot resolve forward references per methods, - * then setting SIZOKfwd is too conservative and would break existing code. - * So, just stop method attributes inference until ad.dsymbolSemantic() done. - */ - //ad.sizeok = Sizeok.fwd; - } - else - return functionSemantic3() || !errors; - } - - if (storage_class & STC.inference) - return functionSemantic3() || !errors; - - return !errors; - } - - /**************************************************** - * Resolve forward reference of function body. - * Returns false if any errors exist in the body. - */ - final bool functionSemantic3() - { - if (semanticRun < PASS.semantic3 && _scope) - { - /* Forward reference - we need to run semantic3 on this function. - * If errors are gagged, and it's not part of a template instance, - * we need to temporarily ungag errors. - */ - TemplateInstance spec = isSpeculative(); - uint olderrs = global.errors; - uint oldgag = global.gag; - if (global.gag && !spec) - global.gag = 0; - semantic3(this, _scope); - global.gag = oldgag; - - // If it is a speculatively-instantiated template, and errors occur, - // we need to mark the template as having errors. - if (spec && global.errors != olderrs) - spec.errors = (global.errors - olderrs != 0); - if (olderrs != global.errors) // if errors compiling this function - return false; - } - - return !errors && !this.hasSemantic3Errors(); - } - - /**************************************************** * Check that this function type is properly resolved. * If not, report "forward reference error" and return true. */ extern (D) final bool checkForwardRef(const ref Loc loc) { - if (!functionSemantic()) + if (!functionSemantic(this)) return true; /* No deco means the functionSemantic() call could not resolve @@ -579,72 +490,6 @@ extern (C++) class FuncDeclaration : Declaration return false; } - // called from semantic3 - /** - * Creates and returns the hidden parameters for this function declaration. - * - * Hidden parameters include the `this` parameter of a class, struct or - * nested function and the selector parameter for Objective-C methods. - */ - extern (D) final void declareThis(Scope* sc) - { - const bool dualCtx = (toParent2() != toParentLocal()); - if (dualCtx) - this.hasDualContext = true; - auto ad = isThis(); - if (!dualCtx && !ad && !isNested()) - { - vthis = null; - objc.selectorParameter = null; - return; - } - - Type addModStc(Type t) - { - return t.addMod(type.mod).addStorageClass(storage_class); - } - - if (dualCtx || isNested()) - { - /* The 'this' for a nested function is the link to the - * enclosing function's stack frame. - * Note that nested functions and member functions are disjoint. - */ - Type tthis = addModStc(dualCtx ? - Type.tvoidptr.sarrayOf(2).pointerTo() : - Type.tvoid.pointerTo()); - vthis = new VarDeclaration(loc, tthis, dualCtx ? Id.this2 : Id.capture, null); - vthis.storage_class |= STC.parameter | STC.nodtor; - } - else if (ad) - { - Type thandle = addModStc(ad.handleType()); - vthis = new ThisDeclaration(loc, thandle); - vthis.storage_class |= STC.parameter; - if (thandle.ty == Tstruct) - { - vthis.storage_class |= STC.ref_; - } - } - - if (auto tf = type.isTypeFunction()) - { - if (tf.isreturn) - vthis.storage_class |= STC.return_; - if (tf.isScopeQual) - vthis.storage_class |= STC.scope_; - if (tf.isreturnscope) - vthis.storage_class |= STC.returnScope; - } - - vthis.dsymbolSemantic(sc); - if (!sc.insert(vthis)) - assert(0); - vthis.parent = this; - if (ad) - objc.selectorParameter = .objc.createSelectorParameter(this, sc); - } - override final bool equals(const RootObject o) const { if (this == o) @@ -1104,20 +949,24 @@ extern (C++) class FuncDeclaration : Declaration } /************************************* - * Determine partial specialization order of 'this' vs g. + * Determine partial specialization order of functions `f` vs `g`. * This is very similar to TemplateDeclaration::leastAsSpecialized(). + * Params: + * f = first function + * g = second function + * names = names of parameters * Returns: * match 'this' is at least as specialized as g * 0 g is more specialized than 'this' */ - final MATCH leastAsSpecialized(FuncDeclaration g, Identifiers* names) + static MATCH leastAsSpecialized(FuncDeclaration f, FuncDeclaration g, Identifiers* names) { enum LOG_LEASTAS = 0; static if (LOG_LEASTAS) { import core.stdc.stdio : printf; - printf("%s.leastAsSpecialized(%s, %s)\n", toChars(), g.toChars(), names ? names.toChars() : "null"); - printf("%s, %s\n", type.toChars(), g.type.toChars()); + printf("leastAsSpecialized(%s, %s, %s)\n", f.toChars(), g.toChars(), names ? names.toChars() : "null"); + printf("%s, %s\n", f.type.toChars(), g.type.toChars()); } /* This works by calling g() with f()'s parameters, and @@ -1125,15 +974,15 @@ extern (C++) class FuncDeclaration : Declaration * as g() is. */ - TypeFunction tf = type.toTypeFunction(); + TypeFunction tf = f.type.toTypeFunction(); TypeFunction tg = g.type.toTypeFunction(); /* If both functions have a 'this' pointer, and the mods are not * the same and g's is not const, then this is less specialized. */ - if (needThis() && g.needThis() && tf.mod != tg.mod) + if (f.needThis() && g.needThis() && tf.mod != tg.mod) { - if (isCtorDeclaration()) + if (f.isCtorDeclaration()) { if (!MODimplicitConv(tg.mod, tf.mod)) return MATCH.nomatch; @@ -3037,7 +2886,7 @@ Expression addInvariant(AggregateDeclaration ad, VarDeclaration vthis) // Workaround for https://issues.dlang.org/show_bug.cgi?id=13394 // For the correct mangling, // run attribute inference on inv if needed. - inv.functionSemantic(); + functionSemantic(inv); } //e = new DsymbolExp(Loc.initial, inv); @@ -3316,7 +3165,7 @@ FuncDeclaration resolveFuncCall(const ref Loc loc, Scope* sc, Dsymbol s, if (m.count == 1) // exactly one match { if (!(flags & FuncResolveFlag.quiet)) - m.lastf.functionSemantic(); + functionSemantic(m.lastf); return m.lastf; } if ((flags & FuncResolveFlag.overloadOnly) && !tthis && m.lastf.needThis()) @@ -3386,12 +3235,18 @@ FuncDeclaration resolveFuncCall(const ref Loc loc, Scope* sc, Dsymbol s, // all of overloads are templates if (td) { - const(char)* msg = "none of the overloads of %s `%s.%s` are callable using argument types `!(%s)%s`"; if (!od && !td.overnext) - msg = "%s `%s.%s` is not callable using argument types `!(%s)%s`"; - .error(loc, msg, + { + .error(loc, "%s `%s` is not callable using argument types `!(%s)%s`", + td.kind(), td.ident.toChars(), tiargsBuf.peekChars(), fargsBuf.peekChars()); + } + else + { + .error(loc, "none of the overloads of %s `%s.%s` are callable using argument types `!(%s)%s`", td.kind(), td.parent.toPrettyChars(), td.ident.toChars(), tiargsBuf.peekChars(), fargsBuf.peekChars()); + } + if (!global.gag || global.params.v.showGaggedErrors) printCandidates(loc, td, sc.isDeprecated()); @@ -3574,7 +3429,11 @@ if (is(Decl == TemplateDeclaration) || is(Decl == FuncDeclaration)) if (!print) return true; - const tmsg = td.toCharsNoConstraints(); + OutBuffer buf; + HdrGenState hgs; + hgs.skipConstraints = true; + toCharsMaybeConstraints(td, buf, hgs); + const tmsg = buf.peekChars(); const cmsg = td.getConstraintEvalError(constraintsTip); // add blank space if there are multiple candidates diff --git a/gcc/d/dmd/funcsem.d b/gcc/d/dmd/funcsem.d new file mode 100644 index 0000000..8420179 --- /dev/null +++ b/gcc/d/dmd/funcsem.d @@ -0,0 +1,219 @@ +/** + * Does semantic analysis for functions. + * + * Specification: $(LINK2 https://dlang.org/spec/function.html, Functions) + * + * Copyright: Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved + * Authors: $(LINK2 https://www.digitalmars.com, Walter Bright) + * License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) + * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/funcsem.d, _funcsem.d) + * Documentation: https://dlang.org/phobos/dmd_funcsem.html + * Coverage: https://codecov.io/gh/dlang/dmd/src/master/src/dmd/funcsem.d + */ + +module dmd.funcsem; + +import core.stdc.stdio; + +import dmd.aggregate; +import dmd.arraytypes; +import dmd.astenums; +import dmd.blockexit; +import dmd.gluelayer; +import dmd.dcast; +import dmd.dclass; +import dmd.declaration; +import dmd.delegatize; +import dmd.dinterpret; +import dmd.dmodule; +import dmd.dscope; +import dmd.dstruct; +import dmd.dsymbol; +import dmd.dsymbolsem; +import dmd.dtemplate; +import dmd.errors; +import dmd.escape; +import dmd.expression; +import dmd.func; +import dmd.globals; +import dmd.hdrgen; +import dmd.id; +import dmd.identifier; +import dmd.init; +import dmd.location; +import dmd.mtype; +import dmd.objc; +import dmd.root.aav; +import dmd.common.outbuffer; +import dmd.rootobject; +import dmd.root.string; +import dmd.root.stringtable; +import dmd.semantic2; +import dmd.semantic3; +import dmd.statement_rewrite_walker; +import dmd.statement; +import dmd.statementsem; +import dmd.tokens; +import dmd.visitor; + +/**************************************************** + * Resolve forward reference of function signature - + * parameter types, return type, and attributes. + * Params: + * fd = function declaration + * Returns: + * false if any errors exist in the signature. + */ +public +extern (C++) +bool functionSemantic(FuncDeclaration fd) +{ + //printf("functionSemantic() %p %s\n", this, toChars()); + if (!fd._scope) + return !fd.errors; + + fd.cppnamespace = fd._scope.namespace; + + if (!fd.originalType) // semantic not yet run + { + TemplateInstance spec = fd.isSpeculative(); + uint olderrs = global.errors; + uint oldgag = global.gag; + if (global.gag && !spec) + global.gag = 0; + dsymbolSemantic(fd, fd._scope); + global.gag = oldgag; + if (spec && global.errors != olderrs) + spec.errors = (global.errors - olderrs != 0); + if (olderrs != global.errors) // if errors compiling this function + return false; + } + + // if inferring return type, sematic3 needs to be run + // - When the function body contains any errors, we cannot assume + // the inferred return type is valid. + // So, the body errors should become the function signature error. + if (fd.inferRetType && fd.type && !fd.type.nextOf()) + return fd.functionSemantic3(); + + TemplateInstance ti; + if (fd.isInstantiated() && !fd.isVirtualMethod() && + ((ti = fd.parent.isTemplateInstance()) is null || ti.isTemplateMixin() || ti.tempdecl.ident == fd.ident)) + { + AggregateDeclaration ad = fd.isMemberLocal(); + if (ad && ad.sizeok != Sizeok.done) + { + /* Currently dmd cannot resolve forward references per methods, + * then setting SIZOKfwd is too conservative and would break existing code. + * So, just stop method attributes inference until ad.dsymbolSemantic() done. + */ + //ad.sizeok = Sizeok.fwd; + } + else + return fd.functionSemantic3() || !fd.errors; + } + + if (fd.storage_class & STC.inference) + return fd.functionSemantic3() || !fd.errors; + + return !fd.errors; +} + +/**************************************************** + * Resolve forward reference of function body. + * Returns false if any errors exist in the body. + */ +public +extern (C++) +bool functionSemantic3(FuncDeclaration fd) +{ + if (fd.semanticRun < PASS.semantic3 && fd._scope) + { + /* Forward reference - we need to run semantic3 on this function. + * If errors are gagged, and it's not part of a template instance, + * we need to temporarily ungag errors. + */ + TemplateInstance spec = fd.isSpeculative(); + uint olderrs = global.errors; + uint oldgag = global.gag; + if (global.gag && !spec) + global.gag = 0; + semantic3(fd, fd._scope); + global.gag = oldgag; + + // If it is a speculatively-instantiated template, and errors occur, + // we need to mark the template as having errors. + if (spec && global.errors != olderrs) + spec.errors = (global.errors - olderrs != 0); + if (olderrs != global.errors) // if errors compiling this function + return false; + } + + return !fd.errors && !fd.hasSemantic3Errors(); +} + +// called from semantic3 +/** + * Creates and returns the hidden parameters for this function declaration. + * + * Hidden parameters include the `this` parameter of a class, struct or + * nested function and the selector parameter for Objective-C methods. + */ +extern (D) void declareThis(FuncDeclaration fd, Scope* sc) +{ + const bool dualCtx = (fd.toParent2() != fd.toParentLocal()); + if (dualCtx) + fd.hasDualContext = true; + auto ad = fd.isThis(); + if (!dualCtx && !ad && !fd.isNested()) + { + fd.vthis = null; + fd.objc.selectorParameter = null; + return; + } + + Type addModStc(Type t) + { + return t.addMod(fd.type.mod).addStorageClass(fd.storage_class); + } + + if (dualCtx || fd.isNested()) + { + /* The 'this' for a nested function is the link to the + * enclosing function's stack frame. + * Note that nested functions and member functions are disjoint. + */ + Type tthis = addModStc(dualCtx ? + Type.tvoidptr.sarrayOf(2).pointerTo() : + Type.tvoid.pointerTo()); + fd.vthis = new VarDeclaration(fd.loc, tthis, dualCtx ? Id.this2 : Id.capture, null); + fd.vthis.storage_class |= STC.parameter | STC.nodtor; + } + else if (ad) + { + Type thandle = addModStc(ad.handleType()); + fd.vthis = new ThisDeclaration(fd.loc, thandle); + fd.vthis.storage_class |= STC.parameter; + if (thandle.ty == Tstruct) + { + fd.vthis.storage_class |= STC.ref_; + } + } + + if (auto tf = fd.type.isTypeFunction()) + { + if (tf.isreturn) + fd.vthis.storage_class |= STC.return_; + if (tf.isScopeQual) + fd.vthis.storage_class |= STC.scope_; + if (tf.isreturnscope) + fd.vthis.storage_class |= STC.returnScope; + } + + fd.vthis.dsymbolSemantic(sc); + if (!sc.insert(fd.vthis)) + assert(0); + fd.vthis.parent = fd; + if (ad) + fd.objc.selectorParameter = .objc.createSelectorParameter(fd, sc); +} diff --git a/gcc/d/dmd/globals.d b/gcc/d/dmd/globals.d index e9e73e8..af7b1fa 100644 --- a/gcc/d/dmd/globals.d +++ b/gcc/d/dmd/globals.d @@ -219,8 +219,8 @@ extern (C++) struct Param const(char)[] argv0; // program name Array!(const(char)*) modFileAliasStrings; // array of char*'s of -I module filename alias strings - Array!(const(char)*)* imppath; // array of char*'s of where to look for import modules - Array!(const(char)*)* fileImppath; // array of char*'s of where to look for file import modules + Array!(const(char)*) imppath; // array of char*'s of where to look for import modules + Array!(const(char)*) fileImppath; // array of char*'s of where to look for file import modules const(char)[] objdir; // .obj/.lib file output directory const(char)[] objname; // .obj file output name const(char)[] libname; // .lib file output name @@ -280,8 +280,8 @@ extern (C++) struct Global string copyright = "Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved"; string written = "written by Walter Bright"; - Array!(const(char)*)* path; /// Array of char*'s which form the import lookup path - Array!(const(char)*)* filePath; /// Array of char*'s which form the file import lookup path + Array!(const(char)*) path; /// Array of char*'s which form the import lookup path + Array!(const(char)*) filePath; /// Array of char*'s which form the file import lookup path private enum string _version = import("VERSION"); char[26] datetime; /// string returned by ctime() @@ -296,8 +296,8 @@ extern (C++) struct Global void* console; /// opaque pointer to console for controlling text attributes - Array!Identifier* versionids; /// command line versions and predefined versions - Array!Identifier* debugids; /// command line debug versions and predefined versions + Array!Identifier versionids; /// command line versions and predefined versions + Array!Identifier debugids; /// command line debug versions and predefined versions bool hasMainFunction; /// Whether a main function has already been compiled in (for -main switch) uint varSequenceNumber = 1; /// Relative lifetime of `VarDeclaration` within a function, used for `scope` checks diff --git a/gcc/d/dmd/globals.h b/gcc/d/dmd/globals.h index 93e7c64..f553ae6 100644 --- a/gcc/d/dmd/globals.h +++ b/gcc/d/dmd/globals.h @@ -202,8 +202,8 @@ struct Param DString argv0; // program name Array modFileAliasStrings; // array of char*'s of -I module filename alias strings - Array *imppath; // array of char*'s of where to look for import modules - Array *fileImppath; // array of char*'s of where to look for file import modules + Array imppath; // array of char*'s of where to look for import modules + Array fileImppath; // array of char*'s of where to look for file import modules DString objdir; // .obj/.lib file output directory DString objname; // .obj file output name DString libname; // .lib file output name @@ -282,8 +282,8 @@ struct Global const DString copyright; const DString written; - Array *path; // Array of char*'s which form the import lookup path - Array *filePath; // Array of char*'s which form the file import lookup path + Array path; // Array of char*'s which form the import lookup path + Array filePath; // Array of char*'s which form the file import lookup path char datetime[26]; /// string returned by ctime() CompileEnv compileEnv; @@ -297,8 +297,8 @@ struct Global void* console; // opaque pointer to console for controlling text attributes - Array* versionids; // command line versions and predefined versions - Array* debugids; // command line debug versions and predefined versions + Array versionids; // command line versions and predefined versions + Array debugids; // command line debug versions and predefined versions d_bool hasMainFunction; unsigned varSequenceNumber; diff --git a/gcc/d/dmd/hdrgen.d b/gcc/d/dmd/hdrgen.d index 570c662..030153c 100644 --- a/gcc/d/dmd/hdrgen.d +++ b/gcc/d/dmd/hdrgen.d @@ -60,6 +60,7 @@ struct HdrGenState bool importcHdr; /// true if generating a .di file from an ImportC file bool doFuncBodies; /// include function bodies in output bool vcg_ast; /// write out codegen-ast + bool skipConstraints; // skip constraints when doing templates bool fullQual; /// fully qualify types when printing int tpltMember; @@ -1957,6 +1958,47 @@ void toCBuffer(Dsymbol s, ref OutBuffer buf, ref HdrGenState hgs) s.accept(v); } +// Note: this function is not actually `const`, because iterating the +// function parameter list may run dsymbolsemantic on enum types +public +void toCharsMaybeConstraints(const TemplateDeclaration td, ref OutBuffer buf, ref HdrGenState hgs) +{ + buf.writestring(td.ident == Id.ctor ? "this" : td.ident.toString()); + buf.writeByte('('); + foreach (i, const tp; *td.parameters) + { + if (i) + buf.writestring(", "); + toCBuffer(tp, buf, hgs); + } + buf.writeByte(')'); + + if (td.onemember) + { + if (const fd = td.onemember.isFuncDeclaration()) + { + if (TypeFunction tf = cast(TypeFunction)fd.type.isTypeFunction()) + { + // !! Casted away const + buf.writestring(parametersTypeToChars(tf.parameterList)); + if (tf.mod) + { + buf.writeByte(' '); + buf.MODtoBuffer(tf.mod); + } + } + } + } + + if (!hgs.skipConstraints && + td.constraint) + { + buf.writestring(" if ("); + toCBuffer(td.constraint, buf, hgs); + buf.writeByte(')'); + } +} + /***************************************** * Pretty-print a template parameter list to a buffer. @@ -2234,6 +2276,16 @@ private void expressionPrettyPrint(Expression e, ref OutBuffer buf, ref HdrGenSt void visitString(StringExp e) { + if (e.hexString || e.sz == 8) + { + buf.writeByte('x'); + buf.writeByte('"'); + buf.writeHexString(e.peekData, true); + buf.writeByte('"'); + if (e.postfix) + buf.writeByte(e.postfix); + return; + } buf.writeByte('"'); const o = buf.length; foreach (i; 0 .. e.len) @@ -2247,6 +2299,37 @@ private void expressionPrettyPrint(Expression e, ref OutBuffer buf, ref HdrGenSt buf.writeByte(e.postfix); } + void visitInterpolation(InterpExp e) + { + buf.writeByte('i'); + buf.writeByte('"'); + const o = buf.length; + + foreach (idx, str; e.interpolatedSet.parts) + { + if (idx % 2 == 0) + { + foreach(ch; str) + writeCharLiteral(buf, ch); + } + else + { + buf.writeByte('$'); + buf.writeByte('('); + foreach(ch; str) + buf.writeByte(ch); + buf.writeByte(')'); + } + } + + if (hgs.ddoc) + escapeDdocString(buf, o); + buf.writeByte('"'); + if (e.postfix) + buf.writeByte(e.postfix); + + } + void visitArrayLiteral(ArrayLiteralExp e) { buf.writeByte('['); @@ -2827,6 +2910,7 @@ private void expressionPrettyPrint(Expression e, ref OutBuffer buf, ref HdrGenSt case EXP.super_: return visitSuper(e.isSuperExp()); case EXP.null_: return visitNull(e.isNullExp()); case EXP.string_: return visitString(e.isStringExp()); + case EXP.interpolated: return visitInterpolation(e.isInterpExp()); case EXP.arrayLiteral: return visitArrayLiteral(e.isArrayLiteralExp()); case EXP.assocArrayLiteral: return visitAssocArrayLiteral(e.isAssocArrayLiteralExp()); case EXP.structLiteral: return visitStructLiteral(e.isStructLiteralExp()); diff --git a/gcc/d/dmd/id.d b/gcc/d/dmd/id.d index a66f2af4..5ad324d 100644 --- a/gcc/d/dmd/id.d +++ b/gcc/d/dmd/id.d @@ -335,6 +335,12 @@ immutable Msgtable[] msgtable = { "_d_arrayassign_l" }, { "_d_arrayassign_r" }, + { "imported" }, + { "InterpolationHeader" }, + { "InterpolationFooter" }, + { "InterpolatedLiteral" }, + { "InterpolatedExpression" }, + // For pragma's { "Pinline", "inline" }, { "lib" }, diff --git a/gcc/d/dmd/json.d b/gcc/d/dmd/json.d index 9819c3a..7c65067 100644 --- a/gcc/d/dmd/json.d +++ b/gcc/d/dmd/json.d @@ -873,12 +873,9 @@ public: propertyStart("predefinedVersions"); arrayStart(); - if (global.versionids) + foreach (const versionid; global.versionids) { - foreach (const versionid; *global.versionids) - { - item(versionid.toString()); - } + item(versionid.toString()); } arrayEnd(); @@ -905,12 +902,9 @@ public: propertyStart("importPaths"); arrayStart(); - if (global.params.imppath) + foreach (importPath; global.params.imppath[]) { - foreach (importPath; *global.params.imppath) - { - item(importPath.toDString); - } + item(importPath.toDString); } arrayEnd(); diff --git a/gcc/d/dmd/lexer.d b/gcc/d/dmd/lexer.d index 5eadd72..937597c 100644 --- a/gcc/d/dmd/lexer.d +++ b/gcc/d/dmd/lexer.d @@ -506,6 +506,29 @@ class Lexer } else goto case_ident; + case 'i': + if (Ccompile) + goto case_ident; + if (p[1] == '"') + { + p++; // skip the i + escapeStringConstant(t, true); + return; + } + else if (p[1] == '`') + { + p++; // skip the i + wysiwygStringConstant(t, true); + return; + } + else if (p[1] == 'q' && p[2] == '{') + { + p += 2; // skip the i and q + tokenStringConstant(t, true); + return; + } + else + goto case_ident; case '"': escapeStringConstant(t); return; @@ -517,7 +540,7 @@ class Lexer case 'f': case 'g': case 'h': - case 'i': + /*case 'i':*/ case 'j': case 'k': case 'l': @@ -1429,9 +1452,18 @@ class Lexer Params: result = pointer to the token that accepts the result */ - private void wysiwygStringConstant(Token* result) + private void wysiwygStringConstant(Token* result, bool supportInterpolation = false) { - result.value = TOK.string_; + if (supportInterpolation) + { + result.value = TOK.interpolated; + result.interpolatedSet = null; + } + else + { + result.value = TOK.string_; + } + Loc start = loc(); auto terminator = p[0]; p++; @@ -1451,6 +1483,14 @@ class Lexer c = '\n'; // treat EndOfLine as \n character endOfLine(); break; + case '$': + if (!supportInterpolation) + goto default; + + if (!handleInterpolatedSegment(result, start)) + goto default; + + continue; case 0: case 0x1A: error("unterminated string constant starting at %s", start.toChars()); @@ -1461,7 +1501,11 @@ class Lexer default: if (c == terminator) { - result.setString(stringbuffer); + if (supportInterpolation) + result.appendInterpolatedPart(stringbuffer); + else + result.setString(stringbuffer); + stringPostfix(result); return; } @@ -1736,13 +1780,21 @@ class Lexer Params: result = pointer to the token that accepts the result */ - private void tokenStringConstant(Token* result) + private void tokenStringConstant(Token* result, bool supportInterpolation = false) { - result.value = TOK.string_; + if (supportInterpolation) + { + result.value = TOK.interpolated; + result.interpolatedSet = null; + } + else + { + result.value = TOK.string_; + } uint nest = 1; const start = loc(); - const pstart = ++p; + auto pstart = ++p; inTokenStringConstant++; scope(exit) inTokenStringConstant--; while (1) @@ -1757,11 +1809,29 @@ class Lexer case TOK.rightCurly: if (--nest == 0) { - result.setString(pstart, p - 1 - pstart); + if (supportInterpolation) + result.appendInterpolatedPart(pstart, p - 1 - pstart); + else + result.setString(pstart, p - 1 - pstart); + stringPostfix(result); return; } continue; + case TOK.dollar: + if (!supportInterpolation) + goto default; + + stringbuffer.setsize(0); + stringbuffer.write(pstart, p - 1 - pstart); + if (!handleInterpolatedSegment(result, start)) + goto default; + + stringbuffer.setsize(0); + + pstart = p; + + continue; case TOK.endOfFile: error("unterminated token string constant starting at %s", start.toChars()); result.setString(); @@ -1772,6 +1842,52 @@ class Lexer } } + // returns true if it got special treatment as an interpolated segment + // otherwise returns false, indicating to treat it as just part of a normal string + private bool handleInterpolatedSegment(Token* token, Loc start) + { + switch(*p) + { + case '(': + // expression, at this level we need to scan until the closing ')' + + // always put the string part in first + token.appendInterpolatedPart(stringbuffer); + stringbuffer.setsize(0); + + int openParenCount = 1; + p++; // skip the first open paren + auto pstart = p; + while (openParenCount > 0) + { + // need to scan with the lexer to support embedded strings and other complex cases + Token tok; + scan(&tok); + if (tok.value == TOK.leftParenthesis) + openParenCount++; + if (tok.value == TOK.rightParenthesis) + openParenCount--; + if (tok.value == TOK.endOfFile) + { + // FIXME: make this error better, it spams a lot + error("unterminated interpolated string constant starting at %s", start.toChars()); + return false; + } + } + + // then put the interpolated string segment + token.appendInterpolatedPart(pstart[0 .. p - 1 - pstart]); + + stringbuffer.setsize(0); // make sure this is reset from the last token scan + // otherwise something like i"$(func("thing")) stuff" can still include it + + return true; + default: + // nothing special + return false; + } + } + /** Scan a quoted string while building the processed string value by handling escape sequences. The result is returned in the given `t` token. @@ -1783,9 +1899,17 @@ class Lexer * D https://dlang.org/spec/lex.html#double_quoted_strings * ImportC C11 6.4.5 */ - private void escapeStringConstant(Token* t) + private void escapeStringConstant(Token* t, bool supportInterpolation = false) { - t.value = TOK.string_; + if (supportInterpolation) + { + t.value = TOK.interpolated; + t.interpolatedSet = null; + } + else + { + t.value = TOK.string_; + } const start = loc(); const tc = *p++; // opening quote @@ -1813,11 +1937,28 @@ class Lexer c = escapeSequence(c2); stringbuffer.writeUTF8(c); continue; + case '$': + if (supportInterpolation) + { + p++; // skip escaped $ + stringbuffer.writeByte('$'); + continue; + } + else + goto default; default: c = escapeSequence(c2); break; } break; + case '$': + if (!supportInterpolation) + goto default; + + if (!handleInterpolatedSegment(t, start)) + goto default; + + continue; case '\n': endOfLine(); if (Ccompile) @@ -1835,7 +1976,10 @@ class Lexer case '"': if (c != tc) goto default; - t.setString(stringbuffer); + if (supportInterpolation) + t.appendInterpolatedPart(stringbuffer); + else + t.setString(stringbuffer); if (!Ccompile) stringPostfix(t); return; diff --git a/gcc/d/dmd/mtype.d b/gcc/d/dmd/mtype.d index 3d88a1d..276f209 100644 --- a/gcc/d/dmd/mtype.d +++ b/gcc/d/dmd/mtype.d @@ -27,9 +27,11 @@ import dmd.denum; import dmd.dstruct; import dmd.dsymbol; import dmd.dtemplate; +import dmd.enumsem; import dmd.errors; import dmd.expression; import dmd.func; +import dmd.funcsem; import dmd.globals; import dmd.hdrgen; import dmd.id; @@ -516,16 +518,39 @@ extern (C++) abstract class Type : ASTNode Terror ]; + static Type merge(Type t) + { + import dmd.basicmangle : tyToDecoBuffer; + + OutBuffer buf; + buf.reserve(3); + + if (t.ty == Tnoreturn) + buf.writestring("Nn"); + else + tyToDecoBuffer(buf, t.ty); + + auto sv = t.stringtable.update(buf[]); + if (sv.value) + return sv.value; + else + { + t.deco = cast(char*)sv.toDchars(); + sv.value = t; + return t; + } + } + for (size_t i = 0; basetab[i] != Terror; i++) { Type t = new TypeBasic(basetab[i]); - t = t.merge(); + t = merge(t); basic[basetab[i]] = t; } basic[Terror] = new TypeError(); tnoreturn = new TypeNoreturn(); - tnoreturn.deco = tnoreturn.merge().deco; + tnoreturn.deco = merge(tnoreturn).deco; basic[Tnoreturn] = tnoreturn; tvoid = basic[Tvoid]; @@ -560,7 +585,7 @@ extern (C++) abstract class Type : ASTNode terror = basic[Terror]; tnoreturn = basic[Tnoreturn]; tnull = new TypeNull(); - tnull.deco = tnull.merge().deco; + tnull.deco = merge(tnull).deco; tvoidptr = tvoid.pointerTo(); tstring = tchar.immutableOf().arrayOf(); @@ -601,29 +626,6 @@ extern (C++) abstract class Type : ASTNode return cast(uint)size(Loc.initial); } - /************************************* - * This version does a merge even if the deco is already computed. - * Necessary for types that have a deco, but are not merged. - */ - final Type merge2() - { - //printf("merge2(%s)\n", toChars()); - Type t = this; - assert(t); - if (!t.deco) - return t.merge(); - - auto sv = stringtable.lookup(t.deco, strlen(t.deco)); - if (sv && sv.value) - { - t = sv.value; - assert(t.deco); - } - else - assert(0); - return t; - } - /********************************* * Store this type's modifier name into buf. */ @@ -1693,7 +1695,7 @@ extern (C++) abstract class Type : ASTNode if (callable) { auto fd = resolveFuncCall(Loc.initial, null, callable, null, this, ArgumentList(), FuncResolveFlag.quiet); - if (!fd || fd.errors || !fd.functionSemantic()) + if (!fd || fd.errors || !functionSemantic(fd)) return Type.terror; auto t = fd.type.nextOf(); diff --git a/gcc/d/dmd/mtype.h b/gcc/d/dmd/mtype.h index c777f35..8b0a1b2 100644 --- a/gcc/d/dmd/mtype.h +++ b/gcc/d/dmd/mtype.h @@ -233,7 +233,6 @@ public: uinteger_t size(); virtual uinteger_t size(const Loc &loc); virtual unsigned alignsize(); - Type *merge2(); void modToBuffer(OutBuffer& buf) const; char *modToChars() const; @@ -909,3 +908,4 @@ Covariant covariant(Type *, Type *, StorageClass * = NULL, bool = false); bool isBaseOf(Type *tthis, Type *t, int *poffset); Type *trySemantic(Type *type, const Loc &loc, Scope *sc); void purityLevel(TypeFunction *type); +Type *merge2(Type *type); diff --git a/gcc/d/dmd/parse.d b/gcc/d/dmd/parse.d index 268622a..0dc54ff 100644 --- a/gcc/d/dmd/parse.d +++ b/gcc/d/dmd/parse.d @@ -2015,6 +2015,7 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer case TOK.wcharLiteral: case TOK.dcharLiteral: case TOK.string_: + case TOK.interpolated: case TOK.hexadecimalString: case TOK.file: case TOK.fileFullPath: @@ -5820,6 +5821,7 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer case TOK.true_: case TOK.false_: case TOK.string_: + case TOK.interpolated: case TOK.hexadecimalString: case TOK.leftParenthesis: case TOK.cast_: @@ -7313,6 +7315,7 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer case TOK.wcharLiteral: case TOK.dcharLiteral: case TOK.string_: + case TOK.interpolated: case TOK.hexadecimalString: case TOK.file: case TOK.fileFullPath: @@ -8177,6 +8180,11 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer nextToken(); break; + case TOK.interpolated: + e = new AST.InterpExp(loc, token.interpolatedSet, token.postfix); + nextToken(); + break; + case TOK.string_: case TOK.hexadecimalString: const bool hexString = token.value == TOK.hexadecimalString; @@ -8810,6 +8818,7 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer case TOK.wcharLiteral: case TOK.dcharLiteral: case TOK.string_: + case TOK.interpolated: case TOK.function_: case TOK.delegate_: case TOK.typeof_: diff --git a/gcc/d/dmd/parsetimevisitor.d b/gcc/d/dmd/parsetimevisitor.d index 3d0a585..422c1c8 100644 --- a/gcc/d/dmd/parsetimevisitor.d +++ b/gcc/d/dmd/parsetimevisitor.d @@ -183,6 +183,7 @@ public: void visit(AST.TypeidExp e) { visit(cast(AST.Expression)e); } void visit(AST.TraitsExp e) { visit(cast(AST.Expression)e); } void visit(AST.StringExp e) { visit(cast(AST.Expression)e); } + void visit(AST.InterpExp e) { visit(cast(AST.Expression)e); } void visit(AST.NewExp e) { visit(cast(AST.Expression)e); } void visit(AST.AssocArrayLiteralExp e) { visit(cast(AST.Expression)e); } void visit(AST.ArrayLiteralExp e) { visit(cast(AST.Expression)e); } diff --git a/gcc/d/dmd/res/default_ddoc_theme.ddoc b/gcc/d/dmd/res/default_ddoc_theme.ddoc index 7ae0db8..20269e1 100644 --- a/gcc/d/dmd/res/default_ddoc_theme.ddoc +++ b/gcc/d/dmd/res/default_ddoc_theme.ddoc @@ -70,7 +70,7 @@ D_CODE =
    -
  1. $0
  2. +
  3. $0
@@ -81,7 +81,7 @@ OTHER_CODE =
    -
  1. $+
  2. +
  3. $+
@@ -517,6 +517,10 @@ DDOC = white-space: pre-wrap; } + .ddoc .code_lines pre { + display: contents; + } + .ddoc .code_lines li:only-of-type::before { color: rgba(255, 255, 255, 1); content: " "; diff --git a/gcc/d/dmd/root/filename.d b/gcc/d/dmd/root/filename.d index 5b0bba4..41c2050 100644 --- a/gcc/d/dmd/root/filename.d +++ b/gcc/d/dmd/root/filename.d @@ -78,7 +78,7 @@ nothrow: private const(char)[] str; /// - extern (D) this(const(char)[] str) pure + extern (D) this(const char[] str) pure { this.str = str.xarraydup; } @@ -96,7 +96,7 @@ nothrow: } /// Ditto - extern (D) static bool equals(const(char)[] name1, const(char)[] name2) pure @nogc + extern (D) static bool equals(const char[] name1, const char[] name2) pure @nogc { if (name1.length != name2.length) return false; @@ -125,7 +125,7 @@ nothrow: } /// Ditto - extern (D) static bool absolute(const(char)[] name) pure @nogc @safe + extern (D) static bool absolute(const char[] name) pure @nogc @safe { if (!name.length) return false; @@ -189,7 +189,7 @@ nothrow: } /// Ditto - extern (D) static const(char)[] ext(const(char)[] str) nothrow pure @safe @nogc + extern (D) static const(char)[] ext(const char[] str) nothrow pure @safe @nogc { foreach_reverse (idx, char e; str) { @@ -249,7 +249,7 @@ nothrow: } /// Ditto - extern (D) static const(char)[] removeExt(const(char)[] str) + extern (D) static const(char)[] removeExt(const char[] str) { auto e = ext(str); if (e.length) @@ -278,7 +278,7 @@ nothrow: } /// Ditto - extern (D) static const(char)[] name(const(char)[] str) pure @nogc @safe + extern (D) static const(char)[] name(const char[] str) pure @nogc @safe { foreach_reverse (idx, char e; str) { @@ -333,7 +333,7 @@ nothrow: } /// Ditto - extern (D) static const(char)[] path(const(char)[] str) + extern (D) static const(char)[] path(const char[] str) { const n = name(str); bool hasTrailingSlash; @@ -358,7 +358,7 @@ nothrow: /************************************** * Replace filename portion of path. */ - extern (D) static const(char)[] replaceName(const(char)[] path, const(char)[] name) + extern (D) static const(char)[] replaceName(const char[] path, const char[] name) { if (absolute(name)) return name; @@ -387,7 +387,7 @@ nothrow: } /// Ditto - extern(D) static const(char)[] combine(const(char)[] path, const(char)[] name) + extern(D) static const(char)[] combine(const char[] path, const char[] name) { return !path.length ? name : buildPath(path, name); } @@ -401,7 +401,7 @@ nothrow: assert(combine("foo/"[], "bar"[]) == "foo/bar"); } - static const(char)[] buildPath(const(char)[][] fragments...) + static const(char)[] buildPath(const char[][] fragments...) { size_t size; foreach (f; fragments) @@ -563,7 +563,7 @@ nothrow: * Returns: * A newly allocated string (free with `FileName.free`) */ - extern(D) static char[] addExt(const(char)[] name, const(char)[] ext) pure + extern(D) static char[] addExt(const char[] name, const char[] ext) pure { const len = name.length + ext.length + 2; auto s = cast(char*)mem.xmalloc(len); @@ -584,7 +584,7 @@ nothrow: } /// Ditto - extern (D) static const(char)[] defaultExt(const(char)[] name, const(char)[] ext) + extern (D) static const(char)[] defaultExt(const char[] name, const char[] ext) { auto e = FileName.ext(name); if (e.length) // it already has an extension @@ -608,7 +608,7 @@ nothrow: } /// Ditto - extern (D) static const(char)[] forceExt(const(char)[] name, const(char)[] ext) + extern (D) static const(char)[] forceExt(const char[] name, const char[] ext) { if (auto e = FileName.ext(name)) return addExt(name[0 .. $ - e.length - 1], ext); @@ -630,7 +630,7 @@ nothrow: } /// Ditto - extern (D) static bool equalsExt(const(char)[] name, const(char)[] ext) pure @nogc + extern (D) static bool equalsExt(const char[] name, const char[] ext) pure @nogc { auto e = FileName.ext(name); if (!e.length && !ext.length) @@ -665,12 +665,12 @@ nothrow: * Returns: * if found, filename combined with path, otherwise null */ - extern (C++) static const(char)* searchPath(Strings* path, const(char)* name, bool cwd) + extern (C++) static const(char)* searchPath(const ref Strings path, const char* name, bool cwd) { - return searchPath(path, name.toDString, cwd).ptr; + return searchPath(path[], name.toDString, cwd).ptr; } - extern (D) static const(char)[] searchPath(Strings* path, const(char)[] name, bool cwd) + extern (D) static const(char)[] searchPath(const char*[] path, const char[] name, bool cwd) { if (absolute(name)) { @@ -681,24 +681,21 @@ nothrow: if (exists(name)) return name; } - if (path) + foreach (p; path) { - foreach (p; *path) + auto n = combine(p.toDString, name); + if (exists(n)) + return n; + //combine might return name + if (n.ptr != name.ptr) { - auto n = combine(p.toDString, name); - if (exists(n)) - return n; - //combine might return name - if (n.ptr != name.ptr) - { - mem.xfree(cast(void*)n.ptr); - } + mem.xfree(cast(void*)n.ptr); } } return null; } - extern (D) static const(char)[] searchPath(const(char)* path, const(char)[] name, bool cwd) + extern (D) static const(char)[] searchPath(const char* path, const char[] name, bool cwd) { if (absolute(name)) { @@ -738,7 +735,7 @@ nothrow: * Returns: * index of the first reserved character in path if found, size_t.max otherwise */ - extern (D) static size_t findReservedChar(const(char)[] name) pure @nogc @safe + extern (D) static size_t findReservedChar(const char[] name) pure @nogc @safe { version (Windows) { @@ -787,7 +784,7 @@ nothrow: * Returns: * true if path contains '..' reference to parent directory */ - extern (D) static bool refersToParentDir(const(char)[] name) pure @nogc @safe + extern (D) static bool refersToParentDir(const char[] name) pure @nogc @safe { size_t s = 0; foreach (i; 0 .. name.length) @@ -845,7 +842,7 @@ nothrow: } /// Ditto - extern (D) static int exists(const(char)[] name) + extern (D) static int exists(const char[] name) { if (!name.length) return 0; @@ -892,7 +889,7 @@ nothrow: Returns: `true` if the directory exists or was successfully created */ - extern (D) static bool ensurePathExists(const(char)[] path) + extern (D) static bool ensurePathExists(const char[] path) { //printf("FileName::ensurePathExists(%s)\n", path ? path : ""); if (!path.length) @@ -967,7 +964,7 @@ nothrow: } /// Ditto - extern (D) static const(char)[] canonicalName(const(char)[] name) + extern (D) static const(char)[] canonicalName(const char[] name) { version (Posix) { @@ -1127,7 +1124,7 @@ version(Windows) * References: * https://msdn.microsoft.com/en-us/library/windows/desktop/aa363855(v=vs.85).aspx */ - private int _mkdir(const(char)[] path) nothrow + private int _mkdir(const char[] path) nothrow { const createRet = path.extendedPathThen!( p => CreateDirectoryW(&p[0], null /*securityAttributes*/)); @@ -1175,7 +1172,7 @@ version(Windows) * Returns: * The result of calling F on the UTF16 version of str. */ - private auto toWStringzThen(alias F)(const(char)[] str) nothrow + private auto toWStringzThen(alias F)(const char[] str) nothrow { import dmd.common.smallbuffer : SmallBuffer, toWStringz; diff --git a/gcc/d/dmd/root/filename.h b/gcc/d/dmd/root/filename.h index d8834a1..0e52b98 100644 --- a/gcc/d/dmd/root/filename.h +++ b/gcc/d/dmd/root/filename.h @@ -38,7 +38,7 @@ public: bool equalsExt(const char *ext); - static const char *searchPath(Strings *path, const char *name, bool cwd); + static const char *searchPath(Strings& path, const char *name, bool cwd); static int exists(const char *name); static bool ensurePathExists(const char *path); static const char *canonicalName(const char *name); diff --git a/gcc/d/dmd/semantic3.d b/gcc/d/dmd/semantic3.d index 174d9b4..125a39d 100644 --- a/gcc/d/dmd/semantic3.d +++ b/gcc/d/dmd/semantic3.d @@ -41,6 +41,7 @@ import dmd.escape; import dmd.expression; import dmd.expressionsem; import dmd.func; +import dmd.funcsem; import dmd.globals; import dmd.id; import dmd.identifier; @@ -384,7 +385,7 @@ private extern(C++) final class Semantic3Visitor : Visitor } } - funcdecl.declareThis(sc2); + declareThis(funcdecl, sc2); // Reverts: https://issues.dlang.org/show_bug.cgi?id=5710 // No compiler supports this, and there was never any spec for it. diff --git a/gcc/d/dmd/statementsem.d b/gcc/d/dmd/statementsem.d index d4827ae..840035c 100644 --- a/gcc/d/dmd/statementsem.d +++ b/gcc/d/dmd/statementsem.d @@ -43,6 +43,7 @@ import dmd.escape; import dmd.expression; import dmd.expressionsem; import dmd.func; +import dmd.funcsem; import dmd.globals; import dmd.gluelayer; import dmd.hdrgen; @@ -1284,7 +1285,7 @@ Statement statementSemanticVisit(Statement s, Scope* sc) Type tfront; if (auto fd = sfront.isFuncDeclaration()) { - if (!fd.functionSemantic()) + if (!functionSemantic(fd)) return rangeError(); tfront = fd.type; } diff --git a/gcc/d/dmd/templatesem.d b/gcc/d/dmd/templatesem.d new file mode 100644 index 0000000..1942afe --- /dev/null +++ b/gcc/d/dmd/templatesem.d @@ -0,0 +1,1497 @@ +/** + * Template semantics. + * + * Copyright: Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved + * Authors: $(LINK2 https://www.digitalmars.com, Walter Bright) + * License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) + * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/templatesem.d, _templatesem.d) + * Documentation: https://dlang.org/phobos/dmd_templatesem.html + * Coverage: https://codecov.io/gh/dlang/dmd/src/master/src/dmd/templatesem.d + */ + +module dmd.templatesem; + +import core.stdc.stdio; +import core.stdc.string; +import dmd.aggregate; +import dmd.aliasthis; +import dmd.arraytypes; +import dmd.astenums; +import dmd.ast_node; +import dmd.attrib; +import dmd.dcast; +import dmd.dclass; +import dmd.declaration; +import dmd.dinterpret; +import dmd.dmangle; +import dmd.dmodule; +import dmd.dscope; +import dmd.dsymbol; +import dmd.dsymbolsem; +import dmd.dtemplate; +import dmd.errors; +import dmd.errorsink; +import dmd.expression; +import dmd.expressionsem; +import dmd.func; +import dmd.funcsem; +import dmd.globals; +import dmd.hdrgen; +import dmd.id; +import dmd.identifier; +import dmd.impcnvtab; +import dmd.init; +import dmd.initsem; +import dmd.location; +import dmd.mtype; +import dmd.opover; +import dmd.optimize; +import dmd.root.array; +import dmd.common.outbuffer; +import dmd.rootobject; +import dmd.semantic2; +import dmd.semantic3; +import dmd.tokens; +import dmd.typesem; +import dmd.visitor; + +/*************************************** + * Given that ti is an instance of this TemplateDeclaration, + * deduce the types of the parameters to this, and store + * those deduced types in dedtypes[]. + * Params: + * sc = context + * td = template + * ti = instance of td + * dedtypes = fill in with deduced types + * argumentList = arguments to template instance + * flag = 1 - don't do semantic() because of dummy types + * 2 - don't change types in matchArg() + * Returns: match level. + */ +public +MATCH matchWithInstance(Scope* sc, TemplateDeclaration td, TemplateInstance ti, ref Objects dedtypes, ArgumentList argumentList, int flag) +{ + enum LOGM = 0; + static if (LOGM) + { + printf("\n+TemplateDeclaration.matchWithInstance(td = %s, ti = %s, flag = %d)\n", td.toChars(), ti.toChars(), flag); + } + version (none) + { + printf("dedtypes.length = %d, parameters.length = %d\n", dedtypes.length, parameters.length); + if (ti.tiargs.length) + printf("ti.tiargs.length = %d, [0] = %p\n", ti.tiargs.length, (*ti.tiargs)[0]); + } + MATCH nomatch() + { + static if (LOGM) + { + printf(" no match\n"); + } + return MATCH.nomatch; + } + MATCH m; + size_t dedtypes_dim = dedtypes.length; + + dedtypes.zero(); + + if (td.errors) + return MATCH.nomatch; + + size_t parameters_dim = td.parameters.length; + int variadic = td.isVariadic() !is null; + + // If more arguments than parameters, no match + if (ti.tiargs.length > parameters_dim && !variadic) + { + static if (LOGM) + { + printf(" no match: more arguments than parameters\n"); + } + return MATCH.nomatch; + } + + assert(dedtypes_dim == parameters_dim); + assert(dedtypes_dim >= ti.tiargs.length || variadic); + + assert(td._scope); + + // Set up scope for template parameters + Scope* paramscope = createScopeForTemplateParameters(td, ti, sc); + + // Attempt type deduction + m = MATCH.exact; + for (size_t i = 0; i < dedtypes_dim; i++) + { + MATCH m2; + TemplateParameter tp = (*td.parameters)[i]; + Declaration sparam; + + //printf("\targument [%d]\n", i); + static if (LOGM) + { + //printf("\targument [%d] is %s\n", i, oarg ? oarg.toChars() : "null"); + TemplateTypeParameter ttp = tp.isTemplateTypeParameter(); + if (ttp) + printf("\tparameter[%d] is %s : %s\n", i, tp.ident.toChars(), ttp.specType ? ttp.specType.toChars() : ""); + } + + m2 = tp.matchArg(ti.loc, paramscope, ti.tiargs, i, td.parameters, dedtypes, &sparam); + //printf("\tm2 = %d\n", m2); + if (m2 == MATCH.nomatch) + { + version (none) + { + printf("\tmatchArg() for parameter %i failed\n", i); + } + return nomatch(); + } + + if (m2 < m) + m = m2; + + if (!flag) + sparam.dsymbolSemantic(paramscope); + if (!paramscope.insert(sparam)) // TODO: This check can make more early + { + // in TemplateDeclaration.semantic, and + // then we don't need to make sparam if flags == 0 + return nomatch(); + } + } + + if (!flag) + { + /* Any parameter left without a type gets the type of + * its corresponding arg + */ + foreach (i, ref dedtype; dedtypes) + { + if (!dedtype) + { + assert(i < ti.tiargs.length); + dedtype = cast(Type)(*ti.tiargs)[i]; + } + } + } + + if (m > MATCH.nomatch && td.constraint && !flag) + { + if (ti.hasNestedArgs(ti.tiargs, td.isstatic)) // TODO: should gag error + ti.parent = ti.enclosing; + else + ti.parent = td.parent; + + // Similar to doHeaderInstantiation + FuncDeclaration fd = td.onemember ? td.onemember.isFuncDeclaration() : null; + if (fd) + { + TypeFunction tf = fd.type.isTypeFunction().syntaxCopy(); + if (argumentList.hasNames) + return nomatch(); + Expressions* fargs = argumentList.arguments; + // TODO: Expressions* fargs = tf.resolveNamedArgs(argumentList, null); + // if (!fargs) + // return nomatch(); + + fd = new FuncDeclaration(fd.loc, fd.endloc, fd.ident, fd.storage_class, tf); + fd.parent = ti; + fd.inferRetType = true; + + // Shouldn't run semantic on default arguments and return type. + foreach (ref param; *tf.parameterList.parameters) + param.defaultArg = null; + + tf.next = null; + tf.incomplete = true; + + // Resolve parameter types and 'auto ref's. + tf.fargs = fargs; + uint olderrors = global.startGagging(); + fd.type = tf.typeSemantic(td.loc, paramscope); + global.endGagging(olderrors); + if (fd.type.ty != Tfunction) + return nomatch(); + fd.originalType = fd.type; // for mangling + } + + // TODO: dedtypes => ti.tiargs ? + if (!evaluateConstraint(td, ti, sc, paramscope, &dedtypes, fd)) + return nomatch(); + } + + static if (LOGM) + { + // Print out the results + printf("--------------------------\n"); + printf("template %s\n", toChars()); + printf("instance %s\n", ti.toChars()); + if (m > MATCH.nomatch) + { + for (size_t i = 0; i < dedtypes_dim; i++) + { + TemplateParameter tp = (*parameters)[i]; + RootObject oarg; + printf(" [%d]", i); + if (i < ti.tiargs.length) + oarg = (*ti.tiargs)[i]; + else + oarg = null; + tp.print(oarg, (*dedtypes)[i]); + } + } + else + return nomatch(); + } + static if (LOGM) + { + printf(" match = %d\n", m); + } + + paramscope.pop(); + static if (LOGM) + { + printf("-TemplateDeclaration.matchWithInstance(td = %s, ti = %s) = %d\n", td.toChars(), ti.toChars(), m); + } + return m; +} + +/**************************** + * Check to see if constraint is satisfied. + */ +bool evaluateConstraint(TemplateDeclaration td, TemplateInstance ti, Scope* sc, Scope* paramscope, Objects* dedargs, FuncDeclaration fd) +{ + /* Detect recursive attempts to instantiate this template declaration, + * https://issues.dlang.org/show_bug.cgi?id=4072 + * void foo(T)(T x) if (is(typeof(foo(x)))) { } + * static assert(!is(typeof(foo(7)))); + * Recursive attempts are regarded as a constraint failure. + */ + /* There's a chicken-and-egg problem here. We don't know yet if this template + * instantiation will be a local one (enclosing is set), and we won't know until + * after selecting the correct template. Thus, function we're nesting inside + * is not on the sc scope chain, and this can cause errors in FuncDeclaration.getLevel(). + * Workaround the problem by setting a flag to relax the checking on frame errors. + */ + + for (TemplatePrevious* p = td.previous; p; p = p.prev) + { + if (!arrayObjectMatch(*p.dedargs, *dedargs)) + continue; + //printf("recursive, no match p.sc=%p %p %s\n", p.sc, this, this.toChars()); + /* It must be a subscope of p.sc, other scope chains are not recursive + * instantiations. + * the chain of enclosing scopes is broken by paramscope (its enclosing + * scope is _scope, but paramscope.callsc is the instantiating scope). So + * it's good enough to check the chain of callsc + */ + for (Scope* scx = paramscope.callsc; scx; scx = scx.callsc) + { + // The first scx might be identical for nested eponymeous templates, e.g. + // template foo() { void foo()() {...} } + if (scx == p.sc && scx !is paramscope.callsc) + return false; + } + /* BUG: should also check for ref param differences + */ + } + + TemplatePrevious pr; + pr.prev = td.previous; + pr.sc = paramscope.callsc; + pr.dedargs = dedargs; + td.previous = ≺ // add this to threaded list + + Scope* scx = paramscope.push(ti); + scx.parent = ti; + scx.tinst = null; + scx.minst = null; + // Set SCOPE.constraint before declaring function parameters for the static condition + // (previously, this was immediately before calling evalStaticCondition), so the + // semantic pass knows not to issue deprecation warnings for these throw-away decls. + // https://issues.dlang.org/show_bug.cgi?id=21831 + scx.flags |= SCOPE.constraint; + + assert(!ti.symtab); + if (fd) + { + /* Declare all the function parameters as variables and add them to the scope + * Making parameters is similar to FuncDeclaration.semantic3 + */ + auto tf = fd.type.isTypeFunction(); + + scx.parent = fd; + + Parameters* fparameters = tf.parameterList.parameters; + const nfparams = tf.parameterList.length; + foreach (i, fparam; tf.parameterList) + { + fparam.storageClass &= (STC.IOR | STC.lazy_ | STC.final_ | STC.TYPECTOR | STC.nodtor); + fparam.storageClass |= STC.parameter; + if (tf.parameterList.varargs == VarArg.typesafe && i + 1 == nfparams) + { + fparam.storageClass |= STC.variadic; + /* Don't need to set STC.scope_ because this will only + * be evaluated at compile time + */ + } + } + foreach (fparam; *fparameters) + { + if (!fparam.ident) + continue; + // don't add it, if it has no name + auto v = new VarDeclaration(fparam.loc, fparam.type, fparam.ident, null); + fparam.storageClass |= STC.parameter; + v.storage_class = fparam.storageClass; + v.dsymbolSemantic(scx); + if (!ti.symtab) + ti.symtab = new DsymbolTable(); + if (!scx.insert(v)) + .error(td.loc, "%s `%s` parameter `%s.%s` is already defined", td.kind, td.toPrettyChars, td.toChars(), v.toChars()); + else + v.parent = fd; + } + if (td.isstatic) + fd.storage_class |= STC.static_; + declareThis(fd, scx); + } + + td.lastConstraint = td.constraint.syntaxCopy(); + td.lastConstraintTiargs = ti.tiargs; + td.lastConstraintNegs.setDim(0); + + import dmd.staticcond; + + assert(ti.inst is null); + ti.inst = ti; // temporary instantiation to enable genIdent() + bool errors; + const bool result = evalStaticCondition(scx, td.constraint, td.lastConstraint, errors, &td.lastConstraintNegs); + if (result || errors) + { + td.lastConstraint = null; + td.lastConstraintTiargs = null; + td.lastConstraintNegs.setDim(0); + } + ti.inst = null; + ti.symtab = null; + scx = scx.pop(); + td.previous = pr.prev; // unlink from threaded list + if (errors) + return false; + return result; +} + +/******************************************* + * Append to buf a textual representation of template parameters with their arguments. + * Params: + * parameters = the template parameters + * tiargs = the correspondeing template arguments + * variadic = if it's a variadic argument list + * buf = where the text output goes + */ +void formatParamsWithTiargs(ref TemplateParameters parameters, ref Objects tiargs, bool variadic, ref OutBuffer buf) +{ + buf.writestring(" with `"); + + // write usual arguments line-by-line + // skips trailing default ones - they are not present in `tiargs` + const end = parameters.length - (variadic ? 1 : 0); + size_t i; + for (; i < tiargs.length && i < end; i++) + { + if (i) + { + buf.writeByte(','); + buf.writenl(); + buf.writestring(" "); + } + write(buf, parameters[i]); + buf.writestring(" = "); + write(buf, tiargs[i]); + } + // write remaining variadic arguments on the last line + if (variadic) + { + if (i) + { + buf.writeByte(','); + buf.writenl(); + buf.writestring(" "); + } + write(buf, parameters[end]); + buf.writestring(" = "); + buf.writeByte('('); + if (end < tiargs.length) + { + write(buf, tiargs[end]); + foreach (j; parameters.length .. tiargs.length) + { + buf.writestring(", "); + write(buf, tiargs[j]); + } + } + buf.writeByte(')'); + } + buf.writeByte('`'); +} + +/****************************** + * Create a scope for the parameters of the TemplateInstance + * `ti` in the parent scope sc from the ScopeDsymbol paramsym. + * + * If paramsym is null a new ScopeDsymbol is used in place of + * paramsym. + * Params: + * td = template that ti is an instance of + * ti = the TemplateInstance whose parameters to generate the scope for. + * sc = the parent scope of ti + * Returns: + * new scope for the parameters of ti + */ +Scope* createScopeForTemplateParameters(TemplateDeclaration td, TemplateInstance ti, Scope* sc) +{ + ScopeDsymbol paramsym = new ScopeDsymbol(); + paramsym.parent = td._scope.parent; + Scope* paramscope = td._scope.push(paramsym); + paramscope.tinst = ti; + paramscope.minst = sc.minst; + paramscope.callsc = sc; + paramscope.stc = 0; + return paramscope; +} + +/******************************************** + * Determine partial specialization order of `td` vs `td2`. + * Params: + * sc = context + * td = first template + * td2 = second template + * argumentList = arguments to template + * Returns: + * MATCH - td is at least as specialized as td2 + * MATCH.nomatch - td2 is more specialized than td + */ +MATCH leastAsSpecialized(Scope* sc, TemplateDeclaration td, TemplateDeclaration td2, ArgumentList argumentList) +{ + enum LOG_LEASTAS = 0; + static if (LOG_LEASTAS) + { + printf("%s.leastAsSpecialized(%s)\n", toChars(), td2.toChars()); + } + + /* This works by taking the template parameters to this template + * declaration and feeding them to td2 as if it were a template + * instance. + * If it works, then this template is at least as specialized + * as td2. + */ + + // Set type arguments to dummy template instance to be types + // generated from the parameters to this template declaration + auto tiargs = new Objects(); + tiargs.reserve(td.parameters.length); + foreach (tp; *td.parameters) + { + if (tp.dependent) + break; + RootObject p = tp.dummyArg(); + if (!p) //TemplateTupleParameter + break; + + tiargs.push(p); + } + scope TemplateInstance ti = new TemplateInstance(Loc.initial, td.ident, tiargs); // create dummy template instance + + // Temporary Array to hold deduced types + Objects dedtypes = Objects(td2.parameters.length); + + // Attempt a type deduction + MATCH m = matchWithInstance(sc, td2, ti, dedtypes, argumentList, 1); + if (m > MATCH.nomatch) + { + /* A non-variadic template is more specialized than a + * variadic one. + */ + TemplateTupleParameter tp = td.isVariadic(); + if (tp && !tp.dependent && !td2.isVariadic()) + goto L1; + + static if (LOG_LEASTAS) + { + printf(" matches %d, so is least as specialized\n", m); + } + return m; + } +L1: + static if (LOG_LEASTAS) + { + printf(" doesn't match, so is not as specialized\n"); + } + return MATCH.nomatch; +} + +/************************************************* + * Match function arguments against a specific template function. + * + * Params: + * td = template declaration for template instance + * ti = template instance. `ti.tdtypes` will be set to Expression/Type deduced template arguments + * sc = instantiation scope + * fd = Partially instantiated function declaration, which is set to an instantiated function declaration + * tthis = 'this' argument if !NULL + * argumentList = arguments to function + * + * Returns: + * match pair of initial and inferred template arguments + */ +extern (D) MATCHpair deduceFunctionTemplateMatch(TemplateDeclaration td, TemplateInstance ti, Scope* sc, ref FuncDeclaration fd, Type tthis, ArgumentList argumentList) +{ + version (none) + { + printf("\nTemplateDeclaration.deduceFunctionTemplateMatch() %s\n", td.toChars()); + for (size_t i = 0; i < (fargs ? fargs.length : 0); i++) + { + Expression e = (*fargs)[i]; + printf("\tfarg[%d] is %s, type is %s\n", cast(int) i, e.toChars(), e.type.toChars()); + } + printf("fd = %s\n", fd.toChars()); + printf("fd.type = %s\n", fd.type.toChars()); + if (tthis) + printf("tthis = %s\n", tthis.toChars()); + } + + assert(td._scope); + + auto dedargs = new Objects(td.parameters.length); + dedargs.zero(); + + Objects* dedtypes = &ti.tdtypes; // for T:T*, the dedargs is the T*, dedtypes is the T + dedtypes.setDim(td.parameters.length); + dedtypes.zero(); + + if (td.errors || fd.errors) + return MATCHpair(MATCH.nomatch, MATCH.nomatch); + + // Set up scope for parameters + Scope* paramscope = createScopeForTemplateParameters(td, ti,sc); + + MATCHpair nomatch() + { + paramscope.pop(); + //printf("\tnomatch\n"); + return MATCHpair(MATCH.nomatch, MATCH.nomatch); + } + + MATCHpair matcherror() + { + // todo: for the future improvement + paramscope.pop(); + //printf("\terror\n"); + return MATCHpair(MATCH.nomatch, MATCH.nomatch); + } + // Mark the parameter scope as deprecated if the templated + // function is deprecated (since paramscope.enclosing is the + // calling scope already) + paramscope.stc |= fd.storage_class & STC.deprecated_; + + TemplateTupleParameter tp = td.isVariadic(); + Tuple declaredTuple = null; + + version (none) + { + for (size_t i = 0; i < dedargs.length; i++) + { + printf("\tdedarg[%d] = ", i); + RootObject oarg = (*dedargs)[i]; + if (oarg) + printf("%s", oarg.toChars()); + printf("\n"); + } + } + + size_t ntargs = 0; // array size of tiargs + size_t inferStart = 0; // index of first parameter to infer + const Loc instLoc = ti.loc; + MATCH matchTiargs = MATCH.exact; + + if (auto tiargs = ti.tiargs) + { + // Set initial template arguments + ntargs = tiargs.length; + size_t n = td.parameters.length; + if (tp) + n--; + if (ntargs > n) + { + if (!tp) + return nomatch(); + + /* The extra initial template arguments + * now form the tuple argument. + */ + auto t = new Tuple(ntargs - n); + assert(td.parameters.length); + (*dedargs)[td.parameters.length - 1] = t; + + for (size_t i = 0; i < t.objects.length; i++) + { + t.objects[i] = (*tiargs)[n + i]; + } + td.declareParameter(paramscope, tp, t); + declaredTuple = t; + } + else + n = ntargs; + + memcpy(dedargs.tdata(), tiargs.tdata(), n * (*dedargs.tdata()).sizeof); + + for (size_t i = 0; i < n; i++) + { + assert(i < td.parameters.length); + Declaration sparam = null; + MATCH m = (*td.parameters)[i].matchArg(instLoc, paramscope, dedargs, i, td.parameters, *dedtypes, &sparam); + //printf("\tdeduceType m = %d\n", m); + if (m == MATCH.nomatch) + return nomatch(); + if (m < matchTiargs) + matchTiargs = m; + + sparam.dsymbolSemantic(paramscope); + if (!paramscope.insert(sparam)) + return nomatch(); + } + if (n < td.parameters.length && !declaredTuple) + { + inferStart = n; + } + else + inferStart = td.parameters.length; + //printf("tiargs matchTiargs = %d\n", matchTiargs); + } + version (none) + { + for (size_t i = 0; i < dedargs.length; i++) + { + printf("\tdedarg[%d] = ", i); + RootObject oarg = (*dedargs)[i]; + if (oarg) + printf("%s", oarg.toChars()); + printf("\n"); + } + } + + ParameterList fparameters = fd.getParameterList(); // function parameter list + const nfparams = fparameters.length; // number of function parameters + if (argumentList.hasNames) + return matcherror(); // TODO: resolve named args + Expression[] fargs = argumentList.arguments ? (*argumentList.arguments)[] : null; + + /* Check for match of function arguments with variadic template + * parameter, such as: + * + * void foo(T, A...)(T t, A a); + * void main() { foo(1,2,3); } + */ + size_t fptupindex = IDX_NOTFOUND; + if (tp) // if variadic + { + // TemplateTupleParameter always makes most lesser matching. + matchTiargs = MATCH.convert; + + if (nfparams == 0 && argumentList.length != 0) // if no function parameters + { + if (!declaredTuple) + { + auto t = new Tuple(); + //printf("t = %p\n", t); + (*dedargs)[td.parameters.length - 1] = t; + td.declareParameter(paramscope, tp, t); + declaredTuple = t; + } + } + else + { + /* Figure out which of the function parameters matches + * the tuple template parameter. Do this by matching + * type identifiers. + * Set the index of this function parameter to fptupindex. + */ + for (fptupindex = 0; fptupindex < nfparams; fptupindex++) + { + auto fparam = (*fparameters.parameters)[fptupindex]; // fparameters[fptupindex] ? + if (fparam.type.ty != Tident) + continue; + TypeIdentifier tid = fparam.type.isTypeIdentifier(); + if (!tp.ident.equals(tid.ident) || tid.idents.length) + continue; + + if (fparameters.varargs != VarArg.none) // variadic function doesn't + return nomatch(); // go with variadic template + + goto L1; + } + fptupindex = IDX_NOTFOUND; + L1: + } + } + + MATCH match = MATCH.exact; + if (td.toParent().isModule()) + tthis = null; + if (tthis) + { + bool hasttp = false; + + // Match 'tthis' to any TemplateThisParameter's + foreach (param; *td.parameters) + { + if (auto ttp = param.isTemplateThisParameter()) + { + hasttp = true; + + Type t = new TypeIdentifier(Loc.initial, ttp.ident); + MATCH m = deduceType(tthis, paramscope, t, *td.parameters, *dedtypes); + if (m == MATCH.nomatch) + return nomatch(); + if (m < match) + match = m; // pick worst match + } + } + + // Match attributes of tthis against attributes of fd + if (fd.type && !fd.isCtorDeclaration() && !(td._scope.stc & STC.static_)) + { + StorageClass stc = td._scope.stc | fd.storage_class2; + // Propagate parent storage class, https://issues.dlang.org/show_bug.cgi?id=5504 + Dsymbol p = td.parent; + while (p.isTemplateDeclaration() || p.isTemplateInstance()) + p = p.parent; + AggregateDeclaration ad = p.isAggregateDeclaration(); + if (ad) + stc |= ad.storage_class; + + ubyte mod = fd.type.mod; + if (stc & STC.immutable_) + mod = MODFlags.immutable_; + else + { + if (stc & (STC.shared_ | STC.synchronized_)) + mod |= MODFlags.shared_; + if (stc & STC.const_) + mod |= MODFlags.const_; + if (stc & STC.wild) + mod |= MODFlags.wild; + } + + ubyte thismod = tthis.mod; + if (hasttp) + mod = MODmerge(thismod, mod); + MATCH m = MODmethodConv(thismod, mod); + if (m == MATCH.nomatch) + return nomatch(); + if (m < match) + match = m; + } + } + + // Loop through the function parameters + { + //printf("%s\n\tnfargs = %d, nfparams = %d, tuple_dim = %d\n", toChars(), nfargs, nfparams, declaredTuple ? declaredTuple.objects.length : 0); + //printf("\ttp = %p, fptupindex = %d, found = %d, declaredTuple = %s\n", tp, fptupindex, fptupindex != IDX_NOTFOUND, declaredTuple ? declaredTuple.toChars() : NULL); + size_t argi = 0; + size_t nfargs2 = fargs.length; // nfargs + supplied defaultArgs + uint inoutMatch = 0; // for debugging only + for (size_t parami = 0; parami < nfparams; parami++) + { + Parameter fparam = fparameters[parami]; + + // Apply function parameter storage classes to parameter types + Type prmtype = fparam.type.addStorageClass(fparam.storageClass); + + Expression farg; + + /* See function parameters which wound up + * as part of a template tuple parameter. + */ + if (fptupindex != IDX_NOTFOUND && parami == fptupindex) + { + TypeIdentifier tid = prmtype.isTypeIdentifier(); + assert(tid); + if (!declaredTuple) + { + /* The types of the function arguments + * now form the tuple argument. + */ + declaredTuple = new Tuple(); + (*dedargs)[td.parameters.length - 1] = declaredTuple; + + /* Count function parameters with no defaults following a tuple parameter. + * void foo(U, T...)(int y, T, U, double, int bar = 0) {} // rem == 2 (U, double) + */ + size_t rem = 0; + foreach (j; parami + 1 .. nfparams) + { + Parameter p = fparameters[j]; + if (p.defaultArg) + { + break; + } + if (!reliesOnTemplateParameters(p.type, (*td.parameters)[inferStart .. td.parameters.length])) + { + Type pt = p.type.syntaxCopy().typeSemantic(fd.loc, paramscope); + if (auto ptt = pt.isTypeTuple()) + rem += ptt.arguments.length; + else + rem += 1; + } + else + { + ++rem; + } + } + + if (nfargs2 - argi < rem) + return nomatch(); + declaredTuple.objects.setDim(nfargs2 - argi - rem); + foreach (i; 0 .. declaredTuple.objects.length) + { + farg = fargs[argi + i]; + + // Check invalid arguments to detect errors early. + if (farg.op == EXP.error || farg.type.ty == Terror) + return nomatch(); + + if (!fparam.isLazy() && farg.type.ty == Tvoid) + return nomatch(); + + Type tt; + MATCH m; + if (ubyte wm = deduceWildHelper(farg.type, &tt, tid)) + { + inoutMatch |= wm; + m = MATCH.constant; + } + else + { + m = deduceTypeHelper(farg.type, tt, tid); + } + if (m == MATCH.nomatch) + return nomatch(); + if (m < match) + match = m; + + /* Remove top const for dynamic array types and pointer types + */ + if ((tt.ty == Tarray || tt.ty == Tpointer) && !tt.isMutable() && (!(fparam.storageClass & STC.ref_) || (fparam.storageClass & STC.auto_) && !farg.isLvalue())) + { + tt = tt.mutableOf(); + } + declaredTuple.objects[i] = tt; + } + td.declareParameter(paramscope, tp, declaredTuple); + } + else + { + // https://issues.dlang.org/show_bug.cgi?id=6810 + // If declared tuple is not a type tuple, + // it cannot be function parameter types. + for (size_t i = 0; i < declaredTuple.objects.length; i++) + { + if (!isType(declaredTuple.objects[i])) + return nomatch(); + } + } + assert(declaredTuple); + argi += declaredTuple.objects.length; + continue; + } + + // If parameter type doesn't depend on inferred template parameters, + // semantic it to get actual type. + if (!reliesOnTemplateParameters(prmtype, (*td.parameters)[inferStart .. td.parameters.length])) + { + // should copy prmtype to avoid affecting semantic result + prmtype = prmtype.syntaxCopy().typeSemantic(fd.loc, paramscope); + + if (TypeTuple tt = prmtype.isTypeTuple()) + { + const tt_dim = tt.arguments.length; + for (size_t j = 0; j < tt_dim; j++, ++argi) + { + Parameter p = (*tt.arguments)[j]; + if (j == tt_dim - 1 && fparameters.varargs == VarArg.typesafe && + parami + 1 == nfparams && argi < fargs.length) + { + prmtype = p.type; + goto Lvarargs; + } + if (argi >= fargs.length) + { + if (p.defaultArg) + continue; + + // https://issues.dlang.org/show_bug.cgi?id=19888 + if (fparam.defaultArg) + break; + + return nomatch(); + } + farg = fargs[argi]; + if (!farg.implicitConvTo(p.type)) + return nomatch(); + } + continue; + } + } + + if (argi >= fargs.length) // if not enough arguments + { + if (!fparam.defaultArg) + goto Lvarargs; + + /* https://issues.dlang.org/show_bug.cgi?id=2803 + * Before the starting of type deduction from the function + * default arguments, set the already deduced parameters into paramscope. + * It's necessary to avoid breaking existing acceptable code. Cases: + * + * 1. Already deduced template parameters can appear in fparam.defaultArg: + * auto foo(A, B)(A a, B b = A.stringof); + * foo(1); + * // at fparam == 'B b = A.string', A is equivalent with the deduced type 'int' + * + * 2. If prmtype depends on default-specified template parameter, the + * default type should be preferred. + * auto foo(N = size_t, R)(R r, N start = 0) + * foo([1,2,3]); + * // at fparam `N start = 0`, N should be 'size_t' before + * // the deduction result from fparam.defaultArg. + */ + if (argi == fargs.length) + { + foreach (ref dedtype; *dedtypes) + { + Type at = isType(dedtype); + if (at && at.ty == Tnone) + { + TypeDeduced xt = cast(TypeDeduced)at; + dedtype = xt.tded; // 'unbox' + } + } + for (size_t i = ntargs; i < dedargs.length; i++) + { + TemplateParameter tparam = (*td.parameters)[i]; + + RootObject oarg = (*dedargs)[i]; + RootObject oded = (*dedtypes)[i]; + if (oarg) + continue; + + if (oded) + { + if (tparam.specialization() || !tparam.isTemplateTypeParameter()) + { + /* The specialization can work as long as afterwards + * the oded == oarg + */ + (*dedargs)[i] = oded; + MATCH m2 = tparam.matchArg(instLoc, paramscope, dedargs, i, td.parameters, *dedtypes, null); + //printf("m2 = %d\n", m2); + if (m2 == MATCH.nomatch) + return nomatch(); + if (m2 < matchTiargs) + matchTiargs = m2; // pick worst match + if (!(*dedtypes)[i].equals(oded)) + .error(td.loc, "%s `%s` specialization not allowed for deduced parameter `%s`", + td.kind, td.toPrettyChars, td.kind, td.toPrettyChars, tparam.ident.toChars()); + } + else + { + if (MATCH.convert < matchTiargs) + matchTiargs = MATCH.convert; + } + (*dedargs)[i] = td.declareParameter(paramscope, tparam, oded); + } + else + { + oded = tparam.defaultArg(instLoc, paramscope); + if (oded) + (*dedargs)[i] = td.declareParameter(paramscope, tparam, oded); + } + } + } + nfargs2 = argi + 1; + + /* If prmtype does not depend on any template parameters: + * + * auto foo(T)(T v, double x = 0); + * foo("str"); + * // at fparam == 'double x = 0' + * + * or, if all template parameters in the prmtype are already deduced: + * + * auto foo(R)(R range, ElementType!R sum = 0); + * foo([1,2,3]); + * // at fparam == 'ElementType!R sum = 0' + * + * Deducing prmtype from fparam.defaultArg is not necessary. + */ + if (prmtype.deco || prmtype.syntaxCopy().trySemantic(td.loc, paramscope)) + { + ++argi; + continue; + } + + // Deduce prmtype from the defaultArg. + farg = fparam.defaultArg.syntaxCopy(); + farg = farg.expressionSemantic(paramscope); + farg = resolveProperties(paramscope, farg); + } + else + { + farg = fargs[argi]; + } + { + // Check invalid arguments to detect errors early. + if (farg.op == EXP.error || farg.type.ty == Terror) + return nomatch(); + + Type att = null; + Lretry: + version (none) + { + printf("\tfarg.type = %s\n", farg.type.toChars()); + printf("\tfparam.type = %s\n", prmtype.toChars()); + } + Type argtype = farg.type; + + if (!fparam.isLazy() && argtype.ty == Tvoid && farg.op != EXP.function_) + return nomatch(); + + // https://issues.dlang.org/show_bug.cgi?id=12876 + // Optimize argument to allow CT-known length matching + farg = farg.optimize(WANTvalue, fparam.isReference()); + //printf("farg = %s %s\n", farg.type.toChars(), farg.toChars()); + + RootObject oarg = farg; + if ((fparam.storageClass & STC.ref_) && (!(fparam.storageClass & STC.auto_) || farg.isLvalue())) + { + /* Allow expressions that have CT-known boundaries and type [] to match with [dim] + */ + bool inferIndexType = (argtype.ty == Tarray) && (prmtype.ty == Tsarray || prmtype.ty == Taarray); + if (auto aaType = prmtype.isTypeAArray()) + { + if (auto indexType = aaType.index.isTypeIdentifier()) + { + inferIndexType = indexType.idents.length == 0; + } + } + if (inferIndexType) + { + if (StringExp se = farg.isStringExp()) + { + argtype = se.type.nextOf().sarrayOf(se.len); + } + else if (ArrayLiteralExp ae = farg.isArrayLiteralExp()) + { + argtype = ae.type.nextOf().sarrayOf(ae.elements.length); + } + else if (SliceExp se = farg.isSliceExp()) + { + if (Type tsa = toStaticArrayType(se)) + argtype = tsa; + } + } + + oarg = argtype; + } + else if ((fparam.storageClass & STC.out_) == 0 && + (argtype.ty == Tarray || argtype.ty == Tpointer) && + templateParameterLookup(prmtype, td.parameters) != IDX_NOTFOUND && + prmtype.isTypeIdentifier().idents.length == 0) + { + /* The farg passing to the prmtype always make a copy. Therefore, + * we can shrink the set of the deduced type arguments for prmtype + * by adjusting top-qualifier of the argtype. + * + * prmtype argtype ta + * T <- const(E)[] const(E)[] + * T <- const(E[]) const(E)[] + * qualifier(T) <- const(E)[] const(E[]) + * qualifier(T) <- const(E[]) const(E[]) + */ + Type ta = argtype.castMod(prmtype.mod ? argtype.nextOf().mod : 0); + if (ta != argtype) + { + Expression ea = farg.copy(); + ea.type = ta; + oarg = ea; + } + } + + if (fparameters.varargs == VarArg.typesafe && parami + 1 == nfparams && argi + 1 < fargs.length) + goto Lvarargs; + + uint im = 0; + MATCH m = deduceType(oarg, paramscope, prmtype, *td.parameters, *dedtypes, &im, inferStart); + //printf("\tL%d deduceType m = %d, im = x%x, inoutMatch = x%x\n", __LINE__, m, im, inoutMatch); + inoutMatch |= im; + + /* If no match, see if the argument can be matched by using + * implicit conversions. + */ + if (m == MATCH.nomatch && prmtype.deco) + m = farg.implicitConvTo(prmtype); + + if (m == MATCH.nomatch) + { + AggregateDeclaration ad = isAggregate(farg.type); + if (ad && ad.aliasthis && !isRecursiveAliasThis(att, argtype)) + { + // https://issues.dlang.org/show_bug.cgi?id=12537 + // The isRecursiveAliasThis() call above + + /* If a semantic error occurs while doing alias this, + * eg purity(https://issues.dlang.org/show_bug.cgi?id=7295), + * just regard it as not a match. + * + * We also save/restore sc.func.flags to avoid messing up + * attribute inference in the evaluation. + */ + const oldflags = sc.func ? sc.func.flags : 0; + auto e = resolveAliasThis(sc, farg, true); + if (sc.func) + sc.func.flags = oldflags; + if (e) + { + farg = e; + goto Lretry; + } + } + } + + if (m > MATCH.nomatch && (fparam.storageClass & (STC.ref_ | STC.auto_)) == STC.ref_) + { + if (!farg.isLvalue()) + { + if ((farg.op == EXP.string_ || farg.op == EXP.slice) && (prmtype.ty == Tsarray || prmtype.ty == Taarray)) + { + // Allow conversion from T[lwr .. upr] to ref T[upr-lwr] + } + else if (global.params.rvalueRefParam == FeatureState.enabled) + { + // Allow implicit conversion to ref + } + else + return nomatch(); + } + } + if (m > MATCH.nomatch && (fparam.storageClass & STC.out_)) + { + if (!farg.isLvalue()) + return nomatch(); + if (!farg.type.isMutable()) // https://issues.dlang.org/show_bug.cgi?id=11916 + return nomatch(); + } + if (m == MATCH.nomatch && fparam.isLazy() && prmtype.ty == Tvoid && farg.type.ty != Tvoid) + m = MATCH.convert; + if (m != MATCH.nomatch) + { + if (m < match) + match = m; // pick worst match + argi++; + continue; + } + } + + Lvarargs: + /* The following code for variadic arguments closely + * matches TypeFunction.callMatch() + */ + if (!(fparameters.varargs == VarArg.typesafe && parami + 1 == nfparams)) + return nomatch(); + + /* Check for match with function parameter T... + */ + Type tb = prmtype.toBasetype(); + switch (tb.ty) + { + // 6764 fix - TypeAArray may be TypeSArray have not yet run semantic(). + case Tsarray: + case Taarray: + { + // Perhaps we can do better with this, see TypeFunction.callMatch() + if (TypeSArray tsa = tb.isTypeSArray()) + { + dinteger_t sz = tsa.dim.toInteger(); + if (sz != fargs.length - argi) + return nomatch(); + } + else if (TypeAArray taa = tb.isTypeAArray()) + { + Expression dim = new IntegerExp(instLoc, fargs.length - argi, Type.tsize_t); + + size_t i = templateParameterLookup(taa.index, td.parameters); + if (i == IDX_NOTFOUND) + { + Expression e; + Type t; + Dsymbol s; + Scope *sco; + + uint errors = global.startGagging(); + /* ref: https://issues.dlang.org/show_bug.cgi?id=11118 + * The parameter isn't part of the template + * ones, let's try to find it in the + * instantiation scope 'sc' and the one + * belonging to the template itself. */ + sco = sc; + taa.index.resolve(instLoc, sco, e, t, s); + if (!e) + { + sco = paramscope; + taa.index.resolve(instLoc, sco, e, t, s); + } + global.endGagging(errors); + + if (!e) + return nomatch(); + + e = e.ctfeInterpret(); + e = e.implicitCastTo(sco, Type.tsize_t); + e = e.optimize(WANTvalue); + if (!dim.equals(e)) + return nomatch(); + } + else + { + // This code matches code in TypeInstance.deduceType() + TemplateParameter tprm = (*td.parameters)[i]; + TemplateValueParameter tvp = tprm.isTemplateValueParameter(); + if (!tvp) + return nomatch(); + Expression e = cast(Expression)(*dedtypes)[i]; + if (e) + { + if (!dim.equals(e)) + return nomatch(); + } + else + { + Type vt = tvp.valType.typeSemantic(Loc.initial, sc); + MATCH m = dim.implicitConvTo(vt); + if (m == MATCH.nomatch) + return nomatch(); + (*dedtypes)[i] = dim; + } + } + } + goto case Tarray; + } + case Tarray: + { + TypeArray ta = cast(TypeArray)tb; + Type tret = fparam.isLazyArray(); + for (; argi < fargs.length; argi++) + { + Expression arg = fargs[argi]; + assert(arg); + + MATCH m; + /* If lazy array of delegates, + * convert arg(s) to delegate(s) + */ + if (tret) + { + if (ta.next.equals(arg.type)) + { + m = MATCH.exact; + } + else + { + m = arg.implicitConvTo(tret); + if (m == MATCH.nomatch) + { + if (tret.toBasetype().ty == Tvoid) + m = MATCH.convert; + } + } + } + else + { + uint wm = 0; + m = deduceType(arg, paramscope, ta.next, *td.parameters, *dedtypes, &wm, inferStart); + inoutMatch |= wm; + } + if (m == MATCH.nomatch) + return nomatch(); + if (m < match) + match = m; + } + goto Lmatch; + } + case Tclass: + case Tident: + goto Lmatch; + + default: + return nomatch(); + } + assert(0); + } + //printf(". argi = %d, nfargs = %d, nfargs2 = %d\n", argi, nfargs, nfargs2); + if (argi != nfargs2 && fparameters.varargs == VarArg.none) + return nomatch(); + } + +Lmatch: + foreach (ref dedtype; *dedtypes) + { + if (Type at = isType(dedtype)) + { + if (at.ty == Tnone) + { + TypeDeduced xt = cast(TypeDeduced)at; + at = xt.tded; // 'unbox' + } + dedtype = at.merge2(); + } + } + for (size_t i = ntargs; i < dedargs.length; i++) + { + TemplateParameter tparam = (*td.parameters)[i]; + //printf("tparam[%d] = %s\n", i, tparam.ident.toChars()); + + /* For T:T*, the dedargs is the T*, dedtypes is the T + * But for function templates, we really need them to match + */ + RootObject oarg = (*dedargs)[i]; + RootObject oded = (*dedtypes)[i]; + //printf("1dedargs[%d] = %p, dedtypes[%d] = %p\n", i, oarg, i, oded); + //if (oarg) printf("oarg: %s\n", oarg.toChars()); + //if (oded) printf("oded: %s\n", oded.toChars()); + if (oarg) + continue; + + if (oded) + { + if (tparam.specialization() || !tparam.isTemplateTypeParameter()) + { + /* The specialization can work as long as afterwards + * the oded == oarg + */ + (*dedargs)[i] = oded; + MATCH m2 = tparam.matchArg(instLoc, paramscope, dedargs, i, td.parameters, *dedtypes, null); + //printf("m2 = %d\n", m2); + if (m2 == MATCH.nomatch) + return nomatch(); + if (m2 < matchTiargs) + matchTiargs = m2; // pick worst match + if (!(*dedtypes)[i].equals(oded)) + .error(td.loc, "%s `%s` specialization not allowed for deduced parameter `%s`", td.kind, td.toPrettyChars, tparam.ident.toChars()); + } + else + { + // Discussion: https://issues.dlang.org/show_bug.cgi?id=16484 + if (MATCH.convert < matchTiargs) + matchTiargs = MATCH.convert; + } + } + else + { + oded = tparam.defaultArg(instLoc, paramscope); + if (!oded) + { + // if tuple parameter and + // tuple parameter was not in function parameter list and + // we're one or more arguments short (i.e. no tuple argument) + if (tparam == tp && + fptupindex == IDX_NOTFOUND && + ntargs <= dedargs.length - 1) + { + // make tuple argument an empty tuple + oded = new Tuple(); + } + else + return nomatch(); + } + if (isError(oded)) + return matcherror(); + ntargs++; + + /* At the template parameter T, the picked default template argument + * X!int should be matched to T in order to deduce dependent + * template parameter A. + * auto foo(T : X!A = X!int, A...)() { ... } + * foo(); // T <-- X!int, A <-- (int) + */ + if (tparam.specialization()) + { + (*dedargs)[i] = oded; + MATCH m2 = tparam.matchArg(instLoc, paramscope, dedargs, i, td.parameters, *dedtypes, null); + //printf("m2 = %d\n", m2); + if (m2 == MATCH.nomatch) + return nomatch(); + if (m2 < matchTiargs) + matchTiargs = m2; // pick worst match + if (!(*dedtypes)[i].equals(oded)) + .error(td.loc, "%s `%s` specialization not allowed for deduced parameter `%s`", td.kind, td.toPrettyChars, tparam.ident.toChars()); + } + } + oded = td.declareParameter(paramscope, tparam, oded); + (*dedargs)[i] = oded; + } + + /* https://issues.dlang.org/show_bug.cgi?id=7469 + * As same as the code for 7469 in findBestMatch, + * expand a Tuple in dedargs to normalize template arguments. + */ + if (auto d = dedargs.length) + { + if (auto va = isTuple((*dedargs)[d - 1])) + { + dedargs.setDim(d - 1); + dedargs.insert(d - 1, &va.objects); + } + } + ti.tiargs = dedargs; // update to the normalized template arguments. + + // Partially instantiate function for constraint and fd.leastAsSpecialized() + { + assert(paramscope.scopesym); + Scope* sc2 = td._scope; + sc2 = sc2.push(paramscope.scopesym); + sc2 = sc2.push(ti); + sc2.parent = ti; + sc2.tinst = ti; + sc2.minst = sc.minst; + sc2.stc |= fd.storage_class & STC.deprecated_; + + fd = td.doHeaderInstantiation(ti, sc2, fd, tthis, argumentList.arguments); + sc2 = sc2.pop(); + sc2 = sc2.pop(); + + if (!fd) + return nomatch(); + } + + if (td.constraint) + { + if (!evaluateConstraint(td, ti, sc, paramscope, dedargs, fd)) + return nomatch(); + } + + version (none) + { + for (size_t i = 0; i < dedargs.length; i++) + { + RootObject o = (*dedargs)[i]; + printf("\tdedargs[%d] = %d, %s\n", i, o.dyncast(), o.toChars()); + } + } + + paramscope.pop(); + //printf("\tmatch %d\n", match); + return MATCHpair(matchTiargs, match); +} diff --git a/gcc/d/dmd/tokens.d b/gcc/d/dmd/tokens.d index 589bc2b..da4a3ee 100644 --- a/gcc/d/dmd/tokens.d +++ b/gcc/d/dmd/tokens.d @@ -124,6 +124,7 @@ enum TOK : ubyte // Leaf operators identifier, string_, + interpolated, hexadecimalString, this_, super_, @@ -380,6 +381,7 @@ enum EXP : ubyte // Leaf operators identifier, string_, + interpolated, this_, super_, halt, @@ -623,6 +625,10 @@ static immutable TOK[TOK.max + 1] Ckeywords = } } (); +struct InterpolatedSet { + // all strings in the parts are zero terminated at length+1 + string[] parts; +} /*********************************************************** */ @@ -645,7 +651,11 @@ extern (C++) struct Token struct { - const(char)* ustring; // UTF8 string + union + { + const(char)* ustring; // UTF8 string + InterpolatedSet* interpolatedSet; + } uint len; ubyte postfix; // 'c', 'w', 'd' } @@ -833,6 +843,7 @@ extern (C++) struct Token // For debugging TOK.error: "error", TOK.string_: "string", + TOK.interpolated: "interpolated string", TOK.onScopeExit: "scope(exit)", TOK.onScopeSuccess: "scope(success)", TOK.onScopeFailure: "scope(failure)", @@ -910,6 +921,24 @@ nothrow: return 0; } + extern(D) void appendInterpolatedPart(const ref OutBuffer buf) { + appendInterpolatedPart(cast(const(char)*)buf[].ptr, buf.length); + } + extern(D) void appendInterpolatedPart(const(char)[] str) { + appendInterpolatedPart(str.ptr, str.length); + } + extern(D) void appendInterpolatedPart(const(char)* ptr, size_t length) { + assert(value == TOK.interpolated); + if (interpolatedSet is null) + interpolatedSet = new InterpolatedSet; + + auto s = cast(char*)mem.xmalloc_noscan(length + 1); + memcpy(s, ptr, length); + s[length] = 0; + + interpolatedSet.parts ~= cast(string) s[0 .. length]; + } + /**** * Set to contents of ptr[0..length] * Params: @@ -918,6 +947,7 @@ nothrow: */ void setString(const(char)* ptr, size_t length) { + value = TOK.string_; auto s = cast(char*)mem.xmalloc_noscan(length + 1); memcpy(s, ptr, length); s[length] = 0; @@ -941,6 +971,7 @@ nothrow: */ void setString() { + value = TOK.string_; ustring = ""; len = 0; postfix = 0; diff --git a/gcc/d/dmd/tokens.h b/gcc/d/dmd/tokens.h index f944663..ef91001 100644 --- a/gcc/d/dmd/tokens.h +++ b/gcc/d/dmd/tokens.h @@ -133,6 +133,7 @@ enum class TOK : unsigned char // Leaf operators identifier, string_, + interpolated, hexadecimalString, this_, super_, @@ -390,6 +391,7 @@ enum class EXP : unsigned char // Leaf operators identifier, string_, + interpolated, this_, super_, halt, @@ -461,7 +463,12 @@ struct Token real_t floatvalue; struct - { utf8_t *ustring; // UTF8 string + { + union + { + utf8_t *ustring; // UTF8 string + void *interpolatedSet; + }; unsigned len; unsigned char postfix; // 'c', 'w', 'd' }; diff --git a/gcc/d/dmd/traits.d b/gcc/d/dmd/traits.d index c67ee81..be7aa99 100644 --- a/gcc/d/dmd/traits.d +++ b/gcc/d/dmd/traits.d @@ -36,6 +36,7 @@ import dmd.errorsink; import dmd.expression; import dmd.expressionsem; import dmd.func; +import dmd.funcsem; import dmd.globals; import dmd.hdrgen; import dmd.id; @@ -1306,7 +1307,7 @@ Expression semanticTraits(TraitsExp e, Scope* sc) // attribute inference. if (fd && fd.parent && fd.parent.isTemplateInstance) { - fd.functionSemantic3(); + functionSemantic3(fd); tf = fd.type.isTypeFunction(); } diff --git a/gcc/d/dmd/typesem.d b/gcc/d/dmd/typesem.d index 714af8a..6721fa6 100644 --- a/gcc/d/dmd/typesem.d +++ b/gcc/d/dmd/typesem.d @@ -35,6 +35,7 @@ import dmd.dstruct; import dmd.dsymbol; import dmd.dsymbolsem; import dmd.dtemplate; +import dmd.enumsem; import dmd.errors; import dmd.errorsink; import dmd.expression; @@ -2919,6 +2920,29 @@ extern (C++) Type merge(Type type) return type; } +/************************************* + * This version does a merge even if the deco is already computed. + * Necessary for types that have a deco, but are not merged. + */ +extern(C++) Type merge2(Type type) +{ + //printf("merge2(%s)\n", toChars()); + Type t = type; + assert(t); + if (!t.deco) + return t.merge(); + + auto sv = Type.stringtable.lookup(t.deco, strlen(t.deco)); + if (sv && sv.value) + { + t = sv.value; + assert(t.deco); + } + else + assert(0); + return t; +} + /*************************************** * Calculate built-in properties which just the type is necessary. * @@ -5697,7 +5721,7 @@ Type getComplexLibraryType(const ref Loc loc, Scope* sc, TY ty) * Returns: * An enum value of either `Covariant.yes` or a reason it's not covariant. */ -extern (C++) Covariant covariant(Type src, Type t, StorageClass* pstc = null, bool cppCovariant = false) +extern(C++) Covariant covariant(Type src, Type t, StorageClass* pstc = null, bool cppCovariant = false) { version (none) { diff --git a/gcc/d/dmd/typinf.d b/gcc/d/dmd/typinf.d index 9e062bd..6ae6df0 100644 --- a/gcc/d/dmd/typinf.d +++ b/gcc/d/dmd/typinf.d @@ -65,6 +65,7 @@ extern (C++) bool genTypeInfo(Expression e, const ref Loc loc, Type torig, Scope fatal(); } + import dmd.typesem : merge2; Type t = torig.merge2(); // do this since not all Type's are merge'd bool needsCodegen = false; if (!t.vtinfo) diff --git a/gcc/d/dmd/visitor.h b/gcc/d/dmd/visitor.h index 7fa08cb0..6e3d315 100644 --- a/gcc/d/dmd/visitor.h +++ b/gcc/d/dmd/visitor.h @@ -195,6 +195,7 @@ class ThisExp; class SuperExp; class NullExp; class StringExp; +class InterpExp; class TupleExp; class ArrayLiteralExp; class AssocArrayLiteralExp; @@ -480,6 +481,7 @@ public: virtual void visit(TypeidExp *e) { visit((Expression *)e); } virtual void visit(TraitsExp *e) { visit((Expression *)e); } virtual void visit(StringExp *e) { visit((Expression *)e); } + virtual void visit(InterpExp *e) { visit((Expression *)e); } virtual void visit(NewExp *e) { visit((Expression *)e); } virtual void visit(AssocArrayLiteralExp *e) { visit((Expression *)e); } virtual void visit(ArrayLiteralExp *e) { visit((Expression *)e); } diff --git a/gcc/d/expr.cc b/gcc/d/expr.cc index 6f596c5..0a85a55 100644 --- a/gcc/d/expr.cc +++ b/gcc/d/expr.cc @@ -2495,17 +2495,18 @@ public: for (size_t i = 0; i < e->len; i++) { - tree value = build_integer_cst (e->getCodeUnit (i), etype); + tree value = build_integer_cst (e->getIndex (i), etype); CONSTRUCTOR_APPEND_ELT (elms, size_int (i), value); } tree ctor = build_constructor (type, elms); TREE_CONSTANT (ctor) = 1; this->result_ = ctor; + return; } else { - /* Copy the string contents to a null terminated string. */ + /* Copy the string contents to a null terminated STRING_CST. */ dinteger_t length = (e->len * e->sz); char *string = XALLOCAVEC (char, length + e->sz); memset (string, 0, length + e->sz); @@ -2514,7 +2515,18 @@ public: /* String value and type includes the null terminator. */ tree value = build_string (length + e->sz, string); - TREE_TYPE (value) = make_array_type (tb->nextOf (), length + 1); + if (e->sz <= 4) + TREE_TYPE (value) = make_array_type (tb->nextOf (), length + 1); + else + { + /* Hexadecimal literal strings with an 8-byte character type are + just an alternative way to store an array of `ulong'. + Treat it as if it were a `uint[]' array instead. */ + dinteger_t resize = e->sz / 4; + TREE_TYPE (value) = make_array_type (Type::tuns32, + (length * resize) + resize); + } + value = build_address (value); if (tb->ty == TY::Tarray) diff --git a/gcc/d/typeinfo.cc b/gcc/d/typeinfo.cc index dfab0e6..1600ca9 100644 --- a/gcc/d/typeinfo.cc +++ b/gcc/d/typeinfo.cc @@ -259,8 +259,9 @@ create_tinfo_types (Module *mod) array_type_node, array_type_node, array_type_node, array_type_node, ptr_type_node, ptr_type_node, ptr_type_node, d_uint_type, ptr_type_node, - array_type_node, ptr_type_node, d_ulong_type, - d_ulong_type, ptr_type_node, NULL); + array_type_node, ptr_type_node, ptr_type_node, + d_uint_type, d_uint_type, d_uint_type, d_uint_type, + NULL); object_module = mod; } @@ -577,7 +578,7 @@ public: void visit (TypeInfoConstDeclaration *d) final override { Type *tm = d->tinfo->mutableOf (); - tm = tm->merge2 (); + tm = merge2 (tm); /* The vtable for TypeInfo_Const. */ this->layout_base (Type::typeinfoconst); @@ -594,7 +595,7 @@ public: void visit (TypeInfoInvariantDeclaration *d) final override { Type *tm = d->tinfo->mutableOf (); - tm = tm->merge2 (); + tm = merge2 (tm); /* The vtable for TypeInfo_Invariant. */ this->layout_base (Type::typeinfoinvariant); @@ -611,7 +612,7 @@ public: void visit (TypeInfoSharedDeclaration *d) final override { Type *tm = d->tinfo->unSharedOf (); - tm = tm->merge2 (); + tm = merge2 (tm); /* The vtable for TypeInfo_Shared. */ this->layout_base (Type::typeinfoshared); @@ -628,7 +629,7 @@ public: void visit (TypeInfoWildDeclaration *d) final override { Type *tm = d->tinfo->mutableOf (); - tm = tm->merge2 (); + tm = merge2 (tm); /* The vtable for TypeInfo_Inout. */ this->layout_base (Type::typeinfowild); @@ -934,10 +935,6 @@ public: else this->layout_field (null_pointer_node); - /* ulong[2] nameSig; */ - this->layout_field (build_zero_cst (d_ulong_type)); - this->layout_field (build_zero_cst (d_ulong_type)); - /* immutable(void)* m_RTInfo; */ if (cd->getRTInfo) this->layout_field (build_expr (cd->getRTInfo, true)); @@ -945,6 +942,12 @@ public: this->layout_field (size_one_node); else this->layout_field (null_pointer_node); + + /* uint[4] nameSig; */ + this->layout_field (build_zero_cst (d_uint_type)); + this->layout_field (build_zero_cst (d_uint_type)); + this->layout_field (build_zero_cst (d_uint_type)); + this->layout_field (build_zero_cst (d_uint_type)); } else { @@ -985,15 +988,17 @@ public: this->layout_field (null_array_node); this->layout_field (null_pointer_node); - /* ulong[2] nameSig; */ - this->layout_field (build_zero_cst (d_ulong_type)); - this->layout_field (build_zero_cst (d_ulong_type)); - /* immutable(void)* m_RTInfo; */ if (cd->getRTInfo) this->layout_field (build_expr (cd->getRTInfo, true)); else this->layout_field (null_pointer_node); + + /* uint[4] nameSig; */ + this->layout_field (build_zero_cst (d_uint_type)); + this->layout_field (build_zero_cst (d_uint_type)); + this->layout_field (build_zero_cst (d_uint_type)); + this->layout_field (build_zero_cst (d_uint_type)); } /* Put out array of Interfaces. */ @@ -1546,7 +1551,7 @@ create_typeinfo (Type *type, Module *mod, bool generate) create_frontend_tinfo_types (); /* Do this since not all Type's are merged. */ - Type *t = type->merge2 (); + Type *t = merge2 (type); Identifier *ident; if (!t->vtinfo) diff --git a/gcc/testsuite/gdc.test/compilable/test13281.d b/gcc/testsuite/gdc.test/compilable/test13281.d index 0d747fa..ab92fcc 100644 --- a/gcc/testsuite/gdc.test/compilable/test13281.d +++ b/gcc/testsuite/gdc.test/compilable/test13281.d @@ -36,12 +36,27 @@ static assert((123 ).stringof == "123"); static assert((123u ).stringof == "123u"); static assert((123L ).stringof == "123L"); static assert((123uL).stringof == "123LU"); -static assert((123.5 ).stringof == "1.235e+2"); -static assert((123.5f ).stringof == "1.235e+2F"); -static assert((123.5L ).stringof == "1.235e+2L"); -static assert((123.5i ).stringof == "1.235e+2i"); -static assert((123.5fi).stringof == "1.235e+2Fi"); -static assert((123.5Li).stringof == "1.235e+2Li"); -static assert((123.5 +5.5i ).stringof == "1.235e+2 + 5.5e+0i"); -static assert((123.5f+5.5fi).stringof == "1.235e+2F + 5.5e+0Fi"); -static assert((123.5L+5.5Li).stringof == "1.235e+2L + 5.5e+0Li"); +version (GNU) +{ + static assert((123.5 ).stringof == "1.235e+2"); + static assert((123.5f ).stringof == "1.235e+2F"); + static assert((123.5L ).stringof == "1.235e+2L"); + static assert((123.5i ).stringof == "1.235e+2i"); + static assert((123.5fi).stringof == "1.235e+2Fi"); + static assert((123.5Li).stringof == "1.235e+2Li"); + static assert((123.5 +5.5i ).stringof == "1.235e+2 + 5.5e+0i"); + static assert((123.5f+5.5fi).stringof == "1.235e+2F + 5.5e+0Fi"); + static assert((123.5L+5.5Li).stringof == "1.235e+2L + 5.5e+0Li"); +} +else +{ + static assert((123.5 ).stringof == "123.5"); + static assert((123.5f ).stringof == "123.5F"); + static assert((123.5L ).stringof == "123.5L"); + static assert((123.5i ).stringof == "123.5i"); + static assert((123.5fi).stringof == "123.5Fi"); + static assert((123.5Li).stringof == "123.5Li"); + static assert((123.5 +5.5i ).stringof == "123.5 + 5.5i"); + static assert((123.5f+5.5fi).stringof == "123.5F + 5.5Fi"); + static assert((123.5L+5.5Li).stringof == "123.5L + 5.5Li"); +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/b19523.d b/gcc/testsuite/gdc.test/fail_compilation/b19523.d index 3626666..d2a05c7 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/b19523.d +++ b/gcc/testsuite/gdc.test/fail_compilation/b19523.d @@ -1,10 +1,11 @@ /* TEST_OUTPUT: ---- -fail_compilation/b19523.d(12): Error: undefined identifier `SomeStruct` -fail_compilation/b19523.d(13): Error: function `b19523.foo(int delegate() arg)` is not callable using argument types `(_error_)` -fail_compilation/b19523.d(13): cannot pass argument `__lambda2` of type `_error_` to parameter `int delegate() arg` ---- +---- +fail_compilation/b19523.d(13): Error: undefined identifier `SomeStruct` +fail_compilation/b19523.d(14): Error: function `foo` is not callable using argument types `(_error_)` +fail_compilation/b19523.d(14): cannot pass argument `__lambda2` of type `_error_` to parameter `int delegate() arg` +fail_compilation/b19523.d(19): `b19523.foo(int delegate() arg)` declared here +---- */ module b19523; diff --git a/gcc/testsuite/gdc.test/fail_compilation/b20011.d b/gcc/testsuite/gdc.test/fail_compilation/b20011.d index 3ddcdaa..50ef6af 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/b20011.d +++ b/gcc/testsuite/gdc.test/fail_compilation/b20011.d @@ -1,16 +1,19 @@ /* TEST_OUTPUT: --- -fail_compilation/b20011.d(25): Error: cannot modify expression `S1(cast(ubyte)0u).member` because it is not an lvalue -fail_compilation/b20011.d(28): Error: cannot modify expression `S2(null).member` because it is not an lvalue -fail_compilation/b20011.d(29): Error: cannot modify expression `S2(null).member` because it is not an lvalue -fail_compilation/b20011.d(32): Error: cannot modify expression `U1(cast(ubyte)0u, ).m2` because it is not an lvalue -fail_compilation/b20011.d(37): Error: function `b20011.main.assignableByRef(ref ubyte p)` is not callable using argument types `(ubyte)` -fail_compilation/b20011.d(37): cannot pass rvalue argument `S1(cast(ubyte)0u).member` of type `ubyte` to parameter `ref ubyte p` -fail_compilation/b20011.d(38): Error: function `b20011.main.assignableByOut(out ubyte p)` is not callable using argument types `(ubyte)` -fail_compilation/b20011.d(38): cannot pass rvalue argument `S1(cast(ubyte)0u).member` of type `ubyte` to parameter `out ubyte p` -fail_compilation/b20011.d(39): Error: function `b20011.main.assignableByConstRef(ref const(ubyte) p)` is not callable using argument types `(ubyte)` -fail_compilation/b20011.d(39): cannot pass rvalue argument `S1(cast(ubyte)0u).member` of type `ubyte` to parameter `ref const(ubyte) p` +fail_compilation/b20011.d(28): Error: cannot modify expression `S1(cast(ubyte)0u).member` because it is not an lvalue +fail_compilation/b20011.d(31): Error: cannot modify expression `S2(null).member` because it is not an lvalue +fail_compilation/b20011.d(32): Error: cannot modify expression `S2(null).member` because it is not an lvalue +fail_compilation/b20011.d(35): Error: cannot modify expression `U1(cast(ubyte)0u, ).m2` because it is not an lvalue +fail_compilation/b20011.d(40): Error: function `assignableByRef` is not callable using argument types `(ubyte)` +fail_compilation/b20011.d(40): cannot pass rvalue argument `S1(cast(ubyte)0u).member` of type `ubyte` to parameter `ref ubyte p` +fail_compilation/b20011.d(37): `b20011.main.assignableByRef(ref ubyte p)` declared here +fail_compilation/b20011.d(41): Error: function `assignableByOut` is not callable using argument types `(ubyte)` +fail_compilation/b20011.d(41): cannot pass rvalue argument `S1(cast(ubyte)0u).member` of type `ubyte` to parameter `out ubyte p` +fail_compilation/b20011.d(38): `b20011.main.assignableByOut(out ubyte p)` declared here +fail_compilation/b20011.d(42): Error: function `assignableByConstRef` is not callable using argument types `(ubyte)` +fail_compilation/b20011.d(42): cannot pass rvalue argument `S1(cast(ubyte)0u).member` of type `ubyte` to parameter `ref const(ubyte) p` +fail_compilation/b20011.d(39): `b20011.main.assignableByConstRef(ref const(ubyte) p)` declared here --- */ module b20011; diff --git a/gcc/testsuite/gdc.test/fail_compilation/bug15613.d b/gcc/testsuite/gdc.test/fail_compilation/bug15613.d index 5b16f72..ac167f3 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/bug15613.d +++ b/gcc/testsuite/gdc.test/fail_compilation/bug15613.d @@ -1,10 +1,12 @@ /* TEST_OUTPUT: --- -fail_compilation/bug15613.d(16): Error: function `bug15613.f(int...)` is not callable using argument types `(typeof(null))` -fail_compilation/bug15613.d(16): cannot pass argument `null` of type `typeof(null)` to parameter `int...` -fail_compilation/bug15613.d(17): Error: function `bug15613.g(Object, ...)` is not callable using argument types `(int)` -fail_compilation/bug15613.d(17): cannot pass argument `8` of type `int` to parameter `Object` +fail_compilation/bug15613.d(18): Error: function `f` is not callable using argument types `(typeof(null))` +fail_compilation/bug15613.d(18): cannot pass argument `null` of type `typeof(null)` to parameter `int...` +fail_compilation/bug15613.d(13): `bug15613.f(int...)` declared here +fail_compilation/bug15613.d(19): Error: function `g` is not callable using argument types `(int)` +fail_compilation/bug15613.d(19): cannot pass argument `8` of type `int` to parameter `Object` +fail_compilation/bug15613.d(14): `bug15613.g(Object, ...)` declared here --- */ @@ -20,8 +22,9 @@ void main() /* TEST_OUTPUT: --- -fail_compilation/bug15613.d(32): Error: function `bug15613.h(int[]...)` is not callable using argument types `(int, void function(int[]...))` -fail_compilation/bug15613.d(32): cannot pass argument `& h` of type `void function(int[]...)` to parameter `int[]...` +fail_compilation/bug15613.d(35): Error: function `h` is not callable using argument types `(int, void function(int[]...))` +fail_compilation/bug15613.d(35): cannot pass argument `& h` of type `void function(int[]...)` to parameter `int[]...` +fail_compilation/bug15613.d(31): `bug15613.h(int[]...)` declared here --- */ diff --git a/gcc/testsuite/gdc.test/fail_compilation/bug16165.d b/gcc/testsuite/gdc.test/fail_compilation/bug16165.d index ca98797..608e347 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/bug16165.d +++ b/gcc/testsuite/gdc.test/fail_compilation/bug16165.d @@ -10,9 +10,11 @@ void g() /* TEST_OUTPUT: --- -fail_compilation/bug16165.d(6): Error: function `bug16165.f(int x, Object y)` is not callable using argument types `(Object, Object, int)` +fail_compilation/bug16165.d(6): Error: function `f` is not callable using argument types `(Object, Object, int)` fail_compilation/bug16165.d(6): cannot pass argument `o` of type `object.Object` to parameter `int x` -fail_compilation/bug16165.d(7): Error: function `bug16165.f(int x, Object y)` is not callable using argument types `(int, int, int)` +fail_compilation/bug16165.d(1): `bug16165.f(int x, Object y)` declared here +fail_compilation/bug16165.d(7): Error: function `f` is not callable using argument types `(int, int, int)` fail_compilation/bug16165.d(7): cannot pass argument `6` of type `int` to parameter `Object y` +fail_compilation/bug16165.d(1): `bug16165.f(int x, Object y)` declared here --- */ diff --git a/gcc/testsuite/gdc.test/fail_compilation/bug9631.d b/gcc/testsuite/gdc.test/fail_compilation/bug9631.d index f0a9456..13974aa 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/bug9631.d +++ b/gcc/testsuite/gdc.test/fail_compilation/bug9631.d @@ -62,12 +62,13 @@ void test3() /* TEST_OUTPUT: --- -fail_compilation/bug9631.d(79): Error: function `bug9631.arg.f(int i, S s)` is not callable using argument types `(int, S)` -fail_compilation/bug9631.d(79): cannot pass argument `y` of type `bug9631.tem!().S` to parameter `bug9631.S s` -fail_compilation/bug9631.d(80): Error: function literal `__lambda4(S s)` is not callable using argument types `(S)` -fail_compilation/bug9631.d(80): cannot pass argument `x` of type `bug9631.S` to parameter `bug9631.tem!().S s` -fail_compilation/bug9631.d(86): Error: constructor `bug9631.arg.A.this(S __param_0)` is not callable using argument types `(S)` -fail_compilation/bug9631.d(86): cannot pass argument `S(0)` of type `bug9631.tem!().S` to parameter `bug9631.S __param_0` +fail_compilation/bug9631.d(80): Error: function `f` is not callable using argument types `(int, S)` +fail_compilation/bug9631.d(80): cannot pass argument `y` of type `bug9631.tem!().S` to parameter `bug9631.S s` +fail_compilation/bug9631.d(79): `bug9631.arg.f(int i, S s)` declared here +fail_compilation/bug9631.d(81): Error: function literal `__lambda4(S s)` is not callable using argument types `(S)` +fail_compilation/bug9631.d(81): cannot pass argument `x` of type `bug9631.S` to parameter `bug9631.tem!().S s` +fail_compilation/bug9631.d(87): Error: constructor `bug9631.arg.A.this(S __param_0)` is not callable using argument types `(S)` +fail_compilation/bug9631.d(87): cannot pass argument `S(0)` of type `bug9631.tem!().S` to parameter `bug9631.S __param_0` --- */ void arg() @@ -89,12 +90,13 @@ void arg() /* TEST_OUTPUT: --- -fail_compilation/bug9631.d(106): Error: function `bug9631.targ.ft!().ft(S __param_0)` is not callable using argument types `(S)` -fail_compilation/bug9631.d(106): cannot pass argument `x` of type `bug9631.S` to parameter `bug9631.tem!().S __param_0` -fail_compilation/bug9631.d(107): Error: template `bug9631.targ.ft` is not callable using argument types `!()(S)` -fail_compilation/bug9631.d(105): Candidate is: `ft()(tem!().S)` -fail_compilation/bug9631.d(109): Error: template `bug9631.targ.ft2` is not callable using argument types `!()(S, int)` -fail_compilation/bug9631.d(108): Candidate is: `ft2(T)(S, T)` +fail_compilation/bug9631.d(108): Error: function `ft` is not callable using argument types `(S)` +fail_compilation/bug9631.d(108): cannot pass argument `x` of type `bug9631.S` to parameter `bug9631.tem!().S __param_0` +fail_compilation/bug9631.d(107): `bug9631.targ.ft!().ft(S __param_0)` declared here +fail_compilation/bug9631.d(109): Error: template `ft` is not callable using argument types `!()(S)` +fail_compilation/bug9631.d(107): Candidate is: `ft()(tem!().S)` +fail_compilation/bug9631.d(111): Error: template `ft2` is not callable using argument types `!()(S, int)` +fail_compilation/bug9631.d(110): Candidate is: `ft2(T)(S, T)` --- */ void targ() diff --git a/gcc/testsuite/gdc.test/fail_compilation/callconst.d b/gcc/testsuite/gdc.test/fail_compilation/callconst.d index 74c1902..a3aee7c 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/callconst.d +++ b/gcc/testsuite/gdc.test/fail_compilation/callconst.d @@ -1,8 +1,9 @@ /* TEST_OUTPUT: --- -fail_compilation/callconst.d(13): Error: function `callconst.func(ref X)` is not callable using argument types `(const(X))` -fail_compilation/callconst.d(13): cannot pass argument `x` of type `const(X)` to parameter `ref X` +fail_compilation/callconst.d(14): Error: function `func` is not callable using argument types `(const(X))` +fail_compilation/callconst.d(14): cannot pass argument `x` of type `const(X)` to parameter `ref X` +fail_compilation/callconst.d(17): `callconst.func(ref X)` declared here --- */ struct X {} diff --git a/gcc/testsuite/gdc.test/fail_compilation/constraints_aggr.d b/gcc/testsuite/gdc.test/fail_compilation/constraints_aggr.d index a3ad34a..4c31e9e 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/constraints_aggr.d +++ b/gcc/testsuite/gdc.test/fail_compilation/constraints_aggr.d @@ -2,12 +2,12 @@ EXTRA_FILES: imports/constraints.d TEST_OUTPUT: --- -fail_compilation/constraints_aggr.d(32): Error: template `imports.constraints.C.f` is not callable using argument types `!()(int)` +fail_compilation/constraints_aggr.d(32): Error: template `f` is not callable using argument types `!()(int)` fail_compilation/imports/constraints.d(60): Candidate is: `f(T)(T v)` with `T = int` must satisfy the following constraint: ` !P!T` -fail_compilation/constraints_aggr.d(33): Error: template `imports.constraints.C.g` is not callable using argument types `!()()` +fail_compilation/constraints_aggr.d(33): Error: template `g` is not callable using argument types `!()()` fail_compilation/imports/constraints.d(63): Candidate is: `g(this T)()` with `T = imports.constraints.C` must satisfy the following constraint: diff --git a/gcc/testsuite/gdc.test/fail_compilation/constraints_func1.d b/gcc/testsuite/gdc.test/fail_compilation/constraints_func1.d index fbb4aa9..d15d281 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/constraints_func1.d +++ b/gcc/testsuite/gdc.test/fail_compilation/constraints_func1.d @@ -2,72 +2,72 @@ EXTRA_FILES: imports/constraints.d TEST_OUTPUT: --- -fail_compilation/constraints_func1.d(79): Error: template `imports.constraints.test1` is not callable using argument types `!()(int)` +fail_compilation/constraints_func1.d(79): Error: template `test1` is not callable using argument types `!()(int)` fail_compilation/imports/constraints.d(9): Candidate is: `test1(T)(T v)` with `T = int` must satisfy the following constraint: ` N!T` -fail_compilation/constraints_func1.d(80): Error: template `imports.constraints.test2` is not callable using argument types `!()(int)` +fail_compilation/constraints_func1.d(80): Error: template `test2` is not callable using argument types `!()(int)` fail_compilation/imports/constraints.d(10): Candidate is: `test2(T)(T v)` with `T = int` must satisfy the following constraint: ` !P!T` -fail_compilation/constraints_func1.d(81): Error: template `imports.constraints.test3` is not callable using argument types `!()(int)` +fail_compilation/constraints_func1.d(81): Error: template `test3` is not callable using argument types `!()(int)` fail_compilation/imports/constraints.d(11): Candidate is: `test3(T)(T v)` with `T = int` must satisfy the following constraint: ` N!T` -fail_compilation/constraints_func1.d(82): Error: template `imports.constraints.test4` is not callable using argument types `!()(int)` +fail_compilation/constraints_func1.d(82): Error: template `test4` is not callable using argument types `!()(int)` fail_compilation/imports/constraints.d(12): Candidate is: `test4(T)(T v)` with `T = int` must satisfy the following constraint: ` N!T` -fail_compilation/constraints_func1.d(83): Error: template `imports.constraints.test5` is not callable using argument types `!()(int)` +fail_compilation/constraints_func1.d(83): Error: template `test5` is not callable using argument types `!()(int)` fail_compilation/imports/constraints.d(13): Candidate is: `test5(T)(T v)` with `T = int` must satisfy one of the following constraints: ` N!T N!T` -fail_compilation/constraints_func1.d(84): Error: template `imports.constraints.test6` is not callable using argument types `!()(int)` +fail_compilation/constraints_func1.d(84): Error: template `test6` is not callable using argument types `!()(int)` fail_compilation/imports/constraints.d(14): Candidate is: `test6(T)(T v)` with `T = int` must satisfy one of the following constraints: ` N!T N!T !P!T` -fail_compilation/constraints_func1.d(85): Error: template `imports.constraints.test7` is not callable using argument types `!()(int)` +fail_compilation/constraints_func1.d(85): Error: template `test7` is not callable using argument types `!()(int)` fail_compilation/imports/constraints.d(15): Candidate is: `test7(T)(T v)` with `T = int` must satisfy one of the following constraints: ` N!T N!T` -fail_compilation/constraints_func1.d(86): Error: template `imports.constraints.test8` is not callable using argument types `!()(int)` +fail_compilation/constraints_func1.d(86): Error: template `test8` is not callable using argument types `!()(int)` fail_compilation/imports/constraints.d(16): Candidate is: `test8(T)(T v)` with `T = int` must satisfy the following constraint: ` N!T` -fail_compilation/constraints_func1.d(87): Error: template `imports.constraints.test9` is not callable using argument types `!()(int)` +fail_compilation/constraints_func1.d(87): Error: template `test9` is not callable using argument types `!()(int)` fail_compilation/imports/constraints.d(17): Candidate is: `test9(T)(T v)` with `T = int` must satisfy the following constraint: ` !P!T` -fail_compilation/constraints_func1.d(88): Error: template `imports.constraints.test10` is not callable using argument types `!()(int)` +fail_compilation/constraints_func1.d(88): Error: template `test10` is not callable using argument types `!()(int)` fail_compilation/imports/constraints.d(18): Candidate is: `test10(T)(T v)` with `T = int` must satisfy the following constraint: ` !P!T` -fail_compilation/constraints_func1.d(89): Error: template `imports.constraints.test11` is not callable using argument types `!()(int)` +fail_compilation/constraints_func1.d(89): Error: template `test11` is not callable using argument types `!()(int)` fail_compilation/imports/constraints.d(19): Candidate is: `test11(T)(T v)` with `T = int` must satisfy one of the following constraints: ` N!T !P!T` -fail_compilation/constraints_func1.d(90): Error: template `imports.constraints.test12` is not callable using argument types `!()(int)` +fail_compilation/constraints_func1.d(90): Error: template `test12` is not callable using argument types `!()(int)` fail_compilation/imports/constraints.d(20): Candidate is: `test12(T)(T v)` with `T = int` must satisfy the following constraint: ` !P!T` -fail_compilation/constraints_func1.d(92): Error: template `imports.constraints.test1` is not callable using argument types `!()(int, int)` +fail_compilation/constraints_func1.d(92): Error: template `test1` is not callable using argument types `!()(int, int)` fail_compilation/imports/constraints.d(9): Candidate is: `test1(T)(T v)` --- */ diff --git a/gcc/testsuite/gdc.test/fail_compilation/constraints_func2.d b/gcc/testsuite/gdc.test/fail_compilation/constraints_func2.d index 4b8ebd5..36fa554 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/constraints_func2.d +++ b/gcc/testsuite/gdc.test/fail_compilation/constraints_func2.d @@ -2,83 +2,83 @@ EXTRA_FILES: imports/constraints.d TEST_OUTPUT: --- -fail_compilation/constraints_func2.d(94): Error: template `imports.constraints.test13` is not callable using argument types `!()(int)` +fail_compilation/constraints_func2.d(94): Error: template `test13` is not callable using argument types `!()(int)` fail_compilation/imports/constraints.d(23): Candidate is: `test13(T)(T v)` with `T = int` must satisfy one of the following constraints: ` N!T !P!T` -fail_compilation/constraints_func2.d(95): Error: template `imports.constraints.test14` is not callable using argument types `!()(int)` +fail_compilation/constraints_func2.d(95): Error: template `test14` is not callable using argument types `!()(int)` fail_compilation/imports/constraints.d(24): Candidate is: `test14(T)(T v)` with `T = int` must satisfy one of the following constraints: ` !P!T N!T` -fail_compilation/constraints_func2.d(96): Error: template `imports.constraints.test15` is not callable using argument types `!()(int)` +fail_compilation/constraints_func2.d(96): Error: template `test15` is not callable using argument types `!()(int)` fail_compilation/imports/constraints.d(25): Candidate is: `test15(T)(T v)` with `T = int` must satisfy one of the following constraints: ` !P!T !P!T` -fail_compilation/constraints_func2.d(97): Error: template `imports.constraints.test16` is not callable using argument types `!()(int)` +fail_compilation/constraints_func2.d(97): Error: template `test16` is not callable using argument types `!()(int)` fail_compilation/imports/constraints.d(26): Candidate is: `test16(T)(T v)` with `T = int` must satisfy one of the following constraints: ` N!T N!T` -fail_compilation/constraints_func2.d(98): Error: template `imports.constraints.test17` is not callable using argument types `!()(int)` +fail_compilation/constraints_func2.d(98): Error: template `test17` is not callable using argument types `!()(int)` fail_compilation/imports/constraints.d(27): Candidate is: `test17(T)(T v)` with `T = int` must satisfy the following constraint: ` N!T` -fail_compilation/constraints_func2.d(99): Error: template `imports.constraints.test18` is not callable using argument types `!()(int)` +fail_compilation/constraints_func2.d(99): Error: template `test18` is not callable using argument types `!()(int)` fail_compilation/imports/constraints.d(28): Candidate is: `test18(T)(T v)` with `T = int` must satisfy one of the following constraints: ` N!T N!T` -fail_compilation/constraints_func2.d(100): Error: template `imports.constraints.test19` is not callable using argument types `!()(int)` +fail_compilation/constraints_func2.d(100): Error: template `test19` is not callable using argument types `!()(int)` fail_compilation/imports/constraints.d(29): Candidate is: `test19(T)(T v)` with `T = int` must satisfy one of the following constraints: ` N!T !P!T N!T` -fail_compilation/constraints_func2.d(101): Error: template `imports.constraints.test20` is not callable using argument types `!()(int)` +fail_compilation/constraints_func2.d(101): Error: template `test20` is not callable using argument types `!()(int)` fail_compilation/imports/constraints.d(30): Candidate is: `test20(T)(T v)` with `T = int` must satisfy the following constraint: ` N!T` -fail_compilation/constraints_func2.d(102): Error: template `imports.constraints.test21` is not callable using argument types `!()(int)` +fail_compilation/constraints_func2.d(102): Error: template `test21` is not callable using argument types `!()(int)` fail_compilation/imports/constraints.d(31): Candidate is: `test21(T)(T v)` with `T = int` must satisfy one of the following constraints: ` N!T N!T` -fail_compilation/constraints_func2.d(103): Error: template `imports.constraints.test22` is not callable using argument types `!()(int)` +fail_compilation/constraints_func2.d(103): Error: template `test22` is not callable using argument types `!()(int)` fail_compilation/imports/constraints.d(32): Candidate is: `test22(T)(T v)` with `T = int` must satisfy one of the following constraints: ` !P!T !P!T` -fail_compilation/constraints_func2.d(104): Error: template `imports.constraints.test23` is not callable using argument types `!()(int)` +fail_compilation/constraints_func2.d(104): Error: template `test23` is not callable using argument types `!()(int)` fail_compilation/imports/constraints.d(33): Candidate is: `test23(T)(T v)` with `T = int` must satisfy one of the following constraints: ` !P!T N!T !P!T` -fail_compilation/constraints_func2.d(105): Error: template `imports.constraints.test24` is not callable using argument types `!()(int)` +fail_compilation/constraints_func2.d(105): Error: template `test24` is not callable using argument types `!()(int)` fail_compilation/imports/constraints.d(34): Candidate is: `test24(R)(R r)` with `R = int` must satisfy the following constraint: ` __traits(hasMember, R, "stuff")` -fail_compilation/constraints_func2.d(106): Error: template `imports.constraints.test25` is not callable using argument types `!()(int)` +fail_compilation/constraints_func2.d(106): Error: template `test25` is not callable using argument types `!()(int)` fail_compilation/imports/constraints.d(35): Candidate is: `test25(T)(T v)` with `T = int` must satisfy the following constraint: ` N!T` -fail_compilation/constraints_func2.d(107): Error: template `imports.constraints.test26` is not callable using argument types `!(float)(int)` +fail_compilation/constraints_func2.d(107): Error: template `test26` is not callable using argument types `!(float)(int)` fail_compilation/imports/constraints.d(36): Candidate is: `test26(T, U)(U u)` with `T = float, U = int` diff --git a/gcc/testsuite/gdc.test/fail_compilation/constraints_func3.d b/gcc/testsuite/gdc.test/fail_compilation/constraints_func3.d index d16bdf0..b4bc3fe 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/constraints_func3.d +++ b/gcc/testsuite/gdc.test/fail_compilation/constraints_func3.d @@ -1,7 +1,7 @@ /* EXTRA_FILES: imports/constraints.d TEST_OUTPUT: ---- +---- fail_compilation/constraints_func3.d(53): Error: none of the overloads of template `imports.constraints.overload` are callable using argument types `!()(int)` fail_compilation/imports/constraints.d(39): Candidates are: `overload(T)(T v)` with `T = int` @@ -23,27 +23,27 @@ fail_compilation/imports/constraints.d(42): `overload(T, must satisfy one of the following constraints: ` N!T N!V` -fail_compilation/constraints_func3.d(56): Error: template `imports.constraints.variadic` is not callable using argument types `!()()` +fail_compilation/constraints_func3.d(56): Error: template `variadic` is not callable using argument types `!()()` fail_compilation/imports/constraints.d(43): Candidate is: `variadic(A, T...)(A a, T v)` -fail_compilation/constraints_func3.d(57): Error: template `imports.constraints.variadic` is not callable using argument types `!()(int)` +fail_compilation/constraints_func3.d(57): Error: template `variadic` is not callable using argument types `!()(int)` fail_compilation/imports/constraints.d(43): Candidate is: `variadic(A, T...)(A a, T v)` with `A = int, T = ()` must satisfy the following constraint: ` N!int` -fail_compilation/constraints_func3.d(58): Error: template `imports.constraints.variadic` is not callable using argument types `!()(int, int)` +fail_compilation/constraints_func3.d(58): Error: template `variadic` is not callable using argument types `!()(int, int)` fail_compilation/imports/constraints.d(43): Candidate is: `variadic(A, T...)(A a, T v)` with `A = int, T = (int)` must satisfy the following constraint: ` N!int` -fail_compilation/constraints_func3.d(59): Error: template `imports.constraints.variadic` is not callable using argument types `!()(int, int, int)` +fail_compilation/constraints_func3.d(59): Error: template `variadic` is not callable using argument types `!()(int, int, int)` fail_compilation/imports/constraints.d(43): Candidate is: `variadic(A, T...)(A a, T v)` with `A = int, T = (int, int)` must satisfy the following constraint: ` N!int` ---- +---- */ void main() diff --git a/gcc/testsuite/gdc.test/fail_compilation/constraints_func4.d b/gcc/testsuite/gdc.test/fail_compilation/constraints_func4.d index c4dea0e..536a3d4 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/constraints_func4.d +++ b/gcc/testsuite/gdc.test/fail_compilation/constraints_func4.d @@ -2,7 +2,7 @@ EXTRA_FILES: imports/constraints.d REQUIRED_ARGS: -verrors=context TEST_OUTPUT: ---- +---- fail_compilation/constraints_func4.d(90): Error: none of the overloads of template `imports.constraints.overload` are callable using argument types `!()(int)` overload(0); ^ @@ -44,13 +44,13 @@ fail_compilation/imports/constraints.d(42): `overload(T, N!V` void overload(T, V)(T v1, V v2) if (N!T || N!V); ^ -fail_compilation/constraints_func4.d(93): Error: template `imports.constraints.variadic` is not callable using argument types `!()()` +fail_compilation/constraints_func4.d(93): Error: template `variadic` is not callable using argument types `!()()` variadic(); ^ fail_compilation/imports/constraints.d(43): Candidate is: `variadic(A, T...)(A a, T v)` void variadic(A, T...)(A a, T v) if (N!int); ^ -fail_compilation/constraints_func4.d(94): Error: template `imports.constraints.variadic` is not callable using argument types `!()(int)` +fail_compilation/constraints_func4.d(94): Error: template `variadic` is not callable using argument types `!()(int)` variadic(0); ^ fail_compilation/imports/constraints.d(43): Candidate is: `variadic(A, T...)(A a, T v)` @@ -60,7 +60,7 @@ fail_compilation/imports/constraints.d(43): Candidate is: `variadic(A, T. ` N!int` void variadic(A, T...)(A a, T v) if (N!int); ^ -fail_compilation/constraints_func4.d(95): Error: template `imports.constraints.variadic` is not callable using argument types `!()(int, int)` +fail_compilation/constraints_func4.d(95): Error: template `variadic` is not callable using argument types `!()(int, int)` variadic(0, 1); ^ fail_compilation/imports/constraints.d(43): Candidate is: `variadic(A, T...)(A a, T v)` @@ -70,7 +70,7 @@ fail_compilation/imports/constraints.d(43): Candidate is: `variadic(A, T. ` N!int` void variadic(A, T...)(A a, T v) if (N!int); ^ -fail_compilation/constraints_func4.d(96): Error: template `imports.constraints.variadic` is not callable using argument types `!()(int, int, int)` +fail_compilation/constraints_func4.d(96): Error: template `variadic` is not callable using argument types `!()(int, int, int)` variadic(0, 1, 2); ^ fail_compilation/imports/constraints.d(43): Candidate is: `variadic(A, T...)(A a, T v)` @@ -80,7 +80,7 @@ fail_compilation/imports/constraints.d(43): Candidate is: `variadic(A, T. ` N!int` void variadic(A, T...)(A a, T v) if (N!int); ^ ---- +---- */ void main() diff --git a/gcc/testsuite/gdc.test/fail_compilation/diag13942.d b/gcc/testsuite/gdc.test/fail_compilation/diag13942.d index 25e0515..9248e09 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/diag13942.d +++ b/gcc/testsuite/gdc.test/fail_compilation/diag13942.d @@ -2,7 +2,7 @@ TEST_OUTPUT: --- fail_compilation/diag13942.d(18): Error: template instance `isRawStaticArray!()` does not match template declaration `isRawStaticArray(T, A...)` -fail_compilation/diag13942.d(26): Error: template `diag13942.to!double.to` is not callable using argument types `!()()` +fail_compilation/diag13942.d(26): Error: template `to` is not callable using argument types `!()()` fail_compilation/diag13942.d(17): Candidate is: `to(A...)(A args)` --- */ diff --git a/gcc/testsuite/gdc.test/fail_compilation/diag16977.d b/gcc/testsuite/gdc.test/fail_compilation/diag16977.d index fc8f660..7e2efd2 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/diag16977.d +++ b/gcc/testsuite/gdc.test/fail_compilation/diag16977.d @@ -3,7 +3,7 @@ TEST_OUTPUT: --- fail_compilation/diag16977.d(25): Error: undefined identifier `undefined`, did you mean function `undefinedId`? fail_compilation/diag16977.d(26): Error: cannot implicitly convert expression `"\x01string"` of type `string` to `int` -fail_compilation/diag16977.d(27): Error: template `diag16977.templ` is not callable using argument types `!()(int)` +fail_compilation/diag16977.d(27): Error: template `templ` is not callable using argument types `!()(int)` fail_compilation/diag16977.d(20): Candidate is: `templ(S)(S s)` with `S = int` must satisfy the following constraint: diff --git a/gcc/testsuite/gdc.test/fail_compilation/diag20268.d b/gcc/testsuite/gdc.test/fail_compilation/diag20268.d index 053626a..0653490 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/diag20268.d +++ b/gcc/testsuite/gdc.test/fail_compilation/diag20268.d @@ -3,7 +3,7 @@ /* TEST_OUTPUT: --- -fail_compilation/diag20268.d(12): Error: template `diag20268.__lambda4` is not callable using argument types `!()(int)` +fail_compilation/diag20268.d(12): Error: template `__lambda4` is not callable using argument types `!()(int)` fail_compilation/diag20268.d(11): Candidate is: `__lambda4(__T1, __T2)(x, y)` --- */ diff --git a/gcc/testsuite/gdc.test/fail_compilation/diag23355.d b/gcc/testsuite/gdc.test/fail_compilation/diag23355.d index a530eb6..c21226f 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/diag23355.d +++ b/gcc/testsuite/gdc.test/fail_compilation/diag23355.d @@ -2,10 +2,10 @@ TEST_OUTPUT: --- fail_compilation/diag23355.d(1): Error: undefined identifier `n` -fail_compilation/diag23355.d(4): Error: template `diag23355.ffi1` is not callable using argument types `!()(int[4])` +fail_compilation/diag23355.d(4): Error: template `ffi1` is not callable using argument types `!()(int[4])` fail_compilation/diag23355.d(1): Candidate is: `ffi1(T)(T[n] s)` fail_compilation/diag23355.d(2): Error: undefined identifier `n` -fail_compilation/diag23355.d(4): Error: template `diag23355.ffi2` is not callable using argument types `!()(int[4])` +fail_compilation/diag23355.d(4): Error: template `ffi2` is not callable using argument types `!()(int[4])` fail_compilation/diag23355.d(2): Candidate is: `ffi2()(T[n] s)` --- */ diff --git a/gcc/testsuite/gdc.test/fail_compilation/diag8101.d b/gcc/testsuite/gdc.test/fail_compilation/diag8101.d index 4c8dfe8..0d19620 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/diag8101.d +++ b/gcc/testsuite/gdc.test/fail_compilation/diag8101.d @@ -1,32 +1,33 @@ /* TEST_OUTPUT: --- -fail_compilation/diag8101.d(61): Error: function `diag8101.f_0(int)` is not callable using argument types `()` -fail_compilation/diag8101.d(61): too few arguments, expected 1, got 0 -fail_compilation/diag8101.d(62): Error: none of the overloads of `f_1` are callable using argument types `()` -fail_compilation/diag8101.d(35): Candidates are: `diag8101.f_1(int)` -fail_compilation/diag8101.d(36): `diag8101.f_1(int, int)` -fail_compilation/diag8101.d(63): Error: none of the overloads of `f_2` are callable using argument types `()` -fail_compilation/diag8101.d(38): Candidates are: `diag8101.f_2(int)` -fail_compilation/diag8101.d(39): `diag8101.f_2(int, int)` -fail_compilation/diag8101.d(40): `diag8101.f_2(int, int, int)` -fail_compilation/diag8101.d(41): `diag8101.f_2(int, int, int, int)` -fail_compilation/diag8101.d(42): `diag8101.f_2(int, int, int, int, int)` -fail_compilation/diag8101.d(43): `diag8101.f_2(int, int, int, int, int, int)` -fail_compilation/diag8101.d(63): ... (1 more, -v to show) ... -fail_compilation/diag8101.d(65): Error: template `diag8101.t_0` is not callable using argument types `!()()` -fail_compilation/diag8101.d(46): Candidate is: `t_0(T1)()` -fail_compilation/diag8101.d(66): Error: none of the overloads of template `diag8101.t_1` are callable using argument types `!()()` -fail_compilation/diag8101.d(48): Candidates are: `t_1(T1)()` -fail_compilation/diag8101.d(49): `t_1(T1, T2)()` -fail_compilation/diag8101.d(67): Error: none of the overloads of template `diag8101.t_2` are callable using argument types `!()()` -fail_compilation/diag8101.d(51): Candidates are: `t_2(T1)()` -fail_compilation/diag8101.d(52): `t_2(T1, T2)()` -fail_compilation/diag8101.d(53): `t_2(T1, T2, T3)()` -fail_compilation/diag8101.d(54): `t_2(T1, T2, T3, T4)()` -fail_compilation/diag8101.d(55): `t_2(T1, T2, T3, T4, T5)()` -fail_compilation/diag8101.d(56): `t_2(T1, T2, T3, T4, T5, T6)()` -fail_compilation/diag8101.d(67): ... (1 more, -v to show) ... +fail_compilation/diag8101.d(62): Error: function `f_0` is not callable using argument types `()` +fail_compilation/diag8101.d(62): too few arguments, expected 1, got 0 +fail_compilation/diag8101.d(34): `diag8101.f_0(int)` declared here +fail_compilation/diag8101.d(63): Error: none of the overloads of `f_1` are callable using argument types `()` +fail_compilation/diag8101.d(36): Candidates are: `diag8101.f_1(int)` +fail_compilation/diag8101.d(37): `diag8101.f_1(int, int)` +fail_compilation/diag8101.d(64): Error: none of the overloads of `f_2` are callable using argument types `()` +fail_compilation/diag8101.d(39): Candidates are: `diag8101.f_2(int)` +fail_compilation/diag8101.d(40): `diag8101.f_2(int, int)` +fail_compilation/diag8101.d(41): `diag8101.f_2(int, int, int)` +fail_compilation/diag8101.d(42): `diag8101.f_2(int, int, int, int)` +fail_compilation/diag8101.d(43): `diag8101.f_2(int, int, int, int, int)` +fail_compilation/diag8101.d(44): `diag8101.f_2(int, int, int, int, int, int)` +fail_compilation/diag8101.d(64): ... (1 more, -v to show) ... +fail_compilation/diag8101.d(66): Error: template `t_0` is not callable using argument types `!()()` +fail_compilation/diag8101.d(47): Candidate is: `t_0(T1)()` +fail_compilation/diag8101.d(67): Error: none of the overloads of template `diag8101.t_1` are callable using argument types `!()()` +fail_compilation/diag8101.d(49): Candidates are: `t_1(T1)()` +fail_compilation/diag8101.d(50): `t_1(T1, T2)()` +fail_compilation/diag8101.d(68): Error: none of the overloads of template `diag8101.t_2` are callable using argument types `!()()` +fail_compilation/diag8101.d(52): Candidates are: `t_2(T1)()` +fail_compilation/diag8101.d(53): `t_2(T1, T2)()` +fail_compilation/diag8101.d(54): `t_2(T1, T2, T3)()` +fail_compilation/diag8101.d(55): `t_2(T1, T2, T3, T4)()` +fail_compilation/diag8101.d(56): `t_2(T1, T2, T3, T4, T5)()` +fail_compilation/diag8101.d(57): `t_2(T1, T2, T3, T4, T5, T6)()` +fail_compilation/diag8101.d(68): ... (1 more, -v to show) ... --- */ diff --git a/gcc/testsuite/gdc.test/fail_compilation/diag8648.d b/gcc/testsuite/gdc.test/fail_compilation/diag8648.d index e48f569..8066d6e 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/diag8648.d +++ b/gcc/testsuite/gdc.test/fail_compilation/diag8648.d @@ -2,13 +2,13 @@ TEST_OUTPUT: --- fail_compilation/diag8648.d(18): Error: undefined identifier `X` -fail_compilation/diag8648.d(29): Error: template `diag8648.foo` is not callable using argument types `!()(Foo!(int, 1))` +fail_compilation/diag8648.d(29): Error: template `foo` is not callable using argument types `!()(Foo!(int, 1))` fail_compilation/diag8648.d(18): Candidate is: `foo(T, n)(X!(T, n))` fail_compilation/diag8648.d(20): Error: undefined identifier `a` -fail_compilation/diag8648.d(31): Error: template `diag8648.bar` is not callable using argument types `!()(Foo!(int, 1))` +fail_compilation/diag8648.d(31): Error: template `bar` is not callable using argument types `!()(Foo!(int, 1))` fail_compilation/diag8648.d(20): Candidate is: `bar(T)(Foo!(T, a))` fail_compilation/diag8648.d(20): Error: undefined identifier `a` -fail_compilation/diag8648.d(32): Error: template `diag8648.bar` is not callable using argument types `!()(Foo!(int, f))` +fail_compilation/diag8648.d(32): Error: template `bar` is not callable using argument types `!()(Foo!(int, f))` fail_compilation/diag8648.d(20): Candidate is: `bar(T)(Foo!(T, a))` --- */ diff --git a/gcc/testsuite/gdc.test/fail_compilation/diag9004.d b/gcc/testsuite/gdc.test/fail_compilation/diag9004.d index 30589bf..4c63bb2 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/diag9004.d +++ b/gcc/testsuite/gdc.test/fail_compilation/diag9004.d @@ -1,7 +1,7 @@ /* TEST_OUTPUT: --- -fail_compilation/diag9004.d(21): Error: template `diag9004.bar` is not callable using argument types `!()(Foo!int, int)` +fail_compilation/diag9004.d(21): Error: template `bar` is not callable using argument types `!()(Foo!int, int)` fail_compilation/diag9004.d(14): Candidate is: `bar(FooT)(FooT foo, FooT.T x)` --- */ diff --git a/gcc/testsuite/gdc.test/fail_compilation/diagin.d b/gcc/testsuite/gdc.test/fail_compilation/diagin.d index 5b8e331..6e8a472 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/diagin.d +++ b/gcc/testsuite/gdc.test/fail_compilation/diagin.d @@ -2,10 +2,11 @@ REQUIRED_ARGS: -preview=in TEST_OUTPUT: --- -fail_compilation/diagin.d(14): Error: function `diagin.foo(in int)` is not callable using argument types `()` -fail_compilation/diagin.d(14): too few arguments, expected 1, got 0 -fail_compilation/diagin.d(16): Error: template `diagin.foo1` is not callable using argument types `!()(bool[])` -fail_compilation/diagin.d(20): Candidate is: `foo1(T)(in T v, string)` +fail_compilation/diagin.d(15): Error: function `foo` is not callable using argument types `()` +fail_compilation/diagin.d(15): too few arguments, expected 1, got 0 +fail_compilation/diagin.d(20): `diagin.foo(in int)` declared here +fail_compilation/diagin.d(17): Error: template `foo1` is not callable using argument types `!()(bool[])` +fail_compilation/diagin.d(21): Candidate is: `foo1(T)(in T v, string)` --- */ diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail12744.d b/gcc/testsuite/gdc.test/fail_compilation/fail12744.d index 711e57f..3b1ab72 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/fail12744.d +++ b/gcc/testsuite/gdc.test/fail_compilation/fail12744.d @@ -14,10 +14,10 @@ fail_compilation/fail12744.d(61): Error: template instance `fail12744.bar12744L! fail_compilation/fail12744.d(40): Error: incompatible parameter storage classes `lazy` and `out` fail_compilation/fail12744.d(62): Error: template instance `fail12744.bar12744L!(foo12744O)` error instantiating fail_compilation/fail12744.d(41): Error: incompatible parameter storage classes `auto ref` and `out` -fail_compilation/fail12744.d(67): Error: template `fail12744.bar12744A` is not callable using argument types `!(foo12744O)(int)` +fail_compilation/fail12744.d(67): Error: template `bar12744A` is not callable using argument types `!(foo12744O)(int)` fail_compilation/fail12744.d(41): Candidate is: `bar12744A(alias f)(auto ref PTT12744!f args)` fail_compilation/fail12744.d(41): Error: incompatible parameter storage classes `auto ref` and `lazy` -fail_compilation/fail12744.d(68): Error: template `fail12744.bar12744A` is not callable using argument types `!(foo12744L)(int)` +fail_compilation/fail12744.d(68): Error: template `bar12744A` is not callable using argument types `!(foo12744L)(int)` fail_compilation/fail12744.d(41): Candidate is: `bar12744A(alias f)(auto ref PTT12744!f args)` --- */ diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail136.d b/gcc/testsuite/gdc.test/fail_compilation/fail136.d index 3bc8653..3fa42e6 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/fail136.d +++ b/gcc/testsuite/gdc.test/fail_compilation/fail136.d @@ -1,7 +1,7 @@ /* TEST_OUTPUT: --- -fail_compilation\fail136.d(10): Error: `"\xef\xbb\xbf"` has no effect +fail_compilation/fail136.d(10): Error: `x"EFBBBF"` has no effect --- */ diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail14669.d b/gcc/testsuite/gdc.test/fail_compilation/fail14669.d index 45fe146..2c2661f 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/fail14669.d +++ b/gcc/testsuite/gdc.test/fail_compilation/fail14669.d @@ -4,7 +4,7 @@ TEST_OUTPUT: fail_compilation/fail14669.d(11): Error: `auto` can only be used as part of `auto ref` for template function parameters fail_compilation/fail14669.d(16): Error: template instance `fail14669.foo1!()` error instantiating fail_compilation/fail14669.d(12): Error: `auto` can only be used as part of `auto ref` for template function parameters -fail_compilation/fail14669.d(17): Error: template `fail14669.foo2` is not callable using argument types `!()(int)` +fail_compilation/fail14669.d(17): Error: template `foo2` is not callable using argument types `!()(int)` fail_compilation/fail14669.d(12): Candidate is: `foo2()(auto int a)` --- */ diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail162.d b/gcc/testsuite/gdc.test/fail_compilation/fail162.d index c79f8d8..600e2c9 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/fail162.d +++ b/gcc/testsuite/gdc.test/fail_compilation/fail162.d @@ -1,7 +1,7 @@ /* TEST_OUTPUT: --- -fail_compilation/fail162.d(25): Error: template `fail162.testHelper` is not callable using argument types `!()(string, string)` +fail_compilation/fail162.d(25): Error: template `testHelper` is not callable using argument types `!()(string, string)` fail_compilation/fail162.d(10): Candidate is: `testHelper(A...)()` fail_compilation/fail162.d(30): Error: template instance `fail162.test!("hello", "world")` error instantiating --- diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail19948.d b/gcc/testsuite/gdc.test/fail_compilation/fail19948.d index ae67443..9c23b78 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/fail19948.d +++ b/gcc/testsuite/gdc.test/fail_compilation/fail19948.d @@ -3,8 +3,9 @@ /* TEST_OUTPUT: --- -fail_compilation/fail19948.d(15): Error: function `fail19948.func(const(X))` is not callable using argument types `(X)` -fail_compilation/fail19948.d(15): cannot pass argument `X()` of type `fail19948.main.X` to parameter `const(fail19948.X)` +fail_compilation/fail19948.d(16): Error: function `func` is not callable using argument types `(X)` +fail_compilation/fail19948.d(16): cannot pass argument `X()` of type `fail19948.main.X` to parameter `const(fail19948.X)` +fail_compilation/fail19948.d(19): `fail19948.func(const(X))` declared here --- */ // DISABLED: win32 diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail20183.d b/gcc/testsuite/gdc.test/fail_compilation/fail20183.d index 8a08844..f04db02 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/fail20183.d +++ b/gcc/testsuite/gdc.test/fail_compilation/fail20183.d @@ -1,8 +1,9 @@ /* REQUIRED_ARGS: -preview=dip1000 TEST_OUTPUT: --- -fail_compilation/fail20183.d(1016): Error: function `fail20183.addr(return ref int b)` is not callable using argument types `(int)` +fail_compilation/fail20183.d(1016): Error: function `addr` is not callable using argument types `(int)` fail_compilation/fail20183.d(1016): cannot pass rvalue argument `S(0).i` of type `int` to parameter `return ref int b` +fail_compilation/fail20183.d(1005): `fail20183.addr(return ref int b)` declared here fail_compilation/fail20183.d(1017): Error: address of struct temporary returned by `s()` assigned to longer lived variable `q` --- */ diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail20730b.d b/gcc/testsuite/gdc.test/fail_compilation/fail20730b.d index d36bb0b..7269f42 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/fail20730b.d +++ b/gcc/testsuite/gdc.test/fail_compilation/fail20730b.d @@ -3,7 +3,7 @@ REQUIRED_ARGS: -verrors=spec -o- TEST_OUTPUT: --- (spec:1) fail_compilation/fail20730b.d-mixin-43(43): Error: C style cast illegal, use `cast(int)mod` -fail_compilation/fail20730b.d(26): Error: template `fail20730b.atomicOp` is not callable using argument types `!("+=")(shared(uint), int)` +fail_compilation/fail20730b.d(26): Error: template `atomicOp` is not callable using argument types `!("+=")(shared(uint), int)` fail_compilation/fail20730b.d(41): Candidate is: `atomicOp(string op, T, V1)(shared ref T val, V1 mod)` with `op = "+=", T = uint, diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail20800.d b/gcc/testsuite/gdc.test/fail_compilation/fail20800.d index 026b7c2..4464222 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/fail20800.d +++ b/gcc/testsuite/gdc.test/fail_compilation/fail20800.d @@ -2,10 +2,11 @@ /* TEST_OUTPUT: ---- -fail_compilation/fail20800.d(22): Error: function `fail20800.fun(int a)` is not callable using argument types `(string)` -fail_compilation/fail20800.d(22): cannot pass argument `(m()).index()` of type `string` to parameter `int a` ---- +---- +fail_compilation/fail20800.d(23): Error: function `fun` is not callable using argument types `(string)` +fail_compilation/fail20800.d(23): cannot pass argument `(m()).index()` of type `string` to parameter `int a` +fail_compilation/fail20800.d(19): `fail20800.fun(int a)` declared here +---- */ struct RegexMatch diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail22202.d b/gcc/testsuite/gdc.test/fail_compilation/fail22202.d index d865fd9..9fb5165 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/fail22202.d +++ b/gcc/testsuite/gdc.test/fail_compilation/fail22202.d @@ -3,8 +3,9 @@ /* TEST_OUTPUT: --- -fail_compilation/fail22202.d(21): Error: function `fail22202.fun(SystemCopy __param_0)` is not callable using argument types `(SystemCopy)` -fail_compilation/fail22202.d(21): `inout ref inout(SystemCopy)(ref inout(SystemCopy) other)` copy constructor cannot be called from a `pure @safe nogc` context +fail_compilation/fail22202.d(22): Error: function `fun` is not callable using argument types `(SystemCopy)` +fail_compilation/fail22202.d(22): `inout ref inout(SystemCopy)(ref inout(SystemCopy) other)` copy constructor cannot be called from a `pure @safe nogc` context +fail_compilation/fail22202.d(17): `fail22202.fun(SystemCopy __param_0)` declared here --- */ diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail236.d b/gcc/testsuite/gdc.test/fail_compilation/fail236.d index accc0e1..96f0ae6 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/fail236.d +++ b/gcc/testsuite/gdc.test/fail_compilation/fail236.d @@ -2,7 +2,7 @@ TEST_OUTPUT: --- fail_compilation/fail236.d(14): Error: undefined identifier `x` -fail_compilation/fail236.d(22): Error: template `fail236.Templ2` is not callable using argument types `!()(int)` +fail_compilation/fail236.d(22): Error: template `Templ2` is not callable using argument types `!()(int)` fail_compilation/fail236.d(12): Candidate is: `Templ2(alias a)(x)` --- */ diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail24301.d b/gcc/testsuite/gdc.test/fail_compilation/fail24301.d index be09c88..6ddece6 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/fail24301.d +++ b/gcc/testsuite/gdc.test/fail_compilation/fail24301.d @@ -1,8 +1,9 @@ /+ TEST_OUTPUT: --- -fail_compilation/fail24301.d(18): Error: function `fail24301.fun(S __param_0)` is not callable using argument types `(S)` -fail_compilation/fail24301.d(18): `ref S(ref S)` copy constructor cannot be used because it is annotated with `@disable` +fail_compilation/fail24301.d(19): Error: function `fun` is not callable using argument types `(S)` +fail_compilation/fail24301.d(19): `ref S(ref S)` copy constructor cannot be used because it is annotated with `@disable` +fail_compilation/fail24301.d(14): `fail24301.fun(S __param_0)` declared here --- +/ struct S diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail263.d b/gcc/testsuite/gdc.test/fail_compilation/fail263.d index 0fa2f86..e57fc50 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/fail263.d +++ b/gcc/testsuite/gdc.test/fail_compilation/fail263.d @@ -1,9 +1,10 @@ /* TEST_OUTPUT: ---- -fail_compilation/fail263.d(19): Error: function `fail263.f(byte* p)` is not callable using argument types `(const(byte)*)` -fail_compilation/fail263.d(19): cannot pass argument `cast(const(byte)*)A` of type `const(byte)*` to parameter `byte* p` ---- +---- +fail_compilation/fail263.d(20): Error: function `f` is not callable using argument types `(const(byte)*)` +fail_compilation/fail263.d(20): cannot pass argument `cast(const(byte)*)A` of type `const(byte)*` to parameter `byte* p` +fail_compilation/fail263.d(14): `fail263.f(byte* p)` declared here +---- */ // https://issues.dlang.org/show_bug.cgi?id=2766 diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail322.d b/gcc/testsuite/gdc.test/fail_compilation/fail322.d index 491111f..faaab68 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/fail322.d +++ b/gcc/testsuite/gdc.test/fail_compilation/fail322.d @@ -1,11 +1,13 @@ /* TEST_OUTPUT: ---- -fail_compilation/fail322.d(13): Error: function `fail322.digestToString2(ref char[16] digest)` is not callable using argument types `(string)` -fail_compilation/fail322.d(13): cannot pass rvalue argument `"1234567890123456"` of type `string` to parameter `ref char[16] digest` -fail_compilation/fail322.d(15): Error: function `fail322.digestToString2(ref char[16] digest)` is not callable using argument types `(const(char[16]))` -fail_compilation/fail322.d(15): cannot pass argument `s` of type `const(char[16])` to parameter `ref char[16] digest` ---- +---- +fail_compilation/fail322.d(15): Error: function `digestToString2` is not callable using argument types `(string)` +fail_compilation/fail322.d(15): cannot pass rvalue argument `"1234567890123456"` of type `string` to parameter `ref char[16] digest` +fail_compilation/fail322.d(20): `fail322.digestToString2(ref char[16] digest)` declared here +fail_compilation/fail322.d(17): Error: function `digestToString2` is not callable using argument types `(const(char[16]))` +fail_compilation/fail322.d(17): cannot pass argument `s` of type `const(char[16])` to parameter `ref char[16] digest` +fail_compilation/fail322.d(20): `fail322.digestToString2(ref char[16] digest)` declared here +---- */ void main() diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail332.d b/gcc/testsuite/gdc.test/fail_compilation/fail332.d index 77e8cd8..de20333 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/fail332.d +++ b/gcc/testsuite/gdc.test/fail_compilation/fail332.d @@ -1,14 +1,18 @@ /* TEST_OUTPUT: --- -fail_compilation/fail332.d(22): Error: function `fail332.foo(int __param_0, ...)` is not callable using argument types `()` -fail_compilation/fail332.d(22): missing argument for parameter #1: `int __param_0` -fail_compilation/fail332.d(23): Error: function `fail332.foo(int __param_0, ...)` is not callable using argument types `(typeof(null))` -fail_compilation/fail332.d(23): cannot pass argument `null` of type `typeof(null)` to parameter `int __param_0` -fail_compilation/fail332.d(25): Error: function `fail332.baz(int[] __param_0...)` is not callable using argument types `(string)` -fail_compilation/fail332.d(25): cannot pass argument `""` of type `string` to parameter `int[] __param_0...` -fail_compilation/fail332.d(26): Error: function `fail332.baz(int[] __param_0...)` is not callable using argument types `(int, typeof(null))` -fail_compilation/fail332.d(26): cannot pass argument `null` of type `typeof(null)` to parameter `int[] __param_0...` +fail_compilation/fail332.d(26): Error: function `foo` is not callable using argument types `()` +fail_compilation/fail332.d(26): missing argument for parameter #1: `int __param_0` +fail_compilation/fail332.d(21): `fail332.foo(int __param_0, ...)` declared here +fail_compilation/fail332.d(27): Error: function `foo` is not callable using argument types `(typeof(null))` +fail_compilation/fail332.d(27): cannot pass argument `null` of type `typeof(null)` to parameter `int __param_0` +fail_compilation/fail332.d(21): `fail332.foo(int __param_0, ...)` declared here +fail_compilation/fail332.d(29): Error: function `baz` is not callable using argument types `(string)` +fail_compilation/fail332.d(29): cannot pass argument `""` of type `string` to parameter `int[] __param_0...` +fail_compilation/fail332.d(22): `fail332.baz(int[] __param_0...)` declared here +fail_compilation/fail332.d(30): Error: function `baz` is not callable using argument types `(int, typeof(null))` +fail_compilation/fail332.d(30): cannot pass argument `null` of type `typeof(null)` to parameter `int[] __param_0...` +fail_compilation/fail332.d(22): `fail332.baz(int[] __param_0...)` declared here --- */ @@ -29,18 +33,24 @@ void test() /* TEST_OUTPUT: --- -fail_compilation/fail332.d(50): Error: function `fail332.bar(Object, int[2]...)` is not callable using argument types `()` -fail_compilation/fail332.d(50): missing argument for parameter #1: `Object` -fail_compilation/fail332.d(51): Error: function `fail332.bar(Object, int[2]...)` is not callable using argument types `(int)` -fail_compilation/fail332.d(51): cannot pass argument `4` of type `int` to parameter `Object` -fail_compilation/fail332.d(52): Error: function `fail332.bar(Object, int[2]...)` is not callable using argument types `(typeof(null))` -fail_compilation/fail332.d(52): expected 2 variadic argument(s), not 0 -fail_compilation/fail332.d(53): Error: function `fail332.bar(Object, int[2]...)` is not callable using argument types `(typeof(null), int)` -fail_compilation/fail332.d(53): expected 2 variadic argument(s), not 1 -fail_compilation/fail332.d(54): Error: function `fail332.bar(Object, int[2]...)` is not callable using argument types `(typeof(null), int, string)` -fail_compilation/fail332.d(54): cannot pass argument `""` of type `string` to parameter `int[2]...` -fail_compilation/fail332.d(55): Error: function `fail332.bar(Object, int[2]...)` is not callable using argument types `(typeof(null), int, int, int)` -fail_compilation/fail332.d(55): expected 2 variadic argument(s), not 3 +fail_compilation/fail332.d(60): Error: function `bar` is not callable using argument types `()` +fail_compilation/fail332.d(60): missing argument for parameter #1: `Object` +fail_compilation/fail332.d(56): `fail332.bar(Object, int[2]...)` declared here +fail_compilation/fail332.d(61): Error: function `bar` is not callable using argument types `(int)` +fail_compilation/fail332.d(61): cannot pass argument `4` of type `int` to parameter `Object` +fail_compilation/fail332.d(56): `fail332.bar(Object, int[2]...)` declared here +fail_compilation/fail332.d(62): Error: function `bar` is not callable using argument types `(typeof(null))` +fail_compilation/fail332.d(62): expected 2 variadic argument(s), not 0 +fail_compilation/fail332.d(56): `fail332.bar(Object, int[2]...)` declared here +fail_compilation/fail332.d(63): Error: function `bar` is not callable using argument types `(typeof(null), int)` +fail_compilation/fail332.d(63): expected 2 variadic argument(s), not 1 +fail_compilation/fail332.d(56): `fail332.bar(Object, int[2]...)` declared here +fail_compilation/fail332.d(64): Error: function `bar` is not callable using argument types `(typeof(null), int, string)` +fail_compilation/fail332.d(64): cannot pass argument `""` of type `string` to parameter `int[2]...` +fail_compilation/fail332.d(56): `fail332.bar(Object, int[2]...)` declared here +fail_compilation/fail332.d(65): Error: function `bar` is not callable using argument types `(typeof(null), int, int, int)` +fail_compilation/fail332.d(65): expected 2 variadic argument(s), not 3 +fail_compilation/fail332.d(56): `fail332.bar(Object, int[2]...)` declared here --- */ void bar(Object, int[2]...); diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail58.d b/gcc/testsuite/gdc.test/fail_compilation/fail58.d index 89b2351..ae70da2 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/fail58.d +++ b/gcc/testsuite/gdc.test/fail_compilation/fail58.d @@ -1,11 +1,13 @@ /* TEST_OUTPUT: ---- -fail_compilation/fail58.d(26): Error: function `fail58.SomeFunc(dchar[] pText, out int pStopPosn)` is not callable using argument types `(string, int)` -fail_compilation/fail58.d(26): cannot pass argument `"123"` of type `string` to parameter `dchar[] pText` -fail_compilation/fail58.d(30): Error: function `fail58.SomeFunc(dchar[] pText, out int pStopPosn)` is not callable using argument types `(string, int)` -fail_compilation/fail58.d(30): cannot pass argument `""` of type `string` to parameter `dchar[] pText` ---- +---- +fail_compilation/fail58.d(28): Error: function `SomeFunc` is not callable using argument types `(string, int)` +fail_compilation/fail58.d(28): cannot pass argument `"123"` of type `string` to parameter `dchar[] pText` +fail_compilation/fail58.d(14): `fail58.SomeFunc(dchar[] pText, out int pStopPosn)` declared here +fail_compilation/fail58.d(32): Error: function `SomeFunc` is not callable using argument types `(string, int)` +fail_compilation/fail58.d(32): cannot pass argument `""` of type `string` to parameter `dchar[] pText` +fail_compilation/fail58.d(14): `fail58.SomeFunc(dchar[] pText, out int pStopPosn)` declared here +---- */ debug import std.stdio; const int anything = -1000; // Line #2 diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail8009.d b/gcc/testsuite/gdc.test/fail_compilation/fail8009.d index a4844bf..f2abfcc 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/fail8009.d +++ b/gcc/testsuite/gdc.test/fail_compilation/fail8009.d @@ -1,7 +1,7 @@ /* TEST_OUTPUT: --- -fail_compilation/fail8009.d(9): Error: template `fail8009.filter` is not callable using argument types `!()(void)` +fail_compilation/fail8009.d(9): Error: template `filter` is not callable using argument types `!()(void)` fail_compilation/fail8009.d(8): Candidate is: `filter(R)(scope bool delegate(ref BAD!R) func)` --- */ diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail95.d b/gcc/testsuite/gdc.test/fail_compilation/fail95.d index 7065bc1..0e61336 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/fail95.d +++ b/gcc/testsuite/gdc.test/fail_compilation/fail95.d @@ -1,7 +1,7 @@ /* TEST_OUTPUT: --- -fail_compilation/fail95.d(19): Error: template `fail95.A` is not callable using argument types `!()(int)` +fail_compilation/fail95.d(19): Error: template `A` is not callable using argument types `!()(int)` fail_compilation/fail95.d(11): Candidate is: `A(alias T)(T)` --- */ diff --git a/gcc/testsuite/gdc.test/fail_compilation/hexstring.d b/gcc/testsuite/gdc.test/fail_compilation/hexstring.d index de83db9..caca3b3 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/hexstring.d +++ b/gcc/testsuite/gdc.test/fail_compilation/hexstring.d @@ -1,18 +1,39 @@ -/** -TEST_OUTPUT: ---- -fail_compilation\hexstring.d(16): Error: cannot implicitly convert expression `"123F"` of type `string` to `immutable(ubyte[])` -fail_compilation\hexstring.d(17): Error: cannot implicitly convert expression `"\x12?"c` of type `string` to `immutable(ubyte[])` -fail_compilation\hexstring.d(18): Error: cannot implicitly convert expression `"\x12?"` of type `string` to `immutable(ubyte[])` -fail_compilation\hexstring.d(15): Error: cannot implicitly convert expression `"\x12?"` of type `string` to `ubyte[]` ---- -*/ -immutable ubyte[] s0 = x"123F"; -static assert(s0[0] == 0x12); -static assert(s0[1] == 0x3F); -immutable byte[] s1 = x"123F"; - -ubyte[] f1 = x"123F"; -immutable ubyte[] f2 = "123F"; -immutable ubyte[] f3 = x"123F"c; -immutable ubyte[] f4 = cast(string) x"123F"; +/** +TEST_OUTPUT: +--- +fail_compilation/hexstring.d(29): Error: cannot implicitly convert expression `"123F"` of type `string` to `immutable(ubyte[])` +fail_compilation/hexstring.d(30): Error: cannot implicitly convert expression `x"123F"c` of type `string` to `immutable(ubyte[])` +fail_compilation/hexstring.d(31): Error: cannot implicitly convert expression `x"123F"` of type `string` to `immutable(ubyte[])` +fail_compilation/hexstring.d(33): Error: hex string length 1 must be a multiple of 2 to cast to `immutable(ushort[])` +fail_compilation/hexstring.d(34): Error: hex string length 3 must be a multiple of 4 to cast to `immutable(uint[])` +fail_compilation/hexstring.d(35): Error: hex string length 5 must be a multiple of 8 to cast to `immutable(ulong[])` +fail_compilation/hexstring.d(36): Error: array cast from `wstring` to `immutable(ulong[])` is not supported at compile time +fail_compilation/hexstring.d(36): perhaps remove postfix `w` from hex string +fail_compilation/hexstring.d(37): Error: array cast from `string` to `immutable(uint[])` is not supported at compile time +fail_compilation/hexstring.d(38): Error: array cast from `string` to `immutable(ushort[])` is not supported at compile time +fail_compilation/hexstring.d(39): Error: array cast from `string` to `immutable(uint[])` is not supported at compile time +fail_compilation/hexstring.d(39): perhaps remove postfix `c` from hex string +fail_compilation/hexstring.d(28): Error: cannot implicitly convert expression `x"123F"` of type `string` to `ubyte[]` +--- +*/ + +immutable ubyte[] s0 = x"123F"; +static assert(s0[0] == 0x12); +static assert(s0[1] == 0x3F); +immutable byte[] s1 = x"123F"; + +enum E(X) = cast(X[]) x"AABBCCDD"; +static assert(E!int[0] == 0xAABBCCDD); + +ubyte[] f1 = x"123F"; +immutable ubyte[] f2 = "123F"; +immutable ubyte[] f3 = x"123F"c; +immutable ubyte[] f4 = cast(string) x"123F"; + +immutable ushort[] f5 = cast(immutable ushort[]) x"11"; +immutable uint[] f6 = cast(immutable uint[]) x"112233"; +immutable ulong[] f7 = cast(immutable ulong[]) x"1122334455"; +immutable ulong[] f8 = cast(immutable ulong[]) x"1122334455"w; +immutable uint[] f9 = cast(immutable uint[]) "ABCD"; +immutable ushort[] f10 = cast(immutable ushort[]) (x"1122" ~ ""); +immutable uint[] f11 = cast(immutable uint[]) x"AABBCCDD"c; diff --git a/gcc/testsuite/gdc.test/fail_compilation/ice10922.d b/gcc/testsuite/gdc.test/fail_compilation/ice10922.d index e76d4ac..552a982 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/ice10922.d +++ b/gcc/testsuite/gdc.test/fail_compilation/ice10922.d @@ -1,8 +1,9 @@ /* TEST_OUTPUT: --- -fail_compilation/ice10922.d(10): Error: function `ice10922.__lambda4(in uint n)` is not callable using argument types `()` -fail_compilation/ice10922.d(10): too few arguments, expected 1, got 0 +fail_compilation/ice10922.d(11): Error: function `__lambda4` is not callable using argument types `()` +fail_compilation/ice10922.d(11): too few arguments, expected 1, got 0 +fail_compilation/ice10922.d(10): `ice10922.__lambda4(in uint n)` declared here --- */ diff --git a/gcc/testsuite/gdc.test/fail_compilation/ice11856_1.d b/gcc/testsuite/gdc.test/fail_compilation/ice11856_1.d index 448e629..476c655 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/ice11856_1.d +++ b/gcc/testsuite/gdc.test/fail_compilation/ice11856_1.d @@ -1,14 +1,14 @@ /* TEST_OUTPUT: ---- +---- fail_compilation/ice11856_1.d(18): Error: no property `g` for `A()` of type `A` fail_compilation/ice11856_1.d(18): the following error occured while looking for a UFCS match -fail_compilation/ice11856_1.d(18): Error: template `ice11856_1.g` is not callable using argument types `!()(A)` +fail_compilation/ice11856_1.d(18): Error: template `g` is not callable using argument types `!()(A)` fail_compilation/ice11856_1.d(16): Candidate is: `g(T)(T x)` with `T = A` must satisfy the following constraint: ` is(typeof(x.f()))` ---- +---- */ struct A {} diff --git a/gcc/testsuite/gdc.test/fail_compilation/ice12501.d b/gcc/testsuite/gdc.test/fail_compilation/ice12501.d index 2c45c8a..c1b1e38 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/ice12501.d +++ b/gcc/testsuite/gdc.test/fail_compilation/ice12501.d @@ -1,12 +1,14 @@ /* TEST_OUTPUT: ---- -fail_compilation/ice12501.d(31): Error: function `ice12501.foo(int value)` is not callable using argument types `(int, int)` -fail_compilation/ice12501.d(31): expected 1 argument(s), not 2 -fail_compilation/ice12501.d(31): Error: function `ice12501.foo(int value)` is not callable using argument types `(int, int)` -fail_compilation/ice12501.d(31): expected 1 argument(s), not 2 -fail_compilation/ice12501.d(45): Error: template instance `ice12501.reduce!(foo, foo).reduce!(Tuple!(int, int), int[])` error instantiating ---- +---- +fail_compilation/ice12501.d(33): Error: function `foo` is not callable using argument types `(int, int)` +fail_compilation/ice12501.d(33): expected 1 argument(s), not 2 +fail_compilation/ice12501.d(40): `ice12501.foo(int value)` declared here +fail_compilation/ice12501.d(33): Error: function `foo` is not callable using argument types `(int, int)` +fail_compilation/ice12501.d(33): expected 1 argument(s), not 2 +fail_compilation/ice12501.d(40): `ice12501.foo(int value)` declared here +fail_compilation/ice12501.d(47): Error: template instance `ice12501.reduce!(foo, foo).reduce!(Tuple!(int, int), int[])` error instantiating +---- */ struct Tuple(T...) diff --git a/gcc/testsuite/gdc.test/fail_compilation/ice14130.d b/gcc/testsuite/gdc.test/fail_compilation/ice14130.d index 151bf17..4b12f8b 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/ice14130.d +++ b/gcc/testsuite/gdc.test/fail_compilation/ice14130.d @@ -2,7 +2,7 @@ TEST_OUTPUT: --- fail_compilation/ice14130.d(10): Error: undefined identifier `Undef` -fail_compilation/ice14130.d(14): Error: template `ice14130.foo` is not callable using argument types `!()(int)` +fail_compilation/ice14130.d(14): Error: template `foo` is not callable using argument types `!()(int)` fail_compilation/ice14130.d(10): Candidate is: `foo(R, F = Undef)(R r, F s = 0)` --- */ diff --git a/gcc/testsuite/gdc.test/fail_compilation/ice14907.d b/gcc/testsuite/gdc.test/fail_compilation/ice14907.d index 5d676cd..eeca1b3 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/ice14907.d +++ b/gcc/testsuite/gdc.test/fail_compilation/ice14907.d @@ -1,14 +1,14 @@ /* TEST_OUTPUT: ---- +---- fail_compilation/ice14907.d(14): Error: struct `ice14907.S(int v = S)` recursive template expansion fail_compilation/ice14907.d(19): while looking for match for `S!()` fail_compilation/ice14907.d(15): Error: template `ice14907.f(int v = f)()` recursive template expansion fail_compilation/ice14907.d(20): while looking for match for `f!()` fail_compilation/ice14907.d(15): Error: template `ice14907.f(int v = f)()` recursive template expansion -fail_compilation/ice14907.d(21): Error: template `ice14907.f` is not callable using argument types `!()()` +fail_compilation/ice14907.d(21): Error: template `f` is not callable using argument types `!()()` fail_compilation/ice14907.d(15): Candidate is: `f(int v = f)()` ---- +---- */ struct S(int v = S) {} diff --git a/gcc/testsuite/gdc.test/fail_compilation/ice14923.d b/gcc/testsuite/gdc.test/fail_compilation/ice14923.d index e3b677e..99d2eee 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/ice14923.d +++ b/gcc/testsuite/gdc.test/fail_compilation/ice14923.d @@ -1,10 +1,11 @@ /* TEST_OUTPUT: ---- -fail_compilation/ice14923.d(22): Error: function `ice14923.parse(C a)` is not callable using argument types `(A)` -fail_compilation/ice14923.d(22): cannot pass argument `b` of type `ice14923.A` to parameter `C a` -fail_compilation/ice14923.d(22): instantiated from here: `bar!((b) => parse(b))` ---- +---- +fail_compilation/ice14923.d(23): Error: function `parse` is not callable using argument types `(A)` +fail_compilation/ice14923.d(23): cannot pass argument `b` of type `ice14923.A` to parameter `C a` +fail_compilation/ice14923.d(21): `ice14923.parse(C a)` declared here +fail_compilation/ice14923.d(23): instantiated from here: `bar!((b) => parse(b))` +---- */ auto bar(alias fun)() diff --git a/gcc/testsuite/gdc.test/fail_compilation/ice23097.d b/gcc/testsuite/gdc.test/fail_compilation/ice23097.d index 90cf03f..5cde816 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/ice23097.d +++ b/gcc/testsuite/gdc.test/fail_compilation/ice23097.d @@ -1,10 +1,11 @@ /* https://issues.dlang.org/show_bug.cgi?id=23097 TEST_OUTPUT: --- -fail_compilation/ice23097.d(12): Error: undefined identifier `ICE` -fail_compilation/ice23097.d(27): Error: template instance `ice23097.ice23097!(S23097)` error instantiating -fail_compilation/ice23097.d(27): Error: function `ice23097.ice23097!(S23097).ice23097(S23097 __param_0)` is not callable using argument types `(S23097)` -fail_compilation/ice23097.d(27): generating a copy constructor for `struct S23097` failed, therefore instances of it are uncopyable +fail_compilation/ice23097.d(13): Error: undefined identifier `ICE` +fail_compilation/ice23097.d(28): Error: template instance `ice23097.ice23097!(S23097)` error instantiating +fail_compilation/ice23097.d(28): Error: function `ice23097` is not callable using argument types `(S23097)` +fail_compilation/ice23097.d(28): generating a copy constructor for `struct S23097` failed, therefore instances of it are uncopyable +fail_compilation/ice23097.d(11): `ice23097.ice23097!(S23097).ice23097(S23097 __param_0)` declared here --- */ auto ice23097(I)(I) diff --git a/gcc/testsuite/gdc.test/fail_compilation/ice6538.d b/gcc/testsuite/gdc.test/fail_compilation/ice6538.d index 9355a0f..de9fe29 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/ice6538.d +++ b/gcc/testsuite/gdc.test/fail_compilation/ice6538.d @@ -7,7 +7,7 @@ TEST_OUTPUT: --- fail_compilation/ice6538.d(23): Error: template instance `Sym!(super)` expression `super` is not a valid template value argument -fail_compilation/ice6538.d(28): Error: template `ice6538.D.foo` is not callable using argument types `!()()` +fail_compilation/ice6538.d(28): Error: template `foo` is not callable using argument types `!()()` fail_compilation/ice6538.d(23): Candidate is: `foo()()` --- */ diff --git a/gcc/testsuite/gdc.test/fail_compilation/ice9284.d b/gcc/testsuite/gdc.test/fail_compilation/ice9284.d index c9ab014..1e87f0a 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/ice9284.d +++ b/gcc/testsuite/gdc.test/fail_compilation/ice9284.d @@ -1,7 +1,7 @@ /* TEST_OUTPUT: --- -fail_compilation/ice9284.d(14): Error: template `ice9284.C.__ctor` is not callable using argument types `!()(int)` +fail_compilation/ice9284.d(14): Error: template `__ctor` is not callable using argument types `!()(int)` fail_compilation/ice9284.d(12): Candidate is: `this()(string)` fail_compilation/ice9284.d(20): Error: template instance `ice9284.C.__ctor!()` error instantiating --- diff --git a/gcc/testsuite/gdc.test/fail_compilation/ice9540.d b/gcc/testsuite/gdc.test/fail_compilation/ice9540.d index 456d3e12..662038c 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/ice9540.d +++ b/gcc/testsuite/gdc.test/fail_compilation/ice9540.d @@ -1,10 +1,11 @@ /* TEST_OUTPUT: ---- -fail_compilation/ice9540.d(35): Error: function `ice9540.A.test.AddFront!(this, f).AddFront.dg(int __param_0)` is not callable using argument types `()` -fail_compilation/ice9540.d(35): too few arguments, expected 1, got 0 -fail_compilation/ice9540.d(26): Error: template instance `ice9540.A.test.AddFront!(this, f)` error instantiating ---- +---- +fail_compilation/ice9540.d(36): Error: function `dg` is not callable using argument types `()` +fail_compilation/ice9540.d(36): too few arguments, expected 1, got 0 +fail_compilation/ice9540.d(33): `ice9540.A.test.AddFront!(this, f).AddFront.dg(int __param_0)` declared here +fail_compilation/ice9540.d(27): Error: template instance `ice9540.A.test.AddFront!(this, f)` error instantiating +---- */ template Tuple(E...) { alias E Tuple; } diff --git a/gcc/testsuite/gdc.test/fail_compilation/iconv_interface_array.d b/gcc/testsuite/gdc.test/fail_compilation/iconv_interface_array.d new file mode 100644 index 0000000..53c1450 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/iconv_interface_array.d @@ -0,0 +1,51 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/iconv_interface_array.d(48): Error: function `testA` is not callable using argument types `(C[4])` +fail_compilation/iconv_interface_array.d(48): cannot pass argument `arr` of type `C[4]` to parameter `I1[4] arr` +fail_compilation/iconv_interface_array.d(27): `iconv_interface_array.testA(I1[4] arr)` declared here +fail_compilation/iconv_interface_array.d(49): Error: function `testB` is not callable using argument types `(C[4])` +fail_compilation/iconv_interface_array.d(49): cannot pass argument `arr` of type `C[4]` to parameter `I2[4] arr` +fail_compilation/iconv_interface_array.d(33): `iconv_interface_array.testB(I2[4] arr)` declared here +fail_compilation/iconv_interface_array.d(50): Error: function `testC` is not callable using argument types `(C[4])` +fail_compilation/iconv_interface_array.d(50): cannot pass argument `arr` of type `C[4]` to parameter `I3[4] arr` +fail_compilation/iconv_interface_array.d(39): `iconv_interface_array.testC(I3[4] arr)` declared here +--- +*/ + +interface I1 { int a(int); } +interface I2 { int b(int); } +interface I3 { int c(int); } + +class C : I1, I2, I3 +{ + int a(int i) { return 1 * i; } + int b(int i) { return 2 * i; } + int c(int i) { return 3 * i; } +} + +void testA(I1[4] arr) +{ + foreach (uint idx, obj; arr) + assert(obj.a(idx) == 1 * idx); +} + +void testB(I2[4] arr) +{ + foreach (idx, obj; arr) + assert(obj.b(cast(int) idx) == 2 * idx); +} + +void testC(I3[4] arr) +{ + foreach (idx, obj; arr) + assert(obj.c(cast(int) idx) == 3 * idx); +} + +void main() +{ + C[4] arr = [ new C, new C, new C, new C ]; + testA(arr); + testB(arr); + testC(arr); +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/interpolatedexpressionsequence_postfix.d b/gcc/testsuite/gdc.test/fail_compilation/interpolatedexpressionsequence_postfix.d new file mode 100644 index 0000000..c915c44 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/interpolatedexpressionsequence_postfix.d @@ -0,0 +1,13 @@ +/* TEST_OUTPUT: +--- +fail_compilation/interpolatedexpressionsequence_postfix.d(10): Error: String postfixes on interpolated expression sequences are not allowed. +fail_compilation/interpolatedexpressionsequence_postfix.d(11): Error: String postfixes on interpolated expression sequences are not allowed. +fail_compilation/interpolatedexpressionsequence_postfix.d(12): Error: String postfixes on interpolated expression sequences are not allowed. +--- +*/ +void main() { + // all postfixes are banned + auto c = i"foo"c; + auto w = i"foo"w; + auto d = i"foo"d; +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/named_arguments_error.d b/gcc/testsuite/gdc.test/fail_compilation/named_arguments_error.d index 5129f30..b634a11 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/named_arguments_error.d +++ b/gcc/testsuite/gdc.test/fail_compilation/named_arguments_error.d @@ -1,22 +1,27 @@ /* TEST_OUTPUT: --- -fail_compilation/named_arguments_error.d(32): Error: function `named_arguments_error.f(int x, int y, int z)` is not callable using argument types `(int, int, int)` -fail_compilation/named_arguments_error.d(32): parameter `x` assigned twice -fail_compilation/named_arguments_error.d(33): Error: function `named_arguments_error.f(int x, int y, int z)` is not callable using argument types `(int, int, int)` -fail_compilation/named_arguments_error.d(33): argument `4` goes past end of parameter list -fail_compilation/named_arguments_error.d(34): Error: function `named_arguments_error.f(int x, int y, int z)` is not callable using argument types `(int, int, int)` -fail_compilation/named_arguments_error.d(34): parameter `y` assigned twice -fail_compilation/named_arguments_error.d(35): Error: function `named_arguments_error.f(int x, int y, int z)` is not callable using argument types `(int, int, int)` -fail_compilation/named_arguments_error.d(35): no parameter named `a` -fail_compilation/named_arguments_error.d(36): Error: function `named_arguments_error.g(int x, int y, int z = 3)` is not callable using argument types `(int, int)` -fail_compilation/named_arguments_error.d(36): missing argument for parameter #1: `int x` -fail_compilation/named_arguments_error.d(38): Error: no named argument `element` allowed for array dimension -fail_compilation/named_arguments_error.d(39): Error: no named argument `number` allowed for scalar -fail_compilation/named_arguments_error.d(40): Error: cannot implicitly convert expression `g(x: 3, y: 4, z: 5)` of type `int` to `string` -fail_compilation/named_arguments_error.d(41): Error: named arguments with Implicit Function Template Instantiation are not supported yet -fail_compilation/named_arguments_error.d(41): Error: template `named_arguments_error.tempfun` is not callable using argument types `!()(string, int)` -fail_compilation/named_arguments_error.d(45): Candidate is: `tempfun(T, U)(T t, U u)` +fail_compilation/named_arguments_error.d(37): Error: function `f` is not callable using argument types `(int, int, int)` +fail_compilation/named_arguments_error.d(37): parameter `x` assigned twice +fail_compilation/named_arguments_error.d(31): `named_arguments_error.f(int x, int y, int z)` declared here +fail_compilation/named_arguments_error.d(38): Error: function `f` is not callable using argument types `(int, int, int)` +fail_compilation/named_arguments_error.d(38): argument `4` goes past end of parameter list +fail_compilation/named_arguments_error.d(31): `named_arguments_error.f(int x, int y, int z)` declared here +fail_compilation/named_arguments_error.d(39): Error: function `f` is not callable using argument types `(int, int, int)` +fail_compilation/named_arguments_error.d(39): parameter `y` assigned twice +fail_compilation/named_arguments_error.d(31): `named_arguments_error.f(int x, int y, int z)` declared here +fail_compilation/named_arguments_error.d(40): Error: function `f` is not callable using argument types `(int, int, int)` +fail_compilation/named_arguments_error.d(40): no parameter named `a` +fail_compilation/named_arguments_error.d(31): `named_arguments_error.f(int x, int y, int z)` declared here +fail_compilation/named_arguments_error.d(41): Error: function `g` is not callable using argument types `(int, int)` +fail_compilation/named_arguments_error.d(41): missing argument for parameter #1: `int x` +fail_compilation/named_arguments_error.d(33): `named_arguments_error.g(int x, int y, int z = 3)` declared here +fail_compilation/named_arguments_error.d(43): Error: no named argument `element` allowed for array dimension +fail_compilation/named_arguments_error.d(44): Error: no named argument `number` allowed for scalar +fail_compilation/named_arguments_error.d(45): Error: cannot implicitly convert expression `g(x: 3, y: 4, z: 5)` of type `int` to `string` +fail_compilation/named_arguments_error.d(46): Error: named arguments with Implicit Function Template Instantiation are not supported yet +fail_compilation/named_arguments_error.d(46): Error: template `tempfun` is not callable using argument types `!()(string, int)` +fail_compilation/named_arguments_error.d(50): Candidate is: `tempfun(T, U)(T t, U u)` --- */ diff --git a/gcc/testsuite/gdc.test/fail_compilation/previewin.d b/gcc/testsuite/gdc.test/fail_compilation/previewin.d index d0e97c8..486dcd5 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/previewin.d +++ b/gcc/testsuite/gdc.test/fail_compilation/previewin.d @@ -1,20 +1,23 @@ /* REQUIRED_ARGS: -preview=in -preview=dip1000 TEST_OUTPUT: ---- -fail_compilation/previewin.d(4): Error: function `previewin.takeFunction(void function(in real) f)` is not callable using argument types `(void function(real x) pure nothrow @nogc @safe)` +---- +fail_compilation/previewin.d(4): Error: function `takeFunction` is not callable using argument types `(void function(real x) pure nothrow @nogc @safe)` fail_compilation/previewin.d(4): cannot pass argument `__lambda1` of type `void function(real x) pure nothrow @nogc @safe` to parameter `void function(in real) f` -fail_compilation/previewin.d(5): Error: function `previewin.takeFunction(void function(in real) f)` is not callable using argument types `(void function(scope const(real) x) pure nothrow @nogc @safe)` +fail_compilation/previewin.d(11): `previewin.takeFunction(void function(in real) f)` declared here +fail_compilation/previewin.d(5): Error: function `takeFunction` is not callable using argument types `(void function(scope const(real) x) pure nothrow @nogc @safe)` fail_compilation/previewin.d(5): cannot pass argument `__lambda2` of type `void function(scope const(real) x) pure nothrow @nogc @safe` to parameter `void function(in real) f` -fail_compilation/previewin.d(6): Error: function `previewin.takeFunction(void function(in real) f)` is not callable using argument types `(void function(ref scope const(real) x) pure nothrow @nogc @safe)` +fail_compilation/previewin.d(11): `previewin.takeFunction(void function(in real) f)` declared here +fail_compilation/previewin.d(6): Error: function `takeFunction` is not callable using argument types `(void function(ref scope const(real) x) pure nothrow @nogc @safe)` fail_compilation/previewin.d(6): cannot pass argument `__lambda3` of type `void function(ref scope const(real) x) pure nothrow @nogc @safe` to parameter `void function(in real) f` +fail_compilation/previewin.d(11): `previewin.takeFunction(void function(in real) f)` declared here fail_compilation/previewin.d(15): Error: scope variable `arg` assigned to global variable `myGlobal` fail_compilation/previewin.d(16): Error: scope variable `arg` assigned to global variable `myGlobal` fail_compilation/previewin.d(17): Error: scope parameter `arg` may not be returned fail_compilation/previewin.d(18): Error: scope variable `arg` assigned to `ref` variable `escape` with longer lifetime fail_compilation/previewin.d(22): Error: returning `arg` escapes a reference to parameter `arg` fail_compilation/previewin.d(22): perhaps annotate the parameter with `return` ---- +---- */ #line 1 diff --git a/gcc/testsuite/gdc.test/fail_compilation/pull12941.d b/gcc/testsuite/gdc.test/fail_compilation/pull12941.d index fce4ab7..ca78050 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/pull12941.d +++ b/gcc/testsuite/gdc.test/fail_compilation/pull12941.d @@ -4,10 +4,12 @@ fail_compilation/pull12941.d(110): Error: `pull12941.foo` called with argument t fail_compilation/pull12941.d(101): `pull12941.foo(return ref scope int* p)` and: fail_compilation/pull12941.d(102): `pull12941.foo(return out scope int* p)` -fail_compilation/pull12941.d(111): Error: function `pull12941.bar(return scope int* p)` is not callable using argument types `(int)` +fail_compilation/pull12941.d(111): Error: function `bar` is not callable using argument types `(int)` fail_compilation/pull12941.d(111): cannot pass argument `1` of type `int` to parameter `return scope int* p` -fail_compilation/pull12941.d(112): Error: function `pull12941.abc(return ref int* p)` is not callable using argument types `(int)` +fail_compilation/pull12941.d(104): `pull12941.bar(return scope int* p)` declared here +fail_compilation/pull12941.d(112): Error: function `abc` is not callable using argument types `(int)` fail_compilation/pull12941.d(112): cannot pass rvalue argument `1` of type `int` to parameter `return ref int* p` +fail_compilation/pull12941.d(105): `pull12941.abc(return ref int* p)` declared here --- */ diff --git a/gcc/testsuite/gdc.test/fail_compilation/test19107.d b/gcc/testsuite/gdc.test/fail_compilation/test19107.d index c802122..9a6e335 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/test19107.d +++ b/gcc/testsuite/gdc.test/fail_compilation/test19107.d @@ -2,7 +2,7 @@ EXTRA_FILES: imports/imp19661.d imports/test19107a.d imports/test19107b.d TEST_OUTPUT: --- -fail_compilation/test19107.d(24): Error: template `test19107.all` is not callable using argument types `!((c) => c)(string[])` +fail_compilation/test19107.d(24): Error: template `all` is not callable using argument types `!((c) => c)(string[])` fail_compilation/test19107.d(18): Candidate is: `all(alias pred, T)(T t)` with `pred = __lambda2, T = string[]` diff --git a/gcc/testsuite/gdc.test/fail_compilation/test19971.d b/gcc/testsuite/gdc.test/fail_compilation/test19971.d index f854362..3d46eeb 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/test19971.d +++ b/gcc/testsuite/gdc.test/fail_compilation/test19971.d @@ -1,9 +1,10 @@ /* TEST_OUTPUT: --- -fail_compilation/test19971.d(15): Error: function `test19971.f(int x)` is not callable using argument types `(string)` -fail_compilation/test19971.d(15): cannot pass argument `"%s"` of type `string` to parameter `int x` -fail_compilation/test19971.d(16): Error: function literal `__lambda1(int x)` is not callable using argument types `(string)` +fail_compilation/test19971.d(16): Error: function `f` is not callable using argument types `(string)` fail_compilation/test19971.d(16): cannot pass argument `"%s"` of type `string` to parameter `int x` +fail_compilation/test19971.d(13): `test19971.f(int x)` declared here +fail_compilation/test19971.d(17): Error: function literal `__lambda1(int x)` is not callable using argument types `(string)` +fail_compilation/test19971.d(17): cannot pass argument `"%s"` of type `string` to parameter `int x` --- */ diff --git a/gcc/testsuite/gdc.test/fail_compilation/test21008.d b/gcc/testsuite/gdc.test/fail_compilation/test21008.d index 9949107..11cfc39 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/test21008.d +++ b/gcc/testsuite/gdc.test/fail_compilation/test21008.d @@ -4,13 +4,16 @@ TEST_OUTPUT: fail_compilation/test21008.d(110): Error: function `test21008.C.after` circular reference to class `C` fail_compilation/test21008.d(117): Error: calling non-static function `toString` requires an instance of type `Object` fail_compilation/test21008.d(117): Error: calling non-static function `toHash` requires an instance of type `Object` -fail_compilation/test21008.d(117): Error: function `object.Object.opCmp(Object o)` is not callable using argument types `()` +fail_compilation/test21008.d(117): Error: function `opCmp` is not callable using argument types `()` fail_compilation/test21008.d(117): too few arguments, expected 1, got 0 -fail_compilation/test21008.d(117): Error: function `object.Object.opEquals(Object o)` is not callable using argument types `()` +$p:druntime/import/object.d$($n$): `object.Object.opCmp(Object o)` declared here +fail_compilation/test21008.d(117): Error: function `opEquals` is not callable using argument types `()` fail_compilation/test21008.d(117): too few arguments, expected 1, got 0 +$p:druntime/import/object.d$($n$): `object.Object.opEquals(Object o)` declared here fail_compilation/test21008.d(117): Error: `Monitor` has no effect -fail_compilation/test21008.d(117): Error: function `object.Object.factory(string classname)` is not callable using argument types `()` +fail_compilation/test21008.d(117): Error: function `factory` is not callable using argument types `()` fail_compilation/test21008.d(117): too few arguments, expected 1, got 0 +$p:druntime/import/object.d$($n$): `object.Object.factory(string classname)` declared here fail_compilation/test21008.d(105): called from here: `handleMiddlewareAnnotation()` --- */ diff --git a/gcc/testsuite/gdc.test/fail_compilation/test21025.d b/gcc/testsuite/gdc.test/fail_compilation/test21025.d index 8564199..6b2496a 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/test21025.d +++ b/gcc/testsuite/gdc.test/fail_compilation/test21025.d @@ -6,7 +6,7 @@ TEST_OUTPUT: --- fail_compilation/test21025.d(15): Error: variable `r` cannot be read at compile time fail_compilation/test21025.d(15): called from here: `binaryFun(r, r)` -fail_compilation/test21025.d(24): Error: template `test21025.uniq` is not callable using argument types `!()(void[])` +fail_compilation/test21025.d(24): Error: template `uniq` is not callable using argument types `!()(void[])` fail_compilation/test21025.d(14): Candidate is: `uniq()(int[] r)` --- */ diff --git a/gcc/testsuite/gdc.test/fail_compilation/test21807.d b/gcc/testsuite/gdc.test/fail_compilation/test21807.d index 9f56bf7..aaa56f9 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/test21807.d +++ b/gcc/testsuite/gdc.test/fail_compilation/test21807.d @@ -27,8 +27,9 @@ class Foo /* TEST_OUTPUT: --- -fail_compilation/test21807.d(117): Error: function `test21807.addr(return ref int b)` is not callable using argument types `(int)` +fail_compilation/test21807.d(117): Error: function `addr` is not callable using argument types `(int)` fail_compilation/test21807.d(117): cannot pass rvalue argument `S(0).i` of type `int` to parameter `return ref int b` +fail_compilation/test21807.d(106): `test21807.addr(return ref int b)` declared here --- */ #line 100 diff --git a/gcc/testsuite/gdc.test/fail_compilation/ufcs.d b/gcc/testsuite/gdc.test/fail_compilation/ufcs.d index 501ef81..3a92a69 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/ufcs.d +++ b/gcc/testsuite/gdc.test/fail_compilation/ufcs.d @@ -1,19 +1,20 @@ /* TEST_OUTPUT: --- -fail_compilation/ufcs.d(25): Error: no property `regularF` for `s` of type `S` -fail_compilation/ufcs.d(25): the following error occured while looking for a UFCS match -fail_compilation/ufcs.d(25): Error: function `ufcs.regularF()` is not callable using argument types `(S)` -fail_compilation/ufcs.d(25): expected 0 argument(s), not 1 -fail_compilation/ufcs.d(26): Error: no property `templateF` for `s` of type `S` +fail_compilation/ufcs.d(26): Error: no property `regularF` for `s` of type `S` fail_compilation/ufcs.d(26): the following error occured while looking for a UFCS match -fail_compilation/ufcs.d(26): Error: template `ufcs.templateF` is not callable using argument types `!()(S)` -fail_compilation/ufcs.d(31): Candidate is: `templateF()()` -fail_compilation/ufcs.d(27): Error: no property `templateO` for `s` of type `S` +fail_compilation/ufcs.d(26): Error: function `regularF` is not callable using argument types `(S)` +fail_compilation/ufcs.d(26): expected 0 argument(s), not 1 +fail_compilation/ufcs.d(31): `ufcs.regularF()` declared here +fail_compilation/ufcs.d(27): Error: no property `templateF` for `s` of type `S` fail_compilation/ufcs.d(27): the following error occured while looking for a UFCS match -fail_compilation/ufcs.d(27): Error: none of the overloads of template `ufcs.templateO` are callable using argument types `!()(S)` -fail_compilation/ufcs.d(33): Candidates are: `templateO()(int x)` -fail_compilation/ufcs.d(34): `templateO()(float y)` +fail_compilation/ufcs.d(27): Error: template `templateF` is not callable using argument types `!()(S)` +fail_compilation/ufcs.d(32): Candidate is: `templateF()()` +fail_compilation/ufcs.d(28): Error: no property `templateO` for `s` of type `S` +fail_compilation/ufcs.d(28): the following error occured while looking for a UFCS match +fail_compilation/ufcs.d(28): Error: none of the overloads of template `ufcs.templateO` are callable using argument types `!()(S)` +fail_compilation/ufcs.d(34): Candidates are: `templateO()(int x)` +fail_compilation/ufcs.d(35): `templateO()(float y)` --- */ diff --git a/gcc/testsuite/gdc.test/fail_compilation/vararg2.d b/gcc/testsuite/gdc.test/fail_compilation/vararg2.d index eb23558..1a2846a 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/vararg2.d +++ b/gcc/testsuite/gdc.test/fail_compilation/vararg2.d @@ -1,10 +1,12 @@ /* TEST_OUTPUT: ---- -fail_compilation/vararg2.d(106): Error: function `vararg2.foo(int x, const return ...)` is not callable using argument types `(double)` +---- +fail_compilation/vararg2.d(106): Error: function `foo` is not callable using argument types `(double)` fail_compilation/vararg2.d(106): cannot pass argument `1.0` of type `double` to parameter `int x` -fail_compilation/vararg2.d(111): Error: function `vararg2.bar(int x, scope shared ...)` is not callable using argument types `(double)` +fail_compilation/vararg2.d(101): `vararg2.foo(int x, const return ...)` declared here +fail_compilation/vararg2.d(111): Error: function `bar` is not callable using argument types `(double)` fail_compilation/vararg2.d(111): cannot pass argument `1.0` of type `double` to parameter `int x` ---- +fail_compilation/vararg2.d(102): `vararg2.bar(int x, scope shared ...)` declared here +---- */ #line 100 diff --git a/gcc/testsuite/gdc.test/runnable/interpolatedexpressionsequence.d b/gcc/testsuite/gdc.test/runnable/interpolatedexpressionsequence.d new file mode 100644 index 0000000..8311507 --- /dev/null +++ b/gcc/testsuite/gdc.test/runnable/interpolatedexpressionsequence.d @@ -0,0 +1,51 @@ +import core.interpolation; + +alias AliasSeq(T...) = T; + +string simpleToString(T...)(T thing) { + string s; + foreach(item; thing) + // all the items provided by core.interpolation have + // toString to return an appropriate value + // + // then this particular example only has embedded strings + // and chars, to we can append them directly + static if(__traits(hasMember, item, "toString")) + s ~= item.toString(); + else + s ~= item; + + return s; +} + +void main() { + int a = 1; + string b = "one"; + // parser won't permit alias = i".." directly; i"..." is meant to + // be used as a function/template parameter at this time. + alias expr = AliasSeq!i"$(a) $(b)"; + // elements from the source code are available at compile time, so + // we static assert those, but the values, of course, are different + static assert(expr[0] == InterpolationHeader()); + static assert(expr[1] == InterpolatedExpression!"a"()); + assert(expr[2] == a); // actual value not available at compile time + static assert(expr[3] == InterpolatedLiteral!" "()); + // the parens around the expression are not included + static assert(expr[4] == InterpolatedExpression!"b"()); + assert(expr[5] == b); // actual value not available at compile time + static assert(expr[6] == InterpolationFooter()); + + // it does currently allow `auto` to be used, it creates a value tuple + // you can embed any D expressions inside the parenthesis, and the + // token is not ended until you get the *outer* ) and ". + auto thing = i"$(b) $("$" ~ ')' ~ `"`)"; + assert(simpleToString(thing) == "one $)\""); + + assert(simpleToString(i"$b") == "$b"); // support for $ident removed by popular demand + + // i`` and iq{} should also work + assert(simpleToString(i` $(b) is $(b)!`) == " one is one!"); + assert(simpleToString(iq{ $(b) is $(b)!}) == " one is one!"); + assert(simpleToString(i`\$('$')`) == "\\$"); // no \ escape there + assert(simpleToString(iq{{$('$')}}) == "{$}"); // {} needs to work +} diff --git a/gcc/testsuite/gdc.test/runnable/literal.d b/gcc/testsuite/gdc.test/runnable/literal.d index 99b1777..6997124 100644 --- a/gcc/testsuite/gdc.test/runnable/literal.d +++ b/gcc/testsuite/gdc.test/runnable/literal.d @@ -241,6 +241,27 @@ void test12950() assert(0b00_00_00_01UL.op12950() == 12951); } +void testHexstring() +{ + static immutable uint[] x = cast(immutable uint[]) x"FFAADDEE"; + static assert(x[0] == 0xFFAADDEE); + assert(x[0] == 0xFFAADDEE); + + static immutable ulong[] y = cast(immutable ulong[]) x"1122334455667788AABBCCDDEEFF0099"; + static assert(y[0] == 0x1122334455667788); + static assert(y[1] == 0xAABBCCDDEEFF0099); + assert(y[0] == 0x1122334455667788); + assert(y[1] == 0xAABBCCDDEEFF0099); + + // Test that mangling of StringExp with size 8 is the same as array literal mangling: + void f(immutable ulong[] a)() {} + static assert(f!y.mangleof == f!([0x1122334455667788, 0xAABBCCDDEEFF0099]).mangleof); + + // Test printing StringExp with size 8 + enum toStr(immutable ulong[] v) = v.stringof; + static assert(toStr!y == `x"88776655443322119900FFEEDDCCBBAA"`); +} + /***************************************************/ int main() @@ -249,6 +270,7 @@ int main() test2(); test13907(); test12950(); + testHexstring(); printf("Success\n"); return 0; -- cgit v1.1 From a4e240643cfa387579d4fa2bf9210a7d20433847 Mon Sep 17 00:00:00 2001 From: Jakub Jelinek Date: Sat, 3 Feb 2024 14:37:19 +0100 Subject: ggc-common: Fix save PCH assertion We are getting a gnuradio PCH ICE /usr/include/pybind11/stl.h:447:1: internal compiler error: in gt_pch_save, at ggc-common.cc:693 0x1304e7d gt_pch_save(_IO_FILE*) ../../gcc/ggc-common.cc:693 0x12a45fb c_common_write_pch() ../../gcc/c-family/c-pch.cc:175 0x18ad711 c_parse_final_cleanups() ../../gcc/cp/decl2.cc:5062 0x213988b c_common_parse_file() ../../gcc/c-family/c-opts.cc:1319 (unfortunately it isn't reproduceable always, but often needs up to 100 attempts, isn't reproduceable in a cross etc.). The bug is in the assertion I've added in gt_pch_save when adding relocation support for the PCH files in case they happen not to be mmapped at the selected address. addr is a relocated address which points to a location in the PCH blob (starting at mmi.preferred_base, with mmi.size bytes) which contains a pointer that needs to be relocated. So the assertion is meant to verify the address is within the PCH blob, obviously it needs to be equal or above mmi.preferred_base, but I got the other comparison wrong and when one is very unlucky and the last sizeof (void *) bytes of the blob happen to be a pointer which needs to be relocated, such as on the s390x host addr 0x8008a04ff8, mmi.preferred_base 0x8000000000 and mmi.size 0x8a05000, addr + sizeof (void *) is equal to mmi.preferred_base + mmi.size and that is still fine, both addresses are end of something. 2024-02-03 Jakub Jelinek * ggc-common.cc (gt_pch_save): Allow addr to be equal to mmi.preferred_base + mmi.size - sizeof (void *). --- gcc/ggc-common.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'gcc') diff --git a/gcc/ggc-common.cc b/gcc/ggc-common.cc index be4909d..caf456f 100644 --- a/gcc/ggc-common.cc +++ b/gcc/ggc-common.cc @@ -692,7 +692,7 @@ gt_pch_save (FILE *f) { gcc_assert ((uintptr_t) addr >= (uintptr_t) mmi.preferred_base && ((uintptr_t) addr + sizeof (void *) - < (uintptr_t) mmi.preferred_base + mmi.size)); + <= (uintptr_t) mmi.preferred_base + mmi.size)); if (addr == last_addr) continue; if (last_addr == NULL) -- cgit v1.1 From 09df058a09f888daad26fa80634068b38b4ad04d Mon Sep 17 00:00:00 2001 From: Jakub Jelinek Date: Sat, 3 Feb 2024 14:38:27 +0100 Subject: wide-int: Fix up wi::bswap_large [PR113722] Since bswap has been converted from a method to a function we miscompile the following testcase. The problem is the assumption that the passed in len argument (number of limbs in the xval array) is the upper bound for the bswap result, which is true only if precision is <= 64. If precision is larger than that, e.g. 128 as in the testcase, if the argument has only one limb (i.e. 0 to ~(unsigned HOST_WIDE_INT) 0), the result can still need 2 limbs for that precision, or generally BLOCKS_NEEDED (precision) limbs, it all depends on how many least significant limbs of the operand are zero. bswap_large as implemented only cleared len limbs of result, then swapped the bytes (invoking UB when oring something in all the limbs above it) and finally passed len to canonize, saying that more limbs aren't needed. The following patch fixes it by renaming len to xlen (so that it is clear it is X's length), using it solely for safe_uhwi argument when we attempt to read from X, and using new len = BLOCKS_NEEDED (precision) instead in the other two spots (i.e. when clearing the val array, turned it also into memset, and in canonize argument). wi::bswap asserts it isn't invoked on widest_int, so we are always invoked on wide_int or similar and those have preallocated result sized for the corresponding precision (i.e. BLOCKS_NEEDED (precision)). 2024-02-03 Jakub Jelinek PR middle-end/113722 * wide-int.cc (wi::bswap_large): Rename third argument from len to xlen and adjust use in safe_uhwi. Add len variable, set it to BLOCKS_NEEDED (precision) and use it for clearing of val and as canonize argument. Clear val using memset instead of a loop. * gcc.dg/pr113722.c: New test. --- gcc/testsuite/gcc.dg/pr113722.c | 22 ++++++++++++++++++++++ gcc/wide-int.cc | 11 +++++------ 2 files changed, 27 insertions(+), 6 deletions(-) create mode 100644 gcc/testsuite/gcc.dg/pr113722.c (limited to 'gcc') diff --git a/gcc/testsuite/gcc.dg/pr113722.c b/gcc/testsuite/gcc.dg/pr113722.c new file mode 100644 index 0000000..74b9e49 --- /dev/null +++ b/gcc/testsuite/gcc.dg/pr113722.c @@ -0,0 +1,22 @@ +/* PR middle-end/113722 */ +/* { dg-do run { target int128 } } */ +/* { dg-options "-O2" } */ + +int +main () +{ + unsigned __int128 a = __builtin_bswap128 ((unsigned __int128) 2); + if (a != ((unsigned __int128) 2) << 120) + __builtin_abort (); + a = __builtin_bswap128 ((unsigned __int128) 0xdeadbeefULL); + if (a != ((unsigned __int128) 0xefbeaddeULL) << 96) + __builtin_abort (); + a = __builtin_bswap128 (((unsigned __int128) 0xdeadbeefULL) << 64); + if (a != ((unsigned __int128) 0xefbeaddeULL) << 32) + __builtin_abort (); + a = __builtin_bswap128 ((((unsigned __int128) 0xdeadbeefULL) << 64) + | 0xcafed00dfeedbac1ULL); + if (a != ((((unsigned __int128) 0xc1baedfe0dd0fecaULL) << 64) + | (((unsigned __int128) 0xefbeaddeULL) << 32))) + __builtin_abort (); +} diff --git a/gcc/wide-int.cc b/gcc/wide-int.cc index af6c0e0..5067493d 100644 --- a/gcc/wide-int.cc +++ b/gcc/wide-int.cc @@ -729,20 +729,19 @@ wi::set_bit_large (HOST_WIDE_INT *val, const HOST_WIDE_INT *xval, } } -/* Byte swap the integer represented by XVAL and LEN into VAL. Return +/* Byte swap the integer represented by XVAL and XLEN into VAL. Return the number of blocks in VAL. Both XVAL and VAL have PRECISION bits. */ unsigned int wi::bswap_large (HOST_WIDE_INT *val, const HOST_WIDE_INT *xval, - unsigned int len, unsigned int precision) + unsigned int xlen, unsigned int precision) { - unsigned int i, s; + unsigned int s, len = BLOCKS_NEEDED (precision); /* This is not a well defined operation if the precision is not a multiple of 8. */ gcc_assert ((precision & 0x7) == 0); - for (i = 0; i < len; i++) - val[i] = 0; + memset (val, 0, sizeof (unsigned HOST_WIDE_INT) * len); /* Only swap the bytes that are not the padding. */ for (s = 0; s < precision; s += 8) @@ -753,7 +752,7 @@ wi::bswap_large (HOST_WIDE_INT *val, const HOST_WIDE_INT *xval, unsigned int block = s / HOST_BITS_PER_WIDE_INT; unsigned int offset = s & (HOST_BITS_PER_WIDE_INT - 1); - byte = (safe_uhwi (xval, len, block) >> offset) & 0xff; + byte = (safe_uhwi (xval, xlen, block) >> offset) & 0xff; block = d / HOST_BITS_PER_WIDE_INT; offset = d & (HOST_BITS_PER_WIDE_INT - 1); -- cgit v1.1 From d436e8e70dacd9c06247bb56d0abeded8fcb4242 Mon Sep 17 00:00:00 2001 From: Jerry DeLisle Date: Fri, 2 Feb 2024 18:12:33 -0800 Subject: libgfortran: EN0.0E0 and ES0.0E0 format editing. F2018 and F2023 standards added zero width exponents. This required additional special handing in the process of building formatted floating point strings. G formatting uses either F or E formatting as documented in write_float.def comments. This logic changes the format token from FMT_G to FMT_F or FMT_E. The new formatting requirements interfere with this process when a FMT_G float string is being built. To avoid this, a new component called 'pushed' is added to the fnode structure to save this condition. The 'pushed' condition is then used to bypass portions of the new ES,E,EN, and D formatting, falling through to the existing default formatting which is retained. libgfortran/ChangeLog: PR libfortran/111022 * io/format.c (get_fnode): Update initialization of fnode. (parse_format_list): Initialization. * io/format.h (struct fnode): Added the new 'pushed' component. * io/write.c (select_buffer): Whitespace. (write_real): Whitespace. (write_real_w0): Adjust logic for the d == 0 condition. * io/write_float.def (determine_precision): Whitespace. (build_float_string): Calculate width of ..E0 exponents and adjust logic accordingly. (build_infnan_string): Whitespace. (CALCULATE_EXP): Whitespace. (quadmath_snprintf): Whitespace. (determine_en_precision): Whitespace. gcc/testsuite/ChangeLog: PR libfortran/111022 * gfortran.dg/fmt_error_10.f: Show D+0 exponent. * gfortran.dg/pr96436_4.f90: Show E+0 exponent. * gfortran.dg/pr96436_5.f90: Show E+0 exponent. * gfortran.dg/pr111022.f90: New test. --- gcc/testsuite/gfortran.dg/fmt_error_10.f | 2 +- gcc/testsuite/gfortran.dg/pr111022.f90 | 72 ++++++++++++++++++++++++++++++++ gcc/testsuite/gfortran.dg/pr96436_4.f90 | 4 +- gcc/testsuite/gfortran.dg/pr96436_5.f90 | 4 +- 4 files changed, 77 insertions(+), 5 deletions(-) create mode 100644 gcc/testsuite/gfortran.dg/pr111022.f90 (limited to 'gcc') diff --git a/gcc/testsuite/gfortran.dg/fmt_error_10.f b/gcc/testsuite/gfortran.dg/fmt_error_10.f index 6e1a5f6..fc6620a 100644 --- a/gcc/testsuite/gfortran.dg/fmt_error_10.f +++ b/gcc/testsuite/gfortran.dg/fmt_error_10.f @@ -18,7 +18,7 @@ str = '(1pd0.15)' write (line,str,iostat=istat, iomsg=msg) 1.0d0 - if (line.ne."1.000000000000000") STOP 5 + if (line.ne."1.000000000000000D+0") STOP 5 read (*,str,iostat=istat, iomsg=msg) x if (istat.ne.5006 .or. msg(1:10).ne."Zero width") STOP 6 if (x.ne.555.25) STOP 7 diff --git a/gcc/testsuite/gfortran.dg/pr111022.f90 b/gcc/testsuite/gfortran.dg/pr111022.f90 new file mode 100644 index 0000000..eef55ff --- /dev/null +++ b/gcc/testsuite/gfortran.dg/pr111022.f90 @@ -0,0 +1,72 @@ +! { dg-do run } +program pr111022 + character(20) :: buffer + write(buffer,"(EN0.3E0)") .6660_4 + if (buffer.ne."666.000E-3") stop 1 + write(buffer,"(EN0.3E0)") 6.660_4 + if (buffer.ne."6.660E+0") stop 2 + write(buffer,"(EN0.3E0)") 66.60_4 + if (buffer.ne."66.600E+0") stop 3 + write(buffer,"(EN0.3E0)") 666.0_4 + if (buffer.ne."666.000E+0") stop 4 + write(buffer,"(EN0.3E0)") 6660.0_4 + if (buffer.ne."6.660E+3") stop 5 + write(buffer,"(EN0.3E0)") 66600.0_4 + if (buffer.ne."66.600E+3") stop 6 + + write(buffer,"(EN0.0E0)") 666.0_4 + if (buffer.ne."666.E+0") stop 7 + write(buffer,"(EN0.0E1)") 666.0_4 + if (buffer.ne."666.E+0") stop 8 + write(buffer,"(EN0.0E2)") 666.0_4 + if (buffer.ne."666.E+00") stop 9 + write(buffer,"(EN0.0E3)") 666.0_4 + if (buffer.ne."666.E+000") stop 10 + write(buffer,"(EN0.0E4)") 666.0_4 + if (buffer.ne."666.E+0000") stop 11 + write(buffer,"(EN0.0E5)") 666.0_4 + if (buffer.ne."666.E+00000") stop 12 + write(buffer,"(EN0.0E6)") 666.0_4 + if (buffer.ne."666.E+000000") stop 13 + + write(buffer,"(ES0.3E0)") .6660_4 + if (buffer.ne."6.660E-1") stop 14 + write(buffer,"(ES0.3E0)") 6.660_4 + if (buffer.ne."6.660E+0") stop 15 + write(buffer,"(ES0.3E0)") 66.60_4 + if (buffer.ne."6.660E+1") stop 16 + write(buffer,"(ES0.3E0)") 666.0_4 + if (buffer.ne."6.660E+2") stop 17 + write(buffer,"(ES0.3E0)") 6660.0_4 + if (buffer.ne."6.660E+3") stop 18 + write(buffer,"(ES0.3E0)") 66600.0_4 + if (buffer.ne."6.660E+4") stop 19 + + write(buffer,"(ES0.0E0)") 666.0_4 + if (buffer.ne."7.E+2") stop 20 + write(buffer,"(ES0.0E1)") 666.0_4 + if (buffer.ne."7.E+2") stop 21 + write(buffer,"(ES0.0E2)") 666.0_4 + if (buffer.ne."7.E+02") stop 22 + write(buffer,"(ES0.0E3)") 666.0_4 + if (buffer.ne."7.E+002") stop 23 + write(buffer,"(ES0.0E4)") 666.0_4 + if (buffer.ne."7.E+0002") stop 24 + write(buffer,"(ES0.0E5)") 666.0_4 + if (buffer.ne."7.E+00002") stop 25 + write(buffer,"(ES0.0E6)") 666.0_4 + if (buffer.ne."7.E+000002") stop 26 + + write(buffer,"(E0.3E0)") .6660_4 + if (buffer.ne."0.666E+0") stop 27 + write(buffer,"(E0.3)") .6660_4 + if (buffer.ne."0.666E+0") stop 28 + write(buffer,"(E0.1E0)") .6660_4 + if (buffer.ne."0.7E+0") stop 29 + write(buffer,"(E0.1)") .6660_4 + if (buffer.ne."0.7E+0") stop 30 + write(buffer,"(E0.5E0)") .6660_4 + if (buffer.ne."0.66600E+0") stop 31 + write(buffer,"(E0.5)") .6660_4 + if (buffer.ne."0.66600E+0") stop 32 +end program pr111022 diff --git a/gcc/testsuite/gfortran.dg/pr96436_4.f90 b/gcc/testsuite/gfortran.dg/pr96436_4.f90 index 335ce5f..7d2cfef 100644 --- a/gcc/testsuite/gfortran.dg/pr96436_4.f90 +++ b/gcc/testsuite/gfortran.dg/pr96436_4.f90 @@ -17,9 +17,9 @@ write(buffer,fmt) ">", 3.0, "<" if (buffer.ne.">0.30E+1<") stop 4 fmt = "(1a1,en0.2,1a1)" write(buffer,fmt) ">", 3.0, "<" -if (buffer.ne.">3.00<") stop 5 +if (buffer.ne.">3.00E+0<") stop 5 fmt = "(1a1,es0.2,1a1)" write(buffer,fmt) ">", 3.0, "<" -if (buffer.ne.">3.00<") stop 6 +if (buffer.ne.">3.00E+0<") stop 6 end diff --git a/gcc/testsuite/gfortran.dg/pr96436_5.f90 b/gcc/testsuite/gfortran.dg/pr96436_5.f90 index a45df89..3870d98 100644 --- a/gcc/testsuite/gfortran.dg/pr96436_5.f90 +++ b/gcc/testsuite/gfortran.dg/pr96436_5.f90 @@ -17,9 +17,9 @@ write(buffer,fmt) ">", 3.0, "<" if (buffer.ne.">0.30E+1<") stop 4 fmt = "(1a1,en0.2,1a1)" write(buffer,fmt) ">", 3.0, "<" -if (buffer.ne.">3.00<") stop 5 +if (buffer.ne.">3.00E+0<") stop 5 fmt = "(1a1,es0.2,1a1)" write(buffer,fmt) ">", 3.0, "<" -if (buffer.ne.">3.00<") stop 6 +if (buffer.ne.">3.00E+0<") stop 6 end -- cgit v1.1 From fa96099957c1cdcf73cb8c83e4f694a38a3d8530 Mon Sep 17 00:00:00 2001 From: John David Anglin Date: Sat, 3 Feb 2024 21:06:00 +0000 Subject: Fix xfail for 32-bit hppa*-*-* in gcc.dg/pr84877.c 2024-02-03 John David Anglin gcc/testsuite/ChangeLog: * gcc.dg/pr84877.c: Adjust xfail parentheses. --- gcc/testsuite/gcc.dg/pr84877.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'gcc') diff --git a/gcc/testsuite/gcc.dg/pr84877.c b/gcc/testsuite/gcc.dg/pr84877.c index 6868120..e82991f 100644 --- a/gcc/testsuite/gcc.dg/pr84877.c +++ b/gcc/testsuite/gcc.dg/pr84877.c @@ -1,4 +1,4 @@ -/* { dg-do run { xfail { cris-*-* sparc*-*-* } || { { ! lp64 } && hppa*-*-* } } } */ +/* { dg-do run { xfail { { cris-*-* sparc*-*-* } || { { ! lp64 } && hppa*-*-* } } } } */ /* { dg-options "-O2" } */ #include -- cgit v1.1 From 435bed3f028b21ccc2242c7ee8612d95f07b30dc Mon Sep 17 00:00:00 2001 From: GCC Administrator Date: Sun, 4 Feb 2024 00:16:59 +0000 Subject: Daily bump. --- gcc/ChangeLog | 20 ++++++++++++++++++++ gcc/DATESTAMP | 2 +- gcc/d/ChangeLog | 31 +++++++++++++++++++++++++++++++ gcc/testsuite/ChangeLog | 17 +++++++++++++++++ 4 files changed, 69 insertions(+), 1 deletion(-) (limited to 'gcc') diff --git a/gcc/ChangeLog b/gcc/ChangeLog index f6ab4fc..32e16d3 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,23 @@ +2024-02-03 Jakub Jelinek + + PR middle-end/113722 + * wide-int.cc (wi::bswap_large): Rename third argument from + len to xlen and adjust use in safe_uhwi. Add len variable, set + it to BLOCKS_NEEDED (precision) and use it for clearing of val + and as canonize argument. Clear val using memset instead of + a loop. + +2024-02-03 Jakub Jelinek + + * ggc-common.cc (gt_pch_save): Allow addr to be equal to + mmi.preferred_base + mmi.size - sizeof (void *). + +2024-02-03 Xi Ruoyao + + * config/loongarch/loongarch-def.h (abi_minimal_isa): Declare. + * config/loongarch/loongarch-opts.cc (abi_minimal_isa): Remove + the ODR-violating locale declaration. + 2024-02-02 Tamar Christina PR tree-optimization/113588 diff --git a/gcc/DATESTAMP b/gcc/DATESTAMP index f3c7b76..038ebd2 100644 --- a/gcc/DATESTAMP +++ b/gcc/DATESTAMP @@ -1 +1 @@ -20240203 +20240204 diff --git a/gcc/d/ChangeLog b/gcc/d/ChangeLog index 1b5db29..04bac02 100644 --- a/gcc/d/ChangeLog +++ b/gcc/d/ChangeLog @@ -1,3 +1,34 @@ +2024-02-03 Iain Buclaw + + * dmd/MERGE: Merge upstream dmd e770945277. + * Make-lang.in (D_FRONTEND_OBJS): Add d/basicmangle.o, d/enumsem.o, + d/funcsem.o, d/templatesem.o. + * d-builtins.cc (build_frontend_type): Update for new front-end + interface. + * d-codegen.cc (declaration_type): Likewise. + (parameter_type): Likewise. + * d-incpath.cc (add_globalpaths): Likewise. + (add_filepaths): Likewise. + (add_import_paths): Likewise. + * d-lang.cc (d_init_options): Likewise. + (d_handle_option): Likewise. + (d_parse_file): Likewise. + * decl.cc (DeclVisitor::finish_vtable): Likewise. + (DeclVisitor::visit (FuncDeclaration *)): Likewise. + (get_symbol_decl): Likewise. + * expr.cc (ExprVisitor::visit (StringExp *)): Likewise. + Implement support for 8-byte hexadecimal strings. + * typeinfo.cc (create_tinfo_types): Update internal TypeInfo + representation. + (TypeInfoVisitor::visit (TypeInfoConstDeclaration *)): Update for new + front-end interface. + (TypeInfoVisitor::visit (TypeInfoInvariantDeclaration *)): Likewise. + (TypeInfoVisitor::visit (TypeInfoSharedDeclaration *)): Likewise. + (TypeInfoVisitor::visit (TypeInfoWildDeclaration *)): Likewise. + (TypeInfoVisitor::visit (TypeInfoClassDeclaration *)): Move data for + TypeInfo_Class.nameSig to the end of the object. + (create_typeinfo): Update for new front-end interface. + 2024-02-02 Iain Buclaw * dmd/MERGE: Merge upstream dmd bce5c1f7b5. diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index 5dc568f..aff4a6e 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,20 @@ +2024-02-03 John David Anglin + + * gcc.dg/pr84877.c: Adjust xfail parentheses. + +2024-02-03 Jerry DeLisle + + PR libfortran/111022 + * gfortran.dg/fmt_error_10.f: Show D+0 exponent. + * gfortran.dg/pr96436_4.f90: Show E+0 exponent. + * gfortran.dg/pr96436_5.f90: Show E+0 exponent. + * gfortran.dg/pr111022.f90: New test. + +2024-02-03 Jakub Jelinek + + PR middle-end/113722 + * gcc.dg/pr113722.c: New test. + 2024-02-03 Patrick Palka PR c++/110006 -- cgit v1.1 From c428454ecee141937a6810dd6213716602d563ca Mon Sep 17 00:00:00 2001 From: Iain Buclaw Date: Sat, 3 Feb 2024 14:00:24 +0100 Subject: d: Merge dmd, druntime a6f1083699, phobos 31dedd7da D front-end changes: - Import dmd v2.107.0. - Character postfixes can now also be used for integers of size two or four. D run-time changes: - Import druntime v2.107.0. Phobos changes: - Import phobos v2.107.0. gcc/d/ChangeLog: * dmd/MERGE: Merge upstream dmd a6f1083699. * dmd/VERSION: Bump version to v2.107.0 * Make-lang.in (D_FRONTEND_OBJS): Add d/pragmasem.o. * d-builtins.cc (strip_type_modifiers): Update for new front-end interface. * d-codegen.cc (declaration_type): Likewise. (parameter_type): Likewise. * d-target.cc (TargetCPP::parameterType): Likewise. * expr.cc (ExprVisitor::visit (IndexExp *)): Likewise. (ExprVisitor::visit (VarExp *)): Likewise. (ExprVisitor::visit (AssocArrayLiteralExp *)): Likewise. * runtime.cc (get_libcall_type): Likewise. * typeinfo.cc (TypeInfoVisitor::visit (TypeInfoConstDeclaration *)): Likewise. (TypeInfoVisitor::visit (TypeInfoInvariantDeclaration *)): Likewise. (TypeInfoVisitor::visit (TypeInfoSharedDeclaration *)): Likewise. (TypeInfoVisitor::visit (TypeInfoWildDeclaration *)): Likewise. * types.cc (build_ctype): Likewise. libphobos/ChangeLog: * libdruntime/MERGE: Merge upstream druntime a6f1083699. * src/MERGE: Merge upstream phobos 31dedd7da. --- gcc/d/Make-lang.in | 1 + gcc/d/d-builtins.cc | 2 +- gcc/d/d-codegen.cc | 4 +- gcc/d/d-target.cc | 4 +- gcc/d/dmd/MERGE | 2 +- gcc/d/dmd/README.md | 1 + gcc/d/dmd/VERSION | 2 +- gcc/d/dmd/constfold.d | 6 +- gcc/d/dmd/cparse.d | 2 +- gcc/d/dmd/ctfeexpr.d | 2 +- gcc/d/dmd/dcast.d | 20 +- gcc/d/dmd/dclass.d | 1 + gcc/d/dmd/declaration.h | 1 - gcc/d/dmd/denum.d | 7 +- gcc/d/dmd/dinterpret.d | 43 +- gcc/d/dmd/dmangle.d | 20 +- gcc/d/dmd/dsymbol.h | 2 +- gcc/d/dmd/dsymbolsem.d | 1888 ++------------------ gcc/d/dmd/dtemplate.d | 759 +------- gcc/d/dmd/dtoh.d | 1 + gcc/d/dmd/enumsem.d | 6 + gcc/d/dmd/expression.d | 3 +- gcc/d/dmd/expression.h | 3 +- gcc/d/dmd/expressionsem.d | 31 +- gcc/d/dmd/func.d | 172 +- gcc/d/dmd/funcsem.d | 1150 ++++++++++++ gcc/d/dmd/hdrgen.d | 3 +- gcc/d/dmd/initsem.d | 86 +- gcc/d/dmd/mtype.d | 353 +--- gcc/d/dmd/mtype.h | 26 +- gcc/d/dmd/opover.d | 1 + gcc/d/dmd/optimize.d | 3 +- gcc/d/dmd/pragmasem.d | 650 +++++++ gcc/d/dmd/scope.h | 2 +- gcc/d/dmd/semantic2.d | 23 +- gcc/d/dmd/sideeffect.d | 10 + gcc/d/dmd/statementsem.d | 181 +- gcc/d/dmd/templatesem.d | 909 +++++++++- gcc/d/dmd/typesem.d | 304 +++- gcc/d/dmd/utils.d | 41 + gcc/d/expr.cc | 9 +- gcc/d/runtime.cc | 6 +- gcc/d/typeinfo.cc | 8 +- gcc/d/types.cc | 2 +- gcc/testsuite/gdc.test/compilable/ddoc12.d | 20 - gcc/testsuite/gdc.test/compilable/ddoc4162.d | 2 +- gcc/testsuite/gdc.test/compilable/ddoc5446.d | 2 +- gcc/testsuite/gdc.test/compilable/ddoc7795.d | 2 +- gcc/testsuite/gdc.test/compilable/ddoc_bom_UTF8.d | 20 + gcc/testsuite/gdc.test/compilable/test24338.d | 10 + .../gdc.test/fail_compilation/discard_value.d | 34 + .../gdc.test/fail_compilation/fail12390.d | 16 - gcc/testsuite/gdc.test/fail_compilation/gag4269a.d | 2 +- gcc/testsuite/gdc.test/fail_compilation/gag4269b.d | 2 +- gcc/testsuite/gdc.test/fail_compilation/gag4269c.d | 2 +- gcc/testsuite/gdc.test/fail_compilation/gag4269d.d | 2 +- gcc/testsuite/gdc.test/fail_compilation/gag4269e.d | 2 +- gcc/testsuite/gdc.test/fail_compilation/gag4269f.d | 2 +- gcc/testsuite/gdc.test/fail_compilation/gag4269g.d | 2 +- .../gdc.test/fail_compilation/hexstring.d | 8 +- gcc/testsuite/gdc.test/fail_compilation/ice10599.d | 2 +- .../gdc.test/fail_compilation/test24365.d | 20 + gcc/testsuite/gdc.test/runnable/helloUTF8.d | 16 - gcc/testsuite/gdc.test/runnable/literal.d | 13 + gcc/testsuite/gdc.test/runnable/staticaa.d | 12 + gcc/testsuite/gdc.test/runnable/xtestenum.d | 14 + 66 files changed, 3603 insertions(+), 3352 deletions(-) create mode 100644 gcc/d/dmd/pragmasem.d delete mode 100644 gcc/testsuite/gdc.test/compilable/ddoc12.d create mode 100644 gcc/testsuite/gdc.test/compilable/ddoc_bom_UTF8.d create mode 100644 gcc/testsuite/gdc.test/compilable/test24338.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/discard_value.d delete mode 100644 gcc/testsuite/gdc.test/fail_compilation/fail12390.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/test24365.d delete mode 100644 gcc/testsuite/gdc.test/runnable/helloUTF8.d (limited to 'gcc') diff --git a/gcc/d/Make-lang.in b/gcc/d/Make-lang.in index 176105b..d379ef1 100644 --- a/gcc/d/Make-lang.in +++ b/gcc/d/Make-lang.in @@ -163,6 +163,7 @@ D_FRONTEND_OBJS = \ d/parsetimevisitor.o \ d/permissivevisitor.o \ d/postordervisitor.o \ + d/pragmasem.o \ d/printast.o \ d/root-aav.o \ d/root-array.o \ diff --git a/gcc/d/d-builtins.cc b/gcc/d/d-builtins.cc index 1b5b3be..4ed8751 100644 --- a/gcc/d/d-builtins.cc +++ b/gcc/d/d-builtins.cc @@ -690,7 +690,7 @@ strip_type_modifiers (Type *type) return tnext->pointerTo (); } - return type->castMod (0); + return castMod (type, 0); } /* Returns true if types T1 and T2 representing return types or types of diff --git a/gcc/d/d-codegen.cc b/gcc/d/d-codegen.cc index af938dd..95dc8b6 100644 --- a/gcc/d/d-codegen.cc +++ b/gcc/d/d-codegen.cc @@ -157,7 +157,7 @@ declaration_type (Declaration *decl) if (decl->isParameter () && valist_array_p (decl->type)) { Type *valist = decl->type->nextOf ()->pointerTo (); - valist = valist->castMod (decl->type->mod); + valist = castMod (valist, decl->type->mod); return build_ctype (valist); } @@ -207,7 +207,7 @@ parameter_type (Parameter *arg) if (valist_array_p (arg->type)) { Type *valist = arg->type->nextOf ()->pointerTo (); - valist = valist->castMod (arg->type->mod); + valist = castMod (valist, arg->type->mod); return build_ctype (valist); } diff --git a/gcc/d/d-target.cc b/gcc/d/d-target.cc index 157253e..ff3489c 100644 --- a/gcc/d/d-target.cc +++ b/gcc/d/d-target.cc @@ -381,11 +381,11 @@ TargetCPP::parameterType (Type *type) Type *tvalist = target.va_listType (Loc (), NULL); if (type->ty == TY::Tsarray && tvalist->ty == TY::Tsarray) { - Type *tb = type->toBasetype ()->mutableOf (); + Type *tb = mutableOf (type->toBasetype ()); if (tb == tvalist) { tb = type->nextOf ()->pointerTo (); - type = tb->castMod (type->mod); + type = castMod (tb, type->mod); } } diff --git a/gcc/d/dmd/MERGE b/gcc/d/dmd/MERGE index 9217c65..57ac2dc 100644 --- a/gcc/d/dmd/MERGE +++ b/gcc/d/dmd/MERGE @@ -1,4 +1,4 @@ -e7709452775d374c1e2dfb67566668ada3dec5fc +a6f10836997d0b5526c8c363d781b4029c77f09f The first line of this file holds the git revision number of the last merge done from the dlang/dmd repository. diff --git a/gcc/d/dmd/README.md b/gcc/d/dmd/README.md index 23f3333..282e818 100644 --- a/gcc/d/dmd/README.md +++ b/gcc/d/dmd/README.md @@ -119,6 +119,7 @@ Note that these groups have no strict meaning, the category assignments are a bi | [expressionsem.d](https://github.com/dlang/dmd/blob/master/compiler/src/dmd/expressionsem.d) | Do semantic analysis for expressions | | [statementsem.d](https://github.com/dlang/dmd/blob/master/compiler/src/dmd/statementsem.d) | Do semantic analysis for statements | | [initsem.d](https://github.com/dlang/dmd/blob/master/compiler/src/dmd/initsem.d) | Do semantic analysis for initializers | +| [pragmasem.d](https://github.com/dlang/dmd/blob/master/compiler/src/dmd/pragmasem.d) | Do semantic analysis for pragmas | | [templatesem.d](https://github.com/dlang/dmd/blob/master/compiler/src/dmd/templatesem.d) | Do semantic analysis for templates | | [templateparamsem.d](https://github.com/dlang/dmd/blob/master/compiler/src/dmd/templateparamsem.d) | Do semantic analysis for template parameters | | [typesem.d](https://github.com/dlang/dmd/blob/master/compiler/src/dmd/typesem.d) | Do semantic analysis for types | diff --git a/gcc/d/dmd/VERSION b/gcc/d/dmd/VERSION index b9813c7..8463aee 100644 --- a/gcc/d/dmd/VERSION +++ b/gcc/d/dmd/VERSION @@ -1 +1 @@ -v2.107.0-beta.1 +v2.107.0 diff --git a/gcc/d/dmd/constfold.d b/gcc/d/dmd/constfold.d index 41fed9c..f5d2b60 100644 --- a/gcc/d/dmd/constfold.d +++ b/gcc/d/dmd/constfold.d @@ -1331,9 +1331,9 @@ int sliceCmpStringWithArray(const StringExp se1, ArrayLiteralExp ae2, size_t lo1 { foreach (j; 0 .. len) { - const val2 = cast(dchar)ae2[j + lo2].toInteger(); - const val1 = se1.getCodeUnit(j + lo1); - const int c = val1 - val2; + const val2 = ae2[j + lo2].toInteger(); + const val1 = se1.getIndex(j + lo1); + const int c = (val1 > val2) - (val1 < val2); if (c) return c; } diff --git a/gcc/d/dmd/cparse.d b/gcc/d/dmd/cparse.d index e0cdc87..d462350 100644 --- a/gcc/d/dmd/cparse.d +++ b/gcc/d/dmd/cparse.d @@ -5291,7 +5291,7 @@ final class CParser(AST) : Parser!AST auto ifn = new AST.ExpInitializer(loc, efn); auto lenfn = new AST.IntegerExp(loc, fn.length + 1, AST.Type.tuns32); // +1 for terminating 0 auto tfn = new AST.TypeSArray(AST.Type.tchar, lenfn); - efn.type = tfn.immutableOf(); + efn.type = tfn.makeImmutable(); efn.committed = true; auto sfn = new AST.VarDeclaration(loc, tfn, Id.__func__, ifn, STC.gshared | STC.immutable_); auto e = new AST.DeclarationExp(loc, sfn); diff --git a/gcc/d/dmd/ctfeexpr.d b/gcc/d/dmd/ctfeexpr.d index af83aad..d2fcf5f 100644 --- a/gcc/d/dmd/ctfeexpr.d +++ b/gcc/d/dmd/ctfeexpr.d @@ -34,6 +34,7 @@ import dmd.root.ctfloat; import dmd.root.port; import dmd.root.rmem; import dmd.tokens; +import dmd.typesem; import dmd.visitor; /****************************************************************/ @@ -640,7 +641,6 @@ bool isSafePointerCast(Type srcPointee, Type destPointee) // It's OK if function pointers differ only in safe/pure/nothrow if (srcPointee.ty == Tfunction && destPointee.ty == Tfunction) { - import dmd.typesem : covariant; return srcPointee.covariant(destPointee) == Covariant.yes || destPointee.covariant(srcPointee) == Covariant.yes; } diff --git a/gcc/d/dmd/dcast.d b/gcc/d/dmd/dcast.d index 628c6889..9ee8e8c 100644 --- a/gcc/d/dmd/dcast.d +++ b/gcc/d/dmd/dcast.d @@ -30,6 +30,7 @@ import dmd.escape; import dmd.expression; import dmd.expressionsem; import dmd.func; +import dmd.funcsem; import dmd.globals; import dmd.hdrgen; import dmd.location; @@ -720,11 +721,6 @@ extern(C++) MATCH implicitConvTo(Expression e, Type t) return m; case Tint8: case Tuns8: - if (e.hexString) - { - m = MATCH.convert; - return m; - } break; case Tenum: if (tn.isTypeEnum().sym.isSpecial()) @@ -739,6 +735,14 @@ extern(C++) MATCH implicitConvTo(Expression e, Type t) break; } } + if (e.hexString) + { + if (tn.isintegral && tn.size == e.sz) + { + m = MATCH.convert; + return m; + } + } break; default: @@ -2185,7 +2189,7 @@ Expression castTo(Expression e, Scope* sc, Type t, Type att = null) if (auto f = isFuncAddress(e)) { - if (f.checkForwardRef(e.loc)) + if (checkForwardRef(f, e.loc)) { return ErrorExp.get(); } @@ -2441,7 +2445,7 @@ Expression castTo(Expression e, Scope* sc, Type t, Type att = null) if (auto f = isFuncAddress(e)) { - if (f.checkForwardRef(e.loc)) + if (checkForwardRef(f, e.loc)) { return ErrorExp.get(); } @@ -2496,7 +2500,7 @@ Expression castTo(Expression e, Scope* sc, Type t, Type att = null) if (auto f = isFuncAddress(e)) { - if (f.checkForwardRef(e.loc)) + if (checkForwardRef(f, e.loc)) { return ErrorExp.get(); } diff --git a/gcc/d/dmd/dclass.d b/gcc/d/dmd/dclass.d index 7e5e7e4..8bac1f4 100644 --- a/gcc/d/dmd/dclass.d +++ b/gcc/d/dmd/dclass.d @@ -33,6 +33,7 @@ import dmd.mtype; import dmd.objc; import dmd.root.rmem; import dmd.target; +import dmd.typesem; import dmd.visitor; /*********************************************************** diff --git a/gcc/d/dmd/declaration.h b/gcc/d/dmd/declaration.h index e4efbbc..afbb997 100644 --- a/gcc/d/dmd/declaration.h +++ b/gcc/d/dmd/declaration.h @@ -703,7 +703,6 @@ public: Expressions *fdensureParams(Expressions *fdep); bool equals(const RootObject * const o) const override final; - int findVtblIndex(Dsymbols *vtbl, int dim); bool overloadInsert(Dsymbol *s) override; bool inUnittest(); static MATCH leastAsSpecialized(FuncDeclaration *f, FuncDeclaration *g, Identifiers *names); diff --git a/gcc/d/dmd/denum.d b/gcc/d/dmd/denum.d index 9abdebd..3679976 100644 --- a/gcc/d/dmd/denum.d +++ b/gcc/d/dmd/denum.d @@ -18,19 +18,16 @@ import core.stdc.stdio; import dmd.astenums; import dmd.attrib; -import dmd.errors; import dmd.gluelayer; import dmd.declaration; import dmd.dscope; import dmd.dsymbol; -import dmd.dsymbolsem; import dmd.expression; import dmd.id; import dmd.identifier; import dmd.init; import dmd.location; import dmd.mtype; -import dmd.typesem; import dmd.visitor; /*********************************************************** @@ -66,6 +63,8 @@ extern (C++) final class EnumDeclaration : ScopeDsymbol import dmd.common.bitfields : generateBitFields; mixin(generateBitFields!(BitFields, ubyte)); + Symbol* sinit; + extern (D) this(const ref Loc loc, Identifier ident, Type memtype) { super(loc, ident); @@ -127,8 +126,6 @@ extern (C++) final class EnumDeclaration : ScopeDsymbol return this; } - Symbol* sinit; - override void accept(Visitor v) { v.visit(this); diff --git a/gcc/d/dmd/dinterpret.d b/gcc/d/dmd/dinterpret.d index d8069c6..b078542 100644 --- a/gcc/d/dmd/dinterpret.d +++ b/gcc/d/dmd/dinterpret.d @@ -50,6 +50,8 @@ import dmd.rootobject; import dmd.root.utf; import dmd.statement; import dmd.tokens; +import dmd.typesem : mutableOf; +import dmd.utils : arrayCastBigEndian; import dmd.visitor; /************************************* @@ -7744,44 +7746,3 @@ private void removeHookTraceImpl(ref CallExp ce, ref FuncDeclaration fd) if (global.params.v.verbose) message("strip %s =>\n %s", oldCE.toChars(), ce.toChars()); } - -/** - * Cast a `ubyte[]` to an array of larger integers as if we are on a big endian architecture - * Params: - * data = array with big endian data - * size = 1 for ubyte[], 2 for ushort[], 4 for uint[], 8 for ulong[] - * Returns: copy of `data`, with bytes shuffled if compiled for `version(LittleEndian)` - */ -ubyte[] arrayCastBigEndian(const ubyte[] data, size_t size) -{ - ubyte[] impl(T)() - { - auto result = new T[](data.length / T.sizeof); - foreach (i; 0 .. result.length) - { - result[i] = 0; - foreach (j; 0 .. T.sizeof) - { - result[i] |= T(data[i * T.sizeof + j]) << ((T.sizeof - 1 - j) * 8); - } - } - return cast(ubyte[]) result; - } - switch (size) - { - case 1: return data.dup; - case 2: return impl!ushort; - case 4: return impl!uint; - case 8: return impl!ulong; - default: assert(0); - } -} - -unittest -{ - ubyte[] data = [0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0xFF, 0x11, 0x22]; - assert(cast(ulong[]) arrayCastBigEndian(data, 8) == [0xAABBCCDDEEFF1122]); - assert(cast(uint[]) arrayCastBigEndian(data, 4) == [0xAABBCCDD, 0xEEFF1122]); - assert(cast(ushort[]) arrayCastBigEndian(data, 2) == [0xAABB, 0xCCDD, 0xEEFF, 0x1122]); - assert(cast(ubyte[]) arrayCastBigEndian(data, 1) == data); -} diff --git a/gcc/d/dmd/dmangle.d b/gcc/d/dmd/dmangle.d index 5bd1379..1d01647 100644 --- a/gcc/d/dmd/dmangle.d +++ b/gcc/d/dmd/dmangle.d @@ -951,6 +951,14 @@ public: OutBuffer tmp; const(char)[] q; + void mangleAsArray() + { + buf.writeByte('A'); + buf.print(e.len); + foreach (i; 0 .. e.len) + mangleInteger(e.getIndex(i)); + } + /* Write string in UTF-8 format */ switch (e.sz) @@ -967,7 +975,7 @@ public: { dchar c; if (const s = utf_decodeWchar(slice, u, c)) - error(e.loc, "%.*s", cast(int)s.length, s.ptr); + return mangleAsArray(); else tmp.writeUTF8(c); } @@ -981,7 +989,7 @@ public: foreach (c; slice) { if (!utf_isValidDchar(c)) - error(e.loc, "invalid UCS-32 char \\U%08x", c); + return mangleAsArray(); else tmp.writeUTF8(c); } @@ -990,13 +998,7 @@ public: } case 8: // String of size 8 has to be hexstring cast to long[], mangle as array literal - buf.writeByte('A'); - buf.print(e.len); - foreach (i; 0 .. e.len) - { - mangleInteger(e.getIndex(i)); - } - return; + return mangleAsArray(); default: assert(0); } diff --git a/gcc/d/dmd/dsymbol.h b/gcc/d/dmd/dsymbol.h index 7d715b4..e463d3d 100644 --- a/gcc/d/dmd/dsymbol.h +++ b/gcc/d/dmd/dsymbol.h @@ -147,7 +147,7 @@ enum /* Flags for symbol search */ -typedef uint SearchOptFlags; +typedef unsigned SearchOptFlags; enum class SearchOpt : SearchOptFlags { all = 0x00, // default diff --git a/gcc/d/dmd/dsymbolsem.d b/gcc/d/dmd/dsymbolsem.d index 658beaf..33a397a 100644 --- a/gcc/d/dmd/dsymbolsem.d +++ b/gcc/d/dmd/dsymbolsem.d @@ -21,17 +21,14 @@ import dmd.arraytypes; import dmd.astcodegen; import dmd.astenums; import dmd.attrib; -import dmd.blockexit; import dmd.clone; import dmd.cond; -import dmd.compiler; import dmd.dcast; import dmd.dclass; import dmd.declaration; import dmd.denum; import dmd.dimport; import dmd.dinterpret; -import dmd.dmangle; import dmd.dmodule; import dmd.dscope; import dmd.dstruct; @@ -56,7 +53,6 @@ import dmd.hdrgen; import dmd.location; import dmd.mtype; import dmd.mustuse; -import dmd.nogc; import dmd.nspace; import dmd.objc; import dmd.opover; @@ -67,17 +63,16 @@ import dmd.root.filename; import dmd.common.outbuffer; import dmd.root.rmem; import dmd.rootobject; -import dmd.root.utf; import dmd.semantic2; import dmd.semantic3; import dmd.sideeffect; -import dmd.statementsem; import dmd.staticassert; import dmd.tokens; import dmd.utils; import dmd.statement; import dmd.target; import dmd.templateparamsem; +import dmd.templatesem; import dmd.typesem; import dmd.visitor; @@ -87,48 +82,6 @@ else version = MARS; enum LOG = false; -package uint setMangleOverride(Dsymbol s, const(char)[] sym) -{ - if (s.isFuncDeclaration() || s.isVarDeclaration()) - { - s.isDeclaration().mangleOverride = sym; - return 1; - } - - if (auto ad = s.isAttribDeclaration()) - { - uint nestedCount = 0; - - ad.include(null).foreachDsymbol( (s) { nestedCount += setMangleOverride(s, sym); } ); - - return nestedCount; - } - return 0; -} - -/** - * Apply pragma printf/scanf to FuncDeclarations under `s`, - * poking through attribute declarations such as `extern(C)` - * but not through aggregates or function bodies. - * - * Params: - * s = symbol to apply - * printf = `true` for printf, `false` for scanf - */ -private void setPragmaPrintf(Dsymbol s, bool printf) -{ - if (auto fd = s.isFuncDeclaration()) - { - fd.printf = printf; - fd.scanf = !printf; - } - - if (auto ad = s.isAttribDeclaration()) - { - ad.include(null).foreachDsymbol( (s) { setPragmaPrintf(s, printf); } ); - } -} - /************************************* * Does semantic analysis on the public face of declarations. */ @@ -1346,9 +1299,10 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor dsym._init = dsym._init.initializerSemantic(sc, dsym.type, sc.intypeof == 1 ? INITnointerpret : INITinterpret); import dmd.semantic2 : lowerStaticAAs; lowerStaticAAs(dsym, sc); - const init_err = dsym._init.isExpInitializer(); + auto init_err = dsym._init.isExpInitializer(); if (init_err && init_err.exp.op == EXP.showCtfeContext) { + init_err.exp = ErrorExp.get(); errorSupplemental(dsym.loc, "compile time context created here"); } } @@ -1800,311 +1754,8 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor override void visit(PragmaDeclaration pd) { - StringExp verifyMangleString(ref Expression e) - { - auto se = semanticString(sc, e, "mangled name"); - if (!se) - return null; - e = se; - if (!se.len) - { - .error(pd.loc, "%s `%s` - zero-length string not allowed for mangled name", pd.kind, pd.toPrettyChars); - return null; - } - if (se.sz != 1) - { - .error(pd.loc, "%s `%s` - mangled name characters can only be of type `char`", pd.kind, pd.toPrettyChars); - return null; - } - version (all) - { - /* Note: D language specification should not have any assumption about backend - * implementation. Ideally pragma(mangle) can accept a string of any content. - * - * Therefore, this validation is compiler implementation specific. - */ - auto slice = se.peekString(); - for (size_t i = 0; i < se.len;) - { - dchar c = slice[i]; - if (c < 0x80) - { - if (c.isValidMangling) - { - ++i; - continue; - } - else - { - .error(pd.loc, "%s `%s` char 0x%02x not allowed in mangled name", pd.kind, pd.toPrettyChars, c); - break; - } - } - if (const msg = utf_decodeChar(slice, i, c)) - { - .error(pd.loc, "%s `%s` %.*s", pd.kind, pd.toPrettyChars, cast(int)msg.length, msg.ptr); - break; - } - if (!isUniAlpha(c)) - { - .error(pd.loc, "%s `%s` char `0x%04x` not allowed in mangled name", pd.kind, pd.toPrettyChars, c); - break; - } - } - } - return se; - } - void declarations() - { - if (!pd.decl) - return; - - Scope* sc2 = pd.newScope(sc); - scope(exit) - if (sc2 != sc) - sc2.pop(); - - foreach (s; (*pd.decl)[]) - { - if (pd.ident == Id.printf || pd.ident == Id.scanf) - { - s.setPragmaPrintf(pd.ident == Id.printf); - s.dsymbolSemantic(sc2); - continue; - } - - s.dsymbolSemantic(sc2); - if (pd.ident != Id.mangle) - continue; - assert(pd.args); - if (auto ad = s.isAggregateDeclaration()) - { - Expression e = (*pd.args)[0]; - sc2 = sc2.startCTFE(); - e = e.expressionSemantic(sc); - e = resolveProperties(sc2, e); - sc2 = sc2.endCTFE(); - AggregateDeclaration agg; - if (auto tc = e.type.isTypeClass()) - agg = tc.sym; - else if (auto ts = e.type.isTypeStruct()) - agg = ts.sym; - ad.pMangleOverride = new MangleOverride; - void setString(ref Expression e) - { - if (auto se = verifyMangleString(e)) - { - const name = (cast(const(char)[])se.peekData()).xarraydup; - ad.pMangleOverride.id = Identifier.idPool(name); - e = se; - } - else - error(e.loc, "must be a string"); - } - if (agg) - { - ad.pMangleOverride.agg = agg; - if (pd.args.length == 2) - { - setString((*pd.args)[1]); - } - else - ad.pMangleOverride.id = agg.ident; - } - else - setString((*pd.args)[0]); - } - else if (auto td = s.isTemplateDeclaration()) - { - .error(pd.loc, "%s `%s` cannot apply to a template declaration", pd.kind, pd.toPrettyChars); - errorSupplemental(pd.loc, "use `template Class(Args...){ pragma(mangle, \"other_name\") class Class {} }`"); - } - else if (auto se = verifyMangleString((*pd.args)[0])) - { - const name = (cast(const(char)[])se.peekData()).xarraydup; - uint cnt = setMangleOverride(s, name); - if (cnt > 1) - .error(pd.loc, "%s `%s` can only apply to a single declaration", pd.kind, pd.toPrettyChars); - } - } - } - - void noDeclarations() - { - if (pd.decl) - { - .error(pd.loc, "%s `%s` is missing a terminating `;`", pd.kind, pd.toPrettyChars); - declarations(); - // do them anyway, to avoid segfaults. - } - } - - // Should be merged with PragmaStatement - //printf("\tPragmaDeclaration::semantic '%s'\n", pd.toChars()); - if (target.supportsLinkerDirective()) - { - if (pd.ident == Id.linkerDirective) - { - if (!pd.args || pd.args.length != 1) - .error(pd.loc, "%s `%s` one string argument expected for pragma(linkerDirective)", pd.kind, pd.toPrettyChars); - else - { - auto se = semanticString(sc, (*pd.args)[0], "linker directive"); - if (!se) - return noDeclarations(); - (*pd.args)[0] = se; - if (global.params.v.verbose) - message("linkopt %.*s", cast(int)se.len, se.peekString().ptr); - } - return noDeclarations(); - } - } - if (pd.ident == Id.msg) - { - if (!pd.args) - return noDeclarations(); - - if (!pragmaMsgSemantic(pd.loc, sc, pd.args)) - return; - - return noDeclarations(); - } - else if (pd.ident == Id.lib) - { - if (!pd.args || pd.args.length != 1) - .error(pd.loc, "%s `%s` string expected for library name", pd.kind, pd.toPrettyChars); - else - { - auto se = semanticString(sc, (*pd.args)[0], "library name"); - if (!se) - return noDeclarations(); - (*pd.args)[0] = se; - - auto name = se.peekString().xarraydup; - if (global.params.v.verbose) - message("library %s", name.ptr); - if (global.params.moduleDeps.buffer && !global.params.moduleDeps.name) - { - OutBuffer* ob = global.params.moduleDeps.buffer; - Module imod = sc._module; - ob.writestring("depsLib "); - ob.writestring(imod.toPrettyChars()); - ob.writestring(" ("); - escapePath(ob, imod.srcfile.toChars()); - ob.writestring(") : "); - ob.writestring(name); - ob.writenl(); - } - mem.xfree(name.ptr); - } - return noDeclarations(); - } - else if (pd.ident == Id.startaddress) - { - pragmaStartAddressSemantic(pd.loc, sc, pd.args); - return noDeclarations(); - } - else if (pd.ident == Id.Pinline) - { - // this pragma now gets evaluated on demand in function semantic - - return declarations(); - } - else if (pd.ident == Id.mangle) - { - if (!pd.args) - pd.args = new Expressions(); - if (pd.args.length == 0 || pd.args.length > 2) - { - .error(pd.loc, pd.args.length == 0 ? "%s `%s` - string expected for mangled name" - : "%s `%s` expected 1 or 2 arguments", pd.kind, pd.toPrettyChars); - pd.args.setDim(1); - (*pd.args)[0] = ErrorExp.get(); // error recovery - } - return declarations(); - } - else if (pd.ident == Id.crt_constructor || pd.ident == Id.crt_destructor) - { - if (pd.args && pd.args.length != 0) - .error(pd.loc, "%s `%s` takes no argument", pd.kind, pd.toPrettyChars); - else - { - immutable isCtor = pd.ident == Id.crt_constructor; - - static uint recurse(Dsymbol s, bool isCtor) - { - if (auto ad = s.isAttribDeclaration()) - { - uint nestedCount; - auto decls = ad.include(null); - if (decls) - { - for (size_t i = 0; i < decls.length; ++i) - nestedCount += recurse((*decls)[i], isCtor); - } - return nestedCount; - } - else if (auto f = s.isFuncDeclaration()) - { - if (isCtor) - f.isCrtCtor = true; - else - f.isCrtDtor = true; - - return 1; - } - else - return 0; - assert(0); - } - - if (recurse(pd, isCtor) > 1) - .error(pd.loc, "%s `%s` can only apply to a single declaration", pd.kind, pd.toPrettyChars); - } - return declarations(); - } - else if (pd.ident == Id.printf || pd.ident == Id.scanf) - { - if (pd.args && pd.args.length != 0) - .error(pd.loc, "%s `%s` takes no argument", pd.kind, pd.toPrettyChars); - return declarations(); - } - else if (!global.params.ignoreUnsupportedPragmas) - { - error(pd.loc, "unrecognized `pragma(%s)`", pd.ident.toChars()); - return declarations(); - } - - if (!global.params.v.verbose) - return declarations(); - - /* Print unrecognized pragmas - */ - OutBuffer buf; - buf.writestring(pd.ident.toString()); - if (pd.args) - { - const errors_save = global.startGagging(); - for (size_t i = 0; i < pd.args.length; i++) - { - Expression e = (*pd.args)[i]; - sc = sc.startCTFE(); - e = e.expressionSemantic(sc); - e = resolveProperties(sc, e); - sc = sc.endCTFE(); - e = e.ctfeInterpret(); - if (i == 0) - buf.writestring(" ("); - else - buf.writeByte(','); - buf.writestring(e.toChars()); - } - if (pd.args.length) - buf.writeByte(')'); - global.endGagging(errors_save); - } - message("pragma %s", buf.peekChars()); - return declarations(); + import dmd.pragmasem : pragmaDeclSemantic; + pragmaDeclSemantic(pd, sc); } override void visit(StaticIfDeclaration sid) @@ -2314,143 +1965,7 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor override void visit(TemplateDeclaration tempdecl) { - static if (LOG) - { - printf("TemplateDeclaration.dsymbolSemantic(this = %p, id = '%s')\n", this, tempdecl.ident.toChars()); - printf("sc.stc = %llx\n", sc.stc); - printf("sc.module = %s\n", sc._module.toChars()); - } - if (tempdecl.semanticRun != PASS.initial) - return; // semantic() already run - - if (tempdecl._scope) - { - sc = tempdecl._scope; - tempdecl._scope = null; - } - if (!sc) - return; - - // Remember templates defined in module object that we need to know about - if (sc._module && sc._module.ident == Id.object) - { - if (tempdecl.ident == Id.RTInfo) - Type.rtinfo = tempdecl; - } - - /* Remember Scope for later instantiations, but make - * a copy since attributes can change. - */ - if (!tempdecl._scope) - { - tempdecl._scope = sc.copy(); - tempdecl._scope.setNoFree(); - } - - tempdecl.semanticRun = PASS.semantic; - - tempdecl.parent = sc.parent; - tempdecl.visibility = sc.visibility; - tempdecl.userAttribDecl = sc.userAttribDecl; - tempdecl.cppnamespace = sc.namespace; - tempdecl.isstatic = tempdecl.toParent().isModule() || (tempdecl._scope.stc & STC.static_); - tempdecl.deprecated_ = !!(sc.stc & STC.deprecated_); - - UserAttributeDeclaration.checkGNUABITag(tempdecl, sc.linkage); - - if (!tempdecl.isstatic) - { - if (auto ad = tempdecl.parent.pastMixin().isAggregateDeclaration()) - ad.makeNested(); - } - - // Set up scope for parameters - auto paramsym = new ScopeDsymbol(); - paramsym.parent = tempdecl.parent; - Scope* paramscope = sc.push(paramsym); - paramscope.stc = 0; - - if (global.params.ddoc.doOutput) - { - tempdecl.origParameters = new TemplateParameters(tempdecl.parameters.length); - for (size_t i = 0; i < tempdecl.parameters.length; i++) - { - TemplateParameter tp = (*tempdecl.parameters)[i]; - (*tempdecl.origParameters)[i] = tp.syntaxCopy(); - } - } - - for (size_t i = 0; i < tempdecl.parameters.length; i++) - { - TemplateParameter tp = (*tempdecl.parameters)[i]; - if (!tp.declareParameter(paramscope)) - { - error(tp.loc, "parameter `%s` multiply defined", tp.ident.toChars()); - tempdecl.errors = true; - } - if (!tp.tpsemantic(paramscope, tempdecl.parameters)) - { - tempdecl.errors = true; - } - if (i + 1 != tempdecl.parameters.length && tp.isTemplateTupleParameter()) - { - .error(tempdecl.loc, "%s `%s` template sequence parameter must be the last one", tempdecl.kind, tempdecl.toPrettyChars); - tempdecl.errors = true; - } - } - - /* Calculate TemplateParameter.dependent - */ - TemplateParameters tparams = TemplateParameters(1); - for (size_t i = 0; i < tempdecl.parameters.length; i++) - { - TemplateParameter tp = (*tempdecl.parameters)[i]; - tparams[0] = tp; - - for (size_t j = 0; j < tempdecl.parameters.length; j++) - { - // Skip cases like: X(T : T) - if (i == j) - continue; - - if (TemplateTypeParameter ttp = (*tempdecl.parameters)[j].isTemplateTypeParameter()) - { - if (reliesOnTident(ttp.specType, &tparams)) - tp.dependent = true; - } - else if (TemplateAliasParameter tap = (*tempdecl.parameters)[j].isTemplateAliasParameter()) - { - if (reliesOnTident(tap.specType, &tparams) || - reliesOnTident(isType(tap.specAlias), &tparams)) - { - tp.dependent = true; - } - } - } - } - - paramscope.pop(); - - // Compute again - tempdecl.onemember = null; - if (tempdecl.members) - { - Dsymbol s; - if (Dsymbol.oneMembers(tempdecl.members, s, tempdecl.ident) && s) - { - tempdecl.onemember = s; - s.parent = tempdecl; - } - } - - /* BUG: should check: - * 1. template functions must not introduce virtual functions, as they - * cannot be accomodated in the vtbl[] - * 2. templates cannot introduce non-static data members (i.e. fields) - * as they would change the instance size of the aggregate. - */ - - tempdecl.semanticRun = PASS.semanticdone; + templateDeclarationSemantic(sc, tempdecl); } override void visit(TemplateInstance ti) @@ -2569,1200 +2084,235 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor else if (ea) { Expression tme = isExpression(tmo); - if (!tme || !ea.equals(tme)) - goto Lcontinue; - } - else if (sa) - { - Dsymbol tmsa = isDsymbol(tmo); - if (sa != tmsa) - goto Lcontinue; - } - else - assert(0); - } - .error(tm.loc, "%s `%s` recursive mixin instantiation", tm.kind, tm.toPrettyChars); - return; - - Lcontinue: - continue; - } - - // Copy the syntax trees from the TemplateDeclaration - tm.members = Dsymbol.arraySyntaxCopy(tempdecl.members); - if (!tm.members) - return; - - tm.symtab = new DsymbolTable(); - - sc.getScopesym().importScope(tm, Visibility(Visibility.Kind.public_)); - - static if (LOG) - { - printf("\tcreate scope for template parameters '%s'\n", tm.toChars()); - } - Scope* scy = sc.push(tm); - scy.parent = tm; - - /* https://issues.dlang.org/show_bug.cgi?id=930 - * - * If the template that is to be mixed in is in the scope of a template - * instance, we have to also declare the type aliases in the new mixin scope. - */ - auto parentInstance = tempdecl.parent ? tempdecl.parent.isTemplateInstance() : null; - if (parentInstance) - parentInstance.declareParameters(scy); - - tm.argsym = new ScopeDsymbol(); - tm.argsym.parent = scy.parent; - Scope* argscope = scy.push(tm.argsym); - - uint errorsave = global.errors; - - // Declare each template parameter as an alias for the argument type - tm.declareParameters(argscope); - - // Add members to enclosing scope, as well as this scope - tm.members.foreachDsymbol(s => s.addMember(argscope, tm)); - - // Do semantic() analysis on template instance members - static if (LOG) - { - printf("\tdo semantic() on template instance members '%s'\n", tm.toChars()); - } - Scope* sc2 = argscope.push(tm); - //size_t deferred_dim = Module.deferred.length; - - __gshared int nest; - //printf("%d\n", nest); - if (++nest > global.recursionLimit) - { - global.gag = 0; // ensure error message gets printed - .error(tm.loc, "%s `%s` recursive expansion", tm.kind, tm.toPrettyChars); - fatal(); - } - - tm.members.foreachDsymbol( s => s.setScope(sc2) ); - - tm.members.foreachDsymbol( s => s.importAll(sc2) ); - - tm.members.foreachDsymbol( s => s.dsymbolSemantic(sc2) ); - - nest--; - - /* In DeclDefs scope, TemplateMixin does not have to handle deferred symbols. - * Because the members would already call Module.addDeferredSemantic() for themselves. - * See Struct, Class, Interface, and EnumDeclaration.dsymbolSemantic(). - */ - //if (!sc.func && Module.deferred.length > deferred_dim) {} - - AggregateDeclaration ad = tm.isMember(); - if (sc.func && !ad) - { - tm.semantic2(sc2); - tm.semantic3(sc2); - } - - // Give additional context info if error occurred during instantiation - if (global.errors != errorsave) - { - .error(tm.loc, "%s `%s` error instantiating", tm.kind, tm.toPrettyChars); - tm.errors = true; - } - - sc2.pop(); - argscope.pop(); - scy.pop(); - - static if (LOG) - { - printf("-TemplateMixin.dsymbolSemantic('%s', this=%p)\n", tm.toChars(), tm); - } - } - - override void visit(Nspace ns) - { - if (ns.semanticRun != PASS.initial) - return; - static if (LOG) - { - printf("+Nspace::semantic('%s')\n", ns.toChars()); - scope(exit) printf("-Nspace::semantic('%s')\n", ns.toChars()); - } - if (ns._scope) - { - sc = ns._scope; - ns._scope = null; - } - if (!sc) - return; - - bool repopulateMembers = false; - if (ns.identExp) - { - // resolve the namespace identifier - sc = sc.startCTFE(); - Expression resolved = ns.identExp.expressionSemantic(sc); - resolved = resolveProperties(sc, resolved); - sc = sc.endCTFE(); - resolved = resolved.ctfeInterpret(); - StringExp name = resolved.toStringExp(); - TupleExp tup = name ? null : resolved.isTupleExp(); - if (!tup && !name) - { - error(ns.loc, "expected string expression for namespace name, got `%s`", ns.identExp.toChars()); - return; - } - ns.identExp = resolved; // we don't need to keep the old AST around - if (name) - { - const(char)[] ident = name.toStringz(); - if (ident.length == 0 || !Identifier.isValidIdentifier(ident)) - { - error(ns.loc, "expected valid identifier for C++ namespace but got `%.*s`", cast(int)ident.length, ident.ptr); - return; - } - ns.ident = Identifier.idPool(ident); - } - else - { - // create namespace stack from the tuple - Nspace parentns = ns; - foreach (i, exp; *tup.exps) - { - name = exp.toStringExp(); - if (!name) - { - error(ns.loc, "expected string expression for namespace name, got `%s`", exp.toChars()); - return; - } - const(char)[] ident = name.toStringz(); - if (ident.length == 0 || !Identifier.isValidIdentifier(ident)) - { - error(ns.loc, "expected valid identifier for C++ namespace but got `%.*s`", cast(int)ident.length, ident.ptr); - return; - } - if (i == 0) - { - ns.ident = Identifier.idPool(ident); - } - else - { - // insert the new namespace - Nspace childns = new Nspace(ns.loc, Identifier.idPool(ident), null, parentns.members); - parentns.members = new Dsymbols; - parentns.members.push(childns); - parentns = childns; - repopulateMembers = true; - } - } - } - } - - ns.semanticRun = PASS.semantic; - ns.parent = sc.parent; - // Link does not matter here, if the UDA is present it will error - UserAttributeDeclaration.checkGNUABITag(ns, LINK.cpp); - - if (!ns.members) - { - ns.semanticRun = PASS.semanticdone; - return; - } - assert(sc); - sc = sc.push(ns); - sc.linkage = LINK.cpp; // note that namespaces imply C++ linkage - sc.parent = ns; - foreach (s; *ns.members) - { - if (repopulateMembers) - { - s.addMember(sc, sc.scopesym); - s.setScope(sc); - } - s.importAll(sc); - } - foreach (s; *ns.members) - { - static if (LOG) - { - printf("\tmember '%s', kind = '%s'\n", s.toChars(), s.kind()); - } - s.dsymbolSemantic(sc); - } - sc.pop(); - ns.semanticRun = PASS.semanticdone; - } - - void funcDeclarationSemantic(FuncDeclaration funcdecl) - { - version (none) - { - printf("FuncDeclaration::semantic(sc = %p, this = %p, '%s', linkage = %d)\n", sc, funcdecl, funcdecl.toPrettyChars(), sc.linkage); - if (funcdecl.isFuncLiteralDeclaration()) - printf("\tFuncLiteralDeclaration()\n"); - printf("sc.parent = %s, parent = %s\n", sc.parent.toChars(), funcdecl.parent ? funcdecl.parent.toChars() : ""); - printf("type: %p, %s\n", funcdecl.type, funcdecl.type.toChars()); - } - - if (funcdecl.semanticRun != PASS.initial && funcdecl.isFuncLiteralDeclaration()) - { - /* Member functions that have return types that are - * forward references can have semantic() run more than - * once on them. - * See test\interface2.d, test20 - */ - return; - } - - if (funcdecl.semanticRun >= PASS.semanticdone) - return; - assert(funcdecl.semanticRun <= PASS.semantic); - funcdecl.semanticRun = PASS.semantic; - - if (funcdecl._scope) - { - sc = funcdecl._scope; - funcdecl._scope = null; - } - - if (!sc || funcdecl.errors) - return; - - funcdecl.cppnamespace = sc.namespace; - funcdecl.parent = sc.parent; - Dsymbol parent = funcdecl.toParent(); - - funcdecl.foverrides.setDim(0); // reset in case semantic() is being retried for this function - - funcdecl.storage_class |= sc.stc & ~STC.ref_; - AggregateDeclaration ad = funcdecl.isThis(); - // Don't nest structs b/c of generated methods which should not access the outer scopes. - // https://issues.dlang.org/show_bug.cgi?id=16627 - if (ad && !funcdecl.isGenerated()) - { - funcdecl.storage_class |= ad.storage_class & (STC.TYPECTOR | STC.synchronized_); - ad.makeNested(); - } - if (sc.func) - funcdecl.storage_class |= sc.func.storage_class & STC.disable; - // Remove prefix storage classes silently. - if ((funcdecl.storage_class & STC.TYPECTOR) && !(ad || funcdecl.isNested())) - funcdecl.storage_class &= ~STC.TYPECTOR; - - //printf("function storage_class = x%llx, sc.stc = x%llx, %x\n", storage_class, sc.stc, Declaration.isFinal()); - - if (sc.flags & SCOPE.compile) - funcdecl.skipCodegen = true; - - funcdecl._linkage = sc.linkage; - if (sc.flags & SCOPE.Cfile && funcdecl.isFuncLiteralDeclaration()) - funcdecl._linkage = LINK.d; // so they are uniquely mangled - - if (auto fld = funcdecl.isFuncLiteralDeclaration()) - { - if (fld.treq) - { - Type treq = fld.treq; - assert(treq.nextOf().ty == Tfunction); - if (treq.ty == Tdelegate) - fld.tok = TOK.delegate_; - else if (treq.isPtrToFunction()) - fld.tok = TOK.function_; - else - assert(0); - funcdecl._linkage = treq.nextOf().toTypeFunction().linkage; - } - } - - // evaluate pragma(inline) - if (auto pragmadecl = sc.inlining) - funcdecl.inlining = evalPragmaInline(pragmadecl.loc, sc, pragmadecl.args); - - funcdecl.visibility = sc.visibility; - funcdecl.userAttribDecl = sc.userAttribDecl; - UserAttributeDeclaration.checkGNUABITag(funcdecl, funcdecl._linkage); - checkMustUseReserved(funcdecl); - - if (!funcdecl.originalType) - funcdecl.originalType = funcdecl.type.syntaxCopy(); - - static TypeFunction getFunctionType(FuncDeclaration fd) - { - if (auto tf = fd.type.isTypeFunction()) - return tf; - - if (!fd.type.isTypeError()) - { - .error(fd.loc, "%s `%s` `%s` must be a function instead of `%s`", fd.kind, fd.toPrettyChars, fd.toChars(), fd.type.toChars()); - fd.type = Type.terror; - } - fd.errors = true; - return null; - } - - if (sc.flags & SCOPE.Cfile) - { - /* C11 allows a function to be declared with a typedef, D does not. - */ - if (auto ti = funcdecl.type.isTypeIdentifier()) - { - auto tj = ti.typeSemantic(funcdecl.loc, sc); - if (auto tjf = tj.isTypeFunction()) - { - /* Copy the type instead of just pointing to it, - * as we don't merge function types - */ - auto tjf2 = new TypeFunction(tjf.parameterList, tjf.next, tjf.linkage); - funcdecl.type = tjf2; - funcdecl.originalType = tjf2; - } - } - } - - if (!getFunctionType(funcdecl)) - return; - - if (!funcdecl.type.deco) - { - sc = sc.push(); - sc.stc |= funcdecl.storage_class & (STC.disable | STC.deprecated_); // forward to function type - - TypeFunction tf = funcdecl.type.toTypeFunction(); - if (sc.func) - { - /* If the nesting parent is pure without inference, - * then this function defaults to pure too. - * - * auto foo() pure { - * auto bar() {} // become a weak purity function - * class C { // nested class - * auto baz() {} // become a weak purity function - * } - * - * static auto boo() {} // typed as impure - * // Even though, boo cannot call any impure functions. - * // See also Expression::checkPurity(). - * } - */ - if (tf.purity == PURE.impure && (funcdecl.isNested() || funcdecl.isThis())) - { - FuncDeclaration fd = null; - for (Dsymbol p = funcdecl.toParent2(); p; p = p.toParent2()) - { - if (AggregateDeclaration adx = p.isAggregateDeclaration()) - { - if (adx.isNested()) - continue; - break; - } - if ((fd = p.isFuncDeclaration()) !is null) - break; - } - - /* If the parent's purity is inferred, then this function's purity needs - * to be inferred first. - */ - if (fd && fd.isPureBypassingInference() >= PURE.weak && !funcdecl.isInstantiated()) - { - tf.purity = PURE.fwdref; // default to pure - } - } - } - - if (tf.isref) - sc.stc |= STC.ref_; - if (tf.isScopeQual) - sc.stc |= STC.scope_; - if (tf.isnothrow) - sc.stc |= STC.nothrow_; - if (tf.isnogc) - sc.stc |= STC.nogc; - if (tf.isproperty) - sc.stc |= STC.property; - if (tf.purity == PURE.fwdref) - sc.stc |= STC.pure_; - - if (tf.trust != TRUST.default_) - { - sc.stc &= ~STC.safeGroup; - if (tf.trust == TRUST.safe) - sc.stc |= STC.safe; - else if (tf.trust == TRUST.system) - sc.stc |= STC.system; - else if (tf.trust == TRUST.trusted) - sc.stc |= STC.trusted; - } - - if (funcdecl.isCtorDeclaration()) - { - tf.isctor = true; - Type tret = ad.handleType(); - assert(tret); - tret = tret.addStorageClass(funcdecl.storage_class | sc.stc); - tret = tret.addMod(funcdecl.type.mod); - tf.next = tret; - if (ad.isStructDeclaration()) - sc.stc |= STC.ref_; - } - - // 'return' on a non-static class member function implies 'scope' as well - if (ad && ad.isClassDeclaration() && (tf.isreturn || sc.stc & STC.return_) && !(sc.stc & STC.static_)) - sc.stc |= STC.scope_; - - // If 'this' has no pointers, remove 'scope' as it has no meaning - // Note: this is already covered by semantic of `VarDeclaration` and `TypeFunction`, - // but existing code relies on `hasPointers()` being called here to resolve forward references: - // https://github.com/dlang/dmd/pull/14232#issuecomment-1162906573 - if (sc.stc & STC.scope_ && ad && ad.isStructDeclaration() && !ad.type.hasPointers()) - { - sc.stc &= ~STC.scope_; - tf.isScopeQual = false; - if (tf.isreturnscope) - { - sc.stc &= ~(STC.return_ | STC.returnScope); - tf.isreturn = false; - tf.isreturnscope = false; - } - } - - sc.linkage = funcdecl._linkage; - - if (!tf.isNaked() && !(funcdecl.isThis() || funcdecl.isNested())) - { - import core.bitop : popcnt; - auto mods = MODtoChars(tf.mod); - .error(funcdecl.loc, "%s `%s` without `this` cannot be `%s`", funcdecl.kind, funcdecl.toPrettyChars, mods); - if (tf.next && tf.next.ty != Tvoid && popcnt(tf.mod) == 1) - .errorSupplemental(funcdecl.loc, - "did you mean to use `%s(%s)` as the return type?", mods, tf.next.toChars()); - - tf.mod = 0; // remove qualifiers - } - - /* Apply const, immutable, wild and shared storage class - * to the function type. Do this before type semantic. - */ - auto stc = funcdecl.storage_class; - if (funcdecl.type.isImmutable()) - stc |= STC.immutable_; - if (funcdecl.type.isConst()) - stc |= STC.const_; - if (funcdecl.type.isShared() || funcdecl.storage_class & STC.synchronized_) - stc |= STC.shared_; - if (funcdecl.type.isWild()) - stc |= STC.wild; - funcdecl.type = funcdecl.type.addSTC(stc); - - funcdecl.type = funcdecl.type.typeSemantic(funcdecl.loc, sc); - sc = sc.pop(); - } - - auto f = getFunctionType(funcdecl); - if (!f) - return; // funcdecl's type is not a function - - { - // Merge back function attributes into 'originalType'. - // It's used for mangling, ddoc, and json output. - TypeFunction tfo = funcdecl.originalType.toTypeFunction(); - tfo.mod = f.mod; - tfo.isScopeQual = f.isScopeQual; - tfo.isreturninferred = f.isreturninferred; - tfo.isscopeinferred = f.isscopeinferred; - tfo.isref = f.isref; - tfo.isnothrow = f.isnothrow; - tfo.isnogc = f.isnogc; - tfo.isproperty = f.isproperty; - tfo.purity = f.purity; - tfo.trust = f.trust; - - funcdecl.storage_class &= ~(STC.TYPECTOR | STC.FUNCATTR); - } - - // check pragma(crt_constructor) signature - if (funcdecl.isCrtCtor || funcdecl.isCrtDtor) - { - const idStr = funcdecl.isCrtCtor ? "crt_constructor" : "crt_destructor"; - if (f.nextOf().ty != Tvoid) - .error(funcdecl.loc, "%s `%s` must return `void` for `pragma(%s)`", funcdecl.kind, funcdecl.toPrettyChars, idStr.ptr); - if (funcdecl._linkage != LINK.c && f.parameterList.length != 0) - .error(funcdecl.loc, "%s `%s` must be `extern(C)` for `pragma(%s)` when taking parameters", funcdecl.kind, funcdecl.toPrettyChars, idStr.ptr); - if (funcdecl.isThis()) - .error(funcdecl.loc, "%s `%s` cannot be a non-static member function for `pragma(%s)`", funcdecl.kind, funcdecl.toPrettyChars, idStr.ptr); - } - - if (funcdecl.overnext && funcdecl.isCsymbol()) - { - /* C does not allow function overloading, but it does allow - * redeclarations of the same function. If .overnext points - * to a redeclaration, ok. Error if it is an overload. - */ - auto fnext = funcdecl.overnext.isFuncDeclaration(); - funcDeclarationSemantic(fnext); - auto fn = fnext.type.isTypeFunction(); - if (!fn || !cFuncEquivalence(f, fn)) - { - .error(funcdecl.loc, "%s `%s` redeclaration with different type", funcdecl.kind, funcdecl.toPrettyChars); - //printf("t1: %s\n", f.toChars()); - //printf("t2: %s\n", fn.toChars()); - } - funcdecl.overnext = null; // don't overload the redeclarations - } - - if ((funcdecl.storage_class & STC.auto_) && !f.isref && !funcdecl.inferRetType) - .error(funcdecl.loc, "%s `%s` storage class `auto` has no effect if return type is not inferred", funcdecl.kind, funcdecl.toPrettyChars); - - if (f.isreturn && !funcdecl.needThis() && !funcdecl.isNested()) - { - /* Non-static nested functions have a hidden 'this' pointer to which - * the 'return' applies - */ - if (sc.scopesym && sc.scopesym.isAggregateDeclaration()) - .error(funcdecl.loc, "%s `%s` `static` member has no `this` to which `return` can apply", funcdecl.kind, funcdecl.toPrettyChars); - else - error(funcdecl.loc, "top-level function `%s` has no `this` to which `return` can apply", funcdecl.toChars()); - } - - if (funcdecl.isAbstract() && !funcdecl.isVirtual()) - { - const(char)* sfunc; - if (funcdecl.isStatic()) - sfunc = "static"; - else if (funcdecl.visibility.kind == Visibility.Kind.private_ || funcdecl.visibility.kind == Visibility.Kind.package_) - sfunc = visibilityToChars(funcdecl.visibility.kind); - else - sfunc = "final"; - .error(funcdecl.loc, "%s `%s` `%s` functions cannot be `abstract`", funcdecl.kind, funcdecl.toPrettyChars, sfunc); - } - - if (funcdecl.isOverride() && !funcdecl.isVirtual() && !funcdecl.isFuncLiteralDeclaration()) - { - Visibility.Kind kind = funcdecl.visible().kind; - if ((kind == Visibility.Kind.private_ || kind == Visibility.Kind.package_) && funcdecl.isMember()) - .error(funcdecl.loc, "%s `%s` `%s` method is not virtual and cannot override", funcdecl.kind, funcdecl.toPrettyChars, visibilityToChars(kind)); - else - .error(funcdecl.loc, "%s `%s` cannot override a non-virtual function", funcdecl.kind, funcdecl.toPrettyChars); - } - - if (funcdecl.isAbstract() && funcdecl.isFinalFunc()) - .error(funcdecl.loc, "%s `%s` cannot be both `final` and `abstract`", funcdecl.kind, funcdecl.toPrettyChars); - - if (funcdecl.printf || funcdecl.scanf) - { - checkPrintfScanfSignature(funcdecl, f, sc); - } - - if (auto id = parent.isInterfaceDeclaration()) - { - funcdecl.storage_class |= STC.abstract_; - if (funcdecl.isCtorDeclaration() || funcdecl.isPostBlitDeclaration() || funcdecl.isDtorDeclaration() || funcdecl.isInvariantDeclaration() || funcdecl.isNewDeclaration() || funcdecl.isDelete()) - .error(funcdecl.loc, "%s `%s` constructors, destructors, postblits, invariants, new and delete functions are not allowed in interface `%s`", funcdecl.kind, funcdecl.toPrettyChars, id.toChars()); - if (funcdecl.fbody && funcdecl.isVirtual()) - .error(funcdecl.loc, "%s `%s` function body only allowed in `final` functions in interface `%s`", funcdecl.kind, funcdecl.toPrettyChars, id.toChars()); - } - - if (UnionDeclaration ud = parent.isUnionDeclaration()) - { - if (funcdecl.isPostBlitDeclaration() || funcdecl.isDtorDeclaration() || funcdecl.isInvariantDeclaration()) - .error(funcdecl.loc, "%s `%s` destructors, postblits and invariants are not allowed in union `%s`", funcdecl.kind, funcdecl.toPrettyChars, ud.toChars()); - } - - if (StructDeclaration sd = parent.isStructDeclaration()) - { - if (funcdecl.isCtorDeclaration()) - { - goto Ldone; - } - } - - if (ClassDeclaration cd = parent.isClassDeclaration()) - { - parent = cd = objc.getParent(funcdecl, cd); - - if (funcdecl.isCtorDeclaration()) - { - goto Ldone; - } - - if (funcdecl.storage_class & STC.abstract_) - cd.isabstract = ThreeState.yes; - - // if static function, do not put in vtbl[] - if (!funcdecl.isVirtual()) - { - //printf("\tnot virtual\n"); - goto Ldone; - } - // Suppress further errors if the return type is an error - if (funcdecl.type.nextOf() == Type.terror) - goto Ldone; - - bool may_override = false; - for (size_t i = 0; i < cd.baseclasses.length; i++) - { - BaseClass* b = (*cd.baseclasses)[i]; - ClassDeclaration cbd = b.type.toBasetype().isClassHandle(); - if (!cbd) - continue; - for (size_t j = 0; j < cbd.vtbl.length; j++) - { - FuncDeclaration f2 = cbd.vtbl[j].isFuncDeclaration(); - if (!f2 || f2.ident != funcdecl.ident) - continue; - if (cbd.parent && cbd.parent.isTemplateInstance()) - { - if (!functionSemantic(f2)) - goto Ldone; - } - may_override = true; - } - } - if (may_override && funcdecl.type.nextOf() is null) - { - /* If same name function exists in base class but 'this' is auto return, - * cannot find index of base class's vtbl[] to override. - */ - .error(funcdecl.loc, "%s `%s` return type inference is not supported if may override base class function", funcdecl.kind, funcdecl.toPrettyChars); - } - - /* Find index of existing function in base class's vtbl[] to override - * (the index will be the same as in cd's current vtbl[]) - */ - int vi = cd.baseClass ? funcdecl.findVtblIndex(&cd.baseClass.vtbl, cast(int)cd.baseClass.vtbl.length) : -1; - - bool doesoverride = false; - switch (vi) - { - case -1: - Lintro: - /* Didn't find one, so - * This is an 'introducing' function which gets a new - * slot in the vtbl[]. - */ - - // Verify this doesn't override previous final function - if (cd.baseClass) - { - Dsymbol s = cd.baseClass.search(funcdecl.loc, funcdecl.ident); - if (s) - { - if (auto f2 = s.isFuncDeclaration()) - { - f2 = f2.overloadExactMatch(funcdecl.type); - if (f2 && f2.isFinalFunc() && f2.visible().kind != Visibility.Kind.private_) - .error(funcdecl.loc, "%s `%s` cannot override `final` function `%s`", funcdecl.kind, funcdecl.toPrettyChars, f2.toPrettyChars()); - } - } - } - - /* These quirky conditions mimic what happens when virtual - inheritance is implemented by producing a virtual base table - with offsets to each of the virtual bases. - */ - if (target.cpp.splitVBasetable && cd.classKind == ClassKind.cpp && - cd.baseClass && cd.baseClass.vtbl.length) - { - /* if overriding an interface function, then this is not - * introducing and don't put it in the class vtbl[] - */ - funcdecl.interfaceVirtual = funcdecl.overrideInterface(); - if (funcdecl.interfaceVirtual) - { - //printf("\tinterface function %s\n", toChars()); - cd.vtblFinal.push(funcdecl); - goto Linterfaces; - } - } - - if (funcdecl.isFinalFunc()) - { - // Don't check here, as it may override an interface function - //if (isOverride()) - // error("is marked as override, but does not override any function"); - cd.vtblFinal.push(funcdecl); - } - else - { - //printf("\tintroducing function %s\n", funcdecl.toChars()); - funcdecl.isIntroducing = true; - if (cd.classKind == ClassKind.cpp && target.cpp.reverseOverloads) - { - /* Overloaded functions with same name are grouped and in reverse order. - * Search for first function of overload group, and insert - * funcdecl into vtbl[] immediately before it. - */ - funcdecl.vtblIndex = cast(int)cd.vtbl.length; - bool found; - foreach (const i, s; cd.vtbl) - { - if (found) - // the rest get shifted forward - ++s.isFuncDeclaration().vtblIndex; - else if (s.ident == funcdecl.ident && s.parent == parent) - { - // found first function of overload group - funcdecl.vtblIndex = cast(int)i; - found = true; - ++s.isFuncDeclaration().vtblIndex; - } - } - cd.vtbl.insert(funcdecl.vtblIndex, funcdecl); - - debug foreach (const i, s; cd.vtbl) - { - // a C++ dtor gets its vtblIndex later (and might even be added twice to the vtbl), - // e.g. when compiling druntime with a debug compiler, namely with core.stdcpp.exception. - if (auto fd = s.isFuncDeclaration()) - assert(fd.vtblIndex == i || - (cd.classKind == ClassKind.cpp && fd.isDtorDeclaration) || - funcdecl.parent.isInterfaceDeclaration); // interface functions can be in multiple vtbls - } - } - else - { - // Append to end of vtbl[] - vi = cast(int)cd.vtbl.length; - cd.vtbl.push(funcdecl); - funcdecl.vtblIndex = vi; - } - } - break; - - case -2: - // can't determine because of forward references - funcdecl.errors = true; - return; - - default: - { - if (vi >= cd.vtbl.length) - { - /* the derived class cd doesn't have its vtbl[] allocated yet. - * https://issues.dlang.org/show_bug.cgi?id=21008 - */ - .error(funcdecl.loc, "%s `%s` circular reference to class `%s`", funcdecl.kind, funcdecl.toPrettyChars, cd.toChars()); - funcdecl.errors = true; - return; - } - FuncDeclaration fdv = cd.baseClass.vtbl[vi].isFuncDeclaration(); - FuncDeclaration fdc = cd.vtbl[vi].isFuncDeclaration(); - // This function is covariant with fdv - - if (fdc == funcdecl) - { - doesoverride = true; - break; - } - - auto vtf = getFunctionType(fdv); - if (vtf.trust > TRUST.system && f.trust == TRUST.system) - .error(funcdecl.loc, "%s `%s` cannot override `@safe` method `%s` with a `@system` attribute", funcdecl.kind, funcdecl.toPrettyChars, - fdv.toPrettyChars); - - if (fdc.toParent() == parent) - { - //printf("vi = %d,\tthis = %p %s %s @ [%s]\n\tfdc = %p %s %s @ [%s]\n\tfdv = %p %s %s @ [%s]\n", - // vi, this, this.toChars(), this.type.toChars(), this.loc.toChars(), - // fdc, fdc .toChars(), fdc .type.toChars(), fdc .loc.toChars(), - // fdv, fdv .toChars(), fdv .type.toChars(), fdv .loc.toChars()); - - // fdc overrides fdv exactly, then this introduces new function. - if (fdc.type.mod == fdv.type.mod && funcdecl.type.mod != fdv.type.mod) - goto Lintro; - } - - if (fdv.isDeprecated && !funcdecl.isDeprecated) - deprecation(funcdecl.loc, "`%s` is overriding the deprecated method `%s`", - funcdecl.toPrettyChars, fdv.toPrettyChars); - - // This function overrides fdv - if (fdv.isFinalFunc()) - .error(funcdecl.loc, "%s `%s` cannot override `final` function `%s`", funcdecl.kind, funcdecl.toPrettyChars, fdv.toPrettyChars()); - - if (!funcdecl.isOverride()) - { - if (fdv.isFuture()) - { - deprecation(funcdecl.loc, "`@__future` base class method `%s` is being overridden by `%s`; rename the latter", fdv.toPrettyChars(), funcdecl.toPrettyChars()); - // Treat 'this' as an introducing function, giving it a separate hierarchy in the vtbl[] - goto Lintro; - } - else - { - // https://issues.dlang.org/show_bug.cgi?id=17349 - error(funcdecl.loc, "cannot implicitly override base class method `%s` with `%s`; add `override` attribute", - fdv.toPrettyChars(), funcdecl.toPrettyChars()); - } - } - doesoverride = true; - if (fdc.toParent() == parent) - { - // If both are mixins, or both are not, then error. - // If either is not, the one that is not overrides the other. - bool thismixin = funcdecl.parent.isClassDeclaration() !is null; - bool fdcmixin = fdc.parent.isClassDeclaration() !is null; - if (thismixin == fdcmixin) - { - .error(funcdecl.loc, "%s `%s` multiple overrides of same function", funcdecl.kind, funcdecl.toPrettyChars); - } - /* - * https://issues.dlang.org/show_bug.cgi?id=711 - * - * If an overriding method is introduced through a mixin, - * we need to update the vtbl so that both methods are - * present. - */ - else if (thismixin) - { - /* if the mixin introduced the overriding method, then reintroduce it - * in the vtbl. The initial entry for the mixined method - * will be updated at the end of the enclosing `if` block - * to point to the current (non-mixined) function. - */ - auto vitmp = cast(int)cd.vtbl.length; - cd.vtbl.push(fdc); - fdc.vtblIndex = vitmp; - } - else if (fdcmixin) - { - /* if the current overriding function is coming from a - * mixined block, then push the current function in the - * vtbl, but keep the previous (non-mixined) function as - * the overriding one. - */ - auto vitmp = cast(int)cd.vtbl.length; - cd.vtbl.push(funcdecl); - funcdecl.vtblIndex = vitmp; - break; - } - else // fdc overrides fdv - { - // this doesn't override any function - break; - } - } - cd.vtbl[vi] = funcdecl; - funcdecl.vtblIndex = vi; - - /* Remember which functions this overrides - */ - funcdecl.foverrides.push(fdv); - - /* This works by whenever this function is called, - * it actually returns tintro, which gets dynamically - * cast to type. But we know that tintro is a base - * of type, so we could optimize it by not doing a - * dynamic cast, but just subtracting the isBaseOf() - * offset if the value is != null. - */ - - if (fdv.tintro) - funcdecl.tintro = fdv.tintro; - else if (!funcdecl.type.equals(fdv.type)) - { - auto tnext = funcdecl.type.nextOf(); - if (auto handle = tnext.isClassHandle()) - { - if (handle.semanticRun < PASS.semanticdone && !handle.isBaseInfoComplete()) - handle.dsymbolSemantic(null); - } - /* Only need to have a tintro if the vptr - * offsets differ - */ - int offset; - if (fdv.type.nextOf().isBaseOf(tnext, &offset)) - { - funcdecl.tintro = fdv.type; - } - } - break; - } - } - - /* Go through all the interface bases. - * If this function is covariant with any members of those interface - * functions, set the tintro. - */ - Linterfaces: - bool foundVtblMatch = false; - - for (ClassDeclaration bcd = cd; !foundVtblMatch && bcd; bcd = bcd.baseClass) - { - foreach (b; bcd.interfaces) - { - vi = funcdecl.findVtblIndex(&b.sym.vtbl, cast(int)b.sym.vtbl.length); - switch (vi) - { - case -1: - break; - - case -2: - // can't determine because of forward references - funcdecl.errors = true; - return; - - default: - { - auto fdv = cast(FuncDeclaration)b.sym.vtbl[vi]; - Type ti = null; - - foundVtblMatch = true; - - /* Remember which functions this overrides - */ - funcdecl.foverrides.push(fdv); - - if (fdv.tintro) - ti = fdv.tintro; - else if (!funcdecl.type.equals(fdv.type)) - { - /* Only need to have a tintro if the vptr - * offsets differ - */ - int offset; - if (fdv.type.nextOf().isBaseOf(funcdecl.type.nextOf(), &offset)) - { - ti = fdv.type; - } - } - if (ti) - { - if (funcdecl.tintro) - { - if (!funcdecl.tintro.nextOf().equals(ti.nextOf()) && !funcdecl.tintro.nextOf().isBaseOf(ti.nextOf(), null) && !ti.nextOf().isBaseOf(funcdecl.tintro.nextOf(), null)) - { - .error(funcdecl.loc, "%s `%s` incompatible covariant types `%s` and `%s`", funcdecl.kind, funcdecl.toPrettyChars, funcdecl.tintro.toChars(), ti.toChars()); - } - } - else - { - funcdecl.tintro = ti; - } - } - } - } + if (!tme || !ea.equals(tme)) + goto Lcontinue; } - } - if (foundVtblMatch) - { - goto L2; - } - - if (!doesoverride && funcdecl.isOverride() && (funcdecl.type.nextOf() || !may_override)) - { - BaseClass* bc = null; - Dsymbol s = null; - for (size_t i = 0; i < cd.baseclasses.length; i++) + else if (sa) { - bc = (*cd.baseclasses)[i]; - s = bc.sym.search_correct(funcdecl.ident); - if (s) - break; + Dsymbol tmsa = isDsymbol(tmo); + if (sa != tmsa) + goto Lcontinue; } + else + assert(0); + } + .error(tm.loc, "%s `%s` recursive mixin instantiation", tm.kind, tm.toPrettyChars); + return; - if (s) - { - HdrGenState hgs; - OutBuffer buf; + Lcontinue: + continue; + } - auto fd = s.isFuncDeclaration(); - functionToBufferFull(cast(TypeFunction)(funcdecl.type), buf, - new Identifier(funcdecl.toPrettyChars()), hgs, null); - const(char)* funcdeclToChars = buf.peekChars(); + // Copy the syntax trees from the TemplateDeclaration + tm.members = Dsymbol.arraySyntaxCopy(tempdecl.members); + if (!tm.members) + return; - if (fd) - { - OutBuffer buf1; + tm.symtab = new DsymbolTable(); - if (fd.ident == funcdecl.ident) - hgs.fullQual = true; + sc.getScopesym().importScope(tm, Visibility(Visibility.Kind.public_)); - // https://issues.dlang.org/show_bug.cgi?id=23745 - // If the potentially overridden function contains errors, - // inform the user to fix that one first - if (fd.errors) - { - error(funcdecl.loc, "function `%s` does not override any function, did you mean to override `%s`?", - funcdecl.toChars(), fd.toPrettyChars()); - errorSupplemental(fd.loc, "Function `%s` contains errors in its declaration, therefore it cannot be correctly overridden", - fd.toPrettyChars()); - } - else - { - functionToBufferFull(cast(TypeFunction)(fd.type), buf1, - new Identifier(fd.toPrettyChars()), hgs, null); + static if (LOG) + { + printf("\tcreate scope for template parameters '%s'\n", tm.toChars()); + } + Scope* scy = sc.push(tm); + scy.parent = tm; - error(funcdecl.loc, "function `%s` does not override any function, did you mean to override `%s`?", - funcdeclToChars, buf1.peekChars()); - } - } - else - { - error(funcdecl.loc, "function `%s` does not override any function, did you mean to override %s `%s`?", - funcdeclToChars, s.kind, s.toPrettyChars()); - errorSupplemental(funcdecl.loc, "Functions are the only declarations that may be overridden"); - } - } - else - .error(funcdecl.loc, "%s `%s` does not override any function", funcdecl.kind, funcdecl.toPrettyChars); - } + /* https://issues.dlang.org/show_bug.cgi?id=930 + * + * If the template that is to be mixed in is in the scope of a template + * instance, we have to also declare the type aliases in the new mixin scope. + */ + auto parentInstance = tempdecl.parent ? tempdecl.parent.isTemplateInstance() : null; + if (parentInstance) + parentInstance.declareParameters(scy); - L2: - objc.setSelector(funcdecl, sc); - objc.checkLinkage(funcdecl); - objc.addToClassMethodList(funcdecl, cd); - objc.setAsOptional(funcdecl, sc); + tm.argsym = new ScopeDsymbol(); + tm.argsym.parent = scy.parent; + Scope* argscope = scy.push(tm.argsym); - /* Go through all the interface bases. - * Disallow overriding any final functions in the interface(s). - */ - foreach (b; cd.interfaces) - { - if (b.sym) - { - if (auto s = search_function(b.sym, funcdecl.ident)) - { - if (auto f2 = s.isFuncDeclaration()) - { - f2 = f2.overloadExactMatch(funcdecl.type); - if (f2 && f2.isFinalFunc() && f2.visible().kind != Visibility.Kind.private_) - .error(funcdecl.loc, "%s `%s` cannot override `final` function `%s.%s`", funcdecl.kind, funcdecl.toPrettyChars, b.sym.toChars(), f2.toPrettyChars()); - } - } - } - } + uint errorsave = global.errors; - if (funcdecl.isOverride) - { - if (funcdecl.storage_class & STC.disable) - deprecation(funcdecl.loc, - "`%s` cannot be annotated with `@disable` because it is overriding a function in the base class", - funcdecl.toPrettyChars); + // Declare each template parameter as an alias for the argument type + tm.declareParameters(argscope); - if (funcdecl.isDeprecated && !(funcdecl.foverrides.length && funcdecl.foverrides[0].isDeprecated)) - deprecation(funcdecl.loc, - "`%s` cannot be marked as `deprecated` because it is overriding a function in the base class", - funcdecl.toPrettyChars); - } + // Add members to enclosing scope, as well as this scope + tm.members.foreachDsymbol(s => s.addMember(argscope, tm)); + // Do semantic() analysis on template instance members + static if (LOG) + { + printf("\tdo semantic() on template instance members '%s'\n", tm.toChars()); } - else if (funcdecl.isOverride() && !parent.isTemplateInstance()) - .error(funcdecl.loc, "%s `%s` `override` only applies to class member functions", funcdecl.kind, funcdecl.toPrettyChars); + Scope* sc2 = argscope.push(tm); + //size_t deferred_dim = Module.deferred.length; - if (auto ti = parent.isTemplateInstance) + __gshared int nest; + //printf("%d\n", nest); + if (++nest > global.recursionLimit) { - objc.setSelector(funcdecl, sc); - objc.setAsOptional(funcdecl, sc); + global.gag = 0; // ensure error message gets printed + .error(tm.loc, "%s `%s` recursive expansion", tm.kind, tm.toPrettyChars); + fatal(); } - objc.validateSelector(funcdecl); - objc.validateOptional(funcdecl); - // Reflect this.type to f because it could be changed by findVtblIndex - f = funcdecl.type.toTypeFunction(); - - Ldone: - if (!funcdecl.fbody && !funcdecl.allowsContractWithoutBody()) - .error(funcdecl.loc, "%s `%s` `in` and `out` contracts can only appear without a body when they are virtual interface functions or abstract", funcdecl.kind, funcdecl.toPrettyChars); + tm.members.foreachDsymbol( s => s.setScope(sc2) ); - /* Do not allow template instances to add virtual functions - * to a class. - */ - if (funcdecl.isVirtual()) - { - if (auto ti = parent.isTemplateInstance()) - { - // Take care of nested templates - while (1) - { - TemplateInstance ti2 = ti.tempdecl.parent.isTemplateInstance(); - if (!ti2) - break; - ti = ti2; - } + tm.members.foreachDsymbol( s => s.importAll(sc2) ); - // If it's a member template - ClassDeclaration cd = ti.tempdecl.isClassMember(); - if (cd) - { - .error(funcdecl.loc, "%s `%s` cannot use template to add virtual function to class `%s`", funcdecl.kind, funcdecl.toPrettyChars, cd.toChars()); - } - } - } + tm.members.foreachDsymbol( s => s.dsymbolSemantic(sc2) ); - funcdecl.checkMain(); // Check main() parameters and return type + nest--; - /* Purity and safety can be inferred for some functions by examining - * the function body. + /* In DeclDefs scope, TemplateMixin does not have to handle deferred symbols. + * Because the members would already call Module.addDeferredSemantic() for themselves. + * See Struct, Class, Interface, and EnumDeclaration.dsymbolSemantic(). */ - if (funcdecl.canInferAttributes(sc)) - funcdecl.initInferAttributes(); - - funcdecl.semanticRun = PASS.semanticdone; + //if (!sc.func && Module.deferred.length > deferred_dim) {} - /* Save scope for possible later use (if we need the - * function internals) - */ - funcdecl._scope = sc.copy(); - funcdecl._scope.setNoFree(); + AggregateDeclaration ad = tm.isMember(); + if (sc.func && !ad) + { + tm.semantic2(sc2); + tm.semantic3(sc2); + } - __gshared bool printedMain = false; // semantic might run more than once - if (global.params.v.verbose && !printedMain) + // Give additional context info if error occurred during instantiation + if (global.errors != errorsave) { - const(char)* type = funcdecl.isMain() ? "main" : funcdecl.isWinMain() ? "winmain" : funcdecl.isDllMain() ? "dllmain" : cast(const(char)*)null; - Module mod = sc._module; + .error(tm.loc, "%s `%s` error instantiating", tm.kind, tm.toPrettyChars); + tm.errors = true; + } - if (type && mod) - { - printedMain = true; - auto name = mod.srcfile.toChars(); - auto path = FileName.searchPath(global.path, name, true); - message("entry %-10s\t%s", type, path ? path : name); - } + sc2.pop(); + argscope.pop(); + scy.pop(); + + static if (LOG) + { + printf("-TemplateMixin.dsymbolSemantic('%s', this=%p)\n", tm.toChars(), tm); } + } - if (funcdecl.fbody && sc._module.isRoot() && - (funcdecl.isMain() || funcdecl.isWinMain() || funcdecl.isDllMain() || funcdecl.isCMain())) - global.hasMainFunction = true; + override void visit(Nspace ns) + { + if (ns.semanticRun != PASS.initial) + return; + static if (LOG) + { + printf("+Nspace::semantic('%s')\n", ns.toChars()); + scope(exit) printf("-Nspace::semantic('%s')\n", ns.toChars()); + } + if (ns._scope) + { + sc = ns._scope; + ns._scope = null; + } + if (!sc) + return; - if (funcdecl.fbody && funcdecl.isMain() && sc._module.isRoot()) + bool repopulateMembers = false; + if (ns.identExp) { - // check if `_d_cmain` is defined - bool cmainTemplateExists() + // resolve the namespace identifier + sc = sc.startCTFE(); + Expression resolved = ns.identExp.expressionSemantic(sc); + resolved = resolveProperties(sc, resolved); + sc = sc.endCTFE(); + resolved = resolved.ctfeInterpret(); + StringExp name = resolved.toStringExp(); + TupleExp tup = name ? null : resolved.isTupleExp(); + if (!tup && !name) { - Dsymbol pscopesym; - auto rootSymbol = sc.search(funcdecl.loc, Id.empty, pscopesym); - if (auto moduleSymbol = rootSymbol.search(funcdecl.loc, Id.object)) - if (moduleSymbol.search(funcdecl.loc, Id.CMain)) - return true; - - return false; + error(ns.loc, "expected string expression for namespace name, got `%s`", ns.identExp.toChars()); + return; } - - // Only mixin `_d_cmain` if it is defined - if (cmainTemplateExists()) + ns.identExp = resolved; // we don't need to keep the old AST around + if (name) + { + const(char)[] ident = name.toStringz(); + if (ident.length == 0 || !Identifier.isValidIdentifier(ident)) + { + error(ns.loc, "expected valid identifier for C++ namespace but got `%.*s`", cast(int)ident.length, ident.ptr); + return; + } + ns.ident = Identifier.idPool(ident); + } + else { - // add `mixin _d_cmain!();` to the declaring module - auto tqual = new TypeIdentifier(funcdecl.loc, Id.CMain); - auto tm = new TemplateMixin(funcdecl.loc, null, tqual, null); - sc._module.members.push(tm); + // create namespace stack from the tuple + Nspace parentns = ns; + foreach (i, exp; *tup.exps) + { + name = exp.toStringExp(); + if (!name) + { + error(ns.loc, "expected string expression for namespace name, got `%s`", exp.toChars()); + return; + } + const(char)[] ident = name.toStringz(); + if (ident.length == 0 || !Identifier.isValidIdentifier(ident)) + { + error(ns.loc, "expected valid identifier for C++ namespace but got `%.*s`", cast(int)ident.length, ident.ptr); + return; + } + if (i == 0) + { + ns.ident = Identifier.idPool(ident); + } + else + { + // insert the new namespace + Nspace childns = new Nspace(ns.loc, Identifier.idPool(ident), null, parentns.members); + parentns.members = new Dsymbols; + parentns.members.push(childns); + parentns = childns; + repopulateMembers = true; + } + } } } - assert(funcdecl.type.ty != Terror || funcdecl.errors); + ns.semanticRun = PASS.semantic; + ns.parent = sc.parent; + // Link does not matter here, if the UDA is present it will error + UserAttributeDeclaration.checkGNUABITag(ns, LINK.cpp); - // semantic for parameters' UDAs - foreach (i, param; f.parameterList) + if (!ns.members) + { + ns.semanticRun = PASS.semanticdone; + return; + } + assert(sc); + sc = sc.push(ns); + sc.linkage = LINK.cpp; // note that namespaces imply C++ linkage + sc.parent = ns; + foreach (s; *ns.members) + { + if (repopulateMembers) + { + s.addMember(sc, sc.scopesym); + s.setScope(sc); + } + s.importAll(sc); + } + foreach (s; *ns.members) { - if (param && param.userAttribDecl) - param.userAttribDecl.dsymbolSemantic(sc); + static if (LOG) + { + printf("\tmember '%s', kind = '%s'\n", s.toChars(), s.kind()); + } + s.dsymbolSemantic(sc); } + sc.pop(); + ns.semanticRun = PASS.semanticdone; } /// Do the semantic analysis on the external interface to the function. override void visit(FuncDeclaration funcdecl) { - funcDeclarationSemantic(funcdecl); + funcDeclarationSemantic(sc, funcdecl); } override void visit(CtorDeclaration ctd) @@ -3799,7 +2349,7 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor sc.stc &= ~STC.static_; // not a static constructor - funcDeclarationSemantic(ctd); + funcDeclarationSemantic(sc, ctd); sc.pop(); @@ -3898,7 +2448,7 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor sc.stc &= ~STC.static_; // not static sc.linkage = LINK.d; - funcDeclarationSemantic(pbd); + funcDeclarationSemantic(sc, pbd); sc.pop(); } @@ -3964,7 +2514,7 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor if (sc.linkage != LINK.cpp) sc.linkage = LINK.d; - funcDeclarationSemantic(dd); + funcDeclarationSemantic(sc, dd); sc.pop(); } @@ -4052,7 +2602,7 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor // Just correct it sc.linkage = LINK.d; } - funcDeclarationSemantic(scd); + funcDeclarationSemantic(sc, scd); sc.linkage = save; // We're going to need ModuleInfo @@ -4168,7 +2718,7 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor // Just correct it sc.linkage = LINK.d; } - funcDeclarationSemantic(sdd); + funcDeclarationSemantic(sc, sdd); sc.linkage = save; // We're going to need ModuleInfo @@ -4219,7 +2769,7 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor sc.flags = (sc.flags & ~SCOPE.contract) | SCOPE.invariant_; sc.linkage = LINK.d; - funcDeclarationSemantic(invd); + funcDeclarationSemantic(sc, invd); sc.pop(); } @@ -4252,7 +2802,7 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor utd.type = new TypeFunction(ParameterList(), Type.tvoid, LINK.d, utd.storage_class); Scope* sc2 = sc.push(); sc2.linkage = LINK.d; - funcDeclarationSemantic(utd); + funcDeclarationSemantic(sc, utd); sc2.pop(); } @@ -4281,7 +2831,7 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor if (!nd.type) nd.type = new TypeFunction(ParameterList(), Type.tvoid.pointerTo(), LINK.d, nd.storage_class); - funcDeclarationSemantic(nd); + funcDeclarationSemantic(sc, nd); } override void visit(StructDeclaration sd) @@ -7278,50 +5828,6 @@ private CallExp doAtomicOp (string op, Identifier var, Expression arg) return CallExp.create(loc, dti, args); } -/*************************************** - * Interpret a `pragma(inline, x)` - * - * Params: - * loc = location for error messages - * sc = scope for evaluation of argument - * args = pragma arguments - * Returns: corresponding `PINLINE` state - */ -PINLINE evalPragmaInline(Loc loc, Scope* sc, Expressions* args) -{ - if (!args || args.length == 0) - return PINLINE.default_; - - if (args && args.length > 1) - { - .error(loc, "one boolean expression expected for `pragma(inline)`, not %llu", cast(ulong) args.length); - args.setDim(1); - (*args)[0] = ErrorExp.get(); - } - - Expression e = (*args)[0]; - if (!e.type) - { - sc = sc.startCTFE(); - e = e.expressionSemantic(sc); - e = resolveProperties(sc, e); - sc = sc.endCTFE(); - e = e.ctfeInterpret(); - e = e.toBoolean(sc); - if (e.isErrorExp()) - .error(loc, "pragma(`inline`, `true` or `false`) expected, not `%s`", (*args)[0].toChars()); - (*args)[0] = e; - } - - const opt = e.toBool(); - if (opt.isEmpty()) - return PINLINE.default_; - else if (opt.get()) - return PINLINE.always; - else - return PINLINE.never; -} - /*************************************************** * Set up loc for a parse of a mixin. Append the input text to the mixin. * Params: diff --git a/gcc/d/dmd/dtemplate.d b/gcc/d/dmd/dtemplate.d index 465ae74..4a195e3 100644 --- a/gcc/d/dmd/dtemplate.d +++ b/gcc/d/dmd/dtemplate.d @@ -816,194 +816,6 @@ extern (C++) final class TemplateDeclaration : ScopeDsymbol return buf.extractChars(); } - /************************************************** - * Declare template parameter tp with value o, and install it in the scope sc. - */ - extern (D) RootObject declareParameter(Scope* sc, TemplateParameter tp, RootObject o) - { - //printf("TemplateDeclaration.declareParameter('%s', o = %p)\n", tp.ident.toChars(), o); - Type ta = isType(o); - Expression ea = isExpression(o); - Dsymbol sa = isDsymbol(o); - Tuple va = isTuple(o); - - Declaration d; - VarDeclaration v = null; - - if (ea) - { - if (ea.op == EXP.type) - ta = ea.type; - else if (auto se = ea.isScopeExp()) - sa = se.sds; - else if (auto te = ea.isThisExp()) - sa = te.var; - else if (auto se = ea.isSuperExp()) - sa = se.var; - else if (auto fe = ea.isFuncExp()) - { - if (fe.td) - sa = fe.td; - else - sa = fe.fd; - } - } - - if (ta) - { - //printf("type %s\n", ta.toChars()); - auto ad = new AliasDeclaration(Loc.initial, tp.ident, ta); - ad.storage_class |= STC.templateparameter; - d = ad; - } - else if (sa) - { - //printf("Alias %s %s;\n", sa.ident.toChars(), tp.ident.toChars()); - auto ad = new AliasDeclaration(Loc.initial, tp.ident, sa); - ad.storage_class |= STC.templateparameter; - d = ad; - } - else if (ea) - { - // tdtypes.data[i] always matches ea here - Initializer _init = new ExpInitializer(loc, ea); - TemplateValueParameter tvp = tp.isTemplateValueParameter(); - Type t = tvp ? tvp.valType : null; - v = new VarDeclaration(loc, t, tp.ident, _init); - v.storage_class = STC.manifest | STC.templateparameter; - d = v; - } - else if (va) - { - //printf("\ttuple\n"); - d = new TupleDeclaration(loc, tp.ident, &va.objects); - } - else - { - assert(0); - } - d.storage_class |= STC.templateparameter; - - if (ta) - { - Type t = ta; - // consistent with Type.checkDeprecated() - while (t.ty != Tenum) - { - if (!t.nextOf()) - break; - t = (cast(TypeNext)t).next; - } - if (Dsymbol s = t.toDsymbol(sc)) - { - if (s.isDeprecated()) - d.storage_class |= STC.deprecated_; - } - } - else if (sa) - { - if (sa.isDeprecated()) - d.storage_class |= STC.deprecated_; - } - - if (!sc.insert(d)) - .error(loc, "%s `%s` declaration `%s` is already defined", kind, toPrettyChars, tp.ident.toChars()); - d.dsymbolSemantic(sc); - /* So the caller's o gets updated with the result of semantic() being run on o - */ - if (v) - o = v._init.initializerToExpression(); - return o; - } - - /************************************************* - * Limited function template instantiation for using fd.leastAsSpecialized() - */ - extern (D) FuncDeclaration doHeaderInstantiation(TemplateInstance ti, Scope* sc2, FuncDeclaration fd, Type tthis, Expressions* fargs) - { - assert(fd); - version (none) - { - printf("doHeaderInstantiation this = %s\n", toChars()); - } - - // function body and contracts are not need - if (fd.isCtorDeclaration()) - fd = new CtorDeclaration(fd.loc, fd.endloc, fd.storage_class, fd.type.syntaxCopy()); - else - fd = new FuncDeclaration(fd.loc, fd.endloc, fd.ident, fd.storage_class, fd.type.syntaxCopy()); - fd.parent = ti; - - assert(fd.type.ty == Tfunction); - auto tf = fd.type.isTypeFunction(); - tf.fargs = fargs; - - if (tthis) - { - // Match 'tthis' to any TemplateThisParameter's - bool hasttp = false; - foreach (tp; *parameters) - { - TemplateThisParameter ttp = tp.isTemplateThisParameter(); - if (ttp) - hasttp = true; - } - if (hasttp) - { - tf = tf.addSTC(ModToStc(tthis.mod)).isTypeFunction(); - assert(!tf.deco); - } - } - - Scope* scx = sc2.push(); - - // Shouldn't run semantic on default arguments and return type. - foreach (ref params; *tf.parameterList.parameters) - params.defaultArg = null; - tf.incomplete = true; - - if (fd.isCtorDeclaration()) - { - // For constructors, emitting return type is necessary for - // isReturnIsolated() in functionResolve. - tf.isctor = true; - - Dsymbol parent = toParentDecl(); - Type tret; - AggregateDeclaration ad = parent.isAggregateDeclaration(); - if (!ad || parent.isUnionDeclaration()) - { - tret = Type.tvoid; - } - else - { - tret = ad.handleType(); - assert(tret); - tret = tret.addStorageClass(fd.storage_class | scx.stc); - tret = tret.addMod(tf.mod); - } - tf.next = tret; - if (ad && ad.isStructDeclaration()) - tf.isref = 1; - //printf("tf = %s\n", tf.toChars()); - } - else - tf.next = null; - fd.type = tf; - fd.type = fd.type.addSTC(scx.stc); - fd.type = fd.type.typeSemantic(fd.loc, scx); - scx = scx.pop(); - - if (fd.type.ty != Tfunction) - return null; - - fd.originalType = fd.type; // for mangling - //printf("\t[%s] fd.type = %s, mod = %x, ", loc.toChars(), fd.type.toChars(), fd.type.mod); - //printf("fd.needThis() = %d\n", fd.needThis()); - - return fd; - } - debug (FindExistingInstance) { __gshared uint nFound, nNotFound, nAdded, nRemoved; @@ -1145,575 +957,6 @@ extern (C++) final class TypeDeduced : Type } -/************************************************* - * Given function arguments, figure out which template function - * to expand, and return matching result. - * Params: - * m = matching result - * dstart = the root of overloaded function templates - * loc = instantiation location - * sc = instantiation scope - * tiargs = initial list of template arguments - * tthis = if !NULL, the 'this' pointer argument - * argumentList= arguments to function - * errorHelper = delegate to send error message to if not null - */ -void functionResolve(ref MatchAccumulator m, Dsymbol dstart, Loc loc, Scope* sc, Objects* tiargs, - Type tthis, ArgumentList argumentList, void delegate(const(char)*) scope errorHelper = null) -{ - version (none) - { - printf("functionResolve() dstart = %s\n", dstart.toChars()); - printf(" tiargs:\n"); - if (tiargs) - { - for (size_t i = 0; i < tiargs.length; i++) - { - RootObject arg = (*tiargs)[i]; - printf("\t%s\n", arg.toChars()); - } - } - printf(" fargs:\n"); - for (size_t i = 0; i < (fargs ? fargs.length : 0); i++) - { - Expression arg = (*fargs)[i]; - printf("\t%s %s\n", arg.type.toChars(), arg.toChars()); - //printf("\tty = %d\n", arg.type.ty); - } - //printf("stc = %llx\n", dstart._scope.stc); - //printf("match:t/f = %d/%d\n", ta_last, m.last); - } - - // results - int property = 0; // 0: uninitialized - // 1: seen @property - // 2: not @property - size_t ov_index = 0; - TemplateDeclaration td_best; - TemplateInstance ti_best; - MATCH ta_last = m.last != MATCH.nomatch ? MATCH.exact : MATCH.nomatch; - Type tthis_best; - - int applyFunction(FuncDeclaration fd) - { - // skip duplicates - if (fd == m.lastf) - return 0; - // explicitly specified tiargs never match to non template function - if (tiargs && tiargs.length > 0) - return 0; - - // constructors need a valid scope in order to detect semantic errors - if (!fd.isCtorDeclaration && - fd.semanticRun < PASS.semanticdone) - { - Ungag ungag = fd.ungagSpeculative(); - fd.dsymbolSemantic(null); - } - if (fd.semanticRun < PASS.semanticdone) - { - .error(loc, "forward reference to template `%s`", fd.toChars()); - return 1; - } - //printf("fd = %s %s, fargs = %s\n", fd.toChars(), fd.type.toChars(), fargs.toChars()); - auto tf = fd.type.isTypeFunction(); - - int prop = tf.isproperty ? 1 : 2; - if (property == 0) - property = prop; - else if (property != prop) - error(fd.loc, "cannot overload both property and non-property functions"); - - /* For constructors, qualifier check will be opposite direction. - * Qualified constructor always makes qualified object, then will be checked - * that it is implicitly convertible to tthis. - */ - Type tthis_fd = fd.needThis() ? tthis : null; - bool isCtorCall = tthis_fd && fd.isCtorDeclaration(); - if (isCtorCall) - { - //printf("%s tf.mod = x%x tthis_fd.mod = x%x %d\n", tf.toChars(), - // tf.mod, tthis_fd.mod, fd.isReturnIsolated()); - if (MODimplicitConv(tf.mod, tthis_fd.mod) || - tf.isWild() && tf.isShared() == tthis_fd.isShared() || - fd.isReturnIsolated()) - { - /* && tf.isShared() == tthis_fd.isShared()*/ - // Uniquely constructed object can ignore shared qualifier. - // TODO: Is this appropriate? - tthis_fd = null; - } - else - return 0; // MATCH.nomatch - } - /* Fix Issue 17970: - If a struct is declared as shared the dtor is automatically - considered to be shared, but when the struct is instantiated - the instance is no longer considered to be shared when the - function call matching is done. The fix makes it so that if a - struct declaration is shared, when the destructor is called, - the instantiated struct is also considered shared. - */ - if (auto dt = fd.isDtorDeclaration()) - { - auto dtmod = dt.type.toTypeFunction(); - auto shared_dtor = dtmod.mod & MODFlags.shared_; - auto shared_this = tthis_fd !is null ? - tthis_fd.mod & MODFlags.shared_ : 0; - if (shared_dtor && !shared_this) - tthis_fd = dtmod; - else if (shared_this && !shared_dtor && tthis_fd !is null) - tf.mod = tthis_fd.mod; - } - const(char)* failMessage; - const(char)** pMessage = errorHelper ? &failMessage : null; - MATCH mfa = tf.callMatch(tthis_fd, argumentList, 0, errorHelper, sc); - //printf("test1: mfa = %d\n", mfa); - if (failMessage) - errorHelper(failMessage); - if (mfa == MATCH.nomatch) - return 0; - - int firstIsBetter() - { - td_best = null; - ti_best = null; - ta_last = MATCH.exact; - m.last = mfa; - m.lastf = fd; - tthis_best = tthis_fd; - ov_index = 0; - m.count = 1; - return 0; - } - - if (mfa > m.last) return firstIsBetter(); - if (mfa < m.last) return 0; - - /* See if one of the matches overrides the other. - */ - assert(m.lastf); - if (m.lastf.overrides(fd)) return 0; - if (fd.overrides(m.lastf)) return firstIsBetter(); - - /* Try to disambiguate using template-style partial ordering rules. - * In essence, if f() and g() are ambiguous, if f() can call g(), - * but g() cannot call f(), then pick f(). - * This is because f() is "more specialized." - */ - { - MATCH c1 = FuncDeclaration.leastAsSpecialized(fd, m.lastf, argumentList.names); - MATCH c2 = FuncDeclaration.leastAsSpecialized(m.lastf, fd, argumentList.names); - //printf("c1 = %d, c2 = %d\n", c1, c2); - if (c1 > c2) return firstIsBetter(); - if (c1 < c2) return 0; - } - - /* The 'overrides' check above does covariant checking only - * for virtual member functions. It should do it for all functions, - * but in order to not risk breaking code we put it after - * the 'leastAsSpecialized' check. - * In the future try moving it before. - * I.e. a not-the-same-but-covariant match is preferred, - * as it is more restrictive. - */ - if (!m.lastf.type.equals(fd.type)) - { - //printf("cov: %d %d\n", m.lastf.type.covariant(fd.type), fd.type.covariant(m.lastf.type)); - const lastCovariant = m.lastf.type.covariant(fd.type); - const firstCovariant = fd.type.covariant(m.lastf.type); - - if (lastCovariant == Covariant.yes || lastCovariant == Covariant.no) - { - if (firstCovariant != Covariant.yes && firstCovariant != Covariant.no) - { - return 0; - } - } - else if (firstCovariant == Covariant.yes || firstCovariant == Covariant.no) - { - return firstIsBetter(); - } - } - - /* If the two functions are the same function, like: - * int foo(int); - * int foo(int x) { ... } - * then pick the one with the body. - * - * If none has a body then don't care because the same - * real function would be linked to the decl (e.g from object file) - */ - if (tf.equals(m.lastf.type) && - fd.storage_class == m.lastf.storage_class && - fd.parent == m.lastf.parent && - fd.visibility == m.lastf.visibility && - fd._linkage == m.lastf._linkage) - { - if (fd.fbody && !m.lastf.fbody) - return firstIsBetter(); - if (!fd.fbody) - return 0; - } - - // https://issues.dlang.org/show_bug.cgi?id=14450 - // Prefer exact qualified constructor for the creating object type - if (isCtorCall && tf.mod != m.lastf.type.mod) - { - if (tthis.mod == tf.mod) return firstIsBetter(); - if (tthis.mod == m.lastf.type.mod) return 0; - } - - m.nextf = fd; - m.count++; - return 0; - } - - int applyTemplate(TemplateDeclaration td) - { - //printf("applyTemplate(): td = %s\n", td.toChars()); - if (td == td_best) // skip duplicates - return 0; - - if (!sc) - sc = td._scope; // workaround for Type.aliasthisOf - - if (td.semanticRun == PASS.initial && td._scope) - { - // Try to fix forward reference. Ungag errors while doing so. - Ungag ungag = td.ungagSpeculative(); - td.dsymbolSemantic(td._scope); - } - if (td.semanticRun == PASS.initial) - { - .error(loc, "forward reference to template `%s`", td.toChars()); - Lerror: - m.lastf = null; - m.count = 0; - m.last = MATCH.nomatch; - return 1; - } - //printf("td = %s\n", td.toChars()); - - if (argumentList.hasNames) - { - .error(loc, "named arguments with Implicit Function Template Instantiation are not supported yet"); - goto Lerror; - } - auto f = td.onemember ? td.onemember.isFuncDeclaration() : null; - if (!f) - { - if (!tiargs) - tiargs = new Objects(); - auto ti = new TemplateInstance(loc, td, tiargs); - Objects dedtypes = Objects(td.parameters.length); - assert(td.semanticRun != PASS.initial); - MATCH mta = matchWithInstance(sc, td, ti, dedtypes, argumentList, 0); - //printf("matchWithInstance = %d\n", mta); - if (mta == MATCH.nomatch || mta < ta_last) // no match or less match - return 0; - - ti.templateInstanceSemantic(sc, argumentList); - if (!ti.inst) // if template failed to expand - return 0; - - Dsymbol s = ti.inst.toAlias(); - FuncDeclaration fd; - if (auto tdx = s.isTemplateDeclaration()) - { - Objects dedtypesX; // empty tiargs - - // https://issues.dlang.org/show_bug.cgi?id=11553 - // Check for recursive instantiation of tdx. - for (TemplatePrevious* p = tdx.previous; p; p = p.prev) - { - if (arrayObjectMatch(*p.dedargs, dedtypesX)) - { - //printf("recursive, no match p.sc=%p %p %s\n", p.sc, this, this.toChars()); - /* It must be a subscope of p.sc, other scope chains are not recursive - * instantiations. - */ - for (Scope* scx = sc; scx; scx = scx.enclosing) - { - if (scx == p.sc) - { - error(loc, "recursive template expansion while looking for `%s.%s`", ti.toChars(), tdx.toChars()); - goto Lerror; - } - } - } - /* BUG: should also check for ref param differences - */ - } - - TemplatePrevious pr; - pr.prev = tdx.previous; - pr.sc = sc; - pr.dedargs = &dedtypesX; - tdx.previous = ≺ // add this to threaded list - - fd = resolveFuncCall(loc, sc, s, null, tthis, argumentList, FuncResolveFlag.quiet); - - tdx.previous = pr.prev; // unlink from threaded list - } - else if (s.isFuncDeclaration()) - { - fd = resolveFuncCall(loc, sc, s, null, tthis, argumentList, FuncResolveFlag.quiet); - } - else - goto Lerror; - - if (!fd) - return 0; - - if (fd.type.ty != Tfunction) - { - m.lastf = fd; // to propagate "error match" - m.count = 1; - m.last = MATCH.nomatch; - return 1; - } - - Type tthis_fd = fd.needThis() && !fd.isCtorDeclaration() ? tthis : null; - - auto tf = fd.type.isTypeFunction(); - MATCH mfa = tf.callMatch(tthis_fd, argumentList, 0, null, sc); - if (mfa < m.last) - return 0; - - if (mta < ta_last) goto Ltd_best2; - if (mta > ta_last) goto Ltd2; - - if (mfa < m.last) goto Ltd_best2; - if (mfa > m.last) goto Ltd2; - - // td_best and td are ambiguous - //printf("Lambig2\n"); - m.nextf = fd; - m.count++; - return 0; - - Ltd_best2: - return 0; - - Ltd2: - // td is the new best match - assert(td._scope); - td_best = td; - ti_best = null; - property = 0; // (backward compatibility) - ta_last = mta; - m.last = mfa; - m.lastf = fd; - tthis_best = tthis_fd; - ov_index = 0; - m.nextf = null; - m.count = 1; - return 0; - } - - //printf("td = %s\n", td.toChars()); - for (size_t ovi = 0; f; f = f.overnext0, ovi++) - { - if (f.type.ty != Tfunction || f.errors) - goto Lerror; - - /* This is a 'dummy' instance to evaluate constraint properly. - */ - auto ti = new TemplateInstance(loc, td, tiargs); - ti.parent = td.parent; // Maybe calculating valid 'enclosing' is unnecessary. - - auto fd = f; - MATCHpair x = td.deduceFunctionTemplateMatch(ti, sc, fd, tthis, argumentList); - MATCH mta = x.mta; - MATCH mfa = x.mfa; - //printf("match:t/f = %d/%d\n", mta, mfa); - if (!fd || mfa == MATCH.nomatch) - continue; - - Type tthis_fd = fd.needThis() ? tthis : null; - - bool isCtorCall = tthis_fd && fd.isCtorDeclaration(); - if (isCtorCall) - { - // Constructor call requires additional check. - auto tf = fd.type.isTypeFunction(); - assert(tf.next); - if (MODimplicitConv(tf.mod, tthis_fd.mod) || - tf.isWild() && tf.isShared() == tthis_fd.isShared() || - fd.isReturnIsolated()) - { - tthis_fd = null; - } - else - continue; // MATCH.nomatch - - // need to check here whether the constructor is the member of a struct - // declaration that defines a copy constructor. This is already checked - // in the semantic of CtorDeclaration, however, when matching functions, - // the template instance is not expanded. - // https://issues.dlang.org/show_bug.cgi?id=21613 - auto ad = fd.isThis(); - auto sd = ad.isStructDeclaration(); - if (checkHasBothRvalueAndCpCtor(sd, fd.isCtorDeclaration(), ti)) - continue; - } - - if (mta < ta_last) goto Ltd_best; - if (mta > ta_last) goto Ltd; - - if (mfa < m.last) goto Ltd_best; - if (mfa > m.last) goto Ltd; - - if (td_best) - { - // Disambiguate by picking the most specialized TemplateDeclaration - MATCH c1 = leastAsSpecialized(sc, td, td_best, argumentList); - MATCH c2 = leastAsSpecialized(sc, td_best, td, argumentList); - //printf("1: c1 = %d, c2 = %d\n", c1, c2); - if (c1 > c2) goto Ltd; - if (c1 < c2) goto Ltd_best; - } - assert(fd && m.lastf); - { - // Disambiguate by tf.callMatch - auto tf1 = fd.type.isTypeFunction(); - auto tf2 = m.lastf.type.isTypeFunction(); - MATCH c1 = tf1.callMatch(tthis_fd, argumentList, 0, null, sc); - MATCH c2 = tf2.callMatch(tthis_best, argumentList, 0, null, sc); - //printf("2: c1 = %d, c2 = %d\n", c1, c2); - if (c1 > c2) goto Ltd; - if (c1 < c2) goto Ltd_best; - } - { - // Disambiguate by picking the most specialized FunctionDeclaration - MATCH c1 = FuncDeclaration.leastAsSpecialized(fd, m.lastf, argumentList.names); - MATCH c2 = FuncDeclaration.leastAsSpecialized(m.lastf, fd, argumentList.names); - //printf("3: c1 = %d, c2 = %d\n", c1, c2); - if (c1 > c2) goto Ltd; - if (c1 < c2) goto Ltd_best; - } - - // https://issues.dlang.org/show_bug.cgi?id=14450 - // Prefer exact qualified constructor for the creating object type - if (isCtorCall && fd.type.mod != m.lastf.type.mod) - { - if (tthis.mod == fd.type.mod) goto Ltd; - if (tthis.mod == m.lastf.type.mod) goto Ltd_best; - } - - m.nextf = fd; - m.count++; - continue; - - Ltd_best: // td_best is the best match so far - //printf("Ltd_best\n"); - continue; - - Ltd: // td is the new best match - //printf("Ltd\n"); - assert(td._scope); - td_best = td; - ti_best = ti; - property = 0; // (backward compatibility) - ta_last = mta; - m.last = mfa; - m.lastf = fd; - tthis_best = tthis_fd; - ov_index = ovi; - m.nextf = null; - m.count = 1; - continue; - } - return 0; - } - - auto td = dstart.isTemplateDeclaration(); - if (td && td.funcroot) - dstart = td.funcroot; - overloadApply(dstart, (Dsymbol s) - { - if (s.errors) - return 0; - if (auto fd = s.isFuncDeclaration()) - return applyFunction(fd); - if (auto td = s.isTemplateDeclaration()) - return applyTemplate(td); - return 0; - }, sc); - - //printf("td_best = %p, m.lastf = %p\n", td_best, m.lastf); - if (td_best && ti_best && m.count == 1) - { - // Matches to template function - assert(td_best.onemember && td_best.onemember.isFuncDeclaration()); - /* The best match is td_best with arguments tdargs. - * Now instantiate the template. - */ - assert(td_best._scope); - if (!sc) - sc = td_best._scope; // workaround for Type.aliasthisOf - - auto ti = new TemplateInstance(loc, td_best, ti_best.tiargs); - ti.templateInstanceSemantic(sc, argumentList); - - m.lastf = ti.toAlias().isFuncDeclaration(); - if (!m.lastf) - goto Lnomatch; - if (ti.errors) - { - Lerror: - m.count = 1; - assert(m.lastf); - m.last = MATCH.nomatch; - return; - } - - // look forward instantiated overload function - // Dsymbol.oneMembers is alredy called in TemplateInstance.semantic. - // it has filled overnext0d - while (ov_index--) - { - m.lastf = m.lastf.overnext0; - assert(m.lastf); - } - - tthis_best = m.lastf.needThis() && !m.lastf.isCtorDeclaration() ? tthis : null; - - if (m.lastf.type.ty == Terror) - goto Lerror; - auto tf = m.lastf.type.isTypeFunction(); - if (!tf.callMatch(tthis_best, argumentList, 0, null, sc)) - goto Lnomatch; - - /* As https://issues.dlang.org/show_bug.cgi?id=3682 shows, - * a template instance can be matched while instantiating - * that same template. Thus, the function type can be incomplete. Complete it. - * - * https://issues.dlang.org/show_bug.cgi?id=9208 - * For auto function, completion should be deferred to the end of - * its semantic3. Should not complete it in here. - */ - if (tf.next && !m.lastf.inferRetType) - { - m.lastf.type = tf.typeSemantic(loc, sc); - } - } - else if (m.lastf) - { - // Matches to non template function, - // or found matches were ambiguous. - assert(m.count >= 1); - } - else - { - Lnomatch: - m.count = 0; - m.lastf = null; - m.last = MATCH.nomatch; - } -} - /* ======================== Type ============================================ */ /**** @@ -6101,7 +5344,7 @@ extern (C++) class TemplateInstance : ScopeDsymbol { TemplateParameter tp = (*tempdecl.parameters)[i]; //printf("\ttdtypes[%d] = %p\n", i, o); - tempdecl.declareParameter(sc, tp, o); + declareParameter(tempdecl, sc, tp, o); } } diff --git a/gcc/d/dmd/dtoh.d b/gcc/d/dmd/dtoh.d index 2bfa96c..4a1ff05 100644 --- a/gcc/d/dmd/dtoh.d +++ b/gcc/d/dmd/dtoh.d @@ -30,6 +30,7 @@ import dmd.location; import dmd.root.filename; import dmd.visitor; import dmd.tokens; +import dmd.typesem; import dmd.common.outbuffer; import dmd.utils; diff --git a/gcc/d/dmd/enumsem.d b/gcc/d/dmd/enumsem.d index 0603960..3886ca2 100644 --- a/gcc/d/dmd/enumsem.d +++ b/gcc/d/dmd/enumsem.d @@ -503,6 +503,8 @@ void enumMemberSemantic(Scope* sc, EnumMember em) { Expression e = em.value; assert(e.dyncast() == DYNCAST.expression); + if (em.ed.memtype) + e = inferType(e, em.ed.memtype); e = e.expressionSemantic(sc); e = resolveProperties(sc, e); e = e.ctfeInterpret(); @@ -571,6 +573,10 @@ void enumMemberSemantic(Scope* sc, EnumMember em) em.origValue = e; } em.value = e; + // https://issues.dlang.org/show_bug.cgi?id=24311 + // First enum member is .init value, which gets put into static segment + if (first) + lowerStaticAAs(e, sc); } else if (first) { diff --git a/gcc/d/dmd/expression.d b/gcc/d/dmd/expression.d index 1603f2b..82de837 100644 --- a/gcc/d/dmd/expression.d +++ b/gcc/d/dmd/expression.d @@ -48,6 +48,7 @@ import dmd.root.string; import dmd.root.utf; import dmd.target; import dmd.tokens; +import dmd.typesem; import dmd.visitor; enum LOGSEMANTIC = false; @@ -3851,7 +3852,7 @@ extern (C++) final class CastExp : UnaExp if (!e1.isLvalue()) return false; return (to.ty == Tsarray && (e1.type.ty == Tvector || e1.type.ty == Tsarray)) || - e1.type.mutableOf().unSharedOf().equals(to.mutableOf().unSharedOf()); + e1.type.mutableOf.unSharedOf().equals(to.mutableOf().unSharedOf()); } override void accept(Visitor v) diff --git a/gcc/d/dmd/expression.h b/gcc/d/dmd/expression.h index d53cc3e..f713d25 100644 --- a/gcc/d/dmd/expression.h +++ b/gcc/d/dmd/expression.h @@ -55,6 +55,7 @@ Expression *resolveLoc(Expression *exp, const Loc &loc, Scope *sc); MATCH implicitConvTo(Expression *e, Type *t); Expression *toLvalue(Expression *_this, Scope *sc, const char* action); Expression *modifiableLvalue(Expression* exp, Scope *sc); +Expression *optimize(Expression *exp, int result, bool keepLvalue = false); typedef unsigned char OwnedBy; enum @@ -108,8 +109,6 @@ public: Expression *addressOf(); Expression *deref(); - Expression *optimize(int result, bool keepLvalue = false); - int isConst(); virtual bool isIdentical(const Expression *e) const; virtual Optional toBool(); diff --git a/gcc/d/dmd/expressionsem.d b/gcc/d/dmd/expressionsem.d index f213303..d7377db 100644 --- a/gcc/d/dmd/expressionsem.d +++ b/gcc/d/dmd/expressionsem.d @@ -85,6 +85,7 @@ import dmd.traits; import dmd.typesem; import dmd.typinf; import dmd.utils; +import dmd.utils : arrayCastBigEndian; import dmd.visitor; enum LOGSEMANTIC = false; @@ -4242,7 +4243,33 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor size_t u; dchar c; - switch (e.postfix) + if (e.hexString) + { + const data = cast(const ubyte[]) e.peekString(); + switch (e.postfix) + { + case 'd': + e.sz = 4; + e.type = Type.tdstring; + break; + case 'w': + e.sz = 2; + e.type = Type.twstring; + break; + case 'c': + default: + e.type = Type.tstring; + e.sz = 1; + break; + } + if ((e.len % e.sz) != 0) + error(e.loc, "hex string with `%s` type needs to be multiple of %d bytes, not %d", + e.type.toChars(), e.sz, cast(int) e.len); + + e.setData(arrayCastBigEndian(data, e.sz).ptr, e.len / e.sz, e.sz); + e.committed = true; + } + else switch (e.postfix) { case 'd': for (u = 0; u < e.len;) @@ -6263,7 +6290,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor auto ad2 = b.sym; ue.e1 = ue.e1.castTo(sc, ad2.type.addMod(ue.e1.type.mod)); ue.e1 = ue.e1.expressionSemantic(sc); - auto vi = exp.f.findVtblIndex(&ad2.vtbl, cast(int)ad2.vtbl.length); + auto vi = findVtblIndex(exp.f, ad2.vtbl[]); assert(vi >= 0); exp.f = ad2.vtbl[vi].isFuncDeclaration(); assert(exp.f); diff --git a/gcc/d/dmd/func.d b/gcc/d/dmd/func.d index adfecc8..ddf21a2 100644 --- a/gcc/d/dmd/func.d +++ b/gcc/d/dmd/func.d @@ -58,6 +58,7 @@ import dmd.semantic3; import dmd.statement_rewrite_walker; import dmd.statement; import dmd.statementsem; +import dmd.templatesem; import dmd.tokens; import dmd.visitor; @@ -467,29 +468,6 @@ extern (C++) class FuncDeclaration : Declaration return f; } - /**************************************************** - * Check that this function type is properly resolved. - * If not, report "forward reference error" and return true. - */ - extern (D) final bool checkForwardRef(const ref Loc loc) - { - if (!functionSemantic(this)) - return true; - - /* No deco means the functionSemantic() call could not resolve - * forward referenes in the type of this function. - */ - if (!type.deco) - { - bool inSemantic3 = (inferRetType && semanticRun >= PASS.semantic3); - .error(loc, "forward reference to %s`%s`", - (inSemantic3 ? "inferred return type of function " : "").ptr, - toChars()); - return true; - } - return false; - } - override final bool equals(const RootObject o) const { if (this == o) @@ -553,154 +531,6 @@ extern (C++) class FuncDeclaration : Declaration return result; } - /************************************************* - * Find index of function in vtbl[0..length] that - * this function overrides. - * Prefer an exact match to a covariant one. - * Params: - * vtbl = vtable to use - * dim = maximal vtable dimension - * Returns: - * -1 didn't find one - * -2 can't determine because of forward references - */ - final int findVtblIndex(Dsymbols* vtbl, int dim) - { - //printf("findVtblIndex() %s\n", toChars()); - import dmd.typesem : covariant; - - FuncDeclaration mismatch = null; - StorageClass mismatchstc = 0; - int mismatchvi = -1; - int exactvi = -1; - int bestvi = -1; - for (int vi = 0; vi < dim; vi++) - { - FuncDeclaration fdv = (*vtbl)[vi].isFuncDeclaration(); - if (fdv && fdv.ident == ident) - { - if (type.equals(fdv.type)) // if exact match - { - if (fdv.parent.isClassDeclaration()) - { - if (fdv.isFuture()) - { - bestvi = vi; - continue; // keep looking - } - return vi; // no need to look further - } - - if (exactvi >= 0) - { - .error(loc, "%s `%s` cannot determine overridden function", kind, toPrettyChars); - return exactvi; - } - exactvi = vi; - bestvi = vi; - continue; - } - - StorageClass stc = 0; - const cov = type.covariant(fdv.type, &stc); - //printf("\tbaseclass cov = %d\n", cov); - final switch (cov) - { - case Covariant.distinct: - // types are distinct - break; - - case Covariant.yes: - bestvi = vi; // covariant, but not identical - break; - // keep looking for an exact match - - case Covariant.no: - mismatchvi = vi; - mismatchstc = stc; - mismatch = fdv; // overrides, but is not covariant - break; - // keep looking for an exact match - - case Covariant.fwdref: - return -2; // forward references - } - } - } - if (_linkage == LINK.cpp && bestvi != -1) - { - StorageClass stc = 0; - FuncDeclaration fdv = (*vtbl)[bestvi].isFuncDeclaration(); - assert(fdv && fdv.ident == ident); - if (type.covariant(fdv.type, &stc, /*cppCovariant=*/true) == Covariant.no) - { - /* https://issues.dlang.org/show_bug.cgi?id=22351 - * Under D rules, `type` and `fdv.type` are covariant, but under C++ rules, they are not. - * For now, continue to allow D covariant rules to apply when `override` has been used, - * but issue a deprecation warning that this behaviour will change in the future. - * Otherwise, follow the C++ covariant rules, which will create a new vtable entry. - */ - if (isOverride()) - { - /* @@@DEPRECATED_2.110@@@ - * After deprecation period has ended, be sure to remove this entire `LINK.cpp` branch, - * but also the `cppCovariant` parameter from Type.covariant, and update the function - * so that both `LINK.cpp` covariant conditions within are always checked. - */ - .deprecation(loc, "overriding `extern(C++)` function `%s%s` with `const` qualified function `%s%s%s` is deprecated", - fdv.toPrettyChars(), fdv.type.toTypeFunction().parameterList.parametersTypeToChars(), - toPrettyChars(), type.toTypeFunction().parameterList.parametersTypeToChars(), type.modToChars()); - - const char* where = type.isNaked() ? "parameters" : "type"; - deprecationSupplemental(loc, "Either remove `override`, or adjust the `const` qualifiers of the " - ~ "overriding function %s", where); - } - else - { - // Treat as if Covariant.no - mismatchvi = bestvi; - mismatchstc = stc; - mismatch = fdv; - bestvi = -1; - } - } - } - if (bestvi == -1 && mismatch) - { - //type.print(); - //mismatch.type.print(); - //printf("%s %s\n", type.deco, mismatch.type.deco); - //printf("stc = %llx\n", mismatchstc); - if (mismatchstc) - { - // Fix it by modifying the type to add the storage classes - type = type.addStorageClass(mismatchstc); - bestvi = mismatchvi; - } - } - return bestvi; - } - - /********************************* - * If function a function in a base class, - * return that base class. - * Returns: - * base class if overriding, null if not - */ - extern (D) final BaseClass* overrideInterface() - { - for (ClassDeclaration cd = toParent2().isClassDeclaration(); cd; cd = cd.baseClass) - { - foreach (b; cd.interfaces) - { - auto v = findVtblIndex(&b.sym.vtbl, cast(int)b.sym.vtbl.length); - if (v >= 0) - return b; - } - } - return null; - } - /**************************************************** * Overload this FuncDeclaration with the new one f. * Return true if successful; i.e. no conflict. diff --git a/gcc/d/dmd/funcsem.d b/gcc/d/dmd/funcsem.d index 8420179..9e706ee 100644 --- a/gcc/d/dmd/funcsem.d +++ b/gcc/d/dmd/funcsem.d @@ -18,6 +18,7 @@ import core.stdc.stdio; import dmd.aggregate; import dmd.arraytypes; import dmd.astenums; +import dmd.attrib; import dmd.blockexit; import dmd.gluelayer; import dmd.dcast; @@ -39,13 +40,18 @@ import dmd.globals; import dmd.hdrgen; import dmd.id; import dmd.identifier; +import dmd.importc; import dmd.init; import dmd.location; import dmd.mtype; +import dmd.mustuse; import dmd.objc; +import dmd.opover; +import dmd.pragmasem; import dmd.root.aav; import dmd.common.outbuffer; import dmd.rootobject; +import dmd.root.filename; import dmd.root.string; import dmd.root.stringtable; import dmd.semantic2; @@ -53,9 +59,980 @@ import dmd.semantic3; import dmd.statement_rewrite_walker; import dmd.statement; import dmd.statementsem; +import dmd.target; import dmd.tokens; +import dmd.typesem; import dmd.visitor; +/********************************** + * Main semantic routine for functions. + */ +void funcDeclarationSemantic(Scope* sc, FuncDeclaration funcdecl) +{ + version (none) + { + printf("FuncDeclaration::semantic(sc = %p, this = %p, '%s', linkage = %d)\n", sc, funcdecl, funcdecl.toPrettyChars(), sc.linkage); + if (funcdecl.isFuncLiteralDeclaration()) + printf("\tFuncLiteralDeclaration()\n"); + printf("sc.parent = %s, parent = %s\n", sc.parent.toChars(), funcdecl.parent ? funcdecl.parent.toChars() : ""); + printf("type: %p, %s\n", funcdecl.type, funcdecl.type.toChars()); + } + + if (funcdecl.semanticRun != PASS.initial && funcdecl.isFuncLiteralDeclaration()) + { + /* Member functions that have return types that are + * forward references can have semantic() run more than + * once on them. + * See test\interface2.d, test20 + */ + return; + } + + if (funcdecl.semanticRun >= PASS.semanticdone) + return; + assert(funcdecl.semanticRun <= PASS.semantic); + funcdecl.semanticRun = PASS.semantic; + + if (funcdecl._scope) + { + sc = funcdecl._scope; + funcdecl._scope = null; + } + + if (!sc || funcdecl.errors) + return; + + funcdecl.cppnamespace = sc.namespace; + funcdecl.parent = sc.parent; + Dsymbol parent = funcdecl.toParent(); + + funcdecl.foverrides.setDim(0); // reset in case semantic() is being retried for this function + + funcdecl.storage_class |= sc.stc & ~STC.ref_; + AggregateDeclaration ad = funcdecl.isThis(); + // Don't nest structs b/c of generated methods which should not access the outer scopes. + // https://issues.dlang.org/show_bug.cgi?id=16627 + if (ad && !funcdecl.isGenerated()) + { + funcdecl.storage_class |= ad.storage_class & (STC.TYPECTOR | STC.synchronized_); + ad.makeNested(); + } + if (sc.func) + funcdecl.storage_class |= sc.func.storage_class & STC.disable; + // Remove prefix storage classes silently. + if ((funcdecl.storage_class & STC.TYPECTOR) && !(ad || funcdecl.isNested())) + funcdecl.storage_class &= ~STC.TYPECTOR; + + //printf("function storage_class = x%llx, sc.stc = x%llx, %x\n", storage_class, sc.stc, Declaration.isFinal()); + + if (sc.flags & SCOPE.compile) + funcdecl.skipCodegen = true; + + funcdecl._linkage = sc.linkage; + if (sc.flags & SCOPE.Cfile && funcdecl.isFuncLiteralDeclaration()) + funcdecl._linkage = LINK.d; // so they are uniquely mangled + + if (auto fld = funcdecl.isFuncLiteralDeclaration()) + { + if (fld.treq) + { + Type treq = fld.treq; + assert(treq.nextOf().ty == Tfunction); + if (treq.ty == Tdelegate) + fld.tok = TOK.delegate_; + else if (treq.isPtrToFunction()) + fld.tok = TOK.function_; + else + assert(0); + funcdecl._linkage = treq.nextOf().toTypeFunction().linkage; + } + } + + // evaluate pragma(inline) + if (auto pragmadecl = sc.inlining) + funcdecl.inlining = evalPragmaInline(pragmadecl.loc, sc, pragmadecl.args); + + funcdecl.visibility = sc.visibility; + funcdecl.userAttribDecl = sc.userAttribDecl; + UserAttributeDeclaration.checkGNUABITag(funcdecl, funcdecl._linkage); + checkMustUseReserved(funcdecl); + + if (!funcdecl.originalType) + funcdecl.originalType = funcdecl.type.syntaxCopy(); + + static TypeFunction getFunctionType(FuncDeclaration fd) + { + if (auto tf = fd.type.isTypeFunction()) + return tf; + + if (!fd.type.isTypeError()) + { + .error(fd.loc, "%s `%s` `%s` must be a function instead of `%s`", fd.kind, fd.toPrettyChars, fd.toChars(), fd.type.toChars()); + fd.type = Type.terror; + } + fd.errors = true; + return null; + } + + if (sc.flags & SCOPE.Cfile) + { + /* C11 allows a function to be declared with a typedef, D does not. + */ + if (auto ti = funcdecl.type.isTypeIdentifier()) + { + auto tj = ti.typeSemantic(funcdecl.loc, sc); + if (auto tjf = tj.isTypeFunction()) + { + /* Copy the type instead of just pointing to it, + * as we don't merge function types + */ + auto tjf2 = new TypeFunction(tjf.parameterList, tjf.next, tjf.linkage); + funcdecl.type = tjf2; + funcdecl.originalType = tjf2; + } + } + } + + if (!getFunctionType(funcdecl)) + return; + + if (!funcdecl.type.deco) + { + sc = sc.push(); + sc.stc |= funcdecl.storage_class & (STC.disable | STC.deprecated_); // forward to function type + + TypeFunction tf = funcdecl.type.toTypeFunction(); + if (sc.func) + { + /* If the nesting parent is pure without inference, + * then this function defaults to pure too. + * + * auto foo() pure { + * auto bar() {} // become a weak purity function + * class C { // nested class + * auto baz() {} // become a weak purity function + * } + * + * static auto boo() {} // typed as impure + * // Even though, boo cannot call any impure functions. + * // See also Expression::checkPurity(). + * } + */ + if (tf.purity == PURE.impure && (funcdecl.isNested() || funcdecl.isThis())) + { + FuncDeclaration fd = null; + for (Dsymbol p = funcdecl.toParent2(); p; p = p.toParent2()) + { + if (AggregateDeclaration adx = p.isAggregateDeclaration()) + { + if (adx.isNested()) + continue; + break; + } + if ((fd = p.isFuncDeclaration()) !is null) + break; + } + + /* If the parent's purity is inferred, then this function's purity needs + * to be inferred first. + */ + if (fd && fd.isPureBypassingInference() >= PURE.weak && !funcdecl.isInstantiated()) + { + tf.purity = PURE.fwdref; // default to pure + } + } + } + + if (tf.isref) + sc.stc |= STC.ref_; + if (tf.isScopeQual) + sc.stc |= STC.scope_; + if (tf.isnothrow) + sc.stc |= STC.nothrow_; + if (tf.isnogc) + sc.stc |= STC.nogc; + if (tf.isproperty) + sc.stc |= STC.property; + if (tf.purity == PURE.fwdref) + sc.stc |= STC.pure_; + + if (tf.trust != TRUST.default_) + { + sc.stc &= ~STC.safeGroup; + if (tf.trust == TRUST.safe) + sc.stc |= STC.safe; + else if (tf.trust == TRUST.system) + sc.stc |= STC.system; + else if (tf.trust == TRUST.trusted) + sc.stc |= STC.trusted; + } + + if (funcdecl.isCtorDeclaration()) + { + tf.isctor = true; + Type tret = ad.handleType(); + assert(tret); + tret = tret.addStorageClass(funcdecl.storage_class | sc.stc); + tret = tret.addMod(funcdecl.type.mod); + tf.next = tret; + if (ad.isStructDeclaration()) + sc.stc |= STC.ref_; + } + + // 'return' on a non-static class member function implies 'scope' as well + if (ad && ad.isClassDeclaration() && (tf.isreturn || sc.stc & STC.return_) && !(sc.stc & STC.static_)) + sc.stc |= STC.scope_; + + // If 'this' has no pointers, remove 'scope' as it has no meaning + // Note: this is already covered by semantic of `VarDeclaration` and `TypeFunction`, + // but existing code relies on `hasPointers()` being called here to resolve forward references: + // https://github.com/dlang/dmd/pull/14232#issuecomment-1162906573 + if (sc.stc & STC.scope_ && ad && ad.isStructDeclaration() && !ad.type.hasPointers()) + { + sc.stc &= ~STC.scope_; + tf.isScopeQual = false; + if (tf.isreturnscope) + { + sc.stc &= ~(STC.return_ | STC.returnScope); + tf.isreturn = false; + tf.isreturnscope = false; + } + } + + sc.linkage = funcdecl._linkage; + + if (!tf.isNaked() && !(funcdecl.isThis() || funcdecl.isNested())) + { + import core.bitop : popcnt; + auto mods = MODtoChars(tf.mod); + .error(funcdecl.loc, "%s `%s` without `this` cannot be `%s`", funcdecl.kind, funcdecl.toPrettyChars, mods); + if (tf.next && tf.next.ty != Tvoid && popcnt(tf.mod) == 1) + .errorSupplemental(funcdecl.loc, + "did you mean to use `%s(%s)` as the return type?", mods, tf.next.toChars()); + + tf.mod = 0; // remove qualifiers + } + + /* Apply const, immutable, wild and shared storage class + * to the function type. Do this before type semantic. + */ + auto stc = funcdecl.storage_class; + if (funcdecl.type.isImmutable()) + stc |= STC.immutable_; + if (funcdecl.type.isConst()) + stc |= STC.const_; + if (funcdecl.type.isShared() || funcdecl.storage_class & STC.synchronized_) + stc |= STC.shared_; + if (funcdecl.type.isWild()) + stc |= STC.wild; + funcdecl.type = funcdecl.type.addSTC(stc); + + funcdecl.type = funcdecl.type.typeSemantic(funcdecl.loc, sc); + sc = sc.pop(); + } + + auto f = getFunctionType(funcdecl); + if (!f) + return; // funcdecl's type is not a function + + { + // Merge back function attributes into 'originalType'. + // It's used for mangling, ddoc, and json output. + TypeFunction tfo = funcdecl.originalType.toTypeFunction(); + tfo.mod = f.mod; + tfo.isScopeQual = f.isScopeQual; + tfo.isreturninferred = f.isreturninferred; + tfo.isscopeinferred = f.isscopeinferred; + tfo.isref = f.isref; + tfo.isnothrow = f.isnothrow; + tfo.isnogc = f.isnogc; + tfo.isproperty = f.isproperty; + tfo.purity = f.purity; + tfo.trust = f.trust; + + funcdecl.storage_class &= ~(STC.TYPECTOR | STC.FUNCATTR); + } + + // check pragma(crt_constructor) signature + if (funcdecl.isCrtCtor || funcdecl.isCrtDtor) + { + const idStr = funcdecl.isCrtCtor ? "crt_constructor" : "crt_destructor"; + if (f.nextOf().ty != Tvoid) + .error(funcdecl.loc, "%s `%s` must return `void` for `pragma(%s)`", funcdecl.kind, funcdecl.toPrettyChars, idStr.ptr); + if (funcdecl._linkage != LINK.c && f.parameterList.length != 0) + .error(funcdecl.loc, "%s `%s` must be `extern(C)` for `pragma(%s)` when taking parameters", funcdecl.kind, funcdecl.toPrettyChars, idStr.ptr); + if (funcdecl.isThis()) + .error(funcdecl.loc, "%s `%s` cannot be a non-static member function for `pragma(%s)`", funcdecl.kind, funcdecl.toPrettyChars, idStr.ptr); + } + + if (funcdecl.overnext && funcdecl.isCsymbol()) + { + /* C does not allow function overloading, but it does allow + * redeclarations of the same function. If .overnext points + * to a redeclaration, ok. Error if it is an overload. + */ + auto fnext = funcdecl.overnext.isFuncDeclaration(); + funcDeclarationSemantic(sc, fnext); + auto fn = fnext.type.isTypeFunction(); + if (!fn || !cFuncEquivalence(f, fn)) + { + .error(funcdecl.loc, "%s `%s` redeclaration with different type", funcdecl.kind, funcdecl.toPrettyChars); + //printf("t1: %s\n", f.toChars()); + //printf("t2: %s\n", fn.toChars()); + } + funcdecl.overnext = null; // don't overload the redeclarations + } + + if ((funcdecl.storage_class & STC.auto_) && !f.isref && !funcdecl.inferRetType) + .error(funcdecl.loc, "%s `%s` storage class `auto` has no effect if return type is not inferred", funcdecl.kind, funcdecl.toPrettyChars); + + if (f.isreturn && !funcdecl.needThis() && !funcdecl.isNested()) + { + /* Non-static nested functions have a hidden 'this' pointer to which + * the 'return' applies + */ + if (sc.scopesym && sc.scopesym.isAggregateDeclaration()) + .error(funcdecl.loc, "%s `%s` `static` member has no `this` to which `return` can apply", funcdecl.kind, funcdecl.toPrettyChars); + else + error(funcdecl.loc, "top-level function `%s` has no `this` to which `return` can apply", funcdecl.toChars()); + } + + if (funcdecl.isAbstract() && !funcdecl.isVirtual()) + { + const(char)* sfunc; + if (funcdecl.isStatic()) + sfunc = "static"; + else if (funcdecl.visibility.kind == Visibility.Kind.private_ || funcdecl.visibility.kind == Visibility.Kind.package_) + sfunc = visibilityToChars(funcdecl.visibility.kind); + else + sfunc = "final"; + .error(funcdecl.loc, "%s `%s` `%s` functions cannot be `abstract`", funcdecl.kind, funcdecl.toPrettyChars, sfunc); + } + + if (funcdecl.isOverride() && !funcdecl.isVirtual() && !funcdecl.isFuncLiteralDeclaration()) + { + Visibility.Kind kind = funcdecl.visible().kind; + if ((kind == Visibility.Kind.private_ || kind == Visibility.Kind.package_) && funcdecl.isMember()) + .error(funcdecl.loc, "%s `%s` `%s` method is not virtual and cannot override", funcdecl.kind, funcdecl.toPrettyChars, visibilityToChars(kind)); + else + .error(funcdecl.loc, "%s `%s` cannot override a non-virtual function", funcdecl.kind, funcdecl.toPrettyChars); + } + + if (funcdecl.isAbstract() && funcdecl.isFinalFunc()) + .error(funcdecl.loc, "%s `%s` cannot be both `final` and `abstract`", funcdecl.kind, funcdecl.toPrettyChars); + + if (funcdecl.printf || funcdecl.scanf) + { + checkPrintfScanfSignature(funcdecl, f, sc); + } + + if (auto id = parent.isInterfaceDeclaration()) + { + funcdecl.storage_class |= STC.abstract_; + if (funcdecl.isCtorDeclaration() || funcdecl.isPostBlitDeclaration() || funcdecl.isDtorDeclaration() || funcdecl.isInvariantDeclaration() || funcdecl.isNewDeclaration() || funcdecl.isDelete()) + .error(funcdecl.loc, "%s `%s` constructors, destructors, postblits, invariants, new and delete functions are not allowed in interface `%s`", funcdecl.kind, funcdecl.toPrettyChars, id.toChars()); + if (funcdecl.fbody && funcdecl.isVirtual()) + .error(funcdecl.loc, "%s `%s` function body only allowed in `final` functions in interface `%s`", funcdecl.kind, funcdecl.toPrettyChars, id.toChars()); + } + + if (UnionDeclaration ud = parent.isUnionDeclaration()) + { + if (funcdecl.isPostBlitDeclaration() || funcdecl.isDtorDeclaration() || funcdecl.isInvariantDeclaration()) + .error(funcdecl.loc, "%s `%s` destructors, postblits and invariants are not allowed in union `%s`", funcdecl.kind, funcdecl.toPrettyChars, ud.toChars()); + } + + if (StructDeclaration sd = parent.isStructDeclaration()) + { + if (funcdecl.isCtorDeclaration()) + { + goto Ldone; + } + } + + if (ClassDeclaration cd = parent.isClassDeclaration()) + { + parent = cd = objc.getParent(funcdecl, cd); + + if (funcdecl.isCtorDeclaration()) + { + goto Ldone; + } + + if (funcdecl.storage_class & STC.abstract_) + cd.isabstract = ThreeState.yes; + + // if static function, do not put in vtbl[] + if (!funcdecl.isVirtual()) + { + //printf("\tnot virtual\n"); + goto Ldone; + } + // Suppress further errors if the return type is an error + if (funcdecl.type.nextOf() == Type.terror) + goto Ldone; + + bool may_override = false; + for (size_t i = 0; i < cd.baseclasses.length; i++) + { + BaseClass* b = (*cd.baseclasses)[i]; + ClassDeclaration cbd = b.type.toBasetype().isClassHandle(); + if (!cbd) + continue; + for (size_t j = 0; j < cbd.vtbl.length; j++) + { + FuncDeclaration f2 = cbd.vtbl[j].isFuncDeclaration(); + if (!f2 || f2.ident != funcdecl.ident) + continue; + if (cbd.parent && cbd.parent.isTemplateInstance()) + { + if (!functionSemantic(f2)) + goto Ldone; + } + may_override = true; + } + } + if (may_override && funcdecl.type.nextOf() is null) + { + /* If same name function exists in base class but 'this' is auto return, + * cannot find index of base class's vtbl[] to override. + */ + .error(funcdecl.loc, "%s `%s` return type inference is not supported if may override base class function", funcdecl.kind, funcdecl.toPrettyChars); + } + + /* Find index of existing function in base class's vtbl[] to override + * (the index will be the same as in cd's current vtbl[]) + */ + int vi = cd.baseClass ? findVtblIndex(funcdecl, cd.baseClass.vtbl[]) : -1; + + bool doesoverride = false; + switch (vi) + { + case -1: + Lintro: + /* Didn't find one, so + * This is an 'introducing' function which gets a new + * slot in the vtbl[]. + */ + + // Verify this doesn't override previous final function + if (cd.baseClass) + { + Dsymbol s = cd.baseClass.search(funcdecl.loc, funcdecl.ident); + if (s) + { + if (auto f2 = s.isFuncDeclaration()) + { + f2 = f2.overloadExactMatch(funcdecl.type); + if (f2 && f2.isFinalFunc() && f2.visible().kind != Visibility.Kind.private_) + .error(funcdecl.loc, "%s `%s` cannot override `final` function `%s`", funcdecl.kind, funcdecl.toPrettyChars, f2.toPrettyChars()); + } + } + } + + /* These quirky conditions mimic what happens when virtual + inheritance is implemented by producing a virtual base table + with offsets to each of the virtual bases. + */ + if (target.cpp.splitVBasetable && cd.classKind == ClassKind.cpp && + cd.baseClass && cd.baseClass.vtbl.length) + { + /* if overriding an interface function, then this is not + * introducing and don't put it in the class vtbl[] + */ + funcdecl.interfaceVirtual = overrideInterface(funcdecl); + if (funcdecl.interfaceVirtual) + { + //printf("\tinterface function %s\n", toChars()); + cd.vtblFinal.push(funcdecl); + goto Linterfaces; + } + } + + if (funcdecl.isFinalFunc()) + { + // Don't check here, as it may override an interface function + //if (isOverride()) + // error("is marked as override, but does not override any function"); + cd.vtblFinal.push(funcdecl); + } + else + { + //printf("\tintroducing function %s\n", funcdecl.toChars()); + funcdecl.isIntroducing = true; + if (cd.classKind == ClassKind.cpp && target.cpp.reverseOverloads) + { + /* Overloaded functions with same name are grouped and in reverse order. + * Search for first function of overload group, and insert + * funcdecl into vtbl[] immediately before it. + */ + funcdecl.vtblIndex = cast(int)cd.vtbl.length; + bool found; + foreach (const i, s; cd.vtbl) + { + if (found) + // the rest get shifted forward + ++s.isFuncDeclaration().vtblIndex; + else if (s.ident == funcdecl.ident && s.parent == parent) + { + // found first function of overload group + funcdecl.vtblIndex = cast(int)i; + found = true; + ++s.isFuncDeclaration().vtblIndex; + } + } + cd.vtbl.insert(funcdecl.vtblIndex, funcdecl); + + debug foreach (const i, s; cd.vtbl) + { + // a C++ dtor gets its vtblIndex later (and might even be added twice to the vtbl), + // e.g. when compiling druntime with a debug compiler, namely with core.stdcpp.exception. + if (auto fd = s.isFuncDeclaration()) + assert(fd.vtblIndex == i || + (cd.classKind == ClassKind.cpp && fd.isDtorDeclaration) || + funcdecl.parent.isInterfaceDeclaration); // interface functions can be in multiple vtbls + } + } + else + { + // Append to end of vtbl[] + vi = cast(int)cd.vtbl.length; + cd.vtbl.push(funcdecl); + funcdecl.vtblIndex = vi; + } + } + break; + + case -2: + // can't determine because of forward references + funcdecl.errors = true; + return; + + default: + { + if (vi >= cd.vtbl.length) + { + /* the derived class cd doesn't have its vtbl[] allocated yet. + * https://issues.dlang.org/show_bug.cgi?id=21008 + */ + .error(funcdecl.loc, "%s `%s` circular reference to class `%s`", funcdecl.kind, funcdecl.toPrettyChars, cd.toChars()); + funcdecl.errors = true; + return; + } + FuncDeclaration fdv = cd.baseClass.vtbl[vi].isFuncDeclaration(); + FuncDeclaration fdc = cd.vtbl[vi].isFuncDeclaration(); + // This function is covariant with fdv + + if (fdc == funcdecl) + { + doesoverride = true; + break; + } + + auto vtf = getFunctionType(fdv); + if (vtf.trust > TRUST.system && f.trust == TRUST.system) + .error(funcdecl.loc, "%s `%s` cannot override `@safe` method `%s` with a `@system` attribute", funcdecl.kind, funcdecl.toPrettyChars, + fdv.toPrettyChars); + + if (fdc.toParent() == parent) + { + //printf("vi = %d,\tthis = %p %s %s @ [%s]\n\tfdc = %p %s %s @ [%s]\n\tfdv = %p %s %s @ [%s]\n", + // vi, this, this.toChars(), this.type.toChars(), this.loc.toChars(), + // fdc, fdc .toChars(), fdc .type.toChars(), fdc .loc.toChars(), + // fdv, fdv .toChars(), fdv .type.toChars(), fdv .loc.toChars()); + + // fdc overrides fdv exactly, then this introduces new function. + if (fdc.type.mod == fdv.type.mod && funcdecl.type.mod != fdv.type.mod) + goto Lintro; + } + + if (fdv.isDeprecated && !funcdecl.isDeprecated) + deprecation(funcdecl.loc, "`%s` is overriding the deprecated method `%s`", + funcdecl.toPrettyChars, fdv.toPrettyChars); + + // This function overrides fdv + if (fdv.isFinalFunc()) + .error(funcdecl.loc, "%s `%s` cannot override `final` function `%s`", funcdecl.kind, funcdecl.toPrettyChars, fdv.toPrettyChars()); + + if (!funcdecl.isOverride()) + { + if (fdv.isFuture()) + { + deprecation(funcdecl.loc, "`@__future` base class method `%s` is being overridden by `%s`; rename the latter", fdv.toPrettyChars(), funcdecl.toPrettyChars()); + // Treat 'this' as an introducing function, giving it a separate hierarchy in the vtbl[] + goto Lintro; + } + else + { + // https://issues.dlang.org/show_bug.cgi?id=17349 + error(funcdecl.loc, "cannot implicitly override base class method `%s` with `%s`; add `override` attribute", + fdv.toPrettyChars(), funcdecl.toPrettyChars()); + } + } + doesoverride = true; + if (fdc.toParent() == parent) + { + // If both are mixins, or both are not, then error. + // If either is not, the one that is not overrides the other. + bool thismixin = funcdecl.parent.isClassDeclaration() !is null; + bool fdcmixin = fdc.parent.isClassDeclaration() !is null; + if (thismixin == fdcmixin) + { + .error(funcdecl.loc, "%s `%s` multiple overrides of same function", funcdecl.kind, funcdecl.toPrettyChars); + } + /* + * https://issues.dlang.org/show_bug.cgi?id=711 + * + * If an overriding method is introduced through a mixin, + * we need to update the vtbl so that both methods are + * present. + */ + else if (thismixin) + { + /* if the mixin introduced the overriding method, then reintroduce it + * in the vtbl. The initial entry for the mixined method + * will be updated at the end of the enclosing `if` block + * to point to the current (non-mixined) function. + */ + auto vitmp = cast(int)cd.vtbl.length; + cd.vtbl.push(fdc); + fdc.vtblIndex = vitmp; + } + else if (fdcmixin) + { + /* if the current overriding function is coming from a + * mixined block, then push the current function in the + * vtbl, but keep the previous (non-mixined) function as + * the overriding one. + */ + auto vitmp = cast(int)cd.vtbl.length; + cd.vtbl.push(funcdecl); + funcdecl.vtblIndex = vitmp; + break; + } + else // fdc overrides fdv + { + // this doesn't override any function + break; + } + } + cd.vtbl[vi] = funcdecl; + funcdecl.vtblIndex = vi; + + /* Remember which functions this overrides + */ + funcdecl.foverrides.push(fdv); + + /* This works by whenever this function is called, + * it actually returns tintro, which gets dynamically + * cast to type. But we know that tintro is a base + * of type, so we could optimize it by not doing a + * dynamic cast, but just subtracting the isBaseOf() + * offset if the value is != null. + */ + + if (fdv.tintro) + funcdecl.tintro = fdv.tintro; + else if (!funcdecl.type.equals(fdv.type)) + { + auto tnext = funcdecl.type.nextOf(); + if (auto handle = tnext.isClassHandle()) + { + if (handle.semanticRun < PASS.semanticdone && !handle.isBaseInfoComplete()) + handle.dsymbolSemantic(null); + } + /* Only need to have a tintro if the vptr + * offsets differ + */ + int offset; + if (fdv.type.nextOf().isBaseOf(tnext, &offset)) + { + funcdecl.tintro = fdv.type; + } + } + break; + } + } + + /* Go through all the interface bases. + * If this function is covariant with any members of those interface + * functions, set the tintro. + */ + Linterfaces: + bool foundVtblMatch = false; + + for (ClassDeclaration bcd = cd; !foundVtblMatch && bcd; bcd = bcd.baseClass) + { + foreach (b; bcd.interfaces) + { + vi = findVtblIndex(funcdecl, b.sym.vtbl[]); + switch (vi) + { + case -1: + break; + + case -2: + // can't determine because of forward references + funcdecl.errors = true; + return; + + default: + { + auto fdv = cast(FuncDeclaration)b.sym.vtbl[vi]; + Type ti = null; + + foundVtblMatch = true; + + /* Remember which functions this overrides + */ + funcdecl.foverrides.push(fdv); + + if (fdv.tintro) + ti = fdv.tintro; + else if (!funcdecl.type.equals(fdv.type)) + { + /* Only need to have a tintro if the vptr + * offsets differ + */ + int offset; + if (fdv.type.nextOf().isBaseOf(funcdecl.type.nextOf(), &offset)) + { + ti = fdv.type; + } + } + if (ti) + { + if (funcdecl.tintro) + { + if (!funcdecl.tintro.nextOf().equals(ti.nextOf()) && !funcdecl.tintro.nextOf().isBaseOf(ti.nextOf(), null) && !ti.nextOf().isBaseOf(funcdecl.tintro.nextOf(), null)) + { + .error(funcdecl.loc, "%s `%s` incompatible covariant types `%s` and `%s`", funcdecl.kind, funcdecl.toPrettyChars, funcdecl.tintro.toChars(), ti.toChars()); + } + } + else + { + funcdecl.tintro = ti; + } + } + } + } + } + } + if (foundVtblMatch) + { + goto L2; + } + + if (!doesoverride && funcdecl.isOverride() && (funcdecl.type.nextOf() || !may_override)) + { + BaseClass* bc = null; + Dsymbol s = null; + for (size_t i = 0; i < cd.baseclasses.length; i++) + { + bc = (*cd.baseclasses)[i]; + s = bc.sym.search_correct(funcdecl.ident); + if (s) + break; + } + + if (s) + { + HdrGenState hgs; + OutBuffer buf; + + auto fd = s.isFuncDeclaration(); + functionToBufferFull(cast(TypeFunction)(funcdecl.type), buf, + new Identifier(funcdecl.toPrettyChars()), hgs, null); + const(char)* funcdeclToChars = buf.peekChars(); + + if (fd) + { + OutBuffer buf1; + + if (fd.ident == funcdecl.ident) + hgs.fullQual = true; + + // https://issues.dlang.org/show_bug.cgi?id=23745 + // If the potentially overridden function contains errors, + // inform the user to fix that one first + if (fd.errors) + { + error(funcdecl.loc, "function `%s` does not override any function, did you mean to override `%s`?", + funcdecl.toChars(), fd.toPrettyChars()); + errorSupplemental(fd.loc, "Function `%s` contains errors in its declaration, therefore it cannot be correctly overridden", + fd.toPrettyChars()); + } + else + { + functionToBufferFull(cast(TypeFunction)(fd.type), buf1, + new Identifier(fd.toPrettyChars()), hgs, null); + + error(funcdecl.loc, "function `%s` does not override any function, did you mean to override `%s`?", + funcdeclToChars, buf1.peekChars()); + } + } + else + { + error(funcdecl.loc, "function `%s` does not override any function, did you mean to override %s `%s`?", + funcdeclToChars, s.kind, s.toPrettyChars()); + errorSupplemental(funcdecl.loc, "Functions are the only declarations that may be overridden"); + } + } + else + .error(funcdecl.loc, "%s `%s` does not override any function", funcdecl.kind, funcdecl.toPrettyChars); + } + + L2: + objc.setSelector(funcdecl, sc); + objc.checkLinkage(funcdecl); + objc.addToClassMethodList(funcdecl, cd); + objc.setAsOptional(funcdecl, sc); + + /* Go through all the interface bases. + * Disallow overriding any final functions in the interface(s). + */ + foreach (b; cd.interfaces) + { + if (b.sym) + { + if (auto s = search_function(b.sym, funcdecl.ident)) + { + if (auto f2 = s.isFuncDeclaration()) + { + f2 = f2.overloadExactMatch(funcdecl.type); + if (f2 && f2.isFinalFunc() && f2.visible().kind != Visibility.Kind.private_) + .error(funcdecl.loc, "%s `%s` cannot override `final` function `%s.%s`", funcdecl.kind, funcdecl.toPrettyChars, b.sym.toChars(), f2.toPrettyChars()); + } + } + } + } + + if (funcdecl.isOverride) + { + if (funcdecl.storage_class & STC.disable) + deprecation(funcdecl.loc, + "`%s` cannot be annotated with `@disable` because it is overriding a function in the base class", + funcdecl.toPrettyChars); + + if (funcdecl.isDeprecated && !(funcdecl.foverrides.length && funcdecl.foverrides[0].isDeprecated)) + deprecation(funcdecl.loc, + "`%s` cannot be marked as `deprecated` because it is overriding a function in the base class", + funcdecl.toPrettyChars); + } + + } + else if (funcdecl.isOverride() && !parent.isTemplateInstance()) + .error(funcdecl.loc, "%s `%s` `override` only applies to class member functions", funcdecl.kind, funcdecl.toPrettyChars); + + if (auto ti = parent.isTemplateInstance) + { + objc.setSelector(funcdecl, sc); + objc.setAsOptional(funcdecl, sc); + } + + objc.validateSelector(funcdecl); + objc.validateOptional(funcdecl); + // Reflect this.type to f because it could be changed by findVtblIndex + f = funcdecl.type.toTypeFunction(); + +Ldone: + if (!funcdecl.fbody && !funcdecl.allowsContractWithoutBody()) + .error(funcdecl.loc, "%s `%s` `in` and `out` contracts can only appear without a body when they are virtual interface functions or abstract", funcdecl.kind, funcdecl.toPrettyChars); + + /* Do not allow template instances to add virtual functions + * to a class. + */ + if (funcdecl.isVirtual()) + { + if (auto ti = parent.isTemplateInstance()) + { + // Take care of nested templates + while (1) + { + TemplateInstance ti2 = ti.tempdecl.parent.isTemplateInstance(); + if (!ti2) + break; + ti = ti2; + } + + // If it's a member template + ClassDeclaration cd = ti.tempdecl.isClassMember(); + if (cd) + { + .error(funcdecl.loc, "%s `%s` cannot use template to add virtual function to class `%s`", funcdecl.kind, funcdecl.toPrettyChars, cd.toChars()); + } + } + } + + funcdecl.checkMain(); // Check main() parameters and return type + + /* Purity and safety can be inferred for some functions by examining + * the function body. + */ + if (funcdecl.canInferAttributes(sc)) + funcdecl.initInferAttributes(); + + funcdecl.semanticRun = PASS.semanticdone; + + /* Save scope for possible later use (if we need the + * function internals) + */ + funcdecl._scope = sc.copy(); + funcdecl._scope.setNoFree(); + + __gshared bool printedMain = false; // semantic might run more than once + if (global.params.v.verbose && !printedMain) + { + const(char)* type = funcdecl.isMain() ? "main" : funcdecl.isWinMain() ? "winmain" : funcdecl.isDllMain() ? "dllmain" : cast(const(char)*)null; + Module mod = sc._module; + + if (type && mod) + { + printedMain = true; + auto name = mod.srcfile.toChars(); + auto path = FileName.searchPath(global.path, name, true); + message("entry %-10s\t%s", type, path ? path : name); + } + } + + if (funcdecl.fbody && sc._module.isRoot() && + (funcdecl.isMain() || funcdecl.isWinMain() || funcdecl.isDllMain() || funcdecl.isCMain())) + global.hasMainFunction = true; + + if (funcdecl.fbody && funcdecl.isMain() && sc._module.isRoot()) + { + // check if `_d_cmain` is defined + bool cmainTemplateExists() + { + Dsymbol pscopesym; + auto rootSymbol = sc.search(funcdecl.loc, Id.empty, pscopesym); + if (auto moduleSymbol = rootSymbol.search(funcdecl.loc, Id.object)) + if (moduleSymbol.search(funcdecl.loc, Id.CMain)) + return true; + + return false; + } + + // Only mixin `_d_cmain` if it is defined + if (cmainTemplateExists()) + { + // add `mixin _d_cmain!();` to the declaring module + auto tqual = new TypeIdentifier(funcdecl.loc, Id.CMain); + auto tm = new TemplateMixin(funcdecl.loc, null, tqual, null); + sc._module.members.push(tm); + } + } + + assert(funcdecl.type.ty != Terror || funcdecl.errors); + + // semantic for parameters' UDAs + foreach (i, param; f.parameterList) + { + if (param && param.userAttribDecl) + param.userAttribDecl.dsymbolSemantic(sc); + } +} + + /**************************************************** * Resolve forward reference of function signature - * parameter types, return type, and attributes. @@ -217,3 +1194,176 @@ extern (D) void declareThis(FuncDeclaration fd, Scope* sc) if (ad) fd.objc.selectorParameter = .objc.createSelectorParameter(fd, sc); } + +/**************************************************** + * Check that this function type is properly resolved. + * If not, report "forward reference error" and return true. + */ +extern (D) bool checkForwardRef(FuncDeclaration fd, const ref Loc loc) +{ + if (!functionSemantic(fd)) + return true; + + /* No deco means the functionSemantic() call could not resolve + * forward referenes in the type of this function. + */ + if (!fd.type.deco) + { + bool inSemantic3 = (fd.inferRetType && fd.semanticRun >= PASS.semantic3); + .error(loc, "forward reference to %s`%s`", + (inSemantic3 ? "inferred return type of function " : "").ptr, + fd.toChars()); + return true; + } + return false; +} + +/************************************************* + * Find index of function in vtbl[0..length] that + * this function overrides. + * Prefer an exact match to a covariant one. + * Params: + * fd = function + * vtbl = vtable to use + * Returns: + * -1 didn't find one + * -2 can't determine because of forward references + */ +int findVtblIndex(FuncDeclaration fd, Dsymbol[] vtbl) +{ + //printf("findVtblIndex() %s\n", toChars()); + import dmd.typesem : covariant; + + FuncDeclaration mismatch = null; + StorageClass mismatchstc = 0; + int mismatchvi = -1; + int exactvi = -1; + int bestvi = -1; + for (int vi = 0; vi < cast(int)vtbl.length; vi++) + { + FuncDeclaration fdv = vtbl[vi].isFuncDeclaration(); + if (fdv && fdv.ident == fd.ident) + { + if (fd.type.equals(fdv.type)) // if exact match + { + if (fdv.parent.isClassDeclaration()) + { + if (fdv.isFuture()) + { + bestvi = vi; + continue; // keep looking + } + return vi; // no need to look further + } + + if (exactvi >= 0) + { + .error(fd.loc, "%s `%s` cannot determine overridden function", fd.kind, fd.toPrettyChars); + return exactvi; + } + exactvi = vi; + bestvi = vi; + continue; + } + + StorageClass stc = 0; + const cov = fd.type.covariant(fdv.type, &stc); + //printf("\tbaseclass cov = %d\n", cov); + final switch (cov) + { + case Covariant.distinct: + // types are distinct + break; + + case Covariant.yes: + bestvi = vi; // covariant, but not identical + break; + // keep looking for an exact match + + case Covariant.no: + mismatchvi = vi; + mismatchstc = stc; + mismatch = fdv; // overrides, but is not covariant + break; + // keep looking for an exact match + + case Covariant.fwdref: + return -2; // forward references + } + } + } + if (fd._linkage == LINK.cpp && bestvi != -1) + { + StorageClass stc = 0; + FuncDeclaration fdv = vtbl[bestvi].isFuncDeclaration(); + assert(fdv && fdv.ident == fd.ident); + if (fd.type.covariant(fdv.type, &stc, /*cppCovariant=*/true) == Covariant.no) + { + /* https://issues.dlang.org/show_bug.cgi?id=22351 + * Under D rules, `type` and `fdv.type` are covariant, but under C++ rules, they are not. + * For now, continue to allow D covariant rules to apply when `override` has been used, + * but issue a deprecation warning that this behaviour will change in the future. + * Otherwise, follow the C++ covariant rules, which will create a new vtable entry. + */ + if (fd.isOverride()) + { + /* @@@DEPRECATED_2.110@@@ + * After deprecation period has ended, be sure to remove this entire `LINK.cpp` branch, + * but also the `cppCovariant` parameter from Type.covariant, and update the function + * so that both `LINK.cpp` covariant conditions within are always checked. + */ + .deprecation(fd.loc, "overriding `extern(C++)` function `%s%s` with `const` qualified function `%s%s%s` is deprecated", + fdv.toPrettyChars(), fdv.type.toTypeFunction().parameterList.parametersTypeToChars(), + fd.toPrettyChars(), fd.type.toTypeFunction().parameterList.parametersTypeToChars(), fd.type.modToChars()); + + const char* where = fd.type.isNaked() ? "parameters" : "type"; + deprecationSupplemental(fd.loc, "Either remove `override`, or adjust the `const` qualifiers of the " + ~ "overriding function %s", where); + } + else + { + // Treat as if Covariant.no + mismatchvi = bestvi; + mismatchstc = stc; + mismatch = fdv; + bestvi = -1; + } + } + } + if (bestvi == -1 && mismatch) + { + //type.print(); + //mismatch.type.print(); + //printf("%s %s\n", type.deco, mismatch.type.deco); + //printf("stc = %llx\n", mismatchstc); + if (mismatchstc) + { + // Fix it by modifying the type to add the storage classes + fd.type = fd.type.addStorageClass(mismatchstc); + bestvi = mismatchvi; + } + } + return bestvi; +} + +/********************************* + * If function is a function in a base class, + * return that base class. + * Params: + * fd = function + * Returns: + * base class if overriding, null if not + */ +BaseClass* overrideInterface(FuncDeclaration fd) +{ + for (ClassDeclaration cd = fd.toParent2().isClassDeclaration(); cd; cd = cd.baseClass) + { + foreach (b; cd.interfaces) + { + auto v = findVtblIndex(fd, b.sym.vtbl[]); + if (v >= 0) + return b; + } + } + return null; +} diff --git a/gcc/d/dmd/hdrgen.d b/gcc/d/dmd/hdrgen.d index 030153c..e4cbcc5 100644 --- a/gcc/d/dmd/hdrgen.d +++ b/gcc/d/dmd/hdrgen.d @@ -50,6 +50,7 @@ import dmd.root.string; import dmd.statement; import dmd.staticassert; import dmd.tokens; +import dmd.typesem; import dmd.visitor; struct HdrGenState @@ -1552,7 +1553,7 @@ void toCBuffer(Dsymbol s, ref OutBuffer buf, ref HdrGenState hgs) buf.writeByte('}'); buf.writenl(); - if (!hgs.importcHdr) + if (!hgs.importcHdr || !d.ident) return; /* C enums get their members inserted into the symbol table of the enum declaration. diff --git a/gcc/d/dmd/initsem.d b/gcc/d/dmd/initsem.d index 5fe3b93..79d7902 100644 --- a/gcc/d/dmd/initsem.d +++ b/gcc/d/dmd/initsem.d @@ -30,6 +30,7 @@ import dmd.errors; import dmd.expression; import dmd.expressionsem; import dmd.func; +import dmd.funcsem; import dmd.globals; import dmd.hdrgen; import dmd.id; @@ -59,36 +60,33 @@ Expression toAssocArrayLiteral(ArrayInitializer ai) { //printf("ArrayInitializer::toAssocArrayInitializer(%s)\n", ai.toChars()); //static int i; if (++i == 2) assert(0); - const dim = ai.value.length; - if (!dim) - { - error(ai.loc, "invalid associative array initializer `%s`, use `null` instead", - toChars(ai)); - return ErrorExp.get(); - } + auto no(const char* format, Initializer i) { error(i.loc, format, toChars(i)); return ErrorExp.get(); } - Expression e; - auto keys = new Expressions(dim); + + const dim = ai.value.length; + if (!dim) + return no("invalid associative array initializer `%s`, use `null` instead", ai); + + auto keys = new Expressions(dim); auto values = new Expressions(dim); - for (size_t i = 0; i < dim; i++) + foreach (i, iz; ai.value[]) { - Initializer iz = ai.value[i]; assert(iz); - e = iz.initializerToExpression(); - if (!e) + auto ev = iz.initializerToExpression(); + if (!ev) return no("invalid value `%s` in initializer", iz); - (*values)[i] = e; - e = ai.index[i]; - if (!e) + (*values)[i] = ev; + + auto ei = ai.index[i]; + if (!ei) return no("missing key for value `%s` in initializer", iz); - (*keys)[i] = e; + (*keys)[i] = ei; } - e = new AssocArrayLiteralExp(ai.loc, keys, values); - return e; + return new AssocArrayLiteralExp(ai.loc, keys, values); } /****************************************** @@ -138,8 +136,12 @@ extern(C++) Initializer initializerSemantic(Initializer init, Scope* sc, ref Typ /* This works by replacing the StructInitializer with an ExpInitializer. */ t = t.toBasetype(); - if (t.ty == Tsarray && t.nextOf().toBasetype().ty == Tstruct) - t = t.nextOf().toBasetype(); + if (auto tsa = t.isTypeSArray()) + { + auto ts = tsa.nextOf().toBasetype().isTypeStruct(); + if (ts) + t = ts; + } if (auto ts = t.isTypeStruct()) { StructDeclaration sd = ts.sym; @@ -154,16 +156,17 @@ extern(C++) Initializer initializerSemantic(Initializer init, Scope* sc, ref Typ if (sd.sizeok != Sizeok.done) return err(); - Expression getExp(size_t j, Type fieldType) - { - // Convert initializer to Expression `ex` - auto tm = fieldType.addMod(t.mod); - auto iz = i.value[j].initializerSemantic(sc, tm, needInterpret); - auto ex = iz.initializerToExpression(null, (sc.flags & SCOPE.Cfile) != 0); - if (ex.op != EXP.error) - i.value[j] = iz; - return ex; - } + Expression getExp(size_t j, Type fieldType) + { + // Convert initializer to Expression `ex` + auto tm = fieldType.addMod(t.mod); + auto iz = i.value[j].initializerSemantic(sc, tm, needInterpret); + auto ex = iz.initializerToExpression(null, (sc.flags & SCOPE.Cfile) != 0); + if (ex.op != EXP.error) + i.value[j] = iz; + return ex; + } + auto elements = resolveStructLiteralNamedArgs(sd, t, sc, i.loc, i.field[], &getExp, (size_t j) => i.value[j].loc); if (!elements) return err(); @@ -232,17 +235,19 @@ extern(C++) Initializer initializerSemantic(Initializer init, Scope* sc, ref Typ auto ei = new ExpInitializer(e.loc, e); return ei.initializerSemantic(sc, t, needInterpret); } + case Tpointer: - if (t.nextOf().ty != Tfunction) - break; - goto default; + if (t.nextOf().isTypeFunction()) + goto default; + break; + default: error(i.loc, "cannot use array to initialize `%s`", t.toChars()); return err(); } i.type = t; length = 0; - for (size_t j = 0; j < i.index.length; j++) + for (size_t j = 0; j < i.index.length; j++) // don't replace with foreach; j is modified { Expression idx = i.index[j]; if (idx) @@ -277,9 +282,8 @@ extern(C++) Initializer initializerSemantic(Initializer init, Scope* sc, ref Typ TupleExp te = ei.exp.isTupleExp(); i.index.remove(j); i.value.remove(j); - for (size_t k = 0; k < te.exps.length; ++k) + foreach (k, e; (*te.exps)[]) { - Expression e = (*te.exps)[k]; i.index.insert(j + k, cast(Expression)null); i.value.insert(j + k, new ExpInitializer(e.loc, e)); } @@ -290,7 +294,7 @@ extern(C++) Initializer initializerSemantic(Initializer init, Scope* sc, ref Typ { i.value[j] = val; } - length++; + ++length; if (length == 0) { error(i.loc, "array dimension overflow"); @@ -311,7 +315,7 @@ extern(C++) Initializer initializerSemantic(Initializer init, Scope* sc, ref Typ } else { - uinteger_t edim = tsa.dim.toInteger(); + ulong edim = tsa.dim.toInteger(); if (i.dim > edim) { error(i.loc, "array initializer has %u elements, but array length is %llu", i.dim, edim); @@ -347,7 +351,7 @@ extern(C++) Initializer initializerSemantic(Initializer init, Scope* sc, ref Typ sc = sc.endCTFE(); if (i.exp.op == EXP.error) return err(); - uint olderrors = global.errors; + const olderrors = global.errors; /* ImportC: convert arrays to pointers, functions to pointers to functions */ @@ -1170,7 +1174,7 @@ Initializer inferType(Initializer init, Scope* sc) bool hasOverloads; if (auto f = isFuncAddress(init.exp, &hasOverloads)) { - if (f.checkForwardRef(init.loc)) + if (checkForwardRef(f, init.loc)) { return new ErrorInitializer(); } diff --git a/gcc/d/dmd/mtype.d b/gcc/d/dmd/mtype.d index 276f209..c46f560 100644 --- a/gcc/d/dmd/mtype.d +++ b/gcc/d/dmd/mtype.d @@ -52,6 +52,12 @@ enum LOGDEFAULTINIT = 0; // log ::defaultInit() enum SIZE_INVALID = (~cast(uinteger_t)0); // error return from size() functions +static if (__VERSION__ < 2095) +{ + // Fix linker errors when building with older compilers. + // See: https://issues.dlang.org/show_bug.cgi?id=21299 + private alias StringValueType = StringValue!Type; +} /*************************** * Return !=0 if modfrom can be implicitly converted to modto @@ -299,7 +305,7 @@ extern (C++) abstract class Type : ASTNode Type swto; // MODFlags.shared_ | MODFlags.wild Type swcto; // MODFlags.shared_ | MODFlags.wildconst } - private Mcache* mcache; + Mcache* mcache; Type pto; // merged pointer to this type Type rto; // reference to this type @@ -440,7 +446,7 @@ extern (C++) abstract class Type : ASTNode final bool equivalent(Type t) { - return immutableOf().equals(t.immutableOf()); + return immutableOf(this).equals(t.immutableOf()); } // kludge for template.isType() @@ -785,255 +791,6 @@ extern (C++) abstract class Type : ASTNode return t; } - /******************************** - * Convert to 'const'. - */ - final Type constOf() - { - //printf("Type::constOf() %p %s\n", this, toChars()); - if (mod == MODFlags.const_) - return this; - if (mcache && mcache.cto) - { - assert(mcache.cto.mod == MODFlags.const_); - return mcache.cto; - } - Type t = makeConst(); - t = t.merge(); - t.fixTo(this); - //printf("-Type::constOf() %p %s\n", t, t.toChars()); - return t; - } - - /******************************** - * Convert to 'immutable'. - */ - final Type immutableOf() - { - //printf("Type::immutableOf() %p %s\n", this, toChars()); - if (isImmutable()) - return this; - if (mcache && mcache.ito) - { - assert(mcache.ito.isImmutable()); - return mcache.ito; - } - Type t = makeImmutable(); - t = t.merge(); - t.fixTo(this); - //printf("\t%p\n", t); - return t; - } - - /******************************** - * Make type mutable. - */ - final Type mutableOf() - { - //printf("Type::mutableOf() %p, %s\n", this, toChars()); - Type t = this; - if (isImmutable()) - { - getMcache(); - t = mcache.ito; // immutable => naked - assert(!t || (t.isMutable() && !t.isShared())); - } - else if (isConst()) - { - getMcache(); - if (isShared()) - { - if (isWild()) - t = mcache.swcto; // shared wild const -> shared - else - t = mcache.sto; // shared const => shared - } - else - { - if (isWild()) - t = mcache.wcto; // wild const -> naked - else - t = mcache.cto; // const => naked - } - assert(!t || t.isMutable()); - } - else if (isWild()) - { - getMcache(); - if (isShared()) - t = mcache.sto; // shared wild => shared - else - t = mcache.wto; // wild => naked - assert(!t || t.isMutable()); - } - if (!t) - { - t = makeMutable(); - t = t.merge(); - t.fixTo(this); - } - else - t = t.merge(); - assert(t.isMutable()); - return t; - } - - final Type sharedOf() - { - //printf("Type::sharedOf() %p, %s\n", this, toChars()); - if (mod == MODFlags.shared_) - return this; - if (mcache && mcache.sto) - { - assert(mcache.sto.mod == MODFlags.shared_); - return mcache.sto; - } - Type t = makeShared(); - t = t.merge(); - t.fixTo(this); - //printf("\t%p\n", t); - return t; - } - - final Type sharedConstOf() - { - //printf("Type::sharedConstOf() %p, %s\n", this, toChars()); - if (mod == (MODFlags.shared_ | MODFlags.const_)) - return this; - if (mcache && mcache.scto) - { - assert(mcache.scto.mod == (MODFlags.shared_ | MODFlags.const_)); - return mcache.scto; - } - Type t = makeSharedConst(); - t = t.merge(); - t.fixTo(this); - //printf("\t%p\n", t); - return t; - } - - /******************************** - * Make type unshared. - * 0 => 0 - * const => const - * immutable => immutable - * shared => 0 - * shared const => const - * wild => wild - * wild const => wild const - * shared wild => wild - * shared wild const => wild const - */ - final Type unSharedOf() - { - //printf("Type::unSharedOf() %p, %s\n", this, toChars()); - Type t = this; - - if (isShared()) - { - getMcache(); - if (isWild()) - { - if (isConst()) - t = mcache.wcto; // shared wild const => wild const - else - t = mcache.wto; // shared wild => wild - } - else - { - if (isConst()) - t = mcache.cto; // shared const => const - else - t = mcache.sto; // shared => naked - } - assert(!t || !t.isShared()); - } - - if (!t) - { - t = this.nullAttributes(); - t.mod = mod & ~MODFlags.shared_; - t.ctype = ctype; - t = t.merge(); - t.fixTo(this); - } - else - t = t.merge(); - assert(!t.isShared()); - return t; - } - - /******************************** - * Convert to 'wild'. - */ - final Type wildOf() - { - //printf("Type::wildOf() %p %s\n", this, toChars()); - if (mod == MODFlags.wild) - return this; - if (mcache && mcache.wto) - { - assert(mcache.wto.mod == MODFlags.wild); - return mcache.wto; - } - Type t = makeWild(); - t = t.merge(); - t.fixTo(this); - //printf("\t%p %s\n", t, t.toChars()); - return t; - } - - final Type wildConstOf() - { - //printf("Type::wildConstOf() %p %s\n", this, toChars()); - if (mod == MODFlags.wildconst) - return this; - if (mcache && mcache.wcto) - { - assert(mcache.wcto.mod == MODFlags.wildconst); - return mcache.wcto; - } - Type t = makeWildConst(); - t = t.merge(); - t.fixTo(this); - //printf("\t%p %s\n", t, t.toChars()); - return t; - } - - final Type sharedWildOf() - { - //printf("Type::sharedWildOf() %p, %s\n", this, toChars()); - if (mod == (MODFlags.shared_ | MODFlags.wild)) - return this; - if (mcache && mcache.swto) - { - assert(mcache.swto.mod == (MODFlags.shared_ | MODFlags.wild)); - return mcache.swto; - } - Type t = makeSharedWild(); - t = t.merge(); - t.fixTo(this); - //printf("\t%p %s\n", t, t.toChars()); - return t; - } - - final Type sharedWildConstOf() - { - //printf("Type::sharedWildConstOf() %p, %s\n", this, toChars()); - if (mod == (MODFlags.shared_ | MODFlags.wildconst)) - return this; - if (mcache && mcache.swcto) - { - assert(mcache.swcto.mod == (MODFlags.shared_ | MODFlags.wildconst)); - return mcache.swcto; - } - Type t = makeSharedWildConst(); - t = t.merge(); - t.fixTo(this); - //printf("\t%p %s\n", t, t.toChars()); - return t; - } - /********************************** * For our new type 'this', which is type-constructed from t, * fill in the cto, ito, sto, scto, wto shortcuts. @@ -1435,56 +1192,6 @@ extern (C++) abstract class Type : ASTNode } /************************************ - * Apply MODxxxx bits to existing type. - */ - final Type castMod(MOD mod) - { - Type t; - switch (mod) - { - case 0: - t = unSharedOf().mutableOf(); - break; - - case MODFlags.const_: - t = unSharedOf().constOf(); - break; - - case MODFlags.wild: - t = unSharedOf().wildOf(); - break; - - case MODFlags.wildconst: - t = unSharedOf().wildConstOf(); - break; - - case MODFlags.shared_: - t = mutableOf().sharedOf(); - break; - - case MODFlags.shared_ | MODFlags.const_: - t = sharedConstOf(); - break; - - case MODFlags.shared_ | MODFlags.wild: - t = sharedWildOf(); - break; - - case MODFlags.shared_ | MODFlags.wildconst: - t = sharedWildConstOf(); - break; - - case MODFlags.immutable_: - t = immutableOf(); - break; - - default: - assert(0); - } - return t; - } - - /************************************ * Add MODxxxx bits to existing type. * We're adding, not replacing, so adding const to * a shared type => "shared const" @@ -1506,16 +1213,16 @@ extern (C++) abstract class Type : ASTNode if (isShared()) { if (isWild()) - t = sharedWildConstOf(); + t = this.sharedWildConstOf(); else - t = sharedConstOf(); + t = this.sharedConstOf(); } else { - if (isWild()) - t = wildConstOf(); + if (this.isWild()) + t = this.wildConstOf(); else - t = constOf(); + t = t.constOf(); } break; @@ -1523,63 +1230,63 @@ extern (C++) abstract class Type : ASTNode if (isShared()) { if (isConst()) - t = sharedWildConstOf(); + t = this.sharedWildConstOf(); else - t = sharedWildOf(); + t = this.sharedWildOf(); } else { if (isConst()) - t = wildConstOf(); + t = this.wildConstOf(); else - t = wildOf(); + t = this.wildOf(); } break; case MODFlags.wildconst: if (isShared()) - t = sharedWildConstOf(); + t = this.sharedWildConstOf(); else - t = wildConstOf(); + t = this.wildConstOf(); break; case MODFlags.shared_: if (isWild()) { if (isConst()) - t = sharedWildConstOf(); + t = this.sharedWildConstOf(); else - t = sharedWildOf(); + t = this.sharedWildOf(); } else { if (isConst()) - t = sharedConstOf(); + t = this.sharedConstOf(); else - t = sharedOf(); + t = this.sharedOf(); } break; case MODFlags.shared_ | MODFlags.const_: if (isWild()) - t = sharedWildConstOf(); + t = this.sharedWildConstOf(); else - t = sharedConstOf(); + t = this.sharedConstOf(); break; case MODFlags.shared_ | MODFlags.wild: if (isConst()) - t = sharedWildConstOf(); + t = this.sharedWildConstOf(); else - t = sharedWildOf(); + t = this.sharedWildOf(); break; case MODFlags.shared_ | MODFlags.wildconst: - t = sharedWildConstOf(); + t = this.sharedWildConstOf(); break; case MODFlags.immutable_: - t = immutableOf(); + t = this.immutableOf(); break; default: @@ -1990,7 +1697,7 @@ extern (C++) abstract class Type : ASTNode final Type unqualify(uint m) { - Type t = mutableOf().unSharedOf(); + Type t = this.mutableOf().unSharedOf(); Type tn = ty == Tenum ? null : nextOf(); if (tn && tn.ty != Tfunction) diff --git a/gcc/d/dmd/mtype.h b/gcc/d/dmd/mtype.h index 8b0a1b2..a7a41c6 100644 --- a/gcc/d/dmd/mtype.h +++ b/gcc/d/dmd/mtype.h @@ -142,11 +142,7 @@ public: TY ty; MOD mod; // modifiers MODxxxx char *deco; - -private: void* mcache; - -public: Type *pto; // merged pointer to this type Type *rto; // reference to this type Type *arrayof; // array of this type @@ -257,17 +253,6 @@ public: bool isSharedWild() const { return (mod & (MODshared | MODwild)) == (MODshared | MODwild); } bool isNaked() const { return mod == 0; } Type *nullAttributes() const; - Type *constOf(); - Type *immutableOf(); - Type *mutableOf(); - Type *sharedOf(); - Type *sharedConstOf(); - Type *unSharedOf(); - Type *wildOf(); - Type *wildConstOf(); - Type *sharedWildOf(); - Type *sharedWildConstOf(); - Type *castMod(MOD mod); Type *addMod(MOD mod); virtual Type *addStorageClass(StorageClass stc); Type *pointerTo(); @@ -909,3 +894,14 @@ bool isBaseOf(Type *tthis, Type *t, int *poffset); Type *trySemantic(Type *type, const Loc &loc, Scope *sc); void purityLevel(TypeFunction *type); Type *merge2(Type *type); +Type *constOf(Type *type); +Type *immutableOf(Type *type); +Type *mutableOf(Type *type); +Type *sharedOf(Type *type); +Type *sharedConstOf(Type *type); +Type *unSharedOf(Type *type); +Type *wildOf(Type *type); +Type *wildConstOf(Type *type); +Type *sharedWildOf(Type *type); +Type *sharedWildConstOf(Type *type); +Type *castMod(Type *type, MOD mod); diff --git a/gcc/d/dmd/opover.d b/gcc/d/dmd/opover.d index d596b84..70eeaff 100644 --- a/gcc/d/dmd/opover.d +++ b/gcc/d/dmd/opover.d @@ -37,6 +37,7 @@ import dmd.location; import dmd.mtype; import dmd.optimize; import dmd.statement; +import dmd.templatesem; import dmd.tokens; import dmd.typesem; import dmd.visitor; diff --git a/gcc/d/dmd/optimize.d b/gcc/d/dmd/optimize.d index f86abde..5c0ef67 100644 --- a/gcc/d/dmd/optimize.d +++ b/gcc/d/dmd/optimize.d @@ -33,6 +33,7 @@ import dmd.printast; import dmd.root.ctfloat; import dmd.sideeffect; import dmd.tokens; +import dmd.typesem; import dmd.visitor; /************************************* @@ -272,7 +273,7 @@ package void setLengthVarIfKnown(VarDeclaration lengthVar, Type type) * Returns: * Constant folded version of `e` */ -Expression optimize(Expression e, int result, bool keepLvalue = false) +extern (C++) Expression optimize(Expression e, int result, bool keepLvalue = false) { //printf("optimize() e: %s result: %d keepLvalue %d\n", e.toChars(), result, keepLvalue); Expression ret = e; diff --git a/gcc/d/dmd/pragmasem.d b/gcc/d/dmd/pragmasem.d new file mode 100644 index 0000000..b52b551 --- /dev/null +++ b/gcc/d/dmd/pragmasem.d @@ -0,0 +1,650 @@ +/** + * Does semantic analysis for pragmas. + * + * Specification: $(LINK2 https://dlang.org/spec/pragma.html, Pragmas) + * + * Copyright: Copyright (C) 1999-2023 by The D Language Foundation, All Rights Reserved + * Authors: $(LINK2 https://www.digitalmars.com, Walter Bright) + * License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) + * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/pragmasem.d, _pragmasem.d) + * Documentation: https://dlang.org/phobos/dmd_pragmasem.html + * Coverage: https://codecov.io/gh/dlang/dmd/src/master/src/dmd/pragmasem.d + */ + +module dmd.pragmasem; + +import core.stdc.stdio; + +import dmd.astenums; +import dmd.arraytypes; +import dmd.attrib; +import dmd.dinterpret; +import dmd.dscope; +import dmd.dsymbol; +import dmd.errors; +import dmd.expression; +import dmd.expressionsem; +import dmd.globals; +import dmd.location; +import dmd.id; +import dmd.statement; + +/** + * Run semantic on `pragma` declaration. + * + * Params: + * pd = pragma declaration or statement to evaluate + * sc = enclosing scope + */ +void pragmaDeclSemantic(PragmaDeclaration pd, Scope* sc) +{ + import dmd.aggregate; + import dmd.common.outbuffer; + import dmd.dmangle; + import dmd.dmodule; + import dmd.dsymbolsem; + import dmd.identifier; + import dmd.root.rmem; + import dmd.root.utf; + import dmd.target; + import dmd.utils; + + StringExp verifyMangleString(ref Expression e) + { + auto se = semanticString(sc, e, "mangled name"); + if (!se) + return null; + e = se; + if (!se.len) + { + .error(pd.loc, "%s `%s` - zero-length string not allowed for mangled name", pd.kind, pd.toPrettyChars); + return null; + } + if (se.sz != 1) + { + .error(pd.loc, "%s `%s` - mangled name characters can only be of type `char`", pd.kind, pd.toPrettyChars); + return null; + } + version (all) + { + /* Note: D language specification should not have any assumption about backend + * implementation. Ideally pragma(mangle) can accept a string of any content. + * + * Therefore, this validation is compiler implementation specific. + */ + auto slice = se.peekString(); + for (size_t i = 0; i < se.len;) + { + dchar c = slice[i]; + if (c < 0x80) + { + if (c.isValidMangling) + { + ++i; + continue; + } + else + { + .error(pd.loc, "%s `%s` char 0x%02x not allowed in mangled name", pd.kind, pd.toPrettyChars, c); + break; + } + } + if (const msg = utf_decodeChar(slice, i, c)) + { + .error(pd.loc, "%s `%s` %.*s", pd.kind, pd.toPrettyChars, cast(int)msg.length, msg.ptr); + break; + } + if (!isUniAlpha(c)) + { + .error(pd.loc, "%s `%s` char `0x%04x` not allowed in mangled name", pd.kind, pd.toPrettyChars, c); + break; + } + } + } + return se; + } + void declarations() + { + if (!pd.decl) + return; + + Scope* sc2 = pd.newScope(sc); + scope(exit) + if (sc2 != sc) + sc2.pop(); + + foreach (s; (*pd.decl)[]) + { + if (pd.ident == Id.printf || pd.ident == Id.scanf) + { + s.setPragmaPrintf(pd.ident == Id.printf); + s.dsymbolSemantic(sc2); + continue; + } + + s.dsymbolSemantic(sc2); + if (pd.ident != Id.mangle) + continue; + assert(pd.args); + if (auto ad = s.isAggregateDeclaration()) + { + Expression e = (*pd.args)[0]; + sc2 = sc2.startCTFE(); + e = e.expressionSemantic(sc); + e = resolveProperties(sc2, e); + sc2 = sc2.endCTFE(); + AggregateDeclaration agg; + if (auto tc = e.type.isTypeClass()) + agg = tc.sym; + else if (auto ts = e.type.isTypeStruct()) + agg = ts.sym; + ad.pMangleOverride = new MangleOverride; + void setString(ref Expression e) + { + if (auto se = verifyMangleString(e)) + { + const name = (cast(const(char)[])se.peekData()).xarraydup; + ad.pMangleOverride.id = Identifier.idPool(name); + e = se; + } + else + error(e.loc, "must be a string"); + } + if (agg) + { + ad.pMangleOverride.agg = agg; + if (pd.args.length == 2) + { + setString((*pd.args)[1]); + } + else + ad.pMangleOverride.id = agg.ident; + } + else + setString((*pd.args)[0]); + } + else if (auto td = s.isTemplateDeclaration()) + { + .error(pd.loc, "%s `%s` cannot apply to a template declaration", pd.kind, pd.toPrettyChars); + errorSupplemental(pd.loc, "use `template Class(Args...){ pragma(mangle, \"other_name\") class Class {} }`"); + } + else if (auto se = verifyMangleString((*pd.args)[0])) + { + const name = (cast(const(char)[])se.peekData()).xarraydup; + uint cnt = setMangleOverride(s, name); + if (cnt > 1) + .error(pd.loc, "%s `%s` can only apply to a single declaration", pd.kind, pd.toPrettyChars); + } + } + } + + void noDeclarations() + { + if (pd.decl) + { + .error(pd.loc, "%s `%s` is missing a terminating `;`", pd.kind, pd.toPrettyChars); + declarations(); + // do them anyway, to avoid segfaults. + } + } + + // Should be merged with PragmaStatement + //printf("\tpragmaDeclSemantic '%s'\n", pd.toChars()); + if (target.supportsLinkerDirective()) + { + if (pd.ident == Id.linkerDirective) + { + if (!pd.args || pd.args.length != 1) + .error(pd.loc, "%s `%s` one string argument expected for pragma(linkerDirective)", pd.kind, pd.toPrettyChars); + else + { + auto se = semanticString(sc, (*pd.args)[0], "linker directive"); + if (!se) + return noDeclarations(); + (*pd.args)[0] = se; + if (global.params.v.verbose) + message("linkopt %.*s", cast(int)se.len, se.peekString().ptr); + } + return noDeclarations(); + } + } + if (pd.ident == Id.msg) + { + if (!pd.args) + return noDeclarations(); + + if (!pragmaMsgSemantic(pd.loc, sc, pd.args)) + return; + + return noDeclarations(); + } + else if (pd.ident == Id.lib) + { + if (!pd.args || pd.args.length != 1) + .error(pd.loc, "%s `%s` string expected for library name", pd.kind, pd.toPrettyChars); + else + { + auto se = semanticString(sc, (*pd.args)[0], "library name"); + if (!se) + return noDeclarations(); + (*pd.args)[0] = se; + + auto name = se.peekString().xarraydup; + if (global.params.v.verbose) + message("library %s", name.ptr); + if (global.params.moduleDeps.buffer && !global.params.moduleDeps.name) + { + OutBuffer* ob = global.params.moduleDeps.buffer; + Module imod = sc._module; + ob.writestring("depsLib "); + ob.writestring(imod.toPrettyChars()); + ob.writestring(" ("); + escapePath(ob, imod.srcfile.toChars()); + ob.writestring(") : "); + ob.writestring(name); + ob.writenl(); + } + mem.xfree(name.ptr); + } + return noDeclarations(); + } + else if (pd.ident == Id.startaddress) + { + pragmaStartAddressSemantic(pd.loc, sc, pd.args); + return noDeclarations(); + } + else if (pd.ident == Id.Pinline) + { + // this pragma now gets evaluated on demand in function semantic + + return declarations(); + } + else if (pd.ident == Id.mangle) + { + if (!pd.args) + pd.args = new Expressions(); + if (pd.args.length == 0 || pd.args.length > 2) + { + .error(pd.loc, pd.args.length == 0 ? "%s `%s` - string expected for mangled name" + : "%s `%s` expected 1 or 2 arguments", pd.kind, pd.toPrettyChars); + pd.args.setDim(1); + (*pd.args)[0] = ErrorExp.get(); // error recovery + } + return declarations(); + } + else if (pd.ident == Id.crt_constructor || pd.ident == Id.crt_destructor) + { + if (pd.args && pd.args.length != 0) + .error(pd.loc, "%s `%s` takes no argument", pd.kind, pd.toPrettyChars); + else + { + immutable isCtor = pd.ident == Id.crt_constructor; + + static uint recurse(Dsymbol s, bool isCtor) + { + if (auto ad = s.isAttribDeclaration()) + { + uint nestedCount; + auto decls = ad.include(null); + if (decls) + { + for (size_t i = 0; i < decls.length; ++i) + nestedCount += recurse((*decls)[i], isCtor); + } + return nestedCount; + } + else if (auto f = s.isFuncDeclaration()) + { + if (isCtor) + f.isCrtCtor = true; + else + f.isCrtDtor = true; + + return 1; + } + else + return 0; + assert(0); + } + + if (recurse(pd, isCtor) > 1) + .error(pd.loc, "%s `%s` can only apply to a single declaration", pd.kind, pd.toPrettyChars); + } + return declarations(); + } + else if (pd.ident == Id.printf || pd.ident == Id.scanf) + { + if (pd.args && pd.args.length != 0) + .error(pd.loc, "%s `%s` takes no argument", pd.kind, pd.toPrettyChars); + return declarations(); + } + else if (!global.params.ignoreUnsupportedPragmas) + { + error(pd.loc, "unrecognized `pragma(%s)`", pd.ident.toChars()); + return declarations(); + } + + if (!global.params.v.verbose) + return declarations(); + + /* Print unrecognized pragmas + */ + OutBuffer buf; + buf.writestring(pd.ident.toString()); + if (pd.args) + { + const errors_save = global.startGagging(); + for (size_t i = 0; i < pd.args.length; i++) + { + Expression e = (*pd.args)[i]; + sc = sc.startCTFE(); + e = e.expressionSemantic(sc); + e = resolveProperties(sc, e); + sc = sc.endCTFE(); + e = e.ctfeInterpret(); + if (i == 0) + buf.writestring(" ("); + else + buf.writeByte(','); + buf.writestring(e.toChars()); + } + if (pd.args.length) + buf.writeByte(')'); + global.endGagging(errors_save); + } + message("pragma %s", buf.peekChars()); + return declarations(); +} + +/** + * Run semantic on `pragma` statement. + * + * Params: + * ps = pragma statement to evaluate + * sc = enclosing scope + * + * Returns : true if `pragma` is valid, or false if an error was found + */ +bool pragmaStmtSemantic(PragmaStatement ps, Scope* sc) +{ + import dmd.statementsem; + + /* https://dlang.org/spec/statement.html#pragma-statement + */ + // Should be merged with PragmaDeclaration + + //printf("pragmaStmtSemantic() %s\n", ps.toChars()); + //printf("body = %p\n", ps._body); + if (ps.ident == Id.msg) + { + if (!pragmaMsgSemantic(ps.loc, sc, ps.args)) + return false; + } + else if (ps.ident == Id.lib) + { + version (all) + { + /* Should this be allowed? + */ + error(ps.loc, "`pragma(lib)` not allowed as statement"); + return false; + } + else + { + if (!ps.args || ps.args.length != 1) + { + error(ps.loc, "`string` expected for library name"); + return false; + } + else + { + auto se = semanticString(sc, (*ps.args)[0], "library name"); + if (!se) + return false; + + if (global.params.v.verbose) + { + message("library %.*s", cast(int)se.len, se.string); + } + } + } + } + else if (ps.ident == Id.linkerDirective) + { + /* Should this be allowed? + */ + error(ps.loc, "`pragma(linkerDirective)` not allowed as statement"); + return false; + } + else if (ps.ident == Id.startaddress) + { + if (!pragmaStartAddressSemantic(ps.loc, sc, ps.args)) + return false; + } + else if (ps.ident == Id.Pinline) + { + if (auto fd = sc.func) + { + fd.inlining = evalPragmaInline(ps.loc, sc, ps.args); + } + else + { + error(ps.loc, "`pragma(inline)` is not inside a function"); + return false; + } + } + else if (ps.ident == Id.mangle) + { + auto es = ps._body ? ps._body.isExpStatement() : null; + auto de = es ? es.exp.isDeclarationExp() : null; + if (!de) + { + error(ps.loc, "`pragma(mangle)` must be attached to a declaration"); + return false; + } + const se = ps.args && (*ps.args).length == 1 ? semanticString(sc, (*ps.args)[0], "pragma mangle argument") : null; + if (!se) + { + error(ps.loc, "`pragma(mangle)` takes a single argument that must be a string literal"); + return false; + } + const cnt = setMangleOverride(de.declaration, cast(const(char)[])se.peekData()); + if (cnt != 1) + assert(0); + } + else if (!global.params.ignoreUnsupportedPragmas) + { + error(ps.loc, "unrecognized `pragma(%s)`", ps.ident.toChars()); + return false; + } + + if (ps._body) + { + if (ps.ident == Id.msg || ps.ident == Id.startaddress) + { + error(ps.loc, "`pragma(%s)` is missing a terminating `;`", ps.ident.toChars()); + return false; + } + ps._body = ps._body.statementSemantic(sc); + } + return true; +} + +/*************************************** + * Interpret a `pragma(inline, x)` + * + * Params: + * loc = location for error messages + * sc = scope for evaluation of argument + * args = pragma arguments + * Returns: corresponding `PINLINE` state + */ +package PINLINE evalPragmaInline(Loc loc, Scope* sc, Expressions* args) +{ + if (!args || args.length == 0) + return PINLINE.default_; + + if (args && args.length > 1) + { + .error(loc, "one boolean expression expected for `pragma(inline)`, not %llu", cast(ulong) args.length); + args.setDim(1); + (*args)[0] = ErrorExp.get(); + } + + Expression e = (*args)[0]; + if (!e.type) + { + sc = sc.startCTFE(); + e = e.expressionSemantic(sc); + e = resolveProperties(sc, e); + sc = sc.endCTFE(); + e = e.ctfeInterpret(); + e = e.toBoolean(sc); + if (e.isErrorExp()) + .error(loc, "pragma(`inline`, `true` or `false`) expected, not `%s`", (*args)[0].toChars()); + (*args)[0] = e; + } + + const opt = e.toBool(); + if (opt.isEmpty()) + return PINLINE.default_; + else if (opt.get()) + return PINLINE.always; + else + return PINLINE.never; +} + +/** + * Apply pragma mangle to FuncDeclarations and VarDeclarations + * under `s`, poking through attribute declarations such as + * `extern(C)` but not through aggregates or function bodies. + * + * Params: + * s = symbol to apply + * sym = overriding symbol name + */ +private uint setMangleOverride(Dsymbol s, const(char)[] sym) +{ + if (s.isFuncDeclaration() || s.isVarDeclaration()) + { + s.isDeclaration().mangleOverride = sym; + return 1; + } + + if (auto ad = s.isAttribDeclaration()) + { + uint nestedCount = 0; + + ad.include(null).foreachDsymbol( (s) { nestedCount += setMangleOverride(s, sym); } ); + + return nestedCount; + } + return 0; +} + +/*********************************************************** + * Evaluate and print a `pragma(msg, args)` + * + * Params: + * loc = location for error messages + * sc = scope for argument interpretation + * args = expressions to print + * Returns: + * `true` on success + */ +private bool pragmaMsgSemantic(Loc loc, Scope* sc, Expressions* args) +{ + import dmd.tokens; + + if (!args) + return true; + foreach (arg; *args) + { + sc = sc.startCTFE(); + auto e = arg.expressionSemantic(sc); + e = resolveProperties(sc, e); + sc = sc.endCTFE(); + + // pragma(msg) is allowed to contain types as well as expressions + e = ctfeInterpretForPragmaMsg(e); + if (e.op == EXP.error) + { + errorSupplemental(loc, "while evaluating `pragma(msg, %s)`", arg.toChars()); + return false; + } + if (auto se = e.toStringExp()) + { + const slice = se.toUTF8(sc).peekString(); + fprintf(stderr, "%.*s", cast(int)slice.length, slice.ptr); + } + else + fprintf(stderr, "%s", e.toChars()); + } + fprintf(stderr, "\n"); + return true; +} + +/** + * Apply pragma printf/scanf to FuncDeclarations under `s`, + * poking through attribute declarations such as `extern(C)` + * but not through aggregates or function bodies. + * + * Params: + * s = symbol to apply + * printf = `true` for printf, `false` for scanf + */ +private void setPragmaPrintf(Dsymbol s, bool printf) +{ + if (auto fd = s.isFuncDeclaration()) + { + fd.printf = printf; + fd.scanf = !printf; + } + + if (auto ad = s.isAttribDeclaration()) + { + ad.include(null).foreachDsymbol( (s) { setPragmaPrintf(s, printf); } ); + } +} + +/*********************************************************** + * Evaluate `pragma(startAddress, func)` and store the resolved symbol in `args` + * + * Params: + * loc = location for error messages + * sc = scope for argument interpretation + * args = pragma arguments + * Returns: + * `true` on success + */ +private bool pragmaStartAddressSemantic(Loc loc, Scope* sc, Expressions* args) +{ + import dmd.dtemplate; + + if (!args || args.length != 1) + { + .error(loc, "function name expected for start address"); + return false; + } + else + { + /* https://issues.dlang.org/show_bug.cgi?id=11980 + * resolveProperties and ctfeInterpret call are not necessary. + */ + Expression e = (*args)[0]; + sc = sc.startCTFE(); + e = e.expressionSemantic(sc); + // e = resolveProperties(sc, e); + sc = sc.endCTFE(); + + // e = e.ctfeInterpret(); + (*args)[0] = e; + Dsymbol sa = getDsymbol(e); + if (!sa || !sa.isFuncDeclaration()) + { + .error(loc, "function name expected for start address, not `%s`", e.toChars()); + return false; + } + } + return true; +} diff --git a/gcc/d/dmd/scope.h b/gcc/d/dmd/scope.h index 4b157cc..f36a14b 100644 --- a/gcc/d/dmd/scope.h +++ b/gcc/d/dmd/scope.h @@ -131,5 +131,5 @@ struct Scope AliasDeclaration *aliasAsg; // if set, then aliasAsg is being assigned a new value, // do not set wasRead for it - Dsymbol *search(const Loc &loc, Identifier *ident, Dsymbol **pscopesym, SearchOptFlags flags = (SearchOptFlags)SearchOpt::all); + Dsymbol *search(const Loc &loc, Identifier *ident, Dsymbol *&pscopesym, SearchOptFlags flags = (SearchOptFlags)SearchOpt::all); }; diff --git a/gcc/d/dmd/semantic2.d b/gcc/d/dmd/semantic2.d index 937e746..b4f91ac 100644 --- a/gcc/d/dmd/semantic2.d +++ b/gcc/d/dmd/semantic2.d @@ -829,7 +829,8 @@ private void doGNUABITagSemantic(ref Expression e, ref Expression* lastTag) } /** - * Try lower a variable's static Associative Array to a newaa struct. + * Try lower a variable's Associative Array initializer to a newaa struct + * so it can be put in static data. * Params: * vd = Variable to lower * sc = Scope @@ -839,11 +840,20 @@ void lowerStaticAAs(VarDeclaration vd, Scope* sc) if (vd.storage_class & STC.manifest) return; if (auto ei = vd._init.isExpInitializer()) - { - scope v = new StaticAAVisitor(sc); - v.vd = vd; - ei.exp.accept(v); - } + lowerStaticAAs(ei.exp, sc); +} + +/** + * Try lower all Associative Array literals in an expression to a newaa struct + * so it can be put in static data. + * Params: + * e = Expression to traverse + * sc = Scope + */ +void lowerStaticAAs(Expression e, Scope* sc) +{ + scope v = new StaticAAVisitor(sc); + e.accept(v); } /// Visit Associative Array literals and lower them to structs for static initialization @@ -851,7 +861,6 @@ private extern(C++) final class StaticAAVisitor : SemanticTimeTransitiveVisitor { alias visit = SemanticTimeTransitiveVisitor.visit; Scope* sc; - VarDeclaration vd; this(Scope* sc) scope @safe { diff --git a/gcc/d/dmd/sideeffect.d b/gcc/d/dmd/sideeffect.d index 8038770..1d4745a 100644 --- a/gcc/d/dmd/sideeffect.d +++ b/gcc/d/dmd/sideeffect.d @@ -19,6 +19,7 @@ import dmd.expression; import dmd.expressionsem; import dmd.func; import dmd.globals; +import dmd.id; import dmd.identifier; import dmd.init; import dmd.mtype; @@ -270,6 +271,15 @@ bool discardValue(Expression e) break; } case EXP.call: + // https://issues.dlang.org/show_bug.cgi?id=24359 + auto ce = e.isCallExp(); + if (const f = ce.f) + { + if (f.ident == Id.__equals && ce.arguments && ce.arguments.length == 2) + { + return discardValue(new EqualExp(EXP.equal, e.loc, (*ce.arguments)[0], (*ce.arguments)[1])); + } + } return false; case EXP.andAnd: case EXP.orOr: diff --git a/gcc/d/dmd/statementsem.d b/gcc/d/dmd/statementsem.d index 840035c..a431d5c 100644 --- a/gcc/d/dmd/statementsem.d +++ b/gcc/d/dmd/statementsem.d @@ -16,12 +16,10 @@ module dmd.statementsem; import core.stdc.stdio; import dmd.aggregate; -import dmd.aliasthis; import dmd.arrayop; import dmd.arraytypes; import dmd.astcodegen; import dmd.astenums; -import dmd.attrib; import dmd.blockexit; import dmd.clone; import dmd.cond; @@ -36,9 +34,7 @@ import dmd.dmodule; import dmd.dscope; import dmd.dsymbol; import dmd.dsymbolsem; -import dmd.dtemplate; import dmd.errors; -import dmd.errorsink; import dmd.escape; import dmd.expression; import dmd.expressionsem; @@ -64,7 +60,6 @@ import dmd.root.string; import dmd.semantic2; import dmd.sideeffect; import dmd.statement; -import dmd.staticassert; import dmd.target; import dmd.tokens; import dmd.typesem; @@ -1751,102 +1746,10 @@ Statement statementSemanticVisit(Statement s, Scope* sc) { /* https://dlang.org/spec/statement.html#pragma-statement */ - // Should be merged with PragmaDeclaration - - //printf("PragmaStatement::semantic() %s\n", ps.toChars()); - //printf("body = %p\n", ps._body); - if (ps.ident == Id.msg) - { - if (!pragmaMsgSemantic(ps.loc, sc, ps.args)) - return setError(); - } - else if (ps.ident == Id.lib) - { - version (all) - { - /* Should this be allowed? - */ - error(ps.loc, "`pragma(lib)` not allowed as statement"); - return setError(); - } - else - { - if (!ps.args || ps.args.length != 1) - { - error(ps.loc, "`string` expected for library name"); - return setError(); - } - else - { - auto se = semanticString(sc, (*ps.args)[0], "library name"); - if (!se) - return setError(); - - if (global.params.v.verbose) - { - message("library %.*s", cast(int)se.len, se.string); - } - } - } - } - else if (ps.ident == Id.linkerDirective) - { - /* Should this be allowed? - */ - error(ps.loc, "`pragma(linkerDirective)` not allowed as statement"); - return setError(); - } - else if (ps.ident == Id.startaddress) - { - if (!pragmaStartAddressSemantic(ps.loc, sc, ps.args)) - return setError(); - } - else if (ps.ident == Id.Pinline) - { - if (auto fd = sc.func) - { - fd.inlining = evalPragmaInline(ps.loc, sc, ps.args); - } - else - { - error(ps.loc, "`pragma(inline)` is not inside a function"); - return setError(); - } - } - else if (ps.ident == Id.mangle) - { - auto es = ps._body ? ps._body.isExpStatement() : null; - auto de = es ? es.exp.isDeclarationExp() : null; - if (!de) - { - error(ps.loc, "`pragma(mangle)` must be attached to a declaration"); - return setError(); - } - const se = ps.args && (*ps.args).length == 1 ? semanticString(sc, (*ps.args)[0], "pragma mangle argument") : null; - if (!se) - { - error(ps.loc, "`pragma(mangle)` takes a single argument that must be a string literal"); - return setError(); - } - const cnt = setMangleOverride(de.declaration, cast(const(char)[])se.peekData()); - if (cnt != 1) - assert(0); - } - else if (!global.params.ignoreUnsupportedPragmas) - { - error(ps.loc, "unrecognized `pragma(%s)`", ps.ident.toChars()); + import dmd.pragmasem : pragmaStmtSemantic; + if (!pragmaStmtSemantic(ps, sc)) return setError(); - } - if (ps._body) - { - if (ps.ident == Id.msg || ps.ident == Id.startaddress) - { - error(ps.loc, "`pragma(%s)` is missing a terminating `;`", ps.ident.toChars()); - return setError(); - } - ps._body = ps._body.statementSemantic(sc); - } result = ps._body; } @@ -5010,86 +4913,6 @@ private void debugThrowWalker(Statement s) s.accept(walker); } -/*********************************************************** - * Evaluate and print a `pragma(msg, args)` - * - * Params: - * loc = location for error messages - * sc = scope for argument interpretation - * args = expressions to print - * Returns: - * `true` on success - */ -bool pragmaMsgSemantic(Loc loc, Scope* sc, Expressions* args) -{ - if (!args) - return true; - foreach (arg; *args) - { - sc = sc.startCTFE(); - auto e = arg.expressionSemantic(sc); - e = resolveProperties(sc, e); - sc = sc.endCTFE(); - - // pragma(msg) is allowed to contain types as well as expressions - e = ctfeInterpretForPragmaMsg(e); - if (e.op == EXP.error) - { - errorSupplemental(loc, "while evaluating `pragma(msg, %s)`", arg.toChars()); - return false; - } - if (auto se = e.toStringExp()) - { - const slice = se.toUTF8(sc).peekString(); - fprintf(stderr, "%.*s", cast(int)slice.length, slice.ptr); - } - else - fprintf(stderr, "%s", e.toChars()); - } - fprintf(stderr, "\n"); - return true; -} - -/*********************************************************** - * Evaluate `pragma(startAddress, func)` and store the resolved symbol in `args` - * - * Params: - * loc = location for error messages - * sc = scope for argument interpretation - * args = pragma arguments - * Returns: - * `true` on success - */ -bool pragmaStartAddressSemantic(Loc loc, Scope* sc, Expressions* args) -{ - if (!args || args.length != 1) - { - .error(loc, "function name expected for start address"); - return false; - } - else - { - /* https://issues.dlang.org/show_bug.cgi?id=11980 - * resolveProperties and ctfeInterpret call are not necessary. - */ - Expression e = (*args)[0]; - sc = sc.startCTFE(); - e = e.expressionSemantic(sc); - // e = resolveProperties(sc, e); - sc = sc.endCTFE(); - - // e = e.ctfeInterpret(); - (*args)[0] = e; - Dsymbol sa = getDsymbol(e); - if (!sa || !sa.isFuncDeclaration()) - { - .error(loc, "function name expected for start address, not `%s`", e.toChars()); - return false; - } - } - return true; -} - /************************************ * Check for skipped variable declarations. * Params: diff --git a/gcc/d/dmd/templatesem.d b/gcc/d/dmd/templatesem.d index 1942afe..0a36838 100644 --- a/gcc/d/dmd/templatesem.d +++ b/gcc/d/dmd/templatesem.d @@ -51,10 +51,160 @@ import dmd.common.outbuffer; import dmd.rootobject; import dmd.semantic2; import dmd.semantic3; +import dmd.templateparamsem; import dmd.tokens; import dmd.typesem; import dmd.visitor; +/************************************ + * Perform semantic analysis on template. + * Params: + * sc = context + * tempdecl = template declaration + */ +void templateDeclarationSemantic(Scope* sc, TemplateDeclaration tempdecl) +{ + enum log = false; + static if (log) + { + printf("TemplateDeclaration.dsymbolSemantic(this = %p, id = '%s')\n", this, tempdecl.ident.toChars()); + printf("sc.stc = %llx\n", sc.stc); + printf("sc.module = %s\n", sc._module.toChars()); + } + if (tempdecl.semanticRun != PASS.initial) + return; // semantic() already run + + if (tempdecl._scope) + { + sc = tempdecl._scope; + tempdecl._scope = null; + } + if (!sc) + return; + + // Remember templates defined in module object that we need to know about + if (sc._module && sc._module.ident == Id.object) + { + if (tempdecl.ident == Id.RTInfo) + Type.rtinfo = tempdecl; + } + + /* Remember Scope for later instantiations, but make + * a copy since attributes can change. + */ + if (!tempdecl._scope) + { + tempdecl._scope = sc.copy(); + tempdecl._scope.setNoFree(); + } + + tempdecl.semanticRun = PASS.semantic; + + tempdecl.parent = sc.parent; + tempdecl.visibility = sc.visibility; + tempdecl.userAttribDecl = sc.userAttribDecl; + tempdecl.cppnamespace = sc.namespace; + tempdecl.isstatic = tempdecl.toParent().isModule() || (tempdecl._scope.stc & STC.static_); + tempdecl.deprecated_ = !!(sc.stc & STC.deprecated_); + + UserAttributeDeclaration.checkGNUABITag(tempdecl, sc.linkage); + + if (!tempdecl.isstatic) + { + if (auto ad = tempdecl.parent.pastMixin().isAggregateDeclaration()) + ad.makeNested(); + } + + // Set up scope for parameters + auto paramsym = new ScopeDsymbol(); + paramsym.parent = tempdecl.parent; + Scope* paramscope = sc.push(paramsym); + paramscope.stc = 0; + + if (global.params.ddoc.doOutput) + { + tempdecl.origParameters = new TemplateParameters(tempdecl.parameters.length); + for (size_t i = 0; i < tempdecl.parameters.length; i++) + { + TemplateParameter tp = (*tempdecl.parameters)[i]; + (*tempdecl.origParameters)[i] = tp.syntaxCopy(); + } + } + + for (size_t i = 0; i < tempdecl.parameters.length; i++) + { + TemplateParameter tp = (*tempdecl.parameters)[i]; + if (!tp.declareParameter(paramscope)) + { + error(tp.loc, "parameter `%s` multiply defined", tp.ident.toChars()); + tempdecl.errors = true; + } + if (!tp.tpsemantic(paramscope, tempdecl.parameters)) + { + tempdecl.errors = true; + } + if (i + 1 != tempdecl.parameters.length && tp.isTemplateTupleParameter()) + { + .error(tempdecl.loc, "%s `%s` template sequence parameter must be the last one", tempdecl.kind, tempdecl.toPrettyChars); + tempdecl.errors = true; + } + } + + /* Calculate TemplateParameter.dependent + */ + TemplateParameters tparams = TemplateParameters(1); + for (size_t i = 0; i < tempdecl.parameters.length; i++) + { + TemplateParameter tp = (*tempdecl.parameters)[i]; + tparams[0] = tp; + + for (size_t j = 0; j < tempdecl.parameters.length; j++) + { + // Skip cases like: X(T : T) + if (i == j) + continue; + + if (TemplateTypeParameter ttp = (*tempdecl.parameters)[j].isTemplateTypeParameter()) + { + if (reliesOnTident(ttp.specType, &tparams)) + tp.dependent = true; + } + else if (TemplateAliasParameter tap = (*tempdecl.parameters)[j].isTemplateAliasParameter()) + { + if (reliesOnTident(tap.specType, &tparams) || + reliesOnTident(isType(tap.specAlias), &tparams)) + { + tp.dependent = true; + } + } + } + } + + paramscope.pop(); + + // Compute again + tempdecl.onemember = null; + if (tempdecl.members) + { + Dsymbol s; + if (Dsymbol.oneMembers(tempdecl.members, s, tempdecl.ident) && s) + { + tempdecl.onemember = s; + s.parent = tempdecl; + } + } + + /* BUG: should check: + * 1. template functions must not introduce virtual functions, as they + * cannot be accomodated in the vtbl[] + * 2. templates cannot introduce non-static data members (i.e. fields) + * as they would change the instance size of the aggregate. + */ + + tempdecl.semanticRun = PASS.semanticdone; +} + + /*************************************** * Given that ti is an instance of this TemplateDeclaration, * deduce the types of the parameters to this, and store @@ -1468,7 +1618,7 @@ Lmatch: sc2.minst = sc.minst; sc2.stc |= fd.storage_class & STC.deprecated_; - fd = td.doHeaderInstantiation(ti, sc2, fd, tthis, argumentList.arguments); + fd = doHeaderInstantiation(td, ti, sc2, fd, tthis, argumentList.arguments); sc2 = sc2.pop(); sc2 = sc2.pop(); @@ -1495,3 +1645,760 @@ Lmatch: //printf("\tmatch %d\n", match); return MATCHpair(matchTiargs, match); } + +/************************************************* + * Limited function template instantiation for using fd.leastAsSpecialized() + */ +private +FuncDeclaration doHeaderInstantiation(TemplateDeclaration td, TemplateInstance ti, Scope* sc2, FuncDeclaration fd, Type tthis, Expressions* fargs) +{ + assert(fd); + version (none) + { + printf("doHeaderInstantiation this = %s\n", toChars()); + } + + // function body and contracts are not need + if (fd.isCtorDeclaration()) + fd = new CtorDeclaration(fd.loc, fd.endloc, fd.storage_class, fd.type.syntaxCopy()); + else + fd = new FuncDeclaration(fd.loc, fd.endloc, fd.ident, fd.storage_class, fd.type.syntaxCopy()); + fd.parent = ti; + + assert(fd.type.ty == Tfunction); + auto tf = fd.type.isTypeFunction(); + tf.fargs = fargs; + + if (tthis) + { + // Match 'tthis' to any TemplateThisParameter's + bool hasttp = false; + foreach (tp; *td.parameters) + { + TemplateThisParameter ttp = tp.isTemplateThisParameter(); + if (ttp) + hasttp = true; + } + if (hasttp) + { + tf = tf.addSTC(ModToStc(tthis.mod)).isTypeFunction(); + assert(!tf.deco); + } + } + + Scope* scx = sc2.push(); + + // Shouldn't run semantic on default arguments and return type. + foreach (ref params; *tf.parameterList.parameters) + params.defaultArg = null; + tf.incomplete = true; + + if (fd.isCtorDeclaration()) + { + // For constructors, emitting return type is necessary for + // isReturnIsolated() in functionResolve. + tf.isctor = true; + + Dsymbol parent = td.toParentDecl(); + Type tret; + AggregateDeclaration ad = parent.isAggregateDeclaration(); + if (!ad || parent.isUnionDeclaration()) + { + tret = Type.tvoid; + } + else + { + tret = ad.handleType(); + assert(tret); + tret = tret.addStorageClass(fd.storage_class | scx.stc); + tret = tret.addMod(tf.mod); + } + tf.next = tret; + if (ad && ad.isStructDeclaration()) + tf.isref = 1; + //printf("tf = %s\n", tf.toChars()); + } + else + tf.next = null; + fd.type = tf; + fd.type = fd.type.addSTC(scx.stc); + fd.type = fd.type.typeSemantic(fd.loc, scx); + scx = scx.pop(); + + if (fd.type.ty != Tfunction) + return null; + + fd.originalType = fd.type; // for mangling + //printf("\t[%s] fd.type = %s, mod = %x, ", loc.toChars(), fd.type.toChars(), fd.type.mod); + //printf("fd.needThis() = %d\n", fd.needThis()); + + return fd; +} + +/************************************************** + * Declare template parameter tp with value o, and install it in the scope sc. + */ +extern (D) RootObject declareParameter(TemplateDeclaration td, Scope* sc, TemplateParameter tp, RootObject o) +{ + //printf("TemplateDeclaration.declareParameter('%s', o = %p)\n", tp.ident.toChars(), o); + Type ta = isType(o); + Expression ea = isExpression(o); + Dsymbol sa = isDsymbol(o); + Tuple va = isTuple(o); + + Declaration d; + VarDeclaration v = null; + + if (ea) + { + if (ea.op == EXP.type) + ta = ea.type; + else if (auto se = ea.isScopeExp()) + sa = se.sds; + else if (auto te = ea.isThisExp()) + sa = te.var; + else if (auto se = ea.isSuperExp()) + sa = se.var; + else if (auto fe = ea.isFuncExp()) + { + if (fe.td) + sa = fe.td; + else + sa = fe.fd; + } + } + + if (ta) + { + //printf("type %s\n", ta.toChars()); + auto ad = new AliasDeclaration(Loc.initial, tp.ident, ta); + ad.storage_class |= STC.templateparameter; + d = ad; + } + else if (sa) + { + //printf("Alias %s %s;\n", sa.ident.toChars(), tp.ident.toChars()); + auto ad = new AliasDeclaration(Loc.initial, tp.ident, sa); + ad.storage_class |= STC.templateparameter; + d = ad; + } + else if (ea) + { + // tdtypes.data[i] always matches ea here + Initializer _init = new ExpInitializer(td.loc, ea); + TemplateValueParameter tvp = tp.isTemplateValueParameter(); + Type t = tvp ? tvp.valType : null; + v = new VarDeclaration(td.loc, t, tp.ident, _init); + v.storage_class = STC.manifest | STC.templateparameter; + d = v; + } + else if (va) + { + //printf("\ttuple\n"); + d = new TupleDeclaration(td.loc, tp.ident, &va.objects); + } + else + { + assert(0); + } + d.storage_class |= STC.templateparameter; + + if (ta) + { + Type t = ta; + // consistent with Type.checkDeprecated() + while (t.ty != Tenum) + { + if (!t.nextOf()) + break; + t = (cast(TypeNext)t).next; + } + if (Dsymbol s = t.toDsymbol(sc)) + { + if (s.isDeprecated()) + d.storage_class |= STC.deprecated_; + } + } + else if (sa) + { + if (sa.isDeprecated()) + d.storage_class |= STC.deprecated_; + } + + if (!sc.insert(d)) + .error(td.loc, "%s `%s` declaration `%s` is already defined", td.kind, td.toPrettyChars, tp.ident.toChars()); + d.dsymbolSemantic(sc); + /* So the caller's o gets updated with the result of semantic() being run on o + */ + if (v) + o = v._init.initializerToExpression(); + return o; +} + +/************************************************* + * Given function arguments, figure out which template function + * to expand, and return matching result. + * Params: + * m = matching result + * dstart = the root of overloaded function templates + * loc = instantiation location + * sc = instantiation scope + * tiargs = initial list of template arguments + * tthis = if !NULL, the 'this' pointer argument + * argumentList= arguments to function + * errorHelper = delegate to send error message to if not null + */ +void functionResolve(ref MatchAccumulator m, Dsymbol dstart, Loc loc, Scope* sc, Objects* tiargs, + Type tthis, ArgumentList argumentList, void delegate(const(char)*) scope errorHelper = null) +{ + version (none) + { + printf("functionResolve() dstart = %s\n", dstart.toChars()); + printf(" tiargs:\n"); + if (tiargs) + { + for (size_t i = 0; i < tiargs.length; i++) + { + RootObject arg = (*tiargs)[i]; + printf("\t%s\n", arg.toChars()); + } + } + printf(" fargs:\n"); + for (size_t i = 0; i < (fargs ? fargs.length : 0); i++) + { + Expression arg = (*fargs)[i]; + printf("\t%s %s\n", arg.type.toChars(), arg.toChars()); + //printf("\tty = %d\n", arg.type.ty); + } + //printf("stc = %llx\n", dstart._scope.stc); + //printf("match:t/f = %d/%d\n", ta_last, m.last); + } + + // results + int property = 0; // 0: uninitialized + // 1: seen @property + // 2: not @property + size_t ov_index = 0; + TemplateDeclaration td_best; + TemplateInstance ti_best; + MATCH ta_last = m.last != MATCH.nomatch ? MATCH.exact : MATCH.nomatch; + Type tthis_best; + + int applyFunction(FuncDeclaration fd) + { + // skip duplicates + if (fd == m.lastf) + return 0; + // explicitly specified tiargs never match to non template function + if (tiargs && tiargs.length > 0) + return 0; + + // constructors need a valid scope in order to detect semantic errors + if (!fd.isCtorDeclaration && + fd.semanticRun < PASS.semanticdone) + { + fd.ungagSpeculative(); + fd.dsymbolSemantic(null); + } + if (fd.semanticRun < PASS.semanticdone) + { + .error(loc, "forward reference to template `%s`", fd.toChars()); + return 1; + } + //printf("fd = %s %s, fargs = %s\n", fd.toChars(), fd.type.toChars(), fargs.toChars()); + auto tf = fd.type.isTypeFunction(); + + int prop = tf.isproperty ? 1 : 2; + if (property == 0) + property = prop; + else if (property != prop) + error(fd.loc, "cannot overload both property and non-property functions"); + + /* For constructors, qualifier check will be opposite direction. + * Qualified constructor always makes qualified object, then will be checked + * that it is implicitly convertible to tthis. + */ + Type tthis_fd = fd.needThis() ? tthis : null; + bool isCtorCall = tthis_fd && fd.isCtorDeclaration(); + if (isCtorCall) + { + //printf("%s tf.mod = x%x tthis_fd.mod = x%x %d\n", tf.toChars(), + // tf.mod, tthis_fd.mod, fd.isReturnIsolated()); + if (MODimplicitConv(tf.mod, tthis_fd.mod) || + tf.isWild() && tf.isShared() == tthis_fd.isShared() || + fd.isReturnIsolated()) + { + /* && tf.isShared() == tthis_fd.isShared()*/ + // Uniquely constructed object can ignore shared qualifier. + // TODO: Is this appropriate? + tthis_fd = null; + } + else + return 0; // MATCH.nomatch + } + /* Fix Issue 17970: + If a struct is declared as shared the dtor is automatically + considered to be shared, but when the struct is instantiated + the instance is no longer considered to be shared when the + function call matching is done. The fix makes it so that if a + struct declaration is shared, when the destructor is called, + the instantiated struct is also considered shared. + */ + if (auto dt = fd.isDtorDeclaration()) + { + auto dtmod = dt.type.toTypeFunction(); + auto shared_dtor = dtmod.mod & MODFlags.shared_; + auto shared_this = tthis_fd !is null ? + tthis_fd.mod & MODFlags.shared_ : 0; + if (shared_dtor && !shared_this) + tthis_fd = dtmod; + else if (shared_this && !shared_dtor && tthis_fd !is null) + tf.mod = tthis_fd.mod; + } + const(char)* failMessage; + MATCH mfa = tf.callMatch(tthis_fd, argumentList, 0, errorHelper, sc); + //printf("test1: mfa = %d\n", mfa); + if (failMessage) + errorHelper(failMessage); + if (mfa == MATCH.nomatch) + return 0; + + int firstIsBetter() + { + td_best = null; + ti_best = null; + ta_last = MATCH.exact; + m.last = mfa; + m.lastf = fd; + tthis_best = tthis_fd; + ov_index = 0; + m.count = 1; + return 0; + } + + if (mfa > m.last) return firstIsBetter(); + if (mfa < m.last) return 0; + + /* See if one of the matches overrides the other. + */ + assert(m.lastf); + if (m.lastf.overrides(fd)) return 0; + if (fd.overrides(m.lastf)) return firstIsBetter(); + + /* Try to disambiguate using template-style partial ordering rules. + * In essence, if f() and g() are ambiguous, if f() can call g(), + * but g() cannot call f(), then pick f(). + * This is because f() is "more specialized." + */ + { + MATCH c1 = FuncDeclaration.leastAsSpecialized(fd, m.lastf, argumentList.names); + MATCH c2 = FuncDeclaration.leastAsSpecialized(m.lastf, fd, argumentList.names); + //printf("c1 = %d, c2 = %d\n", c1, c2); + if (c1 > c2) return firstIsBetter(); + if (c1 < c2) return 0; + } + + /* The 'overrides' check above does covariant checking only + * for virtual member functions. It should do it for all functions, + * but in order to not risk breaking code we put it after + * the 'leastAsSpecialized' check. + * In the future try moving it before. + * I.e. a not-the-same-but-covariant match is preferred, + * as it is more restrictive. + */ + if (!m.lastf.type.equals(fd.type)) + { + //printf("cov: %d %d\n", m.lastf.type.covariant(fd.type), fd.type.covariant(m.lastf.type)); + const lastCovariant = m.lastf.type.covariant(fd.type); + const firstCovariant = fd.type.covariant(m.lastf.type); + + if (lastCovariant == Covariant.yes || lastCovariant == Covariant.no) + { + if (firstCovariant != Covariant.yes && firstCovariant != Covariant.no) + { + return 0; + } + } + else if (firstCovariant == Covariant.yes || firstCovariant == Covariant.no) + { + return firstIsBetter(); + } + } + + /* If the two functions are the same function, like: + * int foo(int); + * int foo(int x) { ... } + * then pick the one with the body. + * + * If none has a body then don't care because the same + * real function would be linked to the decl (e.g from object file) + */ + if (tf.equals(m.lastf.type) && + fd.storage_class == m.lastf.storage_class && + fd.parent == m.lastf.parent && + fd.visibility == m.lastf.visibility && + fd._linkage == m.lastf._linkage) + { + if (fd.fbody && !m.lastf.fbody) + return firstIsBetter(); + if (!fd.fbody) + return 0; + } + + // https://issues.dlang.org/show_bug.cgi?id=14450 + // Prefer exact qualified constructor for the creating object type + if (isCtorCall && tf.mod != m.lastf.type.mod) + { + if (tthis.mod == tf.mod) return firstIsBetter(); + if (tthis.mod == m.lastf.type.mod) return 0; + } + + m.nextf = fd; + m.count++; + return 0; + } + + int applyTemplate(TemplateDeclaration td) + { + //printf("applyTemplate(): td = %s\n", td.toChars()); + if (td == td_best) // skip duplicates + return 0; + + if (!sc) + sc = td._scope; // workaround for Type.aliasthisOf + + if (td.semanticRun == PASS.initial && td._scope) + { + // Try to fix forward reference. Ungag errors while doing so. + td.ungagSpeculative(); + td.dsymbolSemantic(td._scope); + } + if (td.semanticRun == PASS.initial) + { + .error(loc, "forward reference to template `%s`", td.toChars()); + Lerror: + m.lastf = null; + m.count = 0; + m.last = MATCH.nomatch; + return 1; + } + //printf("td = %s\n", td.toChars()); + + if (argumentList.hasNames) + { + .error(loc, "named arguments with Implicit Function Template Instantiation are not supported yet"); + goto Lerror; + } + auto f = td.onemember ? td.onemember.isFuncDeclaration() : null; + if (!f) + { + if (!tiargs) + tiargs = new Objects(); + auto ti = new TemplateInstance(loc, td, tiargs); + Objects dedtypes = Objects(td.parameters.length); + assert(td.semanticRun != PASS.initial); + MATCH mta = matchWithInstance(sc, td, ti, dedtypes, argumentList, 0); + //printf("matchWithInstance = %d\n", mta); + if (mta == MATCH.nomatch || mta < ta_last) // no match or less match + return 0; + + ti.templateInstanceSemantic(sc, argumentList); + if (!ti.inst) // if template failed to expand + return 0; + + Dsymbol s = ti.inst.toAlias(); + FuncDeclaration fd; + if (auto tdx = s.isTemplateDeclaration()) + { + Objects dedtypesX; // empty tiargs + + // https://issues.dlang.org/show_bug.cgi?id=11553 + // Check for recursive instantiation of tdx. + for (TemplatePrevious* p = tdx.previous; p; p = p.prev) + { + if (arrayObjectMatch(*p.dedargs, dedtypesX)) + { + //printf("recursive, no match p.sc=%p %p %s\n", p.sc, this, this.toChars()); + /* It must be a subscope of p.sc, other scope chains are not recursive + * instantiations. + */ + for (Scope* scx = sc; scx; scx = scx.enclosing) + { + if (scx == p.sc) + { + error(loc, "recursive template expansion while looking for `%s.%s`", ti.toChars(), tdx.toChars()); + goto Lerror; + } + } + } + /* BUG: should also check for ref param differences + */ + } + + TemplatePrevious pr; + pr.prev = tdx.previous; + pr.sc = sc; + pr.dedargs = &dedtypesX; + tdx.previous = ≺ // add this to threaded list + + fd = resolveFuncCall(loc, sc, s, null, tthis, argumentList, FuncResolveFlag.quiet); + + tdx.previous = pr.prev; // unlink from threaded list + } + else if (s.isFuncDeclaration()) + { + fd = resolveFuncCall(loc, sc, s, null, tthis, argumentList, FuncResolveFlag.quiet); + } + else + goto Lerror; + + if (!fd) + return 0; + + if (fd.type.ty != Tfunction) + { + m.lastf = fd; // to propagate "error match" + m.count = 1; + m.last = MATCH.nomatch; + return 1; + } + + Type tthis_fd = fd.needThis() && !fd.isCtorDeclaration() ? tthis : null; + + auto tf = fd.type.isTypeFunction(); + MATCH mfa = tf.callMatch(tthis_fd, argumentList, 0, null, sc); + if (mfa < m.last) + return 0; + + if (mta < ta_last) goto Ltd_best2; + if (mta > ta_last) goto Ltd2; + + if (mfa < m.last) goto Ltd_best2; + if (mfa > m.last) goto Ltd2; + + // td_best and td are ambiguous + //printf("Lambig2\n"); + m.nextf = fd; + m.count++; + return 0; + + Ltd_best2: + return 0; + + Ltd2: + // td is the new best match + assert(td._scope); + td_best = td; + ti_best = null; + property = 0; // (backward compatibility) + ta_last = mta; + m.last = mfa; + m.lastf = fd; + tthis_best = tthis_fd; + ov_index = 0; + m.nextf = null; + m.count = 1; + return 0; + } + + //printf("td = %s\n", td.toChars()); + for (size_t ovi = 0; f; f = f.overnext0, ovi++) + { + if (f.type.ty != Tfunction || f.errors) + goto Lerror; + + /* This is a 'dummy' instance to evaluate constraint properly. + */ + auto ti = new TemplateInstance(loc, td, tiargs); + ti.parent = td.parent; // Maybe calculating valid 'enclosing' is unnecessary. + + auto fd = f; + MATCHpair x = td.deduceFunctionTemplateMatch(ti, sc, fd, tthis, argumentList); + MATCH mta = x.mta; + MATCH mfa = x.mfa; + //printf("match:t/f = %d/%d\n", mta, mfa); + if (!fd || mfa == MATCH.nomatch) + continue; + + Type tthis_fd = fd.needThis() ? tthis : null; + + bool isCtorCall = tthis_fd && fd.isCtorDeclaration(); + if (isCtorCall) + { + // Constructor call requires additional check. + auto tf = fd.type.isTypeFunction(); + assert(tf.next); + if (MODimplicitConv(tf.mod, tthis_fd.mod) || + tf.isWild() && tf.isShared() == tthis_fd.isShared() || + fd.isReturnIsolated()) + { + tthis_fd = null; + } + else + continue; // MATCH.nomatch + + // need to check here whether the constructor is the member of a struct + // declaration that defines a copy constructor. This is already checked + // in the semantic of CtorDeclaration, however, when matching functions, + // the template instance is not expanded. + // https://issues.dlang.org/show_bug.cgi?id=21613 + auto ad = fd.isThis(); + auto sd = ad.isStructDeclaration(); + if (checkHasBothRvalueAndCpCtor(sd, fd.isCtorDeclaration(), ti)) + continue; + } + + if (mta < ta_last) goto Ltd_best; + if (mta > ta_last) goto Ltd; + + if (mfa < m.last) goto Ltd_best; + if (mfa > m.last) goto Ltd; + + if (td_best) + { + // Disambiguate by picking the most specialized TemplateDeclaration + MATCH c1 = leastAsSpecialized(sc, td, td_best, argumentList); + MATCH c2 = leastAsSpecialized(sc, td_best, td, argumentList); + //printf("1: c1 = %d, c2 = %d\n", c1, c2); + if (c1 > c2) goto Ltd; + if (c1 < c2) goto Ltd_best; + } + assert(fd && m.lastf); + { + // Disambiguate by tf.callMatch + auto tf1 = fd.type.isTypeFunction(); + auto tf2 = m.lastf.type.isTypeFunction(); + MATCH c1 = tf1.callMatch(tthis_fd, argumentList, 0, null, sc); + MATCH c2 = tf2.callMatch(tthis_best, argumentList, 0, null, sc); + //printf("2: c1 = %d, c2 = %d\n", c1, c2); + if (c1 > c2) goto Ltd; + if (c1 < c2) goto Ltd_best; + } + { + // Disambiguate by picking the most specialized FunctionDeclaration + MATCH c1 = FuncDeclaration.leastAsSpecialized(fd, m.lastf, argumentList.names); + MATCH c2 = FuncDeclaration.leastAsSpecialized(m.lastf, fd, argumentList.names); + //printf("3: c1 = %d, c2 = %d\n", c1, c2); + if (c1 > c2) goto Ltd; + if (c1 < c2) goto Ltd_best; + } + + // https://issues.dlang.org/show_bug.cgi?id=14450 + // Prefer exact qualified constructor for the creating object type + if (isCtorCall && fd.type.mod != m.lastf.type.mod) + { + if (tthis.mod == fd.type.mod) goto Ltd; + if (tthis.mod == m.lastf.type.mod) goto Ltd_best; + } + + m.nextf = fd; + m.count++; + continue; + + Ltd_best: // td_best is the best match so far + //printf("Ltd_best\n"); + continue; + + Ltd: // td is the new best match + //printf("Ltd\n"); + assert(td._scope); + td_best = td; + ti_best = ti; + property = 0; // (backward compatibility) + ta_last = mta; + m.last = mfa; + m.lastf = fd; + tthis_best = tthis_fd; + ov_index = ovi; + m.nextf = null; + m.count = 1; + continue; + } + return 0; + } + + auto td = dstart.isTemplateDeclaration(); + if (td && td.funcroot) + dstart = td.funcroot; + overloadApply(dstart, (Dsymbol s) + { + if (s.errors) + return 0; + if (auto fd = s.isFuncDeclaration()) + return applyFunction(fd); + if (auto td = s.isTemplateDeclaration()) + return applyTemplate(td); + return 0; + }, sc); + + //printf("td_best = %p, m.lastf = %p\n", td_best, m.lastf); + if (td_best && ti_best && m.count == 1) + { + // Matches to template function + assert(td_best.onemember && td_best.onemember.isFuncDeclaration()); + /* The best match is td_best with arguments tdargs. + * Now instantiate the template. + */ + assert(td_best._scope); + if (!sc) + sc = td_best._scope; // workaround for Type.aliasthisOf + + auto ti = new TemplateInstance(loc, td_best, ti_best.tiargs); + ti.templateInstanceSemantic(sc, argumentList); + + m.lastf = ti.toAlias().isFuncDeclaration(); + if (!m.lastf) + goto Lnomatch; + if (ti.errors) + { + Lerror: + m.count = 1; + assert(m.lastf); + m.last = MATCH.nomatch; + return; + } + + // look forward instantiated overload function + // Dsymbol.oneMembers is alredy called in TemplateInstance.semantic. + // it has filled overnext0d + while (ov_index--) + { + m.lastf = m.lastf.overnext0; + assert(m.lastf); + } + + tthis_best = m.lastf.needThis() && !m.lastf.isCtorDeclaration() ? tthis : null; + + if (m.lastf.type.ty == Terror) + goto Lerror; + auto tf = m.lastf.type.isTypeFunction(); + if (!tf.callMatch(tthis_best, argumentList, 0, null, sc)) + goto Lnomatch; + + /* As https://issues.dlang.org/show_bug.cgi?id=3682 shows, + * a template instance can be matched while instantiating + * that same template. Thus, the function type can be incomplete. Complete it. + * + * https://issues.dlang.org/show_bug.cgi?id=9208 + * For auto function, completion should be deferred to the end of + * its semantic3. Should not complete it in here. + */ + if (tf.next && !m.lastf.inferRetType) + { + m.lastf.type = tf.typeSemantic(loc, sc); + } + } + else if (m.lastf) + { + // Matches to non template function, + // or found matches were ambiguous. + assert(m.count >= 1); + } + else + { + Lnomatch: + m.count = 0; + m.lastf = null; + m.last = MATCH.nomatch; + } +} diff --git a/gcc/d/dmd/typesem.d b/gcc/d/dmd/typesem.d index 6721fa6..b1ca92d 100644 --- a/gcc/d/dmd/typesem.d +++ b/gcc/d/dmd/typesem.d @@ -41,6 +41,7 @@ import dmd.errorsink; import dmd.expression; import dmd.expressionsem; import dmd.func; +import dmd.funcsem; import dmd.globals; import dmd.hdrgen; import dmd.id; @@ -3742,12 +3743,12 @@ void resolve(Type mt, const ref Loc loc, Scope* sc, out Expression pe, out Type // f might be a unittest declaration which is incomplete when compiled // without -unittest. That causes a segfault in checkForwardRef, see // https://issues.dlang.org/show_bug.cgi?id=20626 - if ((!f.isUnitTestDeclaration() || global.params.useUnitTests) && f.checkForwardRef(loc)) + if ((!f.isUnitTestDeclaration() || global.params.useUnitTests) && checkForwardRef(f, loc)) goto Lerr; } if (auto f = isFuncAddress(mt.exp)) { - if (f.checkForwardRef(loc)) + if (checkForwardRef(f, loc)) goto Lerr; } @@ -6105,6 +6106,305 @@ extern(C++) bool isBaseOf(Type tthis, Type t, int* poffset) return false; } +/******************************** + * Convert to 'const'. + */ +extern(C++) Type constOf(Type type) +{ + //printf("Type::constOf() %p %s\n", type, type.toChars()); + if (type.mod == MODFlags.const_) + return type; + if (type.mcache && type.mcache.cto) + { + assert(type.mcache.cto.mod == MODFlags.const_); + return type.mcache.cto; + } + Type t = type.makeConst(); + t = t.merge(); + t.fixTo(type); + //printf("-Type::constOf() %p %s\n", t, t.toChars()); + return t; +} + +/******************************** + * Convert to 'immutable'. + */ +extern(C++) Type immutableOf(Type type) +{ + //printf("Type::immutableOf() %p %s\n", this, toChars()); + if (type.isImmutable()) + return type; + if (type.mcache && type.mcache.ito) + { + assert(type.mcache.ito.isImmutable()); + return type.mcache.ito; + } + Type t = type.makeImmutable(); + t = t.merge(); + t.fixTo(type); + //printf("\t%p\n", t); + return t; +} + +/******************************** + * Make type mutable. + */ +extern(C++) Type mutableOf(Type type) +{ + //printf("Type::mutableOf() %p, %s\n", type, type.toChars()); + Type t = type; + if (type.isImmutable()) + { + type.getMcache(); + t = type.mcache.ito; // immutable => naked + assert(!t || (t.isMutable() && !t.isShared())); + } + else if (type.isConst()) + { + type.getMcache(); + if (type.isShared()) + { + if (type.isWild()) + t = type.mcache.swcto; // shared wild const -> shared + else + t = type.mcache.sto; // shared const => shared + } + else + { + if (type.isWild()) + t = type.mcache.wcto; // wild const -> naked + else + t = type.mcache.cto; // const => naked + } + assert(!t || t.isMutable()); + } + else if (type.isWild()) + { + type.getMcache(); + if (type.isShared()) + t = type.mcache.sto; // shared wild => shared + else + t = type.mcache.wto; // wild => naked + assert(!t || t.isMutable()); + } + if (!t) + { + t = type.makeMutable(); + t = t.merge(); + t.fixTo(type); + } + else + t = t.merge(); + assert(t.isMutable()); + return t; +} + +extern(C++) Type sharedOf(Type type) +{ + //printf("Type::sharedOf() %p, %s\n", type, type.toChars()); + if (type.mod == MODFlags.shared_) + return type; + if (type.mcache && type.mcache.sto) + { + assert(type.mcache.sto.mod == MODFlags.shared_); + return type.mcache.sto; + } + Type t = type.makeShared(); + t = t.merge(); + t.fixTo(type); + //printf("\t%p\n", t); + return t; +} + +extern(C++) Type sharedConstOf(Type type) +{ + //printf("Type::sharedConstOf() %p, %s\n", type, type.toChars()); + if (type.mod == (MODFlags.shared_ | MODFlags.const_)) + return type; + if (type.mcache && type.mcache.scto) + { + assert(type.mcache.scto.mod == (MODFlags.shared_ | MODFlags.const_)); + return type.mcache.scto; + } + Type t = type.makeSharedConst(); + t = t.merge(); + t.fixTo(type); + //printf("\t%p\n", t); + return t; +} + +/******************************** + * Make type unshared. + * 0 => 0 + * const => const + * immutable => immutable + * shared => 0 + * shared const => const + * wild => wild + * wild const => wild const + * shared wild => wild + * shared wild const => wild const + */ +extern(C++) Type unSharedOf(Type type) +{ + //printf("Type::unSharedOf() %p, %s\n", type, type.toChars()); + Type t = type; + + if (type.isShared()) + { + type.getMcache(); + if (type.isWild()) + { + if (type.isConst()) + t = type.mcache.wcto; // shared wild const => wild const + else + t = type.mcache.wto; // shared wild => wild + } + else + { + if (type.isConst()) + t = type.mcache.cto; // shared const => const + else + t = type.mcache.sto; // shared => naked + } + assert(!t || !t.isShared()); + } + + if (!t) + { + t = type.nullAttributes(); + t.mod = type.mod & ~MODFlags.shared_; + t.ctype = type.ctype; + t = t.merge(); + t.fixTo(type); + } + else + t = t.merge(); + assert(!t.isShared()); + return t; +} + +/******************************** + * Convert to 'wild'. + */ +extern(C++) Type wildOf(Type type) +{ + //printf("Type::wildOf() %p %s\n", type, type.toChars()); + if (type.mod == MODFlags.wild) + return type; + if (type.mcache && type.mcache.wto) + { + assert(type.mcache.wto.mod == MODFlags.wild); + return type.mcache.wto; + } + Type t = type.makeWild(); + t = t.merge(); + t.fixTo(type); + //printf("\t%p %s\n", t, t.toChars()); + return t; +} + +extern(C++) Type wildConstOf(Type type) +{ + //printf("Type::wildConstOf() %p %s\n", type, type.toChars()); + if (type.mod == MODFlags.wildconst) + return type; + if (type.mcache && type.mcache.wcto) + { + assert(type.mcache.wcto.mod == MODFlags.wildconst); + return type.mcache.wcto; + } + Type t = type.makeWildConst(); + t = t.merge(); + t.fixTo(type); + //printf("\t%p %s\n", t, t.toChars()); + return t; +} + +extern(C++) Type sharedWildOf(Type type) +{ + //printf("Type::sharedWildOf() %p, %s\n", type, type.toChars()); + if (type.mod == (MODFlags.shared_ | MODFlags.wild)) + return type; + if (type.mcache && type.mcache.swto) + { + assert(type.mcache.swto.mod == (MODFlags.shared_ | MODFlags.wild)); + return type.mcache.swto; + } + Type t = type.makeSharedWild(); + t = t.merge(); + t.fixTo(type); + //printf("\t%p %s\n", t, t.toChars()); + return t; +} + +extern(C++) Type sharedWildConstOf(Type type) +{ + //printf("Type::sharedWildConstOf() %p, %s\n", type, type.toChars()); + if (type.mod == (MODFlags.shared_ | MODFlags.wildconst)) + return type; + if (type.mcache && type.mcache.swcto) + { + assert(type.mcache.swcto.mod == (MODFlags.shared_ | MODFlags.wildconst)); + return type.mcache.swcto; + } + Type t = type.makeSharedWildConst(); + t = t.merge(); + t.fixTo(type); + //printf("\t%p %s\n", t, t.toChars()); + return t; +} + +/************************************ + * Apply MODxxxx bits to existing type. + */ +extern(C++) Type castMod(Type type, MOD mod) +{ + Type t; + switch (mod) + { + case 0: + t = type.unSharedOf().mutableOf(); + break; + + case MODFlags.const_: + t = type.unSharedOf().constOf(); + break; + + case MODFlags.wild: + t = type.unSharedOf().wildOf(); + break; + + case MODFlags.wildconst: + t = type.unSharedOf().wildConstOf(); + break; + + case MODFlags.shared_: + t = type.mutableOf().sharedOf(); + break; + + case MODFlags.shared_ | MODFlags.const_: + t = type.sharedConstOf(); + break; + + case MODFlags.shared_ | MODFlags.wild: + t = type.sharedWildOf(); + break; + + case MODFlags.shared_ | MODFlags.wildconst: + t = type.sharedWildConstOf(); + break; + + case MODFlags.immutable_: + t = type.immutableOf(); + break; + + default: + assert(0); + } + return t; +} + /******************************* Private *****************************************/ private: diff --git a/gcc/d/dmd/utils.d b/gcc/d/dmd/utils.d index 75ee78c..72d8036 100644 --- a/gcc/d/dmd/utils.d +++ b/gcc/d/dmd/utils.d @@ -299,3 +299,44 @@ bool parseDigits(T)(ref T val, const(char)[] p, const T max = T.max) assert(i.parseDigits("420", 500) && i == 420); assert(!i.parseDigits("420", 400)); } + +/** + * Cast a `ubyte[]` to an array of larger integers as if we are on a big endian architecture + * Params: + * data = array with big endian data + * size = 1 for ubyte[], 2 for ushort[], 4 for uint[], 8 for ulong[] + * Returns: copy of `data`, with bytes shuffled if compiled for `version(LittleEndian)` + */ +ubyte[] arrayCastBigEndian(const ubyte[] data, size_t size) +{ + ubyte[] impl(T)() + { + auto result = new T[](data.length / T.sizeof); + foreach (i; 0 .. result.length) + { + result[i] = 0; + foreach (j; 0 .. T.sizeof) + { + result[i] |= T(data[i * T.sizeof + j]) << ((T.sizeof - 1 - j) * 8); + } + } + return cast(ubyte[]) result; + } + switch (size) + { + case 1: return data.dup; + case 2: return impl!ushort; + case 4: return impl!uint; + case 8: return impl!ulong; + default: assert(0); + } +} + +unittest +{ + ubyte[] data = [0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0xFF, 0x11, 0x22]; + assert(cast(ulong[]) arrayCastBigEndian(data, 8) == [0xAABBCCDDEEFF1122]); + assert(cast(uint[]) arrayCastBigEndian(data, 4) == [0xAABBCCDD, 0xEEFF1122]); + assert(cast(ushort[]) arrayCastBigEndian(data, 2) == [0xAABB, 0xCCDD, 0xEEFF, 0x1122]); + assert(cast(ubyte[]) arrayCastBigEndian(data, 1) == data); +} diff --git a/gcc/d/expr.cc b/gcc/d/expr.cc index 0a85a55..a050588 100644 --- a/gcc/d/expr.cc +++ b/gcc/d/expr.cc @@ -1178,7 +1178,7 @@ public: { libcall = LIBCALL_AAGETY; ptr = build_address (build_expr (e->e1)); - tinfo = build_typeinfo (e, tb1->unSharedOf ()->mutableOf ()); + tinfo = build_typeinfo (e, mutableOf (unSharedOf (tb1))); } else { @@ -2170,7 +2170,7 @@ public: { /* Generate a slice for non-zero initialized aggregates, otherwise create an empty array. */ - gcc_assert (e->type == Type::tvoid->arrayOf ()->constOf ()); + gcc_assert (e->type == constOf (Type::tvoid->arrayOf ())); tree type = build_ctype (e->type); tree length = size_int (sd->dsym->structsize); @@ -2709,17 +2709,16 @@ public: void visit (AssocArrayLiteralExp *e) final override { - if (e->lowering != NULL) + if (this->constp_ && e->lowering != NULL) { /* When an associative array literal gets lowered, it's converted into a struct literal suitable for static initialization. */ - gcc_assert (this->constp_); this->result_ = build_expr (e->lowering, this->constp_, true); return ; } /* Want the mutable type for typeinfo reference. */ - Type *tb = e->type->toBasetype ()->mutableOf (); + Type *tb = mutableOf (e->type->toBasetype ()); /* Handle empty assoc array literals. */ TypeAArray *ta = tb->isTypeAArray (); diff --git a/gcc/d/runtime.cc b/gcc/d/runtime.cc index 8a47ac1..9d11e7e 100644 --- a/gcc/d/runtime.cc +++ b/gcc/d/runtime.cc @@ -150,11 +150,11 @@ get_libcall_type (d_libcall_type type) break; case LCT_CONST_TYPEINFO: - libcall_types[type] = Type::dtypeinfo->type->constOf (); + libcall_types[type] = constOf (Type::dtypeinfo->type); break; case LCT_CONST_CLASSINFO: - libcall_types[type] = Type::typeinfoclass->type->constOf (); + libcall_types[type] = constOf (Type::typeinfoclass->type); break; case LCT_ARRAY_VOID: @@ -202,7 +202,7 @@ get_libcall_type (d_libcall_type type) break; case LCT_IMMUTABLE_CHARPTR: - libcall_types[type] = Type::tchar->pointerTo ()->immutableOf (); + libcall_types[type] = immutableOf (Type::tchar->pointerTo ()); break; default: diff --git a/gcc/d/typeinfo.cc b/gcc/d/typeinfo.cc index 1600ca9..3dbda55 100644 --- a/gcc/d/typeinfo.cc +++ b/gcc/d/typeinfo.cc @@ -577,7 +577,7 @@ public: void visit (TypeInfoConstDeclaration *d) final override { - Type *tm = d->tinfo->mutableOf (); + Type *tm = mutableOf (d->tinfo); tm = merge2 (tm); /* The vtable for TypeInfo_Const. */ @@ -594,7 +594,7 @@ public: void visit (TypeInfoInvariantDeclaration *d) final override { - Type *tm = d->tinfo->mutableOf (); + Type *tm = mutableOf (d->tinfo); tm = merge2 (tm); /* The vtable for TypeInfo_Invariant. */ @@ -611,7 +611,7 @@ public: void visit (TypeInfoSharedDeclaration *d) final override { - Type *tm = d->tinfo->unSharedOf (); + Type *tm = unSharedOf (d->tinfo); tm = merge2 (tm); /* The vtable for TypeInfo_Shared. */ @@ -628,7 +628,7 @@ public: void visit (TypeInfoWildDeclaration *d) final override { - Type *tm = d->tinfo->mutableOf (); + Type *tm = mutableOf (d->tinfo); tm = merge2 (tm); /* The vtable for TypeInfo_Inout. */ diff --git a/gcc/d/types.cc b/gcc/d/types.cc index ca574fd..4e14b15 100644 --- a/gcc/d/types.cc +++ b/gcc/d/types.cc @@ -1329,7 +1329,7 @@ build_ctype (Type *t) t->accept (&v); else { - Type *tb = t->castMod (0); + Type *tb = castMod (t, 0); if (!tb->ctype) tb->accept (&v); t->ctype = insert_type_modifiers (tb->ctype, t->mod); diff --git a/gcc/testsuite/gdc.test/compilable/ddoc12.d b/gcc/testsuite/gdc.test/compilable/ddoc12.d deleted file mode 100644 index 337f37a..0000000 --- a/gcc/testsuite/gdc.test/compilable/ddoc12.d +++ /dev/null @@ -1,20 +0,0 @@ -// PERMUTE_ARGS: -// REQUIRED_ARGS: -D -Dd${RESULTS_DIR}/compilable -o- -// POST_SCRIPT: compilable/extra-files/ddocAny-postscript.sh - -int ruhred; /// This documents correctly. -int rühred; /// This should too - -/** - * BUG: The parameters are not listed under Params in the generated output - * - * Params: - * ü = first - * ş = second - * ğ = third - * - */ -int foo(int ü, int ş, int ğ) -{ - return ğ; -} diff --git a/gcc/testsuite/gdc.test/compilable/ddoc4162.d b/gcc/testsuite/gdc.test/compilable/ddoc4162.d index dd24475..f609fc9 100644 --- a/gcc/testsuite/gdc.test/compilable/ddoc4162.d +++ b/gcc/testsuite/gdc.test/compilable/ddoc4162.d @@ -1,4 +1,4 @@ -// PERMUTE_ARGS: +// PERMUTE_ARGS: // REQUIRED_ARGS: -D -Dd${RESULTS_DIR}/compilable -o- // POST_SCRIPT: compilable/extra-files/ddocAny-postscript.sh diff --git a/gcc/testsuite/gdc.test/compilable/ddoc5446.d b/gcc/testsuite/gdc.test/compilable/ddoc5446.d index 29cb8c9..2da477f 100644 --- a/gcc/testsuite/gdc.test/compilable/ddoc5446.d +++ b/gcc/testsuite/gdc.test/compilable/ddoc5446.d @@ -1,4 +1,4 @@ -// PERMUTE_ARGS: +// PERMUTE_ARGS: // REQUIRED_ARGS: -D -Dd${RESULTS_DIR}/compilable -o- // EXTRA_FILES: ddoc5446a.d ddoc5446b.d // POST_SCRIPT: compilable/extra-files/ddocAny-postscript.sh diff --git a/gcc/testsuite/gdc.test/compilable/ddoc7795.d b/gcc/testsuite/gdc.test/compilable/ddoc7795.d index 2a6ba02..9ad7740 100644 --- a/gcc/testsuite/gdc.test/compilable/ddoc7795.d +++ b/gcc/testsuite/gdc.test/compilable/ddoc7795.d @@ -1,4 +1,4 @@ -// PERMUTE_ARGS: +// PERMUTE_ARGS: // REQUIRED_ARGS: -D -Dd${RESULTS_DIR}/compilable -o- // POST_SCRIPT: compilable/extra-files/ddocAny-postscript.sh diff --git a/gcc/testsuite/gdc.test/compilable/ddoc_bom_UTF8.d b/gcc/testsuite/gdc.test/compilable/ddoc_bom_UTF8.d new file mode 100644 index 0000000..337f37a --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/ddoc_bom_UTF8.d @@ -0,0 +1,20 @@ +// PERMUTE_ARGS: +// REQUIRED_ARGS: -D -Dd${RESULTS_DIR}/compilable -o- +// POST_SCRIPT: compilable/extra-files/ddocAny-postscript.sh + +int ruhred; /// This documents correctly. +int rühred; /// This should too + +/** + * BUG: The parameters are not listed under Params in the generated output + * + * Params: + * ü = first + * ş = second + * ğ = third + * + */ +int foo(int ü, int ş, int ğ) +{ + return ğ; +} diff --git a/gcc/testsuite/gdc.test/compilable/test24338.d b/gcc/testsuite/gdc.test/compilable/test24338.d new file mode 100644 index 0000000..467b8bd --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/test24338.d @@ -0,0 +1,10 @@ +// https://issues.dlang.org/show_bug.cgi?id=24338 + +enum Foo: char[4] +{ + elem = "test" +} + +immutable a = [Foo.elem]; +immutable b = [Foo.elem]; +immutable c = a ~ b; diff --git a/gcc/testsuite/gdc.test/fail_compilation/discard_value.d b/gcc/testsuite/gdc.test/fail_compilation/discard_value.d new file mode 100644 index 0000000..7fe30a6 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/discard_value.d @@ -0,0 +1,34 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/discard_value.d(24): Error: the result of the equality expression `3 is 3` is discarded +fail_compilation/discard_value.d(25): Error: the result of the equality expression `null !is null` is discarded +fail_compilation/discard_value.d(26): Error: the result of the equality expression `v == 0` is discarded +fail_compilation/discard_value.d(27): Error: the result of the equality expression `v == 0` is discarded +fail_compilation/discard_value.d(28): Error: `!__equals("", "")` has no effect +fail_compilation/discard_value.d(29): Error: the result of the equality expression `"" == ""` is discarded +fail_compilation/discard_value.d(30): Error: the result of the equality expression `fun().i == 4` is discarded +fail_compilation/discard_value.d(30): note that `fun().i` may have a side effect +fail_compilation/discard_value.d(33): Error: the result of the equality expression `slice == slice[0..0]` is discarded +--- +*/ + +struct S { int i; } + +S fun() { return S(42); } + +int v; + +void main() +{ + 3 is 3; + null !is null; + true && v == 0; + true || v == 0; + "" != ""; + "" == ""; // https://issues.dlang.org/show_bug.cgi?id=24359 + fun().i == 4; // https://issues.dlang.org/show_bug.cgi?id=12390 + + int[] slice = [0, 1]; + slice == slice[0 .. 0]; +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail12390.d b/gcc/testsuite/gdc.test/fail_compilation/fail12390.d deleted file mode 100644 index 5c852a1..0000000 --- a/gcc/testsuite/gdc.test/fail_compilation/fail12390.d +++ /dev/null @@ -1,16 +0,0 @@ -/* -TEST_OUTPUT: ---- -fail_compilation/fail12390.d(15): Error: the result of the equality expression `fun().i == 4` is discarded -fail_compilation/fail12390.d(15): note that `fun().i` may have a side effect ---- -*/ - -struct S { int i; } - -S fun() { return S(42); } - -void main() -{ - fun().i == 4; -} diff --git a/gcc/testsuite/gdc.test/fail_compilation/gag4269a.d b/gcc/testsuite/gdc.test/fail_compilation/gag4269a.d index 3ab4db7..85a146c 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/gag4269a.d +++ b/gcc/testsuite/gdc.test/fail_compilation/gag4269a.d @@ -1,4 +1,4 @@ -// REQUIRED_ARGS: -c -o- +// REQUIRED_ARGS: -c -o- /* TEST_OUTPUT: --- diff --git a/gcc/testsuite/gdc.test/fail_compilation/gag4269b.d b/gcc/testsuite/gdc.test/fail_compilation/gag4269b.d index 718fa94..e680721 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/gag4269b.d +++ b/gcc/testsuite/gdc.test/fail_compilation/gag4269b.d @@ -1,4 +1,4 @@ -// REQUIRED_ARGS: -c -o- +// REQUIRED_ARGS: -c -o- /* TEST_OUTPUT: --- diff --git a/gcc/testsuite/gdc.test/fail_compilation/gag4269c.d b/gcc/testsuite/gdc.test/fail_compilation/gag4269c.d index 1a93831..1fa1567 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/gag4269c.d +++ b/gcc/testsuite/gdc.test/fail_compilation/gag4269c.d @@ -1,4 +1,4 @@ -// REQUIRED_ARGS: -c -o- +// REQUIRED_ARGS: -c -o- /* TEST_OUTPUT: --- diff --git a/gcc/testsuite/gdc.test/fail_compilation/gag4269d.d b/gcc/testsuite/gdc.test/fail_compilation/gag4269d.d index bdfabae..3154ea5 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/gag4269d.d +++ b/gcc/testsuite/gdc.test/fail_compilation/gag4269d.d @@ -1,4 +1,4 @@ -// REQUIRED_ARGS: -c -o- +// REQUIRED_ARGS: -c -o- /* TEST_OUTPUT: --- diff --git a/gcc/testsuite/gdc.test/fail_compilation/gag4269e.d b/gcc/testsuite/gdc.test/fail_compilation/gag4269e.d index d6eed62..4a5757c 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/gag4269e.d +++ b/gcc/testsuite/gdc.test/fail_compilation/gag4269e.d @@ -1,4 +1,4 @@ -// REQUIRED_ARGS: -c -o- +// REQUIRED_ARGS: -c -o- /* TEST_OUTPUT: --- diff --git a/gcc/testsuite/gdc.test/fail_compilation/gag4269f.d b/gcc/testsuite/gdc.test/fail_compilation/gag4269f.d index b571059..db781e9 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/gag4269f.d +++ b/gcc/testsuite/gdc.test/fail_compilation/gag4269f.d @@ -1,4 +1,4 @@ -// REQUIRED_ARGS: -c -o- +// REQUIRED_ARGS: -c -o- /* TEST_OUTPUT: --- diff --git a/gcc/testsuite/gdc.test/fail_compilation/gag4269g.d b/gcc/testsuite/gdc.test/fail_compilation/gag4269g.d index 348207e..4799fa1 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/gag4269g.d +++ b/gcc/testsuite/gdc.test/fail_compilation/gag4269g.d @@ -1,4 +1,4 @@ -// REQUIRED_ARGS: -c -o- +// REQUIRED_ARGS: -c -o- /* TEST_OUTPUT: --- diff --git a/gcc/testsuite/gdc.test/fail_compilation/hexstring.d b/gcc/testsuite/gdc.test/fail_compilation/hexstring.d index caca3b3..95b07e7 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/hexstring.d +++ b/gcc/testsuite/gdc.test/fail_compilation/hexstring.d @@ -2,8 +2,6 @@ TEST_OUTPUT: --- fail_compilation/hexstring.d(29): Error: cannot implicitly convert expression `"123F"` of type `string` to `immutable(ubyte[])` -fail_compilation/hexstring.d(30): Error: cannot implicitly convert expression `x"123F"c` of type `string` to `immutable(ubyte[])` -fail_compilation/hexstring.d(31): Error: cannot implicitly convert expression `x"123F"` of type `string` to `immutable(ubyte[])` fail_compilation/hexstring.d(33): Error: hex string length 1 must be a multiple of 2 to cast to `immutable(ushort[])` fail_compilation/hexstring.d(34): Error: hex string length 3 must be a multiple of 4 to cast to `immutable(uint[])` fail_compilation/hexstring.d(35): Error: hex string length 5 must be a multiple of 8 to cast to `immutable(ulong[])` @@ -13,6 +11,8 @@ fail_compilation/hexstring.d(37): Error: array cast from `string` to `immutable( fail_compilation/hexstring.d(38): Error: array cast from `string` to `immutable(ushort[])` is not supported at compile time fail_compilation/hexstring.d(39): Error: array cast from `string` to `immutable(uint[])` is not supported at compile time fail_compilation/hexstring.d(39): perhaps remove postfix `c` from hex string +fail_compilation/hexstring.d(40): Error: hex string with `dstring` type needs to be multiple of 4 bytes, not 5 +fail_compilation/hexstring.d(41): Error: cannot implicitly convert expression `x"44332211"d` of type `dstring` to `immutable(float[])` fail_compilation/hexstring.d(28): Error: cannot implicitly convert expression `x"123F"` of type `string` to `ubyte[]` --- */ @@ -33,7 +33,9 @@ immutable ubyte[] f4 = cast(string) x"123F"; immutable ushort[] f5 = cast(immutable ushort[]) x"11"; immutable uint[] f6 = cast(immutable uint[]) x"112233"; immutable ulong[] f7 = cast(immutable ulong[]) x"1122334455"; -immutable ulong[] f8 = cast(immutable ulong[]) x"1122334455"w; +immutable ulong[] f8 = cast(immutable ulong[]) x"11223344"w; immutable uint[] f9 = cast(immutable uint[]) "ABCD"; immutable ushort[] f10 = cast(immutable ushort[]) (x"1122" ~ ""); immutable uint[] f11 = cast(immutable uint[]) x"AABBCCDD"c; +immutable uint[] f12 = x"1122334455"d; +immutable float[] f13 = x"11223344"d; diff --git a/gcc/testsuite/gdc.test/fail_compilation/ice10599.d b/gcc/testsuite/gdc.test/fail_compilation/ice10599.d index 6e9649c..378894d 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/ice10599.d +++ b/gcc/testsuite/gdc.test/fail_compilation/ice10599.d @@ -1,4 +1,4 @@ -// https://issues.dlang.org/show_bug.cgi?id=10599 +// https://issues.dlang.org/show_bug.cgi?id=10599 // ICE(interpret.c) /* TEST_OUTPUT: diff --git a/gcc/testsuite/gdc.test/fail_compilation/test24365.d b/gcc/testsuite/gdc.test/fail_compilation/test24365.d new file mode 100644 index 0000000..9ec1e2a --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/test24365.d @@ -0,0 +1,20 @@ +// https://issues.dlang.org/show_bug.cgi?id=243645 + +/* +TEST_OUTPUT: +--- +fail_compilation/test24365.d(16): Error: `f` cannot be interpreted at compile time, because it has no available source code +fail_compilation/test24365.d(14): compile time context created here +fail_compilation/test24365.d(19): while evaluating: `static assert(r == 2)` +--- +*/ + +void main() +{ + enum r = () { + void f(); + f(); + return 2; + }(); + static assert(r == 2); +} diff --git a/gcc/testsuite/gdc.test/runnable/helloUTF8.d b/gcc/testsuite/gdc.test/runnable/helloUTF8.d deleted file mode 100644 index aed6613..0000000 --- a/gcc/testsuite/gdc.test/runnable/helloUTF8.d +++ /dev/null @@ -1,16 +0,0 @@ -/* -PERMUTE_ARGS: -RUN_OUTPUT: ---- -hello world ---- -*/ - -extern(C) int printf(const char *, ...); - -int main(char[][] args) -{ - printf("hello world\n"); - - return 0; -} diff --git a/gcc/testsuite/gdc.test/runnable/literal.d b/gcc/testsuite/gdc.test/runnable/literal.d index 6997124..27b5543 100644 --- a/gcc/testsuite/gdc.test/runnable/literal.d +++ b/gcc/testsuite/gdc.test/runnable/literal.d @@ -260,6 +260,19 @@ void testHexstring() // Test printing StringExp with size 8 enum toStr(immutable ulong[] v) = v.stringof; static assert(toStr!y == `x"88776655443322119900FFEEDDCCBBAA"`); + + // Hex string postfixes + // https://issues.dlang.org/show_bug.cgi?id=24363 + wstring wStr = x"AA BB CC DD"w; + immutable int[] dStr = x"AA BB CC DD"d; + assert(wStr[0] == 0xAABB); + assert(wStr[1] == 0xCCDD); + assert(dStr[0] == 0xAABBCCDD); + + // Test sliceCmpStringWithArray with size 8 + static immutable ulong[] z0 = cast(immutable ulong[]) x"1111 1111 1111 1111 0000 000F 0000 0000"; + static immutable ulong[] z1 = [0x1111_1111_1111_1111, 0x0000_000E_0000_0000]; + static assert(z0 !is z1); } /***************************************************/ diff --git a/gcc/testsuite/gdc.test/runnable/staticaa.d b/gcc/testsuite/gdc.test/runnable/staticaa.d index 606b70e..e5b25d1 100644 --- a/gcc/testsuite/gdc.test/runnable/staticaa.d +++ b/gcc/testsuite/gdc.test/runnable/staticaa.d @@ -154,6 +154,17 @@ void testLocalStatic() @trusted ///////////////////////////////////////////// +// https://issues.dlang.org/show_bug.cgi?id=24311 +enum E : int[int] { x = [123: 456] } + +void testEnumInit() +{ + E e = E.init; + assert(e[123] == 456); +} + +///////////////////////////////////////////// + void main() { testSimple(); @@ -163,4 +174,5 @@ void main() testClassInit(); testImmutable(); testLocalStatic(); + testEnumInit(); } diff --git a/gcc/testsuite/gdc.test/runnable/xtestenum.d b/gcc/testsuite/gdc.test/runnable/xtestenum.d index ce77782..4a4edd1 100644 --- a/gcc/testsuite/gdc.test/runnable/xtestenum.d +++ b/gcc/testsuite/gdc.test/runnable/xtestenum.d @@ -156,6 +156,19 @@ class C7379 } /***********************************/ +// https://issues.dlang.org/show_bug.cgi?id=23515 + +enum Easing : void function() +{ + identity1 = (){}, +} + +void test23515() +{ + Easing.identity1(); +} + +/***********************************/ int main() { @@ -166,6 +179,7 @@ int main() test5(); test6(); test7(); + test23515(); printf("Success\n"); return 0; -- cgit v1.1 From 8e6ebacc9e3cee0d2053fdaceda0ae052e34b777 Mon Sep 17 00:00:00 2001 From: Li Wei Date: Fri, 2 Feb 2024 09:42:28 +0800 Subject: LoongArch: testsuite: Fix gcc.dg/vect/vect-reduc-mul_{1, 2}.c FAIL. This FAIL was introduced from r14-6908. The reason is that when merging constant vector permutation implementations, the 128-bit matching situation was not fully considered. In fact, the expansion of 128-bit vectors after merging only supports value-based 4 elements set shuffle, so this time is a complete implementation of the entire 128-bit vector constant permutation, and some structural adjustments have also been made to the code. gcc/ChangeLog: * config/loongarch/loongarch.cc (loongarch_expand_vselect): Adjust. (loongarch_expand_vselect_vconcat): Ditto. (loongarch_try_expand_lsx_vshuf_const): New, use vshuf to implement all 128-bit constant permutation situations. (loongarch_expand_lsx_shuffle): Adjust and rename function name. (loongarch_is_imm_set_shuffle): Renamed function name. (loongarch_expand_vec_perm_even_odd): Function forward declaration. (loongarch_expand_vec_perm_even_odd_1): Add implement for 128-bit extract-even and extract-odd permutations. (loongarch_is_odd_extraction): Delete. (loongarch_is_even_extraction): Ditto. (loongarch_expand_vec_perm_const): Adjust. --- gcc/config/loongarch/loongarch.cc | 218 ++++++++++++++++++++++++++++---------- 1 file changed, 163 insertions(+), 55 deletions(-) (limited to 'gcc') diff --git a/gcc/config/loongarch/loongarch.cc b/gcc/config/loongarch/loongarch.cc index 8bc1844..6172384 100644 --- a/gcc/config/loongarch/loongarch.cc +++ b/gcc/config/loongarch/loongarch.cc @@ -8029,7 +8029,8 @@ struct expand_vec_perm_d static bool loongarch_expand_vselect (rtx target, rtx op0, - const unsigned char *perm, unsigned nelt) + const unsigned char *perm, unsigned nelt, + bool testing_p) { rtx rperm[MAX_VECT_LEN], x; rtx_insn *insn; @@ -8048,6 +8049,9 @@ loongarch_expand_vselect (rtx target, rtx op0, remove_insn (insn); return false; } + + if (testing_p) + remove_insn (insn); return true; } @@ -8055,7 +8059,8 @@ loongarch_expand_vselect (rtx target, rtx op0, static bool loongarch_expand_vselect_vconcat (rtx target, rtx op0, rtx op1, - const unsigned char *perm, unsigned nelt) + const unsigned char *perm, unsigned nelt, + bool testing_p) { machine_mode v2mode; rtx x; @@ -8063,7 +8068,7 @@ loongarch_expand_vselect_vconcat (rtx target, rtx op0, rtx op1, if (!GET_MODE_2XWIDER_MODE (GET_MODE (op0)).exists (&v2mode)) return false; x = gen_rtx_VEC_CONCAT (v2mode, op0, op1); - return loongarch_expand_vselect (target, x, perm, nelt); + return loongarch_expand_vselect (target, x, perm, nelt, testing_p); } static tree @@ -8317,11 +8322,87 @@ loongarch_set_handled_components (sbitmap components) #define TARGET_ASM_ALIGNED_SI_OP "\t.word\t" #undef TARGET_ASM_ALIGNED_DI_OP #define TARGET_ASM_ALIGNED_DI_OP "\t.dword\t" + +/* Use the vshuf instruction to implement all 128-bit constant vector + permuatation. */ + +static bool +loongarch_try_expand_lsx_vshuf_const (struct expand_vec_perm_d *d) +{ + int i; + rtx target, op0, op1, sel, tmp; + rtx rperm[MAX_VECT_LEN]; + + if (GET_MODE_SIZE (d->vmode) == 16) + { + target = d->target; + op0 = d->op0; + op1 = d->one_vector_p ? d->op0 : d->op1; + + if (GET_MODE (op0) != GET_MODE (op1) + || GET_MODE (op0) != GET_MODE (target)) + return false; + + if (d->testing_p) + return true; + + for (i = 0; i < d->nelt; i += 1) + rperm[i] = GEN_INT (d->perm[i]); + + if (d->vmode == E_V2DFmode) + { + sel = gen_rtx_CONST_VECTOR (E_V2DImode, gen_rtvec_v (d->nelt, rperm)); + tmp = simplify_gen_subreg (E_V2DImode, d->target, d->vmode, 0); + emit_move_insn (tmp, sel); + } + else if (d->vmode == E_V4SFmode) + { + sel = gen_rtx_CONST_VECTOR (E_V4SImode, gen_rtvec_v (d->nelt, rperm)); + tmp = simplify_gen_subreg (E_V4SImode, d->target, d->vmode, 0); + emit_move_insn (tmp, sel); + } + else + { + sel = gen_rtx_CONST_VECTOR (d->vmode, gen_rtvec_v (d->nelt, rperm)); + emit_move_insn (d->target, sel); + } + + switch (d->vmode) + { + case E_V2DFmode: + emit_insn (gen_lsx_vshuf_d_f (target, target, op1, op0)); + break; + case E_V2DImode: + emit_insn (gen_lsx_vshuf_d (target, target, op1, op0)); + break; + case E_V4SFmode: + emit_insn (gen_lsx_vshuf_w_f (target, target, op1, op0)); + break; + case E_V4SImode: + emit_insn (gen_lsx_vshuf_w (target, target, op1, op0)); + break; + case E_V8HImode: + emit_insn (gen_lsx_vshuf_h (target, target, op1, op0)); + break; + case E_V16QImode: + emit_insn (gen_lsx_vshuf_b (target, op1, op0, target)); + break; + default: + break; + } + + return true; + } + return false; +} + /* Construct (set target (vec_select op0 (parallel selector))) and - return true if that's a valid instruction in the active ISA. */ + return true if that's a valid instruction in the active ISA. + In fact, it matches the special constant vector with repeated + 4-element sets. */ static bool -loongarch_expand_lsx_shuffle (struct expand_vec_perm_d *d) +loongarch_is_imm_set_shuffle (struct expand_vec_perm_d *d) { rtx x, elts[MAX_VECT_LEN]; rtvec v; @@ -8340,6 +8421,9 @@ loongarch_expand_lsx_shuffle (struct expand_vec_perm_d *d) if (!loongarch_const_vector_shuffle_set_p (x, d->vmode)) return false; + if (d->testing_p) + return true; + x = gen_rtx_VEC_SELECT (d->vmode, d->op0, x); x = gen_rtx_SET (d->target, x); @@ -8352,6 +8436,27 @@ loongarch_expand_lsx_shuffle (struct expand_vec_perm_d *d) return true; } +static bool +loongarch_expand_vec_perm_even_odd (struct expand_vec_perm_d *); + +/* Try to match and expand all kinds of 128-bit const vector permutation + cases. */ + +static bool +loongarch_expand_lsx_shuffle (struct expand_vec_perm_d *d) +{ + if (!ISA_HAS_LSX && GET_MODE_SIZE (d->vmode) != 16) + return false; + + if (loongarch_is_imm_set_shuffle (d)) + return true; + + if (loongarch_expand_vec_perm_even_odd (d)) + return true; + + return loongarch_try_expand_lsx_vshuf_const (d); +} + /* Try to simplify a two vector permutation using 2 intra-lane interleave insns and cross-lane shuffle for 32-byte vectors. */ @@ -8444,7 +8549,7 @@ loongarch_expand_vec_perm_interleave (struct expand_vec_perm_d *d) return true; } -/* Implement extract-even and extract-odd permutations. */ +/* Implement 128-bit and 256-bit extract-even and extract-odd permutations. */ static bool loongarch_expand_vec_perm_even_odd_1 (struct expand_vec_perm_d *d, unsigned odd) @@ -8459,6 +8564,50 @@ loongarch_expand_vec_perm_even_odd_1 (struct expand_vec_perm_d *d, unsigned odd) switch (d->vmode) { + /* 128 bit. */ + case E_V2DFmode: + if (odd) + emit_insn (gen_lsx_vilvh_d_f (d->target, d->op0, d->op1)); + else + emit_insn (gen_lsx_vilvl_d_f (d->target, d->op0, d->op1)); + break; + + case E_V2DImode: + if (odd) + emit_insn (gen_lsx_vilvh_d (d->target, d->op0, d->op1)); + else + emit_insn (gen_lsx_vilvl_d (d->target, d->op0, d->op1)); + break; + + case E_V4SFmode: + if (odd) + emit_insn (gen_lsx_vpickod_w_f (d->target, d->op0, d->op1)); + else + emit_insn (gen_lsx_vpickev_w_f (d->target, d->op0, d->op1)); + break; + + case E_V4SImode: + if (odd) + emit_insn (gen_lsx_vpickod_w (d->target, d->op0, d->op1)); + else + emit_insn (gen_lsx_vpickev_w (d->target, d->op0, d->op1)); + break; + + case E_V8HImode: + if (odd) + emit_insn (gen_lsx_vpickod_h (d->target, d->op0, d->op1)); + else + emit_insn (gen_lsx_vpickev_h (d->target, d->op0, d->op1)); + break; + + case E_V16QImode: + if (odd) + emit_insn (gen_lsx_vpickod_b (d->target, d->op0, d->op1)); + else + emit_insn (gen_lsx_vpickev_b (d->target, d->op0, d->op1)); + break; + + /* 256 bit. */ case E_V4DFmode: /* Shuffle the lanes around into { 0 4 2 6 } and { 1 5 3 7 }. */ if (odd) @@ -8533,7 +8682,7 @@ static bool loongarch_expand_vec_perm_even_odd (struct expand_vec_perm_d *d) { unsigned i, odd, nelt = d->nelt; - if (!ISA_HAS_LASX) + if (!ISA_HAS_LASX && !ISA_HAS_LSX) return false; odd = d->perm[0]; @@ -8997,44 +9146,6 @@ loongarch_is_quad_duplicate (struct expand_vec_perm_d *d) } static bool -loongarch_is_odd_extraction (struct expand_vec_perm_d *d) -{ - bool result = true; - unsigned char buf = 1; - - for (int i = 0; i < d->nelt; i += 1) - { - if (buf != d->perm[i]) - { - result = false; - break; - } - buf += 2; - } - - return result; -} - -static bool -loongarch_is_even_extraction (struct expand_vec_perm_d *d) -{ - bool result = true; - unsigned char buf = 0; - - for (int i = 0; i < d->nelt; i += 1) - { - if (buf != d->perm[i]) - { - result = false; - break; - } - buf += 2; - } - - return result; -} - -static bool loongarch_is_extraction_permutation (struct expand_vec_perm_d *d) { bool result = true; @@ -9290,32 +9401,29 @@ loongarch_expand_vec_perm_const (struct expand_vec_perm_d *d) for (i = 1; i < d->nelt; i += 2) perm2[i] += d->nelt; if (loongarch_expand_vselect_vconcat (d->target, d->op0, d->op1, - perm2, d->nelt)) + perm2, d->nelt, d->testing_p)) return true; } else { if (loongarch_expand_vselect_vconcat (d->target, d->op0, d->op1, - d->perm, d->nelt)) + d->perm, d->nelt, + d->testing_p)) return true; /* Try again with swapped operands. */ for (i = 0; i < d->nelt; ++i) perm2[i] = (d->perm[i] + d->nelt) & (2 * d->nelt - 1); if (loongarch_expand_vselect_vconcat (d->target, d->op1, d->op0, - perm2, d->nelt)) + perm2, d->nelt, d->testing_p)) return true; } - if (loongarch_expand_lsx_shuffle (d)) + if (loongarch_is_imm_set_shuffle (d)) return true; - if (loongarch_is_odd_extraction (d) - || loongarch_is_even_extraction (d)) - { - if (loongarch_expand_vec_perm_even_odd (d)) - return true; - } + if (loongarch_expand_vec_perm_even_odd (d)) + return true; if (loongarch_is_lasx_lowpart_interleave (d) || loongarch_is_lasx_lowpart_interleave_2 (d) -- cgit v1.1 From 829b26328aebca167083f4cf81ca69f7d906e704 Mon Sep 17 00:00:00 2001 From: Xi Ruoyao Date: Fri, 2 Feb 2024 08:51:08 +0800 Subject: LoongArch: Avoid out-of-bounds access in loongarch_symbol_insns We call loongarch_symbol_insns with mode = MAX_MACHINE_MODE sometimes. But in loongarch_symbol_insns: if (LSX_SUPPORTED_MODE_P (mode) || LASX_SUPPORTED_MODE_P (mode)) return 0; And LSX_SUPPORTED_MODE_P is defined as: #define LSX_SUPPORTED_MODE_P(MODE) \ (ISA_HAS_LSX \ && GET_MODE_SIZE (MODE) == UNITS_PER_LSX_REG ... ... GET_MODE_SIZE is expanded to a call to mode_to_bytes, which is defined: ALWAYS_INLINE poly_uint16 mode_to_bytes (machine_mode mode) { #if GCC_VERSION >= 4001 return (__builtin_constant_p (mode) ? mode_size_inline (mode) : mode_size[mode]); #else return mode_size[mode]; #endif } There is an assertion in mode_size_inline: gcc_assert (mode >= 0 && mode < NUM_MACHINE_MODES); Note that NUM_MACHINE_MODES = MAX_MACHINE_MODE (emitted by genmodes.cc), thus if __builtin_constant_p (mode) is evaluated true (it happens when GCC is bootstrapped with LTO+PGO), the assertion will be triggered and cause an ICE. OTOH if __builtin_constant_p (mode) is evaluated false, mode_size[mode] is still an out-of-bound array access (the length or the mode_size array is NUM_MACHINE_MODES). So we shouldn't call LSX_SUPPORTED_MODE_P or LASX_SUPPORTED_MODE_P with MAX_MACHINE_MODE in loongarch_symbol_insns. This is very similar to a MIPS bug PR98491 fixed by me about 3 years ago. gcc/ChangeLog: * config/loongarch/loongarch.cc (loongarch_symbol_insns): Do not use LSX_SUPPORTED_MODE_P or LASX_SUPPORTED_MODE_P if mode is MAX_MACHINE_MODE. --- gcc/config/loongarch/loongarch.cc | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'gcc') diff --git a/gcc/config/loongarch/loongarch.cc b/gcc/config/loongarch/loongarch.cc index 6172384..0428b6e 100644 --- a/gcc/config/loongarch/loongarch.cc +++ b/gcc/config/loongarch/loongarch.cc @@ -2007,7 +2007,8 @@ loongarch_symbol_insns (enum loongarch_symbol_type type, machine_mode mode) { /* LSX LD.* and ST.* cannot support loading symbols via an immediate operand. */ - if (LSX_SUPPORTED_MODE_P (mode) || LASX_SUPPORTED_MODE_P (mode)) + if (mode != MAX_MACHINE_MODE + && (LSX_SUPPORTED_MODE_P (mode) || LASX_SUPPORTED_MODE_P (mode))) return 0; switch (type) -- cgit v1.1 From aa33570033fb642f2e25326cd67f98e70f199533 Mon Sep 17 00:00:00 2001 From: Xi Ruoyao Date: Sat, 3 Feb 2024 03:16:14 +0800 Subject: LoongArch: Fix wrong LSX FP vector negation We expanded (neg x) to (minus const0 x) for LSX FP vectors, this is wrong because -0.0 is not 0 - 0.0. This causes some Python tests to fail when Python is built with LSX enabled. Use the vbitrevi.{d/w} instructions to simply reverse the sign bit instead. We are already doing this for LASX and now we can unify them into simd.md. gcc/ChangeLog: * config/loongarch/lsx.md (neg2): Remove the incorrect expand. * config/loongarch/simd.md (simdfmt_as_i): New define_mode_attr. (elmsgnbit): Likewise. (neg2): New define_insn. * config/loongarch/lasx.md (negv4df2, negv8sf2): Remove as they are now instantiated in simd.md. --- gcc/config/loongarch/lasx.md | 16 ---------------- gcc/config/loongarch/lsx.md | 11 ----------- gcc/config/loongarch/simd.md | 18 ++++++++++++++++++ 3 files changed, 18 insertions(+), 27 deletions(-) (limited to 'gcc') diff --git a/gcc/config/loongarch/lasx.md b/gcc/config/loongarch/lasx.md index e2115ff..ac84db7 100644 --- a/gcc/config/loongarch/lasx.md +++ b/gcc/config/loongarch/lasx.md @@ -3028,22 +3028,6 @@ [(set_attr "type" "simd_logic") (set_attr "mode" "V8SF")]) -(define_insn "negv4df2" - [(set (match_operand:V4DF 0 "register_operand" "=f") - (neg:V4DF (match_operand:V4DF 1 "register_operand" "f")))] - "ISA_HAS_LASX" - "xvbitrevi.d\t%u0,%u1,63" - [(set_attr "type" "simd_logic") - (set_attr "mode" "V4DF")]) - -(define_insn "negv8sf2" - [(set (match_operand:V8SF 0 "register_operand" "=f") - (neg:V8SF (match_operand:V8SF 1 "register_operand" "f")))] - "ISA_HAS_LASX" - "xvbitrevi.w\t%u0,%u1,31" - [(set_attr "type" "simd_logic") - (set_attr "mode" "V8SF")]) - (define_insn "xvfmadd4" [(set (match_operand:FLASX 0 "register_operand" "=f") (fma:FLASX (match_operand:FLASX 1 "register_operand" "f") diff --git a/gcc/config/loongarch/lsx.md b/gcc/config/loongarch/lsx.md index 7002eda..b9b94b9 100644 --- a/gcc/config/loongarch/lsx.md +++ b/gcc/config/loongarch/lsx.md @@ -728,17 +728,6 @@ DONE; }) -(define_expand "neg2" - [(set (match_operand:FLSX 0 "register_operand") - (neg:FLSX (match_operand:FLSX 1 "register_operand")))] - "ISA_HAS_LSX" -{ - rtx reg = gen_reg_rtx (mode); - emit_move_insn (reg, CONST0_RTX (mode)); - emit_insn (gen_sub3 (operands[0], reg, operands[1])); - DONE; -}) - (define_expand "lsx_vrepli" [(match_operand:ILSX 0 "register_operand") (match_operand 1 "const_imm10_operand")] diff --git a/gcc/config/loongarch/simd.md b/gcc/config/loongarch/simd.md index cb0a194..00ff282 100644 --- a/gcc/config/loongarch/simd.md +++ b/gcc/config/loongarch/simd.md @@ -85,12 +85,21 @@ (define_mode_attr simdifmt_for_f [(V2DF "l") (V4DF "l") (V4SF "w") (V8SF "w")]) +;; Suffix for integer mode in LSX or LASX instructions to operating FP +;; vectors using integer vector operations. +(define_mode_attr simdfmt_as_i [(V2DF "d") (V4DF "d") + (V4SF "w") (V8SF "w")]) + ;; Size of vector elements in bits. (define_mode_attr elmbits [(V2DI "64") (V4DI "64") (V4SI "32") (V8SI "32") (V8HI "16") (V16HI "16") (V16QI "8") (V32QI "8")]) +;; The index of sign bit in FP vector elements. +(define_mode_attr elmsgnbit [(V2DF "63") (V4DF "63") + (V4SF "31") (V8SF "31")]) + ;; This attribute is used to form an immediate operand constraint using ;; "const__operand". (define_mode_attr bitimm [(V16QI "uimm3") (V32QI "uimm3") @@ -457,6 +466,15 @@ DONE; }) +;; FP negation. +(define_insn "neg2" + [(set (match_operand:FVEC 0 "register_operand" "=f") + (neg:FVEC (match_operand:FVEC 1 "register_operand" "f")))] + "" + "vbitrevi.\t%0,%1," + [(set_attr "type" "simd_logic") + (set_attr "mode" "")]) + ; The LoongArch SX Instructions. (include "lsx.md") -- cgit v1.1 From 777df37a12e55ecbc135efbed2749a8a8a756d4d Mon Sep 17 00:00:00 2001 From: Jeff Law Date: Sun, 4 Feb 2024 13:01:50 -0700 Subject: [committed] Reasonably handle SUBREGs in risc-v cost modeling This patch adjusts the costs so that we treat REG and SUBREG expressions the same for costing. This was motivated by bt_skip_func and bt_find_func in xz and results in nearly a 5% improvement in the dynamic instruction count for input #2 and smaller, but definitely visible improvements pretty much across the board. Exceptions would be perlbench input #1 and exchange2 which showed very small regressions. In the bt_find_func and bt_skip_func cases we have something like this: > (insn 10 7 11 2 (set (reg/v:DI 136 [ x ]) > (zero_extend:DI (subreg/s/u:SI (reg/v:DI 137 [ a ]) 0))) "zz.c":6:21 387 {*zero_extendsidi2_bitmanip} > (nil)) > (insn 11 10 12 2 (set (reg:DI 142 [ _1 ]) > (plus:DI (reg/v:DI 136 [ x ]) > (reg/v:DI 139 [ b ]))) "zz.c":7:23 5 {adddi3} > (nil)) [ ... ]> (insn 13 12 14 2 (set (reg:DI 143 [ _2 ]) > (plus:DI (reg/v:DI 136 [ x ]) > (reg/v:DI 141 [ c ]))) "zz.c":8:23 5 {adddi3} > (nil)) Note the two uses of (reg 136). The best way to handle that in combine might be a 3->2 split. But there's a much better approach if we look at fwprop... (set (reg:DI 142 [ _1 ]) (plus:DI (zero_extend:DI (subreg/s/u:SI (reg/v:DI 137 [ a ]) 0)) (reg/v:DI 139 [ b ]))) change not profitable (cost 4 -> cost 8) So that should be the same cost as a regular DImode addition when the ZBA extension is enabled. But it ends up costing more because the clause to cost this variant isn't prepared to handle a SUBREG. That results in the RTL above having too high a cost and fwprop gives up. One approach would be to replace the REG_P with REG_P || SUBREG_P in the costing code. I ultimately decided against that and instead check if the operand in question passes register_operand. By far the most important case to handle is the DImode PLUS. But for the sake of consistency, I changed the other instances in riscv_rtx_costs as well. For those other cases we're talking about improvements in the .000001% range. While we are into stage4, this just hits cost modeling which we've generally agreed is still appropriate (though we were mostly talking about vector). So I'm going to extend that general agreement ever so slightly and include scalar cost modeling :-) gcc/ * config/riscv/riscv.cc (riscv_rtx_costs): Handle SUBREG and REG similarly. gcc/testsuite/ * gcc.target/riscv/reg_subreg_costs.c: New test. Co-authored-by: Jivan Hakobyan --- gcc/config/riscv/riscv.cc | 18 +++++++++++------- gcc/testsuite/gcc.target/riscv/reg_subreg_costs.c | 15 +++++++++++++++ 2 files changed, 26 insertions(+), 7 deletions(-) create mode 100644 gcc/testsuite/gcc.target/riscv/reg_subreg_costs.c (limited to 'gcc') diff --git a/gcc/config/riscv/riscv.cc b/gcc/config/riscv/riscv.cc index d7cdd71..d6868a6 100644 --- a/gcc/config/riscv/riscv.cc +++ b/gcc/config/riscv/riscv.cc @@ -3055,7 +3055,8 @@ riscv_rtx_costs (rtx x, machine_mode mode, int outer_code, int opno ATTRIBUTE_UN case SET: /* If we are called for an INSN that's a simple set of a register, then cost based on the SET_SRC alone. */ - if (outer_code == INSN && REG_P (SET_DEST (x))) + if (outer_code == INSN + && register_operand (SET_DEST (x), GET_MODE (SET_DEST (x)))) { riscv_rtx_costs (SET_SRC (x), mode, outer_code, opno, total, speed); return true; @@ -3172,7 +3173,7 @@ riscv_rtx_costs (rtx x, machine_mode mode, int outer_code, int opno ATTRIBUTE_UN rtx and_rhs = XEXP (x, 1); rtx ashift_lhs = XEXP (XEXP (x, 0), 0); rtx ashift_rhs = XEXP (XEXP (x, 0), 1); - if (REG_P (ashift_lhs) + if (register_operand (ashift_lhs, GET_MODE (ashift_lhs)) && CONST_INT_P (ashift_rhs) && CONST_INT_P (and_rhs) && ((INTVAL (and_rhs) >> INTVAL (ashift_rhs)) == 0xffffffff)) @@ -3188,7 +3189,7 @@ riscv_rtx_costs (rtx x, machine_mode mode, int outer_code, int opno ATTRIBUTE_UN } /* bclr pattern for zbs. */ if (TARGET_ZBS - && REG_P (XEXP (x, 1)) + && register_operand (XEXP (x, 1), GET_MODE (XEXP (x, 1))) && GET_CODE (XEXP (x, 0)) == ROTATE && CONST_INT_P (XEXP ((XEXP (x, 0)), 0)) && INTVAL (XEXP ((XEXP (x, 0)), 0)) == -2) @@ -3344,7 +3345,8 @@ riscv_rtx_costs (rtx x, machine_mode mode, int outer_code, int opno ATTRIBUTE_UN if (TARGET_ZBA && (TARGET_64BIT && (mode == DImode)) && GET_CODE (XEXP (x, 0)) == ZERO_EXTEND - && REG_P (XEXP (XEXP (x, 0), 0)) + && register_operand (XEXP (XEXP (x, 0), 0), + GET_MODE (XEXP (XEXP (x, 0), 0))) && GET_MODE (XEXP (XEXP (x, 0), 0)) == SImode) { *total = COSTS_N_INSNS (1); @@ -3355,7 +3357,8 @@ riscv_rtx_costs (rtx x, machine_mode mode, int outer_code, int opno ATTRIBUTE_UN && ((!TARGET_64BIT && (mode == SImode)) || (TARGET_64BIT && (mode == DImode))) && (GET_CODE (XEXP (x, 0)) == ASHIFT) - && REG_P (XEXP (XEXP (x, 0), 0)) + && register_operand (XEXP (XEXP (x, 0), 0), + GET_MODE (XEXP (XEXP (x, 0), 0))) && CONST_INT_P (XEXP (XEXP (x, 0), 1)) && IN_RANGE (INTVAL (XEXP (XEXP (x, 0), 1)), 1, 3)) { @@ -3368,7 +3371,8 @@ riscv_rtx_costs (rtx x, machine_mode mode, int outer_code, int opno ATTRIBUTE_UN if (TARGET_ZBA && mode == word_mode && GET_CODE (XEXP (x, 0)) == MULT - && REG_P (XEXP (XEXP (x, 0), 0)) + && register_operand (XEXP (XEXP (x, 0), 0), + GET_MODE (XEXP (XEXP (x, 0), 0))) && CONST_INT_P (XEXP (XEXP (x, 0), 1)) && pow2p_hwi (INTVAL (XEXP (XEXP (x, 0), 1))) && IN_RANGE (exact_log2 (INTVAL (XEXP (XEXP (x, 0), 1))), 1, 3)) @@ -3390,7 +3394,7 @@ riscv_rtx_costs (rtx x, machine_mode mode, int outer_code, int opno ATTRIBUTE_UN if (TARGET_ZBA && (TARGET_64BIT && (mode == DImode)) && (GET_CODE (XEXP (x, 0)) == AND) - && (REG_P (XEXP (x, 1)))) + && register_operand (XEXP (x, 1), GET_MODE (XEXP (x, 1)))) { do { rtx and_lhs = XEXP (XEXP (x, 0), 0); diff --git a/gcc/testsuite/gcc.target/riscv/reg_subreg_costs.c b/gcc/testsuite/gcc.target/riscv/reg_subreg_costs.c new file mode 100644 index 0000000..874dff3 --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/reg_subreg_costs.c @@ -0,0 +1,15 @@ +/* { dg-do compile } */ +/* { dg-require-effective-target rv64 } */ +/* { dg-skip-if "" { *-*-* } { "-O0" "-Og" "-Os" "-Oz" } } */ +/* { dg-options "-march=rv64gc_zba" } */ + +#include +void foo(uint32_t a, uint64_t *b_ptr, uint64_t b, uint64_t *c_ptr, uint64_t c) +{ + uint64_t x = a; + *b_ptr = b + x; + *c_ptr = c + x; +} + +/* { dg-final { scan-assembler-not "\\szext.w\\s" } } */ + -- cgit v1.1 From 7c2c7dd24bd93cd9cb8a6e54a4d11850982665fd Mon Sep 17 00:00:00 2001 From: Takayuki 'January June' Suwa Date: Sun, 4 Feb 2024 19:20:16 +0900 Subject: xtensa: Recover constant synthesis for HImode after LRA transition After LRA transition, HImode constants that don't fit into signed 12 bits are no longer subject to constant synthesis: /* example */ void test(void) { short foo = 32767; __asm__ ("" :: "r"(foo)); } ;; before .literal_position .literal .LC0, 32767 test: l32r a9, .LC0 ret.n This patch fixes that: ;; after test: movi.n a9, -1 extui a9, a9, 17, 15 ret.n gcc/ChangeLog: * config/xtensa/xtensa.md (SHI): New mode iterator. (2 split patterns related to constsynth): Change to also accept HImode operands. --- gcc/config/xtensa/xtensa.md | 22 ++++++++++++++-------- 1 file changed, 14 insertions(+), 8 deletions(-) (limited to 'gcc') diff --git a/gcc/config/xtensa/xtensa.md b/gcc/config/xtensa/xtensa.md index f3953aa..d07e121 100644 --- a/gcc/config/xtensa/xtensa.md +++ b/gcc/config/xtensa/xtensa.md @@ -87,6 +87,10 @@ ;; the same template. (define_mode_iterator HQI [HI QI]) +;; This mode iterator allows the SI and HI patterns to be defined from +;; the same template. +(define_mode_iterator SHI [SI HI]) + ;; Attributes. @@ -1291,28 +1295,30 @@ (set_attr "length" "2,2,2,2,2,2,3,3,3,3,6,3,3,3,3,3")]) (define_split - [(set (match_operand:SI 0 "register_operand") - (match_operand:SI 1 "const_int_operand"))] + [(set (match_operand:SHI 0 "register_operand") + (match_operand:SHI 1 "const_int_operand"))] "!TARGET_CONST16 && !TARGET_AUTO_LITPOOLS && ! xtensa_split1_finished_p () && ! xtensa_simm12b (INTVAL (operands[1]))" [(set (match_dup 0) (match_dup 1))] { - operands[1] = force_const_mem (SImode, operands[1]); + operands[1] = force_const_mem (mode, operands[1]); }) (define_split - [(set (match_operand:SI 0 "register_operand") - (match_operand:SI 1 "constantpool_operand"))] + [(set (match_operand:SHI 0 "register_operand") + (match_operand:SHI 1 "constantpool_operand"))] "! optimize_debug && reload_completed" [(const_int 0)] { - rtx x = avoid_constant_pool_reference (operands[1]); + rtx x = avoid_constant_pool_reference (operands[1]), dst = operands[0]; if (! CONST_INT_P (x)) FAIL; - if (! xtensa_constantsynth (operands[0], INTVAL (x))) - emit_move_insn (operands[0], x); + if (mode == HImode) + dst = gen_rtx_REG (SImode, REGNO (dst)); + if (! xtensa_constantsynth (dst, INTVAL (x))) + emit_move_insn (dst, x); DONE; }) -- cgit v1.1 From 3f722e7886ff46385033d9187e21f49c523083d4 Mon Sep 17 00:00:00 2001 From: Takayuki 'January June' Suwa Date: Sat, 3 Feb 2024 23:18:43 +0900 Subject: xtensa: Fix missing mode warning in "*eqne_zero_masked_bits" gcc/ChangeLog: * config/xtensa/xtensa.md (*eqne_zero_masked_bits): Add missing ":SI" to the match_operator. --- gcc/config/xtensa/xtensa.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'gcc') diff --git a/gcc/config/xtensa/xtensa.md b/gcc/config/xtensa/xtensa.md index d07e121..1a2249b 100644 --- a/gcc/config/xtensa/xtensa.md +++ b/gcc/config/xtensa/xtensa.md @@ -3269,7 +3269,7 @@ (define_insn_and_split "*eqne_zero_masked_bits" [(set (match_operand:SI 0 "register_operand" "=a") - (match_operator 3 "boolean_operator" + (match_operator:SI 3 "boolean_operator" [(and:SI (match_operand:SI 1 "register_operand" "r") (match_operand:SI 2 "const_int_operand" "i")) (const_int 0)]))] -- cgit v1.1 From 72319171e1bb9ec1ecf19b382a67735e4efe0987 Mon Sep 17 00:00:00 2001 From: GCC Administrator Date: Mon, 5 Feb 2024 00:17:56 +0000 Subject: Daily bump. --- gcc/ChangeLog | 47 +++++++++++++++++++++++++++++++++++++++++++++++ gcc/DATESTAMP | 2 +- gcc/d/ChangeLog | 21 +++++++++++++++++++++ gcc/testsuite/ChangeLog | 5 +++++ 4 files changed, 74 insertions(+), 1 deletion(-) (limited to 'gcc') diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 32e16d3..4cbc90d 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,50 @@ +2024-02-04 Takayuki 'January June' Suwa + + * config/xtensa/xtensa.md (*eqne_zero_masked_bits): + Add missing ":SI" to the match_operator. + +2024-02-04 Takayuki 'January June' Suwa + + * config/xtensa/xtensa.md (SHI): New mode iterator. + (2 split patterns related to constsynth): + Change to also accept HImode operands. + +2024-02-04 Jeff Law + + * config/riscv/riscv.cc (riscv_rtx_costs): Handle SUBREG and REG + similarly. + +2024-02-04 Xi Ruoyao + + * config/loongarch/lsx.md (neg2): Remove the + incorrect expand. + * config/loongarch/simd.md (simdfmt_as_i): New define_mode_attr. + (elmsgnbit): Likewise. + (neg2): New define_insn. + * config/loongarch/lasx.md (negv4df2, negv8sf2): Remove as they + are now instantiated in simd.md. + +2024-02-04 Xi Ruoyao + + * config/loongarch/loongarch.cc (loongarch_symbol_insns): Do not + use LSX_SUPPORTED_MODE_P or LASX_SUPPORTED_MODE_P if mode is + MAX_MACHINE_MODE. + +2024-02-04 Li Wei + + * config/loongarch/loongarch.cc (loongarch_expand_vselect): Adjust. + (loongarch_expand_vselect_vconcat): Ditto. + (loongarch_try_expand_lsx_vshuf_const): New, use vshuf to implement + all 128-bit constant permutation situations. + (loongarch_expand_lsx_shuffle): Adjust and rename function name. + (loongarch_is_imm_set_shuffle): Renamed function name. + (loongarch_expand_vec_perm_even_odd): Function forward declaration. + (loongarch_expand_vec_perm_even_odd_1): Add implement for 128-bit + extract-even and extract-odd permutations. + (loongarch_is_odd_extraction): Delete. + (loongarch_is_even_extraction): Ditto. + (loongarch_expand_vec_perm_const): Adjust. + 2024-02-03 Jakub Jelinek PR middle-end/113722 diff --git a/gcc/DATESTAMP b/gcc/DATESTAMP index 038ebd2..a53d85f 100644 --- a/gcc/DATESTAMP +++ b/gcc/DATESTAMP @@ -1 +1 @@ -20240204 +20240205 diff --git a/gcc/d/ChangeLog b/gcc/d/ChangeLog index 04bac02..45dd031 100644 --- a/gcc/d/ChangeLog +++ b/gcc/d/ChangeLog @@ -1,3 +1,24 @@ +2024-02-04 Iain Buclaw + + * dmd/MERGE: Merge upstream dmd a6f1083699. + * dmd/VERSION: Bump version to v2.107.0 + * Make-lang.in (D_FRONTEND_OBJS): Add d/pragmasem.o. + * d-builtins.cc (strip_type_modifiers): Update for new front-end + interface. + * d-codegen.cc (declaration_type): Likewise. + (parameter_type): Likewise. + * d-target.cc (TargetCPP::parameterType): Likewise. + * expr.cc (ExprVisitor::visit (IndexExp *)): Likewise. + (ExprVisitor::visit (VarExp *)): Likewise. + (ExprVisitor::visit (AssocArrayLiteralExp *)): Likewise. + * runtime.cc (get_libcall_type): Likewise. + * typeinfo.cc (TypeInfoVisitor::visit (TypeInfoConstDeclaration *)): + Likewise. + (TypeInfoVisitor::visit (TypeInfoInvariantDeclaration *)): Likewise. + (TypeInfoVisitor::visit (TypeInfoSharedDeclaration *)): Likewise. + (TypeInfoVisitor::visit (TypeInfoWildDeclaration *)): Likewise. + * types.cc (build_ctype): Likewise. + 2024-02-03 Iain Buclaw * dmd/MERGE: Merge upstream dmd e770945277. diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index aff4a6e..5748a98 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,8 @@ +2024-02-04 Jeff Law + + * gcc.target/riscv/reg_subreg_costs.c: New test. + Co-authored-by: Jivan Hakobyan + 2024-02-03 John David Anglin * gcc.dg/pr84877.c: Adjust xfail parentheses. -- cgit v1.1 From 7c190f93cd53a8391d78da2ba39d98dba9211faa Mon Sep 17 00:00:00 2001 From: Monk Chiang Date: Fri, 2 Feb 2024 11:58:44 +0800 Subject: RISC-V: Support scheduling for sifive p400 series Add sifive p400 series scheduler module. For more information see https://www.sifive.com/cores/performance-p450-470. gcc/ChangeLog: * config/riscv/riscv.md: Include sifive-p400.md. * config/riscv/sifive-p400.md: New file. * config/riscv/riscv-cores.def (RISCV_TUNE): Add parameter. * config/riscv/riscv-opts.h (enum riscv_microarchitecture_type): Add sifive_p400. * config/riscv/riscv.cc (sifive_p400_tune_info): New. * config/riscv/riscv.h (TARGET_SFB_ALU): Update. * doc/invoke.texi (RISC-V Options): Add sifive-p400-series --- gcc/config/riscv/riscv-cores.def | 1 + gcc/config/riscv/riscv-opts.h | 1 + gcc/config/riscv/riscv.cc | 17 ++++ gcc/config/riscv/riscv.h | 1 + gcc/config/riscv/riscv.md | 3 +- gcc/config/riscv/sifive-p400.md | 174 +++++++++++++++++++++++++++++++++++++++ gcc/doc/invoke.texi | 4 +- 7 files changed, 198 insertions(+), 3 deletions(-) create mode 100644 gcc/config/riscv/sifive-p400.md (limited to 'gcc') diff --git a/gcc/config/riscv/riscv-cores.def b/gcc/config/riscv/riscv-cores.def index a07a79e..0785e8f 100644 --- a/gcc/config/riscv/riscv-cores.def +++ b/gcc/config/riscv/riscv-cores.def @@ -37,6 +37,7 @@ RISCV_TUNE("rocket", generic, rocket_tune_info) RISCV_TUNE("sifive-3-series", generic, rocket_tune_info) RISCV_TUNE("sifive-5-series", generic, rocket_tune_info) RISCV_TUNE("sifive-7-series", sifive_7, sifive_7_tune_info) +RISCV_TUNE("sifive-p400-series", sifive_p400, sifive_p400_tune_info) RISCV_TUNE("sifive-p600-series", sifive_p600, sifive_p600_tune_info) RISCV_TUNE("thead-c906", generic, thead_c906_tune_info) RISCV_TUNE("generic-ooo", generic_ooo, generic_ooo_tune_info) diff --git a/gcc/config/riscv/riscv-opts.h b/gcc/config/riscv/riscv-opts.h index 2595166..4edddba 100644 --- a/gcc/config/riscv/riscv-opts.h +++ b/gcc/config/riscv/riscv-opts.h @@ -55,6 +55,7 @@ extern enum riscv_isa_spec_class riscv_isa_spec; enum riscv_microarchitecture_type { generic, sifive_7, + sifive_p400, sifive_p600, generic_ooo }; diff --git a/gcc/config/riscv/riscv.cc b/gcc/config/riscv/riscv.cc index d6868a6..799d791 100644 --- a/gcc/config/riscv/riscv.cc +++ b/gcc/config/riscv/riscv.cc @@ -447,6 +447,23 @@ static const struct riscv_tune_param sifive_7_tune_info = { NULL, /* vector cost */ }; +/* Costs to use when optimizing for Sifive p400 Series. */ +static const struct riscv_tune_param sifive_p400_tune_info = { + {COSTS_N_INSNS (4), COSTS_N_INSNS (4)}, /* fp_add */ + {COSTS_N_INSNS (4), COSTS_N_INSNS (4)}, /* fp_mul */ + {COSTS_N_INSNS (20), COSTS_N_INSNS (20)}, /* fp_div */ + {COSTS_N_INSNS (4), COSTS_N_INSNS (4)}, /* int_mul */ + {COSTS_N_INSNS (6), COSTS_N_INSNS (6)}, /* int_div */ + 3, /* issue_rate */ + 4, /* branch_cost */ + 3, /* memory_cost */ + 4, /* fmv_cost */ + true, /* slow_unaligned_access */ + false, /* use_divmod_expansion */ + RISCV_FUSE_LUI_ADDI | RISCV_FUSE_AUIPC_ADDI, /* fusible_ops */ + &generic_vector_cost, /* vector cost */ +}; + /* Costs to use when optimizing for Sifive p600 Series. */ static const struct riscv_tune_param sifive_p600_tune_info = { {COSTS_N_INSNS (4), COSTS_N_INSNS (4)}, /* fp_add */ diff --git a/gcc/config/riscv/riscv.h b/gcc/config/riscv/riscv.h index e0cb3ba..669308c 100644 --- a/gcc/config/riscv/riscv.h +++ b/gcc/config/riscv/riscv.h @@ -898,6 +898,7 @@ extern enum riscv_cc get_riscv_cc (const rtx use); #define TARGET_SFB_ALU \ ((riscv_microarchitecture == sifive_7) \ + || (riscv_microarchitecture == sifive_p400) \ || (riscv_microarchitecture == sifive_p600)) #define LOGICAL_OP_NON_SHORT_CIRCUIT 0 diff --git a/gcc/config/riscv/riscv.md b/gcc/config/riscv/riscv.md index 2a164a0..39b2979 100644 --- a/gcc/config/riscv/riscv.md +++ b/gcc/config/riscv/riscv.md @@ -687,7 +687,7 @@ ;; Microarchitectures we know how to tune for. ;; Keep this in sync with enum riscv_microarchitecture. (define_attr "tune" - "generic,sifive_7,sifive_p600,generic_ooo" + "generic,sifive_7,sifive_p400,sifive_p600,generic_ooo" (const (symbol_ref "((enum attr_tune) riscv_microarchitecture)"))) ;; Describe a user's asm statement. @@ -3850,6 +3850,7 @@ (include "pic.md") (include "generic.md") (include "sifive-7.md") +(include "sifive-p400.md") (include "sifive-p600.md") (include "thead.md") (include "generic-ooo.md") diff --git a/gcc/config/riscv/sifive-p400.md b/gcc/config/riscv/sifive-p400.md new file mode 100644 index 0000000..cc244d3 --- /dev/null +++ b/gcc/config/riscv/sifive-p400.md @@ -0,0 +1,174 @@ +;; Scheduling description for Sifive p400. + +;; Sifive p400 series is a triple-issue, superscalar, out-of-order processor. + +;; CPU execution units: +;; ialu Integer Units: all arithmetic and logic. +;; +;; bru Branch Resolution Unit: all branches. +;; +;; st Memory Write Unit: all writes to memory. +;; +;; ld Memory Read Unit: all reads from memory. +;; +;; imul Integer Multiply Unit +;; +;; idiv Integer Divide Unit +;; +;; system System Unit: all coprocessor accesses. +;; +;; fpu Floating Point Unit +;; +;; fmul Floating Point Multiply Unit +;; +;; fdiv Floating Point Divide Unit + +;; Four automata are defined to reduce number of states +;; which a single large automaton will have. +(define_automaton "sifive_p400_iex,sifive_p400_fex,sifive_p400_mem,sifive_p400_div") + +;; The Sifive p400 has six pipelines: +;; A-pipe Load, Store +;; B-pipe ALU, Branch +;; M-pipe ALU, MUL, DIV and I2F(integer to float instruction) +;; C-pipe ALU, Conditional move and system for coprocessor accesses +;; F-pipe FPU, MUL, F2I(float to integer instruction) +;; FM-pipe FPU, MUL, DIV + +(define_cpu_unit "sifive_p400_A" "sifive_p400_mem") +(define_cpu_unit "sifive_p400_B" "sifive_p400_iex") +(define_cpu_unit "sifive_p400_M" "sifive_p400_iex") +(define_cpu_unit "sifive_p400_C" "sifive_p400_iex") +(define_cpu_unit "sifive_p400_F" "sifive_p400_fex") +(define_cpu_unit "sifive_p400_FM" "sifive_p400_fex") + +;; Load and store unit. +(define_cpu_unit "sifive_p400_ld" "sifive_p400_mem") +(define_cpu_unit "sifive_p400_st" "sifive_p400_mem") + +;; Branch unit. +(define_cpu_unit "sifive_p400_bru" "sifive_p400_iex") + +;; Integer and multiply unit. +(define_cpu_unit "sifive_p400_ialu" "sifive_p400_iex") +(define_cpu_unit "sifive_p400_imul" "sifive_p400_iex") +(define_cpu_unit "sifive_p400_system" "sifive_p400_iex") + +;; Divide unit. +(define_cpu_unit "sifive_p400_idiv" "sifive_p400_div") +(define_cpu_unit "sifive_p400_fdiv" "sifive_p400_div") + +;; Float and multiply unit. +(define_cpu_unit "sifive_p400_fmul" "sifive_p400_fex") +(define_cpu_unit "sifive_p400_fpu" "sifive_p400_fex") + +;; ALU instruction can use pipeline C, B and M. +(define_reservation "p400_int_pipe" "(sifive_p400_C|sifive_p400_B|sifive_p400_M)") +;; FPU instruction can use pipeline F and FM. +(define_reservation "p400_float_pipe" "(sifive_p400_F|sifive_p400_FM)") + +(define_insn_reservation "sifive_p400_load" 3 + (and (eq_attr "tune" "sifive_p400") + (eq_attr "type" "load")) + "sifive_p400_A,sifive_p400_ld*2") + +(define_insn_reservation "sifive_p400_fpload" 4 + (and (eq_attr "tune" "sifive_p400") + (eq_attr "type" "fpload")) + "sifive_p400_A,sifive_p400_ld*3") + +(define_insn_reservation "sifive_p400_store" 1 + (and (eq_attr "tune" "sifive_p400") + (eq_attr "type" "store")) + "sifive_p400_A+sifive_p400_st") + +(define_insn_reservation "sifive_p400_fpstore" 1 + (and (eq_attr "tune" "sifive_p400") + (eq_attr "type" "fpstore")) + "sifive_p400_A+sifive_p400_st") + +(define_insn_reservation "sifive_p400_branch" 1 + (and (eq_attr "tune" "sifive_p400") + (eq_attr "type" "branch,jump,call")) + "sifive_p400_B+sifive_p400_bru") + +(define_insn_reservation "sifive_p400_sfb_alu" 1 + (and (eq_attr "tune" "sifive_p400") + (eq_attr "type" "sfb_alu")) + "sifive_p400_C+sifive_p400_bru+sifive_p400_ialu") + +(define_insn_reservation "sifive_p400_atomic" 3 + (and (eq_attr "tune" "sifive_p400") + (eq_attr "type" "atomic")) + "sifive_p400_C,sifive_p400_system*2") + +(define_insn_reservation "sifive_p400_mul" 3 + (and (eq_attr "tune" "sifive_p400") + (eq_attr "type" "imul")) + "sifive_p400_M,sifive_p400_imul*2") + +(define_insn_reservation "sifive_p400_div" 31 + (and (eq_attr "tune" "sifive_p400") + (eq_attr "type" "idiv")) + "sifive_p400_M, sifive_p400_idiv*5") + +(define_insn_reservation "sifive_p400_alu" 1 + (and (eq_attr "tune" "sifive_p400") + (eq_attr "type" "unknown,arith,logical,shift,slt,multi,bitmanip,clz,ctz,rotate")) + "p400_int_pipe+sifive_p400_ialu") + +(define_insn_reservation "sifive_p400_cpop" 3 + (and (eq_attr "tune" "sifive_p400") + (eq_attr "type" "cpop")) + "p400_int_pipe,sifive_p400_ialu*2") + +(define_insn_reservation "sifive_p400_load_immediate" 1 + (and (eq_attr "tune" "sifive_p400") + (eq_attr "type" "nop,const,auipc,move")) + "p400_int_pipe") + +(define_insn_reservation "sifive_p400_fma" 4 + (and (eq_attr "tune" "sifive_p400") + (eq_attr "type" "fadd,fmul,fmadd")) + "p400_float_pipe,sifive_p400_fmul*3") + +(define_insn_reservation "sifive_p400_i2f" 2 + (and (eq_attr "tune" "sifive_p400") + (eq_attr "type" "mtc,fcvt_i2f")) + "sifive_p400_M,sifive_p400_ialu") + +(define_insn_reservation "sifive_p400_f2i" 2 + (and (eq_attr "tune" "sifive_p400") + (eq_attr "type" "mfc,fcmp,fcvt_f2i")) + "sifive_p400_F,sifive_p400_fpu") + +(define_insn_reservation "sifive_p400_fmove" 2 + (and (eq_attr "tune" "sifive_p400") + (eq_attr "type" "fmove,fcvt")) + "p400_float_pipe,sifive_p400_fpu") + +(define_insn_reservation "sifive_p400_fdiv_s" 18 + (and (eq_attr "tune" "sifive_p400") + (eq_attr "type" "fdiv,fsqrt") + (eq_attr "mode" "SF")) + "sifive_p400_FM, sifive_p400_fdiv*5") + +(define_insn_reservation "sifive_p400_fdiv_d" 31 + (and (eq_attr "tune" "sifive_p400") + (eq_attr "type" "fdiv,fsqrt") + (eq_attr "mode" "DF")) + "sifive_p400_FM, sifive_p400_fdiv*5") + +(define_bypass 1 "sifive_p400_load,sifive_p400_alu,sifive_p400_mul,sifive_p400_sfb_alu" + "sifive_p400_alu,sifive_p400_branch") + +(define_bypass 1 "sifive_p400_load,sifive_p400_alu,sifive_p400_mul, + sifive_p400_f2i,sifive_p400_fmove,sifive_p400_sfb_alu" + "sifive_p400_store" "riscv_store_data_bypass_p") + +(define_bypass 1 "sifive_p400_i2f" + "sifive_p400_fma,sifive_p400_f2i,sifive_p400_fmove,sifive_p400_fdiv_s,sifive_p400_fdiv_d") + +(define_bypass 1 "sifive_p400_f2i" + "sifive_p400_branch,sifive_p400_sfb_alu,sifive_p400_mul, + sifive_p400_div,sifive_p400_alu,sifive_p400_cpop") diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi index e9c691d..f864582 100644 --- a/gcc/doc/invoke.texi +++ b/gcc/doc/invoke.texi @@ -30714,8 +30714,8 @@ Permissible values for this option are: @samp{sifive-e20}, @samp{sifive-e21}, Optimize the output for the given processor, specified by microarchitecture or particular CPU name. Permissible values for this option are: @samp{rocket}, @samp{sifive-3-series}, @samp{sifive-5-series}, @samp{sifive-7-series}, -@samp{thead-c906}, @samp{size}, @samp{sifive-p600-series}, -and all valid options for @option{-mcpu=}. +@samp{thead-c906}, @samp{size}, @samp{sifive-p400-series}, +@samp{sifive-p600-series}, and all valid options for @option{-mcpu=}. When @option{-mtune=} is not specified, use the setting from @option{-mcpu}, the default is @samp{rocket} if both are not specified. -- cgit v1.1 From 91e09b3a7e9c86bb29fc138744fd2e087216733c Mon Sep 17 00:00:00 2001 From: Monk Chiang Date: Fri, 2 Feb 2024 11:58:45 +0800 Subject: RISC-V: Add sifive-p450, sifive-p67 to -mcpu gcc/ChangeLog: * config/riscv/riscv-cores.def: Add sifive-p450, sifive-p670. * doc/invoke.texi (RISC-V Options): Add sifive-p450, sifive-p670. gcc/testsuite/ChangeLog: * gcc.target/riscv/mcpu-sifive-p450.c: New test. * gcc.target/riscv/mcpu-sifive-p670.c: New test. --- gcc/config/riscv/riscv-cores.def | 9 +++++ gcc/doc/invoke.texi | 3 +- gcc/testsuite/gcc.target/riscv/mcpu-sifive-p450.c | 34 +++++++++++++++++++ gcc/testsuite/gcc.target/riscv/mcpu-sifive-p670.c | 40 +++++++++++++++++++++++ 4 files changed, 85 insertions(+), 1 deletion(-) create mode 100644 gcc/testsuite/gcc.target/riscv/mcpu-sifive-p450.c create mode 100644 gcc/testsuite/gcc.target/riscv/mcpu-sifive-p670.c (limited to 'gcc') diff --git a/gcc/config/riscv/riscv-cores.def b/gcc/config/riscv/riscv-cores.def index 0785e8f..57928bc 100644 --- a/gcc/config/riscv/riscv-cores.def +++ b/gcc/config/riscv/riscv-cores.def @@ -76,6 +76,15 @@ RISCV_CORE("sifive-s76", "rv64imafdc", "sifive-7-series") RISCV_CORE("sifive-u54", "rv64imafdc", "sifive-5-series") RISCV_CORE("sifive-u74", "rv64imafdc", "sifive-7-series") RISCV_CORE("sifive-x280", "rv64imafdcv_zfh_zba_zbb_zvfh_zvl512b", "sifive-7-series") +RISCV_CORE("sifive-p450", "rv64imafdc_za64rs_zic64b_zicbom_zicbop_zicboz_" + "ziccamoa_ziccif_zicclsm_ziccrse_zicsr_zifencei_" + "zihintntl_zihintpause_zihpm_zfhmin_zba_zbb_zbs", + "sifive-p400-series") +RISCV_CORE("sifive-p670", "rv64imafdcv_za64rs_zic64b_zicbom_zicbop_zicboz_" + "ziccamoa_ziccif_zicclsm_ziccrse_zicsr_zifencei_" + "zihintntl_zihintpause_zihpm_zfhmin_zba_zbb_zbs_" + "zvl128b_zvbb_zvknc_zvkng_zvksc_zvksg", + "sifive-p600-series") RISCV_CORE("thead-c906", "rv64imafdc_xtheadba_xtheadbb_xtheadbs_xtheadcmo_" "xtheadcondmov_xtheadfmemidx_xtheadmac_" diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi index f864582..71339b8 100644 --- a/gcc/doc/invoke.texi +++ b/gcc/doc/invoke.texi @@ -30707,7 +30707,8 @@ by particular CPU name. Permissible values for this option are: @samp{sifive-e20}, @samp{sifive-e21}, @samp{sifive-e24}, @samp{sifive-e31}, @samp{sifive-e34}, @samp{sifive-e76}, @samp{sifive-s21}, @samp{sifive-s51}, @samp{sifive-s54}, @samp{sifive-s76}, -@samp{sifive-u54}, @samp{sifive-u74}, and @samp{sifive-x280}. +@samp{sifive-u54}, @samp{sifive-u74}, @samp{sifive-x280}, @samp{sifive-xp450}, +@samp{sifive-x670}. @opindex mtune @item -mtune=@var{processor-string} diff --git a/gcc/testsuite/gcc.target/riscv/mcpu-sifive-p450.c b/gcc/testsuite/gcc.target/riscv/mcpu-sifive-p450.c new file mode 100644 index 0000000..5630418 --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/mcpu-sifive-p450.c @@ -0,0 +1,34 @@ +/* { dg-do compile } */ +/* { dg-skip-if "-march given" { *-*-* } { "-march=*" } } */ +/* { dg-options "-mcpu=sifive-p450 -mabi=lp64d" } */ +/* SiFive p450 => rv64imafdc_za64rs_zic64b_zicbom_zicbop_zicboz_ziccamoa_ziccif_zicclsm_ziccrse_zicsr_zifencei_zihintntl_zihintpause_zihpm_zfhmin_zba_zbb_zbs */ + +#if !((__riscv_xlen == 64) \ + && !defined(__riscv_32e) \ + && (__riscv_flen == 64) \ + && defined(__riscv_c) \ + && defined(__riscv_za64rs) \ + && defined(__riscv_zic64b) \ + && defined(__riscv_zicbom) \ + && defined(__riscv_zicbop) \ + && defined(__riscv_zicboz) \ + && defined(__riscv_ziccamoa) \ + && defined(__riscv_ziccif) \ + && defined(__riscv_zicclsm) \ + && defined(__riscv_ziccrse) \ + && defined(__riscv_zicsr) \ + && defined(__riscv_zifencei) \ + && defined(__riscv_zihintntl) \ + && defined(__riscv_zihintpause) \ + && defined(__riscv_zihpm) \ + && defined(__riscv_zfhmin) \ + && defined(__riscv_zba) \ + && defined(__riscv_zbb) \ + && defined(__riscv_zbs)) +#error "unexpected arch" +#endif + +int main() +{ + return 0; +} diff --git a/gcc/testsuite/gcc.target/riscv/mcpu-sifive-p670.c b/gcc/testsuite/gcc.target/riscv/mcpu-sifive-p670.c new file mode 100644 index 0000000..8dfd490 --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/mcpu-sifive-p670.c @@ -0,0 +1,40 @@ +/* { dg-do compile } */ +/* { dg-skip-if "-march given" { *-*-* } { "-march=*" } } */ +/* { dg-options "-mcpu=sifive-p670 -mabi=lp64d" } */ +/* SiFive p670 => rv64imafdcv_za64rs_zic64b_zicbom_zicbop_zicboz_ziccamoa_ziccif_zicclsm_ziccrse_zicsr_zifencei_zihintntl_zihintpause_zihpm_zfhmin_zba_zbb_zbs_zvl128b_zvbb_zvknc_zvkng_zvksc_zvksg */ + +#if !((__riscv_xlen == 64) \ + && !defined(__riscv_32e) \ + && (__riscv_flen == 64) \ + && defined(__riscv_c) \ + && defined(__riscv_za64rs) \ + && defined(__riscv_zic64b) \ + && defined(__riscv_zicbom) \ + && defined(__riscv_zicbop) \ + && defined(__riscv_zicboz) \ + && defined(__riscv_ziccamoa) \ + && defined(__riscv_ziccif) \ + && defined(__riscv_zicclsm) \ + && defined(__riscv_ziccrse) \ + && defined(__riscv_zicsr) \ + && defined(__riscv_zifencei) \ + && defined(__riscv_zihintntl) \ + && defined(__riscv_zihintpause) \ + && defined(__riscv_zihpm) \ + && defined(__riscv_zfhmin) \ + && defined(__riscv_zba) \ + && defined(__riscv_zbb) \ + && defined(__riscv_zbs) \ + && defined(__riscv_zvl128b) \ + && defined(__riscv_zvbb) \ + && defined(__riscv_zvknc) \ + && defined(__riscv_zvkng) \ + && defined(__riscv_zvksc) \ + && defined(__riscv_zvksg)) +#error "unexpected arch" +#endif + +int main() +{ + return 0; +} -- cgit v1.1 From 5b281946c4b51132caf5e5b64c730fef92dd6123 Mon Sep 17 00:00:00 2001 From: Richard Biener Date: Thu, 1 Feb 2024 13:54:11 +0100 Subject: target/113255 - avoid REG_POINTER on a pointer difference The following avoids re-using a register holding a pointer (and thus might be REG_POINTER) for the result of a pointer difference computation. That might confuse heuristics in (broken) RTL alias analysis which relies on REG_POINTER indicating that we're dealing with one. This alone doesn't fix anything. PR target/113255 * config/i386/i386-expand.cc (expand_set_or_cpymem_prologue_epilogue_by_misaligned_moves): Use a new pseudo for the skipped number of bytes. --- gcc/config/i386/i386-expand.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'gcc') diff --git a/gcc/config/i386/i386-expand.cc b/gcc/config/i386/i386-expand.cc index 5706220..50f9fe2 100644 --- a/gcc/config/i386/i386-expand.cc +++ b/gcc/config/i386/i386-expand.cc @@ -8429,7 +8429,7 @@ expand_set_or_cpymem_prologue_epilogue_by_misaligned_moves (rtx destmem, rtx src /* See how many bytes we skipped. */ saveddest = expand_simple_binop (GET_MODE (*destptr), MINUS, saveddest, *destptr, - saveddest, 1, OPTAB_DIRECT); + NULL_RTX, 1, OPTAB_DIRECT); /* Adjust srcptr and count. */ if (!issetmem) *srcptr = expand_simple_binop (GET_MODE (*srcptr), MINUS, *srcptr, -- cgit v1.1 From d413df070ba5efadd2fb8b6c6aa6003b8cae617b Mon Sep 17 00:00:00 2001 From: Jakub Jelinek Date: Mon, 5 Feb 2024 09:33:26 +0100 Subject: i386: Clear REG_UNUSED and REG_DEAD notes from the IL at the end of vzeroupper pass [PR113059] The move of the vzeroupper pass from after reload pass to after postreload_cse helped only partially, CSE-like passes can still invalidate those notes (especially REG_UNUSED) if they use some earlier register holding some value later on in the IL. So, either we could try to move it one pass further after gcse2 and hope no later pass invalidates the notes, or the following patch attempts to restore the REG_DEAD/REG_UNUSED state from GCC 13 and earlier, where the LRA or reload passes remove all REG_DEAD/REG_UNUSED notes and the notes reappear only at the start of dse2 pass when it calls df_note_add_problem (); df_analyze (); So, effectively NEXT_PASS (pass_postreload_cse); NEXT_PASS (pass_gcse2); NEXT_PASS (pass_split_after_reload); NEXT_PASS (pass_ree); NEXT_PASS (pass_compare_elim_after_reload); NEXT_PASS (pass_thread_prologue_and_epilogue); passes operate without those notes in the IL. While in GCC 14 mode switching computes the notes problem at the start of vzeroupper, the patch below removes them at the end of the pass again, so that the above passes continue to operate without them. 2024-02-05 Jakub Jelinek PR target/113059 * config/i386/i386-features.cc (rest_of_handle_insert_vzeroupper): Remove REG_DEAD/REG_UNUSED notes at the end of the pass before df_analyze call. --- gcc/config/i386/i386-features.cc | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) (limited to 'gcc') diff --git a/gcc/config/i386/i386-features.cc b/gcc/config/i386/i386-features.cc index 4020b27..e0b9615 100644 --- a/gcc/config/i386/i386-features.cc +++ b/gcc/config/i386/i386-features.cc @@ -2664,6 +2664,32 @@ rest_of_handle_insert_vzeroupper (void) /* Call optimize_mode_switching. */ g->get_passes ()->execute_pass_mode_switching (); + /* LRA removes all REG_DEAD/REG_UNUSED notes and normally they + reappear in the IL only at the start of pass_rtl_dse2, which does + df_note_add_problem (); df_analyze (); + The vzeroupper is scheduled after postreload_cse pass and mode + switching computes the notes as well, the problem is that e.g. + pass_gcse2 doesn't maintain the notes, see PR113059 and + PR112760. Remove the notes now to restore status quo ante + until we figure out how to maintain the notes or what else + to do. */ + basic_block bb; + rtx_insn *insn; + FOR_EACH_BB_FN (bb, cfun) + FOR_BB_INSNS (bb, insn) + if (NONDEBUG_INSN_P (insn)) + { + rtx *pnote = ®_NOTES (insn); + while (*pnote != 0) + { + if (REG_NOTE_KIND (*pnote) == REG_DEAD + || REG_NOTE_KIND (*pnote) == REG_UNUSED) + *pnote = XEXP (*pnote, 1); + else + pnote = &XEXP (*pnote, 1); + } + } + df_analyze (); return 0; } -- cgit v1.1 From dede174fbb57bdd3e26f322b6096d53edf0089c4 Mon Sep 17 00:00:00 2001 From: Jakub Jelinek Date: Mon, 5 Feb 2024 10:57:39 +0100 Subject: lower-bitint: Remove single label _BitInt switches [PR113737] The following testcase ICEs, because group_case_labels_stmt optimizes switch (a.0_7) [50.00%], case 0: [50.00%], case 2: [50.00%]> where L7 block starts with __builtin_unreachable (); to switch (a.0_7) [50.00%]> and single label GIMPLE_SWITCH is something the switch expansion refuses to lower: if (gimple_switch_num_labels (m_switch) == 1 || range_check_type (index_type) == NULL_TREE) return false; (range_check_type never returns NULL for BITINT_TYPE), but the gimple lowering pass relies on all large/huge _BitInt switches to be lowered by that pass. The following patch just removes those after making the single successor edge EDGE_FALLTHRU. I've done it even if !optimize just in case in case we'd end up with single case label from earlier passes. 2024-02-05 Jakub Jelinek PR tree-optimization/113737 * gimple-lower-bitint.cc (gimple_lower_bitint): If GIMPLE_SWITCH has just a single label, remove it and make single successor edge EDGE_FALLTHRU. * gcc.dg/bitint-84.c: New test. --- gcc/gimple-lower-bitint.cc | 9 ++++++++- gcc/testsuite/gcc.dg/bitint-84.c | 32 ++++++++++++++++++++++++++++++++ 2 files changed, 40 insertions(+), 1 deletion(-) create mode 100644 gcc/testsuite/gcc.dg/bitint-84.c (limited to 'gcc') diff --git a/gcc/gimple-lower-bitint.cc b/gcc/gimple-lower-bitint.cc index a7cc5ce..e92f573 100644 --- a/gcc/gimple-lower-bitint.cc +++ b/gcc/gimple-lower-bitint.cc @@ -5832,7 +5832,14 @@ gimple_lower_bitint (void) if (optimize) group_case_labels_stmt (swtch); - switch_statements.safe_push (swtch); + if (gimple_switch_num_labels (swtch) == 1) + { + single_succ_edge (bb)->flags |= EDGE_FALLTHRU; + gimple_stmt_iterator gsi = gsi_for_stmt (swtch); + gsi_remove (&gsi, true); + } + else + switch_statements.safe_push (swtch); } } diff --git a/gcc/testsuite/gcc.dg/bitint-84.c b/gcc/testsuite/gcc.dg/bitint-84.c new file mode 100644 index 0000000..dffdf16 --- /dev/null +++ b/gcc/testsuite/gcc.dg/bitint-84.c @@ -0,0 +1,32 @@ +/* PR tree-optimization/113737 */ +/* { dg-do compile { target bitint } } */ +/* { dg-options "-O2 -std=c23" } */ + +#if __BITINT_MAXWIDTH__ >= 129 +_BitInt(129) a; +#else +_BitInt(63) a; +#endif + +int b[1], c; + +int +foo (void) +{ + switch (a) + case 0: + case 2: + return 1; + return 0; +} + +void +bar (int i) +{ + for (;; ++i) + { + c = b[i]; + if (!foo ()) + __asm__ (""); + } +} -- cgit v1.1 From 9d139c036547a4b3b43439b82f94a9c350d4fa2f Mon Sep 17 00:00:00 2001 From: Richard Biener Date: Mon, 5 Feb 2024 10:21:06 +0100 Subject: Vectorizer and address-spaces The following makes sure to use the correct pointer mode when building pointer types to a non-default address-space. * tree-vect-data-refs.cc (vect_create_data_ref_ptr): Use the default mode when building a pointer. --- gcc/tree-vect-data-refs.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'gcc') diff --git a/gcc/tree-vect-data-refs.cc b/gcc/tree-vect-data-refs.cc index 2ca5a1b..f79ade9 100644 --- a/gcc/tree-vect-data-refs.cc +++ b/gcc/tree-vect-data-refs.cc @@ -5323,7 +5323,7 @@ vect_create_data_ref_ptr (vec_info *vinfo, stmt_vec_info stmt_info, } while (sinfo); } - aggr_ptr_type = build_pointer_type_for_mode (aggr_type, ptr_mode, + aggr_ptr_type = build_pointer_type_for_mode (aggr_type, VOIDmode, need_ref_all); aggr_ptr = vect_get_new_vect_var (aggr_ptr_type, vect_pointer_var, base_name); -- cgit v1.1 From 42959acb8409c39e1c71c43528832611c3b71e25 Mon Sep 17 00:00:00 2001 From: Richard Biener Date: Mon, 5 Feb 2024 09:44:12 +0100 Subject: tree-optimization/113707 - ICE with VN elimination The following avoids different avail answers depending on how the iteration progressed. PR tree-optimization/113707 * tree-ssa-sccvn.cc (rpo_elim::eliminate_avail): After checking the avail set treat out-of-region defines as available. * gcc.dg/torture/pr113707-1.c: New testcase. * gcc.dg/torture/pr113707-2.c: Likewise. --- gcc/testsuite/gcc.dg/torture/pr113707-1.c | 45 +++++++++++++++++++++++++++++++ gcc/testsuite/gcc.dg/torture/pr113707-2.c | 26 ++++++++++++++++++ gcc/tree-ssa-sccvn.cc | 5 ++++ 3 files changed, 76 insertions(+) create mode 100644 gcc/testsuite/gcc.dg/torture/pr113707-1.c create mode 100644 gcc/testsuite/gcc.dg/torture/pr113707-2.c (limited to 'gcc') diff --git a/gcc/testsuite/gcc.dg/torture/pr113707-1.c b/gcc/testsuite/gcc.dg/torture/pr113707-1.c new file mode 100644 index 0000000..c1a50b3 --- /dev/null +++ b/gcc/testsuite/gcc.dg/torture/pr113707-1.c @@ -0,0 +1,45 @@ +/* { dg-do compile } */ + +int printf(const char *, ...); +struct a { + int b; +} n; +int a, c, d, e, f = 1, g, h, j = 1, k, l, m, o; +int main() { + struct a p; + int i; + p.b = 1; + if (!j) + goto q; + p.b = i = 0; + for (; i < 1; i++) + if (k) + while (m) + r: + q: + if (p.b) + g = 1; + while (1) { + i = 0; + for (; i < 5; i++) + ; + if (l) { + while (h) + ; + if (o) { + d = 0; + for (; d < 8; d++) + ; + } + } + for (; e; e--) + while (a) + p = n; + if (c) + goto r; + printf("0"); + if (f) + break; + } + return 0; +} diff --git a/gcc/testsuite/gcc.dg/torture/pr113707-2.c b/gcc/testsuite/gcc.dg/torture/pr113707-2.c new file mode 100644 index 0000000..957e6f1 --- /dev/null +++ b/gcc/testsuite/gcc.dg/torture/pr113707-2.c @@ -0,0 +1,26 @@ +/* { dg-do compile } */ + +int a, b, c, d, e, f, g, h, j, k, l; +void n() { + while (c) + if (1) { + for (h = 5; h; h--) { + int m = e % 2; + d = ~g || h ^ m / -1; + if (h > 5) + e = k; + } + return; + } +} +int main() { + if (a) + for (int i = 0; i < 2; i++) { + for (f = 1; f < 6; f++) + for (c = 7; c >= 0; c--) + if (l) + b = 0; + n(); + } + return 0; +} diff --git a/gcc/tree-ssa-sccvn.cc b/gcc/tree-ssa-sccvn.cc index bbcf865..8792cd0 100644 --- a/gcc/tree-ssa-sccvn.cc +++ b/gcc/tree-ssa-sccvn.cc @@ -7776,6 +7776,11 @@ rpo_elim::eliminate_avail (basic_block bb, tree op) av = av->next; } while (av); + /* While we prefer avail we have to fallback to using the value + directly if defined outside of the region when none of the + available defs suit. */ + if (!valnum_info->visited) + return valnum; } else if (valnum != VN_TOP) /* valnum is is_gimple_min_invariant. */ -- cgit v1.1 From 4d7fe3cf82505b45719356a2e51b1480b5ee21d6 Mon Sep 17 00:00:00 2001 From: Xi Ruoyao Date: Sat, 3 Feb 2024 03:35:07 +0800 Subject: MIPS: Fix wrong MSA FP vector negation We expanded (neg x) to (minus const0 x) for MSA FP vectors, this is wrong because -0.0 is not 0 - 0.0. This causes some Python tests to fail when Python is built with MSA enabled. Use the bnegi.df instructions to simply reverse the sign bit instead. gcc/ChangeLog: * config/mips/mips-msa.md (elmsgnbit): New define_mode_attr. (neg2): Change the mode iterator from MSA to IMSA because in FP arithmetic we cannot use (0 - x) for -x. (neg2): New define_insn to implement FP vector negation, using a bnegi instruction to negate the sign bit. --- gcc/config/mips/mips-msa.md | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) (limited to 'gcc') diff --git a/gcc/config/mips/mips-msa.md b/gcc/config/mips/mips-msa.md index 83d9a08..920161e 100644 --- a/gcc/config/mips/mips-msa.md +++ b/gcc/config/mips/mips-msa.md @@ -231,6 +231,10 @@ (V4SI "uimm5") (V2DI "uimm6")]) +;; The index of sign bit in FP vector elements. +(define_mode_attr elmsgnbit [(V2DF "63") (V4DF "63") + (V4SF "31") (V8SF "31")]) + (define_expand "vec_init" [(match_operand:MSA 0 "register_operand") (match_operand:MSA 1 "")] @@ -597,9 +601,9 @@ }) (define_expand "neg2" - [(set (match_operand:MSA 0 "register_operand") - (minus:MSA (match_dup 2) - (match_operand:MSA 1 "register_operand")))] + [(set (match_operand:IMSA 0 "register_operand") + (minus:IMSA (match_dup 2) + (match_operand:IMSA 1 "register_operand")))] "ISA_HAS_MSA" { rtx reg = gen_reg_rtx (mode); @@ -607,6 +611,14 @@ operands[2] = reg; }) +(define_insn "neg2" + [(set (match_operand:FMSA 0 "register_operand" "=f") + (neg (match_operand:FMSA 1 "register_operand" "f")))] + "ISA_HAS_MSA" + "bnegi.\t%w0,%w1," + [(set_attr "type" "simd_bit") + (set_attr "mode" "")]) + (define_expand "msa_ldi" [(match_operand:IMSA 0 "register_operand") (match_operand 1 "const_imm10_operand")] -- cgit v1.1 From 55357960fbddd261e32f088f5dd328d58b0f25b3 Mon Sep 17 00:00:00 2001 From: Xi Ruoyao Date: Mon, 5 Feb 2024 20:17:25 +0800 Subject: mips: Fix missing mode in neg2 I was too sleepy writting this :(. gcc/ChangeLog: * config/mips/mips-msa.md (neg2): Add missing mode for neg. --- gcc/config/mips/mips-msa.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'gcc') diff --git a/gcc/config/mips/mips-msa.md b/gcc/config/mips/mips-msa.md index 920161e..779157f 100644 --- a/gcc/config/mips/mips-msa.md +++ b/gcc/config/mips/mips-msa.md @@ -613,7 +613,7 @@ (define_insn "neg2" [(set (match_operand:FMSA 0 "register_operand" "=f") - (neg (match_operand:FMSA 1 "register_operand" "f")))] + (neg:FMSA (match_operand:FMSA 1 "register_operand" "f")))] "ISA_HAS_MSA" "bnegi.\t%w0,%w1," [(set_attr "type" "simd_bit") -- cgit v1.1 From e5f50e63a83d03d1db6be1578070041ac7f31c37 Mon Sep 17 00:00:00 2001 From: "H.J. Lu" <(no_default)> Date: Mon, 5 Feb 2024 03:46:50 -0800 Subject: x86-64: Update gcc.target/i386/apx-ndd.c Fix the following issues: 1. Replace long with int64_t to support x32. 2. Replace \\(%rdi\\) with \\(%(?:r|e)di\\) for memory operand since x32 uses (%edi). 3. Replace %(?:|r|e)al with %al in negb scan. * gcc.target/i386/apx-ndd.c: Updated. --- gcc/testsuite/gcc.target/i386/apx-ndd.c | 68 ++++++++++++++++----------------- 1 file changed, 34 insertions(+), 34 deletions(-) (limited to 'gcc') diff --git a/gcc/testsuite/gcc.target/i386/apx-ndd.c b/gcc/testsuite/gcc.target/i386/apx-ndd.c index b215f66..0eb751ad 100644 --- a/gcc/testsuite/gcc.target/i386/apx-ndd.c +++ b/gcc/testsuite/gcc.target/i386/apx-ndd.c @@ -75,9 +75,9 @@ FOO2 (short, add, +) FOO (int, add, +) FOO1 (int, add, +) FOO2 (int, add, +) -FOO (long, add, +) -FOO1 (long, add, +) -FOO2 (long, add, +) +FOO (int64_t, add, +) +FOO1 (int64_t, add, +) +FOO2 (int64_t, add, +) FOO (char, sub, -) FOO1 (char, sub, -) @@ -85,8 +85,8 @@ FOO (short, sub, -) FOO1 (short, sub, -) FOO (int, sub, -) FOO1 (int, sub, -) -FOO (long, sub, -) -FOO1 (long, sub, -) +FOO (int64_t, sub, -) +FOO1 (int64_t, sub, -) F (char, neg, -) F1 (char, neg, -) @@ -94,8 +94,8 @@ F (short, neg, -) F1 (short, neg, -) F (int, neg, -) F1 (int, neg, -) -F (long, neg, -) -F1 (long, neg, -) +F (int64_t, neg, -) +F1 (int64_t, neg, -) F (char, not, ~) F1 (char, not, ~) @@ -103,8 +103,8 @@ F (short, not, ~) F1 (short, not, ~) F (int, not, ~) F1 (int, not, ~) -F (long, not, ~) -F1 (long, not, ~) +F (int64_t, not, ~) +F1 (int64_t, not, ~) FOO (char, and, &) FOO1 (char, and, &) @@ -112,8 +112,8 @@ FOO (short, and, &) FOO1 (short, and, &) FOO (int, and, &) FOO1 (int, and, &) -FOO (long, and, &) -FOO1 (long, and, &) +FOO (int64_t, and, &) +FOO1 (int64_t, and, &) FOO (char, or, |) FOO1 (char, or, |) @@ -121,8 +121,8 @@ FOO (short, or, |) FOO1 (short, or, |) FOO (int, or, |) FOO1 (int, or, |) -FOO (long, or, |) -FOO1 (long, or, |) +FOO (int64_t, or, |) +FOO1 (int64_t, or, |) FOO (char, xor, ^) FOO1 (char, xor, ^) @@ -130,8 +130,8 @@ FOO (short, xor, ^) FOO1 (short, xor, ^) FOO (int, xor, ^) FOO1 (int, xor, ^) -FOO (long, xor, ^) -FOO1 (long, xor, ^) +FOO (int64_t, xor, ^) +FOO1 (int64_t, xor, ^) FOO (char, shl, <<) FOO3 (char, shl, <<, 7) @@ -139,8 +139,8 @@ FOO (short, shl, <<) FOO3 (short, shl, <<, 7) FOO (int, shl, <<) FOO3 (int, shl, <<, 7) -FOO (long, shl, <<) -FOO3 (long, shl, <<, 7) +FOO (int64_t, shl, <<) +FOO3 (int64_t, shl, <<, 7) FOO (char, sar, >>) FOO3 (char, sar, >>, 7) @@ -148,8 +148,8 @@ FOO (short, sar, >>) FOO3 (short, sar, >>, 7) FOO (int, sar, >>) FOO3 (int, sar, >>, 7) -FOO (long, sar, >>) -FOO3 (long, sar, >>, 7) +FOO (int64_t, sar, >>) +FOO3 (int64_t, sar, >>, 7) FOO (uint8_t, shr, >>) FOO3 (uint8_t, shr, >>, 7) @@ -170,33 +170,33 @@ FOO4 (uint16_t, rol, <<, >>, 1) FOO4 (uint32_t, rol, <<, >>, 1) FOO4 (uint64_t, rol, <<, >>, 1) -/* { dg-final { scan-assembler-times "add(?:b|l|w|q)\[^\n\r]*1, \\(%rdi\\), %(?:|r|e)a(?:x|l)" 4 } } */ +/* { dg-final { scan-assembler-times "add(?:b|l|w|q)\[^\n\r]*1, \\(%(?:r|e)di\\), %(?:|r|e)a(?:x|l)" 4 } } */ /* { dg-final { scan-assembler-times "lea(?:l|q)\[^\n\r]\\(%r(?:d|s)i,%r(?:d|s)i\\), %(?:|r|e)ax" 4 } } */ -/* { dg-final { scan-assembler-times "add(?:b|l|w|q)\[^\n\r]%(?:|r|e)si(?:|l), \\(%rdi\\), %(?:|r|e)a(?:x|l)" 4 } } */ -/* { dg-final { scan-assembler-times "sub(?:b|l|w|q)\[^\n\r]*1, \\(%rdi\\), %(?:|r|e)a(?:x|l)" 4 } } */ +/* { dg-final { scan-assembler-times "add(?:b|l|w|q)\[^\n\r]%(?:|r|e)si(?:|l), \\(%(?:r|e)di\\), %(?:|r|e)a(?:x|l)" 4 } } */ +/* { dg-final { scan-assembler-times "sub(?:b|l|w|q)\[^\n\r]*1, \\(%(?:r|e)di\\), %(?:|r|e)a(?:x|l)" 4 } } */ /* { dg-final { scan-assembler-times "sub(?:b|l|w|q)\[^\n\r]%(?:|r|e)si(?:|l), %(?:|r|e)di, %(?:|r|e)a(?:x|l)" 4 } } */ -/* { dg-final { scan-assembler-times "negb\[^\n\r]\\(%rdi\\), %(?:|r|e)al" 1 } } */ -/* { dg-final { scan-assembler-times "neg(?:l|w|q)\[^\n\r]\\(%rdi\\), %(?:|r|e)ax" 3 } } */ +/* { dg-final { scan-assembler-times "negb\[^\n\r]\\(%(?:r|e)di\\), %al" 1 } } */ +/* { dg-final { scan-assembler-times "neg(?:l|w|q)\[^\n\r]\\(%(?:r|e)di\\), %(?:|r|e)ax" 3 } } */ /* { dg-final { scan-assembler-times "neg(?:l|w|q)\[^\n\r]%(?:|r|e)di, %(?:|r|e)ax" 4 } } */ -/* { dg-final { scan-assembler-times "not(?:b|l|w|q)\[^\n\r]\\(%rdi\\), %(?:|r|e)a(?:x|l)" 4 } } */ +/* { dg-final { scan-assembler-times "not(?:b|l|w|q)\[^\n\r]\\(%(?:r|e)di\\), %(?:|r|e)a(?:x|l)" 4 } } */ /* { dg-final { scan-assembler-times "not(?:l|w|q)\[^\n\r]%(?:|r|e)di, %(?:|r|e)ax" 4 } } */ -/* { dg-final { scan-assembler-times "andb\[^\n\r]*1, \\(%rdi\\), %al" 1 } } */ -/* { dg-final { scan-assembler-times "and(?:l|w|q)\[^\n\r]*1, \\(%rdi\\), %(?:|r|e)ax" 3 } } */ +/* { dg-final { scan-assembler-times "andb\[^\n\r]*1, \\(%(?:r|e)di\\), %al" 1 } } */ +/* { dg-final { scan-assembler-times "and(?:l|w|q)\[^\n\r]*1, \\(%(?:r|e)di\\), %(?:|r|e)ax" 3 } } */ /* { dg-final { scan-assembler-times "and(?:l|w|q)\[^\n\r]%(?:|r|e)di, %(?:|r|e)si, %(?:|r|e)ax" 2 } } */ /* { dg-final { scan-assembler-times "and(?:l|w|q)\[^\n\r]%(?:|r|e)si, %(?:|r|e)di, %(?:|r|e)ax" 2 } } */ -/* { dg-final { scan-assembler-times "orb\[^\n\r]*1, \\(%rdi\\), %al" 2} } */ -/* { dg-final { scan-assembler-times "or(?:l|w|q)\[^\n\r]*1, \\(%rdi\\), %(?:|r|e)ax" 6 } } */ +/* { dg-final { scan-assembler-times "orb\[^\n\r]*1, \\(%(?:r|e)di\\), %al" 2} } */ +/* { dg-final { scan-assembler-times "or(?:l|w|q)\[^\n\r]*1, \\(%(?:r|e)di\\), %(?:|r|e)ax" 6 } } */ /* { dg-final { scan-assembler-times "or(?:l|w|q)\[^\n\r]%(?:|r|e)di, %(?:|r|e)si, %(?:|r|e)ax" 4 } } */ /* { dg-final { scan-assembler-times "or(?:l|w|q)\[^\n\r]%(?:|r|e)si, %(?:|r|e)di, %(?:|r|e)ax" 4 } } */ -/* { dg-final { scan-assembler-times "xorb\[^\n\r]*1, \\(%rdi\\), %al" 1 } } */ -/* { dg-final { scan-assembler-times "xor(?:l|w|q)\[^\n\r]*1, \\(%rdi\\), %(?:|r|e)ax" 3 } } */ +/* { dg-final { scan-assembler-times "xorb\[^\n\r]*1, \\(%(?:r|e)di\\), %al" 1 } } */ +/* { dg-final { scan-assembler-times "xor(?:l|w|q)\[^\n\r]*1, \\(%(?:r|e)di\\), %(?:|r|e)ax" 3 } } */ /* { dg-final { scan-assembler-times "xor(?:l|w|q)\[^\n\r]%(?:|r|e)di, %(?:|r|e)si, %(?:|r|e)ax" 2 } } */ /* { dg-final { scan-assembler-times "xor(?:l|w|q)\[^\n\r]%(?:|r|e)si, %(?:|r|e)di, %(?:|r|e)ax" 2 } } */ -/* { dg-final { scan-assembler-times "sal(?:b|l|w|q)\[^\n\r]*1, \\(%rdi\\), %(?:|r|e)a(?:x|l)" 4 } } */ +/* { dg-final { scan-assembler-times "sal(?:b|l|w|q)\[^\n\r]*1, \\(%(?:r|e)di\\), %(?:|r|e)a(?:x|l)" 4 } } */ /* { dg-final { scan-assembler-times "sal(?:l|w|q)\[^\n\r]*7, %(?:|r|e)di, %(?:|r|e)ax" 4 } } */ -/* { dg-final { scan-assembler-times "sar(?:b|l|w|q)\[^\n\r]*1, \\(%rdi\\), %(?:|r|e)a(?:x|l)" 4 } } */ +/* { dg-final { scan-assembler-times "sar(?:b|l|w|q)\[^\n\r]*1, \\(%(?:r|e)di\\), %(?:|r|e)a(?:x|l)" 4 } } */ /* { dg-final { scan-assembler-times "sar(?:b|l|w|q)\[^\n\r]*7, %(?:|r|e)di(?:|l), %(?:|r|e)a(?:x|l)" 4 } } */ -/* { dg-final { scan-assembler-times "shr(?:b|l|w|q)\[^\n\r]*1, \\(%rdi\\), %(?:|r|e)a(?:x|l)" 4 } } */ +/* { dg-final { scan-assembler-times "shr(?:b|l|w|q)\[^\n\r]*1, \\(%(?:r|e)di\\), %(?:|r|e)a(?:x|l)" 4 } } */ /* { dg-final { scan-assembler-times "shr(?:b|l|w|q)\[^\n\r]*7, %(?:|r|e)di(?:|l), %(?:|r|e)a(?:x|l)" 4 } } */ /* { dg-final { scan-assembler-times "ror(?:b|l|w|q)\[^\n\r]*1, %(?:|r|e)di(?:|l), %(?:|r|e)a(?:x|l)" 4 } } */ /* { dg-final { scan-assembler-times "rol(?:b|l|w|q)\[^\n\r]*1, %(?:|r|e)di(?:|l), %(?:|r|e)a(?:x|l)" 4 } } */ -- cgit v1.1 From 23f1b496aa6c7015a2b986aa183041c722104779 Mon Sep 17 00:00:00 2001 From: Richard Ball Date: Mon, 5 Feb 2024 14:03:05 +0000 Subject: arm: Fix missing bti instruction for virtual thunks Adds missing bti instruction at the beginning of a virtual thunk, when bti is enabled. gcc/ChangeLog: * config/arm/arm.cc (arm_output_mi_thunk): Emit insn for bti_c when bti is enabled. gcc/testsuite/ChangeLog: * lib/target-supports.exp: Add v8_1_m_main_pacbti. * g++.target/arm/bti_thunk.C: New test. --- gcc/config/arm/arm.cc | 2 ++ gcc/testsuite/g++.target/arm/bti_thunk.C | 20 ++++++++++++++++++++ gcc/testsuite/lib/target-supports.exp | 2 ++ 3 files changed, 24 insertions(+) create mode 100644 gcc/testsuite/g++.target/arm/bti_thunk.C (limited to 'gcc') diff --git a/gcc/config/arm/arm.cc b/gcc/config/arm/arm.cc index e5a9444..c44047c 100644 --- a/gcc/config/arm/arm.cc +++ b/gcc/config/arm/arm.cc @@ -29257,6 +29257,8 @@ arm_output_mi_thunk (FILE *file, tree thunk, HOST_WIDE_INT delta, const char *fnname = IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (thunk)); assemble_start_function (thunk, fnname); + if (aarch_bti_enabled ()) + emit_insn (aarch_gen_bti_c ()); if (TARGET_32BIT) arm32_output_mi_thunk (file, thunk, delta, vcall_offset, function); else diff --git a/gcc/testsuite/g++.target/arm/bti_thunk.C b/gcc/testsuite/g++.target/arm/bti_thunk.C new file mode 100644 index 0000000..23c1acc --- /dev/null +++ b/gcc/testsuite/g++.target/arm/bti_thunk.C @@ -0,0 +1,20 @@ +/* { dg-do compile } */ +/* { dg-require-effective-target arm_arch_v8_1m_main_pacbti_ok } */ +/* { dg-add-options arm_arch_v8_1m_main_pacbti } */ +/* { dg-additional-options "-mbranch-protection=bti" }*/ + +#include + +struct C18 { + virtual void f7(); +}; + +struct C19 : virtual C18 { + virtual void f7(); +}; + +void C19::f7() { + printf("foo\n"); +} + +/* { dg-final { scan-assembler-times "\tbti" 2 } } */ diff --git a/gcc/testsuite/lib/target-supports.exp b/gcc/testsuite/lib/target-supports.exp index f66dcaa..b1faaf4 100644 --- a/gcc/testsuite/lib/target-supports.exp +++ b/gcc/testsuite/lib/target-supports.exp @@ -5533,6 +5533,8 @@ foreach { armfunc armflag armdefs } { __ARM_ARCH_8M_BASE__ v8m_main "-march=armv8-m.main+fp -mthumb" __ARM_ARCH_8M_MAIN__ v8_1m_main "-march=armv8.1-m.main+fp -mthumb" __ARM_ARCH_8M_MAIN__ + v8_1m_main_pacbti "-march=armv8.1-m.main+pacbti+fp -mthumb" + "__ARM_ARCH_8M_MAIN__ && __ARM_FEATURE_BTI" v9a "-march=armv9-a+simd" __ARM_ARCH_9A__ } { eval [string map [list FUNC $armfunc FLAG $armflag DEFS $armdefs ] { proc check_effective_target_arm_arch_FUNC_ok { } { -- cgit v1.1 From 194ab79b580b69554124cf8257b19c957690a8a8 Mon Sep 17 00:00:00 2001 From: Jakub Jelinek Date: Mon, 5 Feb 2024 18:53:59 +0100 Subject: c: Avoid ICE with _BitInt(N) : 0 bitfield [PR113740] finish_struct already made sure not to call build_bitint_type for signed _BitInt(2) : 1; or signed _BitInt(2) : 0; bitfields (but instead build a zero precision integral type, we remove it later), this patch makes sure we do it also for unsigned _BitInt(1) : 0; because of the build_bitint_type assertion that precision is >= (unsigned ? 1 : 2). 2024-02-05 Jakub Jelinek PR c/113740 * c-decl.cc (finish_struct): Only use build_bitint_type if bit-field has width larger or equal to minimum _BitInt precision. * gcc.dg/bitint-85.c: New test. --- gcc/c/c-decl.cc | 2 +- gcc/testsuite/gcc.dg/bitint-85.c | 5 +++++ 2 files changed, 6 insertions(+), 1 deletion(-) create mode 100644 gcc/testsuite/gcc.dg/bitint-85.c (limited to 'gcc') diff --git a/gcc/c/c-decl.cc b/gcc/c/c-decl.cc index 934e557..fe20bc2 100644 --- a/gcc/c/c-decl.cc +++ b/gcc/c/c-decl.cc @@ -9555,7 +9555,7 @@ finish_struct (location_t loc, tree t, tree fieldlist, tree attributes, if (width != TYPE_PRECISION (type)) { if (TREE_CODE (type) == BITINT_TYPE - && (width > 1 || TYPE_UNSIGNED (type))) + && width >= (TYPE_UNSIGNED (type) ? 1 : 2)) TREE_TYPE (field) = build_bitint_type (width, TYPE_UNSIGNED (type)); else diff --git a/gcc/testsuite/gcc.dg/bitint-85.c b/gcc/testsuite/gcc.dg/bitint-85.c new file mode 100644 index 0000000..f2301cc --- /dev/null +++ b/gcc/testsuite/gcc.dg/bitint-85.c @@ -0,0 +1,5 @@ +/* PR c/113740 */ +/* { dg-do compile { target bitint } } */ +/* { dg-options "-std=c23" } */ + +struct S { unsigned _BitInt(32) : 0; }; -- cgit v1.1 From 51f8ac3341078303e81e72d9013698a31c5ddd29 Mon Sep 17 00:00:00 2001 From: "H.J. Lu" Date: Thu, 1 Feb 2024 08:02:27 -0800 Subject: x86-64: Find a scratch register for large model profiling 2 scratch registers, %r10 and %r11, are available at function entry for large model profiling. But %r10 may be used by stack realignment and we can't use %r10 in this case. Add x86_64_select_profile_regnum to find a caller-saved register which isn't live or a callee-saved register which has been saved on stack in the prologue at entry for large model profiling and sorry if we can't find one. gcc/ PR target/113689 * config/i386/i386.cc (x86_64_select_profile_regnum): New. (x86_function_profiler): Call x86_64_select_profile_regnum to get a scratch register for large model profiling. gcc/testsuite/ PR target/113689 * gcc.target/i386/pr113689-1.c: New file. * gcc.target/i386/pr113689-2.c: Likewise. * gcc.target/i386/pr113689-3.c: Likewise. --- gcc/config/i386/i386.cc | 91 +++++++++++++++++++++++++----- gcc/testsuite/gcc.target/i386/pr113689-1.c | 49 ++++++++++++++++ gcc/testsuite/gcc.target/i386/pr113689-2.c | 41 ++++++++++++++ gcc/testsuite/gcc.target/i386/pr113689-3.c | 48 ++++++++++++++++ 4 files changed, 214 insertions(+), 15 deletions(-) create mode 100644 gcc/testsuite/gcc.target/i386/pr113689-1.c create mode 100644 gcc/testsuite/gcc.target/i386/pr113689-2.c create mode 100644 gcc/testsuite/gcc.target/i386/pr113689-3.c (limited to 'gcc') diff --git a/gcc/config/i386/i386.cc b/gcc/config/i386/i386.cc index b3e7c74..f02c6c0 100644 --- a/gcc/config/i386/i386.cc +++ b/gcc/config/i386/i386.cc @@ -22749,6 +22749,48 @@ current_fentry_section (const char **name) return true; } +/* Return a caller-saved register which isn't live or a callee-saved + register which has been saved on stack in the prologue at entry for + profile. */ + +static int +x86_64_select_profile_regnum (bool r11_ok ATTRIBUTE_UNUSED) +{ + /* Use %r10 if the profiler is emitted before the prologue or it isn't + used by DRAP. */ + if (ix86_profile_before_prologue () + || !crtl->drap_reg + || REGNO (crtl->drap_reg) != R10_REG) + return R10_REG; + + /* The profiler is emitted after the prologue. If there is a + caller-saved register which isn't live or a callee-saved + register saved on stack in the prologue, use it. */ + + bitmap reg_live = df_get_live_out (ENTRY_BLOCK_PTR_FOR_FN (cfun)); + + int i; + for (i = 0; i < FIRST_PSEUDO_REGISTER; i++) + if (GENERAL_REGNO_P (i) + && i != R10_REG +#ifdef NO_PROFILE_COUNTERS + && (r11_ok || i != R11_REG) +#else + && i != R11_REG +#endif + && TEST_HARD_REG_BIT (accessible_reg_set, i) + && (ix86_save_reg (i, true, true) + || (call_used_regs[i] + && !fixed_regs[i] + && !REGNO_REG_SET_P (reg_live, i)))) + return i; + + sorry ("no register available for profiling %<-mcmodel=large%s%>", + ix86_cmodel == CM_LARGE_PIC ? " -fPIC" : ""); + + return INVALID_REGNUM; +} + /* Output assembler code to FILE to increment profiler label # LABELNO for profiling a function entry. */ void @@ -22783,42 +22825,61 @@ x86_function_profiler (FILE *file, int labelno ATTRIBUTE_UNUSED) fprintf (file, "\tleaq\t%sP%d(%%rip), %%r11\n", LPREFIX, labelno); #endif + int scratch; + const char *reg; + char legacy_reg[4] = { 0 }; + if (!TARGET_PECOFF) { switch (ix86_cmodel) { case CM_LARGE: - /* NB: R10 is caller-saved. Although it can be used as a - static chain register, it is preserved when calling - mcount for nested functions. */ + scratch = x86_64_select_profile_regnum (true); + reg = hi_reg_name[scratch]; + if (LEGACY_INT_REGNO_P (scratch)) + { + legacy_reg[0] = 'r'; + legacy_reg[1] = reg[0]; + legacy_reg[2] = reg[1]; + reg = legacy_reg; + } if (ASSEMBLER_DIALECT == ASM_INTEL) - fprintf (file, "1:\tmovabs\tr10, OFFSET FLAT:%s\n" - "\tcall\tr10\n", mcount_name); + fprintf (file, "1:\tmovabs\t%s, OFFSET FLAT:%s\n" + "\tcall\t%s\n", reg, mcount_name, reg); else - fprintf (file, "1:\tmovabsq\t$%s, %%r10\n\tcall\t*%%r10\n", - mcount_name); + fprintf (file, "1:\tmovabsq\t$%s, %%%s\n\tcall\t*%%%s\n", + mcount_name, reg, reg); break; case CM_LARGE_PIC: #ifdef NO_PROFILE_COUNTERS + scratch = x86_64_select_profile_regnum (false); + reg = hi_reg_name[scratch]; + if (LEGACY_INT_REGNO_P (scratch)) + { + legacy_reg[0] = 'r'; + legacy_reg[1] = reg[0]; + legacy_reg[2] = reg[1]; + reg = legacy_reg; + } if (ASSEMBLER_DIALECT == ASM_INTEL) { fprintf (file, "1:movabs\tr11, " "OFFSET FLAT:_GLOBAL_OFFSET_TABLE_-1b\n"); - fprintf (file, "\tlea\tr10, 1b[rip]\n"); - fprintf (file, "\tadd\tr10, r11\n"); + fprintf (file, "\tlea\t%s, 1b[rip]\n", reg); + fprintf (file, "\tadd\t%s, r11\n", reg); fprintf (file, "\tmovabs\tr11, OFFSET FLAT:%s@PLTOFF\n", mcount_name); - fprintf (file, "\tadd\tr10, r11\n"); - fprintf (file, "\tcall\tr10\n"); + fprintf (file, "\tadd\t%s, r11\n", reg); + fprintf (file, "\tcall\t%s\n", reg); break; } fprintf (file, "1:\tmovabsq\t$_GLOBAL_OFFSET_TABLE_-1b, %%r11\n"); - fprintf (file, "\tleaq\t1b(%%rip), %%r10\n"); - fprintf (file, "\taddq\t%%r11, %%r10\n"); + fprintf (file, "\tleaq\t1b(%%rip), %%%s\n", reg); + fprintf (file, "\taddq\t%%r11, %%%s\n", reg); fprintf (file, "\tmovabsq\t$%s@PLTOFF, %%r11\n", mcount_name); - fprintf (file, "\taddq\t%%r11, %%r10\n"); - fprintf (file, "\tcall\t*%%r10\n"); + fprintf (file, "\taddq\t%%r11, %%%s\n", reg); + fprintf (file, "\tcall\t*%%%s\n", reg); #else sorry ("profiling %<-mcmodel=large%> with PIC is not supported"); #endif diff --git a/gcc/testsuite/gcc.target/i386/pr113689-1.c b/gcc/testsuite/gcc.target/i386/pr113689-1.c new file mode 100644 index 0000000..8285c0a --- /dev/null +++ b/gcc/testsuite/gcc.target/i386/pr113689-1.c @@ -0,0 +1,49 @@ +/* { dg-do run { target { lp64 && fpic } } } */ +/* { dg-options "-O2 -fno-pic -fprofile -mcmodel=large" } */ + +#include + +__attribute__((noipa)) +void +bar (int a1, int a2, int a3, int a4, int a5, int a6, + char *x, char *y, int *z) +{ + if (a1 != 1) + __builtin_abort (); + if (a2 != 2) + __builtin_abort (); + if (a3 != 3) + __builtin_abort (); + if (a4 != 4) + __builtin_abort (); + if (a5 != 5) + __builtin_abort (); + if (a6 != 6) + __builtin_abort (); + x[0] = 42; + y[0] = 42; + if (z[0] != 16) + __builtin_abort (); +} + +__attribute__((noipa)) +void +foo (int c, int d, int e, int f, int g, int h, int z, ...) +{ + typedef char B[32]; + B b __attribute__((aligned (32))); + va_list ap; + va_start (ap, z); + double x = va_arg (ap, double); + if (x > 40.0) + __builtin_abort (); + bar (c, d, e, f, g, h, &b[0], __builtin_alloca (z), &z); + va_end (ap); +} + +int +main () +{ + foo (1, 2, 3, 4, 5, 6, 16, 38.0); + return 0; +} diff --git a/gcc/testsuite/gcc.target/i386/pr113689-2.c b/gcc/testsuite/gcc.target/i386/pr113689-2.c new file mode 100644 index 0000000..2e5579a --- /dev/null +++ b/gcc/testsuite/gcc.target/i386/pr113689-2.c @@ -0,0 +1,41 @@ +/* { dg-do run { target { lp64 && fpic } } } */ +/* { dg-options "-O2 -fpic -fprofile -mcmodel=large" } */ + +__attribute__((noipa)) +void +bar (int a1, int a2, int a3, int a4, int a5, int a6, + char *x, char *y, int *z) +{ + if (a1 != 1) + __builtin_abort (); + if (a2 != 2) + __builtin_abort (); + if (a3 != 3) + __builtin_abort (); + if (a4 != 4) + __builtin_abort (); + if (a5 != 5) + __builtin_abort (); + if (a6 != 6) + __builtin_abort (); + x[0] = 42; + y[0] = 42; + if (z[0] != 16) + __builtin_abort (); +} + +__attribute__((noipa)) +void +foo (int c, int d, int e, int f, int g, int h, int z) +{ + typedef char B[32]; + B b __attribute__((aligned (32))); + bar (c, d, e, f, g, h, &b[0], __builtin_alloca (z), &z); +} + +int +main () +{ + foo (1, 2, 3, 4, 5, 6, 16); + return 0; +} diff --git a/gcc/testsuite/gcc.target/i386/pr113689-3.c b/gcc/testsuite/gcc.target/i386/pr113689-3.c new file mode 100644 index 0000000..dab7519 --- /dev/null +++ b/gcc/testsuite/gcc.target/i386/pr113689-3.c @@ -0,0 +1,48 @@ +/* { dg-do run { target { lp64 && fpic } } } */ +/* { dg-options "-O2 -fpic -fprofile -mcmodel=large" } */ + +#include + +__attribute__((noipa)) +void +bar (char *x, char *y, int *z) +{ + x[0] = 42; + y[0] = 42; + if (z[0] != 16) + __builtin_abort (); +} + +__attribute__((noipa)) +void +foo (int a1, int a2, int a3, int a4, int a5, int a6, int z, ...) +{ + typedef char B[32]; + B b __attribute__((aligned (32))); + va_list ap; + va_start (ap, z); + double x = va_arg (ap, double); + if (x > 40.0) + __builtin_abort (); + if (a1 != 1) + __builtin_abort (); + if (a2 != 2) + __builtin_abort (); + if (a3 != 3) + __builtin_abort (); + if (a4 != 4) + __builtin_abort (); + if (a5 != 5) + __builtin_abort (); + if (a6 != 6) + __builtin_abort (); + bar (&b[0], __builtin_alloca (z), &z); + va_end (ap); +} + +int +main () +{ + foo (1, 2, 3, 4, 5, 6, 16, 38.0); + return 0; +} -- cgit v1.1 From e86066a71e684065fae6910b9e2aaf37d7177e01 Mon Sep 17 00:00:00 2001 From: Ian Lance Taylor Date: Fri, 20 Oct 2023 10:25:04 -0700 Subject: compiler: add Type::message_name As we move toward generics, the error messages need to be able to refer to types in a readable manner. Add that capability, and use it today in AST dumps. Reviewed-on: https://go-review.googlesource.com/c/gofrontend/+/536716 --- gcc/go/gofrontend/MERGE | 2 +- gcc/go/gofrontend/ast-dump.cc | 9 +- gcc/go/gofrontend/types.cc | 310 ++++++++++++++++++++++++++++++++++++++++-- gcc/go/gofrontend/types.h | 79 ++++++++++- 4 files changed, 375 insertions(+), 25 deletions(-) (limited to 'gcc') diff --git a/gcc/go/gofrontend/MERGE b/gcc/go/gofrontend/MERGE index 429904a..ec7e2ab 100644 --- a/gcc/go/gofrontend/MERGE +++ b/gcc/go/gofrontend/MERGE @@ -1,4 +1,4 @@ -8c056e335cecec67d1d223a329b7ba4dac778a65 +1cb83a415e86ab4de0d436d277377d8fc060cb61 The first line of this file holds the git revision number of the last merge done from the gofrontend repository. diff --git a/gcc/go/gofrontend/ast-dump.cc b/gcc/go/gofrontend/ast-dump.cc index eca0bf1..12f49e6 100644 --- a/gcc/go/gofrontend/ast-dump.cc +++ b/gcc/go/gofrontend/ast-dump.cc @@ -223,14 +223,7 @@ Ast_dump_context::dump_type(const Type* t) if (t == NULL) this->ostream() << "(nil type)"; else - // FIXME: write a type pretty printer instead of - // using mangled names. - if (this->gogo_ != NULL) - { - Backend_name bname; - t->backend_name(this->gogo_, &bname); - this->ostream() << "(" << bname.name() << ")"; - } + this->ostream() << "(" << t->message_name() << ")"; } // Dump a textual representation of a block to the diff --git a/gcc/go/gofrontend/types.cc b/gcc/go/gofrontend/types.cc index b349ad1..a39cfbf 100644 --- a/gcc/go/gofrontend/types.cc +++ b/gcc/go/gofrontend/types.cc @@ -270,6 +270,16 @@ Type::set_is_error() this->classification_ = TYPE_ERROR; } +// Return a string version of this type to use in an error message. + +std::string +Type::message_name() const +{ + std::string ret; + this->do_message_name(&ret); + return ret; +} + // If this is a pointer type, return the type to which it points. // Otherwise, return NULL. @@ -742,16 +752,14 @@ Type::are_assignable(const Type* lhs, const Type* rhs, std::string* reason) { if (rhs->interface_type() != NULL) reason->assign(_("need explicit conversion")); - else if (lhs_orig->named_type() != NULL - && rhs_orig->named_type() != NULL) + else { - size_t len = (lhs_orig->named_type()->name().length() - + rhs_orig->named_type()->name().length() - + 100); + const std::string& lhs_name(lhs_orig->message_name()); + const std::string& rhs_name(rhs_orig->message_name()); + size_t len = lhs_name.length() + rhs_name.length() + 100; char* buf = new char[len]; snprintf(buf, len, _("cannot use type %s as type %s"), - rhs_orig->named_type()->message_name().c_str(), - lhs_orig->named_type()->message_name().c_str()); + rhs_name.c_str(), lhs_name.c_str()); reason->assign(buf); delete[] buf; } @@ -4244,6 +4252,33 @@ Integer_type::is_identical(const Integer_type* t) const return this->is_abstract_ == t->is_abstract_; } +// Message name. + +void +Integer_type::do_message_name(std::string* ret) const +{ + ret->append("is_byte_) + ret->append("byte"); + else if (this->is_rune_) + ret->append("rune"); + else + { + if (this->is_unsigned_) + ret->push_back('u'); + if (this->is_abstract_) + ret->append("int"); + else + { + ret->append("int"); + char buf[10]; + snprintf(buf, sizeof buf, "%d", this->bits_); + ret->append(buf); + } + } + ret->push_back('>'); +} + // Hash code. unsigned int @@ -4382,6 +4417,21 @@ Float_type::is_identical(const Float_type* t) const return this->is_abstract_ == t->is_abstract_; } +// Message name. + +void +Float_type::do_message_name(std::string* ret) const +{ + ret->append("is_abstract_) + { + char buf[10]; + snprintf(buf, sizeof buf, "%d", this->bits_); + ret->append(buf); + } + ret->push_back('>'); +} + // Hash code. unsigned int @@ -4496,6 +4546,21 @@ Complex_type::is_identical(const Complex_type *t) const return this->is_abstract_ == t->is_abstract_; } +// Message name. + +void +Complex_type::do_message_name(std::string* ret) const +{ + ret->append("is_abstract_) + { + char buf[10]; + snprintf(buf, sizeof buf, "%d", this->bits_); + ret->append(buf); + } + ret->push_back('>'); +} + // Hash code. unsigned int @@ -4661,6 +4726,10 @@ class Sink_type : public Type { } protected: + void + do_message_name(std::string* ret) const + { ret->append(""); } + bool do_compare_is_identity(Gogo*) { return false; } @@ -4696,6 +4765,70 @@ Type::make_sink_type() // Class Function_type. +// Message name. + +void +Function_type::do_message_name(std::string* ret) const +{ + ret->append("func"); + if (this->receiver_ != NULL) + { + ret->append(" (receiver "); + this->append_message_name(this->receiver_->type(), ret); + ret->append(") "); + } + this->append_signature(ret); +} + +// Append just the signature to RET. + +void +Function_type::append_signature(std::string* ret) const +{ + ret->push_back('('); + if (this->parameters_ != NULL) + { + bool first = true; + for (Typed_identifier_list::const_iterator p = this->parameters_->begin(); + p != this->parameters_->end(); + ++p) + { + if (first) + first = false; + else + ret->append(", "); + this->append_message_name(p->type(), ret); + } + } + ret->push_back(')'); + + if (this->results_ != NULL) + { + if (this->results_->size() == 1) + { + ret->push_back(' '); + this->append_message_name(this->results_->front().type(), ret); + } + else + { + ret->append(" ("); + bool first = true; + for (Typed_identifier_list::const_iterator p = + this->results_->begin(); + p != this->results_->end(); + ++p) + { + if (first) + first = false; + else + ret->append(", "); + this->append_message_name(p->type(), ret); + } + ret->push_back(')'); + } + } +} + // Traversal. int @@ -5548,6 +5681,20 @@ Type::make_backend_function_type(Typed_identifier* receiver, // Class Pointer_type. +// Message name. + +void +Pointer_type::do_message_name(std::string* ret) const +{ + if (this->to_type_->is_void_type()) + ret->append("unsafe.Pointer"); + else + { + ret->push_back('*'); + this->append_message_name(this->to_type_, ret); + } +} + // Traversal. int @@ -5764,6 +5911,10 @@ class Call_multiple_result_type : public Type { } protected: + void + do_message_name(std::string* ret) const + { ret->append(""); } + bool do_has_pointer() const { return false; } @@ -5940,6 +6091,41 @@ Struct_type::Identical_structs Struct_type::identical_structs; Struct_type::Struct_method_tables Struct_type::struct_method_tables; +// Message name. + +void +Struct_type::do_message_name(std::string* ret) const +{ + if (this->fields_ == NULL || this->fields_->empty()) + { + ret->append("struct{}"); + return; + } + + ret->append("struct {"); + + bool first = true; + for (Struct_field_list::const_iterator p = this->fields_->begin(); + p != this->fields_->end(); + ++p) + { + if (first) + first = false; + else + ret->append("; "); + + if (!p->is_anonymous()) + { + ret->append(p->field_name()); + ret->push_back(' '); + } + + this->append_message_name(p->type(), ret); + } + + ret->append(" }"); +} + // Traversal. int @@ -7344,6 +7530,35 @@ Array_type::is_identical(const Array_type* t, int flags) const return false; } +// Message name. + +void +Array_type::do_message_name(std::string* ret) const +{ + ret->push_back('['); + if (!this->is_slice_type()) + { + Numeric_constant nc; + if (!this->length_->numeric_constant_value(&nc)) + ret->append(""); + else + { + mpz_t val; + if (!nc.to_int(&val)) + ret->append(""); + else + { + char* s = mpz_get_str(NULL, 10, val); + ret->append(s); + free(s); + mpz_clear(val); + } + } + } + ret->push_back(']'); + this->append_message_name(this->element_type_, ret); +} + // Traversal. int @@ -8249,6 +8464,17 @@ Map_type::backend_zero_value(Gogo* gogo) return zvar; } +// Message name. + +void +Map_type::do_message_name(std::string* ret) const +{ + ret->append("map["); + this->append_message_name(this->key_type_, ret); + ret->push_back(']'); + this->append_message_name(this->val_type_, ret); +} + // Traversal. int @@ -8803,6 +9029,20 @@ Type::make_map_type(Type* key_type, Type* val_type, Location location) // Class Channel_type. +// Message name. + +void +Channel_type::do_message_name(std::string* ret) const +{ + if (!this->may_send_) + ret->append("<-"); + ret->append("chan"); + if (!this->may_receive_) + ret->append("<-"); + ret->push_back(' '); + this->append_message_name(this->element_type_, ret); +} + // Verify. bool @@ -9053,6 +9293,45 @@ Interface_type::method_count() const return this->all_methods_ == NULL ? 0 : this->all_methods_->size(); } +// Message name. + +void +Interface_type::do_message_name(std::string* ret) const +{ + const Typed_identifier_list* methods = (this->methods_are_finalized_ + ? this->all_methods_ + : this->parse_methods_); + if (methods == NULL || methods->empty()) + { + ret->append("interface{}"); + return; + } + + ret->append("interface {"); + + bool first = true; + for (Typed_identifier_list::const_iterator p = methods->begin(); + p != methods->end(); + ++p) + { + if (first) + first = false; + else + ret->append("; "); + + if (!p->name().empty()) + ret->append(p->name()); + + Function_type* ft = p->type()->function_type(); + if (ft == NULL) + this->append_message_name(p->type(), ret); + else + ft->append_signature(ret); + } + + ret->append(" }"); +} + // Traversal. int @@ -10295,10 +10574,10 @@ Named_type::name() const // Return the name of the type to use in an error message. -std::string -Named_type::message_name() const +void +Named_type::do_message_name(std::string* ret) const { - return this->named_object_->message_name(); + ret->append(this->named_object_->message_name()); } // Return the base type for this type. We have to be careful about @@ -12819,6 +13098,17 @@ Forward_declaration_type::add_existing_method(Named_object* nom) no->type_declaration_value()->add_existing_method(nom); } +// Message name. + +void +Forward_declaration_type::do_message_name(std::string* ret) const +{ + if (this->is_defined()) + this->append_message_name(this->real_type(), ret); + else + ret->append(this->named_object_->message_name()); +} + // Traversal. int diff --git a/gcc/go/gofrontend/types.h b/gcc/go/gofrontend/types.h index 3dd3279..cbc7ce0 100644 --- a/gcc/go/gofrontend/types.h +++ b/gcc/go/gofrontend/types.h @@ -575,6 +575,10 @@ class Type static Named_type* make_builtin_named_type(const char* name, Type* type); + // Return a string version of this type to use in an error message. + std::string + message_name() const; + // Traverse a type. static int traverse(Type*, Traverse*); @@ -1095,6 +1099,10 @@ class Type // Functions implemented by the child class. + // Message name. + virtual void + do_message_name(std::string*) const = 0; + // Traverse the subtypes. virtual int do_traverse(Traverse*); @@ -1195,6 +1203,11 @@ class Type type_descriptor_constructor(Gogo*, int runtime_type_kind, Named_type*, const Methods*, bool only_value_methods); + // For the benefit of child class message name construction. + void + append_message_name(const Type* type, std::string* ret) const + { type->do_message_name(ret); } + // For the benefit of child class reflection string generation. void append_reflection(const Type* type, Gogo* gogo, std::string* ret) const @@ -1656,6 +1669,10 @@ class Error_type : public Type { } protected: + void + do_message_name(std::string* ret) const + { ret->append(""); } + bool do_compare_is_identity(Gogo*) { return false; } @@ -1683,6 +1700,10 @@ class Void_type : public Type { } protected: + void + do_message_name(std::string* ret) const + { ret->append("void"); } + bool do_compare_is_identity(Gogo*) { return false; } @@ -1712,6 +1733,10 @@ class Boolean_type : public Type { } protected: + void + do_message_name(std::string* ret) const + { ret->append(""); } + bool do_compare_is_identity(Gogo*) { return true; } @@ -1797,6 +1822,9 @@ class Integer_type : public Type { this->is_rune_ = true; } protected: + void + do_message_name(std::string* ret) const; + bool do_compare_is_identity(Gogo*) { return true; } @@ -1874,6 +1902,9 @@ class Float_type : public Type is_identical(const Float_type* t) const; protected: + void + do_message_name(std::string* ret) const; + bool do_compare_is_identity(Gogo*) { return false; } @@ -1952,6 +1983,9 @@ class Complex_type : public Type is_identical(const Complex_type* t) const; protected: + void + do_message_name(std::string*) const; + bool do_compare_is_identity(Gogo*) { return false; } @@ -2009,6 +2043,10 @@ class String_type : public Type { } protected: + void + do_message_name(std::string* ret) const + { ret->append(""); } + bool do_has_pointer() const { return true; } @@ -2166,7 +2204,14 @@ class Function_type : public Type is_backend_function_type() const { return false; } + // Append just the signature of the function type. + void + append_signature(std::string*) const; + protected: + void + do_message_name(std::string*) const; + int do_traverse(Traverse*); @@ -2293,6 +2338,9 @@ class Pointer_type : public Type make_pointer_type_descriptor_type(); protected: + void + do_message_name(std::string*) const; + int do_traverse(Traverse*); @@ -2346,6 +2394,10 @@ class Nil_type : public Type { } protected: + void + do_message_name(std::string* ret) const + { ret->append(""); } + bool do_compare_is_identity(Gogo*) { return false; } @@ -2671,6 +2723,9 @@ class Struct_type : public Type write_to_c_header(std::ostream&) const; protected: + void + do_message_name(std::string*) const; + int do_traverse(Traverse*); @@ -2851,6 +2906,9 @@ class Array_type : public Type write_equal_function(Gogo*, Named_object* function, Named_type*); protected: + void + do_message_name(std::string*) const; + int do_traverse(Traverse* traverse); @@ -2999,6 +3057,9 @@ class Map_type : public Type static const int bucket_size = 8; protected: + void + do_message_name(std::string*) const; + int do_traverse(Traverse*); @@ -3118,6 +3179,9 @@ class Channel_type : public Type select_case_type(); protected: + void + do_message_name(std::string*) const; + int do_traverse(Traverse* traverse) { return Type::traverse(this->element_type_, traverse); } @@ -3273,6 +3337,9 @@ class Interface_type : public Type { return this->methods_are_finalized_; } protected: + void + do_message_name(std::string*) const; + int do_traverse(Traverse*); @@ -3450,12 +3517,6 @@ class Named_type : public Type const std::string& name() const; - // Return the name of the type for an error message. The difference - // is that if the type is defined in a different package, this will - // return PACKAGE.NAME. - std::string - message_name() const; - // Return the underlying type. Type* real_type() @@ -3599,6 +3660,9 @@ class Named_type : public Type convert(Gogo*); protected: + void + do_message_name(std::string* ret) const; + int do_traverse(Traverse* traverse) { return Type::traverse(this->type_, traverse); } @@ -3758,6 +3822,9 @@ class Forward_declaration_type : public Type add_existing_method(Named_object*); protected: + void + do_message_name(std::string*) const; + int do_traverse(Traverse* traverse); -- cgit v1.1 From f1412546ac8999b7f6eeeee8cf967ce3f31794c2 Mon Sep 17 00:00:00 2001 From: Ian Lance Taylor Date: Fri, 2 Feb 2024 15:05:08 -0800 Subject: libgo: bump libgo version for GCC 14 release PR go/113668 Reviewed-on: https://go-review.googlesource.com/c/gofrontend/+/560676 --- gcc/go/gofrontend/MERGE | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'gcc') diff --git a/gcc/go/gofrontend/MERGE b/gcc/go/gofrontend/MERGE index ec7e2ab..73cb095 100644 --- a/gcc/go/gofrontend/MERGE +++ b/gcc/go/gofrontend/MERGE @@ -1,4 +1,4 @@ -1cb83a415e86ab4de0d436d277377d8fc060cb61 +e15a14e410b8fc5d28012d5b313cb6c8476c7df9 The first line of this file holds the git revision number of the last merge done from the gofrontend repository. -- cgit v1.1 From c7e8381748f78335e9fef23f363b6a9e4463ce7e Mon Sep 17 00:00:00 2001 From: Jason Merrill Date: Mon, 5 Feb 2024 13:54:22 -0500 Subject: c++: prvalue of array type [PR111286] Here we want to build a prvalue array to bind to the T reference, but we were wrongly trying to strip cv-quals from the array prvalue, which should be treated the same as a class prvalue. PR c++/111286 gcc/cp/ChangeLog: * tree.cc (rvalue): Don't drop cv-quals from an array. gcc/testsuite/ChangeLog: * g++.dg/cpp0x/initlist-array22.C: New test. --- gcc/cp/tree.cc | 9 +++++---- gcc/testsuite/g++.dg/cpp0x/initlist-array22.C | 12 ++++++++++++ 2 files changed, 17 insertions(+), 4 deletions(-) create mode 100644 gcc/testsuite/g++.dg/cpp0x/initlist-array22.C (limited to 'gcc') diff --git a/gcc/cp/tree.cc b/gcc/cp/tree.cc index 5c8c05d..50dc345 100644 --- a/gcc/cp/tree.cc +++ b/gcc/cp/tree.cc @@ -977,11 +977,12 @@ rvalue (tree expr) expr = mark_rvalue_use (expr); - /* [basic.lval] - - Non-class rvalues always have cv-unqualified types. */ + /* [expr.type]: "If a prvalue initially has the type "cv T", where T is a + cv-unqualified non-class, non-array type, the type of the expression is + adjusted to T prior to any further analysis. */ type = TREE_TYPE (expr); - if (!CLASS_TYPE_P (type) && cv_qualified_p (type)) + if (!CLASS_TYPE_P (type) && TREE_CODE (type) != ARRAY_TYPE + && cv_qualified_p (type)) type = cv_unqualified (type); /* We need to do this for rvalue refs as well to get the right answer diff --git a/gcc/testsuite/g++.dg/cpp0x/initlist-array22.C b/gcc/testsuite/g++.dg/cpp0x/initlist-array22.C new file mode 100644 index 0000000..8629e4b --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp0x/initlist-array22.C @@ -0,0 +1,12 @@ +// PR c++/111286 +// { dg-do compile { target c++11 } } +// { dg-additional-options -Wno-unused } + +struct A { + A() noexcept {} +}; + +void foo() { + using T = const A (&)[1]; + T{}; +} -- cgit v1.1 From 106cc847c5cda948efd4bc20910e79258b5313ed Mon Sep 17 00:00:00 2001 From: Joseph Myers Date: Mon, 5 Feb 2024 21:33:30 +0000 Subject: Update gcc zh_CN.po * zh_CN.po: Update. --- gcc/po/zh_CN.po | 359 +++++++++++++++++++++++++------------------------------- 1 file changed, 157 insertions(+), 202 deletions(-) (limited to 'gcc') diff --git a/gcc/po/zh_CN.po b/gcc/po/zh_CN.po index 42661f6..0462ba2 100644 --- a/gcc/po/zh_CN.po +++ b/gcc/po/zh_CN.po @@ -4,7 +4,7 @@ # Meng Jie , 2005-2014. # Jeff Bai , 2015. # Mingye Wang (Arthur2e5) , 2015, 2016. -# Boyuan Yang <073plan@gmail.com>, 2019, 2023. +# Boyuan Yang <073plan@gmail.com>, 2019, 2023, 2024. # Zixing Zhou , 2023. # # Fellow translatiors: @@ -32,19 +32,19 @@ # msgid "" msgstr "" -"Project-Id-Version: gcc 13.1-b20230409\n" +"Project-Id-Version: gcc 13.2.0\n" "Report-Msgid-Bugs-To: https://gcc.gnu.org/bugs/\n" "POT-Creation-Date: 2023-07-26 18:38+0000\n" -"PO-Revision-Date: 2023-04-13 22:07-0400\n" +"PO-Revision-Date: 2024-02-05 15:48-0500\n" "Last-Translator: Boyuan Yang <073plan@gmail.com>\n" "Language-Team: Chinese (simplified) \n" "Language: zh_CN\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Bugs: Report translation errors to the Language-Team address.\n" "Plural-Forms: nplurals=1; plural=0;\n" -"X-Generator: Poedit 2.4.3\n" +"X-Bugs: Report translation errors to the Language-Team address.\n" +"X-Generator: Poedit 3.4.2\n" #: cif-code.def:39 msgid "function not considered for inlining" @@ -67,7 +67,6 @@ msgid "function not inlinable" msgstr "函数不能内联" #: cif-code.def:60 -#, fuzzy msgid "function body can be overwritten at link time" msgstr "函数体可能在链接时被改写" @@ -221,10 +220,9 @@ msgid "permerror: " msgstr "永久错误:" #: config/i386/djgpp.h:143 -#, fuzzy, c-format -#| msgid "-f%s not supported: ignored" +#, c-format msgid "-f%s ignored (not supported for DJGPP)\n" -msgstr "-f%s 不受支持:已忽略" +msgstr "-f%s 已被忽略(不支持 DJGPP)\n" #. The remainder are real diagnostic types. #: fortran/gfc-diagnostic.def:33 @@ -372,8 +370,7 @@ msgid "rdynamic is not supported" msgstr "不支持 rdynamic" #: config/dragonfly.h:76 config/i386/freebsd.h:82 config/i386/freebsd64.h:35 -#: config/ia64/freebsd.h:26 config/rs6000/sysv4.h:750 -#: config/sparc/freebsd.h:45 +#: config/ia64/freebsd.h:26 config/rs6000/sysv4.h:750 config/sparc/freebsd.h:45 msgid "consider using '-pg' instead of '-p' with gprof(1)" msgstr "与 gprof(1) 一起使用时请考虑使用‘-pg’以代替‘-p’" @@ -434,7 +431,6 @@ msgid "Darwin does not support -mfentry or associated options" msgstr "Darwin 不支持 -mfentry 以及相关选项" #: config/i386/sol2.h:59 -#, fuzzy msgid "-mx32 is not supported on Solaris" msgstr "Solaris 不支持 -mx32" @@ -451,10 +447,8 @@ msgid "-msingle-float and -msoft-float cannot both be specified" msgstr "不能同时指定 -msingle-float 和 -msoft-float" #: config/moxie/moxiebox.h:43 -#, fuzzy -#| msgid "Assume target CPU is configured as little endian" msgid "this target is little-endian" -msgstr "假定目标 CPU 被配置为小端在前" +msgstr "该目标为小端序" #: config/msp430/msp430.h:90 msgid "-mcode-region requires the large memory model (-mlarge)" @@ -468,16 +462,14 @@ msgstr "-mdata-region 需要大内存模型(-mlarge)" msgid "You need a C startup file for -msys-crt0=" msgstr "-msys-crt0 需要指定C语言启动文件" -#: config/pa/pa-hpux11.h:134 config/pa/pa-hpux11.h:137 -#: config/pa/pa64-hpux.h:29 config/pa/pa64-hpux.h:32 config/pa/pa64-hpux.h:41 -#: config/pa/pa64-hpux.h:44 +#: config/pa/pa-hpux11.h:134 config/pa/pa-hpux11.h:137 config/pa/pa64-hpux.h:29 +#: config/pa/pa64-hpux.h:32 config/pa/pa64-hpux.h:41 config/pa/pa64-hpux.h:44 #, fuzzy msgid "warning: consider linking with '-static' as system libraries with" msgstr "警告:考虑链接时使用‘-static’因为系统库" -#: config/pa/pa-hpux11.h:135 config/pa/pa-hpux11.h:138 -#: config/pa/pa64-hpux.h:30 config/pa/pa64-hpux.h:33 config/pa/pa64-hpux.h:42 -#: config/pa/pa64-hpux.h:45 +#: config/pa/pa-hpux11.h:135 config/pa/pa-hpux11.h:138 config/pa/pa64-hpux.h:30 +#: config/pa/pa64-hpux.h:33 config/pa/pa64-hpux.h:42 config/pa/pa64-hpux.h:45 msgid " profiling support are only provided in archive format" msgstr "取样支持只支持存档格式" @@ -486,9 +478,8 @@ msgid " conflicting code gen style switches are used" msgstr "使用了相互冲突的代码生成风格" #: config/rs6000/freebsd64.h:114 -#, fuzzy msgid "consider using `-pg' instead of `-p' with gprof(1)" -msgstr "与 gprof(1) 一起使用时请考虑使用‘-pg’以代替‘-p’" +msgstr "与 gprof(1) 一起使用时请考虑使用‘-pg’而非‘-p’" #: config/rs6000/rs6000.h:170 msgid "Missing -mcpu option in ASM_CPU_SPEC?" @@ -515,9 +506,8 @@ msgid "SH2a does not support little-endian" msgstr "SH2a 不支持小端在前" #: config/sparc/linux64.h:142 -#, fuzzy msgid "-fsanitize=address is not supported in this configuration" -msgstr "%s 不为这个配置所支持" +msgstr "该配置不支持 -fsanitize=address" #: config/sparc/linux64.h:156 config/sparc/linux64.h:162 #: config/sparc/netbsd-elf.h:103 config/sparc/netbsd-elf.h:112 @@ -538,14 +528,12 @@ msgid "-c or -S required for Ada" msgstr "Ada 需要指定 -c 或 -S" #: ada/gcc-interface/lang-specs.h:56 -#, fuzzy msgid "-c required for gnat2why" -msgstr "Ada 需要指定 -c 或 -S" +msgstr "gnat2why 需要 -c" #: ada/gcc-interface/lang-specs.h:67 -#, fuzzy msgid "-c required for gnat2scil" -msgstr "Ada 需要指定 -c 或 -S" +msgstr "gnat2scil 需要 -c" #: fortran/lang-specs.h:60 fortran/lang-specs.h:74 msgid "gfortran does not support -E without -cpp" @@ -613,7 +601,7 @@ msgstr "不起作用。为向前兼容保留的选项。" #: fortran/lang.opt:218 #, no-c-format msgid "Warn if the type of a variable might be not interoperable with C." -msgstr "对可能不与C语言互通的类型给出警告" +msgstr "对可能不与C语言互通的类型给出警告。" #: fortran/lang.opt:226 #, fuzzy, no-c-format @@ -627,10 +615,9 @@ msgid "Warn about equality comparisons involving REAL or COMPLEX expressions." msgstr "" #: fortran/lang.opt:238 -#, fuzzy, no-c-format -#| msgid "Warn about most implicit conversions" +#, no-c-format msgid "Warn about most implicit conversions." -msgstr "对大多数隐式类型转换给出警告" +msgstr "对大多数隐式类型转换给出警告。" #: fortran/lang.opt:242 #, fuzzy, no-c-format @@ -641,7 +628,7 @@ msgstr "可能缺少括号的情况下给出警告" #: fortran/lang.opt:250 #, no-c-format msgid "Warn if loops have been interchanged." -msgstr "当循环被互换时给出警告" +msgstr "当循环被互换时给出警告。" #: fortran/lang.opt:254 #, fuzzy, no-c-format @@ -686,7 +673,7 @@ msgstr "当格式字符串不是字面量时给出警告" #: fortran/lang.opt:298 #, no-c-format msgid "Warn that -fno-automatic may break recursion." -msgstr "当 -fno-automatic 可能破坏递归时给警告" +msgstr "当 -fno-automatic 可能破坏递归时给警告。" #: fortran/lang.opt:306 #, fuzzy, no-c-format @@ -782,7 +769,7 @@ msgstr "无论选择何种标准,所有内建过程均可用" #: fortran/lang.opt:394 #, no-c-format msgid "Allow a BOZ literal constant to appear in an invalid context and with X instead of Z." -msgstr "允许 BOZ 字面常量在无效上下文中出现,并且使用 X 代替 Z" +msgstr "允许 BOZ 字面常量在无效上下文中出现,并且使用 X 代替 Z." #: fortran/lang.opt:402 #, fuzzy, no-c-format @@ -817,7 +804,7 @@ msgstr "对为过程参数而临时创建的数组产生一个运行时警告" #: fortran/lang.opt:425 #, no-c-format msgid "-fconvert=\tThe endianness used for unformatted files." -msgstr "-fconvert=\t用于非格式化文件的字节序" +msgstr "-fconvert=\t用于非格式化文件的字节序。" #: fortran/lang.opt:450 #, fuzzy, no-c-format @@ -1045,9 +1032,9 @@ msgid "Try to interchange loops if profitable." msgstr "" #: fortran/lang.opt:619 -#, fuzzy, no-c-format +#, no-c-format msgid "Enable front end optimization." -msgstr "启用链接时优化。" +msgstr "启用前端优化。" #: fortran/lang.opt:623 #, fuzzy, no-c-format @@ -1092,7 +1079,7 @@ msgstr "-finit-real=\t初始化局部实变量" #: fortran/lang.opt:669 #, no-c-format msgid "-finline-arg-packing\tPerform argument packing inline." -msgstr "-finline-arg-packing\t内联执行参数打包" +msgstr "-finline-arg-packing\t内联执行参数打包。" #: fortran/lang.opt:673 #, fuzzy, no-c-format @@ -1158,34 +1145,34 @@ msgid "Enable range checking during compilation." msgstr "启用编译时范围检查" #: fortran/lang.opt:737 -#, fuzzy, no-c-format +#, no-c-format msgid "Interpret any REAL(4) as a REAL(8)." -msgstr "解译任何真实 (4) 作为真实 (8)" +msgstr "将所有 REAL(4) 解译为 REAL(8)。" #: fortran/lang.opt:741 -#, fuzzy, no-c-format +#, no-c-format msgid "Interpret any REAL(4) as a REAL(10)." -msgstr "解译任何真实 (4) 作为真实 (10)" +msgstr "将所有 REAL(4) 解译为 REAL(10)。" #: fortran/lang.opt:745 -#, fuzzy, no-c-format +#, no-c-format msgid "Interpret any REAL(4) as a REAL(16)." -msgstr "解译任何真实 (4) 作为真实 (16)" +msgstr "将所有 REAL(4) 解译为 REAL(16)。" #: fortran/lang.opt:749 -#, fuzzy, no-c-format +#, no-c-format msgid "Interpret any REAL(8) as a REAL(4)." -msgstr "解译任何真实 (8) 作为真实 (4)" +msgstr "将所有 REAL(8) 解译为 REAL(4)。" #: fortran/lang.opt:753 -#, fuzzy, no-c-format +#, no-c-format msgid "Interpret any REAL(8) as a REAL(10)." -msgstr "解译任何真实 (8) 作为真实 (10)" +msgstr "将所有 REAL(8) 解译为 REAL(10)。" #: fortran/lang.opt:757 -#, fuzzy, no-c-format +#, no-c-format msgid "Interpret any REAL(8) as a REAL(16)." -msgstr "解译任何真实 (8) 作为真实 (16)" +msgstr "将所有 REAL(8) 解译为 REAL(16)。" #: fortran/lang.opt:761 #, fuzzy, no-c-format @@ -1280,40 +1267,34 @@ msgid "Statically link the GCC Quad-Precision Math Library (libquadmath)." msgstr "静态链接 GNU Fortran 助手库(libgfortran)" #: fortran/lang.opt:872 -#, fuzzy, no-c-format -#| msgid "Conform to the ISO Fortran 2003 standard" +#, no-c-format msgid "Conform to the ISO Fortran 2003 standard." -msgstr "遵循 ISO Fortran 2003 标准" +msgstr "遵循 ISO Fortran 2003 标准。" #: fortran/lang.opt:876 -#, fuzzy, no-c-format -#| msgid "Conform to the ISO Fortran 2008 standard" +#, no-c-format msgid "Conform to the ISO Fortran 2008 standard." -msgstr "遵循 ISO Fortran 2008 标准" +msgstr "遵循 ISO Fortran 2008 标准。" #: fortran/lang.opt:880 -#, fuzzy, no-c-format -#| msgid "Conform to the ISO Fortran 2008 standard including TS 29113" +#, no-c-format msgid "Conform to the ISO Fortran 2008 standard including TS 29113." -msgstr "遵循 ISO Fortran 2008 标准,包括 TS 29113" +msgstr "遵循 ISO Fortran 2008 标准,包括 TS 29113." #: fortran/lang.opt:884 -#, fuzzy, no-c-format -#| msgid "Conform to the ISO Fortran 2008 standard" +#, no-c-format msgid "Conform to the ISO Fortran 2018 standard." -msgstr "遵循 ISO Fortran 2008 标准" +msgstr "遵循 ISO Fortran 2008 标准。" #: fortran/lang.opt:888 -#, fuzzy, no-c-format -#| msgid "Conform to the ISO Fortran 95 standard" +#, no-c-format msgid "Conform to the ISO Fortran 95 standard." -msgstr "遵循 ISO Fortran 95 标准" +msgstr "遵循 ISO Fortran 95 标准。" #: fortran/lang.opt:892 -#, fuzzy, no-c-format -#| msgid "Conform to nothing in particular" +#, no-c-format msgid "Conform to nothing in particular." -msgstr "不特别遵循任何标准" +msgstr "不特别遵循任何标准。" #: fortran/lang.opt:896 #, fuzzy, no-c-format @@ -1322,10 +1303,9 @@ msgid "Accept extensions to support legacy code." msgstr "接受一定的扩展以支持传统的代码" #: rust/lang.opt:47 rust/lang.opt:51 c-family/c.opt:1407 c-family/c.opt:1411 -#, fuzzy, no-c-format -#| msgid "Warn when a variable is unused" +#, no-c-format msgid "Warn when a const variable is unused." -msgstr "有未使用的变量时警告" +msgstr "有未使用的常变量时警告。" #: rust/lang.opt:55 c-family/c.opt:1399 #, fuzzy, no-c-format @@ -1396,10 +1376,9 @@ msgid "-A=\tAssert the to . Putting '-' be msgstr "-A<问题>=<答案>\t给出问题的答案。在问题前加一个‘-’将禁用其答案" #: c-family/c.opt:186 -#, fuzzy, no-c-format -#| msgid "Do not discard comments" +#, no-c-format msgid "Do not discard comments." -msgstr "不丢弃注释" +msgstr "不丢弃注释。" #: c-family/c.opt:190 #, fuzzy, no-c-format @@ -1438,16 +1417,14 @@ msgid "-I \tAdd to the end of the main include path." msgstr "-I <目录>\t将目录添加至主包含路径末尾" #: c-family/c.opt:217 -#, fuzzy, no-c-format -#| msgid "Generate make dependencies" +#, no-c-format msgid "Generate make dependencies." -msgstr "生成 make 依赖项" +msgstr "生成 make 依赖项。" #: c-family/c.opt:221 -#, fuzzy, no-c-format -#| msgid "Generate make dependencies and compile" +#, no-c-format msgid "Generate make dependencies and compile." -msgstr "生成 make 依赖规则并编译" +msgstr "生成 make 依赖规则并编译。" #: c-family/c.opt:225 #, fuzzy, no-c-format @@ -1456,34 +1433,29 @@ msgid "-MF \tWrite dependency output to the given file." msgstr "-MF <文件>\t将依赖项输出到给定文件" #: c-family/c.opt:229 -#, fuzzy, no-c-format -#| msgid "Treat missing header files as generated files" +#, no-c-format msgid "Treat missing header files as generated files." -msgstr "将缺失的头文件看作生成的文件" +msgstr "将缺失的头文件视为生成的文件。" #: c-family/c.opt:233 -#, fuzzy, no-c-format -#| msgid "Like -M but ignore system header files" +#, no-c-format msgid "Like -M but ignore system header files." -msgstr "与 -M 类似但是忽略系统头文件" +msgstr "与 -M 类似,但是忽略系统头文件。" #: c-family/c.opt:237 -#, fuzzy, no-c-format -#| msgid "Like -MD but ignore system header files" +#, no-c-format msgid "Like -MD but ignore system header files." -msgstr "与 -MD 类似但是忽略系统头文件" +msgstr "与 -MD 类似,但是忽略系统头文件。" #: c-family/c.opt:241 -#, fuzzy, no-c-format -#| msgid "Generate run time type descriptor information" +#, no-c-format msgid "Generate C++ Module dependency information." -msgstr "生成运行时类型描述信息" +msgstr "生成 C++ 模块依赖信息。" #: c-family/c.opt:249 -#, fuzzy, no-c-format -#| msgid "Generate phony targets for all headers" +#, no-c-format msgid "Generate phony targets for all headers." -msgstr "为所有头文件生成伪目标" +msgstr "为所有头文件生成伪目标。" #: c-family/c.opt:253 #, fuzzy, no-c-format @@ -1717,10 +1689,9 @@ msgid "Warn about C++23 constructs in code compiled with an older standard." msgstr "" #: c-family/c.opt:483 -#, fuzzy, no-c-format -#| msgid "Warn about casting functions to incompatible types" +#, no-c-format msgid "Warn about casts between incompatible function types." -msgstr "当把函数转换为不兼容类型时给出警告" +msgstr "当把函数转换为不兼容类型时给出警告。" #: c-family/c.opt:487 #, fuzzy, no-c-format @@ -1753,10 +1724,9 @@ msgstr "当下标类型为“char”时给出警告" #: c-family/c.opt:1620 c-family/c.opt:1624 c-family/c.opt:1628 #: c-family/c.opt:1632 c-family/c.opt:1636 c-family/c.opt:1640 #: config/i386/i386.opt:999 -#, fuzzy, no-c-format -#| msgid "Deprecated. This switch has no effect" +#, no-c-format msgid "Removed in GCC 9. This switch has no effect." -msgstr "已弃用。此开关不起作用。" +msgstr "已在 GCC 9 被移除。此开关不起作用。" #: c-family/c.opt:511 #, fuzzy, no-c-format @@ -2479,10 +2449,9 @@ msgid "Warn if a class interface has no superclass. Root classes may use an att msgstr "" #: c-family/c.opt:1127 -#, fuzzy, no-c-format -#| msgid "Warn if a C-style cast is used in a program" +#, no-c-format msgid "Warn if a C-style cast is used in a program." -msgstr "程序使用 C 风格的类型转换时给出警告" +msgstr "程序使用 C 风格的类型转换时给出警告。" #: c-family/c.opt:1131 #, fuzzy, no-c-format @@ -2875,12 +2844,12 @@ msgstr "" #: c-family/c.opt:1477 #, no-c-format msgid "Warn when a literal '0' is used as null pointer." -msgstr "在字面“0”被用作空指针时给出警告" +msgstr "在字面“0”被用作空指针时给出警告。" #: c-family/c.opt:1481 #, no-c-format msgid "Warn about useless casts." -msgstr "对无用的类型转换给出警告" +msgstr "对无用的类型转换给出警告。" #: c-family/c.opt:1485 #, no-c-format @@ -3210,7 +3179,7 @@ msgstr "除非必需,不生成 DLL 导出的内联函数" #: c-family/c.opt:1880 #, no-c-format msgid "Allow implicit conversions between vectors with differing numbers of subparts and/or differing element types." -msgstr "允许具有不同元素数量和/或元素类型的向量间的转换" +msgstr "允许具有不同元素数量和/或元素类型的向量间的转换。" #: c-family/c.opt:1884 #, no-c-format @@ -5772,7 +5741,7 @@ msgstr "为避免硬件失常,在 CSYNC 或 SSYNC 指令前添加一些 NOP #: config/bfin/bfin.opt:61 #, no-c-format msgid "Avoid speculative loads to work around a hardware anomaly." -msgstr "禁用投机载入以避免一个硬件异常" +msgstr "禁用投机载入以避免一个硬件异常。" #: config/bfin/bfin.opt:65 #, fuzzy, no-c-format @@ -7650,7 +7619,7 @@ msgstr "控制产生的倒数估计。" #: config/i386/i386.opt:590 #, no-c-format msgid "Generate cld instruction in the function prologue." -msgstr "在函数序言中生成 cld 指令" +msgstr "在函数序言中生成 cld 指令。" #: config/i386/i386.opt:594 #, fuzzy, no-c-format @@ -7675,7 +7644,7 @@ msgstr "进行海法调度,当处理器是 bdver1 时也进行派遣调度" #: config/i386/i386.opt:613 #, no-c-format msgid "Use 128-bit AVX instructions instead of 256-bit AVX instructions in the auto-vectorizer." -msgstr "自动向量化时使用 128 位 AVX 指令而不是 256 位 AVX 指令" +msgstr "自动向量化时使用 128 位 AVX 指令而不是 256 位 AVX 指令。" #: config/i386/i386.opt:617 #, fuzzy, no-c-format @@ -7777,7 +7746,7 @@ msgstr "支持 MMX、SSE、SSE2、SSE3、SSSE3、SSE4.1、SSE4.2 和 AVX 内建 #: config/i386/i386.opt:715 #, no-c-format msgid "Support MMX, SSE, SSE2, SSE3, SSSE3, SSE4.1, SSE4.2, AVX and AVX2 built-in functions and code generation." -msgstr "支持 MMX、SSE、SSE2、SSE3、SSSE3、SSE4.1、SSE4.2、AVX 和 AVX2 内建函数及代码生成" +msgstr "支持 MMX、SSE、SSE2、SSE3、SSSE3、SSE4.1、SSE4.2、AVX 和 AVX2 内建函数及代码生成。" #: config/i386/i386.opt:719 #, no-c-format @@ -7787,12 +7756,12 @@ msgstr "支持 MMX、SSE、SSE2、SSE3、SSSE3、SSE4.1、SSE4.2、AVX、AVX2 #: config/i386/i386.opt:723 #, no-c-format msgid "Support MMX, SSE, SSE2, SSE3, SSSE3, SSE4.1, SSE4.2, AVX, AVX2 and AVX512F and AVX512PF built-in functions and code generation." -msgstr "支持 MMX、SSE、SSE2、SSE3、SSSE3、SSE4.1、SSE4.2、AVX、AVX2、AVX512F 和 AVX512PF 内建函数及代码生成" +msgstr "支持 MMX、SSE、SSE2、SSE3、SSSE3、SSE4.1、SSE4.2、AVX、AVX2、AVX512F 和 AVX512PF 内建函数及代码生成。" #: config/i386/i386.opt:727 #, no-c-format msgid "Support MMX, SSE, SSE2, SSE3, SSSE3, SSE4.1, SSE4.2, AVX, AVX2 and AVX512F and AVX512ER built-in functions and code generation." -msgstr "支持 MMX、SSE、SSE2、SSE3、SSSE3、SSE4.1、SSE4.2、AVX、AVX2、AVX512F 和 AVX512ER 内建函数及代码生成" +msgstr "支持 MMX、SSE、SSE2、SSE3、SSSE3、SSE4.1、SSE4.2、AVX、AVX2、AVX512F 和 AVX512ER 内建函数及代码生成。" #: config/i386/i386.opt:731 #, no-c-format @@ -7958,7 +7927,7 @@ msgstr "支持 PCLMUL 内建函数及代码生成。" #: config/i386/i386.opt:847 #, no-c-format msgid "Support BMI built-in functions and code generation." -msgstr "支持 BMI 内建函数及代码生成" +msgstr "支持 BMI 内建函数及代码生成。" #: config/i386/i386.opt:851 #, no-c-format @@ -9758,7 +9727,7 @@ msgstr "开启调试输出" #: config/sparc/sparc.opt:254 #, no-c-format msgid "Enable strict 32-bit psABI struct return checking." -msgstr "启用严格的 32 位 psABI 结构返回检查" +msgstr "启用严格的 32 位 psABI 结构返回检查。" #: config/sparc/sparc.opt:258 #, fuzzy, no-c-format @@ -11631,7 +11600,7 @@ msgstr "" #: config/rx/elf.opt:38 config/rx/rx.opt:99 #, no-c-format msgid "Specifies the number of registers to reserve for interrupt handlers." -msgstr "指定保留给中断处理函数使用的寄存器的数量" +msgstr "指定保留给中断处理函数使用的寄存器的数量。" #: config/rx/elf.opt:44 config/rx/rx.opt:105 #, no-c-format @@ -11662,7 +11631,7 @@ msgstr "启用使用 RX FPU 指令。这是默认值。" #: config/rx/rx.opt:50 #, no-c-format msgid "Specify the target RX cpu type." -msgstr "选择目标 RX CPU 的类型" +msgstr "指定目标 RX CPU 的类型。" #: config/rx/rx.opt:71 #, no-c-format @@ -12915,7 +12884,7 @@ msgstr "为缺少 MMU 和 FPU 的 SH4 400 系列生成代码" #: config/sh/sh.opt:122 #, no-c-format msgid "Generate code for SH4 500 series (FPU-less)." -msgstr "为缺少 FPU 的 SH4 500 系列生成代码" +msgstr "为缺少 FPU 的 SH4 500 系列生成代码。" #: config/sh/sh.opt:127 #, fuzzy, no-c-format @@ -15236,7 +15205,7 @@ msgstr "在调试转储中不输出前一条和后一条指令号码" #: common.opt:1559 #, no-c-format msgid "Enable CFI tables via GAS assembler directives." -msgstr "用 GAS 汇编指示来启用 CFI 表" +msgstr "用 GAS 汇编指示来启用 CFI 表。" #: common.opt:1563 #, fuzzy, no-c-format @@ -16639,7 +16608,7 @@ msgstr "将条件存储转换为非条件存储" #: common.opt:2922 #, no-c-format msgid "Perform conversions of switch initializations." -msgstr "转换开关初始化" +msgstr "转换开关初始化。" #: common.opt:2926 #, fuzzy, no-c-format @@ -18413,7 +18382,7 @@ msgstr "" #: params.opt:950 #, no-c-format msgid "The minimal probability of speculation success (in percents), so that speculative insn will be scheduled." -msgstr "以百分比表示的投机成功的最小概率,影响对投机指令的调度" +msgstr "以百分比表示的投机成功的最小概率,影响对投机指令的调度。" #: params.opt:954 #, no-c-format @@ -20615,8 +20584,7 @@ msgstr "使用‘%%&’ 时没有指定任何动态 TLS 引用" msgid "invalid %%J value" msgstr "无效 %%J 值" -#: config/alpha/alpha.cc:5169 config/ia64/ia64.cc:5578 -#: config/or1k/or1k.cc:1249 +#: config/alpha/alpha.cc:5169 config/ia64/ia64.cc:5578 config/or1k/or1k.cc:1249 #, c-format msgid "invalid %%r value" msgstr "无效 %%r 值" @@ -20801,8 +20769,7 @@ msgstr "代码‘%c’的操作数无效" #: config/arm/arm.cc:24675 config/arm/arm.cc:24702 config/arm/arm.cc:24709 #: config/bfin/bfin.cc:1441 config/bfin/bfin.cc:1448 config/bfin/bfin.cc:1455 #: config/bfin/bfin.cc:1462 config/bfin/bfin.cc:1471 config/bfin/bfin.cc:1478 -#: config/bfin/bfin.cc:1485 config/bfin/bfin.cc:1492 -#: config/nds32/nds32.cc:3546 +#: config/bfin/bfin.cc:1485 config/bfin/bfin.cc:1492 config/nds32/nds32.cc:3546 #, c-format msgid "invalid operand for code '%c'" msgstr "代码‘%c’的操作数无效" @@ -22097,9 +22064,9 @@ msgstr "({匿名})" #: c/c-parser.cc:20351 c/gimple-parser.cc:406 c/gimple-parser.cc:447 #: c/gimple-parser.cc:456 c/gimple-parser.cc:665 c/gimple-parser.cc:2261 #: c/gimple-parser.cc:2298 c/gimple-parser.cc:2377 c/gimple-parser.cc:2404 -#: c/c-parser.cc:3671 c/c-parser.cc:3861 c/c-parser.cc:3896 -#: c/c-parser.cc:12051 c/gimple-parser.cc:2069 c/gimple-parser.cc:2126 -#: cp/parser.cc:15350 cp/parser.cc:33084 cp/parser.cc:33720 +#: c/c-parser.cc:3671 c/c-parser.cc:3861 c/c-parser.cc:3896 c/c-parser.cc:12051 +#: c/gimple-parser.cc:2069 c/gimple-parser.cc:2126 cp/parser.cc:15350 +#: cp/parser.cc:33084 cp/parser.cc:33720 #, gcc-internal-format msgid "expected %<;%>" msgstr "需要%<;%>" @@ -22151,8 +22118,8 @@ msgstr "需要 %<;%>、%<,%> 或 %<)%>" msgid "expected %<(%>" msgstr "需要%<(%>" -#: c/c-parser.cc:5444 c/c-parser.cc:5446 c/c-parser.cc:13856 -#: cp/parser.cc:33735 cp/parser.cc:37503 go/gofrontend/embed.cc:439 +#: c/c-parser.cc:5444 c/c-parser.cc:5446 c/c-parser.cc:13856 cp/parser.cc:33735 +#: cp/parser.cc:37503 go/gofrontend/embed.cc:439 #, gcc-internal-format msgid "expected %<[%>" msgstr "需要%<[%>" @@ -22160,8 +22127,8 @@ msgstr "需要%<[%>" #: c/c-parser.cc:6099 c/c-parser.cc:12394 c/c-parser.cc:19377 #: c/c-parser.cc:19463 c/c-parser.cc:20121 c/c-parser.cc:20993 #: c/c-parser.cc:24656 c/gimple-parser.cc:399 c/gimple-parser.cc:2337 -#: c/c-parser.cc:3658 c/c-parser.cc:3885 c/c-parser.cc:11946 -#: cp/parser.cc:21039 cp/parser.cc:33729 go/gofrontend/embed.cc:370 +#: c/c-parser.cc:3658 c/c-parser.cc:3885 c/c-parser.cc:11946 cp/parser.cc:21039 +#: cp/parser.cc:33729 go/gofrontend/embed.cc:370 #, gcc-internal-format msgid "expected %<{%>" msgstr "需要%<{%>" @@ -24658,27 +24625,26 @@ msgstr "类型属性在定义后被忽略" #: c-family/c-attribs.cc:5812 c-family/c-common.cc:6056 #: c-family/c-common.cc:6059 config/darwin.cc:2143 config/arm/arm.cc:7444 #: config/arm/arm.cc:7472 config/arm/arm.cc:7489 config/avr/avr.cc:10158 -#: config/csky/csky.cc:6498 config/csky/csky.cc:6520 -#: config/h8300/h8300.cc:4968 config/h8300/h8300.cc:4992 -#: config/i386/i386-options.cc:3434 config/i386/i386-options.cc:3592 -#: config/i386/i386-options.cc:3824 config/i386/i386-options.cc:3854 -#: config/ia64/ia64.cc:785 config/loongarch/loongarch.cc:6539 -#: config/rs6000/rs6000.cc:20476 ada/gcc-interface/utils.cc:6588 -#: ada/gcc-interface/utils.cc:6604 ada/gcc-interface/utils.cc:6642 -#: ada/gcc-interface/utils.cc:6659 ada/gcc-interface/utils.cc:6676 -#: ada/gcc-interface/utils.cc:6691 ada/gcc-interface/utils.cc:6707 -#: ada/gcc-interface/utils.cc:6733 ada/gcc-interface/utils.cc:6802 -#: ada/gcc-interface/utils.cc:6829 ada/gcc-interface/utils.cc:6850 -#: ada/gcc-interface/utils.cc:6871 ada/gcc-interface/utils.cc:6919 -#: ada/gcc-interface/utils.cc:6935 ada/gcc-interface/utils.cc:6990 -#: c/c-decl.cc:4788 c/c-decl.cc:4791 c/c-decl.cc:4806 c/c-parser.cc:5433 -#: cp/tree.cc:5032 d/d-attribs.cc:480 d/d-attribs.cc:699 d/d-attribs.cc:720 -#: d/d-attribs.cc:736 d/d-attribs.cc:753 d/d-attribs.cc:785 d/d-attribs.cc:914 -#: d/d-attribs.cc:973 d/d-attribs.cc:989 d/d-attribs.cc:1005 -#: d/d-attribs.cc:1154 d/d-attribs.cc:1167 d/d-attribs.cc:1384 -#: d/d-attribs.cc:1402 d/d-attribs.cc:1449 d/d-attribs.cc:1487 -#: d/d-attribs.cc:1503 d/d-attribs.cc:1560 d/d-attribs.cc:1588 -#: jit/dummy-frontend.cc:185 lto/lto-lang.cc:288 +#: config/csky/csky.cc:6498 config/csky/csky.cc:6520 config/h8300/h8300.cc:4968 +#: config/h8300/h8300.cc:4992 config/i386/i386-options.cc:3434 +#: config/i386/i386-options.cc:3592 config/i386/i386-options.cc:3824 +#: config/i386/i386-options.cc:3854 config/ia64/ia64.cc:785 +#: config/loongarch/loongarch.cc:6539 config/rs6000/rs6000.cc:20476 +#: ada/gcc-interface/utils.cc:6588 ada/gcc-interface/utils.cc:6604 +#: ada/gcc-interface/utils.cc:6642 ada/gcc-interface/utils.cc:6659 +#: ada/gcc-interface/utils.cc:6676 ada/gcc-interface/utils.cc:6691 +#: ada/gcc-interface/utils.cc:6707 ada/gcc-interface/utils.cc:6733 +#: ada/gcc-interface/utils.cc:6802 ada/gcc-interface/utils.cc:6829 +#: ada/gcc-interface/utils.cc:6850 ada/gcc-interface/utils.cc:6871 +#: ada/gcc-interface/utils.cc:6919 ada/gcc-interface/utils.cc:6935 +#: ada/gcc-interface/utils.cc:6990 c/c-decl.cc:4788 c/c-decl.cc:4791 +#: c/c-decl.cc:4806 c/c-parser.cc:5433 cp/tree.cc:5032 d/d-attribs.cc:480 +#: d/d-attribs.cc:699 d/d-attribs.cc:720 d/d-attribs.cc:736 d/d-attribs.cc:753 +#: d/d-attribs.cc:785 d/d-attribs.cc:914 d/d-attribs.cc:973 d/d-attribs.cc:989 +#: d/d-attribs.cc:1005 d/d-attribs.cc:1154 d/d-attribs.cc:1167 +#: d/d-attribs.cc:1384 d/d-attribs.cc:1402 d/d-attribs.cc:1449 +#: d/d-attribs.cc:1487 d/d-attribs.cc:1503 d/d-attribs.cc:1560 +#: d/d-attribs.cc:1588 jit/dummy-frontend.cc:185 lto/lto-lang.cc:288 #, gcc-internal-format msgid "%qE attribute ignored" msgstr "%qE属性被忽略" @@ -26135,7 +26101,7 @@ msgstr "无法获取程序状态:%s" #: collect-utils.cc:120 #, gcc-internal-format, gfc-internal-format msgid "%s terminated with signal %d [%s]%s" -msgstr "%s 以信号 %d [%s]%s 退出。" +msgstr "%s 以信号 %d [%s]%s 退出" #: collect-utils.cc:136 #, gcc-internal-format, gfc-internal-format @@ -26731,7 +26697,7 @@ msgstr "在比较周围组合变量时假定有符号数从不溢出" #: fold-const.cc:13568 #, gcc-internal-format msgid "fold check: original tree changed by fold" -msgstr "折叠检查: 原始树因折叠而改变 " +msgstr "折叠检查: 原始树因折叠而改变" #: function.cc:253 #, fuzzy, gcc-internal-format @@ -34471,8 +34437,7 @@ msgstr "线程局部的 COMMON 数据没有实现" msgid "requested alignment for %q+D is greater than implemented alignment of %wu" msgstr "%q+D需要的对齐边界大于实现的对齐边界 %wu" -#: varasm.cc:2304 c/c-decl.cc:5725 c/c-parser.cc:1789 -#: m2/gm2-gcc/m2type.cc:1259 +#: varasm.cc:2304 c/c-decl.cc:5725 c/c-parser.cc:1789 m2/gm2-gcc/m2type.cc:1259 #, gcc-internal-format msgid "storage size of %q+D isn%'t known" msgstr "%q+D的存储大小未知" @@ -34892,9 +34857,8 @@ msgstr "%qE属性需要一个字符串常量作为实参" msgid "section attribute cannot be specified for local variables" msgstr "不能为局部变量指定节属性" -#: c-family/c-attribs.cc:2284 config/bfin/bfin.cc:4796 -#: config/bfin/bfin.cc:4847 config/bfin/bfin.cc:4873 config/bfin/bfin.cc:4886 -#: d/d-attribs.cc:1055 +#: c-family/c-attribs.cc:2284 config/bfin/bfin.cc:4796 config/bfin/bfin.cc:4847 +#: config/bfin/bfin.cc:4873 config/bfin/bfin.cc:4886 d/d-attribs.cc:1055 #, gcc-internal-format msgid "section of %q+D conflicts with previous declaration" msgstr "%q+D的节与早先的声明冲突" @@ -38904,8 +38868,7 @@ msgstr "-malign-functions=%d 不在 0 和 %d 之间" msgid "%<-mbranch-cost=%d%> is not between 0 and 5" msgstr "%sbranch-cost=%d%s不在 0 和 5 之间" -#: common/config/i386/i386-common.cc:1873 -#: common/config/s390/s390-common.cc:137 +#: common/config/i386/i386-common.cc:1873 common/config/s390/s390-common.cc:137 #, gcc-internal-format msgid "%<-fsplit-stack%> currently only supported on GNU/Linux" msgstr "%<-fsplit-stack%>只在 GNU/Linux 下被支持" @@ -40239,8 +40202,8 @@ msgstr "L%d 缓存延迟未知,对 %s 来说" msgid "bad value %qs for %<-mmemory-latency%>" msgstr "-mmemory-latency 开关的值%qs错误" -#: config/alpha/alpha.cc:6657 config/alpha/alpha.cc:6660 -#: config/arc/arc.cc:7099 config/arc/arc.cc:7373 config/s390/s390.cc:949 +#: config/alpha/alpha.cc:6657 config/alpha/alpha.cc:6660 config/arc/arc.cc:7099 +#: config/arc/arc.cc:7373 config/s390/s390.cc:949 #, gcc-internal-format msgid "bad builtin fcode" msgstr "错误的内建 fcode" @@ -43254,14 +43217,12 @@ msgstr "%qs属性只能应用于函数" msgid "%qE cannot have both %qs and %qs attributes" msgstr "%qE不能同时有%和%属性" -#: config/mips/mips.cc:1475 config/mips/mips.cc:1481 -#: config/nios2/nios2.cc:4487 +#: config/mips/mips.cc:1475 config/mips/mips.cc:1481 config/nios2/nios2.cc:4487 #, gcc-internal-format msgid "%qE redeclared with conflicting %qs attributes" msgstr "%qE重声明有冲突的属性%qs" -#: config/mips/mips.cc:1513 config/mips/mips.cc:1567 -#: config/riscv/riscv.cc:4022 +#: config/mips/mips.cc:1513 config/mips/mips.cc:1567 config/riscv/riscv.cc:4022 #, fuzzy, gcc-internal-format #| msgid "%qE attribute requires a string constant argument" msgid "%qE attribute requires a string argument" @@ -45355,7 +45316,7 @@ msgstr "%qE属性的实参不是一个字符串常量" #: config/s390/s390.cc:10240 #, gcc-internal-format msgid "total size of local variables exceeds architecture limit" -msgstr "局部变量大小总和超过架构极限。" +msgstr "局部变量大小总和超过架构极限" #: config/s390/s390.cc:11647 #, fuzzy, gcc-internal-format @@ -47970,8 +47931,8 @@ msgstr "需要行尾" msgid "ISO C forbids an empty translation unit" msgstr "ISO C 不允许翻译单元为空" -#: c/c-parser.cc:1796 c/c-parser.cc:1805 c/c-parser.cc:23171 -#: cp/parser.cc:47460 cp/semantics.cc:3400 cp/semantics.cc:3409 +#: c/c-parser.cc:1796 c/c-parser.cc:1805 c/c-parser.cc:23171 cp/parser.cc:47460 +#: cp/semantics.cc:3400 cp/semantics.cc:3409 #, gcc-internal-format msgid "%qs without corresponding %qs" msgstr "" @@ -49361,8 +49322,7 @@ msgstr "%H折叠变量需要正整常数表达式" msgid "% modifier incompatible with %qs" msgstr "%qs必须与%qs一起使用" -#: c/c-parser.cc:16994 cp/parser.cc:40371 cp/parser.cc:40760 -#: cp/parser.cc:40810 +#: c/c-parser.cc:16994 cp/parser.cc:40371 cp/parser.cc:40760 cp/parser.cc:40810 #, fuzzy, gcc-internal-format msgid "invalid depend kind" msgstr "无效的调度类型" @@ -49634,8 +49594,8 @@ msgstr "联合定义后需要%<;%>" msgid "expected %<==%>, %<<%> or %<>%> comparison in % condition" msgstr "" -#: c/c-parser.cc:19446 cp/parser.cc:42128 cp/parser.cc:42411 -#: cp/parser.cc:42505 cp/parser.cc:42523 +#: c/c-parser.cc:19446 cp/parser.cc:42128 cp/parser.cc:42411 cp/parser.cc:42505 +#: cp/parser.cc:42523 #, fuzzy, gcc-internal-format msgid "invalid form of %<#pragma omp atomic compare%>" msgstr "%<#pragma omp atomic%>运算符无效" @@ -50583,7 +50543,7 @@ msgstr "要求全局寄存器变量%qD的地址" #: c/c-typeck.cc:5233 d/d-codegen.cc:721 #, gcc-internal-format msgid "address of register variable %qD requested" -msgstr "要求寄存器变量%qD的地址。" +msgstr "要求寄存器变量 %qD 的地址" #: c/c-typeck.cc:5372 #, gcc-internal-format @@ -51224,8 +51184,7 @@ msgstr "初始值设定项末尾有多余的花括号组" msgid "braces around scalar initializer" msgstr "标量初始化带花括号" -#: c/c-typeck.cc:9291 c/c-typeck.cc:10775 cp/typeck2.cc:1242 -#: cp/typeck2.cc:1600 +#: c/c-typeck.cc:9291 c/c-typeck.cc:10775 cp/typeck2.cc:1242 cp/typeck2.cc:1600 #, gcc-internal-format msgid "initialization of flexible array member in a nested context" msgstr "在嵌套的上下文中初始化可变数组成员" @@ -53212,7 +53171,7 @@ msgstr "备选 2: %q+#F" #: cp/call.cc:13226 #, gcc-internal-format msgid "ISO C++ says that these are ambiguous, even though the worst conversion for the first is better than the worst conversion for the second:" -msgstr "ISO C++ 认为有歧义,尽管第一个备选的最差类型转换要好于第二个备选的最差类型转换" +msgstr "ISO C++ 认为有歧义,尽管第一个备选的最差类型转换要好于第二个备选的最差类型转换:" #: cp/call.cc:13627 #, fuzzy, gcc-internal-format @@ -54201,8 +54160,8 @@ msgstr "成员%qD是未初始化的引用" msgid "%qs cannot be constant evaluated because the argument cannot be interpreted" msgstr "" -#: cp/constexpr.cc:5632 cp/constexpr.cc:7723 -#: rust/backend/rust-constexpr.cc:872 rust/backend/rust-constexpr.cc:2492 +#: cp/constexpr.cc:5632 cp/constexpr.cc:7723 rust/backend/rust-constexpr.cc:872 +#: rust/backend/rust-constexpr.cc:2492 #, fuzzy, gcc-internal-format #| msgid "dereferencing % pointer" msgid "dereferencing a null pointer" @@ -82565,9 +82524,9 @@ msgid "The base procedure at %L must have an explicit interface" msgstr "%3$L处 %2$s 中的过程‘%1$s’没有显式接口" #: fortran/trans-openmp.cc:8043 -#, fuzzy, gcc-internal-format +#, gcc-internal-format msgid "Cannot find symbol %qs" -msgstr "在类%qs中找不到可溢出的寄存器" +msgstr "无法找到符号 %qs" #: fortran/trans-openmp.cc:8054 #, fuzzy, gcc-internal-format @@ -82679,7 +82638,7 @@ msgstr "gfc_trans_code():错误的语句代码" #: go/gofrontend/embed.cc:278 #, gcc-internal-format msgid "invalid embedcfg: not a JSON object" -msgstr "" +msgstr "无效的 embedcfg:不是 JSON 对象" #: go/gofrontend/embed.cc:285 #, fuzzy, gcc-internal-format @@ -82695,7 +82654,7 @@ msgstr "" #: go/gofrontend/embed.cc:297 #, gcc-internal-format msgid "invalid embedcfg: missing Files" -msgstr "" +msgstr "无效的 embedcfg:缺失文件" #: go/gofrontend/embed.cc:302 #, gcc-internal-format @@ -82766,8 +82725,7 @@ msgid "extraneous data at end of file" msgstr "初始值设定项末尾有多余的花括号组" #: go/gofrontend/embed.cc:645 -#, fuzzy, gcc-internal-format -#| msgid "Unexpected EOF" +#, gcc-internal-format msgid "unexpected EOF" msgstr "非预期的文件结束" @@ -83496,9 +83454,9 @@ msgid "nullability specifier %qE cannot be applied to multi-level pointer type % msgstr "" #: objc/objc-act.cc:1778 -#, fuzzy, gcc-internal-format +#, gcc-internal-format msgid "the dot syntax is not available in Objective-C 1.0" -msgstr "%<@synthesize%> 在 Objective-C 1.0 里不可用" +msgstr "点语法在 Objective-C 1.0 中不可用" #. We know that 'class_name' is an Objective-C class name as the #. parser won't call this function if it is not. This is only a @@ -83515,15 +83473,14 @@ msgid "could not find interface for class %qE" msgstr "找不到类%qE的接口" #: objc/objc-act.cc:1808 objc/objc-act.cc:7144 -#, fuzzy, gcc-internal-format -#| msgid "%qD is not a variable" +#, gcc-internal-format msgid "class %qE is unavailable" -msgstr "%qD不是一个变量" +msgstr "类 %qE 不可用" #: objc/objc-act.cc:1810 objc/objc-act.cc:7001 objc/objc-act.cc:7146 #, gcc-internal-format msgid "class %qE is deprecated" -msgstr "已弃用类%qE" +msgstr "已弃用类 %qE" #: objc/objc-act.cc:1839 #, gcc-internal-format @@ -84001,15 +83958,14 @@ msgid "cannot find interface declaration for %qE, superclass of %qE" msgstr "找不到%2$qE超类%1$qE的接口声明" #: objc/objc-act.cc:6999 -#, fuzzy, gcc-internal-format -#| msgid "%qD is not a variable" +#, gcc-internal-format msgid "class %qE is not available" -msgstr "%qD不是一个变量" +msgstr "类 %qE 不可用" #: objc/objc-act.cc:7032 #, gcc-internal-format msgid "reimplementation of class %qE" -msgstr "类%qE的重新实现" +msgstr "类 %qE 的重新实现" #: objc/objc-act.cc:7065 #, gcc-internal-format @@ -84137,10 +84093,9 @@ msgid "definition of protocol %qE not found" msgstr "找不到协议%qE的方法定义" #: objc/objc-act.cc:8272 -#, fuzzy, gcc-internal-format -#| msgid "protocol %qE is deprecated" +#, gcc-internal-format msgid "protocol %qE is unavailable" -msgstr "已弃用协议%qE" +msgstr "协议 %qE 不可用" #. It would be nice to use warn_deprecated_use() here, but #. we are using TREE_CHAIN (which is supposed to be the -- cgit v1.1 From d49780c08aade447953bfe4e877d386f5757f165 Mon Sep 17 00:00:00 2001 From: Jason Merrill Date: Mon, 5 Feb 2024 15:59:45 -0500 Subject: c++: -frounding-math test [PR109359] This test was fixed by the patch for PR95226, but that patch had no testcase so let's add this one. PR c++/109359 gcc/testsuite/ChangeLog: * g++.dg/ext/frounding-math1.C: New test. --- gcc/testsuite/g++.dg/ext/frounding-math1.C | 8 ++++++++ 1 file changed, 8 insertions(+) create mode 100644 gcc/testsuite/g++.dg/ext/frounding-math1.C (limited to 'gcc') diff --git a/gcc/testsuite/g++.dg/ext/frounding-math1.C b/gcc/testsuite/g++.dg/ext/frounding-math1.C new file mode 100644 index 0000000..ecc46fd --- /dev/null +++ b/gcc/testsuite/g++.dg/ext/frounding-math1.C @@ -0,0 +1,8 @@ +// PR c++/109359 +// { dg-additional-options -frounding-math } + +// For a while we were emitting two doubles (4 .long directives) as the value +// of a float array; it should only be two .longs. + +// { dg-final { scan-assembler-times "long" 2 { target x86_64-*-* } } } +float xs[] = {0.001914, 0.630539}; -- cgit v1.1 From 184978cd74f962712e813030d58edc109ad9a92d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christoph=20M=C3=BCllner?= Date: Mon, 5 Feb 2024 12:52:23 +0100 Subject: riscv: Fix compiler warning in thead.cc MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit A recent commit introduced a compiler warning in thead.cc: error: invalid suffix on literal; C++11 requires a space between literal and string macro [-Werror=literal-suffix] 1144 | fprintf (file, "(%s),"HOST_WIDE_INT_PRINT_DEC",%u", reg_names[REGNO (addr.reg)], | ^ This commit addresses this issue and breaks the line such that it won't exceed 80 characters. gcc/ChangeLog: * config/riscv/thead.cc (th_print_operand_address): Fix compiler warning. Signed-off-by: Christoph Müllner --- gcc/config/riscv/thead.cc | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'gcc') diff --git a/gcc/config/riscv/thead.cc b/gcc/config/riscv/thead.cc index e4b8c37..951b608 100644 --- a/gcc/config/riscv/thead.cc +++ b/gcc/config/riscv/thead.cc @@ -1141,7 +1141,8 @@ th_print_operand_address (FILE *file, machine_mode mode, rtx x) return true; case ADDRESS_REG_WB: - fprintf (file, "(%s),"HOST_WIDE_INT_PRINT_DEC",%u", reg_names[REGNO (addr.reg)], + fprintf (file, "(%s)," HOST_WIDE_INT_PRINT_DEC ",%u", + reg_names[REGNO (addr.reg)], INTVAL (addr.offset) >> addr.shift, addr.shift); return true; -- cgit v1.1 From 1c9ddaae92f203a8f39976f754ca1b02c3b9fb56 Mon Sep 17 00:00:00 2001 From: GCC Administrator Date: Tue, 6 Feb 2024 00:18:46 +0000 Subject: Daily bump. --- gcc/ChangeLog | 80 +++++++++++++++++++++++++++++++++++++++++++++++++ gcc/DATESTAMP | 2 +- gcc/c/ChangeLog | 7 +++++ gcc/cp/ChangeLog | 5 ++++ gcc/po/ChangeLog | 4 +++ gcc/testsuite/ChangeLog | 47 +++++++++++++++++++++++++++++ 6 files changed, 144 insertions(+), 1 deletion(-) (limited to 'gcc') diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 4cbc90d..0e3ac48 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,83 @@ +2024-02-05 Christoph Müllner + + * config/riscv/thead.cc (th_print_operand_address): Fix compiler + warning. + +2024-02-05 H.J. Lu + + PR target/113689 + * config/i386/i386.cc (x86_64_select_profile_regnum): New. + (x86_function_profiler): Call x86_64_select_profile_regnum to + get a scratch register for large model profiling. + +2024-02-05 Richard Ball + + * config/arm/arm.cc (arm_output_mi_thunk): Emit + insn for bti_c when bti is enabled. + +2024-02-05 Xi Ruoyao + + * config/mips/mips-msa.md (neg2): Add missing mode for + neg. + +2024-02-05 Xi Ruoyao + + * config/mips/mips-msa.md (elmsgnbit): New define_mode_attr. + (neg2): Change the mode iterator from MSA to IMSA because + in FP arithmetic we cannot use (0 - x) for -x. + (neg2): New define_insn to implement FP vector negation, + using a bnegi instruction to negate the sign bit. + +2024-02-05 Richard Biener + + PR tree-optimization/113707 + * tree-ssa-sccvn.cc (rpo_elim::eliminate_avail): After + checking the avail set treat out-of-region defines as + available. + +2024-02-05 Richard Biener + + * tree-vect-data-refs.cc (vect_create_data_ref_ptr): Use + the default mode when building a pointer. + +2024-02-05 Jakub Jelinek + + PR tree-optimization/113737 + * gimple-lower-bitint.cc (gimple_lower_bitint): If GIMPLE_SWITCH + has just a single label, remove it and make single successor edge + EDGE_FALLTHRU. + +2024-02-05 Jakub Jelinek + + PR target/113059 + * config/i386/i386-features.cc (rest_of_handle_insert_vzeroupper): + Remove REG_DEAD/REG_UNUSED notes at the end of the pass before + df_analyze call. + +2024-02-05 Richard Biener + + PR target/113255 + * config/i386/i386-expand.cc + (expand_set_or_cpymem_prologue_epilogue_by_misaligned_moves): + Use a new pseudo for the skipped number of bytes. + +2024-02-05 Monk Chiang + + * config/riscv/riscv-cores.def: Add sifive-p450, sifive-p670. + * doc/invoke.texi (RISC-V Options): Add sifive-p450, + sifive-p670. + +2024-02-05 Monk Chiang + + * config/riscv/riscv.md: Include sifive-p400.md. + * config/riscv/sifive-p400.md: New file. + * config/riscv/riscv-cores.def (RISCV_TUNE): Add parameter. + * config/riscv/riscv-opts.h (enum riscv_microarchitecture_type): + Add sifive_p400. + * config/riscv/riscv.cc (sifive_p400_tune_info): New. + * config/riscv/riscv.h (TARGET_SFB_ALU): Update. + * doc/invoke.texi (RISC-V Options): Add sifive-p400-series + 2024-02-04 Takayuki 'January June' Suwa * config/xtensa/xtensa.md (*eqne_zero_masked_bits): diff --git a/gcc/DATESTAMP b/gcc/DATESTAMP index a53d85f..14a359f 100644 --- a/gcc/DATESTAMP +++ b/gcc/DATESTAMP @@ -1 +1 @@ -20240205 +20240206 diff --git a/gcc/c/ChangeLog b/gcc/c/ChangeLog index eb3e02c..002bf41 100644 --- a/gcc/c/ChangeLog +++ b/gcc/c/ChangeLog @@ -1,3 +1,10 @@ +2024-02-05 Jakub Jelinek + + PR c/113740 + * c-decl.cc (finish_struct): Only use build_bitint_type if + bit-field has width larger or equal to minimum _BitInt + precision. + 2024-01-31 Joseph Myers PR c/112571 diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index f524ec6..452a70c 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,3 +1,8 @@ +2024-02-05 Jason Merrill + + PR c++/111286 + * tree.cc (rvalue): Don't drop cv-quals from an array. + 2024-02-03 Patrick Palka PR c++/110006 diff --git a/gcc/po/ChangeLog b/gcc/po/ChangeLog index a5656aa..c0ff212 100644 --- a/gcc/po/ChangeLog +++ b/gcc/po/ChangeLog @@ -1,3 +1,7 @@ +2024-02-05 Joseph Myers + + * zh_CN.po: Update. + 2023-07-31 Joseph Myers * sv.po: Update. diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index 5748a98..a824e23 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,50 @@ +2024-02-05 Jason Merrill + + PR c++/109359 + * g++.dg/ext/frounding-math1.C: New test. + +2024-02-05 Jason Merrill + + PR c++/111286 + * g++.dg/cpp0x/initlist-array22.C: New test. + +2024-02-05 H.J. Lu + + PR target/113689 + * gcc.target/i386/pr113689-1.c: New file. + * gcc.target/i386/pr113689-2.c: Likewise. + * gcc.target/i386/pr113689-3.c: Likewise. + +2024-02-05 Jakub Jelinek + + PR c/113740 + * gcc.dg/bitint-85.c: New test. + +2024-02-05 Richard Ball + + * lib/target-supports.exp: Add v8_1_m_main_pacbti. + * g++.target/arm/bti_thunk.C: New test. + +2024-02-05 H.J. Lu <(no_default)> + + * gcc.target/i386/apx-ndd.c: Updated. + +2024-02-05 Richard Biener + + PR tree-optimization/113707 + * gcc.dg/torture/pr113707-1.c: New testcase. + * gcc.dg/torture/pr113707-2.c: Likewise. + +2024-02-05 Jakub Jelinek + + PR tree-optimization/113737 + * gcc.dg/bitint-84.c: New test. + +2024-02-05 Monk Chiang + + * gcc.target/riscv/mcpu-sifive-p450.c: New test. + * gcc.target/riscv/mcpu-sifive-p670.c: New test. + 2024-02-04 Jeff Law * gcc.target/riscv/reg_subreg_costs.c: New test. -- cgit v1.1 From c5d34912ad576be1ef19be92f7eabde54b9089eb Mon Sep 17 00:00:00 2001 From: Jason Merrill Date: Mon, 5 Feb 2024 19:56:45 -0500 Subject: c++: defaulted op== for incomplete class [PR107291] After complaining about lack of friendship, we should not try to go on and define the defaulted comparison operator anyway. PR c++/107291 gcc/cp/ChangeLog: * method.cc (early_check_defaulted_comparison): Fail if not friend. gcc/testsuite/ChangeLog: * g++.dg/cpp2a/spaceship-eq17.C: New test. --- gcc/cp/method.cc | 6 +++++- gcc/testsuite/g++.dg/cpp2a/spaceship-eq17.C | 5 +++++ 2 files changed, 10 insertions(+), 1 deletion(-) create mode 100644 gcc/testsuite/g++.dg/cpp2a/spaceship-eq17.C (limited to 'gcc') diff --git a/gcc/cp/method.cc b/gcc/cp/method.cc index d49e5a5..3b8dc75 100644 --- a/gcc/cp/method.cc +++ b/gcc/cp/method.cc @@ -1228,7 +1228,11 @@ early_check_defaulted_comparison (tree fn) /* Defaulted outside the class body. */ ctx = TYPE_MAIN_VARIANT (parmtype); if (!is_friend (ctx, fn)) - error_at (loc, "defaulted %qD is not a friend of %qT", fn, ctx); + { + error_at (loc, "defaulted %qD is not a friend of %qT", fn, ctx); + inform (location_of (ctx), "declared here"); + ok = false; + } } else if (!same_type_ignoring_top_level_qualifiers_p (parmtype, ctx)) saw_bad = true; diff --git a/gcc/testsuite/g++.dg/cpp2a/spaceship-eq17.C b/gcc/testsuite/g++.dg/cpp2a/spaceship-eq17.C new file mode 100644 index 0000000..039bfac --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp2a/spaceship-eq17.C @@ -0,0 +1,5 @@ +// PR c++/107291 +// { dg-do compile { target c++20 } } + +struct S4; // { dg-message "declared here" } +bool operator==(S4 const &, S4 const &) = default; // { dg-error "not a friend" } -- cgit v1.1 From ca04e7a2e1b08ed02e22e2656ba6032099195856 Mon Sep 17 00:00:00 2001 From: Tejas Belagod Date: Thu, 11 Jan 2024 12:37:06 +0530 Subject: AArch64: aarch64_class_max_nregs mishandles 64-bit structure modes [PR112577] The target hook aarch64_class_max_nregs returns the incorrect result for 64-bit structure modes like V31DImode or V41DFmode etc. The calculation of the nregs is based on the size of AdvSIMD vector register for 64-bit modes which ought to be UNITS_PER_VREG / 2. This patch fixes the register size. gcc/ChangeLog: PR target/112577 * config/aarch64/aarch64.cc (aarch64_class_max_nregs): Handle 64-bit vector structure modes correctly. --- gcc/config/aarch64/aarch64.cc | 2 ++ 1 file changed, 2 insertions(+) (limited to 'gcc') diff --git a/gcc/config/aarch64/aarch64.cc b/gcc/config/aarch64/aarch64.cc index 4556b8d..872393a 100644 --- a/gcc/config/aarch64/aarch64.cc +++ b/gcc/config/aarch64/aarch64.cc @@ -12961,6 +12961,8 @@ aarch64_class_max_nregs (reg_class_t regclass, machine_mode mode) && constant_multiple_p (GET_MODE_SIZE (mode), aarch64_vl_bytes (mode, vec_flags), &nregs)) return nregs; + if (vec_flags == (VEC_ADVSIMD | VEC_STRUCT | VEC_PARTIAL)) + return GET_MODE_SIZE (mode).to_constant () / 8; return (vec_flags & VEC_ADVSIMD ? CEIL (lowest_size, UNITS_PER_VREG) : CEIL (lowest_size, UNITS_PER_WORD)); -- cgit v1.1 From 760a1a5b5e427707357ca1fa858c4561258972df Mon Sep 17 00:00:00 2001 From: Jakub Jelinek Date: Tue, 6 Feb 2024 12:57:53 +0100 Subject: tree-ssa-math-opts: Fix up convert_{mult,plusminus}_to_widen [PR113759] MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit On the following testcase we emit invalid stmt: error: type mismatch in ‘widen_mult_plus_expr’ 6 | foo (int c, int b) | ^~~ unsigned long int unsigned int unsigned long _31 = WIDEN_MULT_PLUS_EXPR ; The recent PR113560 r14-8680 changes tweaked convert_mult_to_widen, but didn't change convert_plusminus_to_widen for the TREE_TYPE (rhsN) != typeN cases, but looking at this, it was already before that change quite weird. Earlier in those functions it determines actual_precision and from_unsignedN and wants to use that precision and signedness for the operands and it used build_and_insert_cast for that (which emits a cast stmt, even for INTEGER_CSTs) and later on for INTEGER_CST arguments fold_converted them to typeN (which is unclear to me why, because it seems to have assumed that TREE_TYPE (rhsN) is typeN, for the actual_precision or from_unsignedN cases it would be wrong except that build_and_insert_cast forced a SSA_NAME and so it doesn't trigger anymore). Now, since r14-8680 it is possible that rhsN also has some other type from typeN and we again want to cast. The following patch changes this, so that for the differences in actual_precision and/or from_unsignedN we actually update typeN and then use it as the type to convert the arguments to if it isn't useless, for INTEGER_CSTs by just fold_converting, otherwise using build_and_insert_cast. And uses useless_type_conversion_p test so that we don't convert unless necessary. Plus by doing that effectively also doing the important part of the r14-8680 convert_mult_to_widen changes in convert_plusminus_to_widen. 2024-02-06 Jakub Jelinek PR tree-optimization/113759 * tree-ssa-math-opts.cc (convert_mult_to_widen): If actual_precision or from_unsignedN differs from properties of typeN, update typeN to build_nonstandard_integer_type. If TREE_TYPE (rhsN) is not uselessly convertible to typeN, convert it using fold_convert or build_and_insert_cast depending on if rhsN is INTEGER_CST or not. (convert_plusminus_to_widen): Likewise. * gcc.c-torture/compile/pr113759.c: New test. --- gcc/testsuite/gcc.c-torture/compile/pr113759.c | 20 ++++++++ gcc/tree-ssa-math-opts.cc | 66 +++++++++++++------------- 2 files changed, 54 insertions(+), 32 deletions(-) create mode 100644 gcc/testsuite/gcc.c-torture/compile/pr113759.c (limited to 'gcc') diff --git a/gcc/testsuite/gcc.c-torture/compile/pr113759.c b/gcc/testsuite/gcc.c-torture/compile/pr113759.c new file mode 100644 index 0000000..742c1b2 --- /dev/null +++ b/gcc/testsuite/gcc.c-torture/compile/pr113759.c @@ -0,0 +1,20 @@ +/* PR tree-optimization/113759 */ + +extern short t[]; + +int +foo (int c, int b) +{ + if (b < 0) + __builtin_unreachable (); + if (c <= 0) + __builtin_unreachable (); + int d; + for (; c >= 0; c--) + { + int a = b + c; + d = t[a]; + t[a] = 0; + } + return d; +} diff --git a/gcc/tree-ssa-math-opts.cc b/gcc/tree-ssa-math-opts.cc index aa9f7b5..a8d25c2 100644 --- a/gcc/tree-ssa-math-opts.cc +++ b/gcc/tree-ssa-math-opts.cc @@ -2865,25 +2865,25 @@ convert_mult_to_widen (gimple *stmt, gimple_stmt_iterator *gsi) if (2 * actual_precision > TYPE_PRECISION (type)) return false; if (actual_precision != TYPE_PRECISION (type1) - || from_unsigned1 != TYPE_UNSIGNED (type1) - || (TREE_TYPE (rhs1) != type1 - && TREE_CODE (rhs1) != INTEGER_CST)) - rhs1 = build_and_insert_cast (gsi, loc, - build_nonstandard_integer_type - (actual_precision, from_unsigned1), rhs1); + || from_unsigned1 != TYPE_UNSIGNED (type1)) + type1 = build_nonstandard_integer_type (actual_precision, from_unsigned1); + if (!useless_type_conversion_p (type1, TREE_TYPE (rhs1))) + { + if (TREE_CODE (rhs1) == INTEGER_CST) + rhs1 = fold_convert (type1, rhs1); + else + rhs1 = build_and_insert_cast (gsi, loc, type1, rhs1); + } if (actual_precision != TYPE_PRECISION (type2) - || from_unsigned2 != TYPE_UNSIGNED (type2) - || (TREE_TYPE (rhs2) != type2 - && TREE_CODE (rhs2) != INTEGER_CST)) - rhs2 = build_and_insert_cast (gsi, loc, - build_nonstandard_integer_type - (actual_precision, from_unsigned2), rhs2); - - /* Handle constants. */ - if (TREE_CODE (rhs1) == INTEGER_CST) - rhs1 = fold_convert (type1, rhs1); - if (TREE_CODE (rhs2) == INTEGER_CST) - rhs2 = fold_convert (type2, rhs2); + || from_unsigned2 != TYPE_UNSIGNED (type2)) + type2 = build_nonstandard_integer_type (actual_precision, from_unsigned2); + if (!useless_type_conversion_p (type2, TREE_TYPE (rhs2))) + { + if (TREE_CODE (rhs2) == INTEGER_CST) + rhs2 = fold_convert (type2, rhs2); + else + rhs2 = build_and_insert_cast (gsi, loc, type2, rhs2); + } gimple_assign_set_rhs1 (stmt, rhs1); gimple_assign_set_rhs2 (stmt, rhs2); @@ -3086,26 +3086,28 @@ convert_plusminus_to_widen (gimple_stmt_iterator *gsi, gimple *stmt, actual_precision = GET_MODE_PRECISION (actual_mode); if (actual_precision != TYPE_PRECISION (type1) || from_unsigned1 != TYPE_UNSIGNED (type1)) - mult_rhs1 = build_and_insert_cast (gsi, loc, - build_nonstandard_integer_type - (actual_precision, from_unsigned1), - mult_rhs1); + type1 = build_nonstandard_integer_type (actual_precision, from_unsigned1); + if (!useless_type_conversion_p (type1, TREE_TYPE (mult_rhs1))) + { + if (TREE_CODE (mult_rhs1) == INTEGER_CST) + mult_rhs1 = fold_convert (type1, mult_rhs1); + else + mult_rhs1 = build_and_insert_cast (gsi, loc, type1, mult_rhs1); + } if (actual_precision != TYPE_PRECISION (type2) || from_unsigned2 != TYPE_UNSIGNED (type2)) - mult_rhs2 = build_and_insert_cast (gsi, loc, - build_nonstandard_integer_type - (actual_precision, from_unsigned2), - mult_rhs2); + type2 = build_nonstandard_integer_type (actual_precision, from_unsigned2); + if (!useless_type_conversion_p (type2, TREE_TYPE (mult_rhs2))) + { + if (TREE_CODE (mult_rhs2) == INTEGER_CST) + mult_rhs2 = fold_convert (type2, mult_rhs2); + else + mult_rhs2 = build_and_insert_cast (gsi, loc, type2, mult_rhs2); + } if (!useless_type_conversion_p (type, TREE_TYPE (add_rhs))) add_rhs = build_and_insert_cast (gsi, loc, type, add_rhs); - /* Handle constants. */ - if (TREE_CODE (mult_rhs1) == INTEGER_CST) - mult_rhs1 = fold_convert (type1, mult_rhs1); - if (TREE_CODE (mult_rhs2) == INTEGER_CST) - mult_rhs2 = fold_convert (type2, mult_rhs2); - gimple_assign_set_rhs_with_ops (gsi, wmult_code, mult_rhs1, mult_rhs2, add_rhs); update_stmt (gsi_stmt (*gsi)); -- cgit v1.1 From 483c061d699309d58a1b28ce5c00ee9b55a7365c Mon Sep 17 00:00:00 2001 From: Jakub Jelinek Date: Tue, 6 Feb 2024 12:58:55 +0100 Subject: lower-bitint: Encode address space qualifiers in VIEW_CONVERT_EXPRs [PR113736] As discussed in the PR, e.g. build_fold_addr_expr needs TYPE_ADDR_SPACE on the outermost reference rather than just on the base, so the following patch makes sure to propagate the address space from the accessed var to the MEM_REFs and/or VIEW_CONVERT_EXPRs used to access those. 2024-02-06 Jakub Jelinek PR tree-optimization/113736 * gimple-lower-bitint.cc (bitint_large_huge::limb_access): Use var's address space for MEM_REF or VIEW_CONVERT_EXPRs. * gcc.dg/bitint-86.c: New test. --- gcc/gimple-lower-bitint.cc | 13 +++++++++---- gcc/testsuite/gcc.dg/bitint-86.c | 40 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 49 insertions(+), 4 deletions(-) create mode 100644 gcc/testsuite/gcc.dg/bitint-86.c (limited to 'gcc') diff --git a/gcc/gimple-lower-bitint.cc b/gcc/gimple-lower-bitint.cc index e92f573..41484a0 100644 --- a/gcc/gimple-lower-bitint.cc +++ b/gcc/gimple-lower-bitint.cc @@ -601,12 +601,17 @@ bitint_large_huge::limb_access (tree type, tree var, tree idx, bool write_p) { tree atype = (tree_fits_uhwi_p (idx) ? limb_access_type (type, idx) : m_limb_type); + tree ltype = m_limb_type; + addr_space_t as = TYPE_ADDR_SPACE (TREE_TYPE (var)); + if (as != TYPE_ADDR_SPACE (ltype)) + ltype = build_qualified_type (ltype, TYPE_QUALS (ltype) + | ENCODE_QUAL_ADDR_SPACE (as)); tree ret; if (DECL_P (var) && tree_fits_uhwi_p (idx)) { tree ptype = build_pointer_type (strip_array_types (TREE_TYPE (var))); unsigned HOST_WIDE_INT off = tree_to_uhwi (idx) * m_limb_size; - ret = build2 (MEM_REF, m_limb_type, + ret = build2 (MEM_REF, ltype, build_fold_addr_expr (var), build_int_cst (ptype, off)); TREE_THIS_VOLATILE (ret) = TREE_THIS_VOLATILE (var); @@ -615,7 +620,7 @@ bitint_large_huge::limb_access (tree type, tree var, tree idx, bool write_p) else if (TREE_CODE (var) == MEM_REF && tree_fits_uhwi_p (idx)) { ret - = build2 (MEM_REF, m_limb_type, TREE_OPERAND (var, 0), + = build2 (MEM_REF, ltype, TREE_OPERAND (var, 0), size_binop (PLUS_EXPR, TREE_OPERAND (var, 1), build_int_cst (TREE_TYPE (TREE_OPERAND (var, 1)), tree_to_uhwi (idx) @@ -633,10 +638,10 @@ bitint_large_huge::limb_access (tree type, tree var, tree idx, bool write_p) { unsigned HOST_WIDE_INT nelts = CEIL (tree_to_uhwi (TYPE_SIZE (type)), limb_prec); - tree atype = build_array_type_nelts (m_limb_type, nelts); + tree atype = build_array_type_nelts (ltype, nelts); var = build1 (VIEW_CONVERT_EXPR, atype, var); } - ret = build4 (ARRAY_REF, m_limb_type, var, idx, NULL_TREE, NULL_TREE); + ret = build4 (ARRAY_REF, ltype, var, idx, NULL_TREE, NULL_TREE); } if (!write_p && !useless_type_conversion_p (atype, m_limb_type)) { diff --git a/gcc/testsuite/gcc.dg/bitint-86.c b/gcc/testsuite/gcc.dg/bitint-86.c new file mode 100644 index 0000000..4e5761a --- /dev/null +++ b/gcc/testsuite/gcc.dg/bitint-86.c @@ -0,0 +1,40 @@ +/* PR tree-optimization/113736 */ +/* { dg-do compile { target bitint } } */ +/* { dg-options "-O2 -std=gnu23 -w" } */ + +#if __BITINT_MAXWIDTH__ >= 710 +struct S { _BitInt(710) a; }; +struct T { struct S b[4]; }; + +#ifdef __x86_64__ +#define SEG __seg_gs +#elif defined __i386__ +#define SEG __seg_fs +#else +#define SEG +#endif + +void +foo (__seg_gs struct T *p) +{ + struct S s; + p->b[0] = s; +} + +void +bar (__seg_gs struct T *p, _BitInt(710) x, int y, double z) +{ + p->b[0].a = x + 42; + p->b[1].a = x << y; + p->b[2].a = x >> y; + p->b[3].a = z; +} + +int +baz (__seg_gs struct T *p, _BitInt(710) x, _BitInt(710) y) +{ + return __builtin_add_overflow (x, y, &p->b[1].a); +} +#else +int i; +#endif -- cgit v1.1 From d3eac7d96de790df51859f63c13838f153b416de Mon Sep 17 00:00:00 2001 From: Jakub Jelinek Date: Tue, 6 Feb 2024 13:00:04 +0100 Subject: asan: Don't fold some strlens with -fsanitize=address [PR110676] The UB on the following testcase isn't diagnosed by -fsanitize=address, because we see that the array has a single element and optimize the strlen to 0. I think it is fine to assume e.g. for range purposes the lower bound for the strlen as long as we don't try to optimize strlen (str) where we know that it returns [26, 42] to 26 + strlen (str + 26), but for the upper bound we really want to punt on optimizing that for -fsanitize=address to read all the bytes of the string and diagnose if we run to object end etc. 2024-02-06 Jakub Jelinek PR sanitizer/110676 * gimple-fold.cc (gimple_fold_builtin_strlen): For -fsanitize=address reset maxlen to sizetype maximum. * gcc.dg/asan/pr110676.c: New test. --- gcc/gimple-fold.cc | 5 +++++ gcc/testsuite/gcc.dg/asan/pr110676.c | 14 ++++++++++++++ 2 files changed, 19 insertions(+) create mode 100644 gcc/testsuite/gcc.dg/asan/pr110676.c (limited to 'gcc') diff --git a/gcc/gimple-fold.cc b/gcc/gimple-fold.cc index a46e640..5191102 100644 --- a/gcc/gimple-fold.cc +++ b/gcc/gimple-fold.cc @@ -4019,6 +4019,11 @@ gimple_fold_builtin_strlen (gimple_stmt_iterator *gsi) maxlen = wi::to_wide (max_object_size (), prec) - 2; } + /* For -fsanitize=address, don't optimize the upper bound of the + length to be able to diagnose UB on non-zero terminated arrays. */ + if (sanitize_flags_p (SANITIZE_ADDRESS)) + maxlen = wi::max_value (TYPE_PRECISION (sizetype), UNSIGNED); + if (minlen == maxlen) { /* Fold the strlen call to a constant. */ diff --git a/gcc/testsuite/gcc.dg/asan/pr110676.c b/gcc/testsuite/gcc.dg/asan/pr110676.c new file mode 100644 index 0000000..0ae6fdd --- /dev/null +++ b/gcc/testsuite/gcc.dg/asan/pr110676.c @@ -0,0 +1,14 @@ +/* PR sanitizer/110676 */ +/* { dg-do run } */ +/* { dg-skip-if "" { *-*-* } { "*" } { "-O0" } } */ +/* { dg-shouldfail "asan" } */ + +int +main () +{ + char s[1] = "A"; + return __builtin_strlen (s); +} + +/* { dg-output "ERROR: AddressSanitizer: stack-buffer-overflow on address.*(\n|\r\n|\r)" } */ +/* { dg-output "READ of size.*" } */ -- cgit v1.1 From d29136ad3282905145e24d7ec10b6efe4ab5d2f1 Mon Sep 17 00:00:00 2001 From: Juzhe-Zhong Date: Tue, 6 Feb 2024 07:12:24 +0800 Subject: RISC-V: Fix infinite compilation of VSETVL PASS This patch fixes issue reported by Jeff. Testing is running. Ok for trunk if I passed the testing with no regression ? gcc/ChangeLog: * config/riscv/riscv-vsetvl.cc (pre_vsetvl::emit_vsetvl): Fix inifinite compilation. (pre_vsetvl::remove_vsetvl_pre_insns): Ditto. --- gcc/config/riscv/riscv-vsetvl.cc | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) (limited to 'gcc') diff --git a/gcc/config/riscv/riscv-vsetvl.cc b/gcc/config/riscv/riscv-vsetvl.cc index 2c0dcdf..32f262d 100644 --- a/gcc/config/riscv/riscv-vsetvl.cc +++ b/gcc/config/riscv/riscv-vsetvl.cc @@ -2281,9 +2281,8 @@ private: } } - void remove_vsetvl_insn (const vsetvl_info &info) + void remove_vsetvl_insn (rtx_insn *rinsn) { - rtx_insn *rinsn = info.get_insn ()->rtl (); if (dump_file) { fprintf (dump_file, " Eliminate insn %d:\n", INSN_UID (rinsn)); @@ -3231,7 +3230,7 @@ pre_vsetvl::emit_vsetvl () if (curr_info.delete_p ()) { if (vsetvl_insn_p (insn->rtl ())) - remove_vsetvl_insn (curr_info); + remove_vsetvl_insn (curr_info.get_insn ()->rtl ()); continue; } else if (curr_info.valid_p ()) @@ -3269,7 +3268,7 @@ pre_vsetvl::emit_vsetvl () for (const vsetvl_info &item : m_delete_list) { gcc_assert (vsetvl_insn_p (item.get_insn ()->rtl ())); - remove_vsetvl_insn (item); + remove_vsetvl_insn (item.get_insn ()->rtl ()); } /* Insert vsetvl info that was not deleted after lift up. */ @@ -3434,7 +3433,7 @@ pre_vsetvl::remove_vsetvl_pre_insns () INSN_UID (rinsn)); print_rtl_single (dump_file, rinsn); } - remove_insn (rinsn); + remove_vsetvl_insn (rinsn); } } -- cgit v1.1 From 68a8ec7c7404db6fce1be307a3d8bdde6cdbc6fb Mon Sep 17 00:00:00 2001 From: Marek Polacek Date: Mon, 5 Feb 2024 21:52:19 -0500 Subject: c++: add auto_diagnostic_group to early_check_defaulted_comparison gcc/cp/ChangeLog: * method.cc (early_check_defaulted_comparison): Add auto_diagnostic_group. --- gcc/cp/method.cc | 1 + 1 file changed, 1 insertion(+) (limited to 'gcc') diff --git a/gcc/cp/method.cc b/gcc/cp/method.cc index 3b8dc75..957496d 100644 --- a/gcc/cp/method.cc +++ b/gcc/cp/method.cc @@ -1229,6 +1229,7 @@ early_check_defaulted_comparison (tree fn) ctx = TYPE_MAIN_VARIANT (parmtype); if (!is_friend (ctx, fn)) { + auto_diagnostic_group d; error_at (loc, "defaulted %qD is not a friend of %qT", fn, ctx); inform (location_of (ctx), "declared here"); ok = false; -- cgit v1.1 From df9f6b934886f51c0c07220d1ee38874b69646c7 Mon Sep 17 00:00:00 2001 From: Jakub Jelinek Date: Tue, 6 Feb 2024 15:56:50 +0100 Subject: aarch64: Fix build against libc++ in c++11 mode [PR113763] std::pair ctor used in tiles constexpr variable is only constexpr in C++14 and later, it works with libstdc++ because it is marked constexpr there even in C++11 mode. The following patch fixes it by using an unnamed local class instead of std::pair, and additionally changes the first element from unsigned int to unsigned char because 0xff has to fit into unsigned char on all hosts. 2024-02-06 Jakub Jelinek PR target/113763 * config/aarch64/aarch64.cc (aarch64_output_sme_zero_za): Change tiles element from std::pair to an unnamed struct. Adjust uses of tile range variable. --- gcc/config/aarch64/aarch64.cc | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'gcc') diff --git a/gcc/config/aarch64/aarch64.cc b/gcc/config/aarch64/aarch64.cc index 872393a..bdbfe2a 100644 --- a/gcc/config/aarch64/aarch64.cc +++ b/gcc/config/aarch64/aarch64.cc @@ -13132,7 +13132,7 @@ aarch64_output_sme_zero_za (rtx mask) if (mask_val == 0xff) return "zero\t{ za }"; - static constexpr std::pair tiles[] = { + static constexpr struct { unsigned char mask; char letter; } tiles[] = { { 0xff, 'b' }, { 0x55, 'h' }, { 0x11, 's' }, @@ -13146,14 +13146,14 @@ aarch64_output_sme_zero_za (rtx mask) const char *prefix = "{ "; for (auto &tile : tiles) { - auto tile_mask = tile.first; + unsigned int tile_mask = tile.mask; unsigned int tile_index = 0; while (tile_mask < 0x100) { if ((mask_val & tile_mask) == tile_mask) { i += snprintf (buffer + i, sizeof (buffer) - i, "%sza%d.%c", - prefix, tile_index, tile.second); + prefix, tile_index, tile.letter); prefix = ", "; mask_val &= ~tile_mask; } -- cgit v1.1 From 8ec2f1922a14ee3636840d1ebc1c40d26e6043a4 Mon Sep 17 00:00:00 2001 From: Andrew Carlotti Date: Wed, 31 Jan 2024 16:28:12 +0000 Subject: aarch64: Fix function multiversioning mangling It would be neater if the middle end for target_clones used a target hook for version name mangling, so we only do version name mangling once. However, that would require more intrusive refactoring that will have to wait till Stage 1. gcc/ChangeLog: * config/aarch64/aarch64.cc (aarch64_mangle_decl_assembler_name): Move before new caller, and add ".default" suffix. (get_suffixed_assembler_name): New. (make_resolver_func): Use get_suffixed_assembler_name. (aarch64_generate_version_dispatcher_body): Redo name mangling. gcc/testsuite/ChangeLog: * g++.target/aarch64/mv-symbols1.C: New test. * g++.target/aarch64/mv-symbols2.C: Ditto. * g++.target/aarch64/mv-symbols3.C: Ditto. * g++.target/aarch64/mv-symbols4.C: Ditto. * g++.target/aarch64/mv-symbols5.C: Ditto. * g++.target/aarch64/mvc-symbols1.C: Ditto. * g++.target/aarch64/mvc-symbols2.C: Ditto. * g++.target/aarch64/mvc-symbols3.C: Ditto. * g++.target/aarch64/mvc-symbols4.C: Ditto. --- gcc/config/aarch64/aarch64.cc | 119 ++++++++++++++++-------- gcc/testsuite/g++.target/aarch64/mv-symbols1.C | 66 +++++++++++++ gcc/testsuite/g++.target/aarch64/mv-symbols2.C | 52 +++++++++++ gcc/testsuite/g++.target/aarch64/mv-symbols3.C | 41 ++++++++ gcc/testsuite/g++.target/aarch64/mv-symbols4.C | 48 ++++++++++ gcc/testsuite/g++.target/aarch64/mv-symbols5.C | 56 +++++++++++ gcc/testsuite/g++.target/aarch64/mvc-symbols1.C | 44 +++++++++ gcc/testsuite/g++.target/aarch64/mvc-symbols2.C | 29 ++++++ gcc/testsuite/g++.target/aarch64/mvc-symbols3.C | 35 +++++++ gcc/testsuite/g++.target/aarch64/mvc-symbols4.C | 23 +++++ 10 files changed, 475 insertions(+), 38 deletions(-) create mode 100644 gcc/testsuite/g++.target/aarch64/mv-symbols1.C create mode 100644 gcc/testsuite/g++.target/aarch64/mv-symbols2.C create mode 100644 gcc/testsuite/g++.target/aarch64/mv-symbols3.C create mode 100644 gcc/testsuite/g++.target/aarch64/mv-symbols4.C create mode 100644 gcc/testsuite/g++.target/aarch64/mv-symbols5.C create mode 100644 gcc/testsuite/g++.target/aarch64/mvc-symbols1.C create mode 100644 gcc/testsuite/g++.target/aarch64/mvc-symbols2.C create mode 100644 gcc/testsuite/g++.target/aarch64/mvc-symbols3.C create mode 100644 gcc/testsuite/g++.target/aarch64/mvc-symbols4.C (limited to 'gcc') diff --git a/gcc/config/aarch64/aarch64.cc b/gcc/config/aarch64/aarch64.cc index bdbfe2a..32eae49 100644 --- a/gcc/config/aarch64/aarch64.cc +++ b/gcc/config/aarch64/aarch64.cc @@ -19872,6 +19872,62 @@ build_ifunc_arg_type () return pointer_type; } +/* Implement TARGET_MANGLE_DECL_ASSEMBLER_NAME, to add function multiversioning + suffixes. */ + +tree +aarch64_mangle_decl_assembler_name (tree decl, tree id) +{ + /* For function version, add the target suffix to the assembler name. */ + if (TREE_CODE (decl) == FUNCTION_DECL + && DECL_FUNCTION_VERSIONED (decl)) + { + aarch64_fmv_feature_mask feature_mask = get_feature_mask_for_version (decl); + + std::string name = IDENTIFIER_POINTER (id); + + /* For the default version, append ".default". */ + if (feature_mask == 0ULL) + { + name += ".default"; + return get_identifier (name.c_str()); + } + + name += "._"; + + for (int i = 0; i < FEAT_MAX; i++) + { + if (feature_mask & aarch64_fmv_feature_data[i].feature_mask) + { + name += "M"; + name += aarch64_fmv_feature_data[i].name; + } + } + + if (DECL_ASSEMBLER_NAME_SET_P (decl)) + SET_DECL_RTL (decl, NULL); + + id = get_identifier (name.c_str()); + } + return id; +} + +/* Return an identifier for the base assembler name of a versioned function. + This is computed by taking the default version's assembler name, and + stripping off the ".default" suffix if it's already been appended. */ + +static tree +get_suffixed_assembler_name (tree default_decl, const char *suffix) +{ + std::string name = IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (default_decl)); + + auto size = name.size (); + if (size >= 8 && name.compare (size - 8, 8, ".default") == 0) + name.resize (size - 8); + name += suffix; + return get_identifier (name.c_str()); +} + /* Make the resolver function decl to dispatch the versions of a multi-versioned function, DEFAULT_DECL. IFUNC_ALIAS_DECL is ifunc alias that will point to the created resolver. Create an @@ -19885,8 +19941,9 @@ make_resolver_func (const tree default_decl, { tree decl, type, t; - /* Create resolver function name based on default_decl. */ - tree decl_name = clone_function_name (default_decl, "resolver"); + /* Create resolver function name based on default_decl. We need to remove an + existing ".default" suffix if this has already been appended. */ + tree decl_name = get_suffixed_assembler_name (default_decl, ".resolver"); const char *resolver_name = IDENTIFIER_POINTER (decl_name); /* The resolver function should have signature @@ -20233,6 +20290,28 @@ aarch64_generate_version_dispatcher_body (void *node_p) dispatch_function_versions (resolver_decl, &fn_ver_vec, &empty_bb); cgraph_edge::rebuild_edges (); pop_cfun (); + + /* Fix up symbol names. First we need to obtain the base name, which may + have already been mangled. */ + tree base_name = get_suffixed_assembler_name (default_ver_decl, ""); + + /* We need to redo the version mangling on the non-default versions for the + target_clones case. Redoing the mangling for the target_version case is + redundant but does no harm. We need to skip the default version, because + expand_clones will append ".default" later; fortunately that suffix is the + one we want anyway. */ + for (versn_info = node_version_info->next->next; versn_info; + versn_info = versn_info->next) + { + tree version_decl = versn_info->this_node->decl; + tree name = aarch64_mangle_decl_assembler_name (version_decl, + base_name); + symtab->change_decl_assembler_name (version_decl, name); + } + + /* We also need to use the base name for the ifunc declaration. */ + symtab->change_decl_assembler_name (node->decl, base_name); + return resolver_decl; } @@ -20345,42 +20424,6 @@ aarch64_common_function_versions (tree fn1, tree fn2) return (aarch64_compare_version_priority (fn1, fn2) != 0); } -/* Implement TARGET_MANGLE_DECL_ASSEMBLER_NAME, to add function multiversioning - suffixes. */ - -tree -aarch64_mangle_decl_assembler_name (tree decl, tree id) -{ - /* For function version, add the target suffix to the assembler name. */ - if (TREE_CODE (decl) == FUNCTION_DECL - && DECL_FUNCTION_VERSIONED (decl)) - { - aarch64_fmv_feature_mask feature_mask = get_feature_mask_for_version (decl); - - /* No suffix for the default version. */ - if (feature_mask == 0ULL) - return id; - - std::string name = IDENTIFIER_POINTER (id); - name += "._"; - - for (int i = 0; i < FEAT_MAX; i++) - { - if (feature_mask & aarch64_fmv_feature_data[i].feature_mask) - { - name += "M"; - name += aarch64_fmv_feature_data[i].name; - } - } - - if (DECL_ASSEMBLER_NAME_SET_P (decl)) - SET_DECL_RTL (decl, NULL); - - id = get_identifier (name.c_str()); - } - return id; -} - /* Implement TARGET_FUNCTION_ATTRIBUTE_INLINABLE_P. Use an opt-out rather than an opt-in list. */ diff --git a/gcc/testsuite/g++.target/aarch64/mv-symbols1.C b/gcc/testsuite/g++.target/aarch64/mv-symbols1.C new file mode 100644 index 0000000..53e0abc --- /dev/null +++ b/gcc/testsuite/g++.target/aarch64/mv-symbols1.C @@ -0,0 +1,66 @@ +/* { dg-do compile } */ +/* { dg-require-ifunc "" } */ +/* { dg-options "-O0" } */ + +int foo () +{ + return 1; +} + +__attribute__((target_version("dotprod"))) +int foo () +{ + return 3; +} +__attribute__((target_version("sve+sve2"))) +int foo () +{ + return 5; +} + +__attribute__((target_version("sve+sve2"))) +int foo (int) +{ + return 6; +} + +__attribute__((target_version("dotprod"))) +int foo (int) +{ + return 4; +} + +int foo (int) +{ + return 2; +} + + +int bar() +{ + return foo (); +} + +int bar(int x) +{ + return foo (x); +} + +/* When updating any of the symbol names in these tests, make sure to also + update any tests for their absence in mv-symbolsN.C */ + +/* { dg-final { scan-assembler-times "\n_Z3foov\.default:\n" 1 } } */ +/* { dg-final { scan-assembler-times "\n_Z3foov\._Mdotprod:\n" 1 } } */ +/* { dg-final { scan-assembler-times "\n_Z3foov\._MsveMsve2:\n" 1 } } */ +/* { dg-final { scan-assembler-times "\n_Z3foov\.resolver:\n" 1 } } */ +/* { dg-final { scan-assembler-times "\n\tbl\t_Z3foov\n" 1 } } */ +/* { dg-final { scan-assembler-times "\n\t\.type\t_Z3foov, %gnu_indirect_function\n" 1 } } */ +/* { dg-final { scan-assembler-times "\n\t\.set\t_Z3foov,_Z3foov\.resolver\n" 1 } } */ + +/* { dg-final { scan-assembler-times "\n_Z3fooi\.default:\n" 1 } } */ +/* { dg-final { scan-assembler-times "\n_Z3fooi\._Mdotprod:\n" 1 } } */ +/* { dg-final { scan-assembler-times "\n_Z3fooi\._MsveMsve2:\n" 1 } } */ +/* { dg-final { scan-assembler-times "\n_Z3fooi\.resolver:\n" 1 } } */ +/* { dg-final { scan-assembler-times "\n\tbl\t_Z3fooi\n" 1 } } */ +/* { dg-final { scan-assembler-times "\n\t\.type\t_Z3fooi, %gnu_indirect_function\n" 1 } } */ +/* { dg-final { scan-assembler-times "\n\t\.set\t_Z3fooi,_Z3fooi\.resolver\n" 1 } } */ diff --git a/gcc/testsuite/g++.target/aarch64/mv-symbols2.C b/gcc/testsuite/g++.target/aarch64/mv-symbols2.C new file mode 100644 index 0000000..f0c7967 --- /dev/null +++ b/gcc/testsuite/g++.target/aarch64/mv-symbols2.C @@ -0,0 +1,52 @@ +/* { dg-do compile } */ +/* { dg-require-ifunc "" } */ +/* { dg-options "-O0" } */ + +__attribute__((target_version("default"))) +int foo () +{ + return 1; +} + +__attribute__((target_version("dotprod"))) +int foo () +{ + return 3; +} +__attribute__((target_version("sve+sve2"))) +int foo () +{ + return 5; +} + +__attribute__((target_version("sve+sve2"))) +int foo (int) +{ + return 6; +} + +__attribute__((target_version("dotprod"))) +int foo (int) +{ + return 4; +} + +__attribute__((target_version("default"))) +int foo (int) +{ + return 2; +} + +/* { dg-final { scan-assembler-times "\n_Z3foov\.default:\n" 1 } } */ +/* { dg-final { scan-assembler-times "\n_Z3foov\._Mdotprod:\n" 1 } } */ +/* { dg-final { scan-assembler-times "\n_Z3foov\._MsveMsve2:\n" 1 } } */ +/* { dg-final { scan-assembler-times "\n_Z3foov\.resolver:\n" 0 } } */ +/* { dg-final { scan-assembler-times "\n\t\.type\t_Z3foov, %gnu_indirect_function\n" 0 } } */ +/* { dg-final { scan-assembler-times "\n\t\.set\t_Z3foov,_Z3foov\.resolver\n" 0 } } */ + +/* { dg-final { scan-assembler-times "\n_Z3fooi\.default:\n" 1 } } */ +/* { dg-final { scan-assembler-times "\n_Z3fooi\._Mdotprod:\n" 1 } } */ +/* { dg-final { scan-assembler-times "\n_Z3fooi\._MsveMsve2:\n" 1 } } */ +/* { dg-final { scan-assembler-times "\n_Z3fooi\.resolver:\n" 0 } } */ +/* { dg-final { scan-assembler-times "\n\t\.type\t_Z3fooi, %gnu_indirect_function\n" 0 } } */ +/* { dg-final { scan-assembler-times "\n\t\.set\t_Z3fooi,_Z3fooi\.resolver\n" 0 } } */ diff --git a/gcc/testsuite/g++.target/aarch64/mv-symbols3.C b/gcc/testsuite/g++.target/aarch64/mv-symbols3.C new file mode 100644 index 0000000..3d30e27 --- /dev/null +++ b/gcc/testsuite/g++.target/aarch64/mv-symbols3.C @@ -0,0 +1,41 @@ +/* { dg-do compile } */ +/* { dg-require-ifunc "" } */ +/* { dg-options "-O0" } */ + +__attribute__((target_version("default"))) +int foo (); + +__attribute__((target_version("dotprod"))) +int foo (); + +__attribute__((target_version("sve+sve2"))) +int foo (); + +__attribute__((target_version("default"))) +int foo (int); + +__attribute__((target_version("dotprod"))) +int foo (int); + +__attribute__((target_version("sve+sve2"))) +int foo (int); + +int bar() +{ + return foo (); +} + +/* { dg-final { scan-assembler-times "\n_Z3foov\.default:\n" 0 } } */ +/* { dg-final { scan-assembler-times "\n_Z3foov\._Mdotprod:\n" 0 } } */ +/* { dg-final { scan-assembler-times "\n_Z3foov\._MsveMsve2:\n" 0 } } */ +/* { dg-final { scan-assembler-times "\n_Z3foov\.resolver:\n" 1 } } */ +/* { dg-final { scan-assembler-times "\n\tbl\t_Z3foov\n" 1 } } */ +/* { dg-final { scan-assembler-times "\n\t\.type\t_Z3foov, %gnu_indirect_function\n" 1 } } */ +/* { dg-final { scan-assembler-times "\n\t\.set\t_Z3foov,_Z3foov\.resolver\n" 1 } } */ + +/* { dg-final { scan-assembler-times "\n_Z3fooi\.default:\n" 0 } } */ +/* { dg-final { scan-assembler-times "\n_Z3fooi\._Mdotprod:\n" 0 } } */ +/* { dg-final { scan-assembler-times "\n_Z3fooi\._MsveMsve2:\n" 0 } } */ +/* { dg-final { scan-assembler-times "\n_Z3fooi\.resolver:\n" 0 } } */ +/* { dg-final { scan-assembler-times "\n\t\.type\t_Z3fooi, %gnu_indirect_function\n" 0 } } */ +/* { dg-final { scan-assembler-times "\n\t\.set\t_Z3fooi,_Z3fooi\.resolver\n" 0 } } */ diff --git a/gcc/testsuite/g++.target/aarch64/mv-symbols4.C b/gcc/testsuite/g++.target/aarch64/mv-symbols4.C new file mode 100644 index 0000000..73e3279 --- /dev/null +++ b/gcc/testsuite/g++.target/aarch64/mv-symbols4.C @@ -0,0 +1,48 @@ +/* { dg-do compile } */ +/* { dg-require-ifunc "" } */ +/* { dg-options "-O0" } */ + +__attribute__((target_version("default"))) +int foo () +{ + return 1; +} + +__attribute__((target_version("dotprod"))) +int foo (); + +__attribute__((target_version("sve+sve2"))) +int foo (); + +__attribute__((target_version("default"))) +int foo (int) +{ + return 2; +} + +__attribute__((target_version("dotprod"))) +int foo (int); + +__attribute__((target_version("sve+sve2"))) +int foo (int); + + +int bar() +{ + return foo (); +} + +/* { dg-final { scan-assembler-times "\n_Z3foov\.default:\n" 1 } } */ +/* { dg-final { scan-assembler-times "\n_Z3foov\._Mdotprod:\n" 0 } } */ +/* { dg-final { scan-assembler-times "\n_Z3foov\._MsveMsve2:\n" 0 } } */ +/* { dg-final { scan-assembler-times "\n_Z3foov\.resolver:\n" 1 } } */ +/* { dg-final { scan-assembler-times "\n\tbl\t_Z3foov\n" 1 } } */ +/* { dg-final { scan-assembler-times "\n\t\.type\t_Z3foov, %gnu_indirect_function\n" 1 } } */ +/* { dg-final { scan-assembler-times "\n\t\.set\t_Z3foov,_Z3foov\.resolver\n" 1 } } */ + +/* { dg-final { scan-assembler-times "\n_Z3fooi\.default:\n" 1 } } */ +/* { dg-final { scan-assembler-times "\n_Z3fooi\._Mdotprod:\n" 0 } } */ +/* { dg-final { scan-assembler-times "\n_Z3fooi\._MsveMsve2:\n" 0 } } */ +/* { dg-final { scan-assembler-times "\n_Z3fooi\.resolver:\n" 0 } } */ +/* { dg-final { scan-assembler-times "\n\t\.type\t_Z3fooi, %gnu_indirect_function\n" 0 } } */ +/* { dg-final { scan-assembler-times "\n\t\.set\t_Z3fooi,_Z3fooi\.resolver\n" 0 } } */ diff --git a/gcc/testsuite/g++.target/aarch64/mv-symbols5.C b/gcc/testsuite/g++.target/aarch64/mv-symbols5.C new file mode 100644 index 0000000..05d1379 --- /dev/null +++ b/gcc/testsuite/g++.target/aarch64/mv-symbols5.C @@ -0,0 +1,56 @@ +/* { dg-do compile } */ +/* { dg-require-ifunc "" } */ +/* { dg-options "-O0" } */ + +__attribute__((target_version("default"))) +int foo (); + +__attribute__((target_version("dotprod"))) +int foo () +{ + return 3; +} +__attribute__((target_version("sve+sve2"))) +int foo () +{ + return 5; +} + +__attribute__((target_version("default"))) +int foo (int); + +__attribute__((target_version("dotprod"))) +int foo (int) +{ + return 4; +} + +__attribute__((target_version("sve+sve2"))) +int foo (int) +{ + return 6; +} + + +int bar() +{ + return foo (); +} + +/* When updating any of the symbol names in these tests, make sure to also + update any tests for their absence in mvc-symbolsN.C */ + +/* { dg-final { scan-assembler-times "\n_Z3foov\.default:\n" 0 } } */ +/* { dg-final { scan-assembler-times "\n_Z3foov\._Mdotprod:\n" 1 } } */ +/* { dg-final { scan-assembler-times "\n_Z3foov\._MsveMsve2:\n" 1 } } */ +/* { dg-final { scan-assembler-times "\n_Z3foov\.resolver:\n" 1 } } */ +/* { dg-final { scan-assembler-times "\n\tbl\t_Z3foov\n" 1 } } */ +/* { dg-final { scan-assembler-times "\n\t\.type\t_Z3foov, %gnu_indirect_function\n" 1 } } */ +/* { dg-final { scan-assembler-times "\n\t\.set\t_Z3foov,_Z3foov\.resolver\n" 1 } } */ + +/* { dg-final { scan-assembler-times "\n_Z3fooi\.default:\n" 0 } } */ +/* { dg-final { scan-assembler-times "\n_Z3fooi\._Mdotprod:\n" 1 } } */ +/* { dg-final { scan-assembler-times "\n_Z3fooi\._MsveMsve2:\n" 1 } } */ +/* { dg-final { scan-assembler-times "\n_Z3fooi\.resolver:\n" 0 } } */ +/* { dg-final { scan-assembler-times "\n\t\.type\t_Z3fooi, %gnu_indirect_function\n" 0 } } */ +/* { dg-final { scan-assembler-times "\n\t\.set\t_Z3fooi,_Z3fooi\.resolver\n" 0 } } */ diff --git a/gcc/testsuite/g++.target/aarch64/mvc-symbols1.C b/gcc/testsuite/g++.target/aarch64/mvc-symbols1.C new file mode 100644 index 0000000..2dd7c79 --- /dev/null +++ b/gcc/testsuite/g++.target/aarch64/mvc-symbols1.C @@ -0,0 +1,44 @@ +/* { dg-do compile } */ +/* { dg-require-ifunc "" } */ +/* { dg-options "-O0" } */ + +__attribute__((target_clones("default", "dotprod", "sve+sve2"))) +int foo () +{ + return 1; +} + +__attribute__((target_clones("sve+sve2", "dotprod", "default"))) +int foo (int) +{ + return 2; +} + +int bar() +{ + return foo (); +} + +int bar(int x) +{ + return foo (x); +} + +/* When updating any of the symbol names in these tests, make sure to also + update any tests for their absence in mvc-symbolsN.C */ + +/* { dg-final { scan-assembler-times "\n_Z3foov\.default:\n" 1 } } */ +/* { dg-final { scan-assembler-times "\n_Z3foov\._Mdotprod:\n" 1 } } */ +/* { dg-final { scan-assembler-times "\n_Z3foov\._MsveMsve2:\n" 1 } } */ +/* { dg-final { scan-assembler-times "\n_Z3foov\.resolver:\n" 1 } } */ +/* { dg-final { scan-assembler-times "\n\tbl\t_Z3foov\n" 1 } } */ +/* { dg-final { scan-assembler-times "\n\t\.type\t_Z3foov, %gnu_indirect_function\n" 1 } } */ +/* { dg-final { scan-assembler-times "\n\t\.set\t_Z3foov,_Z3foov\.resolver\n" 1 } } */ + +/* { dg-final { scan-assembler-times "\n_Z3fooi\.default:\n" 1 } } */ +/* { dg-final { scan-assembler-times "\n_Z3fooi\._Mdotprod:\n" 1 } } */ +/* { dg-final { scan-assembler-times "\n_Z3fooi\._MsveMsve2:\n" 1 } } */ +/* { dg-final { scan-assembler-times "\n_Z3fooi\.resolver:\n" 1 } } */ +/* { dg-final { scan-assembler-times "\n\tbl\t_Z3fooi\n" 1 } } */ +/* { dg-final { scan-assembler-times "\n\t\.type\t_Z3fooi, %gnu_indirect_function\n" 1 } } */ +/* { dg-final { scan-assembler-times "\n\t\.set\t_Z3fooi,_Z3fooi\.resolver\n" 1 } } */ diff --git a/gcc/testsuite/g++.target/aarch64/mvc-symbols2.C b/gcc/testsuite/g++.target/aarch64/mvc-symbols2.C new file mode 100644 index 0000000..75b9c12 --- /dev/null +++ b/gcc/testsuite/g++.target/aarch64/mvc-symbols2.C @@ -0,0 +1,29 @@ +/* { dg-do compile } */ +/* { dg-require-ifunc "" } */ +/* { dg-options "-O0" } */ + +__attribute__((target_clones("default", "dotprod", "sve+sve2"))) +int foo () +{ + return 1; +} + +__attribute__((target_clones("sve+sve2", "dotprod", "default"))) +int foo (int) +{ + return 2; +} + +/* { dg-final { scan-assembler-times "\n_Z3foov\.default:\n" 1 } } */ +/* { dg-final { scan-assembler-times "\n_Z3foov\._Mdotprod:\n" 1 } } */ +/* { dg-final { scan-assembler-times "\n_Z3foov\._MsveMsve2:\n" 1 } } */ +/* { dg-final { scan-assembler-times "\n_Z3foov\.resolver:\n" 1 } } */ +/* { dg-final { scan-assembler-times "\n\t\.type\t_Z3foov, %gnu_indirect_function\n" 1 } } */ +/* { dg-final { scan-assembler-times "\n\t\.set\t_Z3foov,_Z3foov\.resolver\n" 1 } } */ + +/* { dg-final { scan-assembler-times "\n_Z3fooi\.default:\n" 1 } } */ +/* { dg-final { scan-assembler-times "\n_Z3fooi\._Mdotprod:\n" 1 } } */ +/* { dg-final { scan-assembler-times "\n_Z3fooi\._MsveMsve2:\n" 1 } } */ +/* { dg-final { scan-assembler-times "\n_Z3fooi\.resolver:\n" 1 } } */ +/* { dg-final { scan-assembler-times "\n\t\.type\t_Z3fooi, %gnu_indirect_function\n" 1 } } */ +/* { dg-final { scan-assembler-times "\n\t\.set\t_Z3fooi,_Z3fooi\.resolver\n" 1 } } */ diff --git a/gcc/testsuite/g++.target/aarch64/mvc-symbols3.C b/gcc/testsuite/g++.target/aarch64/mvc-symbols3.C new file mode 100644 index 0000000..82e777c --- /dev/null +++ b/gcc/testsuite/g++.target/aarch64/mvc-symbols3.C @@ -0,0 +1,35 @@ +/* { dg-do compile } */ +/* { dg-require-ifunc "" } */ +/* { dg-options "-O0" } */ + +__attribute__((target_clones("default", "dotprod", "sve+sve2"))) +int foo (); + +__attribute__((target_clones("sve+sve2", "dotprod", "default"))) +int foo (int); + +int bar() +{ + return foo (); +} + +int bar(int x) +{ + return foo (x); +} + +/* { dg-final { scan-assembler-times "\n_Z3foov\.default:\n" 0 } } */ +/* { dg-final { scan-assembler-times "\n_Z3foov\._Mdotprod:\n" 0 } } */ +/* { dg-final { scan-assembler-times "\n_Z3foov\._MsveMsve2:\n" 0 } } */ +/* { dg-final { scan-assembler-times "\n_Z3foov\.resolver:\n" 1 } } */ +/* { dg-final { scan-assembler-times "\n\tbl\t_Z3foov\n" 1 } } */ +/* { dg-final { scan-assembler-times "\n\t\.type\t_Z3foov, %gnu_indirect_function\n" 1 } } */ +/* { dg-final { scan-assembler-times "\n\t\.set\t_Z3foov,_Z3foov\.resolver\n" 1 } } */ + +/* { dg-final { scan-assembler-times "\n_Z3fooi\.default:\n" 0 } } */ +/* { dg-final { scan-assembler-times "\n_Z3fooi\._Mdotprod:\n" 0 } } */ +/* { dg-final { scan-assembler-times "\n_Z3fooi\._MsveMsve2:\n" 0 } } */ +/* { dg-final { scan-assembler-times "\n_Z3fooi\.resolver:\n" 1 } } */ +/* { dg-final { scan-assembler-times "\n\tbl\t_Z3fooi\n" 1 } } */ +/* { dg-final { scan-assembler-times "\n\t\.type\t_Z3fooi, %gnu_indirect_function\n" 1 } } */ +/* { dg-final { scan-assembler-times "\n\t\.set\t_Z3fooi,_Z3fooi\.resolver\n" 1 } } */ diff --git a/gcc/testsuite/g++.target/aarch64/mvc-symbols4.C b/gcc/testsuite/g++.target/aarch64/mvc-symbols4.C new file mode 100644 index 0000000..6c86ae6 --- /dev/null +++ b/gcc/testsuite/g++.target/aarch64/mvc-symbols4.C @@ -0,0 +1,23 @@ +/* { dg-do compile } */ +/* { dg-require-ifunc "" } */ +/* { dg-options "-O0" } */ + +__attribute__((target_clones("default", "dotprod", "sve+sve2"))) +int foo (); + +__attribute__((target_clones("sve+sve2", "dotprod", "default"))) +int foo (int); + +/* { dg-final { scan-assembler-times "\n_Z3foov\.default:\n" 0 } } */ +/* { dg-final { scan-assembler-times "\n_Z3foov\._Mdotprod:\n" 0 } } */ +/* { dg-final { scan-assembler-times "\n_Z3foov\._MsveMsve2:\n" 0 } } */ +/* { dg-final { scan-assembler-times "\n_Z3foov\.resolver:\n" 0 } } */ +/* { dg-final { scan-assembler-times "\n\t\.type\t_Z3foov, %gnu_indirect_function\n" 0 } } */ +/* { dg-final { scan-assembler-times "\n\t\.set\t_Z3foov,_Z3foov\.resolver\n" 0 } } */ + +/* { dg-final { scan-assembler-times "\n_Z3fooi\.default:\n" 0 } } */ +/* { dg-final { scan-assembler-times "\n_Z3fooi\._Mdotprod:\n" 0 } } */ +/* { dg-final { scan-assembler-times "\n_Z3fooi\._MsveMsve2:\n" 0 } } */ +/* { dg-final { scan-assembler-times "\n_Z3fooi\.resolver:\n" 0 } } */ +/* { dg-final { scan-assembler-times "\n\t\.type\t_Z3fooi, %gnu_indirect_function\n" 0 } } */ +/* { dg-final { scan-assembler-times "\n\t\.set\t_Z3fooi,_Z3fooi\.resolver\n" 0 } } */ -- cgit v1.1 From 1befe47f64bf0b964be90730e2cbef550cb6d2b7 Mon Sep 17 00:00:00 2001 From: Marek Polacek Date: Tue, 6 Feb 2024 11:44:44 -0500 Subject: c++: add fixed test [PR94231] I was suprised to find out that r14-8759 fixed this accepts-invalid. clang version 17.0.6 rejects the test as well; clang version 19.0.0git crashes for which I opened . PR c++/94231 gcc/testsuite/ChangeLog: * g++.dg/cpp0x/deleted17.C: New test. --- gcc/testsuite/g++.dg/cpp0x/deleted17.C | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) create mode 100644 gcc/testsuite/g++.dg/cpp0x/deleted17.C (limited to 'gcc') diff --git a/gcc/testsuite/g++.dg/cpp0x/deleted17.C b/gcc/testsuite/g++.dg/cpp0x/deleted17.C new file mode 100644 index 0000000..3bebe88 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp0x/deleted17.C @@ -0,0 +1,20 @@ +// PR c++/94231 +// { dg-do compile { target c++11 } } + +struct F {F(F&&)=delete;}; + +template +struct M { + F f; + M(); + M(const M&); + M(M&&); +}; + +template +M::M(M&&)=default; // { dg-error "use of deleted function" } + +M<> f() { + M<> m; + return m; +} -- cgit v1.1 From f2a060820c24724bb48ee006d257c449e4d94b72 Mon Sep 17 00:00:00 2001 From: "H.J. Lu" Date: Tue, 6 Feb 2024 10:57:24 -0800 Subject: x86-64: Return 10_REG if there is no scratch register If we can't find a scratch register for large model profiling, return R10_REG. PR target/113689 * config/i386/i386.cc (x86_64_select_profile_regnum): Return R10_REG after sorry. --- gcc/config/i386/i386.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'gcc') diff --git a/gcc/config/i386/i386.cc b/gcc/config/i386/i386.cc index f02c6c0..10bd534 100644 --- a/gcc/config/i386/i386.cc +++ b/gcc/config/i386/i386.cc @@ -22788,7 +22788,7 @@ x86_64_select_profile_regnum (bool r11_ok ATTRIBUTE_UNUSED) sorry ("no register available for profiling %<-mcmodel=large%s%>", ix86_cmodel == CM_LARGE_PIC ? " -fPIC" : ""); - return INVALID_REGNUM; + return R10_REG; } /* Output assembler code to FILE to increment profiler label # LABELNO -- cgit v1.1 From 40485378ade83102d7aa30c317f5d6c90c1d232b Mon Sep 17 00:00:00 2001 From: Jakub Jelinek Date: Tue, 6 Feb 2024 22:34:55 +0100 Subject: c++: Disallow this specifier except for parameter declarations [PR113788] The deducing this patchset added parsing of this specifier to cp_parser_decl_specifier_seq unconditionally, but in the C++ grammar this[opt] only appears in the parameter-declaration non-terminal, so rather than checking in all the callers of cp_parser_decl_specifier_seq except for cp_parser_parameter_declaration that this specifier didn't appear I think it is far easier and closer to what the standard says to only parse this specifier when called from cp_parser_parameter_declaration. 2024-02-06 Jakub Jelinek PR c++/113788 * parser.cc (CP_PARSER_FLAGS_PARAMETER): New enumerator. (cp_parser_decl_specifier_seq): Parse RID_THIS only if CP_PARSER_FLAGS_PARAMETER is set in flags. (cp_parser_parameter_declaration): Or in CP_PARSER_FLAGS_PARAMETER when calling cp_parser_decl_specifier_seq. * g++.dg/parse/pr113788.C: New test. --- gcc/cp/parser.cc | 8 +++++--- gcc/testsuite/g++.dg/parse/pr113788.C | 20 ++++++++++++++++++++ 2 files changed, 25 insertions(+), 3 deletions(-) create mode 100644 gcc/testsuite/g++.dg/parse/pr113788.C (limited to 'gcc') diff --git a/gcc/cp/parser.cc b/gcc/cp/parser.cc index 3748ccd..c4292c4 100644 --- a/gcc/cp/parser.cc +++ b/gcc/cp/parser.cc @@ -2088,7 +2088,9 @@ enum /* When parsing of the noexcept-specifier should be delayed. */ CP_PARSER_FLAGS_DELAY_NOEXCEPT = 0x40, /* When parsing a consteval declarator. */ - CP_PARSER_FLAGS_CONSTEVAL = 0x80 + CP_PARSER_FLAGS_CONSTEVAL = 0x80, + /* When parsing a parameter declaration. */ + CP_PARSER_FLAGS_PARAMETER = 0x100 }; /* This type is used for parameters and variables which hold @@ -16342,7 +16344,7 @@ cp_parser_decl_specifier_seq (cp_parser* parser, /* Special case for "this" specifier, indicating a parm is an xobj parm. The "this" specifier must be the first specifier in the declaration, after any attributes. */ - if (token->keyword == RID_THIS) + if (token->keyword == RID_THIS && (flags & CP_PARSER_FLAGS_PARAMETER)) { cp_lexer_consume_token (parser->lexer); if (token != first_specifier) @@ -25607,7 +25609,7 @@ cp_parser_parameter_declaration (cp_parser *parser, /* Parse the declaration-specifiers. */ cp_token *decl_spec_token_start = cp_lexer_peek_token (parser->lexer); cp_parser_decl_specifier_seq (parser, - flags, + flags | CP_PARSER_FLAGS_PARAMETER, &decl_specifiers, &declares_class_or_enum); diff --git a/gcc/testsuite/g++.dg/parse/pr113788.C b/gcc/testsuite/g++.dg/parse/pr113788.C new file mode 100644 index 0000000..d255037 --- /dev/null +++ b/gcc/testsuite/g++.dg/parse/pr113788.C @@ -0,0 +1,20 @@ +// PR c++/113788 +// { dg-do compile { target c++11 } } + +struct S { int a, b; }; +struct U { + void foo () { this int g = 1; } // { dg-error "expected ';' before 'int'" } +}; +this auto h = 1; // { dg-error "expected unqualified-id before 'this'" } + +int +main () +{ + S s = { 1, 2 }; + short t[3] = { 3, 4, 5 }; + this auto &[a, b] = s; // { dg-error "invalid use of 'this' in non-member function" } + this auto &[c, d, e] = t; // { dg-error "invalid use of 'this' in non-member function" } + this int f = 1; // { dg-error "invalid use of 'this' in non-member function" } + for (this auto &i : t) // { dg-error "invalid use of 'this' in non-member function" } + ; // { dg-error "expected" } +} // { dg-error "expected" } -- cgit v1.1 From 3e4c4c5edf6114c2188066ba595202cf05c81147 Mon Sep 17 00:00:00 2001 From: GCC Administrator Date: Wed, 7 Feb 2024 00:18:31 +0000 Subject: Daily bump. --- gcc/ChangeLog | 54 +++++++++++++++++++++++++++++++++++++++++++++++++ gcc/DATESTAMP | 2 +- gcc/cp/ChangeLog | 19 +++++++++++++++++ gcc/testsuite/ChangeLog | 42 ++++++++++++++++++++++++++++++++++++++ 4 files changed, 116 insertions(+), 1 deletion(-) (limited to 'gcc') diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 0e3ac48..4997309 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,57 @@ +2024-02-06 H.J. Lu + + PR target/113689 + * config/i386/i386.cc (x86_64_select_profile_regnum): Return + R10_REG after sorry. + +2024-02-06 Andrew Carlotti + + * config/aarch64/aarch64.cc (aarch64_mangle_decl_assembler_name): + Move before new caller, and add ".default" suffix. + (get_suffixed_assembler_name): New. + (make_resolver_func): Use get_suffixed_assembler_name. + (aarch64_generate_version_dispatcher_body): Redo name mangling. + +2024-02-06 Jakub Jelinek + + PR target/113763 + * config/aarch64/aarch64.cc (aarch64_output_sme_zero_za): Change tiles + element from std::pair to an unnamed struct. + Adjust uses of tile range variable. + +2024-02-06 Juzhe-Zhong + + * config/riscv/riscv-vsetvl.cc (pre_vsetvl::emit_vsetvl): Fix inifinite compilation. + (pre_vsetvl::remove_vsetvl_pre_insns): Ditto. + +2024-02-06 Jakub Jelinek + + PR sanitizer/110676 + * gimple-fold.cc (gimple_fold_builtin_strlen): For -fsanitize=address + reset maxlen to sizetype maximum. + +2024-02-06 Jakub Jelinek + + PR tree-optimization/113736 + * gimple-lower-bitint.cc (bitint_large_huge::limb_access): Use + var's address space for MEM_REF or VIEW_CONVERT_EXPRs. + +2024-02-06 Jakub Jelinek + + PR tree-optimization/113759 + * tree-ssa-math-opts.cc (convert_mult_to_widen): If actual_precision + or from_unsignedN differs from properties of typeN, update typeN + to build_nonstandard_integer_type. If TREE_TYPE (rhsN) is not + uselessly convertible to typeN, convert it using fold_convert or + build_and_insert_cast depending on if rhsN is INTEGER_CST or not. + (convert_plusminus_to_widen): Likewise. + +2024-02-06 Tejas Belagod + + PR target/112577 + * config/aarch64/aarch64.cc (aarch64_class_max_nregs): Handle 64-bit + vector structure modes correctly. + 2024-02-05 Christoph Müllner * config/riscv/thead.cc (th_print_operand_address): Fix compiler diff --git a/gcc/DATESTAMP b/gcc/DATESTAMP index 14a359f..fb89643 100644 --- a/gcc/DATESTAMP +++ b/gcc/DATESTAMP @@ -1 +1 @@ -20240206 +20240207 diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index 452a70c..8a63a36 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,3 +1,22 @@ +2024-02-06 Jakub Jelinek + + PR c++/113788 + * parser.cc (CP_PARSER_FLAGS_PARAMETER): New enumerator. + (cp_parser_decl_specifier_seq): Parse RID_THIS only if + CP_PARSER_FLAGS_PARAMETER is set in flags. + (cp_parser_parameter_declaration): Or in CP_PARSER_FLAGS_PARAMETER + when calling cp_parser_decl_specifier_seq. + +2024-02-06 Marek Polacek + + * method.cc (early_check_defaulted_comparison): Add + auto_diagnostic_group. + +2024-02-06 Jason Merrill + + PR c++/107291 + * method.cc (early_check_defaulted_comparison): Fail if not friend. + 2024-02-05 Jason Merrill PR c++/111286 diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index a824e23..3fb20ec 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,45 @@ +2024-02-06 Jakub Jelinek + + PR c++/113788 + * g++.dg/parse/pr113788.C: New test. + +2024-02-06 Marek Polacek + + PR c++/94231 + * g++.dg/cpp0x/deleted17.C: New test. + +2024-02-06 Andrew Carlotti + + * g++.target/aarch64/mv-symbols1.C: New test. + * g++.target/aarch64/mv-symbols2.C: Ditto. + * g++.target/aarch64/mv-symbols3.C: Ditto. + * g++.target/aarch64/mv-symbols4.C: Ditto. + * g++.target/aarch64/mv-symbols5.C: Ditto. + * g++.target/aarch64/mvc-symbols1.C: Ditto. + * g++.target/aarch64/mvc-symbols2.C: Ditto. + * g++.target/aarch64/mvc-symbols3.C: Ditto. + * g++.target/aarch64/mvc-symbols4.C: Ditto. + +2024-02-06 Jakub Jelinek + + PR sanitizer/110676 + * gcc.dg/asan/pr110676.c: New test. + +2024-02-06 Jakub Jelinek + + PR tree-optimization/113736 + * gcc.dg/bitint-86.c: New test. + +2024-02-06 Jakub Jelinek + + PR tree-optimization/113759 + * gcc.c-torture/compile/pr113759.c: New test. + +2024-02-06 Jason Merrill + + PR c++/107291 + * g++.dg/cpp2a/spaceship-eq17.C: New test. + 2024-02-05 Jason Merrill PR c++/109359 -- cgit v1.1 From db5c3f6d952bc3950d23c0a6be4e8ec9147ef752 Mon Sep 17 00:00:00 2001 From: Pan Li Date: Tue, 6 Feb 2024 15:35:02 +0800 Subject: RISC-V: Bugfix for RVV overloaded intrinisc ICE when empty args There is one corn case when similar as below example: void test (void) { __riscv_vfredosum_tu (); } It will meet ICE because of the implement details of overloaded function in gcc. According to the rvv intrinisc doc, we have no such overloaded function with empty args. Unfortunately, we register the empty args function as overloaded for avoiding conflict. Thus, there will be actual one register function after return NULL_TREE back to the middle-end, and finally result in ICE when expanding. For example: 1. First we registered void __riscv_vfredmax () as the overloaded function. 2. Then resolve_overloaded_builtin (this func) return NULL_TREE. 3. The functions register in step 1 bypass the args check as empty args. 4. Finally, fall into expand_builtin with empty args and meet ICE. Here we report error when overloaded function with empty args. For example: test.c: In function 'foo': test.c:8:3: error: no matching function call to '__riscv_vfredosum_tu' with empty args 8 | __riscv_vfredosum_tu(); | ^~~~~~~~~~~~~~~~~~~~ Below test are passed for this patch. * The riscv regression tests. PR target/113766 gcc/ChangeLog: * config/riscv/riscv-protos.h (resolve_overloaded_builtin): Adjust the signature of func. * config/riscv/riscv-c.cc (riscv_resolve_overloaded_builtin): Ditto. * config/riscv/riscv-vector-builtins.cc (resolve_overloaded_builtin): Make overloaded func with empty args error. gcc/testsuite/ChangeLog: * gcc.target/riscv/rvv/base/pr113766-1.c: New test. * gcc.target/riscv/rvv/base/pr113766-2.c: New test. Signed-off-by: Pan Li --- gcc/config/riscv/riscv-c.cc | 3 +- gcc/config/riscv/riscv-protos.h | 2 +- gcc/config/riscv/riscv-vector-builtins.cc | 23 +++++- .../gcc.target/riscv/rvv/base/pr113766-1.c | 85 ++++++++++++++++++++++ .../gcc.target/riscv/rvv/base/pr113766-2.c | 48 ++++++++++++ 5 files changed, 155 insertions(+), 6 deletions(-) create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/pr113766-1.c create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/pr113766-2.c (limited to 'gcc') diff --git a/gcc/config/riscv/riscv-c.cc b/gcc/config/riscv/riscv-c.cc index 2e30605..94c3871 100644 --- a/gcc/config/riscv/riscv-c.cc +++ b/gcc/config/riscv/riscv-c.cc @@ -250,7 +250,8 @@ riscv_resolve_overloaded_builtin (unsigned int uncast_location, tree fndecl, case RISCV_BUILTIN_GENERAL: break; case RISCV_BUILTIN_VECTOR: - new_fndecl = riscv_vector::resolve_overloaded_builtin (subcode, arglist); + new_fndecl = riscv_vector::resolve_overloaded_builtin (loc, subcode, + fndecl, arglist); break; default: gcc_unreachable (); diff --git a/gcc/config/riscv/riscv-protos.h b/gcc/config/riscv/riscv-protos.h index b3f0bdb..ae16858 100644 --- a/gcc/config/riscv/riscv-protos.h +++ b/gcc/config/riscv/riscv-protos.h @@ -560,7 +560,7 @@ gimple *gimple_fold_builtin (unsigned int, gimple_stmt_iterator *, gcall *); rtx expand_builtin (unsigned int, tree, rtx); bool check_builtin_call (location_t, vec, unsigned int, tree, unsigned int, tree *); -tree resolve_overloaded_builtin (unsigned int, vec *); +tree resolve_overloaded_builtin (location_t, unsigned int, tree, vec *); bool const_vec_all_same_in_range_p (rtx, HOST_WIDE_INT, HOST_WIDE_INT); bool legitimize_move (rtx, rtx *); void emit_vlmax_vsetvl (machine_mode, rtx); diff --git a/gcc/config/riscv/riscv-vector-builtins.cc b/gcc/config/riscv/riscv-vector-builtins.cc index 403e102..efcdc8f 100644 --- a/gcc/config/riscv/riscv-vector-builtins.cc +++ b/gcc/config/riscv/riscv-vector-builtins.cc @@ -4606,7 +4606,8 @@ check_builtin_call (location_t location, vec, unsigned int code, } tree -resolve_overloaded_builtin (unsigned int code, vec *arglist) +resolve_overloaded_builtin (location_t loc, unsigned int code, tree fndecl, + vec *arglist) { if (code >= vec_safe_length (registered_functions)) return NULL_TREE; @@ -4616,12 +4617,26 @@ resolve_overloaded_builtin (unsigned int code, vec *arglist) if (!rfun || !rfun->overloaded_p) return NULL_TREE; + /* According to the rvv intrinisc doc, we have no such overloaded function + with empty args. Unfortunately, we register the empty args function as + overloaded for avoiding conflict. Thus, there will actual one register + function after return NULL_TREE back to the middle-end, and finally result + in ICE when expanding. For example: + + 1. First we registered void __riscv_vfredmax () as the overloaded function. + 2. Then resolve_overloaded_builtin (this func) return NULL_TREE. + 3. The functions register in step 1 bypass the args check as empty args. + 4. Finally, fall into expand_builtin with empty args and meet ICE. + + Here we report error when overloaded function with empty args. */ + if (rfun->overloaded_p && arglist->length () == 0) + error_at (loc, "no matching function call to %qE with empty args", fndecl); + hashval_t hash = rfun->overloaded_hash (*arglist); registered_function *rfn = non_overloaded_function_table->find_with_hash (rfun, hash); - if (rfn) - return rfn->decl; - return NULL_TREE; + + return rfn ? rfn->decl : NULL_TREE; } function_instance diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/pr113766-1.c b/gcc/testsuite/gcc.target/riscv/rvv/base/pr113766-1.c new file mode 100644 index 0000000..bd4943b --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/rvv/base/pr113766-1.c @@ -0,0 +1,85 @@ +/* { dg-do compile } */ +/* { dg-options "-march=rv64gcv_zvfh -mabi=lp64 -O3" } */ + +#include "riscv_vector.h" + +void +test () +{ + __riscv_vand (); /* { dg-error {no matching function call to '__riscv_vand' with empty args} } */ + __riscv_vand_tu (); /* { dg-error {no matching function call to '__riscv_vand_tu' with empty args} } */ + __riscv_vand_tumu (); /* { dg-error {no matching function call to '__riscv_vand_tumu' with empty args} } */ + + __riscv_vcompress (); /* { dg-error {no matching function call to '__riscv_vcompress' with empty args} } */ + __riscv_vcompress_tu (); /* { dg-error {no matching function call to '__riscv_vcompress_tu' with empty args} } */ + + __riscv_vcpop (); /* { dg-error {no matching function call to '__riscv_vcpop' with empty args} } */ + + __riscv_vdiv (); /* { dg-error {no matching function call to '__riscv_vdiv' with empty args} } */ + __riscv_vdiv_tu (); /* { dg-error {no matching function call to '__riscv_vdiv_tu' with empty args} } */ + __riscv_vdiv_tumu (); /* { dg-error {no matching function call to '__riscv_vdiv_tumu' with empty args} } */ + + __riscv_vfabs (); /* { dg-error {no matching function call to '__riscv_vfabs' with empty args} } */ + __riscv_vfabs_tu (); /* { dg-error {no matching function call to '__riscv_vfabs_tu' with empty args} } */ + __riscv_vfabs_tumu (); /* { dg-error {no matching function call to '__riscv_vfabs_tumu' with empty args} } */ + + __riscv_vfadd (); /* { dg-error {no matching function call to '__riscv_vfadd' with empty args} } */ + __riscv_vfadd_tu (); /* { dg-error {no matching function call to '__riscv_vfadd_tu' with empty args} } */ + __riscv_vfadd_tumu (); /* { dg-error {no matching function call to '__riscv_vfadd_tumu' with empty args} } */ + + __riscv_vfclass (); /* { dg-error {no matching function call to '__riscv_vfclass' with empty args} } */ + __riscv_vfclass_tu (); /* { dg-error {no matching function call to '__riscv_vfclass_tu' with empty args} } */ + __riscv_vfclass_tumu (); /* { dg-error {no matching function call to '__riscv_vfclass_tumu' with empty args} } */ + + __riscv_vfcvt_x (); /* { dg-error {no matching function call to '__riscv_vfcvt_x' with empty args} } */ + __riscv_vfcvt_x_tu (); /* { dg-error {no matching function call to '__riscv_vfcvt_x_tu' with empty args} } */ + __riscv_vfcvt_x_tumu (); /* { dg-error {no matching function call to '__riscv_vfcvt_x_tumu' with empty args} } */ + + __riscv_vfirst (); /* { dg-error {no matching function call to '__riscv_vfirst' with empty args} } */ + + __riscv_vfmadd (); /* { dg-error {no matching function call to '__riscv_vfmadd' with empty args} } */ + __riscv_vfmadd_tu (); /* { dg-error {no matching function call to '__riscv_vfmadd_tu' with empty args} } */ + __riscv_vfmadd_tumu (); /* { dg-error {no matching function call to '__riscv_vfmadd_tumu' with empty args} } */ + + __riscv_vfmerge (); /* { dg-error {no matching function call to '__riscv_vfmerge' with empty args} } */ + __riscv_vfmerge_tu (); /* { dg-error {no matching function call to '__riscv_vfmerge_tu' with empty args} } */ + + __riscv_vfncvt_x (); /* { dg-error {no matching function call to '__riscv_vfncvt_x' with empty args} } */ + __riscv_vfncvt_x_tu (); /* { dg-error {no matching function call to '__riscv_vfncvt_x_tu' with empty args} } */ + __riscv_vfncvt_x_tumu (); /* { dg-error {no matching function call to '__riscv_vfncvt_x_tumu' with empty args} } */ + + __riscv_vfrec7 (); /* { dg-error {no matching function call to '__riscv_vfrec7' with empty args} } */ + __riscv_vfrec7_tu (); /* { dg-error {no matching function call to '__riscv_vfrec7_tu' with empty args} } */ + __riscv_vfrec7_tumu (); /* { dg-error {no matching function call to '__riscv_vfrec7_tumu' with empty args} } */ + + __riscv_vfrsqrt7 (); /* { dg-error {no matching function call to '__riscv_vfrsqrt7' with empty args} } */ + __riscv_vfrsqrt7_tu (); /* { dg-error {no matching function call to '__riscv_vfrsqrt7_tu' with empty args} } */ + __riscv_vfrsqrt7_tumu (); /* { dg-error {no matching function call to '__riscv_vfrsqrt7_tumu' with empty args} } */ + + __riscv_vfsgnjn (); /* { dg-error {no matching function call to '__riscv_vfsgnjn' with empty args} } */ + __riscv_vfsgnjn_tu (); /* { dg-error {no matching function call to '__riscv_vfsgnjn_tu' with empty args} } */ + __riscv_vfsgnjn_tumu (); /* { dg-error {no matching function call to '__riscv_vfsgnjn_tumu' with empty args} } */ + + __riscv_vfslide1down (); /* { dg-error {no matching function call to '__riscv_vfslide1down' with empty args} } */ + __riscv_vfslide1down_tu (); /* { dg-error {no matching function call to '__riscv_vfslide1down_tu' with empty args} } */ + __riscv_vfslide1down_tumu (); /* { dg-error {no matching function call to '__riscv_vfslide1down_tumu' with empty args} } */ + + __riscv_vfwmul (); /* { dg-error {no matching function call to '__riscv_vfwmul' with empty args} } */ + __riscv_vfwmul_tu (); /* { dg-error {no matching function call to '__riscv_vfwmul_tu' with empty args} } */ + __riscv_vfwmul_tumu (); /* { dg-error {no matching function call to '__riscv_vfwmul_tumu' with empty args} } */ + + __riscv_vle32 (); /* { dg-error {no matching function call to '__riscv_vle32' with empty args} } */ + __riscv_vle32_tu (); /* { dg-error {no matching function call to '__riscv_vle32_tu' with empty args} } */ + __riscv_vle32_tumu (); /* { dg-error {no matching function call to '__riscv_vle32_tumu' with empty args} } */ + + __riscv_vlse64 (); /* { dg-error {no matching function call to '__riscv_vlse64' with empty args} } */ + __riscv_vlse64_tu (); /* { dg-error {no matching function call to '__riscv_vlse64_tu' with empty args} } */ + __riscv_vlse64_tumu (); /* { dg-error {no matching function call to '__riscv_vlse64_tumu' with empty args} } */ + + __riscv_vmfeq (); /* { dg-error {no matching function call to '__riscv_vmfeq' with empty args} } */ + + __riscv_vreinterpret_u8m1 (); /* { dg-error {no matching function call to '__riscv_vreinterpret_u8m1' with empty args} } */ + + __riscv_vfredosum (); /* { dg-error {no matching function call to '__riscv_vfredosum' with empty args} } */ + __riscv_vfredosum_tu (); /* { dg-error {no matching function call to '__riscv_vfredosum_tu' with empty args} } */ +} diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/pr113766-2.c b/gcc/testsuite/gcc.target/riscv/rvv/base/pr113766-2.c new file mode 100644 index 0000000..621fb9f --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/rvv/base/pr113766-2.c @@ -0,0 +1,48 @@ +/* { dg-do compile } */ +/* { dg-options "-march=rv64gcv_zvfh -mabi=lp64 -O3" } */ + +#include "riscv_vector.h" + +void +test (vint32m1_t vi32m1, vint64m1_t vi64m1, vfloat32m1_t vf32m1, unsigned vl) +{ + __riscv_vand (vi32m1, vl); /* { dg-error {too few arguments to function '__riscv_vand_vx_i32m1'} } */ + + __riscv_vcompress (vi32m1, vl); /* { dg-error {too many arguments to function '__riscv_vcompress'} } */ + + __riscv_vcpop (vi32m1, vl); /* { dg-error {too many arguments to function '__riscv_vcpop'} } */ + + __riscv_vdiv (vi32m1, vl); /* { dg-error {too few arguments to function '__riscv_vdiv_vx_i32m1'} } */ + + __riscv_vfabs (vf32m1); /* { dg-error {too many arguments to function '__riscv_vfabs'} } */ + + __riscv_vfadd (vf32m1, vl); /* { dg-error {too many arguments to function '__riscv_vfadd'} } */ + + __riscv_vfcvt_x (vf32m1); /* { dg-error {too many arguments to function '__riscv_vfcvt_x'} } */ + + __riscv_vfirst (vf32m1, vl); /* { dg-error {too many arguments to function '__riscv_vfirst'} } */ + + __riscv_vfmadd (vf32m1, vl); /* { dg-error {too many arguments to function '__riscv_vfmadd'} } */ + + __riscv_vfmerge (vf32m1, vl); /* { dg-error {too many arguments to function '__riscv_vfmerge'} } */ + + __riscv_vfncvt_x (vf32m1); /* { dg-error {too many arguments to function '__riscv_vfncvt_x'} } */ + + __riscv_vfrec7 (vf32m1); /* { dg-error {too many arguments to function '__riscv_vfrec7'} } */ + + __riscv_vfrsqrt7 (vf32m1); /* { dg-error {too many arguments to function '__riscv_vfrsqrt7'} } */ + + __riscv_vfsgnjn (vf32m1, vl); /* { dg-error {too few arguments to function '__riscv_vfsgnjn_vf_f32m1'} } */ + + __riscv_vfslide1down (vf32m1, vl); /* { dg-error {too few arguments to function '__riscv_vfslide1down_vf_f32m1'} } */ + + __riscv_vfwmul (vf32m1, vl); /* { dg-error {too many arguments to function '__riscv_vfwmul'} } */ + + __riscv_vle32 (vi32m1, vl); /* { dg-error {too many arguments to function '__riscv_vle32'} } */ + + __riscv_vlse64 (vi64m1, vl); /* { dg-error {too many arguments to function '__riscv_vlse64'} } */ + + __riscv_vmfeq (vf32m1, vl); /* { dg-error {too few arguments to function '__riscv_vmfeq_vf_f32m1_b32'} } */ + + __riscv_vfredosum (vf32m1, vl); /* { dg-error {too many arguments to function '__riscv_vfredosum'} } */ +} -- cgit v1.1 From d755a82079d61783eb0a573b0c74024d29359e4c Mon Sep 17 00:00:00 2001 From: Jakub Jelinek Date: Wed, 7 Feb 2024 09:44:33 +0100 Subject: wide-int: Fix mul_internal overflow handling [PR113753] As the following testcases show, the overflow (needs_overflow) and high handling in wi::mul_internal seem to only work correctly for either small precisions (less than or equal to 32, that is handled by earlier simpler code, not the full Knuth's multiplication algorithm) or for precisions which are multiple of HOST_BITS_PER_WIDE_INT, so it happened to work fine in most pre-_BitInt era types (and for large bitfields we probably didn't have good coverage or were lucky and nothing was asking if there was overflow or not; I think high multiplication is typically used only when we have optab in corresponding mode). E.g. on the gcc.dg/bitint-87.c testcase, there were overflow warnings emitted only the the / 2wb * 3wb _BitInt(128) cases, but not in the other precisions. I found 3 issues when prec > HOST_BITS_PER_HALF_WIDE_INT and (prec % HOST_BITS_PER_WIDE_INT) != 0: 1) the checking for overflow was simply checking the values of the r array members from half_blocks_needed to 2 * half_blocks_needed - 1, for UNSIGNED overflow checking if any of them is non-zero, for SIGNED comparing them if any is different from top where top is computed from the sign bit of the result (see below); similarly, the highpart multiplication simply picks the half limbs at r + half_blocks_needed offset; and furthermore, for SIGNED there is an adjustment if either operand was negative which also just walks r half-limbs from half_blocks_needed onwards; this works great for precisions like 64 or 128, but for precisions like 129, 159, 160 or 161 doesn't, it would need to walk the bits in the half-limbs starting right above the most significant bit of the base precision; that can be up to a whole half-limb and all but one bit from the one below it earlier 2) as the comment says, the multiplication is originally done as unsigned multiplication, with adjustment of the high bits which subtracts the other operand once: if (wi::neg_p (op1)) { b = 0; for (i = 0; i < half_blocks_needed; i++) { t = (unsigned HOST_WIDE_INT)r[i + half_blocks_needed] - (unsigned HOST_WIDE_INT)v[i] - b; r[i + half_blocks_needed] = t & HALF_INT_MASK; b = t >> (HOST_BITS_PER_WIDE_INT - 1); } } and similarly for the other one. Now, this also only works nicely if a negative operand has just a single sign bit set in the given precision; but we were unpacking the operands with wi_unpack (..., SIGNED);, so say for the negative operand in 129-bit precision, that means the least significant bit of u[half_blocks_needed - 2] (or v instead of u depending on which argument it is) is the set sign bit, but then there are 31 further copies of the sign bit in u[half_blocks_needed - 2] and further 32 copies in u[half_blocks_needed - 1]; the above adjustment for signed operands doesn't really do the right job in such cases, it would need to subtract many more times the other operand 3) the computation of top for SIGNED top = r[(half_blocks_needed) - 1]; top = SIGN_MASK (top << (HOST_BITS_PER_WIDE_INT / 2)); top &= mask; also uses the most significant bit which fits into prec of the result only if prec is multiple of HOST_BITS_PER_WIDE_INT, otherwise we need to look at a different bit and sometimes it can be also a bit in r[half_blocks_needed - 2] For 1), while for UNSIGNED overflow it could be fairly easy to check the bits above prec in r half-limbs for being non-zero, doing all the shifts also in the SIGNED adjustment code in 2 further locations and finally for the high handling (unless we want to assert one doesn't do the highpart multiply for such precisions) would be quite ugly and hard to maintain, so I instead chose (implemented in the second hunk) to shift the beyond-precision bits up such that the expectations of the rest of the code are met, that is the LSB of r[half_blocks_needed] after adjustment is the bit immediately above the precision, etc. We don't need to care about the bits it shifts out, because the multiplication will yield at most 2 * prec bits. For 2), the patch changes the wi_unpack argument from SIGNED to UNSIGNED, so that we get all zero bits above the precision. And finally for 3) it does shifts and perhaps picks lower r half-limb so that it uses the actual MSB of the result within prec. 2024-02-07 Jakub Jelinek PR tree-optimization/113753 * wide-int.cc (wi::mul_internal): Unpack op1val and op2val with UNSIGNED rather than SIGNED. If high or needs_overflow and prec is not a multiple of HOST_BITS_PER_WIDE_INT, shift left bits above prec so that they start with r[half_blocks_needed] lowest bit. Fix up computation of top mask for SIGNED. * gcc.dg/torture/bitint-56.c: New test. * gcc.dg/bitint-87.c: New test. --- gcc/testsuite/gcc.dg/bitint-87.c | 24 ++++++++++++++++++++++ gcc/testsuite/gcc.dg/torture/bitint-56.c | 25 +++++++++++++++++++++++ gcc/wide-int.cc | 34 ++++++++++++++++++++++++++++---- 3 files changed, 79 insertions(+), 4 deletions(-) create mode 100644 gcc/testsuite/gcc.dg/bitint-87.c create mode 100644 gcc/testsuite/gcc.dg/torture/bitint-56.c (limited to 'gcc') diff --git a/gcc/testsuite/gcc.dg/bitint-87.c b/gcc/testsuite/gcc.dg/bitint-87.c new file mode 100644 index 0000000..4dbd7ee --- /dev/null +++ b/gcc/testsuite/gcc.dg/bitint-87.c @@ -0,0 +1,24 @@ +/* PR tree-optimization/113753 */ +/* { dg-do compile { target bitint575 } } */ +/* { dg-options "-std=gnu23" } */ + +_BitInt(161) a = 1461501637330902918203684832716283019655932542975wb / 2wb * 2wb; +_BitInt(160) b = 730750818665451459101842416358141509827966271487wb / 2wb * 2wb; +_BitInt(159) c = 365375409332725729550921208179070754913983135743wb / 2wb * 2wb; +_BitInt(129) d = 340282366920938463463374607431768211455wb / 2wb * 2wb; +_BitInt(128) e = 170141183460469231731687303715884105727wb / 2wb * 2wb; +_BitInt(161) f = (-1461501637330902918203684832716283019655932542975wb - 1wb) / 2wb * 2wb; +_BitInt(160) g = (-730750818665451459101842416358141509827966271487wb - 1wb) / 2wb * 2wb; +_BitInt(159) h = (-365375409332725729550921208179070754913983135743wb - 1wb) / 2wb * 2wb; +_BitInt(129) i = (-340282366920938463463374607431768211455wb - 1wb) / 2wb * 2wb; +_BitInt(128) j = (-170141183460469231731687303715884105727wb - 1wb) / 2wb * 2wb; +_BitInt(161) k = 1461501637330902918203684832716283019655932542975wb / 2wb * 3wb; /* { dg-warning "integer overflow in expression of type '_BitInt\\\(161\\\)' results in" } */ +_BitInt(160) l = 730750818665451459101842416358141509827966271487wb / 2wb * 3wb; /* { dg-warning "integer overflow in expression of type '_BitInt\\\(160\\\)' results in" } */ +_BitInt(159) m = 365375409332725729550921208179070754913983135743wb / 2wb * 3wb; /* { dg-warning "integer overflow in expression of type '_BitInt\\\(159\\\)' results in" } */ +_BitInt(129) n = 340282366920938463463374607431768211455wb / 2wb * 3wb; /* { dg-warning "integer overflow in expression of type '_BitInt\\\(129\\\)' results in" } */ +_BitInt(128) o = 170141183460469231731687303715884105727wb / 2wb * 3wb; /* { dg-warning "integer overflow in expression of type '_BitInt\\\(128\\\)' results in" } */ +_BitInt(161) p = (-1461501637330902918203684832716283019655932542975wb - 1wb) / 2wb * 3wb; /* { dg-warning "integer overflow in expression of type '_BitInt\\\(161\\\)' results in" } */ +_BitInt(160) q = (-730750818665451459101842416358141509827966271487wb - 1wb) / 2wb * 3wb; /* { dg-warning "integer overflow in expression of type '_BitInt\\\(160\\\)' results in" } */ +_BitInt(159) r = (-365375409332725729550921208179070754913983135743wb - 1wb) / 2wb * 3wb; /* { dg-warning "integer overflow in expression of type '_BitInt\\\(159\\\)' results in" } */ +_BitInt(129) s = (-340282366920938463463374607431768211455wb - 1wb) / 2wb * 3wb; /* { dg-warning "integer overflow in expression of type '_BitInt\\\(129\\\)' results in" } */ +_BitInt(128) t = (-170141183460469231731687303715884105727wb - 1wb) / 2wb * 3wb; /* { dg-warning "integer overflow in expression of type '_BitInt\\\(128\\\)' results in" } */ diff --git a/gcc/testsuite/gcc.dg/torture/bitint-56.c b/gcc/testsuite/gcc.dg/torture/bitint-56.c new file mode 100644 index 0000000..6a76a81 --- /dev/null +++ b/gcc/testsuite/gcc.dg/torture/bitint-56.c @@ -0,0 +1,25 @@ +/* PR tree-optimization/113753 */ +/* { dg-do run { target bitint } } */ +/* { dg-options "-std=c23 -pedantic-errors" } */ +/* { dg-skip-if "" { ! run_expensive_tests } { "*" } { "-O0" "-O2" } } */ +/* { dg-skip-if "" { ! run_expensive_tests } { "-flto" } { "" } } */ + +#if __BITINT_MAXWIDTH__ >= 129 +unsigned _BitInt(128) +foo (unsigned u, unsigned _BitInt(128) a, unsigned _BitInt(128) b) +{ + unsigned _BitInt(129) m = a % b; + return u * m / u; +} +#endif + +int +main () +{ +#if __BITINT_MAXWIDTH__ >= 129 + if (foo (0xfa637c33, 0x37af7fe8b0000000000000000wb, + 0xfffffffff0000000000000000wb) + != 0x16f7e93f6d726b38b38d0b753wb) + __builtin_abort (); +#endif +} diff --git a/gcc/wide-int.cc b/gcc/wide-int.cc index 5067493d..a8a6443 100644 --- a/gcc/wide-int.cc +++ b/gcc/wide-int.cc @@ -1483,8 +1483,8 @@ wi::mul_internal (HOST_WIDE_INT *val, const HOST_WIDE_INT *op1val, } /* We do unsigned mul and then correct it. */ - wi_unpack (u, op1val, op1len, half_blocks_needed, prec, SIGNED); - wi_unpack (v, op2val, op2len, half_blocks_needed, prec, SIGNED); + wi_unpack (u, op1val, op1len, half_blocks_needed, prec, UNSIGNED); + wi_unpack (v, op2val, op2len, half_blocks_needed, prec, UNSIGNED); /* The 2 is for a full mult. */ memset (r, 0, half_blocks_needed * 2 @@ -1503,6 +1503,28 @@ wi::mul_internal (HOST_WIDE_INT *val, const HOST_WIDE_INT *op1val, r[j + half_blocks_needed] = k; } + unsigned int shift; + if ((high || needs_overflow) && (shift = prec % HOST_BITS_PER_WIDE_INT) != 0) + { + /* The high or needs_overflow code assumes that the high bits + only appear from r[half_blocks_needed] up to + r[half_blocks_needed * 2 - 1]. If prec is not a multiple + of HOST_BITS_PER_WIDE_INT, shift the bits above prec up + to make that code simple. */ + if (shift == HOST_BITS_PER_HALF_WIDE_INT) + memmove (&r[half_blocks_needed], &r[half_blocks_needed - 1], + sizeof (r[0]) * half_blocks_needed); + else + { + unsigned int skip = shift < HOST_BITS_PER_HALF_WIDE_INT; + if (!skip) + shift -= HOST_BITS_PER_HALF_WIDE_INT; + for (i = 2 * half_blocks_needed - 1; i >= half_blocks_needed; i--) + r[i] = ((r[i - skip] << (-shift % HOST_BITS_PER_HALF_WIDE_INT)) + | (r[i - skip - 1] >> shift)); + } + } + /* We did unsigned math above. For signed we must adjust the product (assuming we need to see that). */ if (sgn == SIGNED && (high || needs_overflow)) @@ -1543,8 +1565,12 @@ wi::mul_internal (HOST_WIDE_INT *val, const HOST_WIDE_INT *op1val, top = 0; else { - top = r[(half_blocks_needed) - 1]; - top = SIGN_MASK (top << (HOST_BITS_PER_WIDE_INT / 2)); + top = r[half_blocks_needed - 1 + - ((-prec % HOST_BITS_PER_WIDE_INT) + >= HOST_BITS_PER_HALF_WIDE_INT)]; + top = SIGN_MASK (((unsigned HOST_WIDE_INT) top) + << (HOST_BITS_PER_WIDE_INT / 2 + + (-prec % HOST_BITS_PER_HALF_WIDE_INT))); top &= mask; } -- cgit v1.1 From 6e308d5f71a91225946c199e69708adc92404975 Mon Sep 17 00:00:00 2001 From: Rainer Orth Date: Wed, 7 Feb 2024 10:03:31 +0100 Subject: testsuite: Don't xfail gcc.dg/debug/dwarf2/inline5.c gcc.dg/debug/dwarf2/inline5.c has been XPASSing on Solaris (both SPARC and x86, 32 and 64-bit) with the native assembler since 20210429. According to gcc-testresults postings, the same is true on AIX. XPASS: gcc.dg/debug/dwarf2/inline5.c scan-assembler-not \\\\(DIE \\\\(0x([0-9a-f]*)\\\\) DW_TAG_lexical_block\\\\)[^#/!@;\\\\|]*[#/!@;\\\\|]+ +DW_AT.*DW_TAG_lexical_block\\\\)[^#/!@;\\\\|x]*x\\\\1[^#/!@;\\\\|]*[#/!@;\\\\|] +DW_AT_abstract_origin This is obviously due to commit 16683cefc636636ba6fed23fe0de89ed19bc7876 Author: Alexandre Oliva Date: Wed Apr 28 14:07:41 2021 -0300 fix asm-not pattern in dwarf2/inline5.c This patch thus removes the xfail. Tested on i386-pc-solaris2.11 (as and gas), sparc-sun-solaris2.11 (as and gas), and i686-pc-linux-gnu. 2024-02-06 Rainer Orth gcc/testsuite: * gcc.dg/debug/dwarf2/inline5.c: Don't xfail scan-assembler-not on { aix || solaris2 } && !gas. --- gcc/testsuite/gcc.dg/debug/dwarf2/inline5.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'gcc') diff --git a/gcc/testsuite/gcc.dg/debug/dwarf2/inline5.c b/gcc/testsuite/gcc.dg/debug/dwarf2/inline5.c index 3b50e9f..7dd1148 100644 --- a/gcc/testsuite/gcc.dg/debug/dwarf2/inline5.c +++ b/gcc/testsuite/gcc.dg/debug/dwarf2/inline5.c @@ -9,7 +9,7 @@ /* We do not know which is output first so look for both invalid abstract origins on the lexical blocks (knowing that the abstract instance has no attribute following the DW_TAG_lexical_block. */ -/* { dg-final { scan-assembler-not "\\(DIE \\(0x(\[0-9a-f\]*)\\) DW_TAG_lexical_block\\)\[^#/!@;\\|\]*\[#/!@;\\|\]+ +DW_AT.*DW_TAG_lexical_block\\)\[^#/!@;\\|x\]*x\\1\[^#/!@;\\|\]*\[#/!@;\\|\] +DW_AT_abstract_origin" { xfail { { *-*-aix* || *-*-solaris2.* } && { ! gas } } } } } */ +/* { dg-final { scan-assembler-not "\\(DIE \\(0x(\[0-9a-f\]*)\\) DW_TAG_lexical_block\\)\[^#/!@;\\|\]*\[#/!@;\\|\]+ +DW_AT.*DW_TAG_lexical_block\\)\[^#/!@;\\|x\]*x\\1\[^#/!@;\\|\]*\[#/!@;\\|\] +DW_AT_abstract_origin" } } */ /* { dg-final { scan-assembler-not "DW_TAG_lexical_block\\)\[^#/!@;\\|x\]*x(\[0-9a-f\]*)\[^#/!@;\\|\]*\[#/!@;\\|\]+ +DW_AT_abstract_origin.*\\(DIE \\(0x\\1\\) DW_TAG_lexical_block\\)\[^#/!@;\\|\]*\[#/!@;\\|\]+ +DW_AT" } } */ int foo (int i) -- cgit v1.1 From 29998cc8a21b3a52f706275923166cd1f95d0555 Mon Sep 17 00:00:00 2001 From: Jakub Jelinek Date: Wed, 7 Feb 2024 10:59:06 +0100 Subject: range-op: Fix up ABSU_EXPR handling [PR113756] ABSU_EXPR unary expr is special because it has a signed integer argument and unsigned integer result (of the same precision). The following testcase is miscompiled since ABSU_EXPR handling has been added to range-op because it uses widest_int::from with the result sign (i.e. UNSIGNED) rather than the operand sign (i.e. SIGNED), so e.g. for the 32-bit int argument mask ends up 0xffffffc1 or something similar and even when it has most significant bit in the precision set, in widest_int (tree-ssa-ccp.cc really should stop using widest_int, but that is I think stage1 task) it doesn't appear to be negative and so bit_value_unop ABSU_EXPR doesn't set the resulting mask/value from oring of the argument and its negation. Fixed thusly, not doing that for GIMPLE_BINARY_RHS because I don't know about a binary op that would need something similar. 2024-02-06 Jakub Jelinek PR tree-optimization/113756 * range-op.cc (update_known_bitmask): For GIMPLE_UNARY_RHS, use TYPE_SIGN (lh.type ()) instead of sign for widest_int::from of lh_bits value and mask. * gcc.dg/pr113756.c: New test. --- gcc/range-op.cc | 6 ++++-- gcc/testsuite/gcc.dg/pr113756.c | 36 ++++++++++++++++++++++++++++++++++++ 2 files changed, 40 insertions(+), 2 deletions(-) create mode 100644 gcc/testsuite/gcc.dg/pr113756.c (limited to 'gcc') diff --git a/gcc/range-op.cc b/gcc/range-op.cc index 9a1a3c8..4ccb86e 100644 --- a/gcc/range-op.cc +++ b/gcc/range-op.cc @@ -435,8 +435,10 @@ update_known_bitmask (irange &r, tree_code code, bit_value_unop (code, sign, prec, &widest_value, &widest_mask, TYPE_SIGN (lh.type ()), TYPE_PRECISION (lh.type ()), - widest_int::from (lh_bits.value (), sign), - widest_int::from (lh_bits.mask (), sign)); + widest_int::from (lh_bits.value (), + TYPE_SIGN (lh.type ())), + widest_int::from (lh_bits.mask (), + TYPE_SIGN (lh.type ()))); break; case GIMPLE_BINARY_RHS: bit_value_binop (code, sign, prec, &widest_value, &widest_mask, diff --git a/gcc/testsuite/gcc.dg/pr113756.c b/gcc/testsuite/gcc.dg/pr113756.c new file mode 100644 index 0000000..1444220 --- /dev/null +++ b/gcc/testsuite/gcc.dg/pr113756.c @@ -0,0 +1,36 @@ +/* PR tree-optimization/113756 */ +/* { dg-do run { target int32plus } } */ +/* { dg-options "-O2" } */ + +int d, e, i, k, l = -8; +signed char h, j; + +int +bar (int n, int o, int p3) +{ + int a = o - p3, b = n - p3, c = a + b, f = -b, g = c < 0 ? -c : c; + return a <= f && a <= g ? o : p3; +} + +void +foo (int *n, unsigned short o) +{ + unsigned p = 8896; + for (; e >= 0; e--) + p = 5377; + for (; h <= 0; h++) + for (; j <= 0; j++) + { + *n = 1611581749; + i = bar (34, p - 5294, *n - 1611581687); + k = i + p + 65535 + o + *n - 1611718251; + if (k != 0) + __builtin_abort (); + } +} + +int +main () +{ + foo (&l, l); +} -- cgit v1.1 From 194d0956ef5992d4e453bde3eb5772dc077f610c Mon Sep 17 00:00:00 2001 From: Tamar Christina Date: Wed, 7 Feb 2024 10:57:05 +0000 Subject: middle-end: add additional runtime test for [PR113467] This just adds an additional runtime testcase for the fixed issue. gcc/testsuite/ChangeLog: PR tree-optimization/113467 * gcc.dg/vect/vect-early-break_110-pr113467.c: New test. --- .../gcc.dg/vect/vect-early-break_110-pr113467.c | 52 ++++++++++++++++++++++ 1 file changed, 52 insertions(+) create mode 100644 gcc/testsuite/gcc.dg/vect/vect-early-break_110-pr113467.c (limited to 'gcc') diff --git a/gcc/testsuite/gcc.dg/vect/vect-early-break_110-pr113467.c b/gcc/testsuite/gcc.dg/vect/vect-early-break_110-pr113467.c new file mode 100644 index 0000000..1e2c47b --- /dev/null +++ b/gcc/testsuite/gcc.dg/vect/vect-early-break_110-pr113467.c @@ -0,0 +1,52 @@ +/* { dg-add-options vect_early_break } */ +/* { dg-require-effective-target vect_early_break } */ +/* { dg-require-effective-target vect_long_long } */ + +/* { dg-final { scan-tree-dump-not "LOOP VECTORIZED" "vect" } } */ + +#include "tree-vect.h" +#include + +typedef struct gcry_mpi *gcry_mpi_t; +struct gcry_mpi { + int nlimbs; + unsigned long *d; +}; + +long gcry_mpi_add_ui_up; +void gcry_mpi_add_ui(gcry_mpi_t w, gcry_mpi_t u, unsigned v) { + gcry_mpi_add_ui_up = *w->d; + if (u) { + uint64_t *res_ptr = w->d, *s1_ptr = w->d; + int s1_size = u->nlimbs; + unsigned s2_limb = v, x = *s1_ptr++; + s2_limb += x; + *res_ptr++ = s2_limb; + if (x) + while (--s1_size) { + x = *s1_ptr++ + 1; + *res_ptr++ = x; + if (x) { + break; + } + } + } +} + +int main() +{ + check_vect (); + + static struct gcry_mpi sv; + static uint64_t vals[] = {4294967288ULL, 191ULL, 4160749568ULL, 4294963263ULL, + 127ULL, 4294950912ULL, 255ULL, 4294901760ULL, + 534781951ULL, 33546240ULL, 4294967292ULL, 4294960127ULL, + 4292872191ULL, 4294967295ULL, 4294443007ULL, 3ULL}; + gcry_mpi_t v = &sv; + v->nlimbs = 16; + v->d = vals; + + gcry_mpi_add_ui(v, v, 8); + if (v->d[1] != 192) + __builtin_abort(); +} -- cgit v1.1 From 8f6ed71d8fff3c3c6249651a72aee084e31ffb9e Mon Sep 17 00:00:00 2001 From: Tamar Christina Date: Wed, 7 Feb 2024 10:58:25 +0000 Subject: middle-end: fix ICE when moving statements to empty BB [PR113731] We use gsi_move_before (&stmt_gsi, &dest_gsi); to request that the new statement be placed before any other statement. Typically this then moves the current pointer to be after the statement we just inserted. However it looks like when the BB is empty, this does not happen and the CUR pointer stays NULL. There's a comment in the source of gsi_insert_before that explains: /* If CUR is NULL, we link at the end of the sequence (this case happens This adds a default parameter to gsi_move_before to allow us to control where the insertion happens. gcc/ChangeLog: PR tree-optimization/113731 * gimple-iterator.cc (gsi_move_before): Take new parameter for update method. * gimple-iterator.h (gsi_move_before): Default new param to GSI_SAME_STMT. * tree-vect-loop.cc (move_early_exit_stmts): Call gsi_move_before with GSI_NEW_STMT. gcc/testsuite/ChangeLog: PR tree-optimization/113731 * gcc.dg/vect/vect-early-break_111-pr113731.c: New test. --- gcc/gimple-iterator.cc | 7 ++++--- gcc/gimple-iterator.h | 3 ++- .../gcc.dg/vect/vect-early-break_111-pr113731.c | 22 ++++++++++++++++++++++ gcc/tree-vect-loop.cc | 3 +-- 4 files changed, 29 insertions(+), 6 deletions(-) create mode 100644 gcc/testsuite/gcc.dg/vect/vect-early-break_111-pr113731.c (limited to 'gcc') diff --git a/gcc/gimple-iterator.cc b/gcc/gimple-iterator.cc index 517c533..55ef319 100644 --- a/gcc/gimple-iterator.cc +++ b/gcc/gimple-iterator.cc @@ -666,10 +666,11 @@ gsi_move_after (gimple_stmt_iterator *from, gimple_stmt_iterator *to) /* Move the statement at FROM so it comes right before the statement - at TO. */ + at TO using method M. M defaults to GSI_SAME_STMT. */ void -gsi_move_before (gimple_stmt_iterator *from, gimple_stmt_iterator *to) +gsi_move_before (gimple_stmt_iterator *from, gimple_stmt_iterator *to, + gsi_iterator_update m) { gimple *stmt = gsi_stmt (*from); gsi_remove (from, false); @@ -677,7 +678,7 @@ gsi_move_before (gimple_stmt_iterator *from, gimple_stmt_iterator *to) /* For consistency with gsi_move_after, it might be better to have GSI_NEW_STMT here; however, that breaks several places that expect that TO does not change. */ - gsi_insert_before (to, stmt, GSI_SAME_STMT); + gsi_insert_before (to, stmt, m); } diff --git a/gcc/gimple-iterator.h b/gcc/gimple-iterator.h index 2e83a96..78014a4 100644 --- a/gcc/gimple-iterator.h +++ b/gcc/gimple-iterator.h @@ -86,7 +86,8 @@ extern gimple_stmt_iterator gsi_for_stmt (gimple *); extern gimple_stmt_iterator gsi_for_stmt (gimple *, gimple_seq *); extern gphi_iterator gsi_for_phi (gphi *); extern void gsi_move_after (gimple_stmt_iterator *, gimple_stmt_iterator *); -extern void gsi_move_before (gimple_stmt_iterator *, gimple_stmt_iterator *); +extern void gsi_move_before (gimple_stmt_iterator *, gimple_stmt_iterator *, + gsi_iterator_update = GSI_SAME_STMT); extern void gsi_move_to_bb_end (gimple_stmt_iterator *, basic_block); extern void gsi_insert_on_edge (edge, gimple *); extern void gsi_insert_seq_on_edge (edge, gimple_seq); diff --git a/gcc/testsuite/gcc.dg/vect/vect-early-break_111-pr113731.c b/gcc/testsuite/gcc.dg/vect/vect-early-break_111-pr113731.c new file mode 100644 index 0000000..b205f47 --- /dev/null +++ b/gcc/testsuite/gcc.dg/vect/vect-early-break_111-pr113731.c @@ -0,0 +1,22 @@ +/* { dg-do compile } */ +/* { dg-add-options vect_early_break } */ +/* { dg-require-effective-target vect_early_break } */ +/* { dg-require-effective-target vect_long } */ +/* { dg-additional-options "-msse4.2" { target i?86-*-* x86_64-*-* } } */ + +/* { dg-final { scan-tree-dump "LOOP VECTORIZED" "vect" } } */ + +char* inet_net_pton_ipv4_bits; +char inet_net_pton_ipv4_odst; +void __errno_location(); +void inet_net_pton_ipv4(); +void inet_net_pton() { inet_net_pton_ipv4(); } +void inet_net_pton_ipv4(char *dst, int size) { + while ((inet_net_pton_ipv4_bits > dst) & inet_net_pton_ipv4_odst) { + if (size-- <= 0) + goto emsgsize; + *dst++ = '\0'; + } +emsgsize: + __errno_location(); +} diff --git a/gcc/tree-vect-loop.cc b/gcc/tree-vect-loop.cc index 30b90d9..9aba94b 100644 --- a/gcc/tree-vect-loop.cc +++ b/gcc/tree-vect-loop.cc @@ -11800,8 +11800,7 @@ move_early_exit_stmts (loop_vec_info loop_vinfo) dump_printf_loc (MSG_NOTE, vect_location, "moving stmt %G", stmt); gimple_stmt_iterator stmt_gsi = gsi_for_stmt (stmt); - gsi_move_before (&stmt_gsi, &dest_gsi); - gsi_prev (&dest_gsi); + gsi_move_before (&stmt_gsi, &dest_gsi, GSI_NEW_STMT); } /* Update all the stmts with their new reaching VUSES. */ -- cgit v1.1 From 5c3ba60024fedc6b3d374ebb071bcf5b3e27cd62 Mon Sep 17 00:00:00 2001 From: Tamar Christina Date: Wed, 7 Feb 2024 10:59:32 +0000 Subject: middle-end: fix ICE when destination BB for stores starts with a label [PR113750] The report shows that if the FE leaves a label as the first thing in the dest BB then we ICE because we move the stores before the label. This is easy to fix if we know that there's still only one way into the BB. We would have already rejected the loop if there was multiple paths into the BB however I added an additional check just for early break in case the other constraints are relaxed later with an explanation. After that we fix the issue just by getting the GSI after the labels and I add a bunch of testcases for different positions the label can be added. Only the vect-early-break_112-pr113750.c one results in the label being kept. gcc/ChangeLog: PR tree-optimization/113750 * tree-vect-data-refs.cc (vect_analyze_early_break_dependences): Check for single predecessor when doing early break vect. * tree-vect-loop.cc (move_early_exit_stmts): Get gsi at the start but after labels. gcc/testsuite/ChangeLog: PR tree-optimization/113750 * gcc.dg/vect/vect-early-break_112-pr113750.c: New test. * gcc.dg/vect/vect-early-break_113-pr113750.c: New test. * gcc.dg/vect/vect-early-break_114-pr113750.c: New test. * gcc.dg/vect/vect-early-break_115-pr113750.c: New test. * gcc.dg/vect/vect-early-break_116-pr113750.c: New test. --- .../gcc.dg/vect/vect-early-break_112-pr113750.c | 26 ++++++++++++++++++++++ .../gcc.dg/vect/vect-early-break_113-pr113750.c | 26 ++++++++++++++++++++++ .../gcc.dg/vect/vect-early-break_114-pr113750.c | 26 ++++++++++++++++++++++ .../gcc.dg/vect/vect-early-break_115-pr113750.c | 26 ++++++++++++++++++++++ .../gcc.dg/vect/vect-early-break_116-pr113750.c | 26 ++++++++++++++++++++++ gcc/tree-vect-data-refs.cc | 12 ++++++++++ gcc/tree-vect-loop.cc | 2 +- 7 files changed, 143 insertions(+), 1 deletion(-) create mode 100644 gcc/testsuite/gcc.dg/vect/vect-early-break_112-pr113750.c create mode 100644 gcc/testsuite/gcc.dg/vect/vect-early-break_113-pr113750.c create mode 100644 gcc/testsuite/gcc.dg/vect/vect-early-break_114-pr113750.c create mode 100644 gcc/testsuite/gcc.dg/vect/vect-early-break_115-pr113750.c create mode 100644 gcc/testsuite/gcc.dg/vect/vect-early-break_116-pr113750.c (limited to 'gcc') diff --git a/gcc/testsuite/gcc.dg/vect/vect-early-break_112-pr113750.c b/gcc/testsuite/gcc.dg/vect/vect-early-break_112-pr113750.c new file mode 100644 index 0000000..559ebd8 --- /dev/null +++ b/gcc/testsuite/gcc.dg/vect/vect-early-break_112-pr113750.c @@ -0,0 +1,26 @@ +/* { dg-do compile } */ +/* { dg-add-options vect_early_break } */ +/* { dg-require-effective-target vect_early_break } */ +/* { dg-require-effective-target vect_int } */ + +/* { dg-final { scan-tree-dump "LOOP VECTORIZED" "vect" } } */ + +#ifndef N +#define N 800 +#endif +unsigned vect_a[N]; +unsigned vect_b[N]; + +unsigned test4(unsigned x) +{ + unsigned ret = 0; + for (int i = 0; i < N; i++) + { + vect_b[i] = x + i; + if (vect_a[i] != x) + break; +foo: + vect_a[i] = x; + } + return ret; +} diff --git a/gcc/testsuite/gcc.dg/vect/vect-early-break_113-pr113750.c b/gcc/testsuite/gcc.dg/vect/vect-early-break_113-pr113750.c new file mode 100644 index 0000000..ba85780 --- /dev/null +++ b/gcc/testsuite/gcc.dg/vect/vect-early-break_113-pr113750.c @@ -0,0 +1,26 @@ +/* { dg-do compile } */ +/* { dg-add-options vect_early_break } */ +/* { dg-require-effective-target vect_early_break } */ +/* { dg-require-effective-target vect_int } */ + +/* { dg-final { scan-tree-dump "LOOP VECTORIZED" "vect" } } */ + +#ifndef N +#define N 800 +#endif +unsigned vect_a[N]; +unsigned vect_b[N]; + +unsigned test4(unsigned x) +{ + unsigned ret = 0; + for (int i = 0; i < N; i++) + { + vect_b[i] = x + i; + if (vect_a[i] != x) + break; + vect_a[i] = x; +foo: + } + return ret; +} diff --git a/gcc/testsuite/gcc.dg/vect/vect-early-break_114-pr113750.c b/gcc/testsuite/gcc.dg/vect/vect-early-break_114-pr113750.c new file mode 100644 index 0000000..37af299 --- /dev/null +++ b/gcc/testsuite/gcc.dg/vect/vect-early-break_114-pr113750.c @@ -0,0 +1,26 @@ +/* { dg-do compile } */ +/* { dg-add-options vect_early_break } */ +/* { dg-require-effective-target vect_early_break } */ +/* { dg-require-effective-target vect_int } */ + +/* { dg-final { scan-tree-dump "LOOP VECTORIZED" "vect" } } */ + +#ifndef N +#define N 800 +#endif +unsigned vect_a[N]; +unsigned vect_b[N]; + +unsigned test4(unsigned x) +{ + unsigned ret = 0; + for (int i = 0; i < N; i++) + { + vect_b[i] = x + i; +foo: + if (vect_a[i] != x) + break; + vect_a[i] = x; + } + return ret; +} diff --git a/gcc/testsuite/gcc.dg/vect/vect-early-break_115-pr113750.c b/gcc/testsuite/gcc.dg/vect/vect-early-break_115-pr113750.c new file mode 100644 index 0000000..502686d --- /dev/null +++ b/gcc/testsuite/gcc.dg/vect/vect-early-break_115-pr113750.c @@ -0,0 +1,26 @@ +/* { dg-do compile } */ +/* { dg-add-options vect_early_break } */ +/* { dg-require-effective-target vect_early_break } */ +/* { dg-require-effective-target vect_int } */ + +/* { dg-final { scan-tree-dump "LOOP VECTORIZED" "vect" } } */ + +#ifndef N +#define N 800 +#endif +unsigned vect_a[N]; +unsigned vect_b[N]; + +unsigned test4(unsigned x) +{ + unsigned ret = 0; + for (int i = 0; i < N; i++) + { +foo: + vect_b[i] = x + i; + if (vect_a[i] != x) + break; + vect_a[i] = x; + } + return ret; +} diff --git a/gcc/testsuite/gcc.dg/vect/vect-early-break_116-pr113750.c b/gcc/testsuite/gcc.dg/vect/vect-early-break_116-pr113750.c new file mode 100644 index 0000000..4e02158 --- /dev/null +++ b/gcc/testsuite/gcc.dg/vect/vect-early-break_116-pr113750.c @@ -0,0 +1,26 @@ +/* { dg-do compile } */ +/* { dg-add-options vect_early_break } */ +/* { dg-require-effective-target vect_early_break } */ +/* { dg-require-effective-target vect_int } */ + +/* { dg-final { scan-tree-dump "LOOP VECTORIZED" "vect" } } */ + +#ifndef N +#define N 800 +#endif +unsigned vect_a[N]; +unsigned vect_b[N]; + +unsigned test4(unsigned x) +{ + unsigned ret = 0; + for (int i = 0; i < N; i++) + { + vect_b[i] = x + i; + if (vect_a[i] != x) +foo: + break; + vect_a[i] = x; + } + return ret; +} diff --git a/gcc/tree-vect-data-refs.cc b/gcc/tree-vect-data-refs.cc index f79ade9..5696417 100644 --- a/gcc/tree-vect-data-refs.cc +++ b/gcc/tree-vect-data-refs.cc @@ -819,6 +819,18 @@ vect_analyze_early_break_dependences (loop_vec_info loop_vinfo) trapped already during loop form analysis. */ gcc_assert (dest_bb->loop_father == loop); + /* Check that the destination block we picked has only one pred. To relax this we + have to take special care when moving the statements. We don't currently support + such control flow however this check is there to simplify how we handle + labels that may be present anywhere in the IL. This check is to ensure that the + labels aren't significant for the CFG. */ + if (!single_pred (dest_bb)) + return opt_result::failure_at (vect_location, + "chosen loop exit block (BB %d) does not have a " + "single predecessor which is currently not " + "supported for early break vectorization.\n", + dest_bb->index); + LOOP_VINFO_EARLY_BRK_DEST_BB (loop_vinfo) = dest_bb; if (!LOOP_VINFO_EARLY_BRK_VUSES (loop_vinfo).is_empty ()) diff --git a/gcc/tree-vect-loop.cc b/gcc/tree-vect-loop.cc index 9aba94b..190df9e 100644 --- a/gcc/tree-vect-loop.cc +++ b/gcc/tree-vect-loop.cc @@ -11786,7 +11786,7 @@ move_early_exit_stmts (loop_vec_info loop_vinfo) /* Move all stmts that need moving. */ basic_block dest_bb = LOOP_VINFO_EARLY_BRK_DEST_BB (loop_vinfo); - gimple_stmt_iterator dest_gsi = gsi_start_bb (dest_bb); + gimple_stmt_iterator dest_gsi = gsi_after_labels (dest_bb); for (gimple *stmt : LOOP_VINFO_EARLY_BRK_STORES (loop_vinfo)) { -- cgit v1.1 From 830d4659604e4d0f6e908d1cdb5bf1638a60bb21 Mon Sep 17 00:00:00 2001 From: Richard Biener Date: Wed, 7 Feb 2024 09:12:33 +0100 Subject: Apply TLC to vect_analyze_early_break_dependences There has been some confusion in my understanding of how early breaks work, the following clarifies some comments and undoes one change that shouldn't have been necessary. It also fixes the dependence test to avoit TBAA (we're moving stores down across loads). * tree-vect-data-refs.cc (vect_analyze_early_break_dependences): Only check whether reads are in-bound in places that are not safe. Fix dependence check. Add missing newline. Clarify comments. --- gcc/tree-vect-data-refs.cc | 43 +++++++++++++++++++++++++------------------ 1 file changed, 25 insertions(+), 18 deletions(-) (limited to 'gcc') diff --git a/gcc/tree-vect-data-refs.cc b/gcc/tree-vect-data-refs.cc index 5696417..e1679632 100644 --- a/gcc/tree-vect-data-refs.cc +++ b/gcc/tree-vect-data-refs.cc @@ -684,9 +684,10 @@ vect_analyze_early_break_dependences (loop_vec_info loop_vinfo) /* Since we don't support general control flow, the location we'll move the side-effects to is always the latch connected exit. When we support general control flow we can do better but for now this is fine. Move - side-effects to the in-loop destination of the last early exit. For the PEELED - case we move the side-effects to the latch block as this is guaranteed to be the - last block to be executed when a vector iteration finished. */ + side-effects to the in-loop destination of the last early exit. For the + PEELED case we move the side-effects to the latch block as this is + guaranteed to be the last block to be executed when a vector iteration + finished. */ if (LOOP_VINFO_EARLY_BREAKS_VECT_PEELED (loop_vinfo)) dest_bb = loop->latch; else @@ -697,9 +698,9 @@ vect_analyze_early_break_dependences (loop_vec_info loop_vinfo) loads. */ basic_block bb = dest_bb; - /* In the peeled case we need to check all the loads in the loop since to move the - the stores we lift the stores over all loads into the latch. */ - bool check_deps = LOOP_VINFO_EARLY_BREAKS_VECT_PEELED (loop_vinfo); + /* We move stores across all loads to the beginning of dest_bb, so + the first block processed below doesn't need dependence checking. */ + bool check_deps = false; do { @@ -711,8 +712,7 @@ vect_analyze_early_break_dependences (loop_vec_info loop_vinfo) { gimple *stmt = gsi_stmt (gsi); gsi_prev (&gsi); - if (!gimple_has_ops (stmt) - || is_gimple_debug (stmt)) + if (is_gimple_debug (stmt)) continue; stmt_vec_info stmt_vinfo = loop_vinfo->lookup_stmt (stmt); @@ -720,18 +720,25 @@ vect_analyze_early_break_dependences (loop_vec_info loop_vinfo) if (!dr_ref) continue; + /* We know everything below dest_bb is safe since we know we + had a full vector iteration when reaching it. Either by + the loop entry / IV exit test being last or because this + is the loop latch itself. */ + if (!check_deps) + continue; + /* Check if vector accesses to the object will be within bounds. must be a constant or assume loop will be versioned or niters - bounded by VF so accesses are within range. We only need to check the - reads since writes are moved to a safe place where if we get there we - know they are safe to perform. */ + bounded by VF so accesses are within range. We only need to check + the reads since writes are moved to a safe place where if we get + there we know they are safe to perform. */ if (DR_IS_READ (dr_ref) && !ref_within_array_bound (stmt, DR_REF (dr_ref))) { if (dump_enabled_p ()) dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location, "early breaks not supported: vectorization " - "would %s beyond size of obj.", + "would %s beyond size of obj.\n", DR_IS_READ (dr_ref) ? "read" : "write"); return opt_result::failure_at (stmt, "can't safely apply code motion to " @@ -739,9 +746,6 @@ vect_analyze_early_break_dependences (loop_vec_info loop_vinfo) "the early exit.\n", stmt); } - if (!check_deps) - continue; - if (DR_IS_READ (dr_ref)) bases.safe_push (dr_ref); else if (DR_IS_WRITE (dr_ref)) @@ -768,7 +772,11 @@ vect_analyze_early_break_dependences (loop_vec_info loop_vinfo) the store. */ for (auto dr_read : bases) - if (dr_may_alias_p (dr_ref, dr_read, loop_nest)) + /* Note we're not passing the DRs in stmt order here + since the DR dependence checking routine does not + envision we're moving stores down. The read-write + order tricks it to avoid applying TBAA. */ + if (dr_may_alias_p (dr_read, dr_ref, loop_nest)) { if (dump_enabled_p ()) dump_printf_loc (MSG_MISSED_OPTIMIZATION, @@ -808,8 +816,7 @@ vect_analyze_early_break_dependences (loop_vec_info loop_vinfo) break; } - /* For the non-PEELED case we don't want to check the loads in the IV exit block - for dependencies with the stores, but any block preceeding it we do. */ + /* All earlier blocks need dependence checking. */ check_deps = true; bb = single_pred (bb); } -- cgit v1.1