【问题标题】:Argument forwarding in LLVMLLVM 中的参数转发
【发布时间】:2011-10-31 23:09:06
【问题描述】:

我需要一些关于将参数“转发”到被调用者的建议(在 LLVM-IR 中)。

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

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

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

注意:我正在研究的重点是拥有一个 single 函数 F 来完成所有这些工作;拆分/内联/专业化/模板化F 不是一个选项。


澄清一下,假设我们有以下函数 FuncAFuncB (注​​意:以下只是伪 C 代码,永远记住我们在谈论 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);
  // ...
}

【问题讨论】:

    标签: performance function llvm argument-passing callstack


    【解决方案1】:

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

    • 调试器源(如 gdb)
    • 二进制检测与Valgrind

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

    【讨论】:

    • dtrace 和 CAFxX 描述的一样。
    【解决方案2】:

    不确定这是否有帮助,但我遇到了类似的问题,并通过使用 llvm 向量存储中间值来解决 LLVM 的 tbaa 分析的限制。 LLVM 优化通道后来能够将向量加载/存储优化到标量寄存器中。

    我记得有一些警告。如果您探索这条路线,请告诉我,我可以挖掘一些代码。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2011-05-09
      • 1970-01-01
      • 2014-04-25
      • 2013-06-13
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多