LLVM中的参数转发

CAF*_*FxX 7 performance callstack function llvm argument-passing

我需要一些关于向被调用方"转发"参数的建议(在LLVM-IR中).

假设我有一个在模块F所有其他函数开头调用的函数.从F我需要访问(读取)传递给其直接调用者的参数.

现在要做到这一点,我在结构中的调用者中包含所有参数,并将i8*指针传递给结构F,以及一个标识符,告诉调用哪个调用者F.F然后有一个巨大的开关,分支到适当的拆箱代码.必须这样做,因为模块中的函数具有不同的签名(不同的参数/返回值计数和类型;甚至不同的调用约定),但它显然是次优的(从性能和代码大小的角度来看)因为我需要在堆栈上分配结构,复制其中的参数,传递一个额外的指针F,然后执行拆箱.

我想知道是否有更好的方法来做到这一点,即从函数访问其直接调用者的堆栈帧的方法(知道,由于标识符,调用函数的调用者),或者更一般地,任意在其直接调用者中定义的值.有什么建议?

注意:我正在研究的重点是拥有完成所有这一切的单一功能F; 拆分/内联/专门化/模板化F不是一种选择.


澄清一下,假设我们有以下功能FuncAFuncB(注意:以下只是伪C代码,永远记住我们在谈论LLVM-IR!)

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

Type3 FuncB(Type4 ArgB1, Type5 ArgB2, Type6 ArgB3) {
  F();
  // ...
}
Run Code Online (Sandbox Code Playgroud)

我需要的是一个有效的方法F来执行以下功能:

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

正如我在第一部分中解释的那样,现在我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;
  }
}
Run Code Online (Sandbox Code Playgroud)

这两个功能变成:

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);
  // ...
}
Run Code Online (Sandbox Code Playgroud)

Grz*_*cki 1

恕我直言,你做得对。虽然机器代码汇编中有解决方案,但恐怕 LLVM 汇编可能没有解决方案,因为它是“更高级别”的。如果您想在某些函数的开头运行一个函数,您是否考虑过检查

我知道这不是直接答案,但我希望它可能在某种程度上有所帮助;)。