When using -mcmodel=medany -mexplicit-relocs, weak symbol references aren't handled correctly. The conditional test gets optimized away by the compiler.
The problem is with the RTL generated for the instruction pair for a symbol reference, where the lo part insn only has a label pointing at the high part insn. The optimizer sees that the weak symbol test against zero refers to a code label which is guaranteed to be non-zero, and hence optimizes away the test. As a short term solution, we can get the right result if we mark the code label as weak. Longer term, we need to change how these insn patterns work to solve this problem and other optimization problems. That solution hasn't been defined yet. This was tested with riscv32-elf and riscv64-linux toolchain builds and tests. There were no regressions. The new testcase fails without the patch and works with the patch. This has also been tested with toolchain builds with the compiler modified to use -mcmodel=medany -mexplicit-relocs by default. This fails badly without the patch as there are weak symbols in start files, and works OK with the patch. Committed. Jim gcc/ * config/riscv/riscv.c (riscv_split_symbol): Mark auipc label as weak when target symbol is weak. gcc/testsuite/ * gcc.target/riscv/weak-1.c: New. --- gcc/config/riscv/riscv.c | 5 +++++ gcc/testsuite/gcc.target/riscv/weak-1.c | 14 ++++++++++++++ 2 files changed, 19 insertions(+) create mode 100644 gcc/testsuite/gcc.target/riscv/weak-1.c diff --git a/gcc/config/riscv/riscv.c b/gcc/config/riscv/riscv.c index 9d6d981a42a..381a203da9b 100644 --- a/gcc/config/riscv/riscv.c +++ b/gcc/config/riscv/riscv.c @@ -1103,6 +1103,11 @@ riscv_split_symbol (rtx temp, rtx addr, machine_mode mode, rtx *low_out) label = gen_rtx_SYMBOL_REF (Pmode, ggc_strdup (buf)); SYMBOL_REF_FLAGS (label) |= SYMBOL_FLAG_LOCAL; + /* ??? Ugly hack to make weak symbols work. May need to change the + RTL for the auipc and/or low patterns to get a better fix for + this. */ + if (! nonzero_address_p (addr)) + SYMBOL_REF_WEAK (label) = 1; if (temp == NULL) temp = gen_reg_rtx (Pmode); diff --git a/gcc/testsuite/gcc.target/riscv/weak-1.c b/gcc/testsuite/gcc.target/riscv/weak-1.c new file mode 100644 index 00000000000..0f20501f7c5 --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/weak-1.c @@ -0,0 +1,14 @@ +/* { dg-do compile } */ +/* { dg-options "-mcmodel=medany -mexplicit-relocs -O" } */ + +/* Verify that the branch doesn't get optimized away. */ +extern int weak_func(void) __attribute__ ((weak)); + +int +sub (void) +{ + if (weak_func) + return weak_func (); + return 0; +} +/* { dg-final { scan-assembler "b\(ne|eq\)" } } */ -- 2.17.1