CAF*_*FxX 7 performance callstack function llvm argument-passing
我需要一些关于向被调用方"转发"参数的建议(在LLVM-IR中).
假设我有一个在模块F中所有其他函数开头调用的函数.从F我需要访问(读取)传递给其直接调用者的参数.
现在要做到这一点,我在结构中的调用者中包含所有参数,并将i8*指针传递给结构F,以及一个标识符,告诉调用哪个调用者F.F然后有一个巨大的开关,分支到适当的拆箱代码.必须这样做,因为模块中的函数具有不同的签名(不同的参数/返回值计数和类型;甚至不同的调用约定),但它显然是次优的(从性能和代码大小的角度来看)因为我需要在堆栈上分配结构,复制其中的参数,传递一个额外的指针F,然后执行拆箱.
我想知道是否有更好的方法来做到这一点,即从函数访问其直接调用者的堆栈帧的方法(知道,由于标识符,调用函数的调用者),或者更一般地,任意在其直接调用者中定义的值.有什么建议?
注意:我正在研究的重点是拥有完成所有这一切的单一功能F; 拆分/内联/专门化/模板化F不是一种选择.
澄清一下,假设我们有以下功能FuncA和FuncB(注意:以下只是伪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)
恕我直言,你做得对。虽然机器代码汇编中有解决方案,但恐怕 LLVM 汇编可能没有解决方案,因为它是“更高级别”的。如果您想在某些函数的开头运行一个函数,您是否考虑过检查
我知道这不是直接答案,但我希望它可能在某种程度上有所帮助;)。