commit 523d5a7c933efc058e5e9b7b78ab5f47193787ab Author: eastb233 Date: Sun Jan 19 17:29:40 2020 +0800 package init as gcc-7.3.0 diff --git a/Big-endian-union-bitfield-bugfix.patch b/Big-endian-union-bitfield-bugfix.patch new file mode 100644 index 0000000..a9dfcbb --- /dev/null +++ b/Big-endian-union-bitfield-bugfix.patch @@ -0,0 +1,126 @@ +From 900ccfa89dda3ab5f7e44a0dd4d1e9d108b5dc8b Mon Sep 17 00:00:00 2001 +From: rguenth +Date: Tue, 26 Mar 2019 13:18:23 +0000 +Subject: [PATCH] 2019-02-26 Richard Biener + + Backport from mainline + 2019-02-12 Richard Biener + + PR tree-optimization/89253 + * tree-ssa-loop-split.c (tree_ssa_split_loops): Check we can + duplicate the loop. + + * gfortran.dg/pr89253.f: New testcase. + + 2019-02-08 Richard Biener + + PR middle-end/89223 + * tree-data-ref.c (initialize_matrix_A): Fail if constant + doesn't fit in HWI. + (analyze_subscript_affine_affine): Handle failure from + initialize_matrix_A. + + * gcc.dg/torture/pr89223.c: New testcase. + + 2019-01-28 Richard Biener + + PR tree-optimization/88739 + * tree-ssa-sccvn.c (vn_reference_lookup_3): Avoid generating + BIT_FIELD_REFs of non-mode-precision integral operands. + + * gcc.c-torture/execute/pr88739.c: New test. + + +git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/branches/gcc-7-branch@269942 138bc75d-0d04-0410-961f-82ee72b054a4 +--- +diff --git a/gcc/tree-data-ref.c b/gcc/tree-data-ref.c +index 2480f4e..a349e3e 100644 +--- a/gcc/tree-data-ref.c ++++ b/gcc/tree-data-ref.c +@@ -2118,6 +2118,8 @@ initialize_matrix_A (lambda_matrix A, tree chrec, unsigned index, int mult) + switch (TREE_CODE (chrec)) + { + case POLYNOMIAL_CHREC: ++ if (!cst_and_fits_in_hwi (CHREC_RIGHT (chrec))) ++ return chrec_dont_know; + A[index][0] = mult * int_cst_value (CHREC_RIGHT (chrec)); + return initialize_matrix_A (A, CHREC_LEFT (chrec), index + 1, mult); + +@@ -2499,7 +2501,7 @@ analyze_subscript_affine_affine (tree chrec_a, + tree *last_conflicts) + { + unsigned nb_vars_a, nb_vars_b, dim; +- HOST_WIDE_INT init_a, init_b, gamma, gcd_alpha_beta; ++ HOST_WIDE_INT gamma, gcd_alpha_beta; + lambda_matrix A, U, S; + struct obstack scratch_obstack; + +@@ -2536,9 +2538,20 @@ analyze_subscript_affine_affine (tree chrec_a, + A = lambda_matrix_new (dim, 1, &scratch_obstack); + S = lambda_matrix_new (dim, 1, &scratch_obstack); + +- init_a = int_cst_value (initialize_matrix_A (A, chrec_a, 0, 1)); +- init_b = int_cst_value (initialize_matrix_A (A, chrec_b, nb_vars_a, -1)); +- gamma = init_b - init_a; ++ tree init_a = initialize_matrix_A (A, chrec_a, 0, 1); ++ tree init_b = initialize_matrix_A (A, chrec_b, nb_vars_a, -1); ++ if (init_a == chrec_dont_know ++ || init_b == chrec_dont_know) ++ { ++ if (dump_file && (dump_flags & TDF_DETAILS)) ++ fprintf (dump_file, "affine-affine test failed: " ++ "representation issue.\n"); ++ *overlaps_a = conflict_fn_not_known (); ++ *overlaps_b = conflict_fn_not_known (); ++ *last_conflicts = chrec_dont_know; ++ goto end_analyze_subs_aa; ++ } ++ gamma = int_cst_value (init_b) - int_cst_value (init_a); + + /* Don't do all the hard work of solving the Diophantine equation + when we already know the solution: for example, +diff --git a/gcc/tree-ssa-loop-split.c b/gcc/tree-ssa-loop-split.c +index fd97213..3992597 100644 +--- a/gcc/tree-ssa-loop-split.c ++++ b/gcc/tree-ssa-loop-split.c +@@ -649,7 +649,8 @@ tree_ssa_split_loops (void) + false, true) + && niter.cmp != ERROR_MARK + /* We can't yet handle loops controlled by a != predicate. */ +- && niter.cmp != NE_EXPR) ++ && niter.cmp != NE_EXPR ++ && can_duplicate_loop_p (loop)) + { + if (split_loop (loop, &niter)) + { +diff --git a/gcc/tree-ssa-sccvn.c b/gcc/tree-ssa-sccvn.c +index c93f1f2..a2e3ce2 100644 +--- a/gcc/tree-ssa-sccvn.c ++++ b/gcc/tree-ssa-sccvn.c +@@ -2029,6 +2029,7 @@ vn_reference_lookup_3 (ao_ref *ref, tree vuse, void *vr_, + base2 = get_ref_base_and_extent (gimple_assign_lhs (def_stmt), + &offset2, &size2, &maxsize2, + &reverse); ++ tree def_rhs = gimple_assign_rhs1 (def_stmt); + if (!reverse + && maxsize2 != -1 + && maxsize2 == size2 +@@ -2041,11 +2042,14 @@ vn_reference_lookup_3 (ao_ref *ref, tree vuse, void *vr_, + according to endianness. */ + && (! INTEGRAL_TYPE_P (vr->type) + || ref->size == TYPE_PRECISION (vr->type)) +- && ref->size % BITS_PER_UNIT == 0) ++ && ref->size % BITS_PER_UNIT == 0 ++ && (! INTEGRAL_TYPE_P (TREE_TYPE (def_rhs)) ++ || (TYPE_PRECISION (TREE_TYPE (def_rhs)) ++ == GET_MODE_PRECISION (TYPE_MODE (TREE_TYPE (def_rhs)))))) + { + code_helper rcode = BIT_FIELD_REF; + tree ops[3]; +- ops[0] = SSA_VAL (gimple_assign_rhs1 (def_stmt)); ++ ops[0] = SSA_VAL (def_rhs); + ops[1] = bitsize_int (ref->size); + ops[2] = bitsize_int (offset - offset2); + tree val = vn_nary_build_or_lookup (rcode, vr->type, ops); +-- +2.9.3 diff --git a/CVE-2018-12886.patch b/CVE-2018-12886.patch new file mode 100644 index 0000000..5e782d6 --- /dev/null +++ b/CVE-2018-12886.patch @@ -0,0 +1,655 @@ +diff -urpN a/gcc/cfgexpand.c b/gcc/cfgexpand.c +--- a/gcc/cfgexpand.c 2019-05-30 16:58:45.350508770 +0800 ++++ b/gcc/cfgexpand.c 2019-05-30 11:53:13.315156625 +0800 +@@ -6094,6 +6094,23 @@ stack_protect_prologue (void) + rtx x, y; + + x = expand_normal (crtl->stack_protect_guard); ++ ++ if (targetm.have_stack_protect_combined_set () && guard_decl) ++ { ++ gcc_assert (DECL_P (guard_decl)); ++ y = DECL_RTL (guard_decl); ++ ++ /* Allow the target to compute address of Y and copy it to X without ++ leaking Y into a register. This combined address + copy pattern ++ allows the target to prevent spilling of any intermediate results by ++ splitting it after register allocator. */ ++ if (rtx_insn *insn = targetm.gen_stack_protect_combined_set (x, y)) ++ { ++ emit_insn (insn); ++ return; ++ } ++ } ++ + if (guard_decl) + y = expand_normal (guard_decl); + else +diff -urpN a/gcc/config/arm/arm.c b/gcc/config/arm/arm.c +--- a/gcc/config/arm/arm.c 2019-05-30 16:58:45.354508770 +0800 ++++ b/gcc/config/arm/arm.c 2019-05-30 16:59:05.058508073 +0800 +@@ -7236,21 +7236,34 @@ legitimate_pic_operand_p (rtx x) + return 1; + } + +-/* Record that the current function needs a PIC register. Initialize +- cfun->machine->pic_reg if we have not already done so. */ ++/* Record that the current function needs a PIC register. If PIC_REG is null, ++ a new pseudo is allocated as PIC register, otherwise PIC_REG is used. In ++ both case cfun->machine->pic_reg is initialized if we have not already done ++ so. COMPUTE_NOW decide whether and where to set the PIC register. If true, ++ PIC register is reloaded in the current position of the instruction stream ++ irregardless of whether it was loaded before. Otherwise, it is only loaded ++ if not already done so (crtl->uses_pic_offset_table is null). Note that ++ nonnull PIC_REG is only supported iff COMPUTE_NOW is true and null PIC_REG ++ is only supported iff COMPUTE_NOW is false. */ + + static void +-require_pic_register (void) ++require_pic_register (rtx pic_reg, bool compute_now) + { ++ gcc_assert (compute_now == (pic_reg != NULL_RTX)); ++ + /* A lot of the logic here is made obscure by the fact that this + routine gets called as part of the rtx cost estimation process. + We don't want those calls to affect any assumptions about the real + function; and further, we can't call entry_of_function() until we + start the real expansion process. */ +- if (!crtl->uses_pic_offset_table) ++ if (!crtl->uses_pic_offset_table || compute_now) + { +- gcc_assert (can_create_pseudo_p ()); ++ gcc_assert (can_create_pseudo_p () ++ || (pic_reg != NULL_RTX ++ && REG_P (pic_reg) ++ && GET_MODE (pic_reg) == Pmode)); + if (arm_pic_register != INVALID_REGNUM ++ && !compute_now + && !(TARGET_THUMB1 && arm_pic_register > LAST_LO_REGNUM)) + { + if (!cfun->machine->pic_reg) +@@ -7266,8 +7279,19 @@ require_pic_register (void) + { + rtx_insn *seq, *insn; + +- if (!cfun->machine->pic_reg) +- cfun->machine->pic_reg = gen_reg_rtx (Pmode); ++ if (pic_reg == NULL_RTX && cfun->machine->pic_reg == NULL_RTX) ++ { ++ pic_reg = gen_reg_rtx (Pmode); ++ cfun->machine->pic_reg = pic_reg; ++ } ++ else if (pic_reg == NULL_RTX) ++ { ++ pic_reg = cfun->machine->pic_reg; ++ } ++ else if (cfun->machine->pic_reg == NULL_RTX) ++ { ++ cfun->machine->pic_reg = pic_reg; ++ } + + /* Play games to avoid marking the function as needing pic + if we are being called as part of the cost-estimation +@@ -7278,11 +7306,12 @@ require_pic_register (void) + start_sequence (); + + if (TARGET_THUMB1 && arm_pic_register != INVALID_REGNUM +- && arm_pic_register > LAST_LO_REGNUM) ++ && arm_pic_register > LAST_LO_REGNUM ++ && !compute_now) + emit_move_insn (cfun->machine->pic_reg, + gen_rtx_REG (Pmode, arm_pic_register)); + else +- arm_load_pic_register (0UL); ++ arm_load_pic_register (0UL, pic_reg); + + seq = get_insns (); + end_sequence (); +@@ -7295,16 +7324,33 @@ require_pic_register (void) + we can't yet emit instructions directly in the final + insn stream. Queue the insns on the entry edge, they will + be committed after everything else is expanded. */ +- insert_insn_on_edge (seq, +- single_succ_edge (ENTRY_BLOCK_PTR_FOR_FN (cfun))); ++ if (currently_expanding_to_rtl) ++ insert_insn_on_edge (seq, ++ single_succ_edge ++ (ENTRY_BLOCK_PTR_FOR_FN (cfun))); ++ else ++ emit_insn (seq); + } + } + } + } + ++/* Legitimize PIC load to ORIG into REG. If REG is NULL, a new pseudo is ++ created to hold the result of the load. If not NULL, PIC_REG indicates ++ which register to use as PIC register, otherwise it is decided by register ++ allocator. COMPUTE_NOW forces the PIC register to be loaded at the current ++ location in the instruction stream, irregardless of whether it was loaded ++ previously. Note that nonnull PIC_REG is only supported iff COMPUTE_NOW is ++ true and null PIC_REG is only supported iff COMPUTE_NOW is false. ++ ++ Returns the register REG into which the PIC load is performed. */ ++ + rtx +-legitimize_pic_address (rtx orig, machine_mode mode, rtx reg) ++legitimize_pic_address (rtx orig, machine_mode mode, rtx reg, rtx pic_reg, ++ bool compute_now) + { ++ gcc_assert (compute_now == (pic_reg != NULL_RTX)); ++ + if (GET_CODE (orig) == SYMBOL_REF + || GET_CODE (orig) == LABEL_REF) + { +@@ -7337,9 +7383,12 @@ legitimize_pic_address (rtx orig, machin + rtx mem; + + /* If this function doesn't have a pic register, create one now. */ +- require_pic_register (); ++ require_pic_register (pic_reg, compute_now); ++ ++ if (pic_reg == NULL_RTX) ++ pic_reg = cfun->machine->pic_reg; + +- pat = gen_calculate_pic_address (reg, cfun->machine->pic_reg, orig); ++ pat = gen_calculate_pic_address (reg, pic_reg, orig); + + /* Make the MEM as close to a constant as possible. */ + mem = SET_SRC (pat); +@@ -7388,9 +7437,11 @@ legitimize_pic_address (rtx orig, machin + + gcc_assert (GET_CODE (XEXP (orig, 0)) == PLUS); + +- base = legitimize_pic_address (XEXP (XEXP (orig, 0), 0), Pmode, reg); ++ base = legitimize_pic_address (XEXP (XEXP (orig, 0), 0), Pmode, reg, ++ pic_reg, compute_now); + offset = legitimize_pic_address (XEXP (XEXP (orig, 0), 1), Pmode, +- base == reg ? 0 : reg); ++ base == reg ? 0 : reg, pic_reg, ++ compute_now); + + if (CONST_INT_P (offset)) + { +@@ -7490,16 +7541,17 @@ static GTY(()) int pic_labelno; + low register. */ + + void +-arm_load_pic_register (unsigned long saved_regs ATTRIBUTE_UNUSED) ++arm_load_pic_register (unsigned long saved_regs ATTRIBUTE_UNUSED, rtx pic_reg) + { +- rtx l1, labelno, pic_tmp, pic_rtx, pic_reg; ++ rtx l1, labelno, pic_tmp, pic_rtx; + + if (crtl->uses_pic_offset_table == 0 || TARGET_SINGLE_PIC_BASE) + return; + + gcc_assert (flag_pic); + +- pic_reg = cfun->machine->pic_reg; ++ if (pic_reg == NULL_RTX) ++ pic_reg = cfun->machine->pic_reg; + if (TARGET_VXWORKS_RTP) + { + pic_rtx = gen_rtx_SYMBOL_REF (Pmode, VXWORKS_GOTT_BASE); +@@ -8558,7 +8610,8 @@ arm_legitimize_address (rtx x, rtx orig_ + { + /* We need to find and carefully transform any SYMBOL and LABEL + references; so go back to the original address expression. */ +- rtx new_x = legitimize_pic_address (orig_x, mode, NULL_RTX); ++ rtx new_x = legitimize_pic_address (orig_x, mode, NULL_RTX, NULL_RTX, ++ false /*compute_now*/); + + if (new_x != orig_x) + x = new_x; +@@ -8626,7 +8679,8 @@ thumb_legitimize_address (rtx x, rtx ori + { + /* We need to find and carefully transform any SYMBOL and LABEL + references; so go back to the original address expression. */ +- rtx new_x = legitimize_pic_address (orig_x, mode, NULL_RTX); ++ rtx new_x = legitimize_pic_address (orig_x, mode, NULL_RTX, NULL_RTX, ++ false /*compute_now*/); + + if (new_x != orig_x) + x = new_x; +@@ -17800,7 +17854,7 @@ arm_emit_call_insn (rtx pat, rtx addr, b + ? !targetm.binds_local_p (SYMBOL_REF_DECL (addr)) + : !SYMBOL_REF_LOCAL_P (addr))) + { +- require_pic_register (); ++ require_pic_register (NULL_RTX, false /*compute_now*/); + use_reg (&CALL_INSN_FUNCTION_USAGE (insn), cfun->machine->pic_reg); + } + +@@ -21706,7 +21760,7 @@ arm_expand_prologue (void) + mask &= THUMB2_WORK_REGS; + if (!IS_NESTED (func_type)) + mask |= (1 << IP_REGNUM); +- arm_load_pic_register (mask); ++ arm_load_pic_register (mask, NULL_RTX); + } + + /* If we are profiling, make sure no instructions are scheduled before +@@ -24909,7 +24963,7 @@ thumb1_expand_prologue (void) + /* Load the pic register before setting the frame pointer, + so we can use r7 as a temporary work register. */ + if (flag_pic && arm_pic_register != INVALID_REGNUM) +- arm_load_pic_register (live_regs_mask); ++ arm_load_pic_register (live_regs_mask, NULL_RTX); + + if (!frame_pointer_needed && CALLER_INTERWORKING_SLOT_SIZE > 0) + emit_move_insn (gen_rtx_REG (Pmode, ARM_HARD_FRAME_POINTER_REGNUM), +diff -urpN a/gcc/config/arm/arm.md b/gcc/config/arm/arm.md +--- a/gcc/config/arm/arm.md 2019-05-30 16:58:45.358508769 +0800 ++++ b/gcc/config/arm/arm.md 2019-05-30 11:52:58.491157149 +0800 +@@ -6051,7 +6051,8 @@ + operands[1] = legitimize_pic_address (operands[1], SImode, + (!can_create_pseudo_p () + ? operands[0] +- : 0)); ++ : NULL_RTX), NULL_RTX, ++ false /*compute_now*/); + } + " + ) +@@ -6340,7 +6341,7 @@ + /* r3 is clobbered by set/longjmp, so we can use it as a scratch + register. */ + if (arm_pic_register != INVALID_REGNUM) +- arm_load_pic_register (1UL << 3); ++ arm_load_pic_register (1UL << 3, NULL_RTX); + DONE; + }") + +@@ -8666,6 +8667,164 @@ + (set_attr "conds" "clob")] + ) + ++;; Named patterns for stack smashing protection. ++(define_expand "stack_protect_combined_set" ++ [(parallel ++ [(set (match_operand:SI 0 "memory_operand" "") ++ (unspec:SI [(match_operand:SI 1 "guard_operand" "")] ++ UNSPEC_SP_SET)) ++ (clobber (match_scratch:SI 2 "")) ++ (clobber (match_scratch:SI 3 ""))])] ++ "" ++ "" ++) ++ ++;; Use a separate insn from the above expand to be able to have the mem outside ++;; the operand #1 when register allocation comes. This is needed to avoid LRA ++;; try to reload the guard since we need to control how PIC access is done in ++;; the -fpic/-fPIC case (see COMPUTE_NOW parameter when calling ++;; legitimize_pic_address ()). ++(define_insn_and_split "*stack_protect_combined_set_insn" ++ [(set (match_operand:SI 0 "memory_operand" "=m,m") ++ (unspec:SI [(mem:SI (match_operand:SI 1 "guard_addr_operand" "X,X"))] ++ UNSPEC_SP_SET)) ++ (clobber (match_scratch:SI 2 "=&l,&r")) ++ (clobber (match_scratch:SI 3 "=&l,&r"))] ++ "" ++ "#" ++ "reload_completed" ++ [(parallel [(set (match_dup 0) (unspec:SI [(mem:SI (match_dup 2))] ++ UNSPEC_SP_SET)) ++ (clobber (match_dup 2))])] ++ " ++{ ++ if (flag_pic) ++ { ++ /* Forces recomputing of GOT base now. */ ++ legitimize_pic_address (operands[1], SImode, operands[2], operands[3], ++ true /*compute_now*/); ++ } ++ else ++ { ++ if (address_operand (operands[1], SImode)) ++ operands[2] = operands[1]; ++ else ++ { ++ rtx mem = XEXP (force_const_mem (SImode, operands[1]), 0); ++ emit_move_insn (operands[2], mem); ++ } ++ } ++}" ++ [(set_attr "arch" "t1,32")] ++) ++ ++(define_insn "*stack_protect_set_insn" ++ [(set (match_operand:SI 0 "memory_operand" "=m,m") ++ (unspec:SI [(mem:SI (match_operand:SI 1 "register_operand" "+&l,&r"))] ++ UNSPEC_SP_SET)) ++ (clobber (match_dup 1))] ++ "" ++ "@ ++ ldr\\t%1, [%1]\;str\\t%1, %0\;movs\t%1,#0 ++ ldr\\t%1, [%1]\;str\\t%1, %0\;mov\t%1,#0" ++ [(set_attr "length" "8,12") ++ (set_attr "conds" "clob,nocond") ++ (set_attr "type" "multiple") ++ (set_attr "arch" "t1,32")] ++) ++ ++(define_expand "stack_protect_combined_test" ++ [(parallel ++ [(set (pc) ++ (if_then_else ++ (eq (match_operand:SI 0 "memory_operand" "") ++ (unspec:SI [(match_operand:SI 1 "guard_operand" "")] ++ UNSPEC_SP_TEST)) ++ (label_ref (match_operand 2)) ++ (pc))) ++ (clobber (match_scratch:SI 3 "")) ++ (clobber (match_scratch:SI 4 "")) ++ (clobber (reg:CC CC_REGNUM))])] ++ "" ++ "" ++) ++ ++;; Use a separate insn from the above expand to be able to have the mem outside ++;; the operand #1 when register allocation comes. This is needed to avoid LRA ++;; try to reload the guard since we need to control how PIC access is done in ++;; the -fpic/-fPIC case (see COMPUTE_NOW parameter when calling ++;; legitimize_pic_address ()). ++(define_insn_and_split "*stack_protect_combined_test_insn" ++ [(set (pc) ++ (if_then_else ++ (eq (match_operand:SI 0 "memory_operand" "m,m") ++ (unspec:SI [(mem:SI (match_operand:SI 1 "guard_addr_operand" "X,X"))] ++ UNSPEC_SP_TEST)) ++ (label_ref (match_operand 2)) ++ (pc))) ++ (clobber (match_scratch:SI 3 "=&l,&r")) ++ (clobber (match_scratch:SI 4 "=&l,&r")) ++ (clobber (reg:CC CC_REGNUM))] ++ "" ++ "#" ++ "reload_completed" ++ [(const_int 0)] ++{ ++ rtx eq; ++ ++ if (flag_pic) ++ { ++ /* Forces recomputing of GOT base now. */ ++ legitimize_pic_address (operands[1], SImode, operands[3], operands[4], ++ true /*compute_now*/); ++ } ++ else ++ { ++ if (address_operand (operands[1], SImode)) ++ operands[3] = operands[1]; ++ else ++ { ++ rtx mem = XEXP (force_const_mem (SImode, operands[1]), 0); ++ emit_move_insn (operands[3], mem); ++ } ++ } ++ if (TARGET_32BIT) ++ { ++ emit_insn (gen_arm_stack_protect_test_insn (operands[4], operands[0], ++ operands[3])); ++ rtx cc_reg = gen_rtx_REG (CC_Zmode, CC_REGNUM); ++ eq = gen_rtx_EQ (CC_Zmode, cc_reg, const0_rtx); ++ emit_jump_insn (gen_arm_cond_branch (operands[2], eq, cc_reg)); ++ } ++ else ++ { ++ emit_insn (gen_thumb1_stack_protect_test_insn (operands[4], operands[0], ++ operands[3])); ++ eq = gen_rtx_EQ (VOIDmode, operands[4], const0_rtx); ++ emit_jump_insn (gen_cbranchsi4 (eq, operands[4], const0_rtx, ++ operands[2])); ++ } ++ DONE; ++} ++ [(set_attr "arch" "t1,32")] ++) ++ ++(define_insn "arm_stack_protect_test_insn" ++ [(set (reg:CC_Z CC_REGNUM) ++ (compare:CC_Z (unspec:SI [(match_operand:SI 1 "memory_operand" "m,m") ++ (mem:SI (match_operand:SI 2 "register_operand" "+l,r"))] ++ UNSPEC_SP_TEST) ++ (const_int 0))) ++ (clobber (match_operand:SI 0 "register_operand" "=&l,&r")) ++ (clobber (match_dup 2))] ++ "TARGET_32BIT" ++ "ldr\t%0, [%2]\;ldr\t%2, %1\;eors\t%0, %2, %0" ++ [(set_attr "length" "8,12") ++ (set_attr "conds" "set") ++ (set_attr "type" "multiple") ++ (set_attr "arch" "t,32")] ++) ++ + (define_expand "casesi" + [(match_operand:SI 0 "s_register_operand" "") ; index to jump on + (match_operand:SI 1 "const_int_operand" "") ; lower bound +diff -urpN a/gcc/config/arm/arm-protos.h b/gcc/config/arm/arm-protos.h +--- a/gcc/config/arm/arm-protos.h 2019-05-30 16:58:45.358508769 +0800 ++++ b/gcc/config/arm/arm-protos.h 2019-05-30 11:52:58.491157149 +0800 +@@ -28,7 +28,7 @@ extern enum unwind_info_type arm_except_ + extern int use_return_insn (int, rtx); + extern bool use_simple_return_p (void); + extern enum reg_class arm_regno_class (int); +-extern void arm_load_pic_register (unsigned long); ++extern void arm_load_pic_register (unsigned long, rtx); + extern int arm_volatile_func (void); + extern void arm_expand_prologue (void); + extern void arm_expand_epilogue (bool); +@@ -69,7 +69,7 @@ extern int const_ok_for_dimode_op (HOST_ + extern int arm_split_constant (RTX_CODE, machine_mode, rtx, + HOST_WIDE_INT, rtx, rtx, int); + extern int legitimate_pic_operand_p (rtx); +-extern rtx legitimize_pic_address (rtx, machine_mode, rtx); ++extern rtx legitimize_pic_address (rtx, machine_mode, rtx, rtx, bool); + extern rtx legitimize_tls_address (rtx, rtx); + extern bool arm_legitimate_address_p (machine_mode, rtx, bool); + extern int arm_legitimate_address_outer_p (machine_mode, rtx, RTX_CODE, int); +diff -urpN a/gcc/config/arm/predicates.md b/gcc/config/arm/predicates.md +--- a/gcc/config/arm/predicates.md 2019-05-30 16:58:45.358508769 +0800 ++++ b/gcc/config/arm/predicates.md 2019-05-30 11:52:58.491157149 +0800 +@@ -31,6 +31,23 @@ + || REGNO_REG_CLASS (REGNO (op)) != NO_REGS)); + }) + ++; Predicate for stack protector guard's address in ++; stack_protect_combined_set_insn and stack_protect_combined_test_insn patterns ++(define_predicate "guard_addr_operand" ++ (match_test "true") ++{ ++ return (CONSTANT_ADDRESS_P (op) ++ || !targetm.cannot_force_const_mem (mode, op)); ++}) ++ ++; Predicate for stack protector guard in stack_protect_combined_set and ++; stack_protect_combined_test patterns ++(define_predicate "guard_operand" ++ (match_code "mem") ++{ ++ return guard_addr_operand (XEXP (op, 0), mode); ++}) ++ + (define_predicate "imm_for_neon_inv_logic_operand" + (match_code "const_vector") + { +diff -urpN a/gcc/config/arm/thumb1.md b/gcc/config/arm/thumb1.md +--- a/gcc/config/arm/thumb1.md 2019-05-30 16:58:45.358508769 +0800 ++++ b/gcc/config/arm/thumb1.md 2019-05-30 11:52:58.491157149 +0800 +@@ -1964,4 +1964,17 @@ + }" + [(set_attr "type" "mov_reg")] + ) ++ ++(define_insn "thumb1_stack_protect_test_insn" ++ [(set (match_operand:SI 0 "register_operand" "=&l") ++ (unspec:SI [(match_operand:SI 1 "memory_operand" "m") ++ (mem:SI (match_operand:SI 2 "register_operand" "+l"))] ++ UNSPEC_SP_TEST)) ++ (clobber (match_dup 2))] ++ "TARGET_THUMB1" ++ "ldr\t%0, [%2]\;ldr\t%2, %1\;eors\t%0, %2, %0" ++ [(set_attr "length" "8") ++ (set_attr "conds" "set") ++ (set_attr "type" "multiple")] ++) + +diff -urpN a/gcc/config/arm/unspecs.md b/gcc/config/arm/unspecs.md +--- a/gcc/config/arm/unspecs.md 2019-05-30 16:58:45.358508769 +0800 ++++ b/gcc/config/arm/unspecs.md 2019-05-30 11:52:58.491157149 +0800 +@@ -86,6 +86,9 @@ + UNSPEC_PROBE_STACK ; Probe stack memory reference + UNSPEC_NONSECURE_MEM ; Represent non-secure memory in ARMv8-M with + ; security extension ++ UNSPEC_SP_SET ; Represent the setting of stack protector's canary ++ UNSPEC_SP_TEST ; Represent the testing of stack protector's canary ++ ; against the guard. + ]) + + (define_c_enum "unspec" [ +diff -urpN a/gcc/doc/md.texi b/gcc/doc/md.texi +--- a/gcc/doc/md.texi 2019-05-30 16:58:45.362508769 +0800 ++++ b/gcc/doc/md.texi 2019-05-30 11:52:58.491157149 +0800 +@@ -6955,22 +6955,61 @@ builtins. + The get/set patterns have a single output/input operand respectively, + with @var{mode} intended to be @code{Pmode}. + ++@cindex @code{stack_protect_combined_set} instruction pattern ++@item @samp{stack_protect_combined_set} ++This pattern, if defined, moves a @code{ptr_mode} value from an address ++whose declaration RTX is given in operand 1 to the memory in operand 0 ++without leaving the value in a register afterward. If several ++instructions are needed by the target to perform the operation (eg. to ++load the address from a GOT entry then load the @code{ptr_mode} value ++and finally store it), it is the backend's responsibility to ensure no ++intermediate result gets spilled. This is to avoid leaking the value ++some place that an attacker might use to rewrite the stack guard slot ++after having clobbered it. ++ ++If this pattern is not defined, then the address declaration is ++expanded first in the standard way and a @code{stack_protect_set} ++pattern is then generated to move the value from that address to the ++address in operand 0. ++ + @cindex @code{stack_protect_set} instruction pattern + @item @samp{stack_protect_set} +-This pattern, if defined, moves a @code{ptr_mode} value from the memory +-in operand 1 to the memory in operand 0 without leaving the value in +-a register afterward. This is to avoid leaking the value some place +-that an attacker might use to rewrite the stack guard slot after +-having clobbered it. ++This pattern, if defined, moves a @code{ptr_mode} value from the valid ++memory location in operand 1 to the memory in operand 0 without leaving ++the value in a register afterward. This is to avoid leaking the value ++some place that an attacker might use to rewrite the stack guard slot ++after having clobbered it. ++ ++Note: on targets where the addressing modes do not allow to load ++directly from stack guard address, the address is expanded in a standard ++way first which could cause some spills. + + If this pattern is not defined, then a plain move pattern is generated. + ++@cindex @code{stack_protect_combined_test} instruction pattern ++@item @samp{stack_protect_combined_test} ++This pattern, if defined, compares a @code{ptr_mode} value from an ++address whose declaration RTX is given in operand 1 with the memory in ++operand 0 without leaving the value in a register afterward and ++branches to operand 2 if the values were equal. If several ++instructions are needed by the target to perform the operation (eg. to ++load the address from a GOT entry then load the @code{ptr_mode} value ++and finally store it), it is the backend's responsibility to ensure no ++intermediate result gets spilled. This is to avoid leaking the value ++some place that an attacker might use to rewrite the stack guard slot ++after having clobbered it. ++ ++If this pattern is not defined, then the address declaration is ++expanded first in the standard way and a @code{stack_protect_test} ++pattern is then generated to compare the value from that address to the ++value at the memory in operand 0. ++ + @cindex @code{stack_protect_test} instruction pattern + @item @samp{stack_protect_test} + This pattern, if defined, compares a @code{ptr_mode} value from the +-memory in operand 1 with the memory in operand 0 without leaving the +-value in a register afterward and branches to operand 2 if the values +-were equal. ++valid memory location in operand 1 with the memory in operand 0 without ++leaving the value in a register afterward and branches to operand 2 if ++the values were equal. + + If this pattern is not defined, then a plain compare pattern and + conditional branch pattern is used. +diff -urpN a/gcc/function.c b/gcc/function.c +--- a/gcc/function.c 2019-05-30 16:58:45.362508769 +0800 ++++ b/gcc/function.c 2019-05-30 11:53:14.071156599 +0800 +@@ -5065,18 +5065,34 @@ stack_protect_epilogue (void) + tree guard_decl = targetm.stack_protect_guard (); + rtx_code_label *label = gen_label_rtx (); + rtx x, y; +- rtx_insn *seq; ++ rtx_insn *seq = NULL; + + x = expand_normal (crtl->stack_protect_guard); +- if (guard_decl) +- y = expand_normal (guard_decl); ++ ++ if (targetm.have_stack_protect_combined_test () && guard_decl) ++ { ++ gcc_assert (DECL_P (guard_decl)); ++ y = DECL_RTL (guard_decl); ++ /* Allow the target to compute address of Y and compare it with X without ++ leaking Y into a register. This combined address + compare pattern ++ allows the target to prevent spilling of any intermediate results by ++ splitting it after register allocator. */ ++ seq = targetm.gen_stack_protect_combined_test (x, y, label); ++ } + else +- y = const0_rtx; ++ { ++ if (guard_decl) ++ y = expand_normal (guard_decl); ++ else ++ y = const0_rtx; ++ ++ /* Allow the target to compare Y with X without leaking either into ++ a register. */ ++ if (targetm.have_stack_protect_test ()) ++ seq = targetm.gen_stack_protect_test (x, y, label); ++ } + +- /* Allow the target to compare Y with X without leaking either into +- a register. */ +- if (targetm.have_stack_protect_test () +- && ((seq = targetm.gen_stack_protect_test (x, y, label)) != NULL_RTX)) ++ if (seq) + emit_insn (seq); + else + emit_cmp_and_jump_insns (x, y, EQ, NULL_RTX, ptr_mode, 1, label); +diff -urpN a/gcc/genpreds.c b/gcc/genpreds.c +--- a/gcc/genpreds.c 2019-05-30 16:58:45.362508769 +0800 ++++ b/gcc/genpreds.c 2019-05-30 11:53:14.163156595 +0800 +@@ -1581,7 +1581,8 @@ write_insn_preds_c (void) + #include \"reload.h\"\n\ + #include \"regs.h\"\n\ + #include \"emit-rtl.h\"\n\ +-#include \"tm-constrs.h\"\n"); ++#include \"tm-constrs.h\"\n\ ++#include \"target.h\"\n"); + + FOR_ALL_PREDICATES (p) + write_one_predicate_function (p); +diff -urpN a/gcc/target-insns.def b/gcc/target-insns.def +--- a/gcc/target-insns.def 2019-05-30 16:58:45.362508769 +0800 ++++ b/gcc/target-insns.def 2019-05-30 11:52:58.495157149 +0800 +@@ -96,7 +96,9 @@ DEF_TARGET_INSN (sibcall_value, (rtx x0, + DEF_TARGET_INSN (simple_return, (void)) + DEF_TARGET_INSN (split_stack_prologue, (void)) + DEF_TARGET_INSN (split_stack_space_check, (rtx x0, rtx x1)) ++DEF_TARGET_INSN (stack_protect_combined_set, (rtx x0, rtx x1)) + DEF_TARGET_INSN (stack_protect_set, (rtx x0, rtx x1)) ++DEF_TARGET_INSN (stack_protect_combined_test, (rtx x0, rtx x1, rtx x2)) + DEF_TARGET_INSN (stack_protect_test, (rtx x0, rtx x1, rtx x2)) + DEF_TARGET_INSN (store_multiple, (rtx x0, rtx x1, rtx x2)) + DEF_TARGET_INSN (tablejump, (rtx x0, rtx x1)) diff --git a/CVE-2019-15847.patch b/CVE-2019-15847.patch new file mode 100644 index 0000000..2bf0b09 --- /dev/null +++ b/CVE-2019-15847.patch @@ -0,0 +1,51 @@ +diff -urpN a/gcc/config/rs6000/altivec.md b/gcc/config/rs6000/altivec.md +--- a/gcc/config/rs6000/altivec.md 2018-01-15 01:47:30.483964000 +0800 ++++ b/gcc/config/rs6000/altivec.md 2019-09-09 00:01:25.770835633 +0800 +@@ -74,9 +74,6 @@ + UNSPEC_VUNPACK_LO_SIGN_DIRECT + UNSPEC_VUPKHPX + UNSPEC_VUPKLPX +- UNSPEC_DARN +- UNSPEC_DARN_32 +- UNSPEC_DARN_RAW + UNSPEC_DST + UNSPEC_DSTT + UNSPEC_DSTST +@@ -3770,21 +3767,21 @@ + + (define_insn "darn_32" + [(set (match_operand:SI 0 "register_operand" "=r") +- (unspec:SI [(const_int 0)] UNSPEC_DARN_32))] ++ (unspec_volatile:SI [(const_int 0)] UNSPECV_DARN_32))] + "TARGET_P9_MISC" + "darn %0,0" + [(set_attr "type" "integer")]) + + (define_insn "darn_raw" + [(set (match_operand:DI 0 "register_operand" "=r") +- (unspec:DI [(const_int 0)] UNSPEC_DARN_RAW))] ++ (unspec_volatile:DI [(const_int 0)] UNSPECV_DARN_RAW))] + "TARGET_P9_MISC && TARGET_64BIT" + "darn %0,2" + [(set_attr "type" "integer")]) + + (define_insn "darn" + [(set (match_operand:DI 0 "register_operand" "=r") +- (unspec:DI [(const_int 0)] UNSPEC_DARN))] ++ (unspec_volatile:DI [(const_int 0)] UNSPECV_DARN))] + "TARGET_P9_MISC && TARGET_64BIT" + "darn %0,1" + [(set_attr "type" "integer")]) +diff -urpN a/gcc/config/rs6000/rs6000.md b/gcc/config/rs6000/rs6000.md +--- a/gcc/config/rs6000/rs6000.md 2018-01-21 21:32:58.843504000 +0800 ++++ b/gcc/config/rs6000/rs6000.md 2019-09-08 23:53:13.122859153 +0800 +@@ -163,6 +163,9 @@ + UNSPECV_EH_RR ; eh_reg_restore + UNSPECV_ISYNC ; isync instruction + UNSPECV_MFTB ; move from time base ++ UNSPECV_DARN ; darn 1 (deliver a random number) ++ UNSPECV_DARN_32 ; darn 2 ++ UNSPECV_DARN_RAW ; darn 0 + UNSPECV_NLGR ; non-local goto receiver + UNSPECV_MFFS ; Move from FPSCR + UNSPECV_MTFSF ; Move to FPSCR Fields diff --git a/aarch64-fix-tls-negative-offset.patch b/aarch64-fix-tls-negative-offset.patch new file mode 100644 index 0000000..3ca3c8f --- /dev/null +++ b/aarch64-fix-tls-negative-offset.patch @@ -0,0 +1,24 @@ +diff -urpN a/gcc/config/aarch64/aarch64.c b/gcc/config/aarch64/aarch64.c +--- a/gcc/config/aarch64/aarch64.c 2018-10-09 11:49:19.000000000 +0800 ++++ b/gcc/config/aarch64/aarch64.c 2018-10-09 13:42:15.000000000 +0800 +@@ -1619,7 +1619,7 @@ aarch64_load_symref_appropriately (rtx d + case SYMBOL_SMALL_TLSDESC: + { + machine_mode mode = GET_MODE (dest); +- rtx x0 = gen_rtx_REG (mode, R0_REGNUM); ++ rtx x0 = gen_rtx_REG (ptr_mode, R0_REGNUM); + rtx tp; + + gcc_assert (mode == Pmode || mode == ptr_mode); +@@ -1635,6 +1635,11 @@ aarch64_load_symref_appropriately (rtx d + if (mode != Pmode) + tp = gen_lowpart (mode, tp); + ++ if (mode != ptr_mode) ++ { ++ x0 = force_reg (mode, gen_rtx_SIGN_EXTEND (mode, x0)); ++ } ++ + emit_insn (gen_rtx_SET (dest, gen_rtx_PLUS (mode, tp, x0))); + set_unique_reg_note (get_last_insn (), REG_EQUIV, imm); + return; diff --git a/aarch64-ilp32-call-addr-dimode.patch b/aarch64-ilp32-call-addr-dimode.patch new file mode 100644 index 0000000..0a04deb --- /dev/null +++ b/aarch64-ilp32-call-addr-dimode.patch @@ -0,0 +1,31 @@ +diff -urpN a/gcc/config/aarch64/aarch64.md b/gcc/config/aarch64/aarch64.md +--- a/gcc/config/aarch64/aarch64.md 2018-10-09 11:30:50.000000000 +0800 ++++ b/gcc/config/aarch64/aarch64.md 2018-10-09 11:52:54.000000000 +0800 +@@ -857,6 +857,13 @@ + : !REG_P (callee)) + XEXP (operands[0], 0) = force_reg (Pmode, callee); + ++ if (TARGET_ILP32 ++ && GET_CODE (XEXP (operands[0], 0)) == SYMBOL_REF ++ && GET_MODE (XEXP (operands[0], 0)) == SImode) ++ XEXP (operands[0], 0) = convert_memory_address (DImode, ++ XEXP (operands[0], 0)); ++ ++ + if (operands[2] == NULL_RTX) + operands[2] = const0_rtx; + +@@ -889,6 +896,13 @@ + : !REG_P (callee)) + XEXP (operands[1], 0) = force_reg (Pmode, callee); + ++ if (TARGET_ILP32 ++ && GET_CODE (XEXP (operands[1], 0)) == SYMBOL_REF ++ && GET_MODE (XEXP (operands[1], 0)) == SImode) ++ XEXP (operands[1], 0) = convert_memory_address (DImode, ++ XEXP (operands[1], 0)); ++ ++ + if (operands[3] == NULL_RTX) + operands[3] = const0_rtx; + diff --git a/add-tsv110-pipeline-scheduling.patch b/add-tsv110-pipeline-scheduling.patch new file mode 100644 index 0000000..508de27 --- /dev/null +++ b/add-tsv110-pipeline-scheduling.patch @@ -0,0 +1,780 @@ +diff -urpN a/gcc/config/aarch64/aarch64.c b/gcc/config/aarch64/aarch64.c +--- a/gcc/config/aarch64/aarch64.c 2019-04-15 14:50:25.866378665 +0800 ++++ b/gcc/config/aarch64/aarch64.c 2019-04-15 14:49:21.986376983 +0800 +@@ -554,6 +554,31 @@ static const struct tune_params generic_ + (AARCH64_EXTRA_TUNE_NONE) /* tune_flags. */ + }; + ++static const struct tune_params tsv110_tunings = ++{ ++ &cortexa57_extra_costs, ++ &generic_addrcost_table, ++ &generic_regmove_cost, ++ &generic_vector_cost, ++ &generic_branch_cost, ++ &generic_approx_modes, ++ 4, /* memmov_cost */ ++ 4, /* issue_rate */ ++ AARCH64_FUSE_NOTHING, /* fusible_ops */ ++ 16, /* function_align. */ ++ 16, /* jump_align. */ ++ 8, /* loop_align. */ ++ 2, /* int_reassoc_width. */ ++ 4, /* fp_reassoc_width. */ ++ 1, /* vec_reassoc_width. */ ++ 2, /* min_div_recip_mul_sf. */ ++ 2, /* min_div_recip_mul_df. */ ++ 0, /* max_case_values. */ ++ 0, /* cache_line_size. */ ++ tune_params::AUTOPREFETCHER_OFF, /* autoprefetcher_model. */ ++ (AARCH64_EXTRA_TUNE_NONE) /* tune_flags. */ ++}; ++ + static const struct tune_params cortexa35_tunings = + { + &cortexa53_extra_costs, +diff -urpN a/gcc/config/aarch64/aarch64-cores.def b/gcc/config/aarch64/aarch64-cores.def +--- a/gcc/config/aarch64/aarch64-cores.def 2017-02-15 08:09:28.845771000 +0800 ++++ b/gcc/config/aarch64/aarch64-cores.def 2019-04-15 14:49:21.986376983 +0800 +@@ -78,6 +78,8 @@ AARCH64_CORE("xgene1", xgene1, x + AARCH64_CORE("thunderx2t99p1", thunderx2t99p1, thunderx2t99, 8_1A, AARCH64_FL_FOR_ARCH8_1 | AARCH64_FL_CRYPTO, thunderx2t99, 0x42, 0x516, -1) + AARCH64_CORE("vulcan", vulcan, thunderx2t99, 8_1A, AARCH64_FL_FOR_ARCH8_1 | AARCH64_FL_CRYPTO, thunderx2t99, 0x42, 0x516, -1) + ++AARCH64_CORE("tsv110", tsv110, tsv110, 8A, AARCH64_FL_FOR_ARCH8 | AARCH64_FL_CRC, tsv110, 0x48, 0xd01, -1) ++ + /* V8 big.LITTLE implementations. */ + + AARCH64_CORE("cortex-a57.cortex-a53", cortexa57cortexa53, cortexa53, 8A, AARCH64_FL_FOR_ARCH8 | AARCH64_FL_CRC, cortexa57, 0x41, AARCH64_BIG_LITTLE (0xd07, 0xd03), -1) +diff -urpN a/gcc/config/aarch64/aarch64.md b/gcc/config/aarch64/aarch64.md +--- a/gcc/config/aarch64/aarch64.md 2019-04-15 14:50:25.870378665 +0800 ++++ b/gcc/config/aarch64/aarch64.md 2019-04-15 14:49:21.986376983 +0800 +@@ -226,6 +226,7 @@ + (include "thunderx.md") + (include "../arm/xgene1.md") + (include "thunderx2t99.md") ++(include "tsv110.md") + + ;; ------------------------------------------------------------------- + ;; Jumps and other miscellaneous insns +diff -urpN a/gcc/config/aarch64/aarch64-tune.md b/gcc/config/aarch64/aarch64-tune.md +--- a/gcc/config/aarch64/aarch64-tune.md 2017-02-15 08:09:28.845771000 +0800 ++++ b/gcc/config/aarch64/aarch64-tune.md 2019-04-15 14:49:21.986376983 +0800 +@@ -1,5 +1,5 @@ + ;; -*- buffer-read-only: t -*- + ;; Generated automatically by gentune.sh from aarch64-cores.def + (define_attr "tune" +- "cortexa35,cortexa53,cortexa57,cortexa72,cortexa73,exynosm1,falkor,qdf24xx,thunderx,thunderxt88p1,thunderxt88,thunderxt81,thunderxt83,thunderx2t99,xgene1,thunderx2t99p1,vulcan,cortexa57cortexa53,cortexa72cortexa53,cortexa73cortexa35,cortexa73cortexa53" ++ "cortexa35,cortexa53,cortexa57,cortexa72,cortexa73,exynosm1,falkor,qdf24xx,thunderx,thunderxt88p1,thunderxt88,thunderxt81,thunderxt83,thunderx2t99,xgene1,tsv110,thunderx2t99p1,vulcan,cortexa57cortexa53,cortexa72cortexa53,cortexa73cortexa35,cortexa73cortexa53" + (const (symbol_ref "((enum attr_tune) aarch64_tune)"))) +diff -urpN a/gcc/config/aarch64/tsv110.md b/gcc/config/aarch64/tsv110.md +--- a/gcc/config/aarch64/tsv110.md 1970-01-01 08:00:00.000000000 +0800 ++++ b/gcc/config/aarch64/tsv110.md 2019-04-15 14:55:30.420081420 +0800 +@@ -0,0 +1,708 @@ ++;; tsv110 pipeline description ++;; Copyright (C) 2018 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 ++;; . ++ ++(define_automaton "tsv110") ++ ++(define_attr "tsv110_neon_type" ++ "neon_arith_acc, neon_arith_acc_q, ++ neon_arith_basic, neon_arith_complex, ++ neon_reduc_add_acc, neon_multiply, neon_multiply_q, ++ neon_multiply_long, neon_mla, neon_mla_q, neon_mla_long, ++ neon_sat_mla_long, neon_shift_acc, neon_shift_imm_basic, ++ neon_shift_imm_complex, ++ neon_shift_reg_basic, neon_shift_reg_basic_q, neon_shift_reg_complex, ++ neon_shift_reg_complex_q, neon_fp_negabs, neon_fp_arith, ++ neon_fp_arith_q, neon_fp_reductions_q, neon_fp_cvt_int, ++ neon_fp_cvt_int_q, neon_fp_cvt16, neon_fp_minmax, neon_fp_mul, ++ neon_fp_mul_q, neon_fp_mla, neon_fp_mla_q, neon_fp_recpe_rsqrte, ++ neon_fp_recpe_rsqrte_q, neon_fp_recps_rsqrts, neon_fp_recps_rsqrts_q, ++ neon_bitops, neon_bitops_q, neon_from_gp, ++ neon_from_gp_q, neon_move, neon_tbl3_tbl4, neon_zip_q, neon_to_gp, ++ neon_load_a, neon_load_b, neon_load_c, neon_load_d, neon_load_e, ++ neon_load_f, neon_store_a, neon_store_b, neon_store_complex, ++ unknown" ++ (cond [ ++ (eq_attr "type" "neon_arith_acc, neon_reduc_add_acc,\ ++ neon_reduc_add_acc_q") ++ (const_string "neon_arith_acc") ++ (eq_attr "type" "neon_arith_acc_q") ++ (const_string "neon_arith_acc_q") ++ (eq_attr "type" "neon_abs,neon_abs_q,neon_add, neon_add_q, neon_add_long,\ ++ neon_add_widen, neon_neg, neon_neg_q,\ ++ neon_reduc_add, neon_reduc_add_q,\ ++ neon_reduc_add_long, neon_sub, neon_sub_q,\ ++ neon_sub_long, neon_sub_widen, neon_logic,\ ++ neon_logic_q, neon_tst, neon_tst_q,\ ++ neon_compare, neon_compare_q,\ ++ neon_compare_zero, neon_compare_zero_q,\ ++ neon_minmax, neon_minmax_q, neon_reduc_minmax,\ ++ neon_reduc_minmax_q") ++ (const_string "neon_arith_basic") ++ (eq_attr "type" "neon_add_halve_narrow_q,\ ++ neon_add_halve, neon_add_halve_q,\ ++ neon_sub_halve, neon_sub_halve_q, neon_qabs,\ ++ neon_qabs_q, neon_qadd, neon_qadd_q, neon_qneg,\ ++ neon_qneg_q, neon_qsub, neon_qsub_q,\ ++ neon_sub_halve_narrow_q") ++ (const_string "neon_arith_complex") ++ ++ (eq_attr "type" "neon_mul_b, neon_mul_h, neon_mul_s,\ ++ neon_mul_h_scalar, neon_mul_s_scalar,\ ++ neon_sat_mul_b, neon_sat_mul_h,\ ++ neon_sat_mul_s, neon_sat_mul_h_scalar,\ ++ neon_sat_mul_s_scalar,\ ++ neon_mul_b_long, neon_mul_h_long,\ ++ neon_mul_s_long,\ ++ neon_mul_h_scalar_long, neon_mul_s_scalar_long,\ ++ neon_sat_mul_b_long, neon_sat_mul_h_long,\ ++ neon_sat_mul_s_long, neon_sat_mul_h_scalar_long,\ ++ neon_sat_mul_s_scalar_long,\ ++ neon_mla_b, neon_mla_h, neon_mla_s,\ ++ neon_mla_h_scalar, neon_mla_s_scalar,\ ++ neon_mla_b_long, neon_mla_h_long,\ ++ neon_mla_s_long,\ ++ neon_mla_h_scalar_long, neon_mla_s_scalar_long,\ ++ neon_sat_mla_b_long, neon_sat_mla_h_long,\ ++ neon_sat_mla_s_long, neon_sat_mla_h_scalar_long,\ ++ neon_sat_mla_s_scalar_long") ++ (const_string "neon_multiply") ++ (eq_attr "type" "neon_mul_b_q, neon_mul_h_q, neon_mul_s_q,\ ++ neon_mul_h_scalar_q, neon_mul_s_scalar_q,\ ++ neon_sat_mul_b_q, neon_sat_mul_h_q,\ ++ neon_sat_mul_s_q, neon_sat_mul_h_scalar_q,\ ++ neon_sat_mul_s_scalar_q,\ ++ neon_mla_b_q, neon_mla_h_q, neon_mla_s_q,\ ++ neon_mla_h_scalar_q, neon_mla_s_scalar_q") ++ (const_string "neon_multiply_q") ++ ++ (eq_attr "type" "neon_shift_acc, neon_shift_acc_q") ++ (const_string "neon_shift_acc") ++ (eq_attr "type" "neon_shift_imm, neon_shift_imm_q,\ ++ neon_shift_imm_narrow_q, neon_shift_imm_long") ++ (const_string "neon_shift_imm_basic") ++ (eq_attr "type" "neon_sat_shift_imm, neon_sat_shift_imm_q,\ ++ neon_sat_shift_imm_narrow_q") ++ (const_string "neon_shift_imm_complex") ++ (eq_attr "type" "neon_shift_reg") ++ (const_string "neon_shift_reg_basic") ++ (eq_attr "type" "neon_shift_reg_q") ++ (const_string "neon_shift_reg_basic_q") ++ (eq_attr "type" "neon_sat_shift_reg") ++ (const_string "neon_shift_reg_complex") ++ (eq_attr "type" "neon_sat_shift_reg_q") ++ (const_string "neon_shift_reg_complex_q") ++ ++ (eq_attr "type" "neon_fp_neg_s, neon_fp_neg_s_q,\ ++ neon_fp_abs_s, neon_fp_abs_s_q,\ ++ neon_fp_neg_d, neon_fp_neg_d_q,\ ++ neon_fp_abs_d, neon_fp_abs_d_q,\ ++ neon_fp_minmax_s,neon_fp_minmax_d,\ ++ neon_fp_reduc_minmax_s,neon_fp_reduc_minmax_d") ++ (const_string "neon_fp_negabs") ++ (eq_attr "type" "neon_fp_addsub_s, neon_fp_abd_s,\ ++ neon_fp_reduc_add_s, neon_fp_compare_s,\ ++ neon_fp_round_s,\ ++ neon_fp_addsub_d, neon_fp_abd_d,\ ++ neon_fp_reduc_add_d, neon_fp_compare_d,\ ++ neon_fp_round_d") ++ (const_string "neon_fp_arith") ++ (eq_attr "type" "neon_fp_addsub_s_q, neon_fp_abd_s_q,\ ++ neon_fp_reduc_add_s_q, neon_fp_compare_s_q,\ ++ neon_fp_minmax_s_q, neon_fp_round_s_q,\ ++ neon_fp_addsub_d_q, neon_fp_abd_d_q,\ ++ neon_fp_reduc_add_d_q, neon_fp_compare_d_q,\ ++ neon_fp_minmax_d_q, neon_fp_round_d_q") ++ (const_string "neon_fp_arith_q") ++ (eq_attr "type" "neon_fp_reduc_minmax_s_q,\ ++ neon_fp_reduc_minmax_d_q,\ ++ neon_fp_reduc_add_s_q, neon_fp_reduc_add_d_q") ++ (const_string "neon_fp_reductions_q") ++ (eq_attr "type" "neon_fp_to_int_s, neon_int_to_fp_s,\ ++ neon_fp_to_int_d, neon_int_to_fp_d") ++ (const_string "neon_fp_cvt_int") ++ (eq_attr "type" "neon_fp_to_int_s_q, neon_int_to_fp_s_q,\ ++ neon_fp_to_int_d_q, neon_int_to_fp_d_q") ++ (const_string "neon_fp_cvt_int_q") ++ (eq_attr "type" "neon_fp_cvt_narrow_s_q, neon_fp_cvt_widen_h") ++ (const_string "neon_fp_cvt16") ++ (eq_attr "type" "neon_fp_mul_s, neon_fp_mul_s_scalar,\ ++ neon_fp_mul_d") ++ (const_string "neon_fp_mul") ++ (eq_attr "type" "neon_fp_mul_s_q, neon_fp_mul_s_scalar_q,\ ++ neon_fp_mul_d_q, neon_fp_mul_d_scalar_q") ++ (const_string "neon_fp_mul_q") ++ (eq_attr "type" "neon_fp_mla_s, neon_fp_mla_s_scalar,\ ++ neon_fp_mla_d") ++ (const_string "neon_fp_mla") ++ (eq_attr "type" "neon_fp_mla_s_q, neon_fp_mla_s_scalar_q, ++ neon_fp_mla_d_q, neon_fp_mla_d_scalar_q") ++ (const_string "neon_fp_mla_q") ++ (eq_attr "type" "neon_fp_recpe_s, neon_fp_rsqrte_s,\ ++ neon_fp_recpx_s,\ ++ neon_fp_recpe_d, neon_fp_rsqrte_d,\ ++ neon_fp_recpx_d") ++ (const_string "neon_fp_recpe_rsqrte") ++ (eq_attr "type" "neon_fp_recpe_s_q, neon_fp_rsqrte_s_q,\ ++ neon_fp_recpx_s_q,\ ++ neon_fp_recpe_d_q, neon_fp_rsqrte_d_q,\ ++ neon_fp_recpx_d_q") ++ (const_string "neon_fp_recpe_rsqrte_q") ++ (eq_attr "type" "neon_fp_recps_s, neon_fp_rsqrts_s,\ ++ neon_fp_recps_d, neon_fp_rsqrts_d") ++ (const_string "neon_fp_recps_rsqrts") ++ (eq_attr "type" "neon_fp_recps_s_q, neon_fp_rsqrts_s_q,\ ++ neon_fp_recps_d_q, neon_fp_rsqrts_d_q") ++ (const_string "neon_fp_recps_rsqrts_q") ++ (eq_attr "type" "neon_bsl, neon_cls, neon_cnt,\ ++ neon_rev, neon_permute, neon_rbit,\ ++ neon_tbl1, neon_tbl2, neon_zip,\ ++ neon_dup, neon_dup_q, neon_ext, neon_ext_q,\ ++ neon_move, neon_move_q, neon_move_narrow_q") ++ (const_string "neon_bitops") ++ (eq_attr "type" "neon_bsl_q, neon_cls_q, neon_cnt_q,\ ++ neon_rev_q, neon_permute_q, neon_rbit_q") ++ (const_string "neon_bitops_q") ++ (eq_attr "type" "neon_from_gp,f_mcr,f_mcrr") ++ (const_string "neon_from_gp") ++ (eq_attr "type" "neon_from_gp_q") ++ (const_string "neon_from_gp_q") ++ ++ (eq_attr "type" "f_loads, f_loadd,\ ++ neon_load1_1reg, neon_load1_1reg_q,\ ++ neon_load1_2reg, neon_load1_2reg_q") ++ (const_string "neon_load_a") ++ (eq_attr "type" "neon_load1_3reg, neon_load1_3reg_q,\ ++ neon_load1_4reg, neon_load1_4reg_q") ++ (const_string "neon_load_b") ++ (eq_attr "type" "neon_load1_one_lane, neon_load1_one_lane_q,\ ++ neon_load1_all_lanes, neon_load1_all_lanes_q,\ ++ neon_load2_2reg, neon_load2_2reg_q,\ ++ neon_load2_all_lanes, neon_load2_all_lanes_q") ++ (const_string "neon_load_c") ++ (eq_attr "type" "neon_load2_4reg, neon_load2_4reg_q,\ ++ neon_load3_3reg, neon_load3_3reg_q,\ ++ neon_load3_one_lane, neon_load3_one_lane_q,\ ++ neon_load4_4reg, neon_load4_4reg_q") ++ (const_string "neon_load_d") ++ (eq_attr "type" "neon_load2_one_lane, neon_load2_one_lane_q,\ ++ neon_load3_all_lanes, neon_load3_all_lanes_q,\ ++ neon_load4_all_lanes, neon_load4_all_lanes_q") ++ (const_string "neon_load_e") ++ (eq_attr "type" "neon_load4_one_lane, neon_load4_one_lane_q") ++ (const_string "neon_load_f") ++ ++ (eq_attr "type" "f_stores, f_stored,\ ++ neon_store1_1reg") ++ (const_string "neon_store_a") ++ (eq_attr "type" "neon_store1_2reg, neon_store1_1reg_q") ++ (const_string "neon_store_b") ++ (eq_attr "type" "neon_store1_3reg, neon_store1_3reg_q,\ ++ neon_store3_3reg, neon_store3_3reg_q,\ ++ neon_store2_4reg, neon_store2_4reg_q,\ ++ neon_store4_4reg, neon_store4_4reg_q,\ ++ neon_store2_2reg, neon_store2_2reg_q,\ ++ neon_store3_one_lane, neon_store3_one_lane_q,\ ++ neon_store4_one_lane, neon_store4_one_lane_q,\ ++ neon_store1_4reg, neon_store1_4reg_q,\ ++ neon_store1_one_lane, neon_store1_one_lane_q,\ ++ neon_store2_one_lane, neon_store2_one_lane_q") ++ (const_string "neon_store_complex")] ++ (const_string "unknown"))) ++ ++;; The tsv110 core is modelled as issues pipeline that has ++;; the following functional units. ++;; 1. Three pipelines for integer operations: ALU1, ALU2, ALU3 ++ ++(define_cpu_unit "tsv110_alu1_issue" "tsv110") ++(define_reservation "tsv110_alu1" "tsv110_alu1_issue") ++ ++(define_cpu_unit "tsv110_alu2_issue" "tsv110") ++(define_reservation "tsv110_alu2" "tsv110_alu2_issue") ++ ++(define_cpu_unit "tsv110_alu3_issue" "tsv110") ++(define_reservation "tsv110_alu3" "tsv110_alu3_issue") ++ ++;; 2. One pipeline for complex integer operations: MDU ++ ++(define_cpu_unit "tsv110_mdu_issue" "tsv110") ++(define_reservation "tsv110_mdu" "tsv110_mdu_issue") ++ ++;; 3. Two asymmetric pipelines for Asimd and FP operations: FSU1, FSU2 ++(define_automaton "tsv110_fsu") ++ ++(define_cpu_unit "tsv110_fsu1_issue" ++ "tsv110_fsu") ++(define_cpu_unit "tsv110_fsu2_issue" ++ "tsv110_fsu") ++ ++(define_reservation "tsv110_fsu1" "tsv110_fsu1_issue") ++(define_reservation "tsv110_fsu2" "tsv110_fsu2_issue") ++ ++;; 4. Two pipeline for branch operations but same with alu2 and alu3: BRU1, BRU2 ++ ++;; 5. Two pipelines for load and store operations: LS1, LS2. ++ ++(define_cpu_unit "tsv110_ls1_issue" "tsv110") ++(define_cpu_unit "tsv110_ls2_issue" "tsv110") ++(define_reservation "tsv110_ls1" "tsv110_ls1_issue") ++(define_reservation "tsv110_ls2" "tsv110_ls2_issue") ++ ++;; Block all issue queues. ++ ++(define_reservation "tsv110_block" "tsv110_fsu1_issue + tsv110_fsu2_issue ++ + tsv110_mdu_issue + tsv110_alu1_issue ++ + tsv110_alu2_issue + tsv110_alu3_issue + tsv110_ls1_issue + tsv110_ls2_issue") ++ ++;; Simple Execution Unit: ++;; ++;; Simple ALU without shift ++(define_insn_reservation "tsv110_alu" 1 ++ (and (eq_attr "tune" "tsv110") ++ (eq_attr "type" "alu_imm,logic_imm,\ ++ alu_sreg,logic_reg,\ ++ adc_imm,adc_reg,\ ++ adr,bfm,clz,rbit,rev,\ ++ shift_imm,shift_reg,\ ++ mov_imm,mov_reg,\ ++ mvn_imm,mvn_reg,\ ++ mrs,multiple,no_insn")) ++ "tsv110_alu1|tsv110_alu2|tsv110_alu3") ++ ++(define_insn_reservation "tsv110_alus" 1 ++ (and (eq_attr "tune" "tsv110") ++ (eq_attr "type" "alus_imm,logics_imm,\ ++ alus_sreg,logics_reg,\ ++ adcs_imm,adcs_reg")) ++ "tsv110_alu2|tsv110_alu3") ++ ++;; ALU ops with shift ++(define_insn_reservation "tsv110_alu_shift" 2 ++ (and (eq_attr "tune" "tsv110") ++ (eq_attr "type" "extend,\ ++ alu_shift_imm,alu_shift_reg,\ ++ crc,logic_shift_imm,logic_shift_reg,\ ++ mov_shift,mvn_shift,\ ++ mov_shift_reg,mvn_shift_reg")) ++ "tsv110_mdu") ++ ++(define_insn_reservation "tsv110_alus_shift" 2 ++ (and (eq_attr "tune" "tsv110") ++ (eq_attr "type" "alus_shift_imm,alus_shift_reg,\ ++ logics_shift_imm,logics_shift_reg")) ++ "tsv110_alu2|tsv110_alu3") ++ ++;; Multiplies instructions ++(define_insn_reservation "tsv110_mult" 3 ++ (and (eq_attr "tune" "tsv110") ++ (ior (eq_attr "mul32" "yes") ++ (eq_attr "mul64" "yes"))) ++ "tsv110_mdu") ++ ++;; Integer divide ++(define_insn_reservation "tsv110_div" 10 ++ (and (eq_attr "tune" "tsv110") ++ (eq_attr "type" "udiv,sdiv")) ++ "tsv110_mdu") ++ ++;; Block all issue pipes for a cycle ++(define_insn_reservation "tsv110_block" 1 ++ (and (eq_attr "tune" "tsv110") ++ (eq_attr "type" "block")) ++ "tsv110_block") ++ ++;; Branch execution Unit ++;; ++;; Branches take two issue slot. ++;; No latency as there is no result ++(define_insn_reservation "tsv110_branch" 0 ++ (and (eq_attr "tune" "tsv110") ++ (eq_attr "type" "branch")) ++ "tsv110_alu2|tsv110_alu3") ++ ++;; Load-store execution Unit ++;; ++;; Loads of up to two words. ++(define_insn_reservation "tsv110_load1" 4 ++ (and (eq_attr "tune" "tsv110") ++ (eq_attr "type" "load1,load2")) ++ "tsv110_ls1|tsv110_ls2") ++ ++;; Stores of up to two words. ++(define_insn_reservation "tsv110_store1" 0 ++ (and (eq_attr "tune" "tsv110") ++ (eq_attr "type" "store1,store2")) ++ "tsv110_ls1|tsv110_ls2") ++ ++;; Advanced SIMD Unit - Integer Arithmetic Instructions. ++ ++(define_insn_reservation "tsv110_neon_abd_aba" 4 ++ (and (eq_attr "tune" "tsv110") ++ (eq_attr "type" "neon_abd,neon_arith_acc")) ++ "tsv110_fsu1|tsv110_fsu2") ++ ++(define_insn_reservation "tsv110_neon_abd_aba_q" 4 ++ (and (eq_attr "tune" "tsv110") ++ (eq_attr "type" "neon_arith_acc_q")) ++ "tsv110_fsu1|tsv110_fsu2") ++ ++(define_insn_reservation "tsv110_neon_arith_basic" 2 ++ (and (eq_attr "tune" "tsv110") ++ (eq_attr "tsv110_neon_type" "neon_arith_basic")) ++ "tsv110_fsu1|tsv110_fsu2") ++ ++(define_insn_reservation "tsv110_neon_arith_complex" 4 ++ (and (eq_attr "tune" "tsv110") ++ (eq_attr "tsv110_neon_type" "neon_arith_complex")) ++ "tsv110_fsu1|tsv110_fsu2") ++ ++;; Integer Multiply Instructions. ++;; D-form ++(define_insn_reservation "tsv110_neon_multiply" 4 ++ (and (eq_attr "tune" "tsv110") ++ (eq_attr "tsv110_neon_type" "neon_multiply")) ++ "tsv110_fsu1") ++ ++(define_insn_reservation "tsv110_neon_multiply_dlong" 2 ++ (and (eq_attr "tune" "tsv110") ++ (eq_attr "type" "neon_mul_d_long")) ++ "tsv110_fsu1") ++ ++;; Q-form ++(define_insn_reservation "tsv110_neon_multiply_q" 8 ++ (and (eq_attr "tune" "tsv110") ++ (eq_attr "tsv110_neon_type" "neon_multiply_q")) ++ "tsv110_fsu1") ++ ++;; Integer Shift Instructions. ++ ++(define_insn_reservation ++ "tsv110_neon_shift_acc" 4 ++ (and (eq_attr "tune" "tsv110") ++ (eq_attr "tsv110_neon_type" "neon_shift_acc,\ ++ neon_shift_imm_basic,neon_shift_imm_complex,neon_shift_reg_basic,\ ++ neon_shift_reg_complex")) ++ "tsv110_fsu1") ++ ++(define_insn_reservation ++ "tsv110_neon_shift_acc_q" 4 ++ (and (eq_attr "tune" "tsv110") ++ (eq_attr "tsv110_neon_type" "neon_shift_reg_basic_q,\ ++ neon_shift_reg_complex_q")) ++ "tsv110_fsu1") ++ ++;; Floating Point Instructions. ++ ++(define_insn_reservation ++ "tsv110_neon_fp_negabs" 2 ++ (and (eq_attr "tune" "tsv110") ++ (eq_attr "tsv110_neon_type" "neon_fp_negabs")) ++ "(tsv110_fsu1|tsv110_fsu2)") ++ ++(define_insn_reservation ++ "tsv110_neon_fp_arith" 4 ++ (and (eq_attr "tune" "tsv110") ++ (eq_attr "tsv110_neon_type" "neon_fp_arith")) ++ "(tsv110_fsu1|tsv110_fsu2)") ++ ++(define_insn_reservation ++ "tsv110_neon_fp_arith_q" 4 ++ (and (eq_attr "tune" "tsv110") ++ (eq_attr "tsv110_neon_type" "neon_fp_arith_q")) ++ "tsv110_fsu1|tsv110_fsu2") ++ ++(define_insn_reservation ++ "tsv110_neon_fp_minmax_q" 2 ++ (and (eq_attr "tune" "tsv110") ++ (eq_attr "type" "neon_fp_minmax_s_q,neon_fp_minmax_d_q")) ++ "tsv110_fsu1|tsv110_fsu2") ++ ++(define_insn_reservation ++ "tsv110_neon_fp_reductions_q" 4 ++ (and (eq_attr "tune" "tsv110") ++ (eq_attr "tsv110_neon_type" "neon_fp_reductions_q")) ++ "tsv110_fsu1|tsv110_fsu2") ++ ++(define_insn_reservation ++ "tsv110_neon_fp_cvt_int" 2 ++ (and (eq_attr "tune" "tsv110") ++ (eq_attr "tsv110_neon_type" "neon_fp_cvt_int,neon_fp_cvt_int_q")) ++ "tsv110_fsu1|tsv110_fsu2") ++ ++(define_insn_reservation ++ "tsv110_neon_fp_mul" 5 ++ (and (eq_attr "tune" "tsv110") ++ (eq_attr "tsv110_neon_type" "neon_fp_mul")) ++ "tsv110_fsu1|tsv110_fsu2") ++ ++(define_insn_reservation ++ "tsv110_neon_fp_mul_q" 5 ++ (and (eq_attr "tune" "tsv110") ++ (eq_attr "tsv110_neon_type" "neon_fp_mul_q")) ++ "tsv110_fsu1|tsv110_fsu2") ++ ++(define_insn_reservation ++ "tsv110_neon_fp_mla" 7 ++ (and (eq_attr "tune" "tsv110") ++ (eq_attr "tsv110_neon_type" "neon_fp_mla,\ ++ neon_fp_recps_rsqrts")) ++ "tsv110_fsu1|tsv110_fsu2") ++ ++(define_insn_reservation ++ "tsv110_neon_fp_recpe_rsqrte" 3 ++ (and (eq_attr "tune" "tsv110") ++ (eq_attr "tsv110_neon_type" "neon_fp_recpe_rsqrte")) ++ "tsv110_fsu1|tsv110_fsu2") ++ ++(define_insn_reservation ++ "tsv110_neon_fp_mla_q" 7 ++ (and (eq_attr "tune" "tsv110") ++ (eq_attr "tsv110_neon_type" "neon_fp_mla_q,\ ++ neon_fp_recps_rsqrts_q")) ++ "tsv110_fsu1|tsv110_fsu2") ++ ++(define_insn_reservation ++ "tsv110_neon_fp_recpe_rsqrte_q" 3 ++ (and (eq_attr "tune" "tsv110") ++ (eq_attr "tsv110_neon_type" "neon_fp_recpe_rsqrte_q")) ++ "tsv110_fsu1|tsv110_fsu2") ++ ++;; Miscellaneous Instructions. ++ ++(define_insn_reservation ++ "tsv110_neon_bitops" 2 ++ (and (eq_attr "tune" "tsv110") ++ (eq_attr "tsv110_neon_type" "neon_bitops")) ++ "tsv110_fsu1|tsv110_fsu2") ++ ++(define_insn_reservation ++ "tsv110_neon_dup" 2 ++ (and (eq_attr "tune" "tsv110") ++ (eq_attr "type" "neon_from_gp,f_mcr")) ++ "tsv110_fsu1|tsv110_fsu2") ++ ++(define_insn_reservation ++ "tsv110_neon_mov" 2 ++ (and (eq_attr "tune" "tsv110") ++ (eq_attr "type" "f_mcrr")) ++ "tsv110_fsu1|tsv110_fsu2") ++ ++(define_insn_reservation ++ "tsv110_neon_bitops_q" 2 ++ (and (eq_attr "tune" "tsv110") ++ (eq_attr "tsv110_neon_type" "neon_bitops_q")) ++ "tsv110_fsu1|tsv110_fsu2") ++ ++(define_insn_reservation ++ "tsv110_neon_from_gp_q" 4 ++ (and (eq_attr "tune" "tsv110") ++ (eq_attr "tsv110_neon_type" "neon_from_gp_q")) ++ "(tsv110_alu1+tsv110_fsu1)|(tsv110_alu1+tsv110_fsu2)") ++ ++(define_insn_reservation ++ "tsv110_neon_to_gp" 3 ++ (and (eq_attr "tune" "tsv110") ++ (eq_attr "type" "neon_to_gp,neon_to_gp_q")) ++ "tsv110_fsu1") ++ ++;; Load Instructions. ++ ++(define_insn_reservation ++ "tsv110_neon_ld1_lane" 8 ++ (and (eq_attr "tune" "tsv110") ++ (eq_attr "type" "neon_load1_one_lane,neon_load1_one_lane_q,\ ++ neon_load1_all_lanes,neon_load1_all_lanes_q")) ++ "(tsv110_ls1 + tsv110_fsu1)|(tsv110_ls1 + tsv110_fsu2)|(tsv110_ls2 + tsv110_fsu1)|(tsv110_ls2 + tsv110_fsu2)") ++ ++(define_insn_reservation ++ "tsv110_neon_ld1_reg1" 6 ++ (and (eq_attr "tune" "tsv110") ++ (eq_attr "type" "f_loads,f_loadd,neon_load1_1reg,neon_load1_1reg_q")) ++ "tsv110_ls1|tsv110_ls2") ++ ++(define_insn_reservation ++ "tsv110_neon_ld1_reg2" 6 ++ (and (eq_attr "tune" "tsv110") ++ (eq_attr "type" "neon_load1_2reg,neon_load1_2reg_q")) ++ "tsv110_ls1|tsv110_ls2") ++ ++(define_insn_reservation ++ "tsv110_neon_ld1_reg3" 7 ++ (and (eq_attr "tune" "tsv110") ++ (eq_attr "type" "neon_load1_3reg,neon_load1_3reg_q")) ++ "tsv110_ls1|tsv110_ls2") ++ ++(define_insn_reservation ++ "tsv110_neon_ld1_reg4" 7 ++ (and (eq_attr "tune" "tsv110") ++ (eq_attr "type" "neon_load1_4reg,neon_load1_4reg_q")) ++ "tsv110_ls1|tsv110_ls2") ++ ++(define_insn_reservation ++ "tsv110_neon_ld2" 8 ++ (and (eq_attr "tune" "tsv110") ++ (eq_attr "type" "neon_load1_2reg,neon_load1_2reg_q,\ ++ neon_load2_2reg,neon_load2_2reg_q,neon_load2_all_lanes,\ ++ neon_load2_all_lanes_q,neon_load2_one_lane,neon_load2_one_lane_q")) ++ "(tsv110_ls1 + tsv110_fsu1)|(tsv110_ls1 + tsv110_fsu2)|(tsv110_ls2 + tsv110_fsu1)|(tsv110_ls2 + tsv110_fsu2)") ++ ++(define_insn_reservation ++ "tsv110_neon_ld3" 9 ++ (and (eq_attr "tune" "tsv110") ++ (eq_attr "type" "neon_load3_3reg,neon_load3_3reg_q,\ ++ neon_load3_one_lane,neon_load3_one_lane_q,\ ++ neon_load3_all_lanes,neon_load3_all_lanes_q")) ++ "(tsv110_ls1 + tsv110_fsu1)|(tsv110_ls1 + tsv110_fsu2)|(tsv110_ls2 + tsv110_fsu1)|(tsv110_ls2 + tsv110_fsu2)") ++ ++(define_insn_reservation ++ "tsv110_neon_ld4_lane" 9 ++ (and (eq_attr "tune" "tsv110") ++ (eq_attr "type" "neon_load4_all_lanes,neon_load4_all_lanes_q,\ ++ neon_load4_one_lane,neon_load4_one_lane_q")) ++ "(tsv110_ls1 + tsv110_fsu1)|(tsv110_ls1 + tsv110_fsu2)|(tsv110_ls2 + tsv110_fsu1)|(tsv110_ls2 + tsv110_fsu2)") ++ ++(define_insn_reservation ++ "tsv110_neon_ld4_reg" 11 ++ (and (eq_attr "tune" "tsv110") ++ (eq_attr "type" "neon_load4_all_lanes,neon_load4_all_lanes_q,\ ++ neon_load4_one_lane,neon_load4_one_lane_q")) ++ "(tsv110_ls1 + tsv110_fsu1)|(tsv110_ls1 + tsv110_fsu2)|(tsv110_ls2 + tsv110_fsu1)|(tsv110_ls2 + tsv110_fsu2)") ++ ++;; Store Instructions. ++ ++(define_insn_reservation ++ "tsv110_neon_store_a" 0 ++ (and (eq_attr "tune" "tsv110") ++ (eq_attr "tsv110_neon_type" "neon_store_a")) ++ "tsv110_fsu1|tsv110_fsu2") ++ ++(define_insn_reservation ++ "tsv110_neon_store_b" 0 ++ (and (eq_attr "tune" "tsv110") ++ (eq_attr "tsv110_neon_type" "neon_store_b")) ++ "tsv110_fsu1|tsv110_fsu2") ++ ++;; These block issue for a number of cycles proportional to the number ++;; of 64-bit chunks they will store, we don't attempt to model that ++;; precisely, treat them as blocking execution for two cycles when ++;; issued. ++(define_insn_reservation ++ "tsv110_neon_store_complex" 0 ++ (and (eq_attr "tune" "tsv110") ++ (eq_attr "tsv110_neon_type" "neon_store_complex")) ++ "tsv110_block*2") ++ ++;; Floating-Point Operations. ++ ++(define_insn_reservation "tsv110_fp_const" 2 ++ (and (eq_attr "tune" "tsv110") ++ (eq_attr "type" "fconsts,fconstd,fmov")) ++ "tsv110_fsu1|tsv110_fsu2") ++ ++(define_insn_reservation "tsv110_fp_add_sub" 5 ++ (and (eq_attr "tune" "tsv110") ++ (eq_attr "type" "fadds,faddd,fmuls,fmuld")) ++ "tsv110_fsu1|tsv110_fsu2") ++ ++(define_insn_reservation "tsv110_fp_mac" 7 ++ (and (eq_attr "tune" "tsv110") ++ (eq_attr "type" "fmacs,ffmas,fmacd,ffmad")) ++ "tsv110_fsu1|tsv110_fsu2") ++ ++(define_insn_reservation "tsv110_fp_cvt" 3 ++ (and (eq_attr "tune" "tsv110") ++ (eq_attr "type" "f_cvt")) ++ "tsv110_fsu1|tsv110_fsu2") ++ ++(define_insn_reservation "tsv110_fp_cvtf2i" 4 ++ (and (eq_attr "tune" "tsv110") ++ (eq_attr "type" "f_cvtf2i")) ++ "tsv110_fsu1") ++ ++(define_insn_reservation "tsv110_fp_cvti2f" 5 ++ (and (eq_attr "tune" "tsv110") ++ (eq_attr "type" "f_cvti2f")) ++ "(tsv110_alu1+tsv110_fsu1)|(tsv110_alu1+tsv110_fsu2)") ++ ++(define_insn_reservation "tsv110_fp_cmp" 4 ++ (and (eq_attr "tune" "tsv110") ++ (eq_attr "type" "fcmps,fcmpd")) ++ "tsv110_fsu1|tsv110_fsu2") ++ ++(define_insn_reservation "tsv110_fp_arith" 2 ++ (and (eq_attr "tune" "tsv110") ++ (eq_attr "type" "ffariths,ffarithd")) ++ "tsv110_fsu1|tsv110_fsu2") ++ ++(define_insn_reservation "tsv110_fp_divs" 12 ++ (and (eq_attr "tune" "tsv110") ++ (eq_attr "type" "fdivs,neon_fp_div_s,fdivd,neon_fp_div_d,\ ++ neon_fp_div_s_q,neon_fp_div_d_q")) ++ "tsv110_fsu1") ++ ++(define_insn_reservation "tsv110_fp_sqrts" 24 ++ (and (eq_attr "tune" "tsv110") ++ (eq_attr "type" "fsqrts,neon_fp_sqrt_s,fsqrtd,neon_fp_sqrt_d,\ ++ neon_fp_sqrt_s_q,neon_fp_sqrt_d_q")) ++ "tsv110_fsu2") ++ ++(define_insn_reservation "tsv110_crypto_aes" 3 ++ (and (eq_attr "tune" "tsv110") ++ (eq_attr "type" "crypto_aese,crypto_aesmc")) ++ "tsv110_fsu1") ++ ++(define_insn_reservation "tsv110_crypto_sha1_fast" 2 ++ (and (eq_attr "tune" "tsv110") ++ (eq_attr "type" "crypto_sha1_fast,crypto_sha1_xor")) ++ "(tsv110_fsu1|tsv110_fsu2)") ++ ++(define_insn_reservation "tsv110_crypto_sha256_fast" 2 ++ (and (eq_attr "tune" "tsv110") ++ (eq_attr "type" "crypto_sha256_fast")) ++ "tsv110_fsu1") ++ ++(define_insn_reservation "tsv110_crypto_complex" 5 ++ (and (eq_attr "tune" "tsv110") ++ (eq_attr "type" "crypto_sha1_slow,crypto_sha256_slow")) ++ "tsv110_fsu1") ++ ++;; We lie with calls. They take up all issue slots, but are otherwise ++;; not harmful. ++(define_insn_reservation "tsv110_call" 1 ++ (and (eq_attr "tune" "tsv110") ++ (eq_attr "type" "call")) ++ "tsv110_alu1_issue+tsv110_alu2_issue+tsv110_alu3_issue+tsv110_fsu1_issue+tsv110_fsu2_issue\ ++ +tsv110_mdu_issue+tsv110_ls1_issue+tsv110_ls2_issue" ++) ++ ++;; Simple execution unit bypasses ++(define_bypass 1 "tsv110_alu" ++ "tsv110_alu,tsv110_alu_shift") ++(define_bypass 2 "tsv110_alu_shift" ++ "tsv110_alu,tsv110_alu_shift") ++ ++;; An MLA or a MUL can feed a dependent MLA. ++(define_bypass 3 "tsv110_neon_*mla*,tsv110_neon_*mul*" ++ "tsv110_neon_*mla*") ++ ++;; We don't need to care about control hazards, either the branch is ++;; predicted in which case we pay no penalty, or the branch is ++;; mispredicted in which case instruction scheduling will be unlikely to ++;; help. ++(define_bypass 1 "tsv110_*" ++ "tsv110_call,tsv110_branch") diff --git a/arm-adjust-be-ldrd-strd.patch b/arm-adjust-be-ldrd-strd.patch new file mode 100644 index 0000000..90278d3 --- /dev/null +++ b/arm-adjust-be-ldrd-strd.patch @@ -0,0 +1,60 @@ +diff -urp a/gcc/config/arm/arm.c b/gcc/config/arm/arm.c +--- a/gcc/config/arm/arm.c 2019-01-18 11:25:20.840179114 +0800 ++++ b/gcc/config/arm/arm.c 2019-01-18 11:25:47.548179817 +0800 +@@ -14306,18 +14306,36 @@ gen_movmem_ldrd_strd (rtx *operands) + emit_move_insn (reg0, src); + else + { +- emit_insn (gen_unaligned_loadsi (low_reg, src)); +- src = next_consecutive_mem (src); +- emit_insn (gen_unaligned_loadsi (hi_reg, src)); ++ if (flag_lsrd_be_adjust && BYTES_BIG_ENDIAN && WORDS_BIG_ENDIAN) ++ { ++ emit_insn (gen_unaligned_loadsi (hi_reg, src)); ++ src = next_consecutive_mem (src); ++ emit_insn (gen_unaligned_loadsi (low_reg, src)); ++ } ++ else ++ { ++ emit_insn (gen_unaligned_loadsi (low_reg, src)); ++ src = next_consecutive_mem (src); ++ emit_insn (gen_unaligned_loadsi (hi_reg, src)); ++ } + } + + if (dst_aligned) + emit_move_insn (dst, reg0); + else + { +- emit_insn (gen_unaligned_storesi (dst, low_reg)); +- dst = next_consecutive_mem (dst); +- emit_insn (gen_unaligned_storesi (dst, hi_reg)); ++ if (flag_lsrd_be_adjust && BYTES_BIG_ENDIAN && WORDS_BIG_ENDIAN) ++ { ++ emit_insn (gen_unaligned_storesi (dst, hi_reg)); ++ dst = next_consecutive_mem (dst); ++ emit_insn (gen_unaligned_storesi (dst, low_reg)); ++ } ++ else ++ { ++ emit_insn (gen_unaligned_storesi (dst, low_reg)); ++ dst = next_consecutive_mem (dst); ++ emit_insn (gen_unaligned_storesi (dst, hi_reg)); ++ } + } + + src = next_consecutive_mem (src); +diff -urp a/gcc/config/arm/arm.opt b/gcc/config/arm/arm.opt +--- a/gcc/config/arm/arm.opt 2019-01-18 11:25:20.840179114 +0800 ++++ b/gcc/config/arm/arm.opt 2019-01-18 11:28:51.744184666 +0800 +@@ -274,6 +274,10 @@ masm-syntax-unified + Target Report Var(inline_asm_unified) Init(0) Save + Assume unified syntax for inline assembly code. + ++mlsrd-be-adjust ++Target Report Var(flag_lsrd_be_adjust) Init(1) ++Adjust ldrd/strd splitting order when it's big-endian. ++ + mpure-code + Target Report Var(target_pure_code) Init(0) + Do not allow constant data to be placed in code sections. diff --git a/arm-bigendian-disable-interleaved-LS-vectorize.patch b/arm-bigendian-disable-interleaved-LS-vectorize.patch new file mode 100644 index 0000000..06c12c8 --- /dev/null +++ b/arm-bigendian-disable-interleaved-LS-vectorize.patch @@ -0,0 +1,19 @@ +diff -urpN gcc-7.3.0-bak/gcc/config/arm/arm.c gcc-7.3.0/gcc/config/arm/arm.c +--- gcc-7.3.0-bak/gcc/config/arm/arm.c 2018-11-13 14:23:21.362347728 +0800 ++++ gcc-7.3.0/gcc/config/arm/arm.c 2018-11-13 14:31:15.722360215 +0800 +@@ -26853,7 +26853,14 @@ static bool + arm_array_mode_supported_p (machine_mode mode, + unsigned HOST_WIDE_INT nelems) + { +- if (TARGET_NEON ++ ++ ++ /* We don't want to enable interleaved loads and stores for BYTES_BIG_ENDIAN ++ for now, as the lane-swapping logic needs to be extended in the expanders. ++ See PR target/82518. */ ++ ++ ++ if (TARGET_NEON && !BYTES_BIG_ENDIAN + && (VALID_NEON_DREG_MODE (mode) || VALID_NEON_QREG_MODE (mode)) + && (nelems >= 2 && nelems <= 4)) + return true; diff --git a/arm-fix-push-minipool.patch b/arm-fix-push-minipool.patch new file mode 100644 index 0000000..126ee92 --- /dev/null +++ b/arm-fix-push-minipool.patch @@ -0,0 +1,25 @@ +diff -Nurp a/gcc/config/arm/arm.md b/gcc/config/arm/arm.md +--- a/gcc/config/arm/arm.md 2019-08-10 00:21:12.658523444 +0800 ++++ b/gcc/config/arm/arm.md 2019-08-10 00:21:53.478521496 +0800 +@@ -5337,7 +5337,9 @@ + # + ldrh%?\\t%0, %1" + [(set_attr "type" "alu_shift_reg,load_byte") +- (set_attr "predicable" "yes")] ++ (set_attr "predicable" "yes") ++ (set_attr "pool_range" "*,256") ++ (set_attr "neg_pool_range" "*,244")] + ) + + (define_insn "*arm_zero_extendhisi2_v6" +@@ -5348,7 +5350,9 @@ + uxth%?\\t%0, %1 + ldrh%?\\t%0, %1" + [(set_attr "predicable" "yes") +- (set_attr "type" "extend,load_byte")] ++ (set_attr "type" "extend,load_byte") ++ (set_attr "pool_range" "*,256") ++ (set_attr "neg_pool_range" "*,244")] + ) + + (define_insn "*arm_zero_extendhisi2addsi" diff --git a/cloog-0.18.4.tar.gz b/cloog-0.18.4.tar.gz new file mode 100644 index 0000000..f220816 Binary files /dev/null and b/cloog-0.18.4.tar.gz differ diff --git a/constructor-priority-bugfix.patch b/constructor-priority-bugfix.patch new file mode 100644 index 0000000..fbc3be0 --- /dev/null +++ b/constructor-priority-bugfix.patch @@ -0,0 +1,21 @@ +diff -N -urp a/gcc/config/aarch64/aarch64.c b/gcc/config/aarch64/aarch64.c +--- a/gcc/config/aarch64/aarch64.c 2018-11-16 18:02:11.000000000 +0800 ++++ b/gcc/config/aarch64/aarch64.c 2018-11-16 18:07:39.000000000 +0800 +@@ -6102,7 +6102,7 @@ aarch64_elf_asm_constructor (rtx symbol, + -Wformat-truncation false positive, use a larger size. */ + char buf[23]; + snprintf (buf, sizeof (buf), ".init_array.%.5u", priority); +- s = get_section (buf, SECTION_WRITE, NULL); ++ s = get_section (buf, SECTION_WRITE | SECTION_NOTYPE, NULL); + switch_to_section (s); + assemble_align (POINTER_SIZE); + assemble_aligned_integer (POINTER_BYTES, symbol); +@@ -6122,7 +6122,7 @@ aarch64_elf_asm_destructor (rtx symbol, + -Wformat-truncation false positive, use a larger size. */ + char buf[23]; + snprintf (buf, sizeof (buf), ".fini_array.%.5u", priority); +- s = get_section (buf, SECTION_WRITE, NULL); ++ s = get_section (buf, SECTION_WRITE | SECTION_NOTYPE, NULL); + switch_to_section (s); + assemble_align (POINTER_SIZE); + assemble_aligned_integer (POINTER_BYTES, symbol); diff --git a/fix-operand-size-mismatch-for-i386-sse.patch b/fix-operand-size-mismatch-for-i386-sse.patch new file mode 100644 index 0000000..90e526b --- /dev/null +++ b/fix-operand-size-mismatch-for-i386-sse.patch @@ -0,0 +1,155 @@ +diff -N -urp a/gcc/config/i386/sse.md b/gcc/config/i386/sse.md +--- a/gcc/config/i386/sse.md 2019-10-30 10:02:45.894920908 +0800 ++++ b/gcc/config/i386/sse.md 2019-10-30 10:17:39.682887612 +0800 +@@ -16012,9 +16012,11 @@ + switch (INTVAL (operands[4])) + { + case 3: +- return "vgatherpf0ps\t{%5%{%0%}|%5%{%0%}}"; ++ /* %X5 so that we don't emit any *WORD PTR for -masm=intel, as ++ gas changed what it requires incompatibly. */ ++ return "vgatherpf0ps\t{%5%{%0%}|%X5%{%0%}}"; + case 2: +- return "vgatherpf1ps\t{%5%{%0%}|%5%{%0%}}"; ++ return "vgatherpf1ps\t{%5%{%0%}|%X5%{%0%}}"; + default: + gcc_unreachable (); + } +@@ -16057,9 +16059,11 @@ + switch (INTVAL (operands[4])) + { + case 3: +- return "vgatherpf0pd\t{%5%{%0%}|%5%{%0%}}"; ++ /* %X5 so that we don't emit any *WORD PTR for -masm=intel, as ++ gas changed what it requires incompatibly. */ ++ return "vgatherpf0pd\t{%5%{%0%}|%X5%{%0%}}"; + case 2: +- return "vgatherpf1pd\t{%5%{%0%}|%5%{%0%}}"; ++ return "vgatherpf1pd\t{%5%{%0%}|%X5%{%0%}}"; + default: + gcc_unreachable (); + } +@@ -16103,10 +16107,12 @@ + { + case 3: + case 7: +- return "vscatterpf0ps\t{%5%{%0%}|%5%{%0%}}"; ++ /* %X5 so that we don't emit any *WORD PTR for -masm=intel, as ++ gas changed what it requires incompatibly. */ ++ return "vscatterpf0ps\t{%5%{%0%}|%X5%{%0%}}"; + case 2: + case 6: +- return "vscatterpf1ps\t{%5%{%0%}|%5%{%0%}}"; ++ return "vscatterpf1ps\t{%5%{%0%}|%X5%{%0%}}"; + default: + gcc_unreachable (); + } +@@ -16150,10 +16156,12 @@ + { + case 3: + case 7: +- return "vscatterpf0pd\t{%5%{%0%}|%5%{%0%}}"; ++ /* %X5 so that we don't emit any *WORD PTR for -masm=intel, as ++ gas changed what it requires incompatibly. */ ++ return "vscatterpf0pd\t{%5%{%0%}|%X5%{%0%}}"; + case 2: + case 6: +- return "vscatterpf1pd\t{%5%{%0%}|%5%{%0%}}"; ++ return "vscatterpf1pd\t{%5%{%0%}|%X5%{%0%}}"; + default: + gcc_unreachable (); + } +@@ -19153,12 +19161,6 @@ + (set_attr "prefix" "vex") + (set_attr "mode" "")]) + +-;; Memory operand override for -masm=intel of the v*gatherq* patterns. +-(define_mode_attr gatherq_mode +- [(V4SI "q") (V2DI "x") (V4SF "q") (V2DF "x") +- (V8SI "x") (V4DI "t") (V8SF "x") (V4DF "t") +- (V16SI "t") (V8DI "g") (V16SF "t") (V8DF "g")]) +- + (define_expand "_gathersi" + [(parallel [(set (match_operand:VI48F 0 "register_operand") + (unspec:VI48F +@@ -19192,7 +19194,9 @@ + UNSPEC_GATHER)) + (clobber (match_scratch: 2 "=&Yk"))] + "TARGET_AVX512F" +- "vgatherd\t{%6, %0%{%2%}|%0%{%2%}, %6}" ++;; %X6 so that we don't emit any *WORD PTR for -masm=intel, as ++;; gas changed what it requires incompatibly. ++ "vgatherd\t{%6, %0%{%2%}|%0%{%2%}, %X6}" + [(set_attr "type" "ssemov") + (set_attr "prefix" "evex") + (set_attr "mode" "")]) +@@ -19211,7 +19215,9 @@ + UNSPEC_GATHER)) + (clobber (match_scratch: 1 "=&Yk"))] + "TARGET_AVX512F" +- "vgatherd\t{%5, %0%{%1%}|%0%{%1%}, %5}" ++;; %X5 so that we don't emit any *WORD PTR for -masm=intel, as ++;; gas changed what it requires incompatibly. ++ "vgatherd\t{%5, %0%{%1%}|%0%{%1%}, %X5}" + [(set_attr "type" "ssemov") + (set_attr "prefix" "evex") + (set_attr "mode" "")]) +@@ -19250,9 +19256,9 @@ + UNSPEC_GATHER)) + (clobber (match_scratch:QI 2 "=&Yk"))] + "TARGET_AVX512F" +-{ +- return "vgatherq\t{%6, %1%{%2%}|%1%{%2%}, %6}"; +-} ++;; %X6 so that we don't emit any *WORD PTR for -masm=intel, as ++;; gas changed what it requires incompatibly. ++ "vgatherq\t{%6, %1%{%2%}|%1%{%2%}, %X6}" + [(set_attr "type" "ssemov") + (set_attr "prefix" "evex") + (set_attr "mode" "")]) +@@ -19272,14 +19278,16 @@ + (clobber (match_scratch:QI 1 "=&Yk"))] + "TARGET_AVX512F" + { ++ /* %X5 so that we don't emit any *WORD PTR for -masm=intel, as ++ gas changed what it requires incompatibly. */ + if (mode != mode) + { + if ( != 64) +- return "vgatherq\t{%5, %x0%{%1%}|%x0%{%1%}, %5}"; ++ return "vgatherq\t{%5, %x0%{%1%}|%x0%{%1%}, %X5}"; + else +- return "vgatherq\t{%5, %t0%{%1%}|%t0%{%1%}, %t5}"; ++ return "vgatherq\t{%5, %t0%{%1%}|%t0%{%1%}, %X5}"; + } +- return "vgatherq\t{%5, %0%{%1%}|%0%{%1%}, %5}"; ++ return "vgatherq\t{%5, %0%{%1%}|%0%{%1%}, %X5}"; + } + [(set_attr "type" "ssemov") + (set_attr "prefix" "evex") +@@ -19316,7 +19324,9 @@ + UNSPEC_SCATTER)) + (clobber (match_scratch: 1 "=&Yk"))] + "TARGET_AVX512F" +- "vscatterd\t{%3, %5%{%1%}|%5%{%1%}, %3}" ++;; %X5 so that we don't emit any *WORD PTR for -masm=intel, as ++;; gas changed what it requires incompatibly. ++ "vscatterd\t{%3, %5%{%1%}|%X5%{%1%}, %3}" + [(set_attr "type" "ssemov") + (set_attr "prefix" "evex") + (set_attr "mode" "")]) +@@ -19352,11 +19362,9 @@ + UNSPEC_SCATTER)) + (clobber (match_scratch:QI 1 "=&Yk"))] + "TARGET_AVX512F" +-{ +- if (GET_MODE_SIZE (GET_MODE_INNER (mode)) == 8) +- return "vscatterq\t{%3, %5%{%1%}|%5%{%1%}, %3}"; +- return "vscatterq\t{%3, %5%{%1%}|%t5%{%1%}, %3}"; +-} ++;; %X5 so that we don't emit any *WORD PTR for -masm=intel, as ++;; gas changed what it requires incompatibly. ++ "vscatterq\t{%3, %5%{%1%}|%X5%{%1%}, %3}" + [(set_attr "type" "ssemov") + (set_attr "prefix" "evex") + (set_attr "mode" "")]) diff --git a/floop-interchange.patch b/floop-interchange.patch new file mode 100644 index 0000000..6657eed --- /dev/null +++ b/floop-interchange.patch @@ -0,0 +1,2680 @@ +diff -N -urp a/gcc/Makefile.in b/gcc/Makefile.in +--- a/gcc/Makefile.in 2018-11-15 15:59:30.435048460 +0800 ++++ b/gcc/Makefile.in 2018-11-15 16:04:16.735055997 +0800 +@@ -1293,6 +1293,7 @@ OBJS = \ + gimple-fold.o \ + gimple-laddress.o \ + gimple-loop-jam.o \ ++ gimple-loop-interchange.o \ + gimple-low.o \ + gimple-pretty-print.o \ + gimple-ssa-backprop.o \ +diff -N -urp a/gcc/cfgloop.h b/gcc/cfgloop.h +--- a/gcc/cfgloop.h 2018-11-15 15:59:30.439048461 +0800 ++++ b/gcc/cfgloop.h 2018-11-15 16:03:17.431054436 +0800 +@@ -225,6 +225,16 @@ struct GTY ((chain_next ("%h.next"))) lo + builtins. */ + tree simduid; + ++ /* In loop optimization, it's common to generate loops from the original ++ loop. This field records the index of the original loop which can be ++ used to track the original loop from newly generated loops. This can ++ be done by calling function get_loop (cfun, orig_loop_num). Note the ++ original loop could be destroyed for various reasons thus no longer ++ exists, as a result, function call to get_loop returns NULL pointer. ++ In this case, this field should not be used and needs to be cleared ++ whenever possible. */ ++ int orig_loop_num; ++ + /* Upper bound on number of iterations of a loop. */ + struct nb_iter_bound *bounds; + +diff -N -urp a/gcc/common.opt b/gcc/common.opt +--- a/gcc/common.opt 2018-11-15 15:59:30.447048461 +0800 ++++ b/gcc/common.opt 2018-11-15 16:03:17.431054436 +0800 +@@ -1488,8 +1488,8 @@ Common Alias(floop-nest-optimize) + Enable loop nest transforms. Same as -floop-nest-optimize. + + floop-interchange +-Common Alias(floop-nest-optimize) +-Enable loop nest transforms. Same as -floop-nest-optimize. ++Common Report Var(flag_loop_interchange) Optimization ++Enable loop interchange on trees. + + floop-block + Common Alias(floop-nest-optimize) +diff -N -urp a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi +--- a/gcc/doc/invoke.texi 2018-11-15 15:59:30.451048461 +0800 ++++ b/gcc/doc/invoke.texi 2018-11-15 16:05:06.803057315 +0800 +@@ -8224,11 +8224,9 @@ Perform loop optimizations on trees. Th + at @option{-O} and higher. + + @item -ftree-loop-linear +-@itemx -floop-interchange + @itemx -floop-strip-mine + @itemx -floop-block + @opindex ftree-loop-linear +-@opindex floop-interchange + @opindex floop-strip-mine + @opindex floop-block + Perform loop nest optimizations. Same as +@@ -8328,6 +8326,25 @@ Apply unroll and jam transformations on + nest this unrolls the outer loop by some factor and fuses the resulting + multiple inner loops. This flag is enabled by default at @option{-O3}. + ++@item -floop-interchange ++@opindex floop-interchange ++Perform loop interchange outside of graphite. This flag can improve cache ++performance on loop nest and allow further loop optimizations, like ++vectorization, to take place. For example, the loop ++@smallexample ++for (int i = 0; i < N; i++) ++ for (int j = 0; j < N; j++) ++ for (int k = 0; k < N; k++) ++ c[i][j] = c[i][j] + a[i][k]*b[k][j]; ++@end smallexample ++is transformed to ++@smallexample ++for (int i = 0; i < N; i++) ++ for (int k = 0; k < N; k++) ++ for (int j = 0; j < N; j++) ++ c[i][j] = c[i][j] + a[i][k]*b[k][j]; ++@end smallexample ++ + @item -ftree-loop-im + @opindex ftree-loop-im + Perform loop invariant motion on trees. This pass moves only invariants that +@@ -10203,6 +10220,12 @@ The size of L1 cache, in kilobytes. + @item l2-cache-size + The size of L2 cache, in kilobytes. + ++@item loop-interchange-max-num-stmts ++The maximum number of stmts in a loop to be interchanged. ++ ++@item loop-interchange-stride-ratio ++The minimum ratio between stride of two loops for interchange to be profitable. ++ + @item min-insn-to-prefetch-ratio + The minimum ratio between the number of instructions and the + number of prefetches to enable prefetching in a loop. +diff -N -urp a/gcc/gimple-loop-interchange.cc b/gcc/gimple-loop-interchange.cc +--- a/gcc/gimple-loop-interchange.cc 1970-01-01 08:00:00.000000000 +0800 ++++ b/gcc/gimple-loop-interchange.cc 2018-11-15 16:03:17.443054436 +0800 +@@ -0,0 +1,2039 @@ ++/* Loop interchange. ++ Copyright (C) 2017 Free Software Foundation, Inc. ++ Contributed by ARM Ltd. ++ ++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 ++. */ ++ ++#include "config.h" ++#include "system.h" ++#include "coretypes.h" ++#include "backend.h" ++#include "is-a.h" ++#include "tree.h" ++#include "gimple.h" ++#include "tree-pass.h" ++#include "ssa.h" ++#include "gimple-pretty-print.h" ++#include "fold-const.h" ++#include "gimplify.h" ++#include "gimple-iterator.h" ++#include "gimplify-me.h" ++#include "cfgloop.h" ++#include "params.h" ++#include "tree-ssa.h" ++#include "tree-scalar-evolution.h" ++#include "tree-ssa-loop-manip.h" ++#include "tree-ssa-loop-niter.h" ++#include "tree-ssa-loop-ivopts.h" ++#include "tree-ssa-dce.h" ++#include "tree-data-ref.h" ++#include "tree-vectorizer.h" ++ ++/* This pass performs loop interchange: for example, the loop nest ++ ++ for (int j = 0; j < N; j++) ++ for (int k = 0; k < N; k++) ++ for (int i = 0; i < N; i++) ++ c[i][j] = c[i][j] + a[i][k]*b[k][j]; ++ ++ is transformed to ++ ++ for (int i = 0; i < N; i++) ++ for (int j = 0; j < N; j++) ++ for (int k = 0; k < N; k++) ++ c[i][j] = c[i][j] + a[i][k]*b[k][j]; ++ ++ This pass implements loop interchange in the following steps: ++ ++ 1) Find perfect loop nest for each innermost loop and compute data ++ dependence relations for it. For above example, loop nest is ++ . ++ 2) From innermost to outermost loop, this pass tries to interchange ++ each loop pair. For above case, it firstly tries to interchange ++ and loop nest becomes . ++ Then it tries to interchange and loop nest becomes ++ . The overall effect is to move innermost ++ loop to the outermost position. For loop pair ++ to be interchanged, we: ++ 3) Check if data dependence relations are valid for loop interchange. ++ 4) Check if both loops can be interchanged in terms of transformation. ++ 5) Check if interchanging the two loops is profitable. ++ 6) Interchange the two loops by mapping induction variables. ++ ++ This pass also handles reductions in loop nest. So far we only support ++ simple reduction of inner loop and double reduction of the loop nest. */ ++ ++/* Maximum number of stmts in each loop that should be interchanged. */ ++#define MAX_NUM_STMT (PARAM_VALUE (PARAM_LOOP_INTERCHANGE_MAX_NUM_STMTS)) ++/* Maximum number of data references in loop nest. */ ++#define MAX_DATAREFS (PARAM_VALUE (PARAM_LOOP_MAX_DATAREFS_FOR_DATADEPS)) ++ ++/* Comparison ratio of access stride between inner/outer loops to be ++ interchanged. This is the minimum stride ratio for loop interchange ++ to be profitable. */ ++#define OUTER_STRIDE_RATIO (PARAM_VALUE (PARAM_LOOP_INTERCHANGE_STRIDE_RATIO)) ++/* The same as above, but we require higher ratio for interchanging the ++ innermost two loops. */ ++#define INNER_STRIDE_RATIO ((OUTER_STRIDE_RATIO) + 1) ++ ++/* Vector of strides that DR accesses in each level loop of a loop nest. */ ++#define DR_ACCESS_STRIDE(dr) ((vec *) dr->aux) ++ ++/* Structure recording loop induction variable. */ ++typedef struct induction ++{ ++ /* IV itself. */ ++ tree var; ++ /* IV's initializing value, which is the init arg of the IV PHI node. */ ++ tree init_val; ++ /* IV's initializing expr, which is (the expanded result of) init_val. */ ++ tree init_expr; ++ /* IV's step. */ ++ tree step; ++} *induction_p; ++ ++/* Enum type for loop reduction variable. */ ++enum reduction_type ++{ ++ UNKNOWN_RTYPE = 0, ++ SIMPLE_RTYPE, ++ DOUBLE_RTYPE ++}; ++ ++/* Structure recording loop reduction variable. */ ++typedef struct reduction ++{ ++ /* Reduction itself. */ ++ tree var; ++ /* PHI node defining reduction variable. */ ++ gphi *phi; ++ /* Init and next variables of the reduction. */ ++ tree init; ++ tree next; ++ /* Lcssa PHI node if reduction is used outside of its definition loop. */ ++ gphi *lcssa_phi; ++ /* Stmts defining init and next. */ ++ gimple *producer; ++ gimple *consumer; ++ /* If init is loaded from memory, this is the loading memory reference. */ ++ tree init_ref; ++ /* If reduction is finally stored to memory, this is the stored memory ++ reference. */ ++ tree fini_ref; ++ enum reduction_type type; ++} *reduction_p; ++ ++ ++/* Dump reduction RE. */ ++ ++static void ++dump_reduction (reduction_p re) ++{ ++ if (re->type == SIMPLE_RTYPE) ++ fprintf (dump_file, " Simple reduction: "); ++ else if (re->type == DOUBLE_RTYPE) ++ fprintf (dump_file, " Double reduction: "); ++ else ++ fprintf (dump_file, " Unknown reduction: "); ++ ++ print_gimple_stmt (dump_file, re->phi, 0); ++} ++ ++/* Dump LOOP's induction IV. */ ++static void ++dump_induction (struct loop *loop, induction_p iv) ++{ ++ fprintf (dump_file, " Induction: "); ++ print_generic_expr (dump_file, iv->var, TDF_SLIM); ++ fprintf (dump_file, " = {"); ++ print_generic_expr (dump_file, iv->init_expr, TDF_SLIM); ++ fprintf (dump_file, ", "); ++ print_generic_expr (dump_file, iv->step, TDF_SLIM); ++ fprintf (dump_file, "}_%d\n", loop->num); ++} ++ ++/* Loop candidate for interchange. */ ++ ++struct loop_cand ++{ ++ loop_cand (struct loop *, struct loop *); ++ ~loop_cand (); ++ ++ reduction_p find_reduction_by_stmt (gimple *); ++ void classify_simple_reduction (reduction_p); ++ bool analyze_iloop_reduction_var (tree); ++ bool analyze_oloop_reduction_var (loop_cand *, tree); ++ bool analyze_induction_var (tree, tree); ++ bool analyze_carried_vars (loop_cand *); ++ bool analyze_lcssa_phis (void); ++ bool can_interchange_p (loop_cand *); ++ bool supported_operations (basic_block, loop_cand *, int *); ++ void undo_simple_reduction (reduction_p, bitmap); ++ ++ /* The loop itself. */ ++ struct loop *m_loop; ++ /* The outer loop for interchange. It equals to loop if this loop cand ++ itself represents the outer loop. */ ++ struct loop *m_outer; ++ /* Vector of induction variables in loop. */ ++ vec m_inductions; ++ /* Vector of reduction variables in loop. */ ++ vec m_reductions; ++ /* Lcssa PHI nodes of this loop. */ ++ vec m_lcssa_nodes; ++ /* Single exit edge of this loop. */ ++ edge m_exit; ++ /* Basic blocks of this loop. */ ++ basic_block *m_bbs; ++}; ++ ++/* Constructor. */ ++ ++loop_cand::loop_cand (struct loop *loop, struct loop *outer) ++ : m_loop (loop), m_outer (outer), ++ m_exit (single_exit (loop)), m_bbs (get_loop_body (loop)) ++{ ++ m_inductions.create (3); ++ m_reductions.create (3); ++ m_lcssa_nodes.create (3); ++} ++ ++/* Destructor. */ ++ ++loop_cand::~loop_cand () ++{ ++ induction_p iv; ++ for (unsigned i = 0; m_inductions.iterate (i, &iv); ++i) ++ free (iv); ++ ++ reduction_p re; ++ for (unsigned i = 0; m_reductions.iterate (i, &re); ++i) ++ free (re); ++ ++ m_inductions.release (); ++ m_reductions.release (); ++ m_lcssa_nodes.release (); ++ free (m_bbs); ++} ++ ++/* Return single use stmt of VAR in LOOP, otherwise return NULL. */ ++ ++static gimple * ++single_use_in_loop (tree var, struct loop *loop) ++{ ++ gimple *stmt, *res = NULL; ++ use_operand_p use_p; ++ imm_use_iterator iterator; ++ ++ FOR_EACH_IMM_USE_FAST (use_p, iterator, var) ++ { ++ stmt = USE_STMT (use_p); ++ if (is_gimple_debug (stmt)) ++ continue; ++ ++ if (!flow_bb_inside_loop_p (loop, gimple_bb (stmt))) ++ continue; ++ ++ if (res) ++ return NULL; ++ ++ res = stmt; ++ } ++ return res; ++} ++ ++/* Return true if E is unsupported in loop interchange, i.e, E is a complex ++ edge or part of irreducible loop. */ ++ ++static inline bool ++unsupported_edge (edge e) ++{ ++ return (e->flags & (EDGE_COMPLEX | EDGE_IRREDUCIBLE_LOOP)); ++} ++ ++/* Return the reduction if STMT is one of its lcssa PHI, producer or consumer ++ stmt. */ ++ ++reduction_p ++loop_cand::find_reduction_by_stmt (gimple *stmt) ++{ ++ gphi *phi = dyn_cast (stmt); ++ reduction_p re; ++ ++ for (unsigned i = 0; m_reductions.iterate (i, &re); ++i) ++ if ((phi != NULL && phi == re->lcssa_phi) ++ || (stmt == re->producer || stmt == re->consumer)) ++ return re; ++ ++ return NULL; ++} ++ ++/* Return true if all stmts in BB can be supported by loop interchange, ++ otherwise return false. ILOOP is not NULL if this loop_cand is the ++ outer loop in loop nest. Add the number of supported statements to ++ NUM_STMTS. */ ++ ++bool ++loop_cand::supported_operations (basic_block bb, loop_cand *iloop, ++ int *num_stmts) ++{ ++ int bb_num_stmts = 0; ++ gphi_iterator psi; ++ gimple_stmt_iterator gsi; ++ ++ for (gsi = gsi_start_bb (bb); !gsi_end_p (gsi); gsi_next (&gsi)) ++ { ++ gimple *stmt = gsi_stmt (gsi); ++ if (is_gimple_debug (stmt)) ++ continue; ++ ++ if (gimple_has_side_effects (stmt)) ++ return false; ++ ++ bb_num_stmts++; ++ if (gcall *call = dyn_cast (stmt)) ++ { ++ /* In basic block of outer loop, the call should be cheap since ++ it will be moved to inner loop. */ ++ if (iloop != NULL ++ && !gimple_inexpensive_call_p (call)) ++ return false; ++ continue; ++ } ++ ++ if (!iloop || !gimple_vuse (stmt)) ++ continue; ++ ++ /* Support stmt accessing memory in outer loop only if it is for inner ++ loop's reduction. */ ++ if (iloop->find_reduction_by_stmt (stmt)) ++ continue; ++ ++ tree lhs; ++ /* Support loop invariant memory reference if it's only used once by ++ inner loop. */ ++ /* ??? How's this checking for invariantness? */ ++ if (gimple_assign_single_p (stmt) ++ && (lhs = gimple_assign_lhs (stmt)) != NULL_TREE ++ && TREE_CODE (lhs) == SSA_NAME ++ && single_use_in_loop (lhs, iloop->m_loop)) ++ continue; ++ ++ return false; ++ } ++ *num_stmts += bb_num_stmts; ++ ++ /* Allow PHI nodes in any basic block of inner loop, PHI nodes in outer ++ loop's header, or PHI nodes in dest bb of inner loop's exit edge. */ ++ if (!iloop || bb == m_loop->header ++ || bb == iloop->m_exit->dest) ++ return true; ++ ++ /* Don't allow any other PHI nodes. */ ++ for (psi = gsi_start_phis (bb); !gsi_end_p (psi); gsi_next (&psi)) ++ if (!virtual_operand_p (PHI_RESULT (psi.phi ()))) ++ return false; ++ ++ return true; ++} ++ ++/* Return true if current loop_cand be interchanged. ILOOP is not NULL if ++ current loop_cand is outer loop in loop nest. */ ++ ++bool ++loop_cand::can_interchange_p (loop_cand *iloop) ++{ ++ /* For now we only support at most one reduction. */ ++ unsigned allowed_reduction_num = 1; ++ ++ /* Only support reduction if the loop nest to be interchanged is the ++ innermostin two loops. */ ++ if ((iloop == NULL && m_loop->inner != NULL) ++ || (iloop != NULL && iloop->m_loop->inner != NULL)) ++ allowed_reduction_num = 0; ++ ++ if (m_reductions.length () > allowed_reduction_num ++ || (m_reductions.length () == 1 ++ && m_reductions[0]->type == UNKNOWN_RTYPE)) ++ return false; ++ ++ /* Only support lcssa PHI node which is for reduction. */ ++ if (m_lcssa_nodes.length () > allowed_reduction_num) ++ return false; ++ ++ int num_stmts = 0; ++ /* Check basic blocks other than loop header/exit. */ ++ for (unsigned i = 0; i < m_loop->num_nodes; i++) ++ { ++ basic_block bb = m_bbs[i]; ++ ++ /* Skip basic blocks of inner loops. */ ++ if (bb->loop_father != m_loop) ++ continue; ++ ++ /* Check if basic block has any unsupported operation. */ ++ if (!supported_operations (bb, iloop, &num_stmts)) ++ return false; ++ ++ /* Check if loop has too many stmts. */ ++ if (num_stmts > MAX_NUM_STMT) ++ return false; ++ } ++ ++ return true; ++} ++ ++/* Programmers and optimizers (like loop store motion) may optimize code: ++ ++ for (int i = 0; i < N; i++) ++ for (int j = 0; j < N; j++) ++ a[i] += b[j][i] * c[j][i]; ++ ++ into reduction: ++ ++ for (int i = 0; i < N; i++) ++ { ++ // producer. Note sum can be intitialized to a constant. ++ int sum = a[i]; ++ for (int j = 0; j < N; j++) ++ { ++ sum += b[j][i] * c[j][i]; ++ } ++ // consumer. ++ a[i] = sum; ++ } ++ ++ The result code can't be interchanged without undoing the optimization. ++ This function classifies this kind reduction and records information so ++ that we can undo the store motion during interchange. */ ++ ++void ++loop_cand::classify_simple_reduction (reduction_p re) ++{ ++ gimple *producer, *consumer; ++ ++ /* Check init variable of reduction and how it is initialized. */ ++ if (TREE_CODE (re->init) == SSA_NAME) ++ { ++ producer = SSA_NAME_DEF_STMT (re->init); ++ re->producer = producer; ++ basic_block bb = gimple_bb (producer); ++ if (!bb || bb->loop_father != m_outer) ++ return; ++ ++ if (!gimple_assign_load_p (producer)) ++ return; ++ ++ re->init_ref = gimple_assign_rhs1 (producer); ++ } ++ else if (!CONSTANT_CLASS_P (re->init)) ++ return; ++ ++ /* Check how reduction variable is used. */ ++ consumer = single_use_in_loop (PHI_RESULT (re->lcssa_phi), m_outer); ++ if (!consumer ++ || !gimple_store_p (consumer)) ++ return; ++ ++ re->fini_ref = gimple_get_lhs (consumer); ++ re->consumer = consumer; ++ ++ /* Simple reduction with constant initializer. */ ++ if (!re->init_ref) ++ { ++ gcc_assert (CONSTANT_CLASS_P (re->init)); ++ re->init_ref = unshare_expr (re->fini_ref); ++ } ++ ++ /* Require memory references in producer and consumer are the same so ++ that we can undo reduction during interchange. */ ++ if (re->init_ref && !operand_equal_p (re->init_ref, re->fini_ref, 0)) ++ return; ++ ++ re->type = SIMPLE_RTYPE; ++} ++ ++/* Analyze reduction variable VAR for inner loop of the loop nest to be ++ interchanged. Return true if analysis succeeds. */ ++ ++bool ++loop_cand::analyze_iloop_reduction_var (tree var) ++{ ++ gphi *phi = as_a (SSA_NAME_DEF_STMT (var)); ++ gphi *lcssa_phi = NULL, *use_phi; ++ tree init = PHI_ARG_DEF_FROM_EDGE (phi, loop_preheader_edge (m_loop)); ++ tree next = PHI_ARG_DEF_FROM_EDGE (phi, loop_latch_edge (m_loop)); ++ reduction_p re; ++ gimple *stmt, *next_def, *single_use = NULL; ++ use_operand_p use_p; ++ imm_use_iterator iterator; ++ ++ if (TREE_CODE (next) != SSA_NAME) ++ return false; ++ ++ next_def = SSA_NAME_DEF_STMT (next); ++ basic_block bb = gimple_bb (next_def); ++ if (!bb || !flow_bb_inside_loop_p (m_loop, bb)) ++ return false; ++ ++ /* In restricted reduction, the var is (and must be) used in defining ++ the updated var. The process can be depicted as below: ++ ++ var ;; = PHI ++ | ++ | ++ v ++ +---------------------+ ++ | reduction operators | <-- other operands ++ +---------------------+ ++ | ++ | ++ v ++ next ++ ++ In terms loop interchange, we don't change how NEXT is computed based ++ on VAR and OTHER OPERANDS. In case of double reduction in loop nest ++ to be interchanged, we don't changed it at all. In the case of simple ++ reduction in inner loop, we only make change how VAR/NEXT is loaded or ++ stored. With these conditions, we can relax restrictions on reduction ++ in a way that reduction operation is seen as black box. In general, ++ we can ignore reassociation of reduction operator; we can handle fake ++ reductions in which VAR is not even used to compute NEXT. */ ++ if (! single_imm_use (var, &use_p, &single_use) ++ || ! flow_bb_inside_loop_p (m_loop, gimple_bb (single_use))) ++ return false; ++ ++ /* Check the reduction operation. We require a left-associative operation. ++ For FP math we also need to be allowed to associate operations. */ ++ if (gassign *ass = dyn_cast (single_use)) ++ { ++ enum tree_code code = gimple_assign_rhs_code (ass); ++ if (! (associative_tree_code (code) ++ || (code == MINUS_EXPR ++ && use_p->use == gimple_assign_rhs1_ptr (ass))) ++ || (FLOAT_TYPE_P (TREE_TYPE (var)) ++ && ! flag_associative_math)) ++ return false; ++ } ++ else ++ return false; ++ ++ /* Handle and verify a series of stmts feeding the reduction op. */ ++ if (single_use != next_def ++ && !check_reduction_path (UNKNOWN_LOCATION, m_loop, phi, next, ++ gimple_assign_rhs_code (single_use))) ++ return false; ++ ++ /* Only support cases in which INIT is used in inner loop. */ ++ if (TREE_CODE (init) == SSA_NAME) ++ FOR_EACH_IMM_USE_FAST (use_p, iterator, init) ++ { ++ stmt = USE_STMT (use_p); ++ if (is_gimple_debug (stmt)) ++ continue; ++ ++ if (!flow_bb_inside_loop_p (m_loop, gimple_bb (stmt))) ++ return false; ++ } ++ ++ FOR_EACH_IMM_USE_FAST (use_p, iterator, next) ++ { ++ stmt = USE_STMT (use_p); ++ if (is_gimple_debug (stmt)) ++ continue; ++ ++ /* Or else it's used in PHI itself. */ ++ use_phi = dyn_cast (stmt); ++ if (use_phi == phi) ++ continue; ++ ++ if (use_phi != NULL ++ && lcssa_phi == NULL ++ && gimple_bb (stmt) == m_exit->dest ++ && PHI_ARG_DEF_FROM_EDGE (use_phi, m_exit) == next) ++ lcssa_phi = use_phi; ++ else ++ return false; ++ } ++ if (!lcssa_phi) ++ return false; ++ ++ re = XCNEW (struct reduction); ++ re->var = var; ++ re->init = init; ++ re->next = next; ++ re->phi = phi; ++ re->lcssa_phi = lcssa_phi; ++ ++ classify_simple_reduction (re); ++ ++ if (dump_file && (dump_flags & TDF_DETAILS)) ++ dump_reduction (re); ++ ++ m_reductions.safe_push (re); ++ return true; ++} ++ ++/* Analyze reduction variable VAR for outer loop of the loop nest to be ++ interchanged. ILOOP is not NULL and points to inner loop. For the ++ moment, we only support double reduction for outer loop, like: ++ ++ for (int i = 0; i < n; i++) ++ { ++ int sum = 0; ++ ++ for (int j = 0; j < n; j++) // outer loop ++ for (int k = 0; k < n; k++) // inner loop ++ sum += a[i][k]*b[k][j]; ++ ++ s[i] = sum; ++ } ++ ++ Note the innermost two loops are the loop nest to be interchanged. ++ Return true if analysis succeeds. */ ++ ++bool ++loop_cand::analyze_oloop_reduction_var (loop_cand *iloop, tree var) ++{ ++ gphi *phi = as_a (SSA_NAME_DEF_STMT (var)); ++ gphi *lcssa_phi = NULL, *use_phi; ++ tree init = PHI_ARG_DEF_FROM_EDGE (phi, loop_preheader_edge (m_loop)); ++ tree next = PHI_ARG_DEF_FROM_EDGE (phi, loop_latch_edge (m_loop)); ++ reduction_p re; ++ gimple *stmt, *next_def; ++ use_operand_p use_p; ++ imm_use_iterator iterator; ++ ++ if (TREE_CODE (next) != SSA_NAME) ++ return false; ++ ++ next_def = SSA_NAME_DEF_STMT (next); ++ basic_block bb = gimple_bb (next_def); ++ if (!bb || !flow_bb_inside_loop_p (m_loop, bb)) ++ return false; ++ ++ /* Find inner loop's simple reduction that uses var as initializer. */ ++ reduction_p inner_re = NULL; ++ for (unsigned i = 0; iloop->m_reductions.iterate (i, &inner_re); ++i) ++ if (inner_re->init == var || operand_equal_p (inner_re->init, var, 0)) ++ break; ++ ++ if (inner_re == NULL ++ || inner_re->type != UNKNOWN_RTYPE ++ || inner_re->producer != phi) ++ return false; ++ ++ /* In case of double reduction, outer loop's reduction should be updated ++ by inner loop's simple reduction. */ ++ if (next_def != inner_re->lcssa_phi) ++ return false; ++ ++ /* Outer loop's reduction should only be used to initialize inner loop's ++ simple reduction. */ ++ if (! single_imm_use (var, &use_p, &stmt) ++ || stmt != inner_re->phi) ++ return false; ++ ++ /* Check this reduction is correctly used outside of loop via lcssa phi. */ ++ FOR_EACH_IMM_USE_FAST (use_p, iterator, next) ++ { ++ stmt = USE_STMT (use_p); ++ if (is_gimple_debug (stmt)) ++ continue; ++ ++ /* Or else it's used in PHI itself. */ ++ use_phi = dyn_cast (stmt); ++ if (use_phi == phi) ++ continue; ++ ++ if (lcssa_phi == NULL ++ && use_phi != NULL ++ && gimple_bb (stmt) == m_exit->dest ++ && PHI_ARG_DEF_FROM_EDGE (use_phi, m_exit) == next) ++ lcssa_phi = use_phi; ++ else ++ return false; ++ } ++ if (!lcssa_phi) ++ return false; ++ ++ re = XCNEW (struct reduction); ++ re->var = var; ++ re->init = init; ++ re->next = next; ++ re->phi = phi; ++ re->lcssa_phi = lcssa_phi; ++ re->type = DOUBLE_RTYPE; ++ inner_re->type = DOUBLE_RTYPE; ++ ++ if (dump_file && (dump_flags & TDF_DETAILS)) ++ dump_reduction (re); ++ ++ m_reductions.safe_push (re); ++ return true; ++} ++ ++/* Return true if VAR is induction variable of current loop whose scev is ++ specified by CHREC. */ ++ ++bool ++loop_cand::analyze_induction_var (tree var, tree chrec) ++{ ++ gphi *phi = as_a (SSA_NAME_DEF_STMT (var)); ++ tree init = PHI_ARG_DEF_FROM_EDGE (phi, loop_preheader_edge (m_loop)); ++ ++ /* Var is loop invariant, though it's unlikely to happen. */ ++ if (tree_does_not_contain_chrecs (chrec)) ++ { ++ struct induction *iv = XCNEW (struct induction); ++ iv->var = var; ++ iv->init_val = init; ++ iv->init_expr = chrec; ++ iv->step = build_int_cst (TREE_TYPE (chrec), 0); ++ m_inductions.safe_push (iv); ++ return true; ++ } ++ ++ if (TREE_CODE (chrec) != POLYNOMIAL_CHREC ++ || CHREC_VARIABLE (chrec) != (unsigned) m_loop->num ++ || tree_contains_chrecs (CHREC_LEFT (chrec), NULL) ++ || tree_contains_chrecs (CHREC_RIGHT (chrec), NULL)) ++ return false; ++ ++ struct induction *iv = XCNEW (struct induction); ++ iv->var = var; ++ iv->init_val = init; ++ iv->init_expr = CHREC_LEFT (chrec); ++ iv->step = CHREC_RIGHT (chrec); ++ ++ if (dump_file && (dump_flags & TDF_DETAILS)) ++ dump_induction (m_loop, iv); ++ ++ m_inductions.safe_push (iv); ++ return true; ++} ++ ++/* Return true if all loop carried variables defined in loop header can ++ be successfully analyzed. */ ++ ++bool ++loop_cand::analyze_carried_vars (loop_cand *iloop) ++{ ++ edge e = loop_preheader_edge (m_outer); ++ gphi_iterator gsi; ++ ++ if (dump_file && (dump_flags & TDF_DETAILS)) ++ fprintf (dump_file, "\nLoop(%d) carried vars:\n", m_loop->num); ++ ++ for (gsi = gsi_start_phis (m_loop->header); !gsi_end_p (gsi); gsi_next (&gsi)) ++ { ++ gphi *phi = gsi.phi (); ++ ++ tree var = PHI_RESULT (phi); ++ if (virtual_operand_p (var)) ++ continue; ++ ++ tree chrec = analyze_scalar_evolution (m_loop, var); ++ chrec = instantiate_scev (e, m_loop, chrec); ++ ++ /* Analyze var as reduction variable. */ ++ if (chrec_contains_undetermined (chrec) ++ || chrec_contains_symbols_defined_in_loop (chrec, m_outer->num)) ++ { ++ if (iloop && !analyze_oloop_reduction_var (iloop, var)) ++ return false; ++ if (!iloop && !analyze_iloop_reduction_var (var)) ++ return false; ++ } ++ /* Analyze var as induction variable. */ ++ else if (!analyze_induction_var (var, chrec)) ++ return false; ++ } ++ ++ return true; ++} ++ ++/* Return TRUE if loop closed PHI nodes can be analyzed successfully. */ ++ ++bool ++loop_cand::analyze_lcssa_phis (void) ++{ ++ gphi_iterator gsi; ++ for (gsi = gsi_start_phis (m_exit->dest); !gsi_end_p (gsi); gsi_next (&gsi)) ++ { ++ gphi *phi = gsi.phi (); ++ ++ if (virtual_operand_p (PHI_RESULT (phi))) ++ continue; ++ ++ /* TODO: We only support lcssa phi for reduction for now. */ ++ if (!find_reduction_by_stmt (phi)) ++ return false; ++ } ++ ++ return true; ++} ++ ++/* CONSUMER is a stmt in BB storing reduction result into memory object. ++ When the reduction is intialized from constant value, we need to add ++ a stmt loading from the memory object to target basic block in inner ++ loop during undoing the reduction. Problem is that memory reference ++ may use ssa variables not dominating the target basic block. This ++ function finds all stmts on which CONSUMER depends in basic block BB, ++ records and returns them via STMTS. */ ++ ++static void ++find_deps_in_bb_for_stmt (gimple_seq *stmts, basic_block bb, gimple *consumer) ++{ ++ auto_vec worklist; ++ use_operand_p use_p; ++ ssa_op_iter iter; ++ gimple *stmt, *def_stmt; ++ gimple_stmt_iterator gsi; ++ ++ /* First clear flag for stmts in bb. */ ++ for (gsi = gsi_start_bb (bb); !gsi_end_p (gsi); gsi_next (&gsi)) ++ gimple_set_plf (gsi_stmt (gsi), GF_PLF_1, false); ++ ++ /* DFS search all depended stmts in bb and mark flag for these stmts. */ ++ worklist.safe_push (consumer); ++ while (!worklist.is_empty ()) ++ { ++ stmt = worklist.pop (); ++ FOR_EACH_SSA_USE_OPERAND (use_p, stmt, iter, SSA_OP_USE) ++ { ++ def_stmt = SSA_NAME_DEF_STMT (USE_FROM_PTR (use_p)); ++ ++ if (is_a (def_stmt) ++ || gimple_bb (def_stmt) != bb ++ || gimple_plf (def_stmt, GF_PLF_1)) ++ continue; ++ ++ worklist.safe_push (def_stmt); ++ } ++ gimple_set_plf (stmt, GF_PLF_1, true); ++ } ++ for (gsi = gsi_start_bb_nondebug (bb); ++ !gsi_end_p (gsi) && (stmt = gsi_stmt (gsi)) != consumer;) ++ { ++ /* Move dep stmts to sequence STMTS. */ ++ if (gimple_plf (stmt, GF_PLF_1)) ++ { ++ gsi_remove (&gsi, false); ++ gimple_seq_add_stmt_without_update (stmts, stmt); ++ } ++ else ++ gsi_next_nondebug (&gsi); ++ } ++} ++ ++/* User can write, optimizers can generate simple reduction RE for inner ++ loop. In order to make interchange valid, we have to undo reduction by ++ moving producer and consumer stmts into the inner loop. For example, ++ below code: ++ ++ init = MEM_REF[idx]; //producer ++ loop: ++ var = phi ++ next = var op ... ++ reduc_sum = phi ++ MEM_REF[idx] = reduc_sum //consumer ++ ++ is transformed into: ++ ++ loop: ++ new_var = MEM_REF[idx]; //producer after moving ++ next = new_var op ... ++ MEM_REF[idx] = next; //consumer after moving ++ ++ Note if the reduction variable is initialized to constant, like: ++ ++ var = phi<0.0, next> ++ ++ we compute new_var as below: ++ ++ loop: ++ tmp = MEM_REF[idx]; ++ new_var = !first_iteration ? tmp : 0.0; ++ ++ so that the initial const is used in the first iteration of loop. Also ++ record ssa variables for dead code elimination in DCE_SEEDS. */ ++ ++void ++loop_cand::undo_simple_reduction (reduction_p re, bitmap dce_seeds) ++{ ++ gimple *stmt; ++ gimple_stmt_iterator from, to = gsi_after_labels (m_loop->header); ++ gimple_seq stmts = NULL; ++ tree new_var; ++ ++ /* Prepare the initialization stmts and insert it to inner loop. */ ++ if (re->producer != NULL) ++ { ++ gimple_set_vuse (re->producer, NULL_TREE); ++ from = gsi_for_stmt (re->producer); ++ gsi_remove (&from, false); ++ gimple_seq_add_stmt_without_update (&stmts, re->producer); ++ new_var = re->init; ++ } ++ else ++ { ++ /* Find all stmts on which expression "MEM_REF[idx]" depends. */ ++ find_deps_in_bb_for_stmt (&stmts, gimple_bb (re->consumer), re->consumer); ++ /* Because we generate new stmt loading from the MEM_REF to TMP. */ ++ tree cond, tmp = copy_ssa_name (re->var); ++ stmt = gimple_build_assign (tmp, re->init_ref); ++ gimple_seq_add_stmt_without_update (&stmts, stmt); ++ ++ /* Init new_var to MEM_REF or CONST depending on if it is the first ++ iteration. */ ++ induction_p iv = m_inductions[0]; ++ cond = fold_build2 (NE_EXPR, boolean_type_node, iv->var, iv->init_val); ++ new_var = copy_ssa_name (re->var); ++ stmt = gimple_build_assign (new_var, COND_EXPR, cond, tmp, re->init); ++ gimple_seq_add_stmt_without_update (&stmts, stmt); ++ } ++ gsi_insert_seq_before (&to, stmts, GSI_SAME_STMT); ++ ++ /* Replace all uses of reduction var with new variable. */ ++ use_operand_p use_p; ++ imm_use_iterator iterator; ++ FOR_EACH_IMM_USE_STMT (stmt, iterator, re->var) ++ { ++ FOR_EACH_IMM_USE_ON_STMT (use_p, iterator) ++ SET_USE (use_p, new_var); ++ ++ update_stmt (stmt); ++ } ++ ++ /* Move consumer stmt into inner loop, just after reduction next's def. */ ++ unlink_stmt_vdef (re->consumer); ++ release_ssa_name (gimple_vdef (re->consumer)); ++ gimple_set_vdef (re->consumer, NULL_TREE); ++ gimple_set_vuse (re->consumer, NULL_TREE); ++ gimple_assign_set_rhs1 (re->consumer, re->next); ++ from = gsi_for_stmt (re->consumer); ++ to = gsi_for_stmt (SSA_NAME_DEF_STMT (re->next)); ++ gsi_move_after (&from, &to); ++ ++ /* Mark the reduction variables for DCE. */ ++ bitmap_set_bit (dce_seeds, SSA_NAME_VERSION (re->var)); ++ bitmap_set_bit (dce_seeds, SSA_NAME_VERSION (PHI_RESULT (re->lcssa_phi))); ++} ++ ++/* Free DATAREFS and its auxiliary memory. */ ++ ++static void ++free_data_refs_with_aux (vec datarefs) ++{ ++ data_reference_p dr; ++ for (unsigned i = 0; datarefs.iterate (i, &dr); ++i) ++ if (dr->aux != NULL) ++ { ++ DR_ACCESS_STRIDE (dr)->release (); ++ free (dr->aux); ++ } ++ ++ free_data_refs (datarefs); ++} ++ ++/* Class for loop interchange transformation. */ ++ ++class tree_loop_interchange ++{ ++public: ++ tree_loop_interchange (vec loop_nest) ++ : m_loop_nest (loop_nest), m_niters_iv_var (NULL_TREE), ++ m_dce_seeds (BITMAP_ALLOC (NULL)) { } ++ ~tree_loop_interchange () { BITMAP_FREE (m_dce_seeds); } ++ bool interchange (vec, vec); ++ ++private: ++ void update_data_info (unsigned, unsigned, vec, vec); ++ bool valid_data_dependences (unsigned, unsigned, vec); ++ void interchange_loops (loop_cand &, loop_cand &); ++ void map_inductions_to_loop (loop_cand &, loop_cand &); ++ void move_code_to_inner_loop (struct loop *, struct loop *, basic_block *); ++ ++ /* The whole loop nest in which interchange is ongoing. */ ++ vec m_loop_nest; ++ /* We create new IV which is only used in loop's exit condition check. ++ In case of 3-level loop nest interchange, when we interchange the ++ innermost two loops, new IV created in the middle level loop does ++ not need to be preserved in interchanging the outermost two loops ++ later. We record the IV so that it can be skipped. */ ++ tree m_niters_iv_var; ++ /* Bitmap of seed variables for dead code elimination after interchange. */ ++ bitmap m_dce_seeds; ++}; ++ ++/* Update data refs' access stride and dependence information after loop ++ interchange. I_IDX/O_IDX gives indices of interchanged loops in loop ++ nest. DATAREFS are data references. DDRS are data dependences. */ ++ ++void ++tree_loop_interchange::update_data_info (unsigned i_idx, unsigned o_idx, ++ vec datarefs, ++ vec ddrs) ++{ ++ struct data_reference *dr; ++ struct data_dependence_relation *ddr; ++ ++ /* Update strides of data references. */ ++ for (unsigned i = 0; datarefs.iterate (i, &dr); ++i) ++ { ++ vec *stride = DR_ACCESS_STRIDE (dr); ++ gcc_assert (stride->length () > i_idx); ++ std::swap ((*stride)[i_idx], (*stride)[o_idx]); ++ } ++ /* Update data dependences. */ ++ for (unsigned i = 0; ddrs.iterate (i, &ddr); ++i) ++ if (DDR_ARE_DEPENDENT (ddr) != chrec_known) ++ { ++ for (unsigned j = 0; j < DDR_NUM_DIST_VECTS (ddr); ++j) ++ { ++ lambda_vector dist_vect = DDR_DIST_VECT (ddr, j); ++ std::swap (dist_vect[i_idx], dist_vect[o_idx]); ++ } ++ } ++} ++ ++/* Check data dependence relations, return TRUE if it's valid to interchange ++ two loops specified by I_IDX/O_IDX. Theoretically, interchanging the two ++ loops is valid only if dist vector, after interchanging, doesn't have '>' ++ as the leftmost non-'=' direction. Practically, this function have been ++ conservative here by not checking some valid cases. */ ++ ++bool ++tree_loop_interchange::valid_data_dependences (unsigned i_idx, unsigned o_idx, ++ vec ddrs) ++{ ++ struct data_dependence_relation *ddr; ++ ++ for (unsigned i = 0; ddrs.iterate (i, &ddr); ++i) ++ { ++ /* Skip no-dependence case. */ ++ if (DDR_ARE_DEPENDENT (ddr) == chrec_known) ++ continue; ++ ++ for (unsigned j = 0; j < DDR_NUM_DIST_VECTS (ddr); ++j) ++ { ++ lambda_vector dist_vect = DDR_DIST_VECT (ddr, j); ++ unsigned level = dependence_level (dist_vect, m_loop_nest.length ()); ++ ++ /* If there is no carried dependence. */ ++ if (level == 0) ++ continue; ++ ++ level --; ++ ++ /* If dependence is not carried by any loop in between the two ++ loops [oloop, iloop] to interchange. */ ++ if (level < o_idx || level > i_idx) ++ continue; ++ ++ /* Be conservative, skip case if either direction at i_idx/o_idx ++ levels is not '=' or '<'. */ ++ if (dist_vect[i_idx] < 0 || dist_vect[o_idx] < 0) ++ return false; ++ } ++ } ++ ++ return true; ++} ++ ++/* Interchange two loops specified by ILOOP and OLOOP. */ ++ ++void ++tree_loop_interchange::interchange_loops (loop_cand &iloop, loop_cand &oloop) ++{ ++ reduction_p re; ++ gimple_stmt_iterator gsi; ++ tree i_niters, o_niters, var_after; ++ ++ /* Undo inner loop's simple reduction. */ ++ for (unsigned i = 0; iloop.m_reductions.iterate (i, &re); ++i) ++ if (re->type != DOUBLE_RTYPE) ++ { ++ if (re->producer) ++ reset_debug_uses (re->producer); ++ ++ iloop.undo_simple_reduction (re, m_dce_seeds); ++ } ++ ++ /* Only need to reset debug uses for double reduction. */ ++ for (unsigned i = 0; oloop.m_reductions.iterate (i, &re); ++i) ++ { ++ gcc_assert (re->type == DOUBLE_RTYPE); ++ reset_debug_uses (SSA_NAME_DEF_STMT (re->var)); ++ reset_debug_uses (SSA_NAME_DEF_STMT (re->next)); ++ } ++ ++ /* Prepare niters for both loops. */ ++ struct loop *loop_nest = m_loop_nest[0]; ++ edge instantiate_below = loop_preheader_edge (loop_nest); ++ gsi = gsi_last_bb (loop_preheader_edge (loop_nest)->src); ++ i_niters = number_of_latch_executions (iloop.m_loop); ++ i_niters = analyze_scalar_evolution (loop_outer (iloop.m_loop), i_niters); ++ i_niters = instantiate_scev (instantiate_below, loop_outer (iloop.m_loop), ++ i_niters); ++ i_niters = force_gimple_operand_gsi (&gsi, unshare_expr (i_niters), true, ++ NULL_TREE, false, GSI_CONTINUE_LINKING); ++ o_niters = number_of_latch_executions (oloop.m_loop); ++ if (oloop.m_loop != loop_nest) ++ { ++ o_niters = analyze_scalar_evolution (loop_outer (oloop.m_loop), o_niters); ++ o_niters = instantiate_scev (instantiate_below, loop_outer (oloop.m_loop), ++ o_niters); ++ } ++ o_niters = force_gimple_operand_gsi (&gsi, unshare_expr (o_niters), true, ++ NULL_TREE, false, GSI_CONTINUE_LINKING); ++ ++ /* Move src's code to tgt loop. This is necessary when src is the outer ++ loop and tgt is the inner loop. */ ++ move_code_to_inner_loop (oloop.m_loop, iloop.m_loop, oloop.m_bbs); ++ ++ /* Map outer loop's IV to inner loop, and vice versa. */ ++ map_inductions_to_loop (oloop, iloop); ++ map_inductions_to_loop (iloop, oloop); ++ ++ /* Create canonical IV for both loops. Note canonical IV for outer/inner ++ loop is actually from inner/outer loop. Also we record the new IV ++ created for the outer loop so that it can be skipped in later loop ++ interchange. */ ++ create_canonical_iv (oloop.m_loop, oloop.m_exit, ++ i_niters, &m_niters_iv_var, &var_after); ++ bitmap_set_bit (m_dce_seeds, SSA_NAME_VERSION (var_after)); ++ create_canonical_iv (iloop.m_loop, iloop.m_exit, ++ o_niters, NULL, &var_after); ++ bitmap_set_bit (m_dce_seeds, SSA_NAME_VERSION (var_after)); ++ ++ /* Scrap niters estimation of interchanged loops. */ ++ iloop.m_loop->any_upper_bound = false; ++ iloop.m_loop->any_likely_upper_bound = false; ++ free_numbers_of_iterations_estimates_loop (iloop.m_loop); ++ oloop.m_loop->any_upper_bound = false; ++ oloop.m_loop->any_likely_upper_bound = false; ++ free_numbers_of_iterations_estimates_loop (oloop.m_loop); ++ ++ /* ??? The association between the loop data structure and the ++ CFG changed, so what was loop N at the source level is now ++ loop M. We should think of retaining the association or breaking ++ it fully by creating a new loop instead of re-using the "wrong" one. */ ++} ++ ++/* Map induction variables of SRC loop to TGT loop. The function firstly ++ creates the same IV of SRC loop in TGT loop, then deletes the original ++ IV and re-initialize it using the newly created IV. For example, loop ++ nest: ++ ++ for (i = 0; i < N; i++) ++ for (j = 0; j < M; j++) ++ { ++ //use of i; ++ //use of j; ++ } ++ ++ will be transformed into: ++ ++ for (jj = 0; jj < M; jj++) ++ for (ii = 0; ii < N; ii++) ++ { ++ //use of ii; ++ //use of jj; ++ } ++ ++ after loop interchange. */ ++ ++void ++tree_loop_interchange::map_inductions_to_loop (loop_cand &src, loop_cand &tgt) ++{ ++ induction_p iv; ++ edge e = tgt.m_exit; ++ gimple_stmt_iterator incr_pos = gsi_last_bb (e->src), gsi; ++ ++ /* Map source loop's IV to target loop. */ ++ for (unsigned i = 0; src.m_inductions.iterate (i, &iv); ++i) ++ { ++ gimple *use_stmt, *stmt = SSA_NAME_DEF_STMT (iv->var); ++ gcc_assert (is_a (stmt)); ++ ++ use_operand_p use_p; ++ /* Only map original IV to target loop. */ ++ if (m_niters_iv_var != iv->var) ++ { ++ /* Map the IV by creating the same one in target loop. */ ++ tree var_before, var_after; ++ tree base = unshare_expr (iv->init_expr); ++ tree step = unshare_expr (iv->step); ++ create_iv (base, step, SSA_NAME_VAR (iv->var), ++ tgt.m_loop, &incr_pos, false, &var_before, &var_after); ++ bitmap_set_bit (m_dce_seeds, SSA_NAME_VERSION (var_before)); ++ bitmap_set_bit (m_dce_seeds, SSA_NAME_VERSION (var_after)); ++ ++ /* Replace uses of the original IV var with newly created IV var. */ ++ imm_use_iterator imm_iter; ++ FOR_EACH_IMM_USE_STMT (use_stmt, imm_iter, iv->var) ++ { ++ FOR_EACH_IMM_USE_ON_STMT (use_p, imm_iter) ++ SET_USE (use_p, var_before); ++ ++ update_stmt (use_stmt); ++ } ++ } ++ ++ /* Mark all uses for DCE. */ ++ ssa_op_iter op_iter; ++ FOR_EACH_PHI_OR_STMT_USE (use_p, stmt, op_iter, SSA_OP_USE) ++ { ++ tree use = USE_FROM_PTR (use_p); ++ if (TREE_CODE (use) == SSA_NAME ++ && ! SSA_NAME_IS_DEFAULT_DEF (use)) ++ bitmap_set_bit (m_dce_seeds, SSA_NAME_VERSION (use)); ++ } ++ ++ /* Delete definition of the original IV in the source loop. */ ++ gsi = gsi_for_stmt (stmt); ++ remove_phi_node (&gsi, true); ++ } ++} ++ ++/* Move stmts of outer loop to inner loop. */ ++ ++void ++tree_loop_interchange::move_code_to_inner_loop (struct loop *outer, ++ struct loop *inner, ++ basic_block *outer_bbs) ++{ ++ basic_block oloop_exit_bb = single_exit (outer)->src; ++ gimple_stmt_iterator gsi, to; ++ ++ for (unsigned i = 0; i < outer->num_nodes; i++) ++ { ++ basic_block bb = outer_bbs[i]; ++ ++ /* Skip basic blocks of inner loop. */ ++ if (flow_bb_inside_loop_p (inner, bb)) ++ continue; ++ ++ /* Move code from header/latch to header/latch. */ ++ if (bb == outer->header) ++ to = gsi_after_labels (inner->header); ++ else if (bb == outer->latch) ++ to = gsi_after_labels (inner->latch); ++ else ++ /* Otherwise, simply move to exit->src. */ ++ to = gsi_last_bb (single_exit (inner)->src); ++ ++ for (gsi = gsi_after_labels (bb); !gsi_end_p (gsi);) ++ { ++ gimple *stmt = gsi_stmt (gsi); ++ ++ if (oloop_exit_bb == bb ++ && stmt == gsi_stmt (gsi_last_bb (oloop_exit_bb))) ++ { ++ gsi_next (&gsi); ++ continue; ++ } ++ ++ if (gimple_vuse (stmt)) ++ gimple_set_vuse (stmt, NULL_TREE); ++ if (gimple_vdef (stmt)) ++ { ++ unlink_stmt_vdef (stmt); ++ release_ssa_name (gimple_vdef (stmt)); ++ gimple_set_vdef (stmt, NULL_TREE); ++ } ++ ++ reset_debug_uses (stmt); ++ gsi_move_before (&gsi, &to); ++ } ++ } ++} ++ ++/* Given data reference DR in LOOP_NEST, the function computes DR's access ++ stride at each level of loop from innermost LOOP to outer. On success, ++ it saves access stride at each level loop in a vector which is pointed ++ by DR->aux. For example: ++ ++ int arr[100][100][100]; ++ for (i = 0; i < 100; i++) ;(DR->aux)strides[0] = 40000 ++ for (j = 100; j > 0; j--) ;(DR->aux)strides[1] = 400 ++ for (k = 0; k < 100; k++) ;(DR->aux)strides[2] = 4 ++ arr[i][j - 1][k] = 0; */ ++ ++static void ++compute_access_stride (struct loop *loop_nest, struct loop *loop, ++ data_reference_p dr) ++{ ++ vec *strides = new vec (); ++ basic_block bb = gimple_bb (DR_STMT (dr)); ++ ++ while (!flow_bb_inside_loop_p (loop, bb)) ++ { ++ strides->safe_push (build_int_cst (sizetype, 0)); ++ loop = loop_outer (loop); ++ } ++ gcc_assert (loop == bb->loop_father); ++ ++ tree ref = DR_REF (dr); ++ tree scev_base = build_fold_addr_expr (ref); ++ tree scev = analyze_scalar_evolution (loop, scev_base); ++ scev = instantiate_scev (loop_preheader_edge (loop_nest), loop, scev); ++ if (! chrec_contains_undetermined (scev)) ++ { ++ tree sl = scev; ++ struct loop *expected = loop; ++ while (TREE_CODE (sl) == POLYNOMIAL_CHREC) ++ { ++ struct loop *sl_loop = get_chrec_loop (sl); ++ while (sl_loop != expected) ++ { ++ strides->safe_push (size_int (0)); ++ expected = loop_outer (expected); ++ } ++ strides->safe_push (CHREC_RIGHT (sl)); ++ sl = CHREC_LEFT (sl); ++ expected = loop_outer (expected); ++ } ++ if (! tree_contains_chrecs (sl, NULL)) ++ while (expected != loop_outer (loop_nest)) ++ { ++ strides->safe_push (size_int (0)); ++ expected = loop_outer (expected); ++ } ++ } ++ ++ dr->aux = strides; ++} ++ ++/* Given loop nest LOOP_NEST with innermost LOOP, the function computes ++ access strides with respect to each level loop for all data refs in ++ DATAREFS from inner loop to outer loop. On success, it returns the ++ outermost loop that access strides can be computed successfully for ++ all data references. If access strides cannot be computed at least ++ for two levels of loop for any data reference, it returns NULL. */ ++ ++static struct loop * ++compute_access_strides (struct loop *loop_nest, struct loop *loop, ++ vec datarefs) ++{ ++ unsigned i, j, num_loops = (unsigned) -1; ++ data_reference_p dr; ++ vec *stride; ++ ++ for (i = 0; datarefs.iterate (i, &dr); ++i) ++ { ++ compute_access_stride (loop_nest, loop, dr); ++ stride = DR_ACCESS_STRIDE (dr); ++ if (stride->length () < num_loops) ++ { ++ num_loops = stride->length (); ++ if (num_loops < 2) ++ return NULL; ++ } ++ } ++ ++ for (i = 0; datarefs.iterate (i, &dr); ++i) ++ { ++ stride = DR_ACCESS_STRIDE (dr); ++ if (stride->length () > num_loops) ++ stride->truncate (num_loops); ++ ++ for (j = 0; j < (num_loops >> 1); ++j) ++ std::swap ((*stride)[j], (*stride)[num_loops - j - 1]); ++ } ++ ++ loop = superloop_at_depth (loop, loop_depth (loop) + 1 - num_loops); ++ gcc_assert (loop_nest == loop || flow_loop_nested_p (loop_nest, loop)); ++ return loop; ++} ++ ++/* Prune access strides for data references in DATAREFS by removing strides ++ of loops that isn't in current LOOP_NEST. */ ++ ++static void ++prune_access_strides_not_in_loop (struct loop *loop_nest, ++ struct loop *innermost, ++ vec datarefs) ++{ ++ data_reference_p dr; ++ unsigned num_loops = loop_depth (innermost) - loop_depth (loop_nest) + 1; ++ gcc_assert (num_loops > 1); ++ ++ /* Block remove strides of loops that is not in current loop nest. */ ++ for (unsigned i = 0; datarefs.iterate (i, &dr); ++i) ++ { ++ vec *stride = DR_ACCESS_STRIDE (dr); ++ if (stride->length () > num_loops) ++ stride->block_remove (0, stride->length () - num_loops); ++ } ++} ++ ++/* Dump access strides for all DATAREFS. */ ++ ++static void ++dump_access_strides (vec datarefs) ++{ ++ data_reference_p dr; ++ fprintf (dump_file, "Access Strides for DRs:\n"); ++ for (unsigned i = 0; datarefs.iterate (i, &dr); ++i) ++ { ++ fprintf (dump_file, " "); ++ print_generic_expr (dump_file, DR_REF (dr), TDF_SLIM); ++ fprintf (dump_file, ":\t\t<"); ++ ++ vec *stride = DR_ACCESS_STRIDE (dr); ++ unsigned num_loops = stride->length (); ++ for (unsigned j = 0; j < num_loops; ++j) ++ { ++ print_generic_expr (dump_file, (*stride)[j], TDF_SLIM); ++ fprintf (dump_file, "%s", (j < num_loops - 1) ? ",\t" : ">\n"); ++ } ++ } ++} ++ ++/* Return true if it's profitable to interchange two loops whose index ++ in whole loop nest vector are I_IDX/O_IDX respectively. The function ++ computes and compares three types information from all DATAREFS: ++ 1) Access stride for loop I_IDX and O_IDX. ++ 2) Number of invariant memory references with respect to I_IDX before ++ and after loop interchange. ++ 3) Flags indicating if all memory references access sequential memory ++ in ILOOP, before and after loop interchange. ++ If INNMOST_LOOP_P is true, the two loops for interchanging are the two ++ innermost loops in loop nest. This function also dumps information if ++ DUMP_INFO_P is true. */ ++ ++static bool ++should_interchange_loops (unsigned i_idx, unsigned o_idx, ++ vec datarefs, ++ bool innermost_loops_p, bool dump_info_p = true) ++{ ++ unsigned HOST_WIDE_INT ratio; ++ unsigned i, j, num_old_inv_drs = 0, num_new_inv_drs = 0; ++ struct data_reference *dr; ++ bool all_seq_dr_before_p = true, all_seq_dr_after_p = true; ++ widest_int iloop_strides = 0, oloop_strides = 0; ++ unsigned num_unresolved_drs = 0; ++ unsigned num_resolved_ok_drs = 0; ++ unsigned num_resolved_not_ok_drs = 0; ++ ++ if (dump_info_p && dump_file && (dump_flags & TDF_DETAILS)) ++ fprintf (dump_file, "\nData ref strides:\n\tmem_ref:\t\tiloop\toloop\n"); ++ ++ for (i = 0; datarefs.iterate (i, &dr); ++i) ++ { ++ vec *stride = DR_ACCESS_STRIDE (dr); ++ tree iloop_stride = (*stride)[i_idx], oloop_stride = (*stride)[o_idx]; ++ ++ bool subloop_stride_p = false; ++ /* Data ref can't be invariant or sequential access at current loop if ++ its address changes with respect to any subloops. */ ++ for (j = i_idx + 1; j < stride->length (); ++j) ++ if (!integer_zerop ((*stride)[j])) ++ { ++ subloop_stride_p = true; ++ break; ++ } ++ ++ if (integer_zerop (iloop_stride)) ++ { ++ if (!subloop_stride_p) ++ num_old_inv_drs++; ++ } ++ if (integer_zerop (oloop_stride)) ++ { ++ if (!subloop_stride_p) ++ num_new_inv_drs++; ++ } ++ ++ if (TREE_CODE (iloop_stride) == INTEGER_CST ++ && TREE_CODE (oloop_stride) == INTEGER_CST) ++ { ++ iloop_strides = wi::add (iloop_strides, wi::to_widest (iloop_stride)); ++ oloop_strides = wi::add (oloop_strides, wi::to_widest (oloop_stride)); ++ } ++ else if (multiple_of_p (TREE_TYPE (iloop_stride), ++ iloop_stride, oloop_stride)) ++ num_resolved_ok_drs++; ++ else if (multiple_of_p (TREE_TYPE (iloop_stride), ++ oloop_stride, iloop_stride)) ++ num_resolved_not_ok_drs++; ++ else ++ num_unresolved_drs++; ++ ++ /* Data ref can't be sequential access if its address changes in sub ++ loop. */ ++ if (subloop_stride_p) ++ { ++ all_seq_dr_before_p = false; ++ all_seq_dr_after_p = false; ++ continue; ++ } ++ /* Track if all data references are sequential accesses before/after loop ++ interchange. Note invariant is considered sequential here. */ ++ tree access_size = TYPE_SIZE_UNIT (TREE_TYPE (DR_REF (dr))); ++ if (all_seq_dr_before_p ++ && ! (integer_zerop (iloop_stride) ++ || operand_equal_p (access_size, iloop_stride, 0))) ++ all_seq_dr_before_p = false; ++ if (all_seq_dr_after_p ++ && ! (integer_zerop (oloop_stride) ++ || operand_equal_p (access_size, oloop_stride, 0))) ++ all_seq_dr_after_p = false; ++ } ++ ++ if (dump_info_p && dump_file && (dump_flags & TDF_DETAILS)) ++ { ++ fprintf (dump_file, "\toverall:\t\t"); ++ print_decu (iloop_strides, dump_file); ++ fprintf (dump_file, "\t"); ++ print_decu (oloop_strides, dump_file); ++ fprintf (dump_file, "\n"); ++ ++ fprintf (dump_file, "Invariant data ref: before(%d), after(%d)\n", ++ num_old_inv_drs, num_new_inv_drs); ++ fprintf (dump_file, "All consecutive stride: before(%s), after(%s)\n", ++ all_seq_dr_before_p ? "true" : "false", ++ all_seq_dr_after_p ? "true" : "false"); ++ fprintf (dump_file, "OK to interchage with variable strides: %d\n", ++ num_resolved_ok_drs); ++ fprintf (dump_file, "Not OK to interchage with variable strides: %d\n", ++ num_resolved_not_ok_drs); ++ fprintf (dump_file, "Variable strides we cannot decide: %d\n", ++ num_unresolved_drs); ++ } ++ ++ if (num_unresolved_drs != 0 || num_resolved_not_ok_drs != 0) ++ return false; ++ ++ /* We use different stride comparison ratio for interchanging innermost ++ two loops or not. The idea is to be conservative in interchange for ++ the innermost loops. */ ++ ratio = innermost_loops_p ? INNER_STRIDE_RATIO : OUTER_STRIDE_RATIO; ++ /* Do interchange if it gives better data locality behavior. */ ++ if (wi::gtu_p (iloop_strides, wi::mul (oloop_strides, ratio))) ++ return true; ++ if (wi::gtu_p (iloop_strides, oloop_strides)) ++ { ++ /* Or it creates more invariant memory references. */ ++ if ((!all_seq_dr_before_p || all_seq_dr_after_p) ++ && num_new_inv_drs > num_old_inv_drs) ++ return true; ++ /* Or it makes all memory references sequential. */ ++ if (num_new_inv_drs >= num_old_inv_drs ++ && !all_seq_dr_before_p && all_seq_dr_after_p) ++ return true; ++ } ++ ++ return false; ++} ++ ++/* Try to interchange inner loop of a loop nest to outer level. */ ++ ++bool ++tree_loop_interchange::interchange (vec datarefs, ++ vec ddrs) ++{ ++ bool changed_p = false; ++ /* In each iteration we try to interchange I-th loop with (I+1)-th loop. ++ The overall effect is to push inner loop to outermost level in whole ++ loop nest. */ ++ for (unsigned i = m_loop_nest.length (); i > 1; --i) ++ { ++ unsigned i_idx = i - 1, o_idx = i - 2; ++ ++ /* Check validity for loop interchange. */ ++ if (!valid_data_dependences (i_idx, o_idx, ddrs)) ++ break; ++ ++ loop_cand iloop (m_loop_nest[i_idx], m_loop_nest[o_idx]); ++ loop_cand oloop (m_loop_nest[o_idx], m_loop_nest[o_idx]); ++ ++ /* Check if we can do transformation for loop interchange. */ ++ if (!iloop.analyze_carried_vars (NULL) ++ || !iloop.analyze_lcssa_phis () ++ || !oloop.analyze_carried_vars (&iloop) ++ || !oloop.analyze_lcssa_phis () ++ || !iloop.can_interchange_p (NULL) ++ || !oloop.can_interchange_p (&iloop)) ++ break; ++ ++ /* Check profitability for loop interchange. */ ++ if (should_interchange_loops (i_idx, o_idx, datarefs, ++ iloop.m_loop->inner == NULL)) ++ { ++ if (dump_file && (dump_flags & TDF_DETAILS)) ++ fprintf (dump_file, ++ "Loop_pair is interchanged\n\n", ++ oloop.m_loop->num, iloop.m_loop->num); ++ ++ changed_p = true; ++ interchange_loops (iloop, oloop); ++ /* No need to update if there is no further loop interchange. */ ++ if (o_idx > 0) ++ update_data_info (i_idx, o_idx, datarefs, ddrs); ++ } ++ else ++ { ++ if (dump_file && (dump_flags & TDF_DETAILS)) ++ fprintf (dump_file, ++ "Loop_pair is not interchanged\n\n", ++ oloop.m_loop->num, iloop.m_loop->num); ++ } ++ } ++ ++ simple_dce_from_worklist (m_dce_seeds); ++ return changed_p; ++} ++ ++ ++/* Loop interchange pass. */ ++ ++namespace { ++ ++const pass_data pass_data_linterchange = ++{ ++ GIMPLE_PASS, /* type */ ++ "linterchange", /* name */ ++ OPTGROUP_LOOP, /* optinfo_flags */ ++ TV_LINTERCHANGE, /* tv_id */ ++ PROP_cfg, /* properties_required */ ++ 0, /* properties_provided */ ++ 0, /* properties_destroyed */ ++ 0, /* todo_flags_start */ ++ 0, /* todo_flags_finish */ ++}; ++ ++class pass_linterchange : public gimple_opt_pass ++{ ++public: ++ pass_linterchange (gcc::context *ctxt) ++ : gimple_opt_pass (pass_data_linterchange, ctxt) ++ {} ++ ++ /* opt_pass methods: */ ++ opt_pass * clone () { return new pass_linterchange (m_ctxt); } ++ virtual bool gate (function *) { return flag_loop_interchange; } ++ virtual unsigned int execute (function *); ++ ++}; // class pass_linterchange ++ ++ ++/* Return true if LOOP has proper form for interchange. We check three ++ conditions in the function: ++ 1) In general, a loop can be interchanged only if it doesn't have ++ basic blocks other than header, exit and latch besides possible ++ inner loop nest. This basically restricts loop interchange to ++ below form loop nests: ++ ++ header<---+ ++ | | ++ v | ++ INNER_LOOP | ++ | | ++ v | ++ exit--->latch ++ ++ 2) Data reference in basic block that executes in different times ++ than loop head/exit is not allowed. ++ 3) Record the innermost outer loop that doesn't form rectangle loop ++ nest with LOOP. */ ++ ++static bool ++proper_loop_form_for_interchange (struct loop *loop, struct loop **min_outer) ++{ ++ edge e0, e1, exit; ++ ++ /* Don't interchange if loop has unsupported information for the moment. */ ++ if (loop->safelen > 0 ++ || loop->constraints != 0 ++ || loop->can_be_parallel ++ || loop->dont_vectorize ++ || loop->force_vectorize ++ || loop->in_oacc_kernels_region ++ || loop->orig_loop_num != 0 ++ || loop->simduid != NULL_TREE) ++ return false; ++ ++ /* Don't interchange if outer loop has basic block other than header, exit ++ and latch. */ ++ if (loop->inner != NULL ++ && loop->num_nodes != loop->inner->num_nodes + 3) ++ return false; ++ ++ if ((exit = single_dom_exit (loop)) == NULL) ++ return false; ++ ++ /* Check control flow on loop header/exit blocks. */ ++ if (loop->header == exit->src ++ && (EDGE_COUNT (loop->header->preds) != 2 ++ || EDGE_COUNT (loop->header->succs) != 2)) ++ return false; ++ else if (loop->header != exit->src ++ && (EDGE_COUNT (loop->header->preds) != 2 ++ || !single_succ_p (loop->header) ++ || unsupported_edge (single_succ_edge (loop->header)) ++ || EDGE_COUNT (exit->src->succs) != 2 ++ || !single_pred_p (exit->src) ++ || unsupported_edge (single_pred_edge (exit->src)))) ++ return false; ++ ++ e0 = EDGE_PRED (loop->header, 0); ++ e1 = EDGE_PRED (loop->header, 1); ++ if (unsupported_edge (e0) || unsupported_edge (e1) ++ || (e0->src != loop->latch && e1->src != loop->latch) ++ || (e0->src->loop_father == loop && e1->src->loop_father == loop)) ++ return false; ++ ++ e0 = EDGE_SUCC (exit->src, 0); ++ e1 = EDGE_SUCC (exit->src, 1); ++ if (unsupported_edge (e0) || unsupported_edge (e1) ++ || (e0->dest != loop->latch && e1->dest != loop->latch) ++ || (e0->dest->loop_father == loop && e1->dest->loop_father == loop)) ++ return false; ++ ++ /* Don't interchange if any reference is in basic block that doesn't ++ dominate exit block. */ ++ basic_block *bbs = get_loop_body (loop); ++ for (unsigned i = 0; i < loop->num_nodes; i++) ++ { ++ basic_block bb = bbs[i]; ++ ++ if (bb->loop_father != loop ++ || bb == loop->header || bb == exit->src ++ || dominated_by_p (CDI_DOMINATORS, exit->src, bb)) ++ continue; ++ ++ for (gimple_stmt_iterator gsi = gsi_start_bb_nondebug (bb); ++ !gsi_end_p (gsi); gsi_next_nondebug (&gsi)) ++ if (gimple_vuse (gsi_stmt (gsi))) ++ { ++ free (bbs); ++ return false; ++ } ++ } ++ free (bbs); ++ ++ tree niters = number_of_latch_executions (loop); ++ niters = analyze_scalar_evolution (loop_outer (loop), niters); ++ if (!niters || chrec_contains_undetermined (niters)) ++ return false; ++ ++ /* Record the innermost outer loop that doesn't form rectangle loop nest. */ ++ for (loop_p loop2 = loop_outer (loop); ++ loop2 && flow_loop_nested_p (*min_outer, loop2); ++ loop2 = loop_outer (loop2)) ++ { ++ niters = instantiate_scev (loop_preheader_edge (loop2), ++ loop_outer (loop), niters); ++ if (!evolution_function_is_invariant_p (niters, loop2->num)) ++ { ++ *min_outer = loop2; ++ break; ++ } ++ } ++ return true; ++} ++ ++/* Return true if any two adjacent loops in loop nest [INNERMOST, LOOP_NEST] ++ should be interchanged by looking into all DATAREFS. */ ++ ++static bool ++should_interchange_loop_nest (struct loop *loop_nest, struct loop *innermost, ++ vec datarefs) ++{ ++ unsigned idx = loop_depth (innermost) - loop_depth (loop_nest); ++ gcc_assert (idx > 0); ++ ++ /* Check if any two adjacent loops should be interchanged. */ ++ for (struct loop *loop = innermost; ++ loop != loop_nest; loop = loop_outer (loop), idx--) ++ if (should_interchange_loops (idx, idx - 1, datarefs, ++ loop == innermost, false)) ++ return true; ++ ++ return false; ++} ++ ++/* Given loop nest LOOP_NEST and data references DATAREFS, compute data ++ dependences for loop interchange and store it in DDRS. Note we compute ++ dependences directly rather than call generic interface so that we can ++ return on unknown dependence instantly. */ ++ ++static bool ++tree_loop_interchange_compute_ddrs (vec loop_nest, ++ vec datarefs, ++ vec *ddrs) ++{ ++ struct data_reference *a, *b; ++ struct loop *innermost = loop_nest.last (); ++ ++ for (unsigned i = 0; datarefs.iterate (i, &a); ++i) ++ { ++ bool a_outer_p = gimple_bb (DR_STMT (a))->loop_father != innermost; ++ for (unsigned j = i + 1; datarefs.iterate (j, &b); ++j) ++ if (DR_IS_WRITE (a) || DR_IS_WRITE (b)) ++ { ++ bool b_outer_p = gimple_bb (DR_STMT (b))->loop_father != innermost; ++ /* Don't support multiple write references in outer loop. */ ++ if (a_outer_p && b_outer_p && DR_IS_WRITE (a) && DR_IS_WRITE (b)) ++ return false; ++ ++ ddr_p ddr = initialize_data_dependence_relation (a, b, loop_nest); ++ ddrs->safe_push (ddr); ++ compute_affine_dependence (ddr, loop_nest[0]); ++ ++ /* Give up if ddr is unknown dependence or classic direct vector ++ is not available. */ ++ if (DDR_ARE_DEPENDENT (ddr) == chrec_dont_know ++ || (DDR_ARE_DEPENDENT (ddr) == NULL_TREE ++ && DDR_NUM_DIR_VECTS (ddr) == 0)) ++ return false; ++ ++ /* If either data references is in outer loop of nest, we require ++ no dependence here because the data reference need to be moved ++ into inner loop during interchange. */ ++ if (a_outer_p && b_outer_p ++ && operand_equal_p (DR_REF (a), DR_REF (b), 0)) ++ continue; ++ if (DDR_ARE_DEPENDENT (ddr) != chrec_known ++ && (a_outer_p || b_outer_p)) ++ return false; ++ } ++ } ++ ++ return true; ++} ++ ++/* Prune DATAREFS by removing any data reference not inside of LOOP. */ ++ ++static inline void ++prune_datarefs_not_in_loop (struct loop *loop, vec datarefs) ++{ ++ unsigned i, j; ++ struct data_reference *dr; ++ ++ for (i = 0, j = 0; datarefs.iterate (i, &dr); ++i) ++ { ++ if (flow_bb_inside_loop_p (loop, gimple_bb (DR_STMT (dr)))) ++ datarefs[j++] = dr; ++ else ++ { ++ if (dr->aux) ++ { ++ DR_ACCESS_STRIDE (dr)->release (); ++ free (dr->aux); ++ } ++ free_data_ref (dr); ++ } ++ } ++ datarefs.truncate (j); ++} ++ ++/* Find and store data references in DATAREFS for LOOP nest. If there's ++ difficult data reference in a basic block, we shrink the loop nest to ++ inner loop of that basic block's father loop. On success, return the ++ outer loop of the result loop nest. */ ++ ++static struct loop * ++prepare_data_references (struct loop *loop, vec *datarefs) ++{ ++ struct loop *loop_nest = loop; ++ vec *bb_refs; ++ basic_block bb, *bbs = get_loop_body_in_dom_order (loop); ++ ++ for (unsigned i = 0; i < loop->num_nodes; i++) ++ bbs[i]->aux = NULL; ++ ++ /* Find data references for all basic blocks. Shrink loop nest on difficult ++ data reference. */ ++ for (unsigned i = 0; loop_nest && i < loop->num_nodes; ++i) ++ { ++ bb = bbs[i]; ++ if (!flow_bb_inside_loop_p (loop_nest, bb)) ++ continue; ++ ++ bb_refs = new vec (); ++ if (find_data_references_in_bb (loop, bb, bb_refs) == chrec_dont_know) ++ { ++ loop_nest = bb->loop_father->inner; ++ if (loop_nest && !loop_nest->inner) ++ loop_nest = NULL; ++ ++ free_data_refs (*bb_refs); ++ delete bb_refs; ++ } ++ else if (bb_refs->is_empty ()) ++ delete bb_refs; ++ else ++ bb->aux = bb_refs; ++ } ++ ++ /* Collect all data references in loop nest. */ ++ for (unsigned i = 0; i < loop->num_nodes; i++) ++ { ++ bb = bbs[i]; ++ if (!bb->aux) ++ continue; ++ ++ bb_refs = (vec *) bb->aux; ++ if (loop_nest && flow_bb_inside_loop_p (loop_nest, bb)) ++ datarefs->safe_splice (*bb_refs); ++ else ++ free_data_refs (*bb_refs); ++ ++ delete bb_refs; ++ bb->aux = NULL; ++ } ++ free (bbs); ++ ++ return loop_nest; ++} ++ ++/* Given innermost LOOP, return true if perfect loop nest can be found and ++ data dependences can be computed. If succeed, record the perfect loop ++ nest in LOOP_NEST; record all data references in DATAREFS and record all ++ data dependence relations in DDRS. ++ ++ We do support a restricted form of imperfect loop nest, i.e, loop nest ++ with load/store in outer loop initializing/finalizing simple reduction ++ of the innermost loop. For such outer loop reference, we require that ++ it has no dependence with others sinve it will be moved to inner loop ++ in interchange. */ ++ ++static bool ++prepare_perfect_loop_nest (struct loop *loop, vec *loop_nest, ++ vec *datarefs, vec *ddrs) ++{ ++ struct loop *start_loop = NULL, *innermost = loop; ++ struct loop *outermost = loops_for_fn (cfun)->tree_root; ++ ++ /* Find loop nest from the innermost loop. The outermost is the innermost ++ outer*/ ++ while (loop->num != 0 && loop->inner == start_loop ++ && flow_loop_nested_p (outermost, loop)) ++ { ++ if (!proper_loop_form_for_interchange (loop, &outermost)) ++ break; ++ ++ start_loop = loop; ++ /* If this loop has sibling loop, the father loop won't be in perfect ++ loop nest. */ ++ if (loop->next != NULL) ++ break; ++ ++ loop = loop_outer (loop); ++ } ++ if (!start_loop || !start_loop->inner) ++ return false; ++ ++ /* Prepare the data reference vector for the loop nest, pruning outer ++ loops we cannot handle. */ ++ start_loop = prepare_data_references (start_loop, datarefs); ++ if (!start_loop ++ /* Check if there is no data reference. */ ++ || datarefs->is_empty () ++ /* Check if there are too many of data references. */ ++ || (int) datarefs->length () > MAX_DATAREFS) ++ return false; ++ ++ /* Compute access strides for all data references, pruning outer ++ loops we cannot analyze refs in. */ ++ start_loop = compute_access_strides (start_loop, innermost, *datarefs); ++ if (!start_loop) ++ return false; ++ ++ /* Check if any interchange is profitable in the loop nest. */ ++ if (!should_interchange_loop_nest (start_loop, innermost, *datarefs)) ++ return false; ++ ++ /* Check if data dependences can be computed for loop nest starting from ++ start_loop. */ ++ loop = start_loop; ++ do { ++ loop_nest->truncate (0); ++ ++ if (loop != start_loop) ++ prune_datarefs_not_in_loop (start_loop, *datarefs); ++ ++ if (find_loop_nest (start_loop, loop_nest) ++ && tree_loop_interchange_compute_ddrs (*loop_nest, *datarefs, ddrs)) ++ { ++ if (dump_file && (dump_flags & TDF_DETAILS)) ++ fprintf (dump_file, ++ "\nConsider loop interchange for loop_nest<%d - %d>\n", ++ start_loop->num, innermost->num); ++ ++ if (loop != start_loop) ++ prune_access_strides_not_in_loop (start_loop, innermost, *datarefs); ++ ++ if (dump_file && (dump_flags & TDF_DETAILS)) ++ dump_access_strides (*datarefs); ++ ++ return true; ++ } ++ ++ free_dependence_relations (*ddrs); ++ *ddrs = vNULL; ++ /* Try to compute data dependences with the outermost loop stripped. */ ++ loop = start_loop; ++ start_loop = start_loop->inner; ++ } while (start_loop && start_loop->inner); ++ ++ return false; ++} ++ ++/* Main entry for loop interchange pass. */ ++ ++unsigned int ++pass_linterchange::execute (function *fun) ++{ ++ if (number_of_loops (fun) <= 2) ++ return 0; ++ ++ bool changed_p = false; ++ struct loop *loop; ++ FOR_EACH_LOOP (loop, LI_ONLY_INNERMOST) ++ { ++ vec loop_nest = vNULL; ++ vec datarefs = vNULL; ++ vec ddrs = vNULL; ++ if (prepare_perfect_loop_nest (loop, &loop_nest, &datarefs, &ddrs)) ++ { ++ tree_loop_interchange loop_interchange (loop_nest); ++ changed_p |= loop_interchange.interchange (datarefs, ddrs); ++ } ++ free_dependence_relations (ddrs); ++ free_data_refs_with_aux (datarefs); ++ loop_nest.release (); ++ } ++ ++ if (changed_p) ++ scev_reset_htab (); ++ ++ return changed_p ? (TODO_update_ssa_only_virtuals) : 0; ++} ++ ++} // anon namespace ++ ++gimple_opt_pass * ++make_pass_linterchange (gcc::context *ctxt) ++{ ++ return new pass_linterchange (ctxt); ++} +diff -N -urp a/gcc/gimple-pretty-print.h b/gcc/gimple-pretty-print.h +--- a/gcc/gimple-pretty-print.h 2018-11-15 15:54:01.223039794 +0800 ++++ b/gcc/gimple-pretty-print.h 2018-11-15 16:03:17.447054436 +0800 +@@ -27,10 +27,10 @@ along with GCC; see the file COPYING3. + extern void debug_gimple_stmt (gimple *); + extern void debug_gimple_seq (gimple_seq); + extern void print_gimple_seq (FILE *, gimple_seq, int, int); +-extern void print_gimple_stmt (FILE *, gimple *, int, int); ++extern void print_gimple_stmt (FILE *, gimple *, int, int = 0); + extern void debug (gimple &ref); + extern void debug (gimple *ptr); +-extern void print_gimple_expr (FILE *, gimple *, int, int); ++extern void print_gimple_expr (FILE *, gimple *, int, int = 0); + extern void pp_gimple_stmt_1 (pretty_printer *, gimple *, int, int); + extern void gimple_dump_bb (FILE *, basic_block, int, int); + extern void gimple_dump_bb_for_graph (pretty_printer *, basic_block); +diff -N -urp a/gcc/opts.c b/gcc/opts.c +--- a/gcc/opts.c 2018-11-15 15:59:30.459048461 +0800 ++++ b/gcc/opts.c 2018-11-15 16:03:17.447054436 +0800 +@@ -538,6 +538,7 @@ static const struct default_options defa + { OPT_LEVELS_3_PLUS, OPT_fgcse_after_reload, NULL, 1 }, + { OPT_LEVELS_3_PLUS, OPT_ftree_loop_vectorize, NULL, 1 }, + { OPT_LEVELS_3_PLUS, OPT_ftree_slp_vectorize, NULL, 1 }, ++ { OPT_LEVELS_3_PLUS, OPT_floop_interchange, NULL, 1 }, + { OPT_LEVELS_3_PLUS, OPT_fvect_cost_model_, NULL, VECT_COST_MODEL_DYNAMIC }, + { OPT_LEVELS_3_PLUS, OPT_fipa_cp_clone, NULL, 1 }, + { OPT_LEVELS_3_PLUS, OPT_ftree_partial_pre, NULL, 1 }, +diff -N -urp a/gcc/params.def b/gcc/params.def +--- a/gcc/params.def 2018-11-15 15:59:30.459048461 +0800 ++++ b/gcc/params.def 2018-11-15 16:03:17.451054437 +0800 +@@ -780,6 +780,20 @@ DEFPARAM (PARAM_L2_CACHE_SIZE, + "The size of L2 cache.", + 512, 0, 0) + ++/* Maximum number of statements in loop nest for loop interchange. */ ++ ++DEFPARAM (PARAM_LOOP_INTERCHANGE_MAX_NUM_STMTS, ++ "loop-interchange-max-num-stmts", ++ "The maximum number of stmts in loop nest for loop interchange.", ++ 64, 0, 0) ++ ++/* Minimum stride ratio for loop interchange to be profitiable. */ ++ ++DEFPARAM (PARAM_LOOP_INTERCHANGE_STRIDE_RATIO, ++ "loop-interchange-stride-ratio", ++ "The minimum stride ratio for loop interchange to be profitable", ++ 2, 0, 0) ++ + /* Whether we should use canonical types rather than deep "structural" + type checking. Setting this value to 1 (the default) improves + compilation performance in the C++ and Objective-C++ front end; +diff -N -urp a/gcc/passes.def b/gcc/passes.def +--- a/gcc/passes.def 2018-11-15 15:59:30.463048461 +0800 ++++ b/gcc/passes.def 2018-11-15 16:03:17.451054437 +0800 +@@ -278,6 +278,7 @@ along with GCC; see the file COPYING3. + NEXT_PASS (pass_cd_dce); + NEXT_PASS (pass_record_bounds); + NEXT_PASS (pass_loop_distribution); ++ NEXT_PASS (pass_linterchange); + NEXT_PASS (pass_copy_prop); + NEXT_PASS (pass_graphite); + PUSH_INSERT_PASSES_WITHIN (pass_graphite) +diff -N -urp a/gcc/timevar.def b/gcc/timevar.def +--- a/gcc/timevar.def 2018-11-15 15:59:30.463048461 +0800 ++++ b/gcc/timevar.def 2018-11-15 16:03:17.455054437 +0800 +@@ -182,6 +182,7 @@ DEFTIMEVAR (TV_TREE_LOOP , "tree lo + DEFTIMEVAR (TV_TREE_NOLOOP , "loopless fn") + DEFTIMEVAR (TV_TREE_LOOP_BOUNDS , "tree loop bounds") + DEFTIMEVAR (TV_LIM , "tree loop invariant motion") ++DEFTIMEVAR (TV_LINTERCHANGE , "tree loop interchange") + DEFTIMEVAR (TV_TREE_LOOP_IVCANON , "tree canonical iv") + DEFTIMEVAR (TV_SCEV_CONST , "scev constant prop") + DEFTIMEVAR (TV_TREE_LOOP_UNSWITCH , "tree loop unswitching") +diff -N -urp a/gcc/tree-pass.h b/gcc/tree-pass.h +--- a/gcc/tree-pass.h 2018-11-15 15:59:30.467048461 +0800 ++++ b/gcc/tree-pass.h 2018-11-15 16:03:17.455054437 +0800 +@@ -367,6 +367,7 @@ extern gimple_opt_pass *make_pass_tree_l + extern gimple_opt_pass *make_pass_tree_no_loop (gcc::context *ctxt); + extern gimple_opt_pass *make_pass_tree_loop_init (gcc::context *ctxt); + extern gimple_opt_pass *make_pass_lim (gcc::context *ctxt); ++extern gimple_opt_pass *make_pass_linterchange (gcc::context *ctxt); + extern gimple_opt_pass *make_pass_tree_unswitch (gcc::context *ctxt); + extern gimple_opt_pass *make_pass_loop_split (gcc::context *ctxt); + extern gimple_opt_pass *make_pass_loop_jam (gcc::context *ctxt); +diff -N -urp a/gcc/tree-pretty-print.h b/gcc/tree-pretty-print.h +--- a/gcc/tree-pretty-print.h 2018-11-15 15:54:01.439039800 +0800 ++++ b/gcc/tree-pretty-print.h 2018-11-15 16:03:17.455054437 +0800 +@@ -37,7 +37,7 @@ extern void debug_tree_chain (tree); + extern void print_generic_decl (FILE *, tree, int); + extern void print_generic_stmt (FILE *, tree, int); + extern void print_generic_stmt_indented (FILE *, tree, int, int); +-extern void print_generic_expr (FILE *, tree, int); ++extern void print_generic_expr (FILE *, tree, int = 0); + extern void dump_omp_clauses (pretty_printer *, tree, int, int); + extern int dump_generic_node (pretty_printer *, tree, int, int, bool); + extern void print_declaration (pretty_printer *, tree, int, int); +diff -N -urp a/gcc/tree-scalar-evolution.c b/gcc/tree-scalar-evolution.c +--- a/gcc/tree-scalar-evolution.c 2018-11-15 15:54:01.443039800 +0800 ++++ b/gcc/tree-scalar-evolution.c 2018-11-15 16:03:17.459054437 +0800 +@@ -3000,6 +3000,50 @@ instantiate_scev (basic_block instantiat + return res; + } + ++tree ++instantiate_scev (edge instantiate_below, struct loop *evolution_loop, ++ tree chrec) ++{ ++ tree res; ++ ++ if (dump_file && (dump_flags & TDF_SCEV)) ++ { ++ fprintf (dump_file, "(instantiate_scev \n"); ++ fprintf (dump_file, " (instantiate_below = %d -> %d)\n", ++ instantiate_below->src->index, instantiate_below->dest->index); ++ if (evolution_loop) ++ fprintf (dump_file, " (evolution_loop = %d)\n", evolution_loop->num); ++ fprintf (dump_file, " (chrec = "); ++ print_generic_expr (dump_file, chrec); ++ fprintf (dump_file, ")\n"); ++ } ++ ++ bool destr = false; ++ if (!global_cache) ++ { ++ global_cache = new instantiate_cache_type; ++ destr = true; ++ } ++ ++ res = instantiate_scev_r (instantiate_below->src, evolution_loop, ++ NULL, chrec, NULL, 0); ++ ++ if (destr) ++ { ++ delete global_cache; ++ global_cache = NULL; ++ } ++ ++ if (dump_file && (dump_flags & TDF_SCEV)) ++ { ++ fprintf (dump_file, " (res = "); ++ print_generic_expr (dump_file, res); ++ fprintf (dump_file, "))\n"); ++ } ++ ++ return res; ++} ++ + /* Similar to instantiate_parameters, but does not introduce the + evolutions in outer loops for LOOP invariants in CHREC, and does not + care about causing overflows, as long as they do not affect value +diff -N -urp a/gcc/tree-scalar-evolution.h b/gcc/tree-scalar-evolution.h +--- a/gcc/tree-scalar-evolution.h 2018-11-15 15:54:01.443039800 +0800 ++++ b/gcc/tree-scalar-evolution.h 2018-11-15 16:03:17.459054437 +0800 +@@ -31,6 +31,7 @@ extern void scev_reset_htab (void); + extern void scev_finalize (void); + extern tree analyze_scalar_evolution (struct loop *, tree); + extern tree instantiate_scev (basic_block, struct loop *, tree); ++extern tree instantiate_scev (edge, struct loop *, tree); + extern tree resolve_mixers (struct loop *, tree, bool *); + extern void gather_stats_on_scev_database (void); + extern void final_value_replacement_loop (struct loop *); +diff -N -urp a/gcc/tree-ssa-dce.c b/gcc/tree-ssa-dce.c +--- a/gcc/tree-ssa-dce.c 2018-11-15 15:54:01.443039800 +0800 ++++ b/gcc/tree-ssa-dce.c 2018-11-15 16:03:17.463054437 +0800 +@@ -1729,3 +1729,55 @@ make_pass_cd_dce (gcc::context *ctxt) + { + return new pass_cd_dce (ctxt); + } ++ ++ ++/* A cheap DCE interface. WORKLIST is a list of possibly dead stmts and ++ is consumed by this function. The function has linear complexity in ++ the number of dead stmts with a constant factor like the average SSA ++ use operands number. */ ++ ++void ++simple_dce_from_worklist (bitmap worklist) ++{ ++ while (! bitmap_empty_p (worklist)) ++ { ++ /* Pop item. */ ++ unsigned i = bitmap_first_set_bit (worklist); ++ bitmap_clear_bit (worklist, i); ++ ++ tree def = ssa_name (i); ++ /* Removed by somebody else or still in use. */ ++ if (! def || ! has_zero_uses (def)) ++ continue; ++ ++ gimple *t = SSA_NAME_DEF_STMT (def); ++ if (gimple_has_side_effects (t)) ++ continue; ++ ++ /* Add uses to the worklist. */ ++ ssa_op_iter iter; ++ use_operand_p use_p; ++ FOR_EACH_PHI_OR_STMT_USE (use_p, t, iter, SSA_OP_USE) ++ { ++ tree use = USE_FROM_PTR (use_p); ++ if (TREE_CODE (use) == SSA_NAME ++ && ! SSA_NAME_IS_DEFAULT_DEF (use)) ++ bitmap_set_bit (worklist, SSA_NAME_VERSION (use)); ++ } ++ ++ /* Remove stmt. */ ++ if (dump_file && (dump_flags & TDF_DETAILS)) ++ { ++ fprintf (dump_file, "Removing dead stmt:"); ++ print_gimple_stmt (dump_file, t, 0); ++ } ++ gimple_stmt_iterator gsi = gsi_for_stmt (t); ++ if (gimple_code (t) == GIMPLE_PHI) ++ remove_phi_node (&gsi, true); ++ else ++ { ++ gsi_remove (&gsi, true); ++ release_defs (t); ++ } ++ } ++} +diff -N -urp a/gcc/tree-ssa-dce.h b/gcc/tree-ssa-dce.h +--- a/gcc/tree-ssa-dce.h 1970-01-01 08:00:00.000000000 +0800 ++++ b/gcc/tree-ssa-dce.h 2018-11-15 16:03:17.463054437 +0800 +@@ -0,0 +1,22 @@ ++/* Copyright (C) 2017 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 ++. */ ++ ++#ifndef TREE_SSA_DCE_H ++#define TREE_SSA_DCE_H ++extern void simple_dce_from_worklist (bitmap); ++#endif +diff -N -urp a/gcc/tree-ssa-loop-ivcanon.c b/gcc/tree-ssa-loop-ivcanon.c +--- a/gcc/tree-ssa-loop-ivcanon.c 2018-11-15 15:54:01.447039800 +0800 ++++ b/gcc/tree-ssa-loop-ivcanon.c 2018-11-15 16:03:17.467054437 +0800 +@@ -76,10 +76,13 @@ enum unroll_level + }; + + /* Adds a canonical induction variable to LOOP iterating NITER times. EXIT +- is the exit edge whose condition is replaced. */ +- +-static void +-create_canonical_iv (struct loop *loop, edge exit, tree niter) ++ is the exit edge whose condition is replaced. The ssa versions of the new ++ IV before and after increment will be stored in VAR_BEFORE and VAR_AFTER ++ if they are not NULL. */ ++ ++void ++create_canonical_iv (struct loop *loop, edge exit, tree niter, ++ tree *var_before = NULL, tree *var_after = NULL) + { + edge in; + tree type, var; +@@ -112,7 +115,9 @@ create_canonical_iv (struct loop *loop, + create_iv (niter, + build_int_cst (type, -1), + NULL_TREE, loop, +- &incr_at, false, NULL, &var); ++ &incr_at, false, var_before, &var); ++ if (var_after) ++ *var_after = var; + + cmp = (exit->flags & EDGE_TRUE_VALUE) ? EQ_EXPR : NE_EXPR; + gimple_cond_set_code (cond, cmp); +diff -N -urp a/gcc/tree-ssa-loop-ivopts.h b/gcc/tree-ssa-loop-ivopts.h +--- a/gcc/tree-ssa-loop-ivopts.h 2018-11-15 15:54:01.447039800 +0800 ++++ b/gcc/tree-ssa-loop-ivopts.h 2018-11-15 16:03:17.467054437 +0800 +@@ -33,4 +33,6 @@ bool multiplier_allowed_in_address_p (HO + addr_space_t); + void tree_ssa_iv_optimize (void); + ++void create_canonical_iv (struct loop *, edge, tree, ++ tree * = NULL, tree * = NULL); + #endif /* GCC_TREE_SSA_LOOP_IVOPTS_H */ +diff -N -urp a/gcc/tree-ssa-pre.c b/gcc/tree-ssa-pre.c +--- a/gcc/tree-ssa-pre.c 2018-11-15 15:54:01.447039800 +0800 ++++ b/gcc/tree-ssa-pre.c 2018-11-15 16:03:17.471054437 +0800 +@@ -39,6 +39,7 @@ along with GCC; see the file COPYING3. + #include "gimplify.h" + #include "gimple-iterator.h" + #include "tree-cfg.h" ++#include "tree-ssa-dce.h" + #include "tree-ssa-loop.h" + #include "tree-into-ssa.h" + #include "tree-dfa.h" +@@ -4908,99 +4909,6 @@ mark_operand_necessary (tree op) + return stmt; + } + +-/* Because we don't follow exactly the standard PRE algorithm, and decide not +- to insert PHI nodes sometimes, and because value numbering of casts isn't +- perfect, we sometimes end up inserting dead code. This simple DCE-like +- pass removes any insertions we made that weren't actually used. */ +- +-static void +-remove_dead_inserted_code (void) +-{ +- bitmap worklist; +- unsigned i; +- bitmap_iterator bi; +- gimple *t; +- +- worklist = BITMAP_ALLOC (NULL); +- EXECUTE_IF_SET_IN_BITMAP (inserted_exprs, 0, i, bi) +- { +- t = SSA_NAME_DEF_STMT (ssa_name (i)); +- if (gimple_plf (t, NECESSARY)) +- bitmap_set_bit (worklist, i); +- } +- while (!bitmap_empty_p (worklist)) +- { +- i = bitmap_first_set_bit (worklist); +- bitmap_clear_bit (worklist, i); +- t = SSA_NAME_DEF_STMT (ssa_name (i)); +- +- /* PHI nodes are somewhat special in that each PHI alternative has +- data and control dependencies. All the statements feeding the +- PHI node's arguments are always necessary. */ +- if (gimple_code (t) == GIMPLE_PHI) +- { +- unsigned k; +- +- for (k = 0; k < gimple_phi_num_args (t); k++) +- { +- tree arg = PHI_ARG_DEF (t, k); +- if (TREE_CODE (arg) == SSA_NAME) +- { +- gimple *n = mark_operand_necessary (arg); +- if (n) +- bitmap_set_bit (worklist, SSA_NAME_VERSION (arg)); +- } +- } +- } +- else +- { +- /* Propagate through the operands. Examine all the USE, VUSE and +- VDEF operands in this statement. Mark all the statements +- which feed this statement's uses as necessary. */ +- ssa_op_iter iter; +- tree use; +- +- /* The operands of VDEF expressions are also needed as they +- represent potential definitions that may reach this +- statement (VDEF operands allow us to follow def-def +- links). */ +- +- FOR_EACH_SSA_TREE_OPERAND (use, t, iter, SSA_OP_ALL_USES) +- { +- gimple *n = mark_operand_necessary (use); +- if (n) +- bitmap_set_bit (worklist, SSA_NAME_VERSION (use)); +- } +- } +- } +- +- EXECUTE_IF_SET_IN_BITMAP (inserted_exprs, 0, i, bi) +- { +- t = SSA_NAME_DEF_STMT (ssa_name (i)); +- if (!gimple_plf (t, NECESSARY)) +- { +- gimple_stmt_iterator gsi; +- +- if (dump_file && (dump_flags & TDF_DETAILS)) +- { +- fprintf (dump_file, "Removing unnecessary insertion:"); +- print_gimple_stmt (dump_file, t, 0, 0); +- } +- +- gsi = gsi_for_stmt (t); +- if (gimple_code (t) == GIMPLE_PHI) +- remove_phi_node (&gsi, true); +- else +- { +- gsi_remove (&gsi, true); +- release_defs (t); +- } +- } +- } +- BITMAP_FREE (worklist); +-} +- +- + /* Initialize data structures used by PRE. */ + + static void +@@ -5142,8 +5050,7 @@ pass_pre::execute (function *fun) + statistics_counter_event (fun, "Eliminated", pre_stats.eliminations); + + clear_expression_ids (); +- remove_dead_inserted_code (); +- ++ + scev_finalize (); + fini_pre (); + todo |= fini_eliminate (); +diff -N -urp a/gcc/tree-vect-loop.c b/gcc/tree-vect-loop.c +--- a/gcc/tree-vect-loop.c 2018-11-15 15:54:01.447039800 +0800 ++++ b/gcc/tree-vect-loop.c 2018-11-15 16:03:17.471054437 +0800 +@@ -2632,6 +2632,112 @@ vect_is_slp_reduction (loop_vec_info loo + return true; + } + ++/* Return true if the reduction PHI in LOOP with latch arg LOOP_ARG and ++ reduction operation CODE has a handled computation expression. */ ++ ++bool ++check_reduction_path (location_t loc, loop_p loop, gphi *phi, tree loop_arg, ++ enum tree_code code) ++{ ++ auto_vec > path; ++ auto_bitmap visited; ++ tree lookfor = PHI_RESULT (phi); ++ ssa_op_iter curri; ++ use_operand_p curr = op_iter_init_phiuse (&curri, phi, SSA_OP_USE); ++ while (USE_FROM_PTR (curr) != loop_arg) ++ curr = op_iter_next_use (&curri); ++ curri.i = curri.numops; ++ do ++ { ++ path.safe_push (std::make_pair (curri, curr)); ++ tree use = USE_FROM_PTR (curr); ++ if (use == lookfor) ++ break; ++ gimple *def = SSA_NAME_DEF_STMT (use); ++ if (gimple_nop_p (def) ++ || ! flow_bb_inside_loop_p (loop, gimple_bb (def))) ++ { ++pop: ++ do ++ { ++ std::pair x = path.pop (); ++ curri = x.first; ++ curr = x.second; ++ do ++ curr = op_iter_next_use (&curri); ++ /* Skip already visited or non-SSA operands (from iterating ++ over PHI args). */ ++ while (curr != NULL_USE_OPERAND_P ++ && (TREE_CODE (USE_FROM_PTR (curr)) != SSA_NAME ++ || ! bitmap_set_bit (visited, ++ SSA_NAME_VERSION ++ (USE_FROM_PTR (curr))))); ++ } ++ while (curr == NULL_USE_OPERAND_P && ! path.is_empty ()); ++ if (curr == NULL_USE_OPERAND_P) ++ break; ++ } ++ else ++ { ++ if (gimple_code (def) == GIMPLE_PHI) ++ curr = op_iter_init_phiuse (&curri, as_a (def), SSA_OP_USE); ++ else ++ curr = op_iter_init_use (&curri, def, SSA_OP_USE); ++ while (curr != NULL_USE_OPERAND_P ++ && (TREE_CODE (USE_FROM_PTR (curr)) != SSA_NAME ++ || ! bitmap_set_bit (visited, ++ SSA_NAME_VERSION ++ (USE_FROM_PTR (curr))))) ++ curr = op_iter_next_use (&curri); ++ if (curr == NULL_USE_OPERAND_P) ++ goto pop; ++ } ++ } ++ while (1); ++ if (dump_file && (dump_flags & TDF_DETAILS)) ++ { ++ dump_printf_loc (MSG_NOTE, loc, "reduction path: "); ++ unsigned i; ++ std::pair *x; ++ FOR_EACH_VEC_ELT (path, i, x) ++ { ++ dump_generic_expr (MSG_NOTE, TDF_SLIM, USE_FROM_PTR (x->second)); ++ dump_printf (MSG_NOTE, " "); ++ } ++ dump_printf (MSG_NOTE, "\n"); ++ } ++ ++ /* Check whether the reduction path detected is valid. */ ++ bool fail = path.length () == 0; ++ bool neg = false; ++ for (unsigned i = 1; i < path.length (); ++i) ++ { ++ gimple *use_stmt = USE_STMT (path[i].second); ++ tree op = USE_FROM_PTR (path[i].second); ++ if (! has_single_use (op) ++ || ! is_gimple_assign (use_stmt)) ++ { ++ fail = true; ++ break; ++ } ++ if (gimple_assign_rhs_code (use_stmt) != code) ++ { ++ if (code == PLUS_EXPR ++ && gimple_assign_rhs_code (use_stmt) == MINUS_EXPR) ++ { ++ /* Track whether we negate the reduction value each iteration. */ ++ if (gimple_assign_rhs2 (use_stmt) == op) ++ neg = ! neg; ++ } ++ else ++ { ++ fail = true; ++ break; ++ } ++ } ++ } ++ return ! fail && ! neg; ++} + + /* Function vect_is_simple_reduction_1 + +diff -N -urp a/gcc/tree-vectorizer.h b/gcc/tree-vectorizer.h +--- a/gcc/tree-vectorizer.h 2018-11-15 15:54:01.451039800 +0800 ++++ b/gcc/tree-vectorizer.h 2018-11-15 16:03:17.475054437 +0800 +@@ -1166,6 +1166,9 @@ extern tree vect_create_addr_base_for_ve + extern void destroy_loop_vec_info (loop_vec_info, bool); + extern gimple *vect_force_simple_reduction (loop_vec_info, gimple *, bool, + bool *, bool); ++/* Used in gimple-loop-interchange.c. */ ++extern bool check_reduction_path (location_t, loop_p, gphi *, tree, ++ enum tree_code); + /* Drive for loop analysis stage. */ + extern loop_vec_info vect_analyze_loop (struct loop *, loop_vec_info); + extern tree vect_build_loop_niters (loop_vec_info); diff --git a/floop-unroll-and-jam.patch b/floop-unroll-and-jam.patch new file mode 100644 index 0000000..514aaf8 --- /dev/null +++ b/floop-unroll-and-jam.patch @@ -0,0 +1,905 @@ +diff -N -urp a/gcc/Makefile.in b/gcc/Makefile.in +--- a/gcc/Makefile.in 2018-11-07 11:37:24.615223860 +0800 ++++ b/gcc/Makefile.in 2018-11-07 11:38:26.155223860 +0800 +@@ -1292,6 +1292,7 @@ OBJS = \ + gimple-iterator.o \ + gimple-fold.o \ + gimple-laddress.o \ ++ gimple-loop-jam.o \ + gimple-low.o \ + gimple-pretty-print.o \ + gimple-ssa-backprop.o \ +diff -N -urp a/gcc/cfgloop.c b/gcc/cfgloop.c +--- a/gcc/cfgloop.c 2018-11-07 11:37:24.947223860 +0800 ++++ b/gcc/cfgloop.c 2018-11-07 11:38:26.155223860 +0800 +@@ -296,13 +296,25 @@ establish_preds (struct loop *loop, stru + + /* Add LOOP to the loop hierarchy tree where FATHER is father of the + added loop. If LOOP has some children, take care of that their +- pred field will be initialized correctly. */ ++ pred field will be initialized correctly. If AFTER is non-null ++ then it's expected it's a pointer into FATHERs inner sibling ++ list and LOOP is added behind AFTER, otherwise it's added in front ++ of FATHERs siblings. */ + + void +-flow_loop_tree_node_add (struct loop *father, struct loop *loop) ++flow_loop_tree_node_add (struct loop *father, struct loop *loop, ++ struct loop *after) + { +- loop->next = father->inner; +- father->inner = loop; ++ if (after) ++ { ++ loop->next = after->next; ++ after->next = loop; ++ } ++ else ++ { ++ loop->next = father->inner; ++ father->inner = loop; ++ } + + establish_preds (loop, father); + } +diff -N -urp a/gcc/cfgloop.h b/gcc/cfgloop.h +--- a/gcc/cfgloop.h 2018-11-07 11:37:24.331223860 +0800 ++++ b/gcc/cfgloop.h 2018-11-07 11:38:26.155223860 +0800 +@@ -324,7 +324,8 @@ void record_loop_exits (void); + void rescan_loop_exit (edge, bool, bool); + + /* Loop data structure manipulation/querying. */ +-extern void flow_loop_tree_node_add (struct loop *, struct loop *); ++extern void flow_loop_tree_node_add (struct loop *, struct loop *, ++ struct loop * = NULL); + extern void flow_loop_tree_node_remove (struct loop *); + extern bool flow_loop_nested_p (const struct loop *, const struct loop *); + extern bool flow_bb_inside_loop_p (const struct loop *, const_basic_block); +diff -N -urp a/gcc/cfgloopmanip.c b/gcc/cfgloopmanip.c +--- a/gcc/cfgloopmanip.c 2018-11-07 11:37:24.847223860 +0800 ++++ b/gcc/cfgloopmanip.c 2018-11-07 11:38:26.155223860 +0800 +@@ -1026,9 +1026,11 @@ copy_loop_info (struct loop *loop, struc + } + + /* Copies copy of LOOP as subloop of TARGET loop, placing newly +- created loop into loops structure. */ ++ created loop into loops structure. If AFTER is non-null ++ the new loop is added at AFTER->next, otherwise in front of TARGETs ++ sibling list. */ + struct loop * +-duplicate_loop (struct loop *loop, struct loop *target) ++duplicate_loop (struct loop *loop, struct loop *target, struct loop *after) + { + struct loop *cloop; + cloop = alloc_loop (); +@@ -1040,36 +1042,46 @@ duplicate_loop (struct loop *loop, struc + set_loop_copy (loop, cloop); + + /* Add it to target. */ +- flow_loop_tree_node_add (target, cloop); ++ flow_loop_tree_node_add (target, cloop, after); + + return cloop; + } + + /* Copies structure of subloops of LOOP into TARGET loop, placing +- newly created loops into loop tree. */ ++ newly created loops into loop tree at the end of TARGETs sibling ++ list in the original order. */ + void + duplicate_subloops (struct loop *loop, struct loop *target) + { +- struct loop *aloop, *cloop; ++ struct loop *aloop, *cloop, *tail; + ++ for (tail = target->inner; tail && tail->next; tail = tail->next) ++ ; + for (aloop = loop->inner; aloop; aloop = aloop->next) + { +- cloop = duplicate_loop (aloop, target); ++ cloop = duplicate_loop (aloop, target, tail); ++ tail = cloop; ++ gcc_assert (!tail->next); + duplicate_subloops (aloop, cloop); + } + } + + /* Copies structure of subloops of N loops, stored in array COPIED_LOOPS, +- into TARGET loop, placing newly created loops into loop tree. */ ++ into TARGET loop, placing newly created loops into loop tree adding ++ them to TARGETs sibling list at the end in order. */ + static void + copy_loops_to (struct loop **copied_loops, int n, struct loop *target) + { +- struct loop *aloop; ++ struct loop *aloop, *tail; + int i; + ++ for (tail = target->inner; tail && tail->next; tail = tail->next) ++ ; + for (i = 0; i < n; i++) + { +- aloop = duplicate_loop (copied_loops[i], target); ++ aloop = duplicate_loop (copied_loops[i], target, tail); ++ tail = aloop; ++ gcc_assert (!tail->next); + duplicate_subloops (copied_loops[i], aloop); + } + } +@@ -1133,14 +1145,15 @@ set_zero_probability (edge e) + } + + /* Duplicates body of LOOP to given edge E NDUPL times. Takes care of updating +- loop structure and dominators. E's destination must be LOOP header for +- this to work, i.e. it must be entry or latch edge of this loop; these are +- unique, as the loops must have preheaders for this function to work +- correctly (in case E is latch, the function unrolls the loop, if E is entry +- edge, it peels the loop). Store edges created by copying ORIG edge from +- copies corresponding to set bits in WONT_EXIT bitmap (bit 0 corresponds to +- original LOOP body, the other copies are numbered in order given by control +- flow through them) into TO_REMOVE array. Returns false if duplication is ++ loop structure and dominators (order of inner subloops is retained). ++ E's destination must be LOOP header for this to work, i.e. it must be entry ++ or latch edge of this loop; these are unique, as the loops must have ++ preheaders for this function to work correctly (in case E is latch, the ++ function unrolls the loop, if E is entry edge, it peels the loop). Store ++ edges created by copying ORIG edge from copies corresponding to set bits in ++ WONT_EXIT bitmap (bit 0 corresponds to original LOOP body, the other copies ++ are numbered in order given by control flow through them) into TO_REMOVE ++ array. Returns false if duplication is + impossible. */ + + bool +diff -N -urp a/gcc/cfgloopmanip.h b/gcc/cfgloopmanip.h +--- a/gcc/cfgloopmanip.h 2018-11-07 11:37:24.939223860 +0800 ++++ b/gcc/cfgloopmanip.h 2018-11-07 11:38:26.155223860 +0800 +@@ -47,7 +47,8 @@ extern struct loop *loopify (edge, edge, + unsigned, unsigned); + extern void unloop (struct loop *, bool *, bitmap); + extern void copy_loop_info (struct loop *loop, struct loop *target); +-extern struct loop * duplicate_loop (struct loop *, struct loop *); ++extern struct loop * duplicate_loop (struct loop *, struct loop *, ++ struct loop * = NULL); + extern void duplicate_subloops (struct loop *, struct loop *); + extern bool can_duplicate_loop_p (const struct loop *loop); + extern bool duplicate_loop_to_header_edge (struct loop *, edge, +diff -N -urp a/gcc/common.opt b/gcc/common.opt +--- a/gcc/common.opt 2018-11-07 11:37:24.859223860 +0800 ++++ b/gcc/common.opt 2018-11-07 11:38:26.159223860 +0800 +@@ -1496,8 +1496,8 @@ Common Alias(floop-nest-optimize) + Enable loop nest transforms. Same as -floop-nest-optimize. + + floop-unroll-and-jam +-Common Alias(floop-nest-optimize) +-Enable loop nest transforms. Same as -floop-nest-optimize. ++Common Report Var(flag_unroll_jam) Optimization ++Perform unroll-and-jam on loops. + + fgnu-tm + Common Report Var(flag_tm) +diff -N -urp a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi +--- a/gcc/doc/invoke.texi 2018-11-07 11:37:24.915223860 +0800 ++++ b/gcc/doc/invoke.texi 2018-11-07 11:39:49.031223860 +0800 +@@ -7120,7 +7120,8 @@ Optimize yet more. @option{-O3} turns o + by @option{-O2} and also turns on the @option{-finline-functions}, + @option{-funswitch-loops}, @option{-fpredictive-commoning}, + @option{-fgcse-after-reload}, @option{-ftree-loop-vectorize}, +-@option{-ftree-loop-distribute-patterns}, @option{-fsplit-paths} ++@option{-ftree-loop-distribute-patterns}, @option{-fsplit-paths}, ++@option{-floop-unroll-and-jam}, + @option{-ftree-slp-vectorize}, @option{-fvect-cost-model}, + @option{-ftree-partial-pre}, @option{-fpeel-loops} + and @option{-fipa-cp-clone} options. +@@ -8226,12 +8227,10 @@ at @option{-O} and higher. + @itemx -floop-interchange + @itemx -floop-strip-mine + @itemx -floop-block +-@itemx -floop-unroll-and-jam + @opindex ftree-loop-linear + @opindex floop-interchange + @opindex floop-strip-mine + @opindex floop-block +-@opindex floop-unroll-and-jam + Perform loop nest optimizations. Same as + @option{-floop-nest-optimize}. To use this code transformation, GCC has + to be configured with @option{--with-isl} to enable the Graphite loop +@@ -8323,6 +8322,12 @@ ENDDO + @end smallexample + and the initialization loop is transformed into a call to memset zero. + ++@item -floop-unroll-and-jam ++@opindex floop-unroll-and-jam ++Apply unroll and jam transformations on feasible loops. In a loop ++nest this unrolls the outer loop by some factor and fuses the resulting ++multiple inner loops. This flag is enabled by default at @option{-O3}. ++ + @item -ftree-loop-im + @opindex ftree-loop-im + Perform loop invariant motion on trees. This pass moves only invariants that +@@ -10353,13 +10358,13 @@ loop in the loop nest by a given number + length can be changed using the @option{loop-block-tile-size} + parameter. The default value is 51 iterations. + +-@item loop-unroll-jam-size +-Specify the unroll factor for the @option{-floop-unroll-and-jam} option. The +-default value is 4. +- +-@item loop-unroll-jam-depth +-Specify the dimension to be unrolled (counting from the most inner loop) +-for the @option{-floop-unroll-and-jam}. The default value is 2. ++@item unroll-jam-min-percent ++The minimum percentage of memory references that must be optimized ++away for the unroll-and-jam transformation to be considered profitable. ++ ++@item unroll-jam-max-unroll ++The maximum number of times the outer loop should be unrolled by ++the unroll-and-jam transformation. + + @item ipa-cp-value-list-size + IPA-CP attempts to track all possible values and types passed to a function's +diff -N -urp a/gcc/gimple-loop-jam.c b/gcc/gimple-loop-jam.c +--- a/gcc/gimple-loop-jam.c 1970-01-01 08:00:00.000000000 +0800 ++++ b/gcc/gimple-loop-jam.c 2018-11-07 11:38:26.167223860 +0800 +@@ -0,0 +1,598 @@ ++/* Loop unroll-and-jam. ++ Copyright (C) 2017-2018 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 ++. */ ++ ++#include "config.h" ++#include "system.h" ++#include "coretypes.h" ++#include "params.h" ++#include "tree-pass.h" ++#include "backend.h" ++#include "tree.h" ++#include "gimple.h" ++#include "ssa.h" ++#include "fold-const.h" ++#include "tree-cfg.h" ++#include "tree-ssa.h" ++#include "tree-ssa-loop-niter.h" ++#include "tree-ssa-loop.h" ++#include "tree-ssa-loop-manip.h" ++#include "cfgloop.h" ++#include "tree-scalar-evolution.h" ++#include "gimple-iterator.h" ++#include "cfghooks.h" ++#include "tree-data-ref.h" ++#include "tree-ssa-loop-ivopts.h" ++#include "tree-vectorizer.h" ++ ++/* Unroll and Jam transformation ++ ++ This is a combination of two transformations, where the second ++ is not always valid. It's applicable if a loop nest has redundancies ++ over the iterations of an outer loop while not having that with ++ an inner loop. ++ ++ Given this nest: ++ for (i) { ++ for (j) { ++ B (i,j) ++ } ++ } ++ ++ first unroll: ++ for (i by 2) { ++ for (j) { ++ B (i,j) ++ } ++ for (j) { ++ B (i+1,j) ++ } ++ } ++ ++ then fuse the two adjacent inner loops resulting from that: ++ for (i by 2) { ++ for (j) { ++ B (i,j) ++ B (i+1,j) ++ } ++ } ++ ++ As the order of evaluations of the body B changes this is valid ++ only in certain situations: all distance vectors need to be forward. ++ Additionally if there are multiple induction variables than just ++ a counting control IV (j above) we can also deal with some situations. ++ ++ The validity is checked by unroll_jam_possible_p, and the data-dep ++ testing below. ++ ++ A trivial example where the fusion is wrong would be when ++ B (i,j) == x[j-1] = x[j]; ++ for (i by 2) { ++ for (j) { ++ x[j-1] = x[j]; ++ } ++ for (j) { ++ x[j-1] = x[j]; ++ } ++ } effect: move content to front by two elements ++ --> ++ for (i by 2) { ++ for (j) { ++ x[j-1] = x[j]; ++ x[j-1] = x[j]; ++ } ++ } effect: move content to front by one element ++*/ ++ ++/* Modify the loop tree for the fact that all code once belonging ++ to the OLD loop or the outer loop of OLD now is inside LOOP. */ ++ ++static void ++merge_loop_tree (struct loop *loop, struct loop *old) ++{ ++ basic_block *bbs; ++ int i, n; ++ struct loop *subloop; ++ edge e; ++ edge_iterator ei; ++ ++ /* Find its nodes. */ ++ bbs = XNEWVEC (basic_block, n_basic_blocks_for_fn (cfun)); ++ n = get_loop_body_with_size (loop, bbs, n_basic_blocks_for_fn (cfun)); ++ ++ for (i = 0; i < n; i++) ++ { ++ /* If the block was direct child of OLD loop it's now part ++ of LOOP. If it was outside OLD, then it moved into LOOP ++ as well. This avoids changing the loop father for BBs ++ in inner loops of OLD. */ ++ if (bbs[i]->loop_father == old ++ || loop_depth (bbs[i]->loop_father) < loop_depth (old)) ++ { ++ remove_bb_from_loops (bbs[i]); ++ add_bb_to_loop (bbs[i], loop); ++ continue; ++ } ++ ++ /* If we find a direct subloop of OLD, move it to LOOP. */ ++ subloop = bbs[i]->loop_father; ++ if (loop_outer (subloop) == old && subloop->header == bbs[i]) ++ { ++ flow_loop_tree_node_remove (subloop); ++ flow_loop_tree_node_add (loop, subloop); ++ } ++ } ++ ++ /* Update the information about loop exit edges. */ ++ for (i = 0; i < n; i++) ++ { ++ FOR_EACH_EDGE (e, ei, bbs[i]->succs) ++ { ++ rescan_loop_exit (e, false, false); ++ } ++ } ++ ++ loop->num_nodes = n; ++ ++ free (bbs); ++} ++ ++/* BB is part of the outer loop of an unroll-and-jam situation. ++ Check if any statements therein would prevent the transformation. */ ++ ++static bool ++bb_prevents_fusion_p (basic_block bb) ++{ ++ gimple_stmt_iterator gsi; ++ /* BB is duplicated by outer unrolling and then all N-1 first copies ++ move into the body of the fused inner loop. If BB exits the outer loop ++ the last copy still does so, and the first N-1 copies are cancelled ++ by loop unrolling, so also after fusion it's the exit block. ++ But there might be other reasons that prevent fusion: ++ * stores or unknown side-effects prevent fusion ++ * loads don't ++ * computations into SSA names: these aren't problematic. Their ++ result will be unused on the exit edges of the first N-1 copies ++ (those aren't taken after unrolling). If they are used on the ++ other edge (the one leading to the outer latch block) they are ++ loop-carried (on the outer loop) and the Nth copy of BB will ++ compute them again (i.e. the first N-1 copies will be dead). */ ++ for (gsi = gsi_start_bb (bb); !gsi_end_p (gsi); gsi_next (&gsi)) ++ { ++ gimple *g = gsi_stmt (gsi); ++ if (gimple_vdef (g) || gimple_has_side_effects (g)) ++ return true; ++ } ++ return false; ++} ++ ++/* Given an inner loop LOOP (of some OUTER loop) determine if ++ we can safely fuse copies of it (generated by outer unrolling). ++ If so return true, otherwise return false. */ ++ ++static bool ++unroll_jam_possible_p (struct loop *outer, struct loop *loop) ++{ ++ basic_block *bbs; ++ int i, n; ++ struct tree_niter_desc niter; ++ ++ /* When fusing the loops we skip the latch block ++ of the first one, so it mustn't have any effects to ++ preserve. */ ++ if (!empty_block_p (loop->latch)) ++ return false; ++ ++ if (!single_exit (loop)) ++ return false; ++ ++ /* We need a perfect nest. Quick check for adjacent inner loops. */ ++ if (outer->inner != loop || loop->next) ++ return false; ++ ++ /* Prevent head-controlled inner loops, that we usually have. ++ The guard block would need to be accepted ++ (invariant condition either entering or skipping the loop), ++ without also accepting arbitrary control flow. When unswitching ++ ran before us (as with -O3) this won't be a problem because its ++ outer loop unswitching will have moved out the invariant condition. ++ ++ If we do that we need to extend fuse_loops () to cope with this ++ by threading through the (still invariant) copied condition ++ between the two loop copies. */ ++ if (!dominated_by_p (CDI_DOMINATORS, outer->latch, loop->header)) ++ return false; ++ ++ /* The number of iterations of the inner loop must be loop invariant ++ with respect to the outer loop. */ ++ if (!number_of_iterations_exit (loop, single_exit (loop), &niter, ++ false, true) ++ || niter.cmp == ERROR_MARK ++ || !integer_zerop (niter.may_be_zero) ++ || !expr_invariant_in_loop_p (outer, niter.niter)) ++ return false; ++ ++ /* If the inner loop produces any values that are used inside the ++ outer loop (except the virtual op) then it can flow ++ back (perhaps indirectly) into the inner loop. This prevents ++ fusion: without fusion the value at the last iteration is used, ++ with fusion the value after the initial iteration is used. ++ ++ If all uses are outside the outer loop this doesn't prevent fusion; ++ the value of the last iteration is still used (and the values from ++ all intermediate iterations are dead). */ ++ gphi_iterator psi; ++ for (psi = gsi_start_phis (single_exit (loop)->dest); ++ !gsi_end_p (psi); gsi_next (&psi)) ++ { ++ imm_use_iterator imm_iter; ++ use_operand_p use_p; ++ tree op = gimple_phi_result (psi.phi ()); ++ if (virtual_operand_p (op)) ++ continue; ++ FOR_EACH_IMM_USE_FAST (use_p, imm_iter, op) ++ { ++ gimple *use_stmt = USE_STMT (use_p); ++ if (!is_gimple_debug (use_stmt) ++ && flow_bb_inside_loop_p (outer, gimple_bb (use_stmt))) ++ return false; ++ } ++ } ++ ++ /* And check blocks belonging to just outer loop. */ ++ bbs = XNEWVEC (basic_block, n_basic_blocks_for_fn (cfun)); ++ n = get_loop_body_with_size (outer, bbs, n_basic_blocks_for_fn (cfun)); ++ ++ for (i = 0; i < n; i++) ++ if (bbs[i]->loop_father == outer && bb_prevents_fusion_p (bbs[i])) ++ break; ++ free (bbs); ++ if (i != n) ++ return false; ++ ++ /* For now we can safely fuse copies of LOOP only if all ++ loop carried variables are inductions (or the virtual op). ++ ++ We could handle reductions as well (the initial value in the second ++ body would be the after-iter value of the first body) if it's over ++ an associative and commutative operation. We wouldn't ++ be able to handle unknown cycles. */ ++ for (psi = gsi_start_phis (loop->header); !gsi_end_p (psi); gsi_next (&psi)) ++ { ++ affine_iv iv; ++ tree op = gimple_phi_result (psi.phi ()); ++ ++ if (virtual_operand_p (op)) ++ continue; ++ if (!simple_iv (loop, loop, op, &iv, true)) ++ return false; ++ /* The inductions must be regular, loop invariant step and initial ++ value. */ ++ if (!expr_invariant_in_loop_p (outer, iv.step) ++ || !expr_invariant_in_loop_p (outer, iv.base)) ++ return false; ++ /* XXX With more effort we could also be able to deal with inductions ++ where the initial value is loop variant but a simple IV in the ++ outer loop. The initial value for the second body would be ++ the original initial value plus iv.base.step. The next value ++ for the fused loop would be the original next value of the first ++ copy, _not_ the next value of the second body. */ ++ } ++ ++ return true; ++} ++ ++/* Fuse LOOP with all further neighbors. The loops are expected to ++ be in appropriate form. */ ++ ++static void ++fuse_loops (struct loop *loop) ++{ ++ struct loop *next = loop->next; ++ ++ while (next) ++ { ++ edge e; ++ ++ remove_branch (single_pred_edge (loop->latch)); ++ /* Make delete_basic_block not fiddle with the loop structure. */ ++ basic_block oldlatch = loop->latch; ++ loop->latch = NULL; ++ delete_basic_block (oldlatch); ++ e = redirect_edge_and_branch (loop_latch_edge (next), ++ loop->header); ++ loop->latch = e->src; ++ flush_pending_stmts (e); ++ ++ gcc_assert (EDGE_COUNT (next->header->preds) == 1); ++ ++ /* The PHI nodes of the second body (single-argument now) ++ need adjustments to use the right values: either directly ++ the value of the corresponding PHI in the first copy or ++ the one leaving the first body which unrolling did for us. ++ ++ See also unroll_jam_possible_p () for further possibilities. */ ++ gphi_iterator psi_first, psi_second; ++ e = single_pred_edge (next->header); ++ for (psi_first = gsi_start_phis (loop->header), ++ psi_second = gsi_start_phis (next->header); ++ !gsi_end_p (psi_first); ++ gsi_next (&psi_first), gsi_next (&psi_second)) ++ { ++ gphi *phi_first = psi_first.phi (); ++ gphi *phi_second = psi_second.phi (); ++ tree firstop = gimple_phi_result (phi_first); ++ /* The virtual operand is correct already as it's ++ always live at exit, hence has a LCSSA node and outer ++ loop unrolling updated SSA form. */ ++ if (virtual_operand_p (firstop)) ++ continue; ++ ++ /* Due to unroll_jam_possible_p () we know that this is ++ an induction. The second body goes over the same ++ iteration space. */ ++ add_phi_arg (phi_second, firstop, e, ++ gimple_location (phi_first)); ++ } ++ gcc_assert (gsi_end_p (psi_second)); ++ ++ merge_loop_tree (loop, next); ++ gcc_assert (!next->num_nodes); ++ struct loop *ln = next->next; ++ delete_loop (next); ++ next = ln; ++ } ++ rewrite_into_loop_closed_ssa_1 (NULL, 0, SSA_OP_USE, loop); ++} ++ ++/* Returns true if the distance in DDR can be determined and adjusts ++ the unroll factor in *UNROLL to make unrolling valid for that distance. ++ Otherwise return false. ++ ++ If this data dep can lead to a removed memory reference, increment ++ *REMOVED and adjust *PROFIT_UNROLL to be the necessary unroll factor ++ for this to happen. */ ++ ++static bool ++adjust_unroll_factor (struct data_dependence_relation *ddr, ++ unsigned *unroll, unsigned *profit_unroll, ++ unsigned *removed) ++{ ++ bool ret = false; ++ if (DDR_ARE_DEPENDENT (ddr) != chrec_known) ++ { ++ if (DDR_NUM_DIST_VECTS (ddr) == 0) ++ return false; ++ unsigned i; ++ lambda_vector dist_v; ++ FOR_EACH_VEC_ELT (DDR_DIST_VECTS (ddr), i, dist_v) ++ { ++ /* A distance (a,b) is at worst transformed into (a/N,b) by the ++ unrolling (factor N), so the transformation is valid if ++ a >= N, or b > 0, or b is zero and a > 0. Otherwise the unroll ++ factor needs to be limited so that the first condition holds. ++ That may limit the factor down to zero in the worst case. */ ++ int dist = dist_v[0]; ++ if (dist < 0) ++ gcc_unreachable (); ++ else if ((unsigned)dist >= *unroll) ++ ; ++ else if (lambda_vector_lexico_pos (dist_v + 1, DDR_NB_LOOPS (ddr) - 1) ++ || (lambda_vector_zerop (dist_v + 1, DDR_NB_LOOPS (ddr) - 1) ++ && dist > 0)) ++ ; ++ else ++ *unroll = dist; ++ ++ /* With a distance (a,0) it's always profitable to unroll-and-jam ++ (by a+1), because one memory reference will go away. With ++ (a,b) and b != 0 that's less clear. We will increase the ++ number of streams without lowering the number of mem refs. ++ So for now only handle the first situation. */ ++ if (lambda_vector_zerop (dist_v + 1, DDR_NB_LOOPS (ddr) - 1)) ++ { ++ *profit_unroll = MAX (*profit_unroll, (unsigned)dist + 1); ++ (*removed)++; ++ } ++ ++ ret = true; ++ } ++ } ++ return ret; ++} ++ ++/* Main entry point for the unroll-and-jam transformation ++ described above. */ ++ ++static unsigned int ++tree_loop_unroll_and_jam (void) ++{ ++ struct loop *loop; ++ bool changed = false; ++ ++ gcc_assert (scev_initialized_p ()); ++ ++ /* Go through all innermost loops. */ ++ FOR_EACH_LOOP (loop, LI_ONLY_INNERMOST) ++ { ++ struct loop *outer = loop_outer (loop); ++ ++ if (loop_depth (loop) < 2 ++ || optimize_loop_nest_for_size_p (outer)) ++ continue; ++ ++ if (!unroll_jam_possible_p (outer, loop)) ++ continue; ++ ++ vec datarefs; ++ vec dependences; ++ unsigned unroll_factor, profit_unroll, removed; ++ struct tree_niter_desc desc; ++ bool unroll = false; ++ ++ auto_vec loop_nest; ++ dependences.create (10); ++ datarefs.create (10); ++ if (!compute_data_dependences_for_loop (outer, true, &loop_nest, ++ &datarefs, &dependences)) ++ { ++ if (dump_file && (dump_flags & TDF_DETAILS)) ++ fprintf (dump_file, "Cannot analyze data dependencies\n"); ++ free_data_refs (datarefs); ++ free_dependence_relations (dependences); ++ return false; ++ } ++ if (!datarefs.length ()) ++ continue; ++ ++ if (dump_file && (dump_flags & TDF_DETAILS)) ++ dump_data_dependence_relations (dump_file, dependences); ++ ++ unroll_factor = (unsigned)-1; ++ profit_unroll = 1; ++ removed = 0; ++ ++ /* Check all dependencies. */ ++ unsigned i; ++ struct data_dependence_relation *ddr; ++ FOR_EACH_VEC_ELT (dependences, i, ddr) ++ { ++ struct data_reference *dra, *drb; ++ ++ /* If the refs are independend there's nothing to do. */ ++ if (DDR_ARE_DEPENDENT (ddr) == chrec_known) ++ continue; ++ dra = DDR_A (ddr); ++ drb = DDR_B (ddr); ++ /* Nothing interesting for the self dependencies. */ ++ if (dra == drb) ++ continue; ++ ++ /* Now check the distance vector, for determining a sensible ++ outer unroll factor, and for validity of merging the inner ++ loop copies. */ ++ if (!adjust_unroll_factor (ddr, &unroll_factor, &profit_unroll, ++ &removed)) ++ { ++ /* Couldn't get the distance vector. For two reads that's ++ harmless (we assume we should unroll). For at least ++ one write this means we can't check the dependence direction ++ and hence can't determine safety. */ ++ ++ if (DR_IS_WRITE (dra) || DR_IS_WRITE (drb)) ++ { ++ unroll_factor = 0; ++ break; ++ } ++ } ++ } ++ ++ /* We regard a user-specified minimum percentage of zero as a request ++ to ignore all profitability concerns and apply the transformation ++ always. */ ++ if (!PARAM_VALUE (PARAM_UNROLL_JAM_MIN_PERCENT)) ++ profit_unroll = 2; ++ else if (removed * 100 / datarefs.length () ++ < (unsigned)PARAM_VALUE (PARAM_UNROLL_JAM_MIN_PERCENT)) ++ profit_unroll = 1; ++ if (unroll_factor > profit_unroll) ++ unroll_factor = profit_unroll; ++ if (unroll_factor > (unsigned)PARAM_VALUE (PARAM_UNROLL_JAM_MAX_UNROLL)) ++ unroll_factor = PARAM_VALUE (PARAM_UNROLL_JAM_MAX_UNROLL); ++ unroll = (unroll_factor > 1 ++ && can_unroll_loop_p (outer, unroll_factor, &desc)); ++ ++ if (unroll) ++ { ++ if (dump_enabled_p ()) ++ dump_printf_loc (MSG_OPTIMIZED_LOCATIONS | TDF_DETAILS, ++ find_loop_location (outer), ++ "applying unroll and jam with factor %d\n", ++ unroll_factor); ++ initialize_original_copy_tables (); ++ tree_unroll_loop (outer, unroll_factor, single_dom_exit (outer), ++ &desc); ++ free_original_copy_tables (); ++ fuse_loops (outer->inner); ++ changed = true; ++ } ++ ++ loop_nest.release (); ++ free_dependence_relations (dependences); ++ free_data_refs (datarefs); ++ } ++ ++ if (changed) ++ { ++ scev_reset (); ++ free_dominance_info (CDI_DOMINATORS); ++ return TODO_cleanup_cfg; ++ } ++ return 0; ++} ++ ++/* Pass boilerplate. */ ++ ++namespace { ++ ++const pass_data pass_data_loop_jam = ++{ ++ GIMPLE_PASS, /* type. */ ++ "unrolljam", /* name. */ ++ OPTGROUP_LOOP, /* optinfo_flags. */ ++ TV_LOOP_JAM, /* tv_id. */ ++ PROP_cfg, /* properties_required. */ ++ 0, /* properties_provided. */ ++ 0, /* properties_destroyed. */ ++ 0, /* todo_flags_start. */ ++ 0, /* todo_flags_finish. */ ++}; ++ ++class pass_loop_jam : public gimple_opt_pass ++{ ++public: ++ pass_loop_jam (gcc::context *ctxt) ++ : gimple_opt_pass (pass_data_loop_jam, ctxt) ++ {} ++ ++ /* opt_pass methods: */ ++ virtual bool gate (function *) ++ { ++ return flag_unroll_jam != 0; ++ } ++ virtual unsigned int execute (function *); ++ ++}; ++ ++unsigned int ++pass_loop_jam::execute (function *fun) ++{ ++ if (number_of_loops (fun) <= 1) ++ return 0; ++ ++ return tree_loop_unroll_and_jam (); ++} ++ ++} ++ ++gimple_opt_pass * ++make_pass_loop_jam (gcc::context *ctxt) ++{ ++ return new pass_loop_jam (ctxt); ++} ++ +diff -N -urp a/gcc/opts.c b/gcc/opts.c +--- a/gcc/opts.c 2018-11-07 11:37:24.891223860 +0800 ++++ b/gcc/opts.c 2018-11-07 11:38:26.171223860 +0800 +@@ -534,6 +534,7 @@ static const struct default_options defa + { OPT_LEVELS_1_PLUS_NOT_DEBUG, OPT_finline_functions_called_once, NULL, 1 }, + { OPT_LEVELS_3_PLUS, OPT_fsplit_loops, NULL, 1 }, + { OPT_LEVELS_3_PLUS, OPT_funswitch_loops, NULL, 1 }, ++ { OPT_LEVELS_3_PLUS, OPT_floop_unroll_and_jam, NULL, 1 }, + { OPT_LEVELS_3_PLUS, OPT_fgcse_after_reload, NULL, 1 }, + { OPT_LEVELS_3_PLUS, OPT_ftree_loop_vectorize, NULL, 1 }, + { OPT_LEVELS_3_PLUS, OPT_ftree_slp_vectorize, NULL, 1 }, +diff -N -urp a/gcc/params.def b/gcc/params.def +--- a/gcc/params.def 2018-11-07 11:37:27.543223860 +0800 ++++ b/gcc/params.def 2018-11-07 11:38:26.171223860 +0800 +@@ -1280,6 +1280,16 @@ DEFPARAM (PARAM_VECT_EPILOGUES_NOMASK, + "Enable loop epilogue vectorization using smaller vector size.", + 0, 0, 1) + ++DEFPARAM (PARAM_UNROLL_JAM_MIN_PERCENT, ++ "unroll-jam-min-percent", ++ "Minimum percentage of memrefs that must go away for unroll-and-jam to be considered profitable.", ++ 1, 0, 100) ++ ++DEFPARAM (PARAM_UNROLL_JAM_MAX_UNROLL, ++ "unroll-jam-max-unroll", ++ "Maximum unroll factor for the unroll-and-jam transformation.", ++ 4, 0, 0) ++ + /* + + Local variables: +diff -N -urp a/gcc/passes.def b/gcc/passes.def +--- a/gcc/passes.def 2018-11-07 11:37:24.859223860 +0800 ++++ b/gcc/passes.def 2018-11-07 11:38:26.171223860 +0800 +@@ -272,6 +272,7 @@ along with GCC; see the file COPYING3. + NEXT_PASS (pass_tree_unswitch); + NEXT_PASS (pass_scev_cprop); + NEXT_PASS (pass_loop_split); ++ NEXT_PASS (pass_loop_jam); + /* All unswitching, final value replacement and splitting can expose + empty loops. Remove them now. */ + NEXT_PASS (pass_cd_dce); +diff -N -urp a/gcc/timevar.def b/gcc/timevar.def +--- a/gcc/timevar.def 2018-11-07 11:37:24.935223860 +0800 ++++ b/gcc/timevar.def 2018-11-07 11:38:26.175223860 +0800 +@@ -186,6 +186,7 @@ DEFTIMEVAR (TV_TREE_LOOP_IVCANON , " + DEFTIMEVAR (TV_SCEV_CONST , "scev constant prop") + DEFTIMEVAR (TV_TREE_LOOP_UNSWITCH , "tree loop unswitching") + DEFTIMEVAR (TV_LOOP_SPLIT , "loop splitting") ++DEFTIMEVAR (TV_LOOP_JAM , "unroll and jam") + DEFTIMEVAR (TV_COMPLETE_UNROLL , "complete unrolling") + DEFTIMEVAR (TV_TREE_PARALLELIZE_LOOPS, "tree parallelize loops") + DEFTIMEVAR (TV_TREE_VECTORIZATION , "tree vectorization") +diff -N -urp a/gcc/tree-pass.h b/gcc/tree-pass.h +--- a/gcc/tree-pass.h 2018-11-07 11:37:24.887223860 +0800 ++++ b/gcc/tree-pass.h 2018-11-07 11:38:26.175223860 +0800 +@@ -369,6 +369,7 @@ extern gimple_opt_pass *make_pass_tree_l + extern gimple_opt_pass *make_pass_lim (gcc::context *ctxt); + extern gimple_opt_pass *make_pass_tree_unswitch (gcc::context *ctxt); + extern gimple_opt_pass *make_pass_loop_split (gcc::context *ctxt); ++extern gimple_opt_pass *make_pass_loop_jam (gcc::context *ctxt); + extern gimple_opt_pass *make_pass_predcom (gcc::context *ctxt); + extern gimple_opt_pass *make_pass_iv_canon (gcc::context *ctxt); + extern gimple_opt_pass *make_pass_scev_cprop (gcc::context *ctxt); diff --git a/fstack-clash-protection.patch b/fstack-clash-protection.patch new file mode 100644 index 0000000..ecbc766 --- /dev/null +++ b/fstack-clash-protection.patch @@ -0,0 +1,768 @@ +diff -N -urp a/gcc/combine-stack-adj.c b/gcc/combine-stack-adj.c +--- a/gcc/combine-stack-adj.c 2017-01-20 08:05:30.925466000 +0800 ++++ b/gcc/combine-stack-adj.c 2019-01-10 17:10:16.606528459 +0800 +@@ -508,6 +508,8 @@ combine_stack_adjustments_for_block (bas + continue; + + set = single_set_for_csa (insn); ++ if (set && find_reg_note (insn, REG_STACK_CHECK, NULL_RTX)) ++ set = NULL_RTX; + if (set) + { + rtx dest = SET_DEST (set); +diff -N -urp a/gcc/common.opt b/gcc/common.opt +--- a/gcc/common.opt 2019-01-10 13:33:20.926185828 +0800 ++++ b/gcc/common.opt 2019-01-10 16:37:35.238476827 +0800 +@@ -2336,13 +2336,18 @@ Common Report Var(flag_variable_expansio + Apply variable expansion when loops are unrolled. + + fstack-check= +-Common Report RejectNegative Joined ++Common Report RejectNegative Joined Optimization + -fstack-check=[no|generic|specific] Insert stack checking code into the program. + + fstack-check + Common Alias(fstack-check=, specific, no) + Insert stack checking code into the program. Same as -fstack-check=specific. + ++fstack-clash-protection ++Common Report Var(flag_stack_clash_protection) Optimization ++Insert code to probe each page of stack space as it is allocated to protect ++from stack-clash style attacks. ++ + fstack-limit + Common Var(common_deferred_options) Defer + +diff -N -urp a/gcc/config/aarch64/aarch64.c b/gcc/config/aarch64/aarch64.c +--- a/gcc/config/aarch64/aarch64.c 2019-01-10 13:33:20.914185828 +0800 ++++ b/gcc/config/aarch64/aarch64.c 2019-01-11 14:12:22.248521895 +0800 +@@ -3881,12 +3881,14 @@ aarch64_expand_prologue (void) + { + if (crtl->is_leaf && !cfun->calls_alloca) + { +- if (frame_size > PROBE_INTERVAL && frame_size > STACK_CHECK_PROTECT) +- aarch64_emit_probe_stack_range (STACK_CHECK_PROTECT, +- frame_size - STACK_CHECK_PROTECT); ++ if (frame_size > PROBE_INTERVAL ++ && frame_size > get_stack_check_protect ()) ++ aarch64_emit_probe_stack_range (get_stack_check_protect (), ++ (frame_size ++ - get_stack_check_protect ())); + } + else if (frame_size > 0) +- aarch64_emit_probe_stack_range (STACK_CHECK_PROTECT, frame_size); ++ aarch64_emit_probe_stack_range (get_stack_check_protect (), frame_size); + } + + aarch64_sub_sp (IP0_REGNUM, initial_adjust, true); +diff -N -urp a/gcc/config/i386/i386.c b/gcc/config/i386/i386.c +--- a/gcc/config/i386/i386.c 2019-01-10 13:33:20.674185822 +0800 ++++ b/gcc/config/i386/i386.c 2019-01-28 10:55:37.006876481 +0800 +@@ -14396,7 +14396,7 @@ ix86_expand_prologue (void) + HOST_WIDE_INT size = allocate; + + if (TARGET_64BIT && size >= HOST_WIDE_INT_C (0x80000000)) +- size = 0x80000000 - STACK_CHECK_PROTECT - 1; ++ size = 0x80000000 - get_stack_check_protect () - 1; + + if (TARGET_STACK_PROBE) + { +@@ -14406,18 +14406,21 @@ ix86_expand_prologue (void) + ix86_emit_probe_stack_range (0, size); + } + else +- ix86_emit_probe_stack_range (0, size + STACK_CHECK_PROTECT); ++ ix86_emit_probe_stack_range (0, ++ size + get_stack_check_protect ()); + } + else + { + if (crtl->is_leaf && !cfun->calls_alloca) + { +- if (size > PROBE_INTERVAL && size > STACK_CHECK_PROTECT) +- ix86_emit_probe_stack_range (STACK_CHECK_PROTECT, +- size - STACK_CHECK_PROTECT); ++ if (size > PROBE_INTERVAL ++ && size > get_stack_check_protect ()) ++ ix86_emit_probe_stack_range (get_stack_check_protect (), ++ (size ++ - get_stack_check_protect ())); + } + else +- ix86_emit_probe_stack_range (STACK_CHECK_PROTECT, size); ++ ix86_emit_probe_stack_range (get_stack_check_protect (), size); + } + } + } +diff -N -urp a/gcc/config/ia64/ia64.c b/gcc/config/ia64/ia64.c +--- a/gcc/config/ia64/ia64.c 2017-01-01 20:07:43.905435000 +0800 ++++ b/gcc/config/ia64/ia64.c 2019-01-28 10:58:37.582881234 +0800 +@@ -3481,15 +3481,16 @@ ia64_expand_prologue (void) + + if (crtl->is_leaf && !cfun->calls_alloca) + { +- if (size > PROBE_INTERVAL && size > STACK_CHECK_PROTECT) +- ia64_emit_probe_stack_range (STACK_CHECK_PROTECT, +- size - STACK_CHECK_PROTECT, ++ if (size > PROBE_INTERVAL && size > get_stack_check_protect ()) ++ ia64_emit_probe_stack_range (get_stack_check_protect (), ++ size - get_stack_check_protect (), + bs_size); +- else if (size + bs_size > STACK_CHECK_PROTECT) +- ia64_emit_probe_stack_range (STACK_CHECK_PROTECT, 0, bs_size); ++ else if (size + bs_size > get_stack_check_protect ()) ++ ia64_emit_probe_stack_range (get_stack_check_protect (), ++ 0, bs_size); + } + else if (size + bs_size > 0) +- ia64_emit_probe_stack_range (STACK_CHECK_PROTECT, size, bs_size); ++ ia64_emit_probe_stack_range (get_stack_check_protect (), size, bs_size); + } + + if (dump_file) +diff -N -urp a/gcc/coretypes.h b/gcc/coretypes.h +--- a/gcc/coretypes.h 2017-01-01 20:07:43.905435000 +0800 ++++ b/gcc/coretypes.h 2019-01-11 14:09:58.612518114 +0800 +@@ -371,6 +371,7 @@ typedef unsigned char uchar; + #include "input.h" + #include "is-a.h" + #include "memory-block.h" ++#include "dumpfile.h" + #endif /* GENERATOR_FILE && !USED_FOR_TARGET */ + + #endif /* coretypes.h */ +diff -N -urp a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi +--- a/gcc/doc/invoke.texi 2019-01-10 13:33:20.882185827 +0800 ++++ b/gcc/doc/invoke.texi 2019-01-10 16:40:40.066481692 +0800 +@@ -10050,6 +10050,21 @@ compilation without. The value for comp + needs to be more conservative (higher) in order to make tracer + effective. + ++@item stack-clash-protection-guard-size ++Specify the size of the operating system provided stack guard as ++2 raised to @var{num} bytes. The default value is 12 (4096 bytes). ++Acceptable values are between 12 and 30. Higher values may reduce the ++number of explicit probes, but a value larger than the operating system ++provided guard will leave code vulnerable to stack clash style attacks. ++ ++@item stack-clash-protection-probe-interval ++Stack clash protection involves probing stack space as it is allocated. This ++param controls the maximum distance between probes into the stack as 2 raised ++to @var{num} bytes. Acceptable values are between 10 and 16 and defaults to ++12. Higher values may reduce the number of explicit probes, but a value ++larger than the operating system provided guard will leave code vulnerable to ++stack clash style attacks. ++ + @item max-cse-path-length + + The maximum number of basic blocks on path that CSE considers. +@@ -11248,7 +11263,8 @@ target support in the compiler but comes + @enumerate + @item + Modified allocation strategy for large objects: they are always +-allocated dynamically if their size exceeds a fixed threshold. ++allocated dynamically if their size exceeds a fixed threshold. Note this ++may change the semantics of some code. + + @item + Fixed limit on the size of the static frame of functions: when it is +@@ -11263,6 +11279,25 @@ generic implementation, code performance + Note that old-style stack checking is also the fallback method for + @samp{specific} if no target support has been added in the compiler. + ++@samp{-fstack-check=} is designed for Ada's needs to detect infinite recursion ++and stack overflows. @samp{specific} is an excellent choice when compiling ++Ada code. It is not generally sufficient to protect against stack-clash ++attacks. To protect against those you want @samp{-fstack-clash-protection}. ++ ++@item -fstack-clash-protection ++@opindex fstack-clash-protection ++Generate code to prevent stack clash style attacks. When this option is ++enabled, the compiler will only allocate one page of stack space at a time ++and each page is accessed immediately after allocation. Thus, it prevents ++allocations from jumping over any stack guard page provided by the ++operating system. ++ ++Most targets do not fully support stack clash protection. However, on ++those targets @option{-fstack-clash-protection} will protect dynamic stack ++allocations. @option{-fstack-clash-protection} may also provide limited ++protection for static stack allocations if the target supports ++@option{-fstack-check=specific}. ++ + @item -fstack-limit-register=@var{reg} + @itemx -fstack-limit-symbol=@var{sym} + @itemx -fno-stack-limit +diff -N -urp a/gcc/doc/tm.texi b/gcc/doc/tm.texi +--- a/gcc/doc/tm.texi 2017-04-05 01:52:27.193766000 +0800 ++++ b/gcc/doc/tm.texi 2019-01-10 16:50:44.006497591 +0800 +@@ -3419,6 +3419,10 @@ GCC computed the default from the values + normally not need to override that default. + @end defmac + ++@deftypefn {Target Hook} bool TARGET_STACK_CLASH_PROTECTION_FINAL_DYNAMIC_PROBE (rtx @var{residual}) ++Some targets make optimistic assumptions about the state of stack probing when they emit their prologues. On such targets a probe into the end of any dynamically allocated space is likely required for safety against stack clash style attacks. Define this variable to return nonzero if such a probe is required or zero otherwise. You need not define this macro if it would always have the value zero. ++@end deftypefn ++ + @need 2000 + @node Frame Registers + @subsection Registers That Address the Stack Frame +diff -N -urp a/gcc/doc/tm.texi.in b/gcc/doc/tm.texi.in +--- a/gcc/doc/tm.texi.in 2017-04-05 01:52:27.193766000 +0800 ++++ b/gcc/doc/tm.texi.in 2019-01-10 16:51:41.530499105 +0800 +@@ -2999,6 +2999,8 @@ GCC computed the default from the values + normally not need to override that default. + @end defmac + ++@hook TARGET_STACK_CLASH_PROTECTION_FINAL_DYNAMIC_PROBE ++ + @need 2000 + @node Frame Registers + @subsection Registers That Address the Stack Frame +diff -N -urp a/gcc/explow.c b/gcc/explow.c +--- a/gcc/explow.c 2017-02-02 20:39:09.589196000 +0800 ++++ b/gcc/explow.c 2019-01-10 16:56:07.454506105 +0800 +@@ -39,8 +39,10 @@ along with GCC; see the file COPYING3. + #include "expr.h" + #include "common/common-target.h" + #include "output.h" ++#include "params.h" + + static rtx break_out_memory_refs (rtx); ++static void anti_adjust_stack_and_probe_stack_clash (rtx); + + + /* Truncate and perhaps sign-extend C as appropriate for MODE. */ +@@ -1271,6 +1273,29 @@ get_dynamic_stack_size (rtx *psize, unsi + *psize = size; + } + ++/* Return the number of bytes to "protect" on the stack for -fstack-check. ++ ++ "protect" in the context of -fstack-check means how many bytes we ++ should always ensure are available on the stack. More importantly ++ this is how many bytes are skipped when probing the stack. ++ ++ On some targets we want to reuse the -fstack-check prologue support ++ to give a degree of protection against stack clashing style attacks. ++ ++ In that scenario we do not want to skip bytes before probing as that ++ would render the stack clash protections useless. ++ ++ So we never use STACK_CHECK_PROTECT directly. Instead we indirect though ++ this helper which allows us to provide different values for ++ -fstack-check and -fstack-clash-protection. */ ++HOST_WIDE_INT ++get_stack_check_protect (void) ++{ ++ if (flag_stack_clash_protection) ++ return 0; ++ return STACK_CHECK_PROTECT; ++} ++ + /* Return an rtx representing the address of an area of memory dynamically + pushed on the stack. + +@@ -1429,7 +1454,7 @@ allocate_dynamic_stack_space (rtx size, + probe_stack_range (STACK_OLD_CHECK_PROTECT + STACK_CHECK_MAX_FRAME_SIZE, + size); + else if (flag_stack_check == STATIC_BUILTIN_STACK_CHECK) +- probe_stack_range (STACK_CHECK_PROTECT, size); ++ probe_stack_range (get_stack_check_protect (), size); + + /* Don't let anti_adjust_stack emit notes. */ + suppress_reg_args_size = true; +@@ -1482,6 +1507,8 @@ allocate_dynamic_stack_space (rtx size, + + if (flag_stack_check && STACK_CHECK_MOVING_SP) + anti_adjust_stack_and_probe (size, false); ++ else if (flag_stack_clash_protection) ++ anti_adjust_stack_and_probe_stack_clash (size); + else + anti_adjust_stack (size); + +@@ -1757,6 +1784,237 @@ probe_stack_range (HOST_WIDE_INT first, + emit_insn (gen_blockage ()); + } + ++/* Compute parameters for stack clash probing a dynamic stack ++ allocation of SIZE bytes. ++ ++ We compute ROUNDED_SIZE, LAST_ADDR, RESIDUAL and PROBE_INTERVAL. ++ ++ Additionally we conditionally dump the type of probing that will ++ be needed given the values computed. */ ++ ++void ++compute_stack_clash_protection_loop_data (rtx *rounded_size, rtx *last_addr, ++ rtx *residual, ++ HOST_WIDE_INT *probe_interval, ++ rtx size) ++{ ++ /* Round SIZE down to STACK_CLASH_PROTECTION_PROBE_INTERVAL. */ ++ *probe_interval ++ = 1 << PARAM_VALUE (PARAM_STACK_CLASH_PROTECTION_PROBE_INTERVAL); ++ *rounded_size = simplify_gen_binary (AND, Pmode, size, ++ GEN_INT (-*probe_interval)); ++ ++ /* Compute the value of the stack pointer for the last iteration. ++ It's just SP + ROUNDED_SIZE. */ ++ rtx rounded_size_op = force_operand (*rounded_size, NULL_RTX); ++ *last_addr = force_operand (gen_rtx_fmt_ee (STACK_GROW_OP, Pmode, ++ stack_pointer_rtx, ++ rounded_size_op), ++ NULL_RTX); ++ ++ /* Compute any residuals not allocated by the loop above. Residuals ++ are just the ROUNDED_SIZE - SIZE. */ ++ *residual = simplify_gen_binary (MINUS, Pmode, size, *rounded_size); ++ ++ /* Dump key information to make writing tests easy. */ ++ if (dump_file) ++ { ++ if (*rounded_size == CONST0_RTX (Pmode)) ++ fprintf (dump_file, ++ "Stack clash skipped dynamic allocation and probing loop.\n"); ++ else if (CONST_INT_P (*rounded_size) ++ && INTVAL (*rounded_size) <= 4 * *probe_interval) ++ fprintf (dump_file, ++ "Stack clash dynamic allocation and probing inline.\n"); ++ else if (CONST_INT_P (*rounded_size)) ++ fprintf (dump_file, ++ "Stack clash dynamic allocation and probing in " ++ "rotated loop.\n"); ++ else ++ fprintf (dump_file, ++ "Stack clash dynamic allocation and probing in loop.\n"); ++ ++ if (*residual != CONST0_RTX (Pmode)) ++ fprintf (dump_file, ++ "Stack clash dynamic allocation and probing residuals.\n"); ++ else ++ fprintf (dump_file, ++ "Stack clash skipped dynamic allocation and " ++ "probing residuals.\n"); ++ } ++} ++ ++/* Emit the start of an allocate/probe loop for stack ++ clash protection. ++ ++ LOOP_LAB and END_LAB are returned for use when we emit the ++ end of the loop. ++ ++ LAST addr is the value for SP which stops the loop. */ ++void ++emit_stack_clash_protection_probe_loop_start (rtx *loop_lab, ++ rtx *end_lab, ++ rtx last_addr, ++ bool rotated) ++{ ++ /* Essentially we want to emit any setup code, the top of loop ++ label and the comparison at the top of the loop. */ ++ *loop_lab = gen_label_rtx (); ++ *end_lab = gen_label_rtx (); ++ ++ emit_label (*loop_lab); ++ if (!rotated) ++ emit_cmp_and_jump_insns (stack_pointer_rtx, last_addr, EQ, NULL_RTX, ++ Pmode, 1, *end_lab); ++} ++ ++/* Emit the end of a stack clash probing loop. ++ ++ This consists of just the jump back to LOOP_LAB and ++ emitting END_LOOP after the loop. */ ++ ++void ++emit_stack_clash_protection_probe_loop_end (rtx loop_lab, rtx end_loop, ++ rtx last_addr, bool rotated) ++{ ++ if (rotated) ++ emit_cmp_and_jump_insns (stack_pointer_rtx, last_addr, NE, NULL_RTX, ++ Pmode, 1, loop_lab); ++ else ++ emit_jump (loop_lab); ++ ++ emit_label (end_loop); ++ ++} ++ ++/* Adjust the stack pointer by minus SIZE (an rtx for a number of bytes) ++ while probing it. This pushes when SIZE is positive. SIZE need not ++ be constant. ++ ++ This is subtly different than anti_adjust_stack_and_probe to try and ++ prevent stack-clash attacks ++ ++ 1. It must assume no knowledge of the probing state, any allocation ++ must probe. ++ ++ Consider the case of a 1 byte alloca in a loop. If the sum of the ++ allocations is large, then this could be used to jump the guard if ++ probes were not emitted. ++ ++ 2. It never skips probes, whereas anti_adjust_stack_and_probe will ++ skip probes on the first couple PROBE_INTERVALs on the assumption ++ they're done elsewhere. ++ ++ 3. It only allocates and probes SIZE bytes, it does not need to ++ allocate/probe beyond that because this probing style does not ++ guarantee signal handling capability if the guard is hit. */ ++ ++static void ++anti_adjust_stack_and_probe_stack_clash (rtx size) ++{ ++ /* First ensure SIZE is Pmode. */ ++ if (GET_MODE (size) != VOIDmode && GET_MODE (size) != Pmode) ++ size = convert_to_mode (Pmode, size, 1); ++ ++ /* We can get here with a constant size on some targets. */ ++ rtx rounded_size, last_addr, residual; ++ HOST_WIDE_INT probe_interval; ++ compute_stack_clash_protection_loop_data (&rounded_size, &last_addr, ++ &residual, &probe_interval, size); ++ ++ if (rounded_size != CONST0_RTX (Pmode)) ++ { ++ if (CONST_INT_P (rounded_size) ++ && INTVAL (rounded_size) <= 4 * probe_interval) ++ { ++ for (HOST_WIDE_INT i = 0; ++ i < INTVAL (rounded_size); ++ i += probe_interval) ++ { ++ anti_adjust_stack (GEN_INT (probe_interval)); ++ ++ /* The prologue does not probe residuals. Thus the offset ++ here to probe just beyond what the prologue had already ++ allocated. */ ++ emit_stack_probe (plus_constant (Pmode, stack_pointer_rtx, ++ (probe_interval ++ - GET_MODE_SIZE (word_mode)))); ++ emit_insn (gen_blockage ()); ++ } ++ } ++ else ++ { ++ rtx loop_lab, end_loop; ++ bool rotate_loop = CONST_INT_P (rounded_size); ++ emit_stack_clash_protection_probe_loop_start (&loop_lab, &end_loop, ++ last_addr, rotate_loop); ++ ++ anti_adjust_stack (GEN_INT (probe_interval)); ++ ++ /* The prologue does not probe residuals. Thus the offset here ++ to probe just beyond what the prologue had already allocated. */ ++ emit_stack_probe (plus_constant (Pmode, stack_pointer_rtx, ++ (probe_interval ++ - GET_MODE_SIZE (word_mode)))); ++ ++ emit_stack_clash_protection_probe_loop_end (loop_lab, end_loop, ++ last_addr, rotate_loop); ++ emit_insn (gen_blockage ()); ++ } ++ } ++ ++ if (residual != CONST0_RTX (Pmode)) ++ { ++ rtx label = NULL_RTX; ++ /* RESIDUAL could be zero at runtime and in that case *sp could ++ hold live data. Furthermore, we do not want to probe into the ++ red zone. ++ ++ Go ahead and just guard the probe at *sp on RESIDUAL != 0 at ++ runtime if RESIDUAL is not a compile time constant. */ ++ if (!CONST_INT_P (residual)) ++ { ++ label = gen_label_rtx (); ++ emit_cmp_and_jump_insns (residual, CONST0_RTX (GET_MODE (residual)), ++ EQ, NULL_RTX, Pmode, 1, label); ++ } ++ ++ rtx x = force_reg (Pmode, plus_constant (Pmode, residual, ++ -GET_MODE_SIZE (word_mode))); ++ anti_adjust_stack (residual); ++ emit_stack_probe (gen_rtx_PLUS (Pmode, stack_pointer_rtx, x)); ++ emit_insn (gen_blockage ()); ++ if (!CONST_INT_P (residual)) ++ emit_label (label); ++ } ++ ++ /* Some targets make optimistic assumptions in their prologues about ++ how the caller may have probed the stack. Make sure we honor ++ those assumptions when needed. */ ++ if (size != CONST0_RTX (Pmode) ++ && targetm.stack_clash_protection_final_dynamic_probe (residual)) ++ { ++ /* SIZE could be zero at runtime and in that case *sp could hold ++ live data. Furthermore, we don't want to probe into the red ++ zone. ++ ++ Go ahead and just guard the probe at *sp on SIZE != 0 at runtime ++ if SIZE is not a compile time constant. */ ++ rtx label = NULL_RTX; ++ if (!CONST_INT_P (size)) ++ { ++ label = gen_label_rtx (); ++ emit_cmp_and_jump_insns (size, CONST0_RTX (GET_MODE (size)), ++ EQ, NULL_RTX, Pmode, 1, label); ++ } ++ ++ emit_stack_probe (stack_pointer_rtx); ++ emit_insn (gen_blockage ()); ++ if (!CONST_INT_P (size)) ++ emit_label (label); ++ } ++} ++ + /* Adjust the stack pointer by minus SIZE (an rtx for a number of bytes) + while probing it. This pushes when SIZE is positive. SIZE need not + be constant. If ADJUST_BACK is true, adjust back the stack pointer +diff -N -urp a/gcc/explow.h b/gcc/explow.h +--- a/gcc/explow.h 2017-01-01 20:07:43.905435000 +0800 ++++ b/gcc/explow.h 2019-01-10 16:57:37.934508487 +0800 +@@ -69,6 +69,15 @@ extern void anti_adjust_stack (rtx); + /* Add some bytes to the stack while probing it. An rtx says how many. */ + extern void anti_adjust_stack_and_probe (rtx, bool); + ++/* Support for building allocation/probing loops for stack-clash ++ protection of dyamically allocated stack space. */ ++extern void compute_stack_clash_protection_loop_data (rtx *, rtx *, rtx *, ++ HOST_WIDE_INT *, rtx); ++extern void emit_stack_clash_protection_probe_loop_start (rtx *, rtx *, ++ rtx, bool); ++extern void emit_stack_clash_protection_probe_loop_end (rtx, rtx, ++ rtx, bool); ++ + /* This enum is used for the following two functions. */ + enum save_level {SAVE_BLOCK, SAVE_FUNCTION, SAVE_NONLOCAL}; + +diff -N -urp a/gcc/flag-types.h b/gcc/flag-types.h +--- a/gcc/flag-types.h 2017-01-01 20:07:43.905435000 +0800 ++++ b/gcc/flag-types.h 2019-01-10 16:42:11.490484099 +0800 +@@ -166,7 +166,14 @@ enum permitted_flt_eval_methods + PERMITTED_FLT_EVAL_METHODS_C11 + }; + +-/* Type of stack check. */ ++/* Type of stack check. ++ ++ Stack checking is designed to detect infinite recursion and stack ++ overflows for Ada programs. Furthermore stack checking tries to ensure ++ in that scenario that enough stack space is left to run a signal handler. ++ ++ -fstack-check= does not prevent stack-clash style attacks. For that ++ you want -fstack-clash-protection. */ + enum stack_check_type + { + /* Do not check the stack. */ +diff -N -urp a/gcc/function.c b/gcc/function.c +--- a/gcc/function.c 2017-08-08 21:21:12.755378000 +0800 ++++ b/gcc/function.c 2019-01-10 17:07:17.414523742 +0800 +@@ -5695,6 +5695,58 @@ get_arg_pointer_save_area (void) + return ret; + } + ++ ++/* If debugging dumps are requested, dump information about how the ++ target handled -fstack-check=clash for the prologue. ++ ++ PROBES describes what if any probes were emitted. ++ ++ RESIDUALS indicates if the prologue had any residual allocation ++ (i.e. total allocation was not a multiple of PROBE_INTERVAL). */ ++ ++void ++dump_stack_clash_frame_info (enum stack_clash_probes probes, bool residuals) ++{ ++ if (!dump_file) ++ return; ++ ++ switch (probes) ++ { ++ case NO_PROBE_NO_FRAME: ++ fprintf (dump_file, ++ "Stack clash no probe no stack adjustment in prologue.\n"); ++ break; ++ case NO_PROBE_SMALL_FRAME: ++ fprintf (dump_file, ++ "Stack clash no probe small stack adjustment in prologue.\n"); ++ break; ++ case PROBE_INLINE: ++ fprintf (dump_file, "Stack clash inline probes in prologue.\n"); ++ break; ++ case PROBE_LOOP: ++ fprintf (dump_file, "Stack clash probe loop in prologue.\n"); ++ break; ++ } ++ ++ if (residuals) ++ fprintf (dump_file, "Stack clash residual allocation in prologue.\n"); ++ else ++ fprintf (dump_file, "Stack clash no residual allocation in prologue.\n"); ++ ++ if (frame_pointer_needed) ++ fprintf (dump_file, "Stack clash frame pointer needed.\n"); ++ else ++ fprintf (dump_file, "Stack clash no frame pointer needed.\n"); ++ ++ if (TREE_THIS_VOLATILE (cfun->decl)) ++ fprintf (dump_file, ++ "Stack clash noreturn prologue, assuming no implicit" ++ " probes in caller.\n"); ++ else ++ fprintf (dump_file, ++ "Stack clash not noreturn prologue.\n"); ++} ++ + /* Add a list of INSNS to the hash HASHP, possibly allocating HASHP + for the first time. */ + +diff -N -urp a/gcc/function.h b/gcc/function.h +--- a/gcc/function.h 2017-01-25 01:07:36.015431000 +0800 ++++ b/gcc/function.h 2019-01-10 17:08:12.806525200 +0800 +@@ -553,6 +553,14 @@ do { \ + ((TARGET_PTRMEMFUNC_VBIT_LOCATION == ptrmemfunc_vbit_in_pfn) \ + ? MAX (FUNCTION_BOUNDARY, 2 * BITS_PER_UNIT) : FUNCTION_BOUNDARY) + ++enum stack_clash_probes { ++ NO_PROBE_NO_FRAME, ++ NO_PROBE_SMALL_FRAME, ++ PROBE_INLINE, ++ PROBE_LOOP ++}; ++ ++extern void dump_stack_clash_frame_info (enum stack_clash_probes, bool); + + + extern void push_function_context (void); +diff -N -urp a/gcc/params.def b/gcc/params.def +--- a/gcc/params.def 2019-01-10 13:33:20.894185827 +0800 ++++ b/gcc/params.def 2019-01-10 16:43:15.414485782 +0800 +@@ -213,6 +213,16 @@ DEFPARAM(PARAM_STACK_FRAME_GROWTH, + "Maximal stack frame growth due to inlining (in percent).", + 1000, 0, 0) + ++DEFPARAM(PARAM_STACK_CLASH_PROTECTION_GUARD_SIZE, ++ "stack-clash-protection-guard-size", ++ "Size of the stack guard expressed as a power of two.", ++ 12, 12, 30) ++ ++DEFPARAM(PARAM_STACK_CLASH_PROTECTION_PROBE_INTERVAL, ++ "stack-clash-protection-probe-interval", ++ "Interval in which to probe the stack expressed as a power of two.", ++ 12, 10, 16) ++ + /* The GCSE optimization will be disabled if it would require + significantly more memory than this value. */ + DEFPARAM(PARAM_MAX_GCSE_MEMORY, +diff -N -urp a/gcc/reg-notes.def b/gcc/reg-notes.def +--- a/gcc/reg-notes.def 2017-03-28 05:00:35.674561000 +0800 ++++ b/gcc/reg-notes.def 2019-01-10 17:12:11.678531488 +0800 +@@ -223,6 +223,10 @@ REG_NOTE (ARGS_SIZE) + pseudo reg. */ + REG_NOTE (RETURNED) + ++/* Indicates the instruction is a stack check probe that should not ++ be combined with other stack adjustments. */ ++REG_NOTE (STACK_CHECK) ++ + /* Used to mark a call with the function decl called by the call. + The decl might not be available in the call due to splitting of the call + insn. This note is a SYMBOL_REF. */ +diff -N -urp a/gcc/rtl.h b/gcc/rtl.h +--- a/gcc/rtl.h 2017-03-14 20:47:42.745690000 +0800 ++++ b/gcc/rtl.h 2019-01-10 16:59:15.574511058 +0800 +@@ -2707,6 +2707,7 @@ get_full_set_src_cost (rtx x, machine_mo + /* In explow.c */ + extern HOST_WIDE_INT trunc_int_for_mode (HOST_WIDE_INT, machine_mode); + extern rtx plus_constant (machine_mode, rtx, HOST_WIDE_INT, bool = false); ++extern HOST_WIDE_INT get_stack_check_protect (void); + + /* In rtl.c */ + extern rtx rtx_alloc_stat (RTX_CODE MEM_STAT_DECL); +diff -N -urp a/gcc/sched-deps.c b/gcc/sched-deps.c +--- a/gcc/sched-deps.c 2017-01-01 20:07:43.905435000 +0800 ++++ b/gcc/sched-deps.c 2019-01-10 17:13:37.470533746 +0800 +@@ -4717,6 +4717,11 @@ parse_add_or_inc (struct mem_inc_info *m + if (RTX_FRAME_RELATED_P (insn) || !pat) + return false; + ++ /* Do not allow breaking data dependencies for insns that are marked ++ with REG_STACK_CHECK. */ ++ if (find_reg_note (insn, REG_STACK_CHECK, NULL)) ++ return false; ++ + /* Result must be single reg. */ + if (!REG_P (SET_DEST (pat))) + return false; +diff -N -urp a/gcc/target.def b/gcc/target.def +--- a/gcc/target.def 2019-01-10 13:33:20.762185824 +0800 ++++ b/gcc/target.def 2019-01-10 17:01:49.146515100 +0800 +@@ -5490,6 +5490,12 @@ these registers when the target switches + void, (void), + hook_void_void) + ++DEFHOOK ++(stack_clash_protection_final_dynamic_probe, ++ "Some targets make optimistic assumptions about the state of stack probing when they emit their prologues. On such targets a probe into the end of any dynamically allocated space is likely required for safety against stack clash style attacks. Define this variable to return nonzero if such a probe is required or zero otherwise. You need not define this macro if it would always have the value zero.", ++ bool, (rtx residual), ++ default_stack_clash_protection_final_dynamic_probe) ++ + /* Functions specific to the C family of frontends. */ + #undef HOOK_PREFIX + #define HOOK_PREFIX "TARGET_C_" +diff -N -urp a/gcc/targhooks.c b/gcc/targhooks.c +--- a/gcc/targhooks.c 2017-02-07 19:29:06.644837000 +0800 ++++ b/gcc/targhooks.c 2019-01-10 17:03:23.818517592 +0800 +@@ -2107,4 +2107,10 @@ default_excess_precision (enum excess_pr + return FLT_EVAL_METHOD_PROMOTE_TO_FLOAT; + } + ++bool ++default_stack_clash_protection_final_dynamic_probe (rtx residual ATTRIBUTE_UNUSED) ++{ ++ return 0; ++} ++ + #include "gt-targhooks.h" +diff -N -urp a/gcc/targhooks.h b/gcc/targhooks.h +--- a/gcc/targhooks.h 2017-04-05 01:52:27.193766000 +0800 ++++ b/gcc/targhooks.h 2019-01-10 17:04:11.438518846 +0800 +@@ -263,5 +263,6 @@ extern unsigned int default_min_arithmet + + extern enum flt_eval_method + default_excess_precision (enum excess_precision_type ATTRIBUTE_UNUSED); ++extern bool default_stack_clash_protection_final_dynamic_probe (rtx); + + #endif /* GCC_TARGHOOKS_H */ +diff -N -urp a/gcc/toplev.c b/gcc/toplev.c +--- a/gcc/toplev.c 2017-09-15 16:18:34.015147000 +0800 ++++ b/gcc/toplev.c 2019-01-10 16:45:33.626489420 +0800 +@@ -1573,6 +1573,26 @@ process_options (void) + flag_associative_math = 0; + } + ++ /* -fstack-clash-protection is not currently supported on targets ++ where the stack grows up. */ ++ if (flag_stack_clash_protection && !STACK_GROWS_DOWNWARD) ++ { ++ warning_at (UNKNOWN_LOCATION, 0, ++ "%<-fstack-clash-protection%> is not supported on targets " ++ "where the stack grows from lower to higher addresses"); ++ flag_stack_clash_protection = 0; ++ } ++ ++ /* We can not support -fstack-check= and -fstack-clash-protection at ++ the same time. */ ++ if (flag_stack_check != NO_STACK_CHECK && flag_stack_clash_protection) ++ { ++ warning_at (UNKNOWN_LOCATION, 0, ++ "%<-fstack-check=%> and %<-fstack-clash_protection%> are " ++ "mutually exclusive. Disabling %<-fstack-check=%>"); ++ flag_stack_check = NO_STACK_CHECK; ++ } ++ + /* With -fcx-limited-range, we do cheap and quick complex arithmetic. */ + if (flag_cx_limited_range) + flag_complex_method = 0; diff --git a/gcc-7.3.0.tar.gz b/gcc-7.3.0.tar.gz new file mode 100644 index 0000000..342d66a Binary files /dev/null and b/gcc-7.3.0.tar.gz differ diff --git a/gcc-adapt-to-isl.patch b/gcc-adapt-to-isl.patch new file mode 100644 index 0000000..b82e068 --- /dev/null +++ b/gcc-adapt-to-isl.patch @@ -0,0 +1,12 @@ +diff --git a/gcc/graphite.h b/gcc/graphite.h +index 4e0e58c..be0a22b 100644 (file) +--- a/gcc/graphite.h ++++ b/gcc/graphite.h +@@ -37,6 +37,8 @@ along with GCC; see the file COPYING3. If not see + #include + #include + #include ++#include ++#include + + typedef struct poly_dr *poly_dr_p; diff --git a/gcc.spec b/gcc.spec new file mode 100644 index 0000000..f8796b4 --- /dev/null +++ b/gcc.spec @@ -0,0 +1,3352 @@ +%global DATE 20190804 +%define debug_package %{nil} + +%global gcc_version 7.3.0 +%global gcc_release 20190804 +%global isl_version 0.14 +%global cloog_version 0.18.4 + +%define compat_gcc_provides 7777777 + +%global _unpackaged_files_terminate_build 0 +%undefine _annotated_build + +%global gcc_target_platform %{_arch}-linux-gnu + +%global build_ada 0 +%global build_java 0 +%global build_go 0 +%ifarch aarch64 +%global build_libquadmath 0 +%endif +%ifarch x86_64 +%global build_libquadmath 1 +%endif +%global build_libasan 1 +%global build_libatomic 1 +%global build_libitm 1 +%global attr_ifunc 1 +%global build_cloog 1 +%global build_libstdcxx_docs 0 +%global build_java_tar 0 +%global build_libtsan 1 +%global build_libilp32 0 +%global build_check 0 + +Summary: Various compilers (C, C++, Objective-C, Java, ...) +Name: gcc +Version: 7.3.0 +Release: %{gcc_release}.h30 +License: GPLv3+ and GPLv3+ with exceptions and GPLv2+ with exceptions and LGPLv2+ and BSD +Group: Development/Languages +#Source0: hcc-aarch64-linux-release.tar.bz2 +Source0: gcc-%{version}.tar.gz +Source1: isl-%{isl_version}.tar.xz +Source2: cloog-%{cloog_version}.tar.gz +BuildRoot: %{_tmppath}/%{name}-%{version}-%{release}-root-%(%{__id_u} -n) +BuildRequires: gmp libmpc-devel mpfr gmp-devel glibc-headers gcc-c++ mpfr-devel +#BuildRequires: gmp mpfr gmp-devel glibc-headers gcc-c++ mpfr-devel mpc +%ifarch aarch64 +%if %{build_libilp32} +BuildRequires: glibc-32-headers +%endif +%endif + +Requires: cpp = %{version}-%{release} +Requires: binutils >= 2.20.51.0.2-12 +Requires: glibc-devel >= 2.2.90-12 +Requires: glibc >= 2.16 +Requires: libgcc >= %{version}-%{release} +Requires: libgomp = %{version}-%{release} +Provides: bundled(libiberty) +Provides: gcc = %{compat_gcc_provides} +Provides: gcc(major) = 7.3.0 +BuildRequires: libtool zlib-devel texinfo + +Patch1: fix-operand-size-mismatch-for-i386-sse.patch +Patch2: gcc-adapt-to-isl.patch +Patch3: sanitizer-pr-85835.patch +Patch4: CVE-2018-12886.patch +Patch5: CVE-2019-15847.patch +Patch6: option-mlong-calls.patch +Patch7: add-tsv110-pipeline-scheduling.patch +Patch8: option-mfentry-and-mlong-calls-bugfix.patch +Patch10: aarch64-ilp32-call-addr-dimode.patch +Patch12: aarch64-fix-tls-negative-offset.patch +Patch14: arm-fix-push-minipool.patch +Patch22: arm-bigendian-disable-interleaved-LS-vectorize.patch +Patch23: floop-unroll-and-jam.patch +Patch24: floop-interchange.patch +Patch25: constructor-priority-bugfix.patch +Patch26: arm-adjust-be-ldrd-strd.patch +Patch28: try-unroll.patch +Patch29: Big-endian-union-bitfield-bugfix.patch +Patch31: fstack-clash-protection.patch +Patch34: mark-pattern-as-clobbering-CC-REGNUM.patch +Patch35: turn-on-funwind-tables-by-default.patch + + +#AutoReqProv: off +AutoReq: true + + +%package -n libgcc +Summary: GCC version 7.3.0 shared support library +Group: System Environment/Libraries +Autoreq: false +Provides: libgcc = %{compat_gcc_provides} + +%description -n libgcc +This package contains GCC shared support library which is needed +e.g. for exception handling support. + +%ifarch aarch64 +%if %{build_libilp32} +%package -n libgcc-32 +Summary: GCC version 7.3.0 shared support library +Group: System Environment/Libraries +Autoreq: false +Provides: libgcc = %{compat_gcc_provides} + +%description -n libgcc-32 +This package contains GCC shared support library which is needed +e.g. for exception handling support. +%endif +%endif + +%package c++ +Summary: C++ support for GCC +Group: Development/Languages +Requires: gcc = %{version}-%{release} +Requires: libstdc++ = %{version}-%{release} +Requires: libstdc++-devel = %{version}-%{release} +Autoreq: true +Provides: gcc-c++ = %{compat_gcc_provides} + +%description c++ +This package adds C++ support to the GNU Compiler Collection. +It includes support for most of the current C++ specification, +including templates and exception handling. + +%package -n libstdc++ +Summary: GNU Standard C++ Library +Group: System Environment/Libraries +Autoreq: true +Requires: glibc >= 2.10.90-7 +Provides: libstdc++ = %{compat_gcc_provides} + +%description -n libstdc++ +The libstdc++ package contains a rewritten standard compliant GCC Standard +C++ Library. + +%package -n libstdc++-devel +Summary: Header files and libraries for C++ development +Group: Development/Libraries +Requires: libstdc++%{?_isa} = %{version}-%{release} +Autoreq: true +Provides: libstdc++-devel = %{compat_gcc_provides} + +%description -n libstdc++-devel +This is the GNU implementation of the standard C++ libraries. This +package includes the header files and libraries needed for C++ +development. This includes rewritten implementation of STL. + +%package -n libstdc++-static +Summary: Static libraries for the GNU standard C++ library +Group: Development/Libraries +Requires: libstdc++-devel = %{version}-%{release} +Autoreq: true +Provides: libstdc++-static = %{compat_gcc_provides} + +%description -n libstdc++-static +Static libraries for the GNU standard C++ library. + +%ifarch aarch64 +%if %{build_libilp32} +%package -n libstdc++-32 +Summary: GNU Standard C++ Library +Group: System Environment/Libraries +Autoreq: true +Requires: glibc >= 2.10.90-7 +Provides: libstdc++ = %{compat_gcc_provides} + +%description -n libstdc++-32 +The libstdc++ package contains a rewritten standard compliant GCC Standard +C++ Library. +%endif +%endif + +%package objc +Summary: Objective-C support for GCC +Group: Development/Languages +Requires: gcc = %{version}-%{release} +Requires: libobjc = %{version}-%{release} +Autoreq: true +Provides: gcc-objc = %{compat_gcc_provides} + +%description objc +gcc-objc provides Objective-C support for the GCC. +Mainly used on systems running NeXTSTEP, Objective-C is an +object-oriented derivative of the C language. + +%package objc++ +Summary: Objective-C++ support for GCC +Group: Development/Languages +Requires: gcc-c++ = %{version}-%{release}, gcc-objc = %{version}-%{release} +Autoreq: true +Provides: gcc-objc++ = %{compat_gcc_provides} + +%description objc++ +gcc-objc++ package provides Objective-C++ support for the GCC. + +%package -n libobjc +Summary: Objective-C runtime +Group: System Environment/Libraries +Autoreq: true +Provides: libobjc = %{compat_gcc_provides} + +%description -n libobjc +This package contains Objective-C shared library which is needed to run +Objective-C dynamically linked programs. + +%ifarch aarch64 +%if %{build_libilp32} +%package -n libobjc-32 +Summary: Objective-C runtime +Group: System Environment/Libraries +Autoreq: true +Provides: libobjc = %{compat_gcc_provides} + +%description -n libobjc-32 +This package contains Objective-C shared library which is needed to run +Objective-C dynamically linked programs. +%endif +%endif + +%package -n libitm +Summary: The GNU Transactional Memory library +Group: System Environment/Libraries +Requires(post): /sbin/install-info +Requires(preun): /sbin/install-info + +%description -n libitm +This package contains the GNU Transactional Memory library +which is a GCC transactional memory support runtime library. + +%package -n libitm-devel +Summary: The GNU Transactional Memory support +Group: Development/Libraries +Requires: libitm = %{version}-%{release} +Requires: gcc = %{version}-%{release} + +%description -n libitm-devel +This package contains headers and support files for the +GNU Transactional Memory library. + +%package -n libitm-static +Summary: The GNU Transactional Memory static library +Group: Development/Libraries +Requires: libitm-devel = %{version}-%{release} + +%description -n libitm-static +This package contains GNU Transactional Memory static libraries. + +%package -n libatomic +Summary: The GNU Atomic library +Group: System Environment/Libraries +Requires(post): /sbin/install-info +Requires(preun): /sbin/install-info + +%description -n libatomic +This package contains the GNU Atomic library +which is a GCC support runtime library for atomic operations not supported +by hardware. + +%package -n libatomic-static +Summary: The GNU Atomic static library +Group: Development/Libraries +Requires: libatomic = %{version}-%{release} + +%description -n libatomic-static +This package contains GNU Atomic static libraries. + +%package -n libasan +Summary: The Address Sanitizer runtime library +Group: System Environment/Libraries +Requires(post): /sbin/install-info +Requires(preun): /sbin/install-info + +%description -n libasan +This package contains the Address Sanitizer library +which is used for -fsanitize=address instrumented programs. + +%package -n libasan-static +Summary: The Address Sanitizer static library +Group: Development/Libraries +Requires: libasan = %{version}-%{release} + +%description -n libasan-static +This package contains Address Sanitizer static runtime library. + +%package -n libtsan +Summary: The Thread Sanitizer runtime library +Group: System Environment/Libraries +Requires(post): /sbin/install-info +Requires(preun): /sbin/install-info + +%description -n libtsan +This package contains the Thread Sanitizer library +which is used for -fsanitize=thread instrumented programs. + +%package -n libtsan-static +Summary: The Thread Sanitizer static library +Group: Development/Libraries +Requires: libtsan = %{version}-%{release} + +%description -n libtsan-static +This package contains Thread Sanitizer static runtime library. + +%package plugin-devel +Summary: Support for compiling GCC plugins +Group: Development/Languages +Requires: gcc = %{version}-%{release} +Requires: gmp-devel >= 4.1.2-8, mpfr-devel >= 2.2.1, libmpc-devel >= 0.8.1 + +%description plugin-devel +This package contains header files and other support files +for compiling GCC plugins. The GCC plugin ABI is currently +not stable, so plugins must be rebuilt any time GCC is updated. + +%package gfortran +Summary: Fortran support +Group: Development/Languages +Requires: gcc = %{version}-%{release} +Requires: libgfortran = %{version}-%{release} +BuildRequires: gmp-devel >= 4.1.2-8, mpfr-devel >= 2.2.1, libmpc-devel >= 0.8.1 +%if %{build_libquadmath} +Requires: libquadmath = %{version}-%{release} +Requires: libquadmath-devel = %{version}-%{release} +%endif +Requires(post): /sbin/install-info +Requires(preun): /sbin/install-info +Autoreq: true +Provides: gcc-gfortran = %{compat_gcc_provides} + +%description gfortran +The gcc-gfortran package provides support for compiling Fortran +programs with the GNU Compiler Collection. + +%package -n libgfortran +Summary: Fortran runtime +Group: System Environment/Libraries +Autoreq: true +Provides: libgfortran = %{compat_gcc_provides} +%if %{build_libquadmath} +Requires: libquadmath = %{version}-%{release} +%endif + +%description -n libgfortran +This package contains Fortran shared library which is needed to run +Fortran dynamically linked programs. + +%package -n libgomp +Summary: GCC OpenMP v3.0 shared support library +Group: System Environment/Libraries +Requires(post): /sbin/install-info +Requires(preun): /sbin/install-info +Provides: libgomp = %{compat_gcc_provides} + +%description -n libgomp +This package contains GCC shared support library which is needed +for OpenMP v3.0 support. + +%ifarch aarch64 +%if %{build_libilp32} +%package -n libgfortran-32 +Summary: Fortran runtime +Group: System Environment/Libraries +Autoreq: true +Provides: libgfortran = %{compat_gcc_provides} + +%description -n libgfortran-32 +This package contains Fortran shared library which is needed to run +Fortran dynamically linked programs. + +%package -n libgomp-32 +Summary: GCC OpenMP v3.0 shared support library +Group: System Environment/Libraries +Requires(post): /sbin/install-info +Requires(preun): /sbin/install-info +Provides: libgomp = %{compat_gcc_provides} + +%description -n libgomp-32 +This package contains GCC shared support library which is needed +for OpenMP v3.0 support. +%endif +%endif + +%package -n cpp +Summary: The C Preprocessor +Group: Development/Languages +Requires: filesystem >= 3 +Provides: /lib/cpp +Requires(post): /sbin/install-info +Requires(preun): /sbin/install-info +Autoreq: true +Provides: cpp = %{compat_gcc_provides} + +%description -n cpp +Cpp is the GNU C-Compatible Compiler Preprocessor. +Cpp is a macro processor which is used automatically +by the C compiler to transform your program before actual +compilation. It is called a macro processor because it allows +you to define macros, abbreviations for longer +constructs. + + +The C preprocessor provides four separate functionalities: the +inclusion of header files (files of declarations that can be +substituted into your program); macro expansion (you can define macros, +and the C preprocessor will replace the macros with their definitions +throughout the program); conditional compilation (using special +preprocessing directives, you can include or exclude parts of the +program according to various conditions); and line control (if you use +a program to combine or rearrange source files into an intermediate +file which is then compiled, you can use line control to inform the +compiler about where each source line originated). + +You should install this package if you are a C programmer and you use +macros. + +%description +This is compiler for arm64. +%ifarch x86_64 +%package -n libquadmath +Summary: GCC __float128 shared support library +Group: System Environment/Libraries +Requires(post): /sbin/install-info +Requires(preun): /sbin/install-info + +%description -n libquadmath +This package contains GCC shared support library which is needed +for __float128 math support and for Fortran REAL*16 support. + +%package -n libquadmath-devel +Summary: GCC __float128 support +Group: Development/Libraries +Requires: libquadmath = %{version}-%{release} +Requires: gcc = %{version}-%{release} + +%description -n libquadmath-devel +This package contains headers for building Fortran programs using +REAL*16 and programs using __float128 math. + +%package -n libquadmath-static +Summary: Static libraries for __float128 support +Group: Development/Libraries +Requires: libquadmath-devel = %{version}-%{release} + +%description -n libquadmath-static +This package contains static libraries for building Fortran programs +using REAL*16 and programs using __float128 math. + +%endif + +%if 0%{?_enable_debug_packages} +%define debug_package %{nil} +%global __debug_package 1 +%global __debug_install_post \ + %{_rpmconfigdir}/find-debuginfo.sh %{?_missing_build_ids_terminate_build:--strict-build-id} %{?_find_debuginfo_opts} "%{_builddir}/gcc-%{version}"\ + %{_builddir}/gcc-%{version}/split-debuginfo.sh\ +%{nil} +%package debuginfo +Summary: Debug information for package %{name} +Group: Development/Debug +AutoReqProv: 0 +Requires: gcc-base-debuginfo = %{version}-%{release} +%description debuginfo +This package provides debug information for package %{name}. +Debug information is useful when developing applications that use this +package or when debugging this package. +%files debuginfo -f debugfiles.list +%defattr(-,root,root) +%package base-debuginfo +Summary: Debug information for libraries from package %{name} +Group: Development/Debug +AutoReqProv: 0 +%description base-debuginfo +This package provides debug information for libgcc_s, libgomp and +libstdc++ libraries from package %{name}. +Debug information is useful when developing applications that use this +package or when debugging this package. +%files base-debuginfo -f debugfiles-base.list +%defattr(-,root,root) +%endif +%prep +%setup -q -n gcc-%{version} -a 1 -a 2 +/bin/pwd + + +%patch1 -p1 +%patch2 -p1 +%patch3 -p1 +%patch4 -p1 +%patch5 -p1 +%patch6 -p1 +%patch7 -p1 +%patch8 -p1 +%patch10 -p1 +%patch12 -p1 +%patch14 -p1 +%patch22 -p1 +%patch23 -p1 +%patch24 -p1 +%patch25 -p1 +%patch26 -p1 +%patch28 -p1 +%patch29 -p1 +%patch31 -p1 +%patch34 -p1 +%patch35 -p1 + +%if 0%{?_enable_debug_packages} +cat > split-debuginfo.sh <<\EOF +#!/bin/sh +BUILDDIR="%{_builddir}/gcc-%{version}" +if [ -f "${BUILDDIR}"/debugfiles.list \ + -a -f "${BUILDDIR}"/debuglinks.list ]; then + > "${BUILDDIR}"/debugsources-base.list + > "${BUILDDIR}"/debugfiles-base.list + cd "${RPM_BUILD_ROOT}" + for f in `find usr/lib/debug -name \*.debug \ + | egrep 'lib[0-9]*/lib(gcc|gomp|stdc|quadmath|itm)'`; do + echo "/$f" >> "${BUILDDIR}"/debugfiles-base.list + if [ -f "$f" -a ! -L "$f" ]; then + cp -a "$f" "${BUILDDIR}"/test.debug + /usr/lib/rpm/debugedit -b "${RPM_BUILD_DIR}" -d /usr/src/debug \ + -l "${BUILDDIR}"/debugsources-base.list \ + "${BUILDDIR}"/test.debug + rm -f "${BUILDDIR}"/test.debug + fi + done + for f in `find usr/lib/debug/.build-id -type l`; do + ls -l "$f" | egrep -q -- '->.*lib[0-9]*/lib(gcc|gomp|stdc|quadmath|itm)' \ + && echo "/$f" >> "${BUILDDIR}"/debugfiles-base.list + done + grep -v -f "${BUILDDIR}"/debugfiles-base.list \ + "${BUILDDIR}"/debugfiles.list > "${BUILDDIR}"/debugfiles.list.new + mv -f "${BUILDDIR}"/debugfiles.list.new "${BUILDDIR}"/debugfiles.list + for f in `LC_ALL=C sort -z -u "${BUILDDIR}"/debugsources-base.list \ + | grep -E -v -z '(|)$' \ + | xargs --no-run-if-empty -n 1 -0 echo \ + | sed 's,^,usr/src/debug/,'`; do + if [ -f "$f" ]; then + echo "/$f" >> "${BUILDDIR}"/debugfiles-base.list + echo "%%exclude /$f" >> "${BUILDDIR}"/debugfiles.list + fi + done + mv -f "${BUILDDIR}"/debugfiles-base.list{,.old} + echo "%%dir /usr/lib/debug" > "${BUILDDIR}"/debugfiles-base.list + awk 'BEGIN{FS="/"}(NF>4&&$NF){d="%%dir /"$2"/"$3"/"$4;for(i=5;i> "${BUILDDIR}"/debugfiles-base.list + cat "${BUILDDIR}"/debugfiles-base.list.old >> "${BUILDDIR}"/debugfiles-base.list + rm -f "${BUILDDIR}"/debugfiles-base.list.old +fi +EOF +chmod 755 split-debuginfo.sh +%endif + + + +%build + +%ifarch aarch64_ilp32 +optflags=`echo ${optflags}|sed -e 's/-mabi=ilp32//g'` +optflags=`echo ${optflags}|sed -e 's/-Werror=format-security/ /g'` +CFLAGS='-O2 -g' +%endif +%ifarch x86_64 +%global optflags `echo %{optflags}|sed -e 's/-fcf-protection//g'` +%endif +# Undo the broken autoconf change in recent Fedora versions +export CONFIG_SITE=NONE +%if %{build_java} +export GCJ_PROPERTIES=jdt.compiler.useSingleThread=true +# gjar isn't usable, so even when GCC source tree no longer includes +# fastjar, build it anyway. +mkdir fastjar-%{fastjar_ver}/obj-%{gcc_target_platform} +cd fastjar-%{fastjar_ver}/obj-%{gcc_target_platform} +../configure CFLAGS="%{optflags}" --prefix=%{_prefix} --mandir=%{_mandir} --infodir=%{_infodir} +make -j100 +export PATH=`pwd`${PATH:+:$PATH} +cd ../../ +%endif + +rm -fr obj-%{gcc_target_platform} +mkdir obj-%{gcc_target_platform} +cd obj-%{gcc_target_platform} + +%if %{build_java} +%if !%{bootstrap_java} +# If we don't have gjavah in $PATH, try to build it with the old gij +mkdir java_hacks +cd java_hacks +cp -a ../../libjava/classpath/tools/external external +mkdir -p gnu/classpath/tools +cp -a ../../libjava/classpath/tools/gnu/classpath/tools/{common,javah,getopt} gnu/classpath/tools/ +cp -a ../../libjava/classpath/tools/resource/gnu/classpath/tools/common/messages.properties gnu/classpath/tools/common +cp -a ../../libjava/classpath/tools/resource/gnu/classpath/tools/getopt/messages.properties gnu/classpath/tools/getopt +cd external/asm; for i in `find . -name \*.java`; do gcj --encoding ISO-8859-1 -C $i -I.; done; cd ../.. +for i in `find gnu -name \*.java`; do gcj -C $i -I. -Iexternal/asm/; done +gcj -findirect-dispatch -O2 -fmain=gnu.classpath.tools.javah.Main -I. -Iexternal/asm/ `find . -name \*.class` -o gjavah.real +cat > gjavah < ecj1 <> ../../cloog-%{cloog_version}/source/isl/constraints.c << \EOF +#include +static void __attribute__((used)) *s1 = (void *) isl_union_map_compute_flow; +static void __attribute__((used)) *s2 = (void *) isl_map_dump; +EOF +cd ../../cloog-%{cloog_version} +./autogen.sh +cd - + +../../cloog-%{cloog_version}/configure --with-isl=system \ + --with-isl-prefix=`cd ../isl-install; pwd` \ + CC=/usr/bin/gcc CXX=/usr/bin/g++ \ + CFLAGS="${CFLAGS:-%optflags}" CXXFLAGS="${CXXFLAGS:-%optflags}" \ + --prefix=`cd ..; pwd`/cloog-install +sed -i 's|^hardcode_libdir_flag_spec=.*|hardcode_libdir_flag_spec=""|g' libtool +sed -i 's|^runpath_var=LD_RUN_PATH|runpath_var=DIE_RPATH_DIE|g' libtool +make -j100 +make -j100 install +cd ../cloog-install/lib +ln -sf libcloog-isl.so.4 libcloog-isl.so +ln -sf libcloog-isl.so.4 libcloog.so +cd ../.. + +#test don't build +%if 1 +CC=gcc +OPT_FLAGS=`echo %{optflags}|sed -e 's/\(-Wp,\)\?-D_FORTIFY_SOURCE=[12]//g'` +OPT_FLAGS=`echo $OPT_FLAGS|sed -e 's/-m64//g;s/-m32//g;s/-m31//g'` +OPT_FLAGS=`echo $OPT_FLAGS|sed -e 's/-mfpmath=sse/-mfpmath=sse -msse2/g'` +OPT_FLAGS=`echo $OPT_FLAGS|sed -e 's/-Werror=format-security/ /g'` +OPT_FLAGS=`echo $OPT_FLAGS|sed -e 's/ -pipe / /g'` +%ifarch sparc +OPT_FLAGS=`echo $OPT_FLAGS|sed -e 's/-mcpu=ultrasparc/-mtune=ultrasparc/g;s/-mcpu=v[78]//g'` +%endif +%ifarch %{ix86} +OPT_FLAGS=`echo $OPT_FLAGS|sed -e 's/-march=i.86//g'` +%endif +%ifarch sparc64 +cat > gcc64 <<"EOF" +#!/bin/sh +exec /usr/bin/gcc -m64 "$@" +EOF +chmod +x gcc64 +CC=`pwd`/gcc64 +%endif +%ifarch ppc64 ppc64le ppc64p7 +if gcc -m64 -xc -S /dev/null -o - > /dev/null 2>&1; then + cat > gcc64 <<"EOF" +#!/bin/sh +exec /usr/bin/gcc -m64 "$@" +EOF + chmod +x gcc64 + CC=`pwd`/gcc64 +fi +%endif +%ifarch aarch64_ilp32 +OPT_FLAGS=`echo $OPT_FLAGS|sed -e 's/-mabi=ilp32//g'` +%endif +OPT_FLAGS=`echo "$OPT_FLAGS" | sed -e 's/[[:blank:]]\+/ /g'` +case "$OPT_FLAGS" in + *-fasynchronous-unwind-tables*) + sed -i -e 's/-fno-exceptions /-fno-exceptions -fno-asynchronous-unwind-tables/' \ + ../gcc/Makefile.in + ;; +esac +enablelgo= +enablelada= +%if %{build_ada} +enablelada=,ada +%endif +%if %{build_go} +enablelgo=,go +%endif +OPT_FLAGS="$OPT_FLAGS -fPIE -Wl,-z,relro,-z,now" +OPT_LDFLAGS="$OPT_LDFLAGS -Wl,-z,relro,-z,now" +export extra_ldflags_libobjc="-Wl,-z,relro,-z,now" +export FCFLAGS="$OPT_FLAGS" +CC="$CC" CFLAGS="$OPT_FLAGS" \ + CXXFLAGS="`echo " $OPT_FLAGS " | sed 's/ -Wall / /g;s/ -fexceptions / /g' \ + | sed 's/ -Werror=format-security //'`" \ + LDFLAGS="$OPT_LDFLAGS" \ + CFLAGS_FOR_TARGET="$OPT_FLAGS" \ + CXXFLAGS_FOR_TARGET="$OPT_FLAGS" \ + XCFLAGS="$OPT_FLAGS" TCFLAGS="$OPT_FLAGS" GCJFLAGS="$OPT_FLAGS" \ + ../configure --prefix=%{_prefix} --mandir=%{_mandir} --infodir=%{_infodir} \ + --enable-shared --enable-threads=posix --enable-checking=release \ + --with-system-zlib --enable-__cxa_atexit --disable-libunwind-exceptions \ + --enable-gnu-unique-object --enable-linker-build-id --with-linker-hash-style=gnu \ + --enable-languages=c,c++,objc,obj-c++,fortran,lto --enable-plugin \ + --enable-initfini-array --disable-libgcj --without-isl --without-cloog \ + --enable-gnu-indirect-function --build=%{gcc_target_platform} \ + --with-stage1-ldflags="$OPT_LDFLAGS" \ + --with-boot-ldflags="$OPT_LDFLAGS" \ +%ifarch x86_64 + --with-tune=generic \ + --with-arch_32=x86-64 \ + --disable-multilib +%endif +%ifarch aarch64 +%if %{build_libilp32} + --with-multilib-list=lp64,ilp32 +%else + --with-multilib-list=lp64 +%endif +%endif + +%ifarch %{arm} sparc sparcv9 sparc64 +GCJFLAGS="$OPT_FLAGS" make -j BOOT_CFLAGS="$OPT_FLAGS" bootstrap +%else +#GCJFLAGS="$OPT_FLAGS" make -j BOOT_CFLAGS="$OPT_FLAGS" profiledbootstrap +GCJFLAGS="$OPT_FLAGS" make -j BOOT_CFLAGS="$OPT_FLAGS" BOOT_LDFLAGS="-pie -Wl,-z,relro,-z,now" +%endif +#test don't build +%endif +%if %{build_cloog} +cp -a cloog-install/lib/libcloog-isl.so.4 gcc/ +%endif + +# Make generated man pages even if Pod::Man is not new enough +perl -pi -e 's/head3/head2/' ../contrib/texi2pod.pl +for i in ../gcc/doc/*.texi; do + cp -a $i $i.orig; sed 's/ftable/table/' $i.orig > $i +done +make -j100 -C gcc generated-manpages +for i in ../gcc/doc/*.texi; do mv -f $i.orig $i; done + +# Make generated doxygen pages. +%if %{build_libstdcxx_docs} +cd %{gcc_target_platform}/libstdc++-v3 +make doc-html-doxygen +make doc-man-doxygen +cd ../.. +%endif + +# Copy various doc files here and there +cd .. +mkdir -p rpm.doc/gfortran +mkdir -p rpm.doc/objc +mkdir -p rpm.doc/boehm-gc rpm.doc/fastjar rpm.doc/libffi rpm.doc/libjava +mkdir -p rpm.doc/go rpm.doc/libgo rpm.doc/libquadmath rpm.doc/libitm +#mkdir -p rpm.doc/changelogs/{gcc/cp,gcc/java,gcc/ada,libstdc++-v3,libobjc,libmudflap,libgomp,libatomic,libsanitizer} +mkdir -p rpm.doc/changelogs/{gcc/cp,gcc/java,gcc/ada,libstdc++-v3,libobjc,libgomp,libatomic,libsanitizer} +%if 0 +#for i in {gcc,gcc/cp,gcc/java,gcc/ada,libstdc++-v3,libobjc,libmudflap,libgomp,libatomic,libsanitizer}/ChangeLog*; do +for i in {gcc,gcc/cp,gcc/java,gcc/ada,libstdc++-v3,libobjc,libgomp,libatomic,libsanitizer}/ChangeLog*; do + cp -p $i rpm.doc/changelogs/$i +done + +(cd gcc/fortran; for i in ChangeLog*; do + cp -p $i ../../rpm.doc/gfortran/$i +done) +(cd libgfortran; for i in ChangeLog*; do + cp -p $i ../rpm.doc/gfortran/$i.libgfortran +done) +(cd libobjc; for i in README*; do + cp -p $i ../rpm.doc/objc/$i.libobjc +done) +(cd boehm-gc; for i in ChangeLog*; do + cp -p $i ../rpm.doc/boehm-gc/$i.gc +done) + +(cd fastjar-%{fastjar_ver}; for i in ChangeLog* README*; do + cp -p $i ../rpm.doc/fastjar/$i.fastjar +done) +(cd libffi; for i in ChangeLog* README* LICENSE; do + cp -p $i ../rpm.doc/libffi/$i.libffi +done) +(cd libjava; for i in ChangeLog* README*; do + cp -p $i ../rpm.doc/libjava/$i.libjava +done) +cp -p libjava/LIBGCJ_LICENSE rpm.doc/libjava/ +%if %{build_libquadmath} +(cd libquadmath; for i in ChangeLog* COPYING.LIB; do + cp -p $i ../rpm.doc/libquadmath/$i.libquadmath +done) +%endif +%if %{build_libitm} +(cd libitm; for i in ChangeLog*; do + cp -p $i ../rpm.doc/libitm/$i.libitm +done) +%endif +%if %{build_go} +(cd gcc/go; for i in README* ChangeLog*; do + cp -p $i ../../rpm.doc/go/$i +done) +(cd libgo; for i in LICENSE* PATENTS* README; do + cp -p $i ../rpm.doc/libgo/$i.libgo +done) +%endif + +rm -f rpm.doc/changelogs/gcc/ChangeLog.[1-9] +find rpm.doc -name \*ChangeLog\* | xargs bzip2 -9 +%endif + +%if %{build_java_tar} +find libjava -name \*.h -type f | xargs grep -l '// DO NOT EDIT THIS FILE - it is machine generated' > libjava-classes.list +find libjava -name \*.class -type f >> libjava-classes.list +find libjava/testsuite -name \*.jar -type f >> libjava-classes.list +tar cf - -T libjava-classes.list | bzip2 -9 > $RPM_SOURCE_DIR/libjava-classes-%{version}-%{release}.tar.bz2 +%endif + +%install +rm -fr %{buildroot} + +cd obj-%{gcc_target_platform} + +%if %{build_java} +export GCJ_PROPERTIES=jdt.compiler.useSingleThread=true +export PATH=`pwd`/../fastjar-%{fastjar_ver}/obj-%{gcc_target_platform}${PATH:+:$PATH} +%if !%{bootstrap_java} +export PATH=`pwd`/java_hacks${PATH:+:$PATH} +%endif +%endif + +TARGET_PLATFORM=%{gcc_target_platform} + +# There are some MP bugs in libstdc++ Makefiles +make -j100 -C %{gcc_target_platform}/libstdc++-v3 + +make -j100 prefix=%{buildroot}%{_prefix} mandir=%{buildroot}%{_mandir} \ + infodir=%{buildroot}%{_infodir} install +%if %{build_java} +make -j100 DESTDIR=%{buildroot} -C %{gcc_target_platform}/libjava install-src.zip +%endif +%if %{build_ada} +chmod 644 %{buildroot}%{_infodir}/gnat* +%endif + +%ifarch aarch64_ilp32 +FULLPATH=%{buildroot}%{_prefix}/lib/gcc/%{gcc_target_platform}/%{version}/ilp32 +FULLEPATH=%{buildroot}%{_prefix}/libexec/gcc/%{gcc_target_platform}/%{version}/ilp32 +%else +FULLPATH=%{buildroot}%{_prefix}/lib/gcc/%{gcc_target_platform}/%{version} +FULLEPATH=%{buildroot}%{_prefix}/libexec/gcc/%{gcc_target_platform}/%{version} +%endif +FULLHPATH=%{buildroot}%{_prefix}/lib/gcc/%{gcc_target_platform}/%{version} + +%if %{build_cloog} +cp -a cloog-install/lib/libcloog-isl.so.4 $FULLPATH/ +%endif + +# fix some things +ln -sf gcc %{buildroot}%{_prefix}/bin/cc +rm -f %{buildroot}%{_prefix}/lib/cpp +ln -sf ../bin/cpp %{buildroot}/%{_prefix}/lib/cpp +ln -sf gfortran %{buildroot}%{_prefix}/bin/f95 +rm -f %{buildroot}%{_infodir}/dir +gzip -9 %{buildroot}%{_infodir}/*.info* +ln -sf gcc %{buildroot}%{_prefix}/bin/gnatgcc + +cxxconfig="`find %{gcc_target_platform}/libstdc++-v3/include -name c++config.h`" +for i in `find %{gcc_target_platform}/[36]*/libstdc++-v3/include -name c++config.h 2>/dev/null`; do + if ! diff -up $cxxconfig $i; then + cat > %{buildroot}%{_prefix}/include/c++/%{version}/%{gcc_target_platform}/bits/c++config.h < +#if __WORDSIZE == 32 +%ifarch %{multilib_64_archs} +`cat $(find %{gcc_target_platform}/32/libstdc++-v3/include -name c++config.h)` +%else +`cat $(find %{gcc_target_platform}/libstdc++-v3/include -name c++config.h)` +%endif +#else +%ifarch %{multilib_64_archs} +`cat $(find %{gcc_target_platform}/libstdc++-v3/include -name c++config.h)` +%else +`cat $(find %{gcc_target_platform}/64/libstdc++-v3/include -name c++config.h)` +%endif +#endif +#endif +EOF + break + fi +done + +for f in `find %{buildroot}%{_prefix}/include/c++/%{version}/%{gcc_target_platform}/ -name c++config.h`; do + for i in 1 2 4 8; do + sed -i -e 's/#define _GLIBCXX_ATOMIC_BUILTINS_'$i' 1/#ifdef __GCC_HAVE_SYNC_COMPARE_AND_SWAP_'$i'\ +&\ +#endif/' $f + done +done + +# Nuke bits/*.h.gch dirs +# 1) there is no bits/*.h header installed, so when gch file can't be +# used, compilation fails +# 2) sometimes it is hard to match the exact options used for building +# libstdc++-v3 or they aren't desirable +# 3) there are multilib issues, conflicts etc. with this +# 4) it is huge +# People can always precompile on their own whatever they want, but +# shipping this for everybody is unnecessary. +rm -rf %{buildroot}%{_prefix}/include/c++/%{version}/%{gcc_target_platform}/bits/*.h.gch + +%if %{build_libstdcxx_docs} +libstdcxx_doc_builddir=%{gcc_target_platform}/libstdc++-v3/doc/doxygen +mkdir -p ../rpm.doc/libstdc++-v3 +cp -r -p ../libstdc++-v3/doc/html ../rpm.doc/libstdc++-v3/html +cp -r -p $libstdcxx_doc_builddir/html ../rpm.doc/libstdc++-v3/html/api +mkdir -p %{buildroot}%{_mandir}/man3 +cp -r -p $libstdcxx_doc_builddir/man/man3/* %{buildroot}%{_mandir}/man3/ +find ../rpm.doc/libstdc++-v3 -name \*~ | xargs rm +%endif + +%ifarch sparcv9 sparc64 +ln -f %{buildroot}%{_prefix}/bin/%{gcc_target_platform}-gcc \ + %{buildroot}%{_prefix}/bin/sparc-%{_vendor}-%{_target_os}-gcc +%endif +%ifarch ppc ppc64 ppc64p7 +ln -f %{buildroot}%{_prefix}/bin/%{gcc_target_platform}-gcc \ + %{buildroot}%{_prefix}/bin/ppc-%{_vendor}-%{_target_os}-gcc +%endif + +%ifarch sparcv9 ppc +FULLLPATH=$FULLPATH/lib32 +%endif +%ifarch sparc64 ppc64 ppc64p7 +FULLLPATH=$FULLPATH/lib64 +%endif +if [ -n "$FULLLPATH" ]; then + mkdir -p $FULLLPATH +else + FULLLPATH=$FULLPATH +fi + +find %{buildroot} -name \*.la | xargs rm -f +%if %{build_java} +# gcj -static doesn't work properly anyway, unless using --whole-archive +# and saving 35MB is not bad. +find %{buildroot} -name libgcj.a -o -name libgtkpeer.a \ + -o -name libgjsmalsa.a -o -name libgcj-tools.a -o -name libjvm.a \ + -o -name libgij.a -o -name libgcj_bc.a -o -name libjavamath.a \ + | xargs rm -f + +mv %{buildroot}%{_prefix}/lib/libgcj.spec $FULLPATH/ +sed -i -e 's/lib: /&%%{static:%%eJava programs cannot be linked statically}/' \ + $FULLPATH/libgcj.spec +%endif + +mv %{buildroot}%{_prefix}/%{_lib}/libgfortran.spec $FULLPATH/ +%if %{build_libitm} +mv %{buildroot}%{_prefix}/%{_lib}/libitm.spec $FULLPATH/ +%endif + +%if %{build_libasan} +mv %{buildroot}%{_prefix}/%{_lib}/libsanitizer.spec $FULLPATH/ +%endif + +mkdir -p %{buildroot}/%{_lib} +mv -f %{buildroot}%{_prefix}/%{_lib}/libgcc_s.so.1 %{buildroot}/%{_lib}/libgcc_s-%{version}-%{DATE}.so.1 +chmod 755 %{buildroot}/%{_lib}/libgcc_s-%{version}-%{DATE}.so.1 +ln -sf libgcc_s-%{version}-%{DATE}.so.1 %{buildroot}/%{_lib}/libgcc_s.so.1 +ln -sf /%{_lib}/libgcc_s.so.1 $FULLPATH/libgcc_s.so + +%ifarch aarch64 +%if %{build_libilp32} +mkdir -p %{buildroot}/libilp32 +mv -f %{buildroot}%{_prefix}/libilp32/libgcc_s.so.1 %{buildroot}/libilp32/libgcc_s-%{version}-%{DATE}.so.1 +chmod 755 %{buildroot}/libilp32/libgcc_s-%{version}-%{DATE}.so.1 +ln -sf libgcc_s-%{version}-%{DATE}.so.1 %{buildroot}/libilp32/libgcc_s.so.1 +ln -sf /libilp32/libgcc_s.so.1 $FULLPATH/ilp32/libgcc_s.so +%endif +%endif + +%ifarch sparcv9 ppc +ln -sf /lib64/libgcc_s.so.1 $FULLPATH/64/libgcc_s.so +%endif +%ifarch %{multilib_64_archs} +ln -sf /lib/libgcc_s.so.1 $FULLPATH/32/libgcc_s.so +%endif +%ifarch ppc +rm -f $FULLPATH/libgcc_s.so +echo '/* GNU ld script + Use the shared library, but some functions are only in + the static library, so try that secondarily. */ +OUTPUT_FORMAT(elf32-powerpc) +GROUP ( /lib/libgcc_s.so.1 libgcc.a )' > $FULLPATH/libgcc_s.so +%endif +%ifarch ppc64 ppc64p7 +rm -f $FULLPATH/32/libgcc_s.so +echo '/* GNU ld script + Use the shared library, but some functions are only in + the static library, so try that secondarily. */ +OUTPUT_FORMAT(elf32-powerpc) +GROUP ( /lib/libgcc_s.so.1 libgcc.a )' > $FULLPATH/32/libgcc_s.so +%endif +%ifarch %{arm} +rm -f $FULLPATH/libgcc_s.so +echo '/* GNU ld script + Use the shared library, but some functions are only in + the static library, so try that secondarily. */ +OUTPUT_FORMAT(elf32-littlearm) +GROUP ( /lib/libgcc_s.so.1 libgcc.a )' > $FULLPATH/libgcc_s.so +%endif + +mv -f %{buildroot}%{_prefix}/%{_lib}/libgomp.spec $FULLPATH/ + +%if %{build_ada} +mv -f $FULLPATH/adalib/libgnarl-*.so %{buildroot}%{_prefix}/%{_lib}/ +mv -f $FULLPATH/adalib/libgnat-*.so %{buildroot}%{_prefix}/%{_lib}/ +rm -f $FULLPATH/adalib/libgnarl.so* $FULLPATH/adalib/libgnat.so* +%endif + +mkdir -p %{buildroot}%{_prefix}/libexec/getconf +if gcc/xgcc -B gcc/ -E -dD -xc /dev/null | grep __LONG_MAX__.*2147483647; then + ln -sf POSIX_V6_ILP32_OFF32 %{buildroot}%{_prefix}/libexec/getconf/default +else + ln -sf POSIX_V6_LP64_OFF64 %{buildroot}%{_prefix}/libexec/getconf/default +fi + +%if %{build_java} +pushd ../fastjar-%{fastjar_ver}/obj-%{gcc_target_platform} +make -j100 install DESTDIR=%{buildroot} +popd + +if [ "%{_lib}" != "lib" ]; then + mkdir -p %{buildroot}%{_prefix}/%{_lib}/pkgconfig + sed '/^libdir/s/lib$/%{_lib}/' %{buildroot}%{_prefix}/lib/pkgconfig/libgcj-*.pc \ + > %{buildroot}%{_prefix}/%{_lib}/pkgconfig/`basename %{buildroot}%{_prefix}/lib/pkgconfig/libgcj-*.pc` +fi + +%endif + +mkdir -p %{buildroot}%{_datadir}/gdb/auto-load/%{_prefix}/%{_lib} +mv -f %{buildroot}%{_prefix}/%{_lib}/libstdc++*gdb.py* \ + %{buildroot}%{_datadir}/gdb/auto-load/%{_prefix}/%{_lib}/ + +%ifarch aarch64 +%if %{build_libilp32} +mkdir -p %{buildroot}%{_datadir}/gdb/auto-load/%{_prefix}/libilp32 +mv -f %{buildroot}%{_prefix}/libilp32/libstdc++*gdb.py* \ + %{buildroot}%{_datadir}/gdb/auto-load/%{_prefix}/libilp32 +%endif +%endif + +pushd ../libstdc++-v3/python +for i in `find . -name \*.py`; do + touch -r $i %{buildroot}%{_prefix}/share/gcc-%{version}/python/$i +done +touch -r hook.in %{buildroot}%{_datadir}/gdb/auto-load/%{_prefix}/%{_lib}/libstdc++*gdb.py +%ifarch aarch64 +%if %{build_libilp32} +touch -r hook.in %{buildroot}%{_datadir}/gdb/auto-load/%{_prefix}/libilp32/libstdc++*gdb.py +%endif +%endif +popd + +pushd $FULLPATH +if [ "%{_lib}" = "lib" ]; then +ln -sf ../../../libobjc.so.4 libobjc.so +ln -sf ../../../libstdc++.so.6.*[0-9] libstdc++.so +ln -sf ../../../libgfortran.so.4.* libgfortran.so +ln -sf ../../../libgomp.so.1.* libgomp.so +#ln -sf ../../../libmudflap.so.0.* libmudflap.so +#ln -sf ../../../libmudflapth.so.0.* libmudflapth.so +%if %{build_go} +ln -sf ../../../libgo.so.4.* libgo.so +%endif +%if %{build_libquadmath} +ln -sf ../../../libquadmath.so.0.* libquadmath.so +%endif +%if %{build_libitm} +ln -sf ../../../libitm.so.1.* libitm.so +%endif +%if %{build_libatomic} +ln -sf ../../../libatomic.so.1.* libatomic.so +%endif +%if %{build_libasan} +ln -sf ../../../libasan.so.4.* libasan.so +mv ../../../libasan_preinit.o libasan_preinit.o +%endif +%if %{build_java} +ln -sf ../../../libgcj.so.14.* libgcj.so +ln -sf ../../../libgcj-tools.so.14.* libgcj-tools.so +ln -sf ../../../libgij.so.14.* libgij.so +%endif +else +ln -sf ../../../../%{_lib}/libobjc.so.4 libobjc.so +ln -sf ../../../../%{_lib}/libstdc++.so.6.*[0-9] libstdc++.so +ln -sf ../../../../%{_lib}/libgfortran.so.4.* libgfortran.so +ln -sf ../../../../%{_lib}/libgomp.so.1.* libgomp.so +%ifarch aarch64 +%if %{build_libilp32} +ln -sf ../../../../libilp32/libobjc.so.4 ilp32/libobjc.so +ln -sf ../../../../libilp32/libstdc++.so.6.*[0-9] ilp32/libstdc++.so +ln -sf ../../../../libilp32/libgfortran.so.4.* ilp32/libgfortran.so +ln -sf ../../../../libilp32/libgomp.so.1.* ilp32/libgomp.so +%endif +%endif +#ln -sf ../../../../%{_lib}/libmudflap.so.0.* libmudflap.so +#ln -sf ../../../../%{_lib}/libmudflapth.so.0.* libmudflapth.so +%if %{build_go} +ln -sf ../../../../%{_lib}/libgo.so.4.* libgo.so +%ifarch aarch64 +%if %{build_libilp32} +ln -sf ../../../../libilp32/libgo.so.4.* ilp32/libgo.so +%endif +%endif +%endif +%if %{build_libquadmath} +ln -sf ../../../../%{_lib}/libquadmath.so.0.* libquadmath.so +%ifarch aarch64 +%if %{build_libilp32} +ln -sf ../../../../libilp32/libquadmath.so.0.* ilp32/libquadmath.so +%endif +%endif +%endif +%if %{build_libitm} +ln -sf ../../../../%{_lib}/libitm.so.1.* libitm.so +%ifarch aarch64 +%if %{build_libilp32} +ln -sf ../../../../libilp32/libitm.so.1.* ilp32/libitm.so +%endif +%endif +%endif +%if %{build_libatomic} +ln -sf ../../../../%{_lib}/libatomic.so.1.* libatomic.so +%ifarch aarch64 +%if %{build_libilp32} +ln -sf ../../../../libilp32/libatomic.so.1.* ilp32/libatomic.so +%endif +%endif +%endif +%if %{build_libasan} +ln -sf ../../../../%{_lib}/libasan.so.4.* libasan.so +mv ../../../../%{_lib}/libasan_preinit.o libasan_preinit.o +%ifarch aarch64 +%if %{build_libilp32} +ln -sf ../../../../libilp32/libasan.so.4.* ilp32/libasan.so +mv ../../../../libilp32/libasan_preinit.o ilp32/libasan_preinit.o +%endif +%endif +%endif +%if %{build_libtsan} +rm -f libtsan.so +echo 'INPUT ( %{_prefix}/%{_lib}/'`echo ../../../../%{_lib}/libtsan.so.0.* | sed 's,^.*libt,libt,'`' )' > libtsan.so +%ifarch aarch64 +%if %{build_libilp32} +echo 'INPUT ( %{_prefix}/libilp32/'`echo ../../../../libilp32/libtsan.so.0.* | sed 's,^.*libt,libt,'`' )' > ilp32/libtsan.so +%endif +%endif +%endif +%if %{build_java} +ln -sf ../../../../%{_lib}/libgcj.so.14.* libgcj.so +ln -sf ../../../../%{_lib}/libgcj-tools.so.14.* libgcj-tools.so +ln -sf ../../../../%{_lib}/libgij.so.14.* libgij.so +%ifarch aarch64 +%if %{build_libilp32} +ln -sf ../../../../libilp32/libgcj.so.14.* ilp32/libgcj.so +ln -sf ../../../../libilp32/libgcj-tools.so.14.* ilp32/libgcj-tools.so +ln -sf ../../../../libilp32/libgij.so.14.* ilp32/libgij.so +%endif +%endif +%endif +fi +%if %{build_java} +mv -f %{buildroot}%{_prefix}/%{_lib}/libgcj_bc.so $FULLLPATH/ +%endif +mv -f %{buildroot}%{_prefix}/%{_lib}/libstdc++.*a $FULLLPATH/ +mv -f %{buildroot}%{_prefix}/%{_lib}/libsupc++.*a $FULLLPATH/ +mv -f %{buildroot}%{_prefix}/%{_lib}/libgfortran.*a $FULLLPATH/ +mv -f %{buildroot}%{_prefix}/%{_lib}/libobjc.*a . +mv -f %{buildroot}%{_prefix}/%{_lib}/libgomp.*a . +%ifarch aarch64 +%if %{build_libilp32} +mv -f %{buildroot}%{_prefix}/libilp32/libstdc++.*a $FULLLPATH/ilp32/ +mv -f %{buildroot}%{_prefix}/libilp32/libsupc++.*a $FULLLPATH/ilp32/ +mv -f %{buildroot}%{_prefix}/libilp32/libgfortran.*a $FULLLPATH/ilp32/ +mv -f %{buildroot}%{_prefix}/libilp32/libobjc.*a ./ilp32/ +mv -f %{buildroot}%{_prefix}/libilp32/libgomp.*a ./ilp32/ +%endif +%endif + +#mv -f %{buildroot}%{_prefix}/%{_lib}/libmudflap{,th}.*a $FULLLPATH/ +%if %{build_libquadmath} +mv -f %{buildroot}%{_prefix}/%{_lib}/libquadmath.*a $FULLLPATH/ +%ifarch aarch64 +%if %{build_libilp32} +mv -f %{buildroot}%{_prefix}/libilp32/libquadmath.*a $FULLLPATH/ilp32/ +%endif +%endif +%endif +%if %{build_libitm} +mv -f %{buildroot}%{_prefix}/%{_lib}/libitm.*a $FULLLPATH/ +%ifarch aarch64 +%if %{build_libilp32} +mv -f %{buildroot}%{_prefix}/libilp32/libitm.*a $FULLLPATH/ilp32/ +%endif +%endif +%endif +%if %{build_libatomic} +mv -f %{buildroot}%{_prefix}/%{_lib}/libatomic.*a $FULLLPATH/ +%ifarch aarch64 +%if %{build_libilp32} +mv -f %{buildroot}%{_prefix}/libilp32/libatomic.*a $FULLLPATH/ilp32/ +%endif +%endif +%endif +%if %{build_libasan} +mv -f %{buildroot}%{_prefix}/%{_lib}/libasan.*a $FULLLPATH/ +%ifarch aarch64 +%if %{build_libilp32} +mv -f %{buildroot}%{_prefix}/libilp32/libasan.*a $FULLLPATH/ilp32/ +%endif +%endif +%endif +%if %{build_libtsan} +mv -f %{buildroot}%{_prefix}/%{_lib}/libtsan.*a $FULLLPATH/ +%ifarch aarch64 +%if %{build_libilp32} +mv -f %{buildroot}%{_prefix}/libilp32/libtsan.*a $FULLLPATH/ilp32/ +%endif +%endif +%endif +%if %{build_go} +mv -f %{buildroot}%{_prefix}/%{_lib}/libgo.*a $FULLLPATH/ +mv -f %{buildroot}%{_prefix}/%{_lib}/libgobegin.*a $FULLLPATH/ +%ifarch aarch64 +%if %{build_libilp32} +mv -f %{buildroot}%{_prefix}/libilp32/libgo.*a $FULLLPATH/ilp32/ +mv -f %{buildroot}%{_prefix}/libilp32/libgobegin.*a $FULLLPATH/ilp32/ +%endif +%endif +%endif + +%if %{build_ada} +%ifarch sparcv9 ppc +rm -rf $FULLPATH/64/ada{include,lib} +%endif +%ifarch %{multilib_64_archs} +rm -rf $FULLPATH/32/ada{include,lib} +%endif +if [ "$FULLPATH" != "$FULLLPATH" ]; then +mv -f $FULLPATH/ada{include,lib} $FULLLPATH/ +pushd $FULLLPATH/adalib +if [ "%{_lib}" = "lib" ]; then +ln -sf ../../../../../libgnarl-*.so libgnarl.so +ln -sf ../../../../../libgnarl-*.so libgnarl-4.8.so +ln -sf ../../../../../libgnat-*.so libgnat.so +ln -sf ../../../../../libgnat-*.so libgnat-4.8.so +else +ln -sf ../../../../../../%{_lib}/libgnarl-*.so libgnarl.so +ln -sf ../../../../../../%{_lib}/libgnarl-*.so libgnarl-4.8.so +ln -sf ../../../../../../%{_lib}/libgnat-*.so libgnat.so +ln -sf ../../../../../../%{_lib}/libgnat-*.so libgnat-4.8.so +fi +popd +else +pushd $FULLPATH/adalib +if [ "%{_lib}" = "lib" ]; then +ln -sf ../../../../libgnarl-*.so libgnarl.so +ln -sf ../../../../libgnarl-*.so libgnarl-4.8.so +ln -sf ../../../../libgnat-*.so libgnat.so +ln -sf ../../../../libgnat-*.so libgnat-4.8.so +else +ln -sf ../../../../../%{_lib}/libgnarl-*.so libgnarl.so +ln -sf ../../../../../%{_lib}/libgnarl-*.so libgnarl-4.8.so +ln -sf ../../../../../%{_lib}/libgnat-*.so libgnat.so +ln -sf ../../../../../%{_lib}/libgnat-*.so libgnat-4.8.so +fi +popd +fi +%endif + +%ifarch sparcv9 ppc +ln -sf ../../../../../lib64/libobjc.so.4 64/libobjc.so +ln -sf ../`echo ../../../../lib/libstdc++.so.6.*[0-9] | sed s~/lib/~/lib64/~` 64/libstdc++.so +ln -sf ../`echo ../../../../lib/libgfortran.so.4.* | sed s~/lib/~/lib64/~` 64/libgfortran.so +ln -sf ../`echo ../../../../lib/libgomp.so.1.* | sed s~/lib/~/lib64/~` 64/libgomp.so +#rm -f libmudflap.so libmudflapth.so +echo 'INPUT ( %{_prefix}/lib/'`echo ../../../../lib/libmudflap.so.0.* | sed 's,^.*libm,libm,'`' )' > libmudflap.so +echo 'INPUT ( %{_prefix}/lib/'`echo ../../../../lib/libmudflapth.so.0.* | sed 's,^.*libm,libm,'`' )' > libmudflapth.so +echo 'INPUT ( %{_prefix}/lib64/'`echo ../../../../lib/libmudflap.so.0.* | sed 's,^.*libm,libm,'`' )' > 64/libmudflap.so +echo 'INPUT ( %{_prefix}/lib64/'`echo ../../../../lib/libmudflapth.so.0.* | sed 's,^.*libm,libm,'`' )' > 64/libmudflapth.so +%if %{build_go} +rm -f libgo.so +echo 'INPUT ( %{_prefix}/lib/'`echo ../../../../lib/libgo.so.4.* | sed 's,^.*libg,libg,'`' )' > libgo.so +echo 'INPUT ( %{_prefix}/lib64/'`echo ../../../../lib/libgo.so.4.* | sed 's,^.*libg,libg,'`' )' > 64/libgo.so +%endif +%if %{build_libquadmath} +rm -f libquadmath.so +echo 'INPUT ( %{_prefix}/lib/'`echo ../../../../lib/libquadmath.so.0.* | sed 's,^.*libq,libq,'`' )' > libquadmath.so +echo 'INPUT ( %{_prefix}/lib64/'`echo ../../../../lib/libquadmath.so.0.* | sed 's,^.*libq,libq,'`' )' > 64/libquadmath.so +%endif +%if %{build_libitm} +rm -f libitm.so +echo 'INPUT ( %{_prefix}/lib/'`echo ../../../../lib/libitm.so.1.* | sed 's,^.*libi,libi,'`' )' > libitm.so +echo 'INPUT ( %{_prefix}/lib64/'`echo ../../../../lib/libitm.so.1.* | sed 's,^.*libi,libi,'`' )' > 64/libitm.so +%endif +%if %{build_libatomic} +rm -f libatomic.so +echo 'INPUT ( %{_prefix}/lib/'`echo ../../../../lib/libatomic.so.1.* | sed 's,^.*liba,liba,'`' )' > libatomic.so +echo 'INPUT ( %{_prefix}/lib64/'`echo ../../../../lib/libatomic.so.1.* | sed 's,^.*liba,liba,'`' )' > 64/libatomic.so +%endif +%if %{build_libasan} +rm -f libasan.so +echo 'INPUT ( %{_prefix}/lib/'`echo ../../../../lib/libasan.so.4.* | sed 's,^.*liba,liba,'`' )' > libasan.so +echo 'INPUT ( %{_prefix}/lib64/'`echo ../../../../lib/libasan.so.4.* | sed 's,^.*liba,liba,'`' )' > 64/libasan.so +mv ../../../../lib64/libasan_preinit.o 64/libasan_preinit.o +%endif +%if %{build_java} +ln -sf ../`echo ../../../../lib/libgcj.so.14.* | sed s~/lib/~/lib64/~` 64/libgcj.so +ln -sf ../`echo ../../../../lib/libgcj-tools.so.14.* | sed s~/lib/~/lib64/~` 64/libgcj-tools.so +ln -sf ../`echo ../../../../lib/libgij.so.14.* | sed s~/lib/~/lib64/~` 64/libgij.so +ln -sf lib32/libgcj_bc.so libgcj_bc.so +ln -sf ../lib64/libgcj_bc.so 64/libgcj_bc.so +%endif +ln -sf lib32/libgfortran.a libgfortran.a +ln -sf ../lib64/libgfortran.a 64/libgfortran.a +mv -f %{buildroot}%{_prefix}/lib64/libobjc.*a 64/ +mv -f %{buildroot}%{_prefix}/lib64/libgomp.*a 64/ +ln -sf lib32/libstdc++.a libstdc++.a +ln -sf ../lib64/libstdc++.a 64/libstdc++.a +ln -sf lib32/libsupc++.a libsupc++.a +ln -sf ../lib64/libsupc++.a 64/libsupc++.a +#ln -sf lib32/libmudflap.a libmudflap.a +#ln -sf ../lib64/libmudflap.a 64/libmudflap.a +#ln -sf lib32/libmudflapth.a libmudflapth.a +#ln -sf ../lib64/libmudflapth.a 64/libmudflapth.a +%if %{build_libquadmath} +ln -sf lib32/libquadmath.a libquadmath.a +ln -sf ../lib64/libquadmath.a 64/libquadmath.a +%endif +%if %{build_libitm} +ln -sf lib32/libitm.a libitm.a +ln -sf ../lib64/libitm.a 64/libitm.a +%endif +%if %{build_libatomic} +ln -sf lib32/libatomic.a libatomic.a +ln -sf ../lib64/libatomic.a 64/libatomic.a +%endif +%if %{build_libasan} +ln -sf lib32/libasan.a libasan.a +ln -sf ../lib64/libasan.a 64/libasan.a +%endif +%if %{build_go} +ln -sf lib32/libgo.a libgo.a +ln -sf ../lib64/libgo.a 64/libgo.a +ln -sf lib32/libgobegin.a libgobegin.a +ln -sf ../lib64/libgobegin.a 64/libgobegin.a +%endif +%if %{build_ada} +ln -sf lib32/adainclude adainclude +ln -sf ../lib64/adainclude 64/adainclude +ln -sf lib32/adalib adalib +ln -sf ../lib64/adalib 64/adalib +%endif +%endif +%ifarch %{multilib_64_archs} +mkdir -p 32 +ln -sf ../../../../libobjc.so.4 32/libobjc.so +ln -sf ../`echo ../../../../lib64/libstdc++.so.6.*[0-9] | sed s~/../lib64/~/~` 32/libstdc++.so +ln -sf ../`echo ../../../../lib64/libgfortran.so.4.* | sed s~/../lib64/~/~` 32/libgfortran.so +ln -sf ../`echo ../../../../lib64/libgomp.so.1.* | sed s~/../lib64/~/~` 32/libgomp.so +%if 0 +rm -f libmudflap.so libmudflapth.so +echo 'INPUT ( %{_prefix}/lib64/'`echo ../../../../lib64/libmudflap.so.0.* | sed 's,^.*libm,libm,'`' )' > libmudflap.so +echo 'INPUT ( %{_prefix}/lib64/'`echo ../../../../lib64/libmudflapth.so.0.* | sed 's,^.*libm,libm,'`' )' > libmudflapth.so +echo 'INPUT ( %{_prefix}/lib/'`echo ../../../../lib64/libmudflap.so.0.* | sed 's,^.*libm,libm,'`' )' > 32/libmudflap.so +echo 'INPUT ( %{_prefix}/lib/'`echo ../../../../lib64/libmudflapth.so.0.* | sed 's,^.*libm,libm,'`' )' > 32/libmudflapth.so +%endif +%if %{build_go} +rm -f libgo.so +echo 'INPUT ( %{_prefix}/lib64/'`echo ../../../../lib64/libgo.so.4.* | sed 's,^.*libg,libg,'`' )' > libgo.so +echo 'INPUT ( %{_prefix}/lib/'`echo ../../../../lib64/libgo.so.4.* | sed 's,^.*libg,libg,'`' )' > 32/libgo.so +%endif +%if %{build_libquadmath} +rm -f libquadmath.so +echo 'INPUT ( %{_prefix}/lib64/'`echo ../../../../lib64/libquadmath.so.0.* | sed 's,^.*libq,libq,'`' )' > libquadmath.so +echo 'INPUT ( %{_prefix}/lib/'`echo ../../../../lib64/libquadmath.so.0.* | sed 's,^.*libq,libq,'`' )' > 32/libquadmath.so +%endif +%if %{build_libitm} +rm -f libitm.so +echo 'INPUT ( %{_prefix}/lib64/'`echo ../../../../lib64/libitm.so.1.* | sed 's,^.*libi,libi,'`' )' > libitm.so +echo 'INPUT ( %{_prefix}/lib/'`echo ../../../../lib64/libitm.so.1.* | sed 's,^.*libi,libi,'`' )' > 32/libitm.so +%endif +%if %{build_libatomic} +rm -f libatomic.so +echo 'INPUT ( %{_prefix}/lib64/'`echo ../../../../lib64/libatomic.so.1.* | sed 's,^.*liba,liba,'`' )' > libatomic.so +echo 'INPUT ( %{_prefix}/lib/'`echo ../../../../lib64/libatomic.so.1.* | sed 's,^.*liba,liba,'`' )' > 32/libatomic.so +%endif +%if %{build_libasan} +rm -f libasan.so +echo 'INPUT ( %{_prefix}/lib64/'`echo ../../../../lib64/libasan.so.4.* | sed 's,^.*liba,liba,'`' )' > libasan.so +echo 'INPUT ( %{_prefix}/lib/'`echo ../../../../lib64/libasan.so.4.* | sed 's,^.*liba,liba,'`' )' > 32/libasan.so +mv ../../../../lib/libasan_preinit.o 32/libasan_preinit.o +%endif +%if %{build_java} +ln -sf ../`echo ../../../../lib64/libgcj.so.14.* | sed s~/../lib64/~/~` 32/libgcj.so +ln -sf ../`echo ../../../../lib64/libgcj-tools.so.14.* | sed s~/../lib64/~/~` 32/libgcj-tools.so +ln -sf ../`echo ../../../../lib64/libgij.so.14.* | sed s~/../lib64/~/~` 32/libgij.so +%endif +mv -f %{buildroot}%{_prefix}/lib/libobjc.*a 32/ +mv -f %{buildroot}%{_prefix}/lib/libgomp.*a 32/ +%endif +%ifarch sparc64 ppc64 ppc64p7 +ln -sf ../lib32/libgfortran.a 32/libgfortran.a +ln -sf lib64/libgfortran.a libgfortran.a +ln -sf ../lib32/libstdc++.a 32/libstdc++.a +ln -sf lib64/libstdc++.a libstdc++.a +ln -sf ../lib32/libsupc++.a 32/libsupc++.a +ln -sf lib64/libsupc++.a libsupc++.a +#ln -sf ../lib32/libmudflap.a 32/libmudflap.a +#ln -sf lib64/libmudflap.a libmudflap.a +#ln -sf ../lib32/libmudflapth.a 32/libmudflapth.a +#ln -sf lib64/libmudflapth.a libmudflapth.a +%if %{build_libquadmath} +ln -sf ../lib32/libquadmath.a 32/libquadmath.a +ln -sf lib64/libquadmath.a libquadmath.a +%endif +%if %{build_libitm} +ln -sf ../lib32/libitm.a 32/libitm.a +ln -sf lib64/libitm.a libitm.a +%endif +%if %{build_libatomic} +ln -sf ../lib32/libatomic.a 32/libatomic.a +ln -sf lib64/libatomic.a libatomic.a +%endif +%if %{build_libasan} +ln -sf ../lib32/libasan.a 32/libasan.a +ln -sf lib64/libasan.a libasan.a +%endif +%if %{build_go} +ln -sf ../lib32/libgo.a 32/libgo.a +ln -sf lib64/libgo.a libgo.a +ln -sf ../lib32/libgobegin.a 32/libgobegin.a +ln -sf lib64/libgobegin.a libgobegin.a +%endif +%if %{build_java} +ln -sf ../lib32/libgcj_bc.so 32/libgcj_bc.so +ln -sf lib64/libgcj_bc.so libgcj_bc.so +%endif +%if %{build_ada} +ln -sf ../lib32/adainclude 32/adainclude +ln -sf lib64/adainclude adainclude +ln -sf ../lib32/adalib 32/adalib +ln -sf lib64/adalib adalib +%endif +%else +%ifarch %{multilib_64_archs} +ln -sf ../../../%{multilib_32_arch}-%{_vendor}-%{_target_os}/%{version}/libgfortran.a 32/libgfortran.a +ln -sf ../../../%{multilib_32_arch}-%{_vendor}-%{_target_os}/%{version}/libstdc++.a 32/libstdc++.a +ln -sf ../../../%{multilib_32_arch}-%{_vendor}-%{_target_os}/%{version}/libsupc++.a 32/libsupc++.a +#ln -sf ../../../%{multilib_32_arch}-%{_vendor}-%{_target_os}/%{version}/libmudflap.a 32/libmudflap.a +#ln -sf ../../../%{multilib_32_arch}-%{_vendor}-%{_target_os}/%{version}/libmudflapth.a 32/libmudflapth.a +%if %{build_libquadmath} +ln -sf ../../../%{multilib_32_arch}-%{_vendor}-%{_target_os}/%{version}/libquadmath.a 32/libquadmath.a +%endif +%if %{build_libitm} +ln -sf ../../../%{multilib_32_arch}-%{_vendor}-%{_target_os}/%{version}/libitm.a 32/libitm.a +%endif +%if %{build_libatomic} +ln -sf ../../../%{multilib_32_arch}-%{_vendor}-%{_target_os}/%{version}/libatomic.a 32/libatomic.a +%endif +%if %{build_libasan} +ln -sf ../../../%{multilib_32_arch}-%{_vendor}-%{_target_os}/%{version}/libasan.a 32/libasan.a +%endif +%if %{build_go} +ln -sf ../../../%{multilib_32_arch}-%{_vendor}-%{_target_os}/%{version}/libgo.a 32/libgo.a +ln -sf ../../../%{multilib_32_arch}-%{_vendor}-%{_target_os}/%{version}/libgobegin.a 32/libgobegin.a +%endif +%if %{build_java} +ln -sf ../../../%{multilib_32_arch}-%{_vendor}-%{_target_os}/%{version}/libgcj_bc.so 32/libgcj_bc.so +%endif +%if %{build_ada} +ln -sf ../../../%{multilib_32_arch}-%{_vendor}-%{_target_os}/%{version}/adainclude 32/adainclude +ln -sf ../../../%{multilib_32_arch}-%{_vendor}-%{_target_os}/%{version}/adalib 32/adalib +%endif +%endif +%endif + +# Strip debug info from Fortran/ObjC/Java static libraries +%if 0 +strip -g `find . \( -name libgfortran.a -o -name libobjc.a -o -name libgomp.a \ + -o -name libmudflap.a -o -name libmudflapth.a \ + -o -name libgcc.a -o -name libgcov.a -o -name libquadmath.a \ + -o -name libitm.a -o -name libgo.a -o -name libcaf\*.a \ + -o -name libatomic.a -o -name libasan.a -o -name libtsan.a \) \ + -a -type f` +%endif + +strip -g `find . \( -name libgfortran.a -o -name libobjc.a -o -name libgomp.a \ + -o -name libgcc.a -o -name libgcov.a -o -name libquadmath.a \ + -o -name libitm.a -o -name libgo.a -o -name libcaf\*.a \ + -o -name libatomic.a -o -name libasan.a -o -name libtsan.a \) \ + -a -type f` + + +popd +chmod 755 %{buildroot}%{_prefix}/%{_lib}/libgfortran.so.4.* +chmod 755 %{buildroot}%{_prefix}/%{_lib}/libgomp.so.1.* +chmod 755 %{buildroot}%{_prefix}/%{_lib}/libcc1.so.0.* +#chmod 755 %{buildroot}%{_prefix}/%{_lib}/libmudflap{,th}.so.0.* +%if %{build_libquadmath} +chmod 755 %{buildroot}%{_prefix}/%{_lib}/libquadmath.so.0.* +%endif +%if %{build_libitm} +chmod 755 %{buildroot}%{_prefix}/%{_lib}/libitm.so.1.* +%endif +%if %{build_libatomic} +chmod 755 %{buildroot}%{_prefix}/%{_lib}/libatomic.so.1.* +%endif +%if %{build_libasan} +chmod 755 %{buildroot}%{_prefix}/%{_lib}/libasan.so.4.* +%endif +%if %{build_libtsan} +chmod 755 %{buildroot}%{_prefix}/%{_lib}/libtsan.so.0.* +%endif +%if %{build_go} +chmod 755 %{buildroot}%{_prefix}/%{_lib}/libgo.so.4.* +%endif +chmod 755 %{buildroot}%{_prefix}/%{_lib}/libobjc.so.4.* + +%if %{build_ada} +chmod 755 %{buildroot}%{_prefix}/%{_lib}/libgnarl*so* +chmod 755 %{buildroot}%{_prefix}/%{_lib}/libgnat*so* +%endif + +mv $FULLHPATH/include-fixed/syslimits.h $FULLHPATH/include/syslimits.h +mv $FULLHPATH/include-fixed/limits.h $FULLHPATH/include/limits.h +for h in `find $FULLHPATH/include -name \*.h`; do + if grep -q 'It has been auto-edited by fixincludes from' $h; then + rh=`grep -A2 'It has been auto-edited by fixincludes from' $h | tail -1 | sed 's|^.*"\(.*\)".*$|\1|'` + diff -up $rh $h || : + rm -f $h + fi +done + +cat > %{buildroot}%{_prefix}/bin/c89 <<"EOF" +#!/bin/sh +fl="-std=c89" +for opt; do + case "$opt" in + -ansi|-std=c89|-std=iso9899:1990) fl="";; + -std=*) echo "`basename $0` called with non ANSI/ISO C option $opt" >&2 + exit 1;; + esac +done +exec gcc $fl ${1+"$@"} +EOF +cat > %{buildroot}%{_prefix}/bin/c99 <<"EOF" +#!/bin/sh +fl="-std=c99" +for opt; do + case "$opt" in + -std=c99|-std=iso9899:1999) fl="";; + -std=*) echo "`basename $0` called with non ISO C99 option $opt" >&2 + exit 1;; + esac +done +exec gcc $fl ${1+"$@"} +EOF +chmod 755 %{buildroot}%{_prefix}/bin/c?9 + +%if "%{version}" != "%{gcc_version}" +mv -f $RPM_BUILD_ROOT%{_prefix}/libexec/gcc/%{gcc_target_platform}/{%{version},%{gcc_version}} +ln -sf %{gcc_version} $RPM_BUILD_ROOT%{_prefix}/libexec/gcc/%{gcc_target_platform}/%{version} +mv -f $RPM_BUILD_ROOT%{_prefix}/lib/gcc/%{gcc_target_platform}/{%{version},%{gcc_version}} +ln -sf %{gcc_version} $RPM_BUILD_ROOT%{_prefix}/lib/gcc/%{gcc_target_platform}/%{version} +mv -f $RPM_BUILD_ROOT%{_prefix}/include/c++/{%{version},%{gcc_version}} +ln -sf %{gcc_version} $RPM_BUILD_ROOT%{_prefix}/include/c++/%{version} +mv -f $RPM_BUILD_ROOT%{_prefix}/share/gcc-{%{version},%{gcc_version}} +ln -sf gcc-%{gcc_version} $RPM_BUILD_ROOT%{_prefix}/share/gcc-%{version} +%if %{build_java} +mv -f $RPM_BUILD_ROOT%{_prefix}/%{_lib}/gcj-{%{version},%{gcc_version}} +ln -sf gcj-%{gcc_version} $RPM_BUILD_ROOT%{_prefix}/%{_lib}/gcj-%{version} +mv -f $RPM_BUILD_ROOT%{_prefix}/share/java/libgcj-{%{version},%{gcc_version}}.jar +ln -sf libgcj-%{gcc_version}.jar $RPM_BUILD_ROOT%{_prefix}/share/java/libgcj-%{version}.jar +mv -f $RPM_BUILD_ROOT%{_prefix}/share/java/libgcj-tools-{%{version},%{gcc_version}}.jar +ln -sf libgcj-tools-%{gcc_version}.jar $RPM_BUILD_ROOT%{_prefix}/share/java/libgcj-tools-%{version}.jar +mv -f $RPM_BUILD_ROOT%{_prefix}/share/java/src-{%{version},%{gcc_version}}.zip +ln -sf src-%{gcc_version}.zip $RPM_BUILD_ROOT%{_prefix}/share/java/src-%{version}.zip +%endif +%if %{build_go} +mv -f $RPM_BUILD_ROOT%{_prefix}/%{_lib}/go/{%{version},%{gcc_version}} +ln -sf %{gcc_version} $RPM_BUILD_ROOT%{_prefix}/%{_lib}/go/%{version} +%endif +%endif + +cd .. +%find_lang %{name} +%find_lang cpplib + +# Remove binaries we will not be including, so that they don't end up in +# gcc-debuginfo +rm -f %{buildroot}%{_prefix}/%{_lib}/{libffi*,libiberty.a} +rm -f $FULLEPATH/install-tools/{mkheaders,fixincl} +rm -f %{buildroot}%{_prefix}/lib/{32,64}/libiberty.a +rm -f %{buildroot}%{_prefix}/%{_lib}/libssp* +rm -f %{buildroot}%{_prefix}/bin/gappletviewer || : +rm -f %{buildroot}%{_prefix}/bin/%{_target_platform}-gcc-%{version} || : +rm -f %{buildroot}%{_prefix}/bin/%{_target_platform}-gfortran || : +rm -f %{buildroot}%{_prefix}/bin/%{_target_platform}-gccgo || : +rm -f %{buildroot}%{_prefix}/bin/%{_target_platform}-gcj || : +rm -f %{buildroot}%{_prefix}/bin/%{_target_platform}-gcc-ar || : +rm -f %{buildroot}%{_prefix}/bin/%{_target_platform}-gcc-nm || : +rm -f %{buildroot}%{_prefix}/bin/%{_target_platform}-gcc-ranlib || : + +%ifarch %{multilib_64_archs} +# Remove libraries for the other arch on multilib arches +rm -f %{buildroot}%{_prefix}/lib/lib*.so* +rm -f %{buildroot}%{_prefix}/lib/lib*.a +rm -f %{buildroot}/lib/libgcc_s*.so* +%if %{build_go} +%if "%{version}" != "%{gcc_version}" +mv -f $RPM_BUILD_ROOT%{_prefix}/lib/go/{%{version},%{gcc_version}} +ln -sf %{gcc_version} $RPM_BUILD_ROOT%{_prefix}/lib/go/%{version} +%endif +rm -rf %{buildroot}%{_prefix}/lib/go/%{gcc_version}/%{gcc_target_platform} +%ifnarch sparc64 ppc64 ppc64p7 +ln -sf %{multilib_32_arch}-%{_vendor}-%{_target_os} %{buildroot}%{_prefix}/lib/go/%{gcc_version}/%{gcc_target_platform} +%endif +%endif +%else +%ifarch sparcv9 ppc +rm -f %{buildroot}%{_prefix}/lib64/lib*.so* +rm -f %{buildroot}%{_prefix}/lib64/lib*.a +rm -f %{buildroot}/lib64/libgcc_s*.so* +%if %{build_go} +%if "%{version}" != "%{gcc_version}" +mv -f $RPM_BUILD_ROOT%{_prefix}/lib64/go/{%{version},%{gcc_version}} +ln -sf %{gcc_version} $RPM_BUILD_ROOT%{_prefix}/lib64/go/%{version} +%endif +rm -rf %{buildroot}%{_prefix}/lib64/go/%{gcc_version}/%{gcc_target_platform} +%endif +%endif +%endif + +%if %{build_java} +mkdir -p %{buildroot}%{_prefix}/share/java/gcj-endorsed \ + %{buildroot}%{_prefix}/%{_lib}/gcj-%{gcc_version}/classmap.db.d +chmod 755 %{buildroot}%{_prefix}/share/java/gcj-endorsed \ + %{buildroot}%{_prefix}/%{_lib}/gcj-%{gcc_version} \ + %{buildroot}%{_prefix}/%{_lib}/gcj-%{gcc_version}/classmap.db.d +touch %{buildroot}%{_prefix}/%{_lib}/gcj-%{gcc_version}/classmap.db +%endif + +rm -f %{buildroot}%{mandir}/man3/ffi* + +# Help plugins find out nvra. +echo gcc-%{version}-%{release}.%{_arch} > $FULLHPATH/rpmver + +%check + +%if %{build_check} + +cd obj-%{gcc_target_platform} + +%if %{build_java} +export PATH=`pwd`/../fastjar-%{fastjar_ver}/obj-%{gcc_target_platform}${PATH:+:$PATH} +%if !%{bootstrap_java} +export PATH=`pwd`/java_hacks${PATH:+:$PATH} +%endif +%endif +%if 0 +# run the tests. +make %{?_smp_mflags} -k check ALT_CC_UNDER_TEST=gcc ALT_CXX_UNDER_TEST=g++ \ +%if 0%{?fedora} >= 20 + RUNTESTFLAGS="--target_board=unix/'{,-fstack-protector-strong}'" || : +%else + RUNTESTFLAGS="--target_board=unix/'{,-fstack-protector}'" || : +%endif +echo ====================TESTING========================= +( LC_ALL=C ../contrib/test_summary || : ) 2>&1 | sed -n '/^cat.*EOF/,/^EOF/{/^cat.*EOF/d;/^EOF/d;/^LAST_UPDATED:/d;p;}' +echo ====================TESTING END===================== +mkdir testlogs-%{_target_platform}-%{version}-%{release} +for i in `find . -name \*.log | grep -F testsuite/ | grep -v 'config.log\|acats.*/tests/'`; do + ln $i testlogs-%{_target_platform}-%{version}-%{release}/ || : +done +tar cf - testlogs-%{_target_platform}-%{version}-%{release} | bzip2 -9c \ + | uuencode testlogs-%{_target_platform}.tar.bz2 || : +rm -rf testlogs-%{_target_platform}-%{version}-%{release} +%endif + +%endif #build_check + +%clean +rm -rf %{buildroot} + +%post +if [ -f %{_infodir}/gcc.info.gz ]; then + /sbin/install-info \ + --info-dir=%{_infodir} %{_infodir}/gcc.info.gz || : +fi + +%preun +if [ $1 = 0 -a -f %{_infodir}/gcc.info.gz ]; then + /sbin/install-info --delete \ + --info-dir=%{_infodir} %{_infodir}/gcc.info.gz || : +fi + +%post -n cpp +if [ -f %{_infodir}/cpp.info.gz ]; then + /sbin/install-info \ + --info-dir=%{_infodir} %{_infodir}/cpp.info.gz || : +fi + +%preun -n cpp +if [ $1 = 0 -a -f %{_infodir}/cpp.info.gz ]; then + /sbin/install-info --delete \ + --info-dir=%{_infodir} %{_infodir}/cpp.info.gz || : +fi + +#%post gfortran +#if [ -f %{_infodir}/gfortran.info.gz ]; then +# /sbin/install-info \ +# --info-dir=%{_infodir} %{_infodir}/gfortran.info.gz || : +#fi + +#%preun gfortran +#if [ $1 = 0 -a -f %{_infodir}/gfortran.info.gz ]; then +# /sbin/install-info --delete \ +# --info-dir=%{_infodir} %{_infodir}/gfortran.info.gz || : +#fi + +#%post java +#if [ -f %{_infodir}/gcj.info.gz ]; then +#/sbin/install-info \ +# --info-dir=%{_infodir} %{_infodir}/gcj.info.gz || : +#fi + +#%preun java +#if [ $1 = 0 -a -f %{_infodir}/gcj.info.gz ]; then +# /sbin/install-info --delete \ +# --info-dir=%{_infodir} %{_infodir}/gcj.info.gz || : +#fi + +#%post gnat +#if [ -f %{_infodir}/gnat_rm.info.gz ]; then +# /sbin/install-info \ +# --info-dir=%{_infodir} %{_infodir}/gnat_rm.info.gz || : +# /sbin/install-info \ +# --info-dir=%{_infodir} %{_infodir}/gnat_ugn.info.gz || : +# /sbin/install-info \ +# --info-dir=%{_infodir} %{_infodir}/gnat-style.info.gz || : +#fi + +#%preun gnat +#if [ $1 = 0 -a -f %{_infodir}/gnat_rm.info.gz ]; then +# /sbin/install-info --delete \ +# --info-dir=%{_infodir} %{_infodir}/gnat_rm.info.gz || : +# /sbin/install-info --delete \ +# --info-dir=%{_infodir} %{_infodir}/gnat_ugn.info.gz || : +# /sbin/install-info --delete \ +# --info-dir=%{_infodir} %{_infodir}/gnat-style.info.gz || : +#fi + +# Because glibc Prereq's libgcc and /sbin/ldconfig +# comes from glibc, it might not exist yet when +# libgcc is installed +#%post -n libgcc -p +#if posix.access ("/sbin/ldconfig", "x") then +# local pid = posix.fork () +# if pid == 0 then +# posix.exec ("/sbin/ldconfig") +# elseif pid ~= -1 then +# posix.wait (pid) +# end +#end + +#%postun -n libgcc -p +#if posix.access ("/sbin/ldconfig", "x") then +# local pid = posix.fork () +# if pid == 0 then +# posix.exec ("/sbin/ldconfig") +# elseif pid ~= -1 then +# posix.wait (pid) +# end +#end + +%post -n libstdc++ -p /sbin/ldconfig + +%postun -n libstdc++ -p /sbin/ldconfig + +#%post -n libobjc -p /sbin/ldconfig + +#%postun -n libobjc -p /sbin/ldconfig + +#%post -n libgcj +#/sbin/ldconfig +#if [ -f %{_infodir}/cp-tools.info.gz ]; then +# /sbin/install-info \ +# --info-dir=%{_infodir} %{_infodir}/cp-tools.info.gz || : +# /sbin/install-info \ +# --info-dir=%{_infodir} %{_infodir}/fastjar.info.gz || : +#fi + +#%preun -n libgcj +#if [ $1 = 0 -a -f %{_infodir}/cp-tools.info.gz ]; then +# /sbin/install-info --delete \ +# --info-dir=%{_infodir} %{_infodir}/cp-tools.info.gz || : +# /sbin/install-info --delete \ +# --info-dir=%{_infodir} %{_infodir}/fastjar.info.gz || : +#fi + +#%postun -n libgcj -p /sbin/ldconfig + +#%post -n libgfortran -p /sbin/ldconfig + +#%postun -n libgfortran -p /sbin/ldconfig + +#%post -n libgnat -p /sbin/ldconfig + +#%postun -n libgnat -p /sbin/ldconfig + +%post -n libgomp +/sbin/ldconfig +if [ -f %{_infodir}/libgomp.info.gz ]; then + /sbin/install-info \ + --info-dir=%{_infodir} %{_infodir}/libgomp.info.gz || : +fi + +%preun -n libgomp +if [ $1 = 0 -a -f %{_infodir}/libgomp.info.gz ]; then + /sbin/install-info --delete \ + --info-dir=%{_infodir} %{_infodir}/libgomp.info.gz || : +fi + +%postun -n libgomp -p /sbin/ldconfig + +#%post -n libmudflap -p /sbin/ldconfig + +#%postun -n libmudflap -p /sbin/ldconfig + +#%post -n libquadmath +#/sbin/ldconfig +#if [ -f %{_infodir}/libquadmath.info.gz ]; then +# /sbin/install-info \ +# --info-dir=%{_infodir} %{_infodir}/libquadmath.info.gz || : +#fi + +#%preun -n libquadmath +#if [ $1 = 0 -a -f %{_infodir}/libquadmath.info.gz ]; then +# /sbin/install-info --delete \ +# --info-dir=%{_infodir} %{_infodir}/libquadmath.info.gz || : +#fi + +#%postun -n libquadmath -p /sbin/ldconfig + +#%post -n libitm +#/sbin/ldconfig +#if [ -f %{_infodir}/libitm.info.gz ]; then +# /sbin/install-info \ +# --info-dir=%{_infodir} %{_infodir}/libitm.info.gz || : +#fi + +#%preun -n libitm +#if [ $1 = 0 -a -f %{_infodir}/libitm.info.gz ]; then +# /sbin/install-info --delete \ +# --info-dir=%{_infodir} %{_infodir}/libitm.info.gz || : +#fi + +#%postun -n libitm -p /sbin/ldconfig + +#%post -n libatomic -p /sbin/ldconfig + +#%postun -n libatomic -p /sbin/ldconfig + +#%post -n libasan -p /sbin/ldconfig + +#%postun -n libasan -p /sbin/ldconfig + +#%post -n libtsan -p /sbin/ldconfig + +#%postun -n libtsan -p /sbin/ldconfig + +#%post -n libgo -p /sbin/ldconfig + +#%postun -n libgo -p /sbin/ldconfig + +%files -f %{name}.lang +%defattr(-,root,root,-) +%{_prefix}/bin/cc +%{_prefix}/bin/c89 +%{_prefix}/bin/c99 +%{_prefix}/bin/gcc +%{_prefix}/bin/gcov +%{_prefix}/bin/gcc-ar +%{_prefix}/bin/gcc-nm +%{_prefix}/bin/gcc-ranlib +%ifarch ppc +%{_prefix}/bin/%{_target_platform}-gcc +%endif +%ifarch sparc64 sparcv9 +%{_prefix}/bin/sparc-%{_vendor}-%{_target_os}-gcc +%endif +%ifarch ppc64 ppc64p7 +%{_prefix}/bin/ppc-%{_vendor}-%{_target_os}-gcc +%endif +%{_prefix}/bin/%{gcc_target_platform}-gcc +%{_mandir}/man1/gcc.1* +%{_mandir}/man1/gcov.1* +%{_infodir}/gcc* +%dir %{_prefix}/lib/gcc +%dir %{_prefix}/lib/gcc/%{gcc_target_platform} +%dir %{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_version} +%if "%{version}" != "%{gcc_version}" +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{version} +%endif +%dir %{_prefix}/libexec/gcc +%dir %{_prefix}/libexec/gcc/%{gcc_target_platform} +%dir %{_prefix}/libexec/gcc/%{gcc_target_platform}/%{gcc_version} +%dir %{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_version}/include +%if "%{version}" != "%{gcc_version}" +%{_prefix}/libexec/gcc/%{gcc_target_platform}/%{version} +%endif +%{_prefix}/libexec/gcc/%{gcc_target_platform}/%{gcc_version}/lto1 +%{_prefix}/libexec/gcc/%{gcc_target_platform}/%{gcc_version}/lto-wrapper +%{_prefix}/libexec/gcc/%{gcc_target_platform}/%{gcc_version}/liblto_plugin.so* +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_version}/rpmver +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_version}/include/stddef.h +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_version}/include/stdarg.h +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_version}/include/stdfix.h +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_version}/include/varargs.h +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_version}/include/float.h +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_version}/include/limits.h +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_version}/include/stdbool.h +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_version}/include/iso646.h +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_version}/include/syslimits.h +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_version}/include/unwind.h +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_version}/include/omp.h +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_version}/include/openacc.h +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_version}/include/stdint.h +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_version}/include/stdint-gcc.h +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_version}/include/stdalign.h +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_version}/include/stdnoreturn.h +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_version}/include/stdatomic.h +%ifarch %{ix86} x86_64 +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_version}/include/mmintrin.h +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_version}/include/xmmintrin.h +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_version}/include/emmintrin.h +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_version}/include/pmmintrin.h +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_version}/include/tmmintrin.h +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_version}/include/ammintrin.h +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_version}/include/smmintrin.h +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_version}/include/nmmintrin.h +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_version}/include/bmmintrin.h +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_version}/include/wmmintrin.h +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_version}/include/immintrin.h +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_version}/include/avxintrin.h +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_version}/include/x86intrin.h +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_version}/include/fma4intrin.h +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_version}/include/xopintrin.h +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_version}/include/lwpintrin.h +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_version}/include/popcntintrin.h +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_version}/include/bmiintrin.h +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_version}/include/tbmintrin.h +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_version}/include/ia32intrin.h +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_version}/include/avx2intrin.h +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_version}/include/bmi2intrin.h +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_version}/include/f16cintrin.h +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_version}/include/fmaintrin.h +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_version}/include/lzcntintrin.h +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_version}/include/rtmintrin.h +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_version}/include/xtestintrin.h +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_version}/include/adxintrin.h +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_version}/include/prfchwintrin.h +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_version}/include/rdseedintrin.h +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_version}/include/fxsrintrin.h +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_version}/include/xsaveintrin.h +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_version}/include/xsaveoptintrin.h +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_version}/include/mm_malloc.h +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_version}/include/mm3dnow.h +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_version}/include/cpuid.h +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_version}/include/cross-stdarg.h + +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_version}/include/avx5124fmapsintrin.h +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_version}/include/avx5124vnniwintrin.h +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_version}/include/avx512bwintrin.h +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_version}/include/avx512cdintrin.h +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_version}/include/avx512dqintrin.h +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_version}/include/avx512erintrin.h +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_version}/include/avx512fintrin.h +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_version}/include/avx512ifmaintrin.h +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_version}/include/avx512ifmavlintrin.h +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_version}/include/avx512pfintrin.h +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_version}/include/avx512vbmiintrin.h +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_version}/include/avx512vbmivlintrin.h +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_version}/include/avx512vlbwintrin.h +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_version}/include/avx512vldqintrin.h +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_version}/include/avx512vlintrin.h +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_version}/include/avx512vpopcntdqintrin.h +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_version}/include/cilk/cilk.h +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_version}/include/cilk/cilk_api.h +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_version}/include/cilk/cilk_api_linux.h +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_version}/include/cilk/cilk_stub.h +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_version}/include/cilk/cilk_undocumented.h +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_version}/include/cilk/common.h +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_version}/include/cilk/holder.h +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_version}/include/cilk/hyperobject_base.h +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_version}/include/cilk/metaprogramming.h +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_version}/include/cilk/reducer.h +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_version}/include/cilk/reducer_file.h +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_version}/include/cilk/reducer_list.h +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_version}/include/cilk/reducer_max.h +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_version}/include/cilk/reducer_min.h +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_version}/include/cilk/reducer_min_max.h +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_version}/include/cilk/reducer_opadd.h +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_version}/include/cilk/reducer_opand.h +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_version}/include/cilk/reducer_opmul.h +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_version}/include/cilk/reducer_opor.h +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_version}/include/cilk/reducer_opxor.h +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_version}/include/cilk/reducer_ostream.h +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_version}/include/cilk/reducer_string.h +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_version}/include/clflushoptintrin.h +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_version}/include/clwbintrin.h +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_version}/include/clzerointrin.h +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_version}/include/gcov.h +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_version}/include/mwaitxintrin.h +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_version}/include/pkuintrin.h +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_version}/include/quadmath.h +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_version}/include/quadmath_weak.h +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_version}/include/sgxintrin.h +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_version}/include/shaintrin.h +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_version}/include/xsavecintrin.h +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_version}/include/xsavesintrin.h +%endif +%ifarch ia64 +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_version}/include/ia64intrin.h +%endif +%ifarch ppc ppc64 ppc64le ppc64p7 +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_version}/include/ppc-asm.h +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_version}/include/altivec.h +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_version}/include/spe.h +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_version}/include/paired.h +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_version}/include/ppu_intrinsics.h +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_version}/include/si2vmx.h +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_version}/include/spu2vmx.h +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_version}/include/vec_types.h +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_version}/include/htmintrin.h +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_version}/include/htmxlintrin.h +%endif +%ifarch %{arm} +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_version}/include/unwind-arm-common.h +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_version}/include/mmintrin.h +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_version}/include/arm_neon.h +%endif +%ifarch aarch64 +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_version}/include/arm_neon.h +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_version}/include/arm_fp16.h +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_version}/include/arm_acle.h +%endif +%ifarch sparc sparcv9 sparc64 +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_version}/include/visintrin.h +%endif +%ifarch s390 s390x +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_version}/include/s390intrin.h +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_version}/include/htmintrin.h +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_version}/include/htmxlintrin.h +%endif +%if %{build_libasan} +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_version}/include/sanitizer +%endif +%{_prefix}/libexec/gcc/%{gcc_target_platform}/%{gcc_version}/collect2 +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_version}/crt*.o +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_version}/libgcc.a +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_version}/libgcov.a +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_version}/libgcc_eh.a +%ifnarch aarch64_ilp32 +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_version}/libgcc_s.so +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_version}/libgomp.spec +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_version}/libgomp.a +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_version}/libgomp.so +%if %{build_libitm} +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_version}/libitm.spec +%endif +%if %{build_cloog} +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_version}/libcloog-isl.so.* +%endif +%if %{build_libasan} +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_version}/libsanitizer.spec +%endif +%endif +%ifarch sparcv9 ppc +%dir %{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_version}/64 +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_version}/64/crt*.o +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_version}/64/libgcc.a +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_version}/64/libgcov.a +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_version}/64/libgcc_eh.a +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_version}/64/libgcc_s.so +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_version}/64/libgomp.a +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_version}/64/libgomp.so +#%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_version}/64/libmudflap.a +#%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_version}/64/libmudflapth.a +#%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_version}/64/libmudflap.so +#%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_version}/64/libmudflapth.so +%if %{build_libquadmath} +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_version}/64/libquadmath.a +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_version}/64/libquadmath.so +%endif +%if %{build_libitm} +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_version}/64/libitm.a +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_version}/64/libitm.so +%endif +%if %{build_libatomic} +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_version}/64/libatomic.a +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_version}/64/libatomic.so +%endif +%if %{build_libasan} +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_version}/64/libasan.a +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_version}/64/libasan.so +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_version}/64/libasan_preinit.o +%endif +%endif +%ifarch aarch64 aarch64_ilp32 +%if %{build_libilp32} +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_version}/ilp32/libgomp.a +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_version}/ilp32/libgomp.so +%endif +%endif +%ifarch %{multilib_64_archs} +%dir %{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_version}/32 +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_version}/32/crt*.o +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_version}/32/libgcc.a +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_version}/32/libgcov.a +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_version}/32/libgcc_eh.a +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_version}/32/libgcc_s.so +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_version}/32/libgomp.a +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_version}/32/libgomp.so +#%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_version}/32/libmudflap.a +#%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_version}/32/libmudflapth.a +#%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_version}/32/libmudflap.so +#%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_version}/32/libmudflapth.so +%if %{build_libquadmath} +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_version}/32/libquadmath.a +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_version}/32/libquadmath.so +%endif +%if %{build_libitm} +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_version}/32/libitm.a +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_version}/32/libitm.so +%endif +%if %{build_libatomic} +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_version}/32/libatomic.a +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_version}/32/libatomic.so +%endif +%if %{build_libasan} +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_version}/32/libasan.a +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_version}/32/libasan.so +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_version}/32/libasan_preinit.o +%endif +%endif +%ifarch sparcv9 sparc64 ppc ppc64 ppc64p7 +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_version}/libmudflap.a +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_version}/libmudflapth.a +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_version}/libmudflap.so +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_version}/libmudflapth.so +%if %{build_libquadmath} +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_version}/libquadmath.a +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_version}/libquadmath.so +%endif +%if %{build_libitm} +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_version}/libitm.a +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_version}/libitm.so +%endif +%if %{build_libatomic} +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_version}/libatomic.a +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_version}/libatomic.so +%endif +%if %{build_libasan} +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_version}/libasan.a +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_version}/libasan.so +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_version}/libasan_preinit.o +%endif +%if %{build_libtsan} +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_version}/libtsan.a +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_version}/libtsan.so +%endif +%else +%if %{build_libatomic} +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_version}/libatomic.so +%endif +%if %{build_libasan} +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_version}/libasan.so +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_version}/libasan_preinit.o +%endif +%if %{build_libtsan} +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_version}/libtsan.so +%endif +%endif +%ifarch aarch64 arch64_ilp32 +%if %{build_libilp32} +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_version}/ilp32/libgcc.a +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_version}/ilp32/libgcc_eh.a +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_version}/ilp32/crtfastmath.o +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_version}/ilp32/crtend.o +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_version}/ilp32/crtendS.o +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_version}/ilp32/crtbeginT.o +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_version}/ilp32/crtbegin.o +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_version}/ilp32/libgcov.a +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_version}/ilp32/crtbeginS.o +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_version}/ilp32/libgcc_s.so +%endif +%endif +%dir %{_prefix}/libexec/getconf +%{_prefix}/libexec/getconf/default +#%doc gcc/README* rpm.doc/changelogs/gcc/ChangeLog* gcc/COPYING* COPYING.RUNTIME + +%files -n cpp -f cpplib.lang +%defattr(-,root,root,-) +%{_prefix}/lib/cpp +%{_prefix}/bin/cpp +%{_mandir}/man1/cpp.1* +%{_infodir}/cpp* +%dir %{_prefix}/libexec/gcc +%dir %{_prefix}/libexec/gcc/%{gcc_target_platform} +%dir %{_prefix}/libexec/gcc/%{gcc_target_platform}/%{gcc_version} +%if "%{version}" != "%{gcc_version}" +%{_prefix}/libexec/gcc/%{gcc_target_platform}/%{version} +%endif +%{_prefix}/libexec/gcc/%{gcc_target_platform}/%{gcc_version}/cc1 + +%files -n libgcc +%defattr(-,root,root,-) +/%{_lib}/libgcc_s-%{version}-%{DATE}.so.1 +/%{_lib}/libgcc_s.so.1 +%doc gcc/COPYING* COPYING.RUNTIME + +%ifarch aarch64 +%if %{build_libilp32} +%files -n libgcc-32 +%defattr(-,root,root,-) +/libilp32/libgcc_s-%{version}-%{DATE}.so.1 +/libilp32/libgcc_s.so.1 +%endif +%endif + +%files c++ +%defattr(-,root,root,-) +%{_prefix}/bin/%{gcc_target_platform}-*++ +%{_prefix}/bin/g++ +%{_prefix}/bin/c++ +%{_mandir}/man1/g++.1* +%dir %{_prefix}/lib/gcc +%dir %{_prefix}/lib/gcc/%{gcc_target_platform} +%dir %{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_version} +%if "%{version}" != "%{gcc_version}" +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{version} +%endif +%dir %{_prefix}/libexec/gcc +%dir %{_prefix}/libexec/gcc/%{gcc_target_platform} +%dir %{_prefix}/libexec/gcc/%{gcc_target_platform}/%{gcc_version} +%if "%{version}" != "%{gcc_version}" +%{_prefix}/libexec/gcc/%{gcc_target_platform}/%{version} +%endif +%{_prefix}/libexec/gcc/%{gcc_target_platform}/%{gcc_version}/cc1plus +%ifarch sparcv9 ppc +%dir %{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_version}/64 +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_version}/64/libstdc++.so +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_version}/64/libstdc++.a +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_version}/64/libsupc++.a +%endif +%ifarch %{multilib_64_archs} +%dir %{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_version}/32 +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_version}/32/libstdc++.so +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_version}/32/libstdc++.a +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_version}/32/libsupc++.a +%endif +%ifarch aarch64 aarch64_ilp32 +%if %{build_libilp32} +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_version}/ilp32/libstdc++.so +%endif +%endif +%ifarch sparcv9 ppc %{multilib_64_archs} +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_version}/libstdc++.so +%endif +%ifarch sparcv9 sparc64 ppc ppc64 ppc64p7 +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_version}/libstdc++.a +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_version}/libsupc++.a +%endif +#%doc rpm.doc/changelogs/gcc/cp/ChangeLog* + +%files -n libstdc++ +%defattr(-,root,root,-) +%{_prefix}/%{_lib}/libstdc++.so.6* +%dir %{_datadir}/gdb +%dir %{_datadir}/gdb/auto-load +%dir %{_datadir}/gdb/auto-load/%{_prefix} +%dir %{_datadir}/gdb/auto-load/%{_prefix}/%{_lib}/ +%{_datadir}/gdb/auto-load/%{_prefix}/%{_lib}/libstdc*gdb.py* +%dir %{_prefix}/share/gcc-%{gcc_version} +%dir %{_prefix}/share/gcc-%{gcc_version}/python +%if "%{version}" != "%{gcc_version}" +%{_prefix}/share/gcc-%{version} +%endif +%{_prefix}/share/gcc-%{gcc_version}/python/libstdcxx + +%ifarch aarch64 +%if %{build_libilp32} +%files -n libstdc++-32 +%defattr(-,root,root,-) +%{_prefix}/libilp32/libstdc++.so.6* +%dir %{_datadir}/gdb/auto-load/%{_prefix}/libilp32/ +%{_datadir}/gdb/auto-load/%{_prefix}/libilp32/libstdc*gdb.py* +%endif +%endif + +%files -n libstdc++-devel +%defattr(-,root,root,-) +%dir %{_prefix}/include/c++ +%dir %{_prefix}/include/c++/%{gcc_version} +%if "%{version}" != "%{gcc_version}" +%{_prefix}/include/c++/%{version} +%endif +%{_prefix}/include/c++/%{gcc_version}/[^gjos]* +%{_prefix}/include/c++/%{gcc_version}/os* +%{_prefix}/include/c++/%{gcc_version}/op* +%{_prefix}/include/c++/%{gcc_version}/s[^u]* +%dir %{_prefix}/lib/gcc +%dir %{_prefix}/lib/gcc/%{gcc_target_platform} +%dir %{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_version} +%if "%{version}" != "%{gcc_version}" +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{version} +%endif +%ifnarch sparcv9 ppc %{multilib_64_archs} aarch64_ilp32 +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_version}/libstdc++.so +%endif +#%doc rpm.doc/changelogs/libstdc++-v3/ChangeLog* libstdc++-v3/README* + +%files -n libstdc++-static +%defattr(-,root,root,-) +%dir %{_prefix}/lib/gcc +%dir %{_prefix}/lib/gcc/%{gcc_target_platform} +%dir %{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_version} +%if "%{version}" != "%{gcc_version}" +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{version} +%endif +%ifarch sparcv9 ppc +%dir %{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_version}/lib32 +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_version}/lib32/libstdc++.a +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_version}/lib32/libsupc++.a +%endif +%ifarch aarch64 aarch64_ilp32 +%if %{build_libilp32} +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_version}/ilp32/libstdc++.a +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_version}/ilp32/libsupc++.a +%endif +%endif +%ifarch sparc64 ppc64 ppc64p7 +%dir %{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_version}/lib64 +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_version}/lib64/libstdc++.a +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_version}/lib64/libsupc++.a +%endif +%ifnarch sparcv9 sparc64 ppc ppc64 ppc64p7 aarch64_ilp32 +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_version}/libstdc++.a +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_version}/libsupc++.a +%endif + +%if %{build_libstdcxx_docs} +%files -n libstdc++-docs +%defattr(-,root,root) +%{_mandir}/man3/* +%doc rpm.doc/libstdc++-v3/html +%endif + + +%files objc +%defattr(-,root,root,-) +%dir %{_prefix}/lib/gcc +%dir %{_prefix}/lib/gcc/%{gcc_target_platform} +%dir %{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_version} +%if "%{version}" != "%{gcc_version}" +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{version} +%endif +%dir %{_prefix}/libexec/gcc +%dir %{_prefix}/libexec/gcc/%{gcc_target_platform} +%dir %{_prefix}/libexec/gcc/%{gcc_target_platform}/%{gcc_version} +%if "%{version}" != "%{gcc_version}" +%{_prefix}/libexec/gcc/%{gcc_target_platform}/%{version} +%endif +%dir %{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_version}/include +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_version}/include/objc +%{_prefix}/libexec/gcc/%{gcc_target_platform}/%{gcc_version}/cc1obj +%ifnarch aarch64_ilp32 +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_version}/libobjc.a +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_version}/libobjc.so +%endif +%ifarch sparcv9 ppc +%dir %{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_version}/64 +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_version}/64/libobjc.a +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_version}/64/libobjc.so +%endif +%ifarch %{multilib_64_archs} +%dir %{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_version}/32 +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_version}/32/libobjc.a +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_version}/32/libobjc.so +%endif +%ifarch aarch64 aarch64_ilp32 +%if %{build_libilp32} +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_version}/ilp32/libobjc.a +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_version}/ilp32/libobjc.so +%endif +%endif +#%doc rpm.doc/objc/* +#%doc libobjc/THREADS* rpm.doc/changelogs/libobjc/ChangeLog* + +%files objc++ +%defattr(-,root,root,-) +%dir %{_prefix}/libexec/gcc +%dir %{_prefix}/libexec/gcc/%{gcc_target_platform} +%dir %{_prefix}/libexec/gcc/%{gcc_target_platform}/%{gcc_version} +%if "%{version}" != "%{gcc_version}" +%{_prefix}/libexec/gcc/%{gcc_target_platform}/%{version} +%endif +%{_prefix}/libexec/gcc/%{gcc_target_platform}/%{gcc_version}/cc1objplus + +%files -n libobjc +%defattr(-,root,root,-) +%{_prefix}/%{_lib}/libobjc.so.4* + +%ifarch aarch64 +%if %{build_libilp32} +%files -n libobjc-32 +%defattr(-,root,root,-) +%{_prefix}/libilp32/libobjc.so.4* +%endif +%endif + +%files gfortran +%defattr(-,root,root,-) +%{_prefix}/bin/gfortran +%{_prefix}/bin/f95 +%{_mandir}/man1/gfortran.1* +%{_infodir}/gfortran* +%dir %{_prefix}/lib/gcc +%dir %{_prefix}/lib/gcc/%{gcc_target_platform} +%dir %{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_version} +%if "%{version}" != "%{gcc_version}" +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{version} +%endif +%dir %{_prefix}/libexec/gcc +%dir %{_prefix}/libexec/gcc/%{gcc_target_platform} +%dir %{_prefix}/libexec/gcc/%{gcc_target_platform}/%{gcc_version} +%if "%{version}" != "%{gcc_version}" +%{_prefix}/libexec/gcc/%{gcc_target_platform}/%{version} +%endif +%dir %{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_version}/finclude +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_version}/finclude/omp_lib.h +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_version}/finclude/omp_lib.f90 +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_version}/finclude/omp_lib.mod +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_version}/finclude/omp_lib_kinds.mod +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_version}/finclude/openacc.f90 +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_version}/finclude/openacc.mod +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_version}/finclude/openacc_kinds.mod +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_version}/finclude/openacc_lib.h +%ifarch x86_64 +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_version}/finclude/ieee_arithmetic.mod +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_version}/finclude/ieee_exceptions.mod +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_version}/finclude/ieee_features.mod +%endif +%{_prefix}/libexec/gcc/%{gcc_target_platform}/%{gcc_version}/f951 +%ifnarch aarch64_ilp32 +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_version}/libgfortran.spec +#%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_version}/libgfortranbegin.a +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_version}/libcaf_single.a +%ifarch sparcv9 sparc64 ppc ppc64 ppc64p7 +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_version}/libgfortran.a +%endif +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_version}/libgfortran.so +%endif +%ifarch sparcv9 ppc +%dir %{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_version}/64 +#%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_version}/64/libgfortranbegin.a +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_version}/64/libcaf_single.a +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_version}/64/libgfortran.a +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_version}/64/libgfortran.so +%endif +%ifarch %{multilib_64_archs} +%dir %{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_version}/32 +#%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_version}/32/libgfortranbegin.a +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_version}/32/libcaf_single.a +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_version}/32/libgfortran.a +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_version}/32/libgfortran.so +%endif +%ifarch aarch64 aarch64_ilp32 +%if %{build_libilp32} +#%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_version}/ilp32/libgfortranbegin.a +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_version}/ilp32/libcaf_single.a +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_version}/ilp32/libgfortran.a +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_version}/ilp32/libgfortran.so +%endif +%endif +#%doc rpm.doc/gfortran/* + +%files -n libgfortran +%defattr(-,root,root,-) +%{_prefix}/%{_lib}/libgfortran.so.4* + +%ifarch aarch64 +%if %{build_libilp32} +%files -n libgfortran-32 +%defattr(-,root,root,-) +%{_prefix}/libilp32/libgfortran.so.4* +%endif +%endif + +%if 0 +%files -n libgfortran-static +%defattr(-,root,root,-) +%dir %{_prefix}/lib/gcc +%dir %{_prefix}/lib/gcc/%{gcc_target_platform} +%dir %{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_version} +%if "%{version}" != "%{gcc_version}" +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{version} +%endif +%ifarch sparcv9 ppc +%dir %{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_version}/lib32 +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_version}/lib32/libgfortran.a +%endif +%ifarch sparc64 ppc64 ppc64p7 +%dir %{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_version}/lib64 +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_version}/lib64/libgfortran.a +%endif +%ifnarch sparcv9 sparc64 ppc ppc64 ppc64p7 +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_version}/libgfortran.a +%endif +%endif + +%if %{build_java} +%files java +%defattr(-,root,root,-) +%{_prefix}/bin/gcj +%{_prefix}/bin/gjavah +%{_prefix}/bin/gcjh +%{_prefix}/bin/jcf-dump +%{_mandir}/man1/gcj.1* +%{_mandir}/man1/jcf-dump.1* +%{_mandir}/man1/gjavah.1* +%{_mandir}/man1/gcjh.1* +%{_infodir}/gcj* +%dir %{_prefix}/libexec/gcc +%dir %{_prefix}/libexec/gcc/%{gcc_target_platform} +%dir %{_prefix}/libexec/gcc/%{gcc_target_platform}/%{gcc_version} +%if "%{version}" != "%{gcc_version}" +%{_prefix}/libexec/gcc/%{gcc_target_platform}/%{version} +%endif +%dir %{_prefix}/lib/gcc +%dir %{_prefix}/lib/gcc/%{gcc_target_platform} +%dir %{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_version} +%if "%{version}" != "%{gcc_version}" +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{version} +%endif +%{_prefix}/libexec/gcc/%{gcc_target_platform}/%{gcc_version}/jc1 +%{_prefix}/libexec/gcc/%{gcc_target_platform}/%{gcc_version}/ecj1 +%{_prefix}/libexec/gcc/%{gcc_target_platform}/%{gcc_version}/jvgenmain +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_version}/libgcj.so +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_version}/libgcj-tools.so +%ifarch sparcv9 sparc64 ppc ppc64 ppc64p7 +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_version}/libgcj_bc.so +%endif +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_version}/libgij.so +%ifarch sparcv9 ppc +%dir %{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_version}/64 +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_version}/64/libgcj.so +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_version}/64/libgcj-tools.so +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_version}/64/libgcj_bc.so +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_version}/64/libgij.so +%endif +%ifarch %{multilib_64_archs} +%dir %{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_version}/32 +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_version}/32/libgcj.so +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_version}/32/libgcj-tools.so +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_version}/32/libgcj_bc.so +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_version}/32/libgij.so +%endif +#%doc rpm.doc/changelogs/gcc/java/ChangeLog* + +%files -n libgcj +%defattr(-,root,root,-) +%{_prefix}/bin/jv-convert +%{_prefix}/bin/gij +%{_prefix}/bin/gjar +%{_prefix}/bin/fastjar +%{_prefix}/bin/gnative2ascii +%{_prefix}/bin/grepjar +%{_prefix}/bin/grmic +%{_prefix}/bin/grmid +%{_prefix}/bin/grmiregistry +%{_prefix}/bin/gtnameserv +%{_prefix}/bin/gkeytool +%{_prefix}/bin/gorbd +%{_prefix}/bin/gserialver +%{_prefix}/bin/gcj-dbtool +%{_prefix}/bin/gjarsigner +%{_mandir}/man1/fastjar.1* +%{_mandir}/man1/grepjar.1* +%{_mandir}/man1/gjar.1* +%{_mandir}/man1/gjarsigner.1* +%{_mandir}/man1/jv-convert.1* +%{_mandir}/man1/gij.1* +%{_mandir}/man1/gnative2ascii.1* +%{_mandir}/man1/grmic.1* +%{_mandir}/man1/grmiregistry.1* +%{_mandir}/man1/gcj-dbtool.1* +%{_mandir}/man1/gkeytool.1* +%{_mandir}/man1/gorbd.1* +%{_mandir}/man1/grmid.1* +%{_mandir}/man1/gserialver.1* +%{_mandir}/man1/gtnameserv.1* +%{_infodir}/fastjar.info* +%{_infodir}/cp-tools.info* +%{_prefix}/%{_lib}/libgcj.so.* +%{_prefix}/%{_lib}/libgcj-tools.so.* +%{_prefix}/%{_lib}/libgcj_bc.so.* +%{_prefix}/%{_lib}/libgij.so.* +%dir %{_prefix}/%{_lib}/gcj-%{gcc_version} +%if "%{version}" != "%{gcc_version}" +%{_prefix}/%{_lib}/gcj-%{version} +%endif +%{_prefix}/%{_lib}/gcj-%{gcc_version}/libgtkpeer.so +%{_prefix}/%{_lib}/gcj-%{gcc_version}/libgjsmalsa.so +%{_prefix}/%{_lib}/gcj-%{gcc_version}/libjawt.so +%{_prefix}/%{_lib}/gcj-%{gcc_version}/libjvm.so +%{_prefix}/%{_lib}/gcj-%{gcc_version}/libjavamath.so +%dir %{_prefix}/share/java +%{_prefix}/share/java/[^sl]* +%{_prefix}/share/java/libgcj-%{gcc_version}.jar +%if "%{version}" != "%{gcc_version}" +%{_prefix}/share/java/libgcj-%{version}.jar +%endif +%dir %{_prefix}/%{_lib}/security +%config(noreplace) %{_prefix}/%{_lib}/security/classpath.security +%{_prefix}/%{_lib}/logging.properties +%dir %{_prefix}/%{_lib}/gcj-%{gcc_version}/classmap.db.d +%attr(0644,root,root) %verify(not md5 size mtime) %ghost %config(missingok,noreplace) %{_prefix}/%{_lib}/gcj-%{gcc_version}/classmap.db + +%files -n libgcj-devel +%defattr(-,root,root,-) +%dir %{_prefix}/lib/gcc +%dir %{_prefix}/lib/gcc/%{gcc_target_platform} +%dir %{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_version} +%if "%{version}" != "%{gcc_version}" +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{version} +%endif +%dir %{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_version}/include +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_version}/include/gcj +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_version}/include/jawt.h +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_version}/include/jawt_md.h +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_version}/include/jni.h +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_version}/include/jni_md.h +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_version}/include/jvmpi.h +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_version}/libgcj.spec +%ifarch sparcv9 ppc +%dir %{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_version}/lib32 +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_version}/lib32/libgcj_bc.so +%endif +%ifarch sparc64 ppc64 ppc64p7 +%dir %{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_version}/lib64 +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_version}/lib64/libgcj_bc.so +%endif +%ifnarch sparcv9 sparc64 ppc ppc64 ppc64p7 +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_version}/libgcj_bc.so +%endif +%dir %{_prefix}/include/c++ +%dir %{_prefix}/include/c++/%{gcc_version} +%if "%{version}" != "%{gcc_version}" +%{_prefix}/include/c++/%{version} +%endif +%{_prefix}/include/c++/%{gcc_version}/[gj]* +%{_prefix}/include/c++/%{gcc_version}/org +%{_prefix}/include/c++/%{gcc_version}/sun +%{_prefix}/%{_lib}/pkgconfig/libgcj-*.pc +%doc rpm.doc/boehm-gc/* rpm.doc/fastjar/* rpm.doc/libffi/* +%doc rpm.doc/libjava/* + +%files -n libgcj-src +%defattr(-,root,root,-) +%dir %{_prefix}/share/java +%{_prefix}/share/java/src*.zip +%{_prefix}/share/java/libgcj-tools-%{gcc_version}.jar +%if "%{version}" != "%{gcc_version}" +%{_prefix}/share/java/libgcj-tools-%{version}.jar +%endif +%endif + +%if %{build_ada} +%files gnat +%defattr(-,root,root,-) +%{_prefix}/bin/gnat +%{_prefix}/bin/gnat[^i]* +%{_infodir}/gnat* +%dir %{_prefix}/lib/gcc +%dir %{_prefix}/lib/gcc/%{gcc_target_platform} +%dir %{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_version} +%if "%{version}" != "%{gcc_version}" +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{version} +%endif +%dir %{_prefix}/libexec/gcc +%dir %{_prefix}/libexec/gcc/%{gcc_target_platform} +%dir %{_prefix}/libexec/gcc/%{gcc_target_platform}/%{gcc_version} +%if "%{version}" != "%{gcc_version}" +%{_prefix}/libexec/gcc/%{gcc_target_platform}/%{version} +%endif +%ifarch sparcv9 ppc +%dir %{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_version}/64 +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_version}/64/adainclude +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_version}/64/adalib +%endif +%ifarch %{multilib_64_archs} +%dir %{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_version}/32 +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_version}/32/adainclude +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_version}/32/adalib +%endif +%ifarch sparcv9 sparc64 ppc ppc64 ppc64p7 +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_version}/adainclude +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_version}/adalib +%endif +%{_prefix}/libexec/gcc/%{gcc_target_platform}/%{gcc_version}/gnat1 +#%doc rpm.doc/changelogs/gcc/ada/ChangeLog* + +%files -n libgnat +%defattr(-,root,root,-) +%{_prefix}/%{_lib}/libgnat-*.so +%{_prefix}/%{_lib}/libgnarl-*.so + +%files -n libgnat-devel +%defattr(-,root,root,-) +%dir %{_prefix}/lib/gcc +%dir %{_prefix}/lib/gcc/%{gcc_target_platform} +%dir %{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_version} +%if "%{version}" != "%{gcc_version}" +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{version} +%endif +%ifarch sparcv9 ppc +%dir %{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_version}/lib32 +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_version}/lib32/adainclude +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_version}/lib32/adalib +%exclude %{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_version}/lib32/adalib/libgnat.a +%exclude %{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_version}/lib32/adalib/libgnarl.a +%endif +%ifarch sparc64 ppc64 ppc64p7 +%dir %{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_version}/lib64 +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_version}/lib64/adainclude +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_version}/lib64/adalib +%exclude %{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_version}/lib64/adalib/libgnat.a +%exclude %{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_version}/lib64/adalib/libgnarl.a +%endif +%ifnarch sparcv9 sparc64 ppc ppc64 ppc64p7 +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_version}/adainclude +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_version}/adalib +%exclude %{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_version}/adalib/libgnat.a +%exclude %{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_version}/adalib/libgnarl.a +%endif + +%files -n libgnat-static +%defattr(-,root,root,-) +%dir %{_prefix}/lib/gcc +%dir %{_prefix}/lib/gcc/%{gcc_target_platform} +%dir %{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_version} +%if "%{version}" != "%{gcc_version}" +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{version} +%endif +%ifarch sparcv9 ppc +%dir %{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_version}/lib32 +%dir %{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_version}/lib32/adalib +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_version}/lib32/adalib/libgnat.a +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_version}/lib32/adalib/libgnarl.a +%endif +%ifarch sparc64 ppc64 ppc64p7 +%dir %{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_version}/lib64 +%dir %{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_version}/lib64/adalib +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_version}/lib64/adalib/libgnat.a +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_version}/lib64/adalib/libgnarl.a +%endif +%ifnarch sparcv9 sparc64 ppc ppc64 ppc64p7 +%dir %{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_version}/adalib +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_version}/adalib/libgnat.a +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_version}/adalib/libgnarl.a +%endif +%endif + +%files -n libgomp +%defattr(-,root,root,-) +%{_prefix}/%{_lib}/libgomp.so.1* +%{_infodir}/libgomp.info* +#%doc rpm.doc/changelogs/libgomp/ChangeLog* + +%ifarch aarch64 +%if %{build_libilp32} +%files -n libgomp-32 +%defattr(-,root,root,-) +%{_prefix}/libilp32/libgomp.so.1* +%endif +%endif + +%if 0 +%files -n libmudflap +%defattr(-,root,root,-) +%{_prefix}/%{_lib}/libmudflap.so.0* +%{_prefix}/%{_lib}/libmudflapth.so.0* + +%files -n libmudflap-devel +%defattr(-,root,root,-) +%dir %{_prefix}/lib/gcc +%dir %{_prefix}/lib/gcc/%{gcc_target_platform} +%dir %{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_version} +%if "%{version}" != "%{gcc_version}" +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{version} +%endif +%dir %{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_version}/include +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_version}/include/mf-runtime.h +%ifnarch sparcv9 sparc64 ppc ppc64 ppc64p7 +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_version}/libmudflap.so +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_version}/libmudflapth.so +%endif +#%doc rpm.doc/changelogs/libmudflap/ChangeLog* + +%files -n libmudflap-static +%defattr(-,root,root,-) +%dir %{_prefix}/lib/gcc +%dir %{_prefix}/lib/gcc/%{gcc_target_platform} +%dir %{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_version} +%if "%{version}" != "%{gcc_version}" +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{version} +%endif +%ifarch sparcv9 ppc +%dir %{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_version}/lib32 +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_version}/lib32/libmudflap.a +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_version}/lib32/libmudflapth.a +%endif +%ifarch sparc64 ppc64 ppc64p7 +%dir %{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_version}/lib64 +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_version}/lib64/libmudflap.a +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_version}/lib64/libmudflapth.a +%endif +%ifnarch sparcv9 sparc64 ppc ppc64 ppc64p7 +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_version}/libmudflap.a +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_version}/libmudflapth.a +%endif +%endif + +%if %{build_libquadmath} +%files -n libquadmath +%defattr(-,root,root,-) +%{_prefix}/%{_lib}/libquadmath.so.0* +%{_infodir}/libquadmath.info* +#%%doc rpm.doc/libquadmath/COPYING* + +%files -n libquadmath-devel +%defattr(-,root,root,-) +%dir %{_prefix}/lib/gcc +%dir %{_prefix}/lib/gcc/%{gcc_target_platform} +%dir %{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_version} +%if "%{version}" != "%{gcc_version}" +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{version} +%endif +%dir %{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_version}/include +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_version}/include/quadmath.h +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_version}/include/quadmath_weak.h +%ifnarch sparcv9 sparc64 ppc ppc64 ppc64p7 +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_version}/libquadmath.so +%endif +#%doc rpm.doc/libquadmath/ChangeLog* + +%files -n libquadmath-static +%defattr(-,root,root,-) +%dir %{_prefix}/lib/gcc +%dir %{_prefix}/lib/gcc/%{gcc_target_platform} +%dir %{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_version} +%if "%{version}" != "%{gcc_version}" +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{version} +%endif +%ifarch sparcv9 ppc +%dir %{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_version}/lib32 +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_version}/lib32/libquadmath.a +%endif +%ifarch sparc64 ppc64 ppc64p7 +%dir %{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_version}/lib64 +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_version}/lib64/libquadmath.a +%endif +%ifnarch sparcv9 sparc64 ppc ppc64 ppc64p7 +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_version}/libquadmath.a +%endif +%endif + +%if %{build_libitm} +%files -n libitm +%defattr(-,root,root,-) +%{_prefix}/%{_lib}/libitm.so.1* +%{_infodir}/libitm.info* + +%files -n libitm-devel +%defattr(-,root,root,-) +%dir %{_prefix}/lib/gcc +%dir %{_prefix}/lib/gcc/%{gcc_target_platform} +%dir %{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_version} +%if "%{version}" != "%{gcc_version}" +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{version} +%endif +%dir %{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_version}/include +#%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_version}/include/itm.h +#%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_version}/include/itm_weak.h +%ifnarch sparcv9 sparc64 ppc ppc64 ppc64p7 +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_version}/libitm.so +%endif +#%doc rpm.doc/libitm/ChangeLog* + +%files -n libitm-static +%defattr(-,root,root,-) +%dir %{_prefix}/lib/gcc +%dir %{_prefix}/lib/gcc/%{gcc_target_platform} +%dir %{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_version} +%if "%{version}" != "%{gcc_version}" +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{version} +%endif +%ifarch sparcv9 ppc +%dir %{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_version}/lib32 +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_version}/lib32/libitm.a +%endif +%ifarch sparc64 ppc64 ppc64p7 +%dir %{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_version}/lib64 +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_version}/lib64/libitm.a +%endif +%ifnarch sparcv9 sparc64 ppc ppc64 ppc64p7 +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_version}/libitm.a +%endif +%endif + +%if %{build_libatomic} +%files -n libatomic +%defattr(-,root,root,-) +%{_prefix}/%{_lib}/libatomic.so.1* + +%files -n libatomic-static +%defattr(-,root,root,-) +%dir %{_prefix}/lib/gcc +%dir %{_prefix}/lib/gcc/%{gcc_target_platform} +%dir %{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_version} +%if "%{version}" != "%{gcc_version}" +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{version} +%endif +%ifarch sparcv9 ppc +%dir %{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_version}/lib32 +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_version}/lib32/libatomic.a +%endif +%ifarch sparc64 ppc64 ppc64p7 +%dir %{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_version}/lib64 +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_version}/lib64/libatomic.a +%endif +%ifnarch sparcv9 sparc64 ppc ppc64 ppc64p7 +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_version}/libatomic.a +%endif +#%doc rpm.doc/changelogs/libatomic/ChangeLog* +%endif + +%if %{build_libasan} +%files -n libasan +%defattr(-,root,root,-) +%{_prefix}/%{_lib}/libasan.so.4* + +%files -n libasan-static +%defattr(-,root,root,-) +%dir %{_prefix}/lib/gcc +%dir %{_prefix}/lib/gcc/%{gcc_target_platform} +%dir %{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_version} +%if "%{version}" != "%{gcc_version}" +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{version} +%endif +%ifarch sparcv9 ppc +%dir %{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_version}/lib32 +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_version}/lib32/libasan.a +%endif +%ifarch sparc64 ppc64 ppc64p7 +%dir %{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_version}/lib64 +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_version}/lib64/libasan.a +%endif +%ifnarch sparcv9 sparc64 ppc ppc64 ppc64p7 +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_version}/libasan.a +%endif +#%doc rpm.doc/changelogs/libsanitizer/ChangeLog* libsanitizer/LICENSE.TXT +%endif + +%if %{build_libtsan} +%files -n libtsan +%defattr(-,root,root,-) +%{_prefix}/%{_lib}/libtsan.so.0* + +%files -n libtsan-static +%defattr(-,root,root,-) +%dir %{_prefix}/lib/gcc +%dir %{_prefix}/lib/gcc/%{gcc_target_platform} +%dir %{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_version} +%if "%{version}" != "%{gcc_version}" +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{version} +%endif +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_version}/libtsan.a +#%doc rpm.doc/changelogs/libsanitizer/ChangeLog* libsanitizer/LICENSE.TXT +%endif + +%if %{build_go} +%files go +%defattr(-,root,root,-) +%{_prefix}/bin/gccgo +%{_mandir}/man1/gccgo.1* +%dir %{_prefix}/lib/gcc +%dir %{_prefix}/lib/gcc/%{gcc_target_platform} +%dir %{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_version} +%if "%{version}" != "%{gcc_version}" +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{version} +%endif +%dir %{_prefix}/libexec/gcc +%dir %{_prefix}/libexec/gcc/%{gcc_target_platform} +%dir %{_prefix}/libexec/gcc/%{gcc_target_platform}/%{gcc_version} +%if "%{version}" != "%{gcc_version}" +%{_prefix}/libexec/gcc/%{gcc_target_platform}/%{version} +%endif +%{_prefix}/libexec/gcc/%{gcc_target_platform}/%{gcc_version}/go1 +%ifarch sparcv9 ppc +%dir %{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_version}/64 +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_version}/64/libgo.so +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_version}/64/libgo.a +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_version}/64/libgobegin.a +%endif +%ifarch %{multilib_64_archs} +%dir %{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_version}/32 +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_version}/32/libgo.so +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_version}/32/libgo.a +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_version}/32/libgobegin.a +%endif +%ifarch sparcv9 ppc %{multilib_64_archs} +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_version}/libgo.so +%endif +%ifarch sparcv9 sparc64 ppc ppc64 ppc64p7 +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_version}/libgo.a +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_version}/libgobegin.a +%endif +%doc rpm.doc/go/* + +%files -n libgo +%defattr(-,root,root,-) +%{_prefix}/%{_lib}/libgo.so.4* +%doc rpm.doc/libgo/* + +%files -n libgo-devel +%defattr(-,root,root,-) +%dir %{_prefix}/lib/gcc +%dir %{_prefix}/lib/gcc/%{gcc_target_platform} +%dir %{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_version} +%dir %{_prefix}/%{_lib}/go +%dir %{_prefix}/%{_lib}/go/%{gcc_version} +%if "%{version}" != "%{gcc_version}" +%{_prefix}/%{_lib}/go/%{version} +%endif +%{_prefix}/%{_lib}/go/%{gcc_version}/%{gcc_target_platform} +%ifarch %{multilib_64_archs} +%ifnarch sparc64 ppc64 ppc64p7 +%dir %{_prefix}/lib/go +%dir %{_prefix}/lib/go/%{gcc_version} +%if "%{version}" != "%{gcc_version}" +%{_prefix}/lib/go/%{version} +%endif +%{_prefix}/lib/go/%{gcc_version}/%{gcc_target_platform} +%endif +%endif +%ifarch sparcv9 ppc +%dir %{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_version}/lib32 +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_version}/lib32/libgobegin.a +%endif +%ifarch sparc64 ppc64 ppc64p7 +%dir %{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_version}/lib64 +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_version}/lib64/libgobegin.a +%endif +%ifnarch sparcv9 sparc64 ppc ppc64 ppc64p7 +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_version}/libgobegin.a +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_version}/libgo.so +%endif + +%files -n libgo-static +%defattr(-,root,root,-) +%dir %{_prefix}/lib/gcc +%dir %{_prefix}/lib/gcc/%{gcc_target_platform} +%dir %{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_version} +%if "%{version}" != "%{gcc_version}" +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{version} +%endif +%ifarch sparcv9 ppc +%dir %{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_version}/lib32 +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_version}/lib32/libgo.a +%endif +%ifarch sparc64 ppc64 ppc64p7 +%dir %{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_version}/lib64 +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_version}/lib64/libgo.a +%endif +%ifnarch sparcv9 sparc64 ppc ppc64 ppc64p7 +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_version}/libgo.a +%endif +%endif + +%if 1 +%files plugin-devel +%defattr(-,root,root,-) +%dir %{_prefix}/lib/gcc +%dir %{_prefix}/lib/gcc/%{gcc_target_platform} +%dir %{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_version} +%if "%{version}" != "%{gcc_version}" +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{version} +%endif +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_version}/plugin +%dir %{_prefix}/libexec/gcc +%dir %{_prefix}/libexec/gcc/%{gcc_target_platform} +%dir %{_prefix}/libexec/gcc/%{gcc_target_platform}/%{gcc_version} +%if "%{version}" != "%{gcc_version}" +%{_prefix}/libexec/gcc/%{gcc_target_platform}/%{version} +%endif +%{_prefix}/libexec/gcc/%{gcc_target_platform}/%{gcc_version}/plugin +%endif + + + +%changelog +* Tue Dec 31 2019 openEuler Buildteam - 7.3.0-20190804.h30 +- Type:NA +- ID:NA +- SUG:NA +- DESC:delete unneeded requires + +* Mon Dec 30 2019 openEuler Buildteam - 7.3.0-20190804.h29 +- Type:NA +- ID:NA +- SUG:NA +- DESC:delete unneeded requires + +* Mon Dec 23 2019 openEuler Buildteam - 7.3.0-20190804.h28 +- Type:NA +- ID:NA +- SUG:NA +- DESC:delete unneeded info in changelog + +* Tue Dec 4 2019 guoge - 7.3.0-20190804.h27 +- Type:enhancement +- ID:NA +- SUG:NA +- DESC: delete some patches + +* Tue Dec 4 2019 guoge - 7.3.0-20190804.h26 +- Type:enhancement +- ID:NA +- SUG:NA +- DESC: update patches + +* Fri Nov 29 2019 jiangchuangang - 7.3.0-20190804.h25 +- Type:enhancement +- ID:NA +- SUG:NA +- DESC:revise gcc_target_platform + +* Thu Nov 14 2019 jiangchuangang - 7.3.0-20190804.h24 +- Type:enhancement +- ID:NA +- SUG:NA +- DESC:rename patch + +* Mon Nov 5 2019 jiangchuangang - 7.3.0-20190804.h23 +- Type:enhancement +- ID:NA +- SUG:NA +- DESC: revise gcc_target_platform + +* Mon Nov 5 2019 jiangchuangang - 7.3.0-20190804.h22 +- Type:enhancement +- ID:NA +- SUG:NA +- DESC:support for x86 architecture + +* Thu Oct 24 2019 shenyangyang 7.3.0-20190804.h21 +- Type:enhancement +- ID:NA +- SUG:NA +- DESC:add build requires of zlib-devel + +* Wed Oct 23 2019 shenyangyang 7.3.0-20190804.h20 +- Type:enhancement +- ID:NA +- SUG:NA +- DESC:delete %{?dist} + +* Wed Sep 11 2019 gaoyi - 7.3.0-20190804.h19 +- Type:enhancement +- ID:NA +- SUG:NA +- DESC: export extra_ldflags_libobjc for libobjc + +* Tue Sep 10 2019 gaoyi - 7.3.0-20190804.h18 +- Type:enhancement +- ID:NA +- SUG:NA +- DESC: export FCFLAGS for fortran to add SP + +* Mon Sep 09 2019 gaoyi - 7.3.0-20190804.h17 +- Type:bugfix +- ID:NA +- SUG:NA +- DESC: add CVE-2019-15847 + +* Sun Aug 04 2019 liufeng 7.3.0-20190804.h16 +- Type:enhancement +- ID:NA +- SUG:NA +- DESC: update gcc version + +* Tue Jun 5 2019 zoujing 7.3.0-20190601.h15 +- Type:enhancement +- ID:NA +- SUG:NA +- DESC: update gcc version + +* Fri May 31 2019 zoujing 7.3.0-20190515.h14 +- Type:enhancement +- ID:NA +- SUG:NA +- DESC: sync patch from compile + +* Tue May 21 2019 zoujing 7.3.0-20190515.h13 +- Type:enhancement +- ID:NA +- SUG:NA +- DESC: add libtsan + +* Fri May 17 2019 zoujing 7.3.0-20190515.h12 +- Type:enhancement +- ID:NA +- SUG:NA +- DESC: update gcc version + +* Mon May 13 2019 shenyining 7.3.0-20190316.h11 +- Type:enhancement +- ID:NA +- SUG:NA +- DESC:add sec compile option + +* Mon May 13 2019 yutianqi 7.3.0-20190316.h10 +- Type:enhancement +- ID:NA +- SUG:NA +- DESC:change gcc src to src and patch + +* Wed May 8 2019 luochunsheng 7.3.0-20190316.h9 +- Type:enhancement +- ID:NA +- SUG:NA +- DESC:remove sensitive information + +*Fri Apr 12 2019 liuxueping 7.3.0-20190316.h8 +- Type:NA +- ID:NA +- SUG:NA +- DESC: delete BuildRequires: -bep-env + +*Tue Mar 26 2019 zoujing 7.3.0-20190316.h7 +- Type:NA +- ID:NA +- SUG:NA +- DESC: update gcc-7.3.0 + +*Wed Mar 20 2019 zoujing 7.3.0-20190214.h6 +- Type:NA +- ID:NA +- SUG:NA +- DESC: revert add --disable-libstdcxx-dual-abi + +*Sat Mar 16 2019 zoujing 7.3.0-20190214.h5 +- Type:NA +- ID:NA +- SUG:NA +- DESC: revert add --disable-libstdcxx-dual-abi + +*Thu Mar 14 2019 zoujing 7.3.0-20190214.h4 +- Type:NA +- ID:NA +- SUG:NA +- DESC: add --disable-libstdcxx-dual-abi and some include files + +*Tue Mar 5 2019 zoujing 7.3.0-20190214.h3 +- Type:NA +- ID:NA +- SUG:NA +- DESC: add plugin-devel and optionial for compile + +* Mon Mar 1 2019 hexiaowen 7.3.0-20190214.h2 +- Type:NA +- ID:NA +- SUG:NA +- DESC: add plugin-devel and option + +* Tue Feb 26 2019 zoujing -1.h1 +- Type:NA +- ID:NA +- SUG:NA +- DESC: add libasan + +* Sun Feb 24 2019 zoujing +- Type:NA +- ID:NA +- SUG:NA +- DESC: remove -Werror=format-security + +* Thu Feb 21 2019 zoujing +- Type:NA +- ID:NA +- SUG:NA +- DESC:add libatomic and libitm packages on gcc 7.3.0 + +* Fri Feb 15 2019 zoujing +- Type:NA +- ID:NA +- SUG:NA +- DESC:update gcc-7.3.0 sourcecode + +* Fri Nov 11 2016 liupeifeng3@huawei.com +- gcc update 199192 +* Mon Aug 15 2016 wuhui3@huawei.com +- gcc update svn revision 197280 +* Fri Oct 23 2015 wuhui3@huawei.com +- add some +* Sat May 23 2015 john.wanghui@huawei.com +- create spec +* Sat May 23 2015 jiangjiji@huawei.com +- compile programs diff --git a/isl-0.14.tar.xz b/isl-0.14.tar.xz new file mode 100644 index 0000000..823478e Binary files /dev/null and b/isl-0.14.tar.xz differ diff --git a/mark-pattern-as-clobbering-CC-REGNUM.patch b/mark-pattern-as-clobbering-CC-REGNUM.patch new file mode 100644 index 0000000..b65621e --- /dev/null +++ b/mark-pattern-as-clobbering-CC-REGNUM.patch @@ -0,0 +1,13 @@ +diff -N -urp a/gcc/config/aarch64/aarch64.md b/gcc/config/aarch64/aarch64.md +--- a/gcc/config/aarch64/aarch64.md 2019-05-30 16:12:52.950606040 +0800 ++++ b/gcc/config/aarch64/aarch64.md 2019-05-30 16:15:56.606599549 +0800 +@@ -3110,7 +3110,8 @@ + (define_insn_and_split "*compare_cstore_insn" + [(set (match_operand:GPI 0 "register_operand" "=r") + (EQL:GPI (match_operand:GPI 1 "register_operand" "r") +- (match_operand:GPI 2 "aarch64_imm24" "n")))] ++ (match_operand:GPI 2 "aarch64_imm24" "n"))) ++ (clobber (reg:CC CC_REGNUM))] + "!aarch64_move_imm (INTVAL (operands[2]), mode) + && !aarch64_plus_operand (operands[2], mode) + && !reload_completed" diff --git a/option-mfentry-and-mlong-calls-bugfix.patch b/option-mfentry-and-mlong-calls-bugfix.patch new file mode 100644 index 0000000..c242567 --- /dev/null +++ b/option-mfentry-and-mlong-calls-bugfix.patch @@ -0,0 +1,108 @@ +diff -N -urp a/gcc/config/aarch64/aarch64.c b/gcc/config/aarch64/aarch64.c +--- a/gcc/config/aarch64/aarch64.c 2018-09-19 17:11:42.583520820 +0800 ++++ b/gcc/config/aarch64/aarch64.c 2018-09-19 17:10:22.715520820 +0800 +@@ -1260,29 +1260,32 @@ aarch64_is_long_call_p (rtx sym) + void + aarch64_function_profiler (FILE *file, int labelno ATTRIBUTE_UNUSED) + { +- if (!TARGET_LONG_CALLS) ++ if (flag_fentry) + { +- fprintf (file, "\tmov\tx9, x30\n"); +- fprintf (file, "\tbl\t__fentry__\n"); +- fprintf (file, "\tmov\tx30, x9\n"); +- } +- else +- { +- if (flag_pic) ++ if (!TARGET_LONG_CALLS) + { + fprintf (file, "\tmov\tx9, x30\n"); +- fprintf (file, "\tadrp\tx10, :got:__fentry__\n"); +- fprintf (file, "\tldr\tx10, [x10, #:got_lo12:__fentry__]\n"); +- fprintf (file, "\tblr\tx10\n"); ++ fprintf (file, "\tbl\t__fentry__\n"); + fprintf (file, "\tmov\tx30, x9\n"); + } + else + { +- fprintf (file, "\tmov\tx9, x30\n"); +- fprintf (file, "\tadrp\tx10, __fentry__\n"); +- fprintf (file, "\tadd\tx10, x10, :lo12:__fentry__\n"); +- fprintf (file, "\tblr\tx10\n"); +- fprintf (file, "\tmov\tx30, x9\n"); ++ if (flag_pic) ++ { ++ fprintf (file, "\tmov\tx9, x30\n"); ++ fprintf (file, "\tadrp\tx10, :got:__fentry__\n"); ++ fprintf (file, "\tldr\tx10, [x10, #:got_lo12:__fentry__]\n"); ++ fprintf (file, "\tblr\tx10\n"); ++ fprintf (file, "\tmov\tx30, x9\n"); ++ } ++ else ++ { ++ fprintf (file, "\tmov\tx9, x30\n"); ++ fprintf (file, "\tadrp\tx10, __fentry__\n"); ++ fprintf (file, "\tadd\tx10, x10, :lo12:__fentry__\n"); ++ fprintf (file, "\tblr\tx10\n"); ++ fprintf (file, "\tmov\tx30, x9\n"); ++ } + } + } + } +@@ -12020,6 +12023,15 @@ aarch64_emit_unlikely_jump (rtx insn) + add_int_reg_note (jump, REG_BR_PROB, very_unlikely); + } + ++/* Return true, if profiling code should be emitted before ++ prologue. Otherwise it returns false. ++ Note: For x86 with "hotfix" it is sorried. */ ++static bool ++aarch64_profile_before_prologue (void) ++{ ++ return flag_fentry != 0; ++} ++ + /* Expand a compare and swap pattern. */ + + void +@@ -14952,6 +14964,9 @@ aarch64_run_selftests (void) + #undef TARGET_ASM_ALIGNED_SI_OP + #define TARGET_ASM_ALIGNED_SI_OP "\t.word\t" + ++#undef TARGET_PROFILE_BEFORE_PROLOGUE ++#define TARGET_PROFILE_BEFORE_PROLOGUE aarch64_profile_before_prologue ++ + #undef TARGET_ASM_CAN_OUTPUT_MI_THUNK + #define TARGET_ASM_CAN_OUTPUT_MI_THUNK \ + hook_bool_const_tree_hwi_hwi_const_tree_true +diff -N -urp a/gcc/config/aarch64/aarch64.h b/gcc/config/aarch64/aarch64.h +--- a/gcc/config/aarch64/aarch64.h 2018-09-19 17:11:42.587520820 +0800 ++++ b/gcc/config/aarch64/aarch64.h 2018-09-19 17:10:22.715520820 +0800 +@@ -850,9 +850,12 @@ typedef struct + { \ + rtx fun, lr; \ + const rtx_insn* tmp = get_insns (); \ +- lr = get_hard_reg_initial_val (Pmode, LR_REGNUM); \ +- fun = gen_rtx_SYMBOL_REF (Pmode, MCOUNT_NAME); \ +- emit_library_call (fun, LCT_NORMAL, VOIDmode, 1, lr, Pmode); \ ++ if (!flag_fentry) \ ++ { \ ++ lr = get_hard_reg_initial_val (Pmode, LR_REGNUM); \ ++ fun = gen_rtx_SYMBOL_REF (Pmode, MCOUNT_NAME); \ ++ emit_library_call (fun, LCT_NORMAL, VOIDmode, 1, lr, Pmode); \ ++ } \ + if (TARGET_LONG_CALLS) \ + { \ + emit_insn (gen_blockage ()); \ +diff -N -urp a/gcc/config/aarch64/aarch64.opt b/gcc/config/aarch64/aarch64.opt +--- a/gcc/config/aarch64/aarch64.opt 2018-09-19 17:11:42.587520820 +0800 ++++ b/gcc/config/aarch64/aarch64.opt 2018-09-19 17:10:22.715520820 +0800 +@@ -192,3 +192,7 @@ single precision and to 32 bits for doub + mverbose-cost-dump + Common Undocumented Var(flag_aarch64_verbose_cost) + Enables verbose cost model dumping in the debug dump files. ++ ++mfentry ++Target Report Var(flag_fentry) Init(0) ++Emit profiling counter call at function entry immediately after prologue. diff --git a/option-mlong-calls.patch b/option-mlong-calls.patch new file mode 100644 index 0000000..7aadfbe --- /dev/null +++ b/option-mlong-calls.patch @@ -0,0 +1,362 @@ +diff -N -urp a/gcc/config/aarch64/aarch64-protos.h b/gcc/config/aarch64/aarch64-protos.h +--- a/gcc/config/aarch64/aarch64-protos.h 2018-11-06 10:43:27.862079389 +0800 ++++ b/gcc/config/aarch64/aarch64-protos.h 2018-11-06 10:44:34.930081154 +0800 +@@ -353,6 +353,10 @@ bool aarch64_use_return_insn_p (void); + const char *aarch64_mangle_builtin_type (const_tree); + const char *aarch64_output_casesi (rtx *); + ++extern void aarch64_pr_long_calls (struct cpp_reader *); ++extern void aarch64_pr_no_long_calls (struct cpp_reader *); ++extern void aarch64_pr_long_calls_off (struct cpp_reader *); ++ + enum aarch64_symbol_type aarch64_classify_symbol (rtx, rtx); + enum aarch64_symbol_type aarch64_classify_tls_symbol (rtx); + enum reg_class aarch64_regno_regclass (unsigned); +@@ -384,6 +388,7 @@ void aarch64_expand_epilogue (bool); + void aarch64_expand_mov_immediate (rtx, rtx); + void aarch64_expand_prologue (void); + void aarch64_expand_vector_init (rtx, rtx); ++void aarch64_function_profiler (FILE *, int); + void aarch64_init_cumulative_args (CUMULATIVE_ARGS *, const_tree, rtx, + const_tree, unsigned); + void aarch64_init_expanders (void); +diff -N -urp a/gcc/config/aarch64/aarch64.c b/gcc/config/aarch64/aarch64.c +--- a/gcc/config/aarch64/aarch64.c 2018-11-06 10:43:27.870079389 +0800 ++++ b/gcc/config/aarch64/aarch64.c 2018-11-06 10:44:34.934081154 +0800 +@@ -70,6 +70,9 @@ + /* This file should be included last. */ + #include "target-def.h" + ++static void aarch64_set_default_type_attributes (tree); ++static int aarch64_comp_type_attributes (const_tree, const_tree); ++ + /* Defined for convenience. */ + #define POINTER_BYTES (POINTER_SIZE / BITS_PER_UNIT) + +@@ -1092,12 +1095,163 @@ aarch64_hard_regno_caller_save_mode (uns + return choose_hard_reg_mode (regno, nregs, false); + } + ++/* Table of machine attributes. */ ++static const struct attribute_spec aarch64_attribute_table[] = ++{ ++ /* { name, min_len, max_len, decl_req, type_req, fn_type_req, handler, ++ affects_type_identity }. */ ++ /* Function calls made to this symbol must be done indirectly, because ++ it may lie outside of the 26 bit addressing range of a normal function ++ call. */ ++ { "long_call", 0, 0, false, true, true, NULL, false }, ++ /* Whereas these functions are always known to reside within the 26 bit ++ addressing range. */ ++ { "short_call", 0, 0, false, true, true, NULL, false }, ++ { NULL, 0, 0, false, false, false, NULL, false } ++}; ++ ++/* Encode the current state of the #pragma[no_]long_calls. */ ++typedef enum ++{ ++ OFF, /* No #pragma[no_]long_calls is in effect. */ ++ LONG, /* #pragma long_calls is in effect. */ ++ SHORT /* #pragma no_long_calls is in effect. */ ++} aarch64_pragma_enum; ++ ++static aarch64_pragma_enum aarch64_pragma_long_calls = OFF; ++ ++void ++aarch64_pr_long_calls (struct cpp_reader * pfile ATTRIBUTE_UNUSED) ++{ ++ aarch64_pragma_long_calls = LONG; ++} ++ ++void ++aarch64_pr_no_long_calls (struct cpp_reader * pfile ATTRIBUTE_UNUSED) ++{ ++ aarch64_pragma_long_calls = SHORT; ++} ++ ++void ++aarch64_pr_long_calls_off (struct cpp_reader * pfile ATTRIBUTE_UNUSED) ++{ ++ aarch64_pragma_long_calls = OFF; ++} ++ ++/* Return 0 if the attributes for two types are incompatible, 1 if they ++ are compatible. */ ++static int ++aarch64_comp_type_attributes (const_tree type1, const_tree type2) ++{ ++ int l1, l2, s1, s2; ++ ++ /* Check for mismatch of non-default calling convention. */ ++ if (TREE_CODE (type1) != FUNCTION_TYPE) ++ return 1; ++ ++ /* Check for mismatched call attributes. */ ++ l1 = lookup_attribute ("long_call", TYPE_ATTRIBUTES (type1)) != NULL; ++ l2 = lookup_attribute ("long_call", TYPE_ATTRIBUTES (type2)) != NULL; ++ s1 = lookup_attribute ("short_call", TYPE_ATTRIBUTES (type1)) != NULL; ++ s2 = lookup_attribute ("short_call", TYPE_ATTRIBUTES (type2)) != NULL; ++ ++ /* Only bother to check if an attribute is defined. */ ++ if (l1 | l2 | s1 | s2) ++ { ++ /* If one type has an attribute, the other ++ must have the same attribute. */ ++ if ((l1 != l2) || (s1 != s2)) ++ { ++ return 0; ++ } ++ ++ /* Disallow mixed attributes. */ ++ if ((l1 && s2) || (l2 && s1)) ++ { ++ return 0; ++ } ++ } ++ ++ return 1; ++} ++ ++/* Assigns default attributes to newly defined type. This is used to ++ set short_call/long_call attributes for function types of ++ functions defined inside corresponding #pragma scopes. */ ++static void ++aarch64_set_default_type_attributes (tree type) ++{ ++ /* Add __attribute__ ((long_call)) to all functions, when ++ inside #pragma long_calls or __attribute__ ((short_call)), ++ when inside #pragma no_long_calls. */ ++ if (TREE_CODE (type) == FUNCTION_TYPE || TREE_CODE (type) == METHOD_TYPE) ++ { ++ tree type_attr_list = NULL; ++ tree attr_name = NULL; ++ type_attr_list = TYPE_ATTRIBUTES (type); ++ ++ if (aarch64_pragma_long_calls == LONG) ++ { ++ attr_name = get_identifier ("long_call"); ++ } ++ else if (aarch64_pragma_long_calls == SHORT) ++ { ++ attr_name = get_identifier ("short_call"); ++ } ++ else ++ { ++ return; ++ } ++ ++ type_attr_list = tree_cons (attr_name, NULL_TREE, type_attr_list); ++ TYPE_ATTRIBUTES (type) = type_attr_list; ++ } ++} ++ ++/* Return true if DECL is known to be linked into section SECTION. */ ++static bool ++aarch64_function_in_section_p (tree decl, section *section) ++{ ++ /* We can only be certain about the prevailing symbol definition. */ ++ if (!decl_binds_to_current_def_p (decl)) ++ return false; ++ ++ /* If DECL_SECTION_NAME is set, assume it is trustworthy. */ ++ if (!DECL_SECTION_NAME (decl)) ++ { ++ /* Make sure that we will not create a unique section for DECL. */ ++ if (flag_function_sections || DECL_COMDAT_GROUP (decl)) ++ return false; ++ } ++ ++ return function_section (decl) == section; ++} ++ + /* Return true if calls to DECL should be treated as + long-calls (ie called via a register). */ + static bool +-aarch64_decl_is_long_call_p (const_tree decl ATTRIBUTE_UNUSED) ++aarch64_decl_is_long_call_p (tree decl) + { +- return false; ++ tree attrs = NULL; ++ ++ if (!decl) ++ return TARGET_LONG_CALLS; ++ ++ attrs = TYPE_ATTRIBUTES (TREE_TYPE (decl)); ++ if (lookup_attribute ("short_call", attrs)) ++ return false; ++ ++ /* For "f", be conservative, and only cater for cases in which the ++ whole of the current function is placed in the same section. */ ++ if (!flag_reorder_blocks_and_partition ++ && TREE_CODE (decl) == FUNCTION_DECL ++ && aarch64_function_in_section_p (decl, current_function_section ())) ++ return false; ++ ++ if (lookup_attribute ("long_call", attrs)) ++ return true; ++ ++ return TARGET_LONG_CALLS; + } + + /* Return true if calls to symbol-ref SYM should be treated as +@@ -1108,6 +1257,36 @@ aarch64_is_long_call_p (rtx sym) + return aarch64_decl_is_long_call_p (SYMBOL_REF_DECL (sym)); + } + ++void ++aarch64_function_profiler (FILE *file, int labelno ATTRIBUTE_UNUSED) ++{ ++ if (!TARGET_LONG_CALLS) ++ { ++ fprintf (file, "\tmov\tx9, x30\n"); ++ fprintf (file, "\tbl\t__fentry__\n"); ++ fprintf (file, "\tmov\tx30, x9\n"); ++ } ++ else ++ { ++ if (flag_pic) ++ { ++ fprintf (file, "\tmov\tx9, x30\n"); ++ fprintf (file, "\tadrp\tx10, :got:__fentry__\n"); ++ fprintf (file, "\tldr\tx10, [x10, #:got_lo12:__fentry__]\n"); ++ fprintf (file, "\tblr\tx10\n"); ++ fprintf (file, "\tmov\tx30, x9\n"); ++ } ++ else ++ { ++ fprintf (file, "\tmov\tx9, x30\n"); ++ fprintf (file, "\tadrp\tx10, __fentry__\n"); ++ fprintf (file, "\tadd\tx10, x10, :lo12:__fentry__\n"); ++ fprintf (file, "\tblr\tx10\n"); ++ fprintf (file, "\tmov\tx30, x9\n"); ++ } ++ } ++} ++ + /* Return true if calls to symbol-ref SYM should not go through + plt stubs. */ + +@@ -15099,6 +15278,15 @@ aarch64_libgcc_floating_mode_supported_p + #undef TARGET_SCHED_CAN_SPECULATE_INSN + #define TARGET_SCHED_CAN_SPECULATE_INSN aarch64_sched_can_speculate_insn + ++#undef TARGET_SET_DEFAULT_TYPE_ATTRIBUTES ++#define TARGET_SET_DEFAULT_TYPE_ATTRIBUTES aarch64_set_default_type_attributes ++ ++#undef TARGET_ATTRIBUTE_TABLE ++#define TARGET_ATTRIBUTE_TABLE aarch64_attribute_table ++ ++#undef TARGET_COMP_TYPE_ATTRIBUTES ++#define TARGET_COMP_TYPE_ATTRIBUTES aarch64_comp_type_attributes ++ + #undef TARGET_CAN_USE_DOLOOP_P + #define TARGET_CAN_USE_DOLOOP_P can_use_doloop_if_innermost + +diff -N -urp a/gcc/config/aarch64/aarch64.h b/gcc/config/aarch64/aarch64.h +--- a/gcc/config/aarch64/aarch64.h 2018-11-06 10:43:27.870079389 +0800 ++++ b/gcc/config/aarch64/aarch64.h 2018-11-06 10:49:29.574088911 +0800 +@@ -28,7 +28,6 @@ + + + +-#define REGISTER_TARGET_PRAGMAS() aarch64_register_pragmas () + + /* Target machine storage layout. */ + +@@ -659,6 +658,14 @@ typedef struct + } CUMULATIVE_ARGS; + #endif + ++/* Handle pragmas for compatibility with Intel's compilers. */ ++#define REGISTER_TARGET_PRAGMAS() do { \ ++ c_register_pragma (0, "long_calls", aarch64_pr_long_calls); \ ++ c_register_pragma (0, "no_long_calls", aarch64_pr_no_long_calls); \ ++ c_register_pragma (0, "long_calls_off", aarch64_pr_long_calls_off); \ ++ aarch64_register_pragmas (); \ ++} while (0) ++ + #define FUNCTION_ARG_PADDING(MODE, TYPE) \ + (aarch64_pad_arg_upward (MODE, TYPE) ? upward : downward) + +@@ -842,13 +849,20 @@ typedef struct + #define PROFILE_HOOK(LABEL) \ + { \ + rtx fun, lr; \ ++ const rtx_insn* tmp = get_insns (); \ + lr = get_hard_reg_initial_val (Pmode, LR_REGNUM); \ + fun = gen_rtx_SYMBOL_REF (Pmode, MCOUNT_NAME); \ + emit_library_call (fun, LCT_NORMAL, VOIDmode, 1, lr, Pmode); \ ++ if (TARGET_LONG_CALLS) \ ++ { \ ++ emit_insn (gen_blockage ()); \ ++ emit_insn_after (gen_blockage (), NEXT_INSN (tmp)); \ ++ } \ + } + + /* All the work done in PROFILE_HOOK, but still required. */ +-#define FUNCTION_PROFILER(STREAM, LABELNO) do { } while (0) ++#define FUNCTION_PROFILER(STREAM, LABELNO) \ ++ aarch64_function_profiler (STREAM, LABELNO) + + /* For some reason, the Linux headers think they know how to define + these macros. They don't!!! */ +diff -N -urp a/gcc/config/aarch64/aarch64.md b/gcc/config/aarch64/aarch64.md +--- a/gcc/config/aarch64/aarch64.md 2018-11-06 10:43:27.874079389 +0800 ++++ b/gcc/config/aarch64/aarch64.md 2018-11-06 10:44:34.934081154 +0800 +@@ -850,9 +850,10 @@ + { + rtx pat; + rtx callee = XEXP (operands[0], 0); +- if (!REG_P (callee) +- && ((GET_CODE (callee) != SYMBOL_REF) +- || aarch64_is_noplt_call_p (callee))) ++ ++ if (GET_CODE (callee) == SYMBOL_REF ++ ? (aarch64_is_long_call_p (callee) || aarch64_is_noplt_call_p (callee)) ++ : !REG_P (callee)) + XEXP (operands[0], 0) = force_reg (Pmode, callee); + + if (operands[2] == NULL_RTX) +@@ -881,9 +882,10 @@ + { + rtx pat; + rtx callee = XEXP (operands[1], 0); +- if (!REG_P (callee) +- && ((GET_CODE (callee) != SYMBOL_REF) +- || aarch64_is_noplt_call_p (callee))) ++ ++ if (GET_CODE (callee) == SYMBOL_REF ++ ? (aarch64_is_long_call_p (callee) || aarch64_is_noplt_call_p (callee)) ++ : !REG_P (callee)) + XEXP (operands[1], 0) = force_reg (Pmode, callee); + + if (operands[3] == NULL_RTX) +diff -N -urp a/gcc/config/aarch64/aarch64.opt b/gcc/config/aarch64/aarch64.opt +--- a/gcc/config/aarch64/aarch64.opt 2018-11-06 10:43:27.874079389 +0800 ++++ b/gcc/config/aarch64/aarch64.opt 2018-11-06 10:44:34.934081154 +0800 +@@ -80,6 +80,10 @@ mlittle-endian + Target Report RejectNegative InverseMask(BIG_END) + Assume target CPU is configured as little endian. + ++mlong-calls ++Target Report Mask(LONG_CALLS) ++Generate call insns as indirect calls, if necessary. ++ + mcmodel= + Target RejectNegative Joined Enum(cmodel) Var(aarch64_cmodel_var) Init(AARCH64_CMODEL_SMALL) Save + Specify the code model. +diff -N -urp a/gcc/config/aarch64/predicates.md b/gcc/config/aarch64/predicates.md +--- a/gcc/config/aarch64/predicates.md 2018-11-06 10:43:27.878079389 +0800 ++++ b/gcc/config/aarch64/predicates.md 2018-11-06 10:44:34.938081154 +0800 +@@ -27,8 +27,9 @@ + ) + + (define_predicate "aarch64_call_insn_operand" +- (ior (match_code "symbol_ref") +- (match_operand 0 "register_operand"))) ++ (ior (and (match_code "symbol_ref") ++ (match_test "!aarch64_is_long_call_p (op)")) ++ (match_operand 0 "register_operand"))) + + ;; Return true if OP a (const_int 0) operand. + (define_predicate "const0_operand" diff --git a/sanitizer-pr-85835.patch b/sanitizer-pr-85835.patch new file mode 100644 index 0000000..0e25584 --- /dev/null +++ b/sanitizer-pr-85835.patch @@ -0,0 +1,33 @@ +diff --git a/libsanitizer/sanitizer_common/sanitizer_platform_limits_posix.cc b/libsanitizer/sanitizer_common/sanitizer_platform_limits_posix.cc +index 858bb21..de18e56 100644 (file) +--- a/libsanitizer/sanitizer_common/sanitizer_platform_limits_posix.cc ++++ b/libsanitizer/sanitizer_common/sanitizer_platform_limits_posix.cc +@@ -157,7 +157,6 @@ typedef struct user_fpregs elf_fpregset_t; + # include + #endif + #include +-#include + #include + #include + #include +@@ -250,7 +249,19 @@ namespace __sanitizer { + #endif // SANITIZER_LINUX || SANITIZER_FREEBSD + + #if SANITIZER_LINUX && !SANITIZER_ANDROID +- unsigned struct_ustat_sz = sizeof(struct ustat); ++ // Use pre-computed size of struct ustat to avoid which ++ // has been removed from glibc 2.28. ++#if defined(__aarch64__) || defined(__s390x__) || defined (__mips64) \ ++ || defined(__powerpc64__) || defined(__arch64__) || defined(__sparcv9) \ ++ || defined(__x86_64__) ++#define SIZEOF_STRUCT_USTAT 32 ++#elif defined(__arm__) || defined(__i386__) || defined(__mips__) \ ++ || defined(__powerpc__) || defined(__s390__) ++#define SIZEOF_STRUCT_USTAT 20 ++#else ++#error Unknown size of struct ustat ++#endif ++ unsigned struct_ustat_sz = SIZEOF_STRUCT_USTAT; + unsigned struct_rlimit64_sz = sizeof(struct rlimit64); + unsigned struct_statvfs64_sz = sizeof(struct statvfs64); + #endif // SANITIZER_LINUX && !SANITIZER_ANDROID diff --git a/try-unroll.patch b/try-unroll.patch new file mode 100644 index 0000000..6f564f8 --- /dev/null +++ b/try-unroll.patch @@ -0,0 +1,11 @@ +--- a/gcc/tree-ssa-loop-ivcanon.c 2018-12-06 05:05:43.841181211 +0800 ++++ b/gcc/tree-ssa-loop-ivcanon.c 2018-12-06 05:03:17.545185153 +0800 +@@ -726,7 +726,7 @@ try_unroll_loop_completely (struct loop + edge_to_cancel = NULL; + } + +- if (!n_unroll_found) ++ if (!n_unroll_found || SCEV_NOT_KNOWN == TREE_CODE (niter)) + return false; + + if (n_unroll > (unsigned) PARAM_VALUE (PARAM_MAX_COMPLETELY_PEEL_TIMES)) diff --git a/turn-on-funwind-tables-by-default.patch b/turn-on-funwind-tables-by-default.patch new file mode 100644 index 0000000..878d887 --- /dev/null +++ b/turn-on-funwind-tables-by-default.patch @@ -0,0 +1,25 @@ +diff -N -urp a/gcc/common/config/aarch64/aarch64-common.c b/gcc/common/config/aarch64/aarch64-common.c +--- a/gcc/common/config/aarch64/aarch64-common.c 2019-07-02 09:28:49.798701181 +0800 ++++ b/gcc/common/config/aarch64/aarch64-common.c 2019-07-02 09:30:15.436282799 +0800 +@@ -51,6 +51,10 @@ static const struct default_options aarc + { OPT_LEVELS_1_PLUS, OPT_fsched_pressure, NULL, 1 }, + /* Enable redundant extension instructions removal at -O2 and higher. */ + { OPT_LEVELS_2_PLUS, OPT_free, NULL, 1 }, ++#if (TARGET_DEFAULT_ASYNC_UNWIND_TABLES == 1) ++ { OPT_LEVELS_ALL, OPT_fasynchronous_unwind_tables, NULL, 1 }, ++ { OPT_LEVELS_ALL, OPT_funwind_tables, NULL, 1}, ++#endif + { OPT_LEVELS_NONE, 0, NULL, 0 } + }; + +diff -N -urp a/gcc/config.gcc b/gcc/config.gcc +--- a/gcc/config.gcc 2019-07-02 09:28:50.114701170 +0800 ++++ b/gcc/config.gcc 2019-07-02 09:31:50.636196118 +0800 +@@ -966,6 +966,7 @@ aarch64*-*-linux*) + tm_file="${tm_file} dbxelf.h elfos.h gnu-user.h linux.h glibc-stdint.h" + tm_file="${tm_file} aarch64/aarch64-elf.h aarch64/aarch64-linux.h" + tmake_file="${tmake_file} aarch64/t-aarch64 aarch64/t-aarch64-linux" ++ tm_defines="${tm_defines} TARGET_DEFAULT_ASYNC_UNWIND_TABLES=1" + case $target in + aarch64_be-*) + tm_defines="${tm_defines} TARGET_BIG_ENDIAN_DEFAULT=1"