r10k_safe_mem_expr_p couldn't cope with a MEM_REF of an ADDR_EXPR, which for some reason is produced for r10k-cache-barrier-8.c when compiled with -O2 -lto but not when compiled with just -O2.
This function is still much too conservative, but I wanted to be safe for kernel code that plays clever tricks with link-time symbol definitions. A trivial example is: extern char _region_start[]; where _region_start is defined in the linker script. _region_start[1] can't be seen as an in-range access to an object as far as the -mr10k-cache-barrier= option is concerned. Tested on mipsisa64-elf, mips64-elf and mips64-linux-gnu. Applied. Will be tested once gcc.target/mips uses gcc-dg. Richard gcc/ * config/mips/mips.c (r10k_safe_mem_expr_p): Use get_inner_reference. Index: gcc/config/mips/mips.c =================================================================== --- gcc/config/mips/mips.c 2012-08-26 11:35:15.000000000 +0100 +++ gcc/config/mips/mips.c 2012-08-26 11:36:43.667807911 +0100 @@ -14446,17 +14446,18 @@ r10k_safe_address_p (rtx x, rtx insn) static bool r10k_safe_mem_expr_p (tree expr, HOST_WIDE_INT offset) { - if (offset < 0 || offset >= int_size_in_bytes (TREE_TYPE (expr))) - return false; + HOST_WIDE_INT bitoffset, bitsize; + tree inner, var_offset; + enum machine_mode mode; + int unsigned_p, volatile_p; - while (TREE_CODE (expr) == COMPONENT_REF) - { - expr = TREE_OPERAND (expr, 0); - if (expr == NULL_TREE) - return false; - } + inner = get_inner_reference (expr, &bitsize, &bitoffset, &var_offset, &mode, + &unsigned_p, &volatile_p, false); + if (!DECL_P (inner) || !DECL_SIZE_UNIT (inner) || var_offset) + return false; - return DECL_P (expr); + offset += bitoffset / BITS_PER_UNIT; + return offset >= 0 && offset < tree_low_cst (DECL_SIZE_UNIT (inner), 1); } /* A for_each_rtx callback for which DATA points to the instruction