kpatch/kpatch-build/gcc-plugins/ppc64le-plugin.c
Josh Poimboeuf 0019e83622 gcc-plugin: run the plugin at an earlier pass
On ppc64le, building drivers/media/i2c/cx25840/cx25840.ko with GCC 4.85,
the plugin triggers the following errors:

  {standard input}: Assembler messages:
  {standard input}:1078: Error: operand out of range (0x0000000000008fd4 is not between 0xffffffffffff8000 and 0x0000000000007ffc)
  {standard input}:1288: Error: operand out of range (0x000000000000874c is not between 0xffffffffffff8000 and 0x0000000000007ffc)
  {standard input}:3844: Error: operand out of range (0x00000000000080e8 is not between 0xffffffffffff8000 and 0x0000000000007ffc)
  {standard input}:4028: Error: operand out of range (0x00000000000082b4 is not between 0xffffffffffff8000 and 0x0000000000007ffc)
  {standard input}:4031: Error: operand out of range (0x00000000000080b4 is not between 0xffffffffffff8000 and 0x0000000000007ffc)
  {standard input}:6661: Error: operand out of range (0x000000000000841c is not between 0xffffffffffff8000 and 0x0000000000007ffc)
  {standard input}:6664: Error: operand out of range (0x0000000000008214 is not between 0xffffffffffff8000 and 0x0000000000007ffc)
  {standard input}:6845: Error: operand out of range (0x00000000000089dc is not between 0xffffffffffff8000 and 0x0000000000007ffc)
  {standard input}:6848: Error: operand out of range (0x00000000000087d4 is not between 0xffffffffffff8000 and 0x0000000000007ffc)
  {standard input}:7587: Error: operand out of range (0x0000000000008930 is not between 0xffffffffffff8000 and 0x0000000000007ffc)
  {standard input}:7590: Error: operand out of range (0x0000000000008728 is not between 0xffffffffffff8000 and 0x0000000000007ffc)
  {standard input}:14592: Error: operand out of range (0xffffffffffff79b8 is not between 0xffffffffffff8000 and 0x0000000000007ffc)
  make[1]: *** [drivers/media/i2c/cx25840/cx25840-core.o] Error 1

The problem is that the plugin nops were inserted too late.  GCC laid
out the code with knowledge about the distance between branches, but
then the plugin came along after that and increased the branch distances
by inserting the nops.

Fix it by inserting the nops as early as possible.  The 'vregs' pass is
where the insn codes get initialized, so run the plugin immediately
afterwards.

Signed-off-by: Josh Poimboeuf <jpoimboe@redhat.com>
2018-03-16 17:16:17 -05:00

87 lines
2.2 KiB
C

#include "gcc-common.h"
#include <error.h>
#define PLUGIN_NAME "ppc64le-plugin"
int plugin_is_GPL_compatible;
struct plugin_info plugin_info = {
.version = "1",
.help = PLUGIN_NAME ": insert nops after local calls\n",
};
static unsigned int ppc64le_plugin_execute(void)
{
rtx_insn *insn;
int code;
const char *name;
static int nonlocal_code = -1, local_code = -1,
value_nonlocal_code = -1, value_local_code = -1;
static bool initialized = false;
if (initialized)
goto found;
/* Find the rs6000.md code numbers for local and non-local calls */
initialized = true;
for (code = 0; code < 1000; code++) {
name = get_insn_name(code);
if (!name)
continue;
if (!strcmp(name , "*call_local_aixdi"))
local_code = code;
else if (!strcmp(name , "*call_nonlocal_aixdi"))
nonlocal_code = code;
else if (!strcmp(name, "*call_value_local_aixdi"))
value_local_code = code;
else if (!strcmp(name, "*call_value_nonlocal_aixdi"))
value_nonlocal_code = code;
if (nonlocal_code != -1 && local_code != -1 &&
value_nonlocal_code != -1 && value_local_code != -1)
goto found;
}
found:
if (nonlocal_code == -1 || local_code == -1 ||
value_nonlocal_code == -1 || value_local_code == -1) {
fprintf(stderr, PLUGIN_NAME ": can't find call instruction codes");
return 1;
}
/* Convert local calls to non-local */
for (insn = get_insns(); insn; insn = NEXT_INSN(insn)) {
if (GET_CODE(insn) == CALL_INSN) {
if (INSN_CODE(insn) == local_code)
INSN_CODE(insn) = nonlocal_code;
else if (INSN_CODE(insn) == value_local_code)
INSN_CODE(insn) = value_nonlocal_code;
}
}
return 0;
}
#define PASS_NAME ppc64le_plugin
#define NO_GATE
#include "gcc-generate-rtl-pass.h"
int plugin_init(struct plugin_name_args *plugin_info,
struct plugin_gcc_version *version)
{
const char * const plugin_name = plugin_info->base_name;
PASS_INFO(ppc64le_plugin, "vregs", 1, PASS_POS_INSERT_AFTER);
if (!plugin_default_version_check(version, &gcc_version))
error(1, 0, PLUGIN_NAME ": incompatible gcc/plugin versions");
register_callback(plugin_name, PLUGIN_INFO, NULL, &plugin_info);
register_callback(plugin_name, PLUGIN_PASS_MANAGER_SETUP, NULL,
&ppc64le_plugin_pass_info);
return 0;
}