Пересылка аргументов в LLVM

Мне нужен совет по «пересылке» аргументов вызываемому (в LLVM-IR).

Предположим, у меня есть функция F , которая вызывается в начале всех других функций в модуле. Из F мне нужно получить доступ (прочитать) аргументы, переданные его непосредственному вызывающему объекту.

Прямо сейчас, чтобы сделать это I box все аргументы вызывающего объекта внутри структуры и передают указатель i8 * на структуру в F вместе с идентификатором, указывающим, из какого вызывающего абонента F вызывается. F затем имеет гигантский переключатель, который переходит к соответствующему коду распаковки. Это необходимо сделать, потому что функции в модуле имеют разные сигнатуры (разное количество и типы аргументов / возвращаемых значений; даже разные соглашения о вызовах), но это явно неоптимально (как с точки зрения производительности, так и с точки зрения размера кода), потому что мне нужно выделить структуру в стеке, скопировать th e аргументы внутри него, передавая дополнительный указатель на F и затем выполняя распаковку.

Мне было интересно, есть ли лучший способ сделать это, то есть способ доступа из функции стековый фрейм его непосредственного вызывающего (зная, благодаря идентификатору, из которого вызывалась функция) или, в более общем смысле, произвольные значения, определенные в его непосредственном вызывающем . Есть предложения?

примечание: весь смысл того, над чем я работаю, заключается в наличии единственной функции F , которая делает все это; разделение / встраивание / специализация / создание шаблонов F не вариант.


для пояснения предположим, что у нас есть следующие функции FuncA и FuncB (примечание: что ниже приведен псевдокод, всегда помните, что мы говорим о LLVM-IR!)

Type1 FuncA(Type2 ArgA1) {
  F();
  // ...
}

Type3 FuncB(Type4 ArgB1, Type5 ArgB2, Type6 ArgB3) {
  F();
  // ...
}

мне нужен эффективный способ, чтобы функция F выполняла следующие действия:

void F() {
  switch (caller) {
    case FuncA:
      // do something with ArgA1
      break;
    case FuncB:
      // do something with ArgB1, ArgB2, ArgB3
      break;
  }
}

как я Как было объяснено в первой части, прямо сейчас мой F выглядит так:

struct Args_FuncA { Type2 ArgA1 };
struct Args_FuncB { Type4 ArgB1, Type5 ArgB2, Type6 ArgB3 };

void F(int callerID, void *args) {
  switch (callerID) {
    case ID_FuncA:
      Args_FuncA *ArgsFuncA = (Args_FuncA*)args;
      Type2 ArgA1 = ArgsFuncA->ArgA1;
      // do something with ArgA1
      break;
    case ID_FuncB:
      Args_FuncB *ArgsFuncB = (Args_FuncB*)args;
      Type4 ArgB1 = ArgsFuncB->ArgB1;
      Type5 ArgB2 = ArgsFuncB->ArgB2;
      Type6 ArgB3 = ArgsFuncB->ArgB3;
      // do something with ArgB1, ArgB2, ArgB3
      break;
  }
}

и две функции становятся:

Type1 FuncA(Type2 ArgA1) {
  Args_FuncA args = { ArgA1 };
  F(ID_FuncA, (void*)&args);
  // ...
}

Type3 FuncB(Type4 ArgB1, Type5 ArgB2, Type6 ArgB3) {
  Args_FuncB args = { ArgB1, ArgB2, ArgB3 };
  F(ID_FuncB, (void*)&args);
  // ...
}
7
задан CAFxX 29 January 2012 в 09:45
поделиться