【发布时间】:2011-10-31 23:09:06
【问题描述】:
我需要一些关于将参数“转发”到被调用者的建议(在 LLVM-IR 中)。
假设我有一个函数F,它在模块中所有其他函数的开头被调用。我需要从F 访问(读取)传递给其直接调用者的参数。
现在要做到这一点,我将调用者中的所有参数装箱到一个结构中,并将指向该结构的i8* 指针传递给F,以及一个告诉哪个调用者F 正在被调用的标识符。 F 然后有一个巨大的开关,它分支到适当的拆箱代码。必须这样做,因为模块中的函数具有不同的签名(不同的参数/返回值计数和类型;甚至不同的调用约定),但这显然不是最佳的(从性能和代码大小的角度来看),因为我需要在堆栈上分配结构,复制其中的参数,将附加指针传递给F,然后执行拆箱。
我想知道是否有更好的方法来做到这一点,即一种从函数访问的方法其直接调用者的堆栈帧(通过标识符知道该函数是哪个调用者调用自)或更一般地说,在其直接调用者中定义的任意值。有什么建议吗?
注意:我正在研究的重点是拥有一个 single 函数 F 来完成所有这些工作;拆分/内联/专业化/模板化F 不是一个选项。
澄清一下,假设我们有以下函数 FuncA 和 FuncB (注意:以下只是伪 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