Ho bisogno di alcuni consigli su "inoltro" argomenti a un chiamato (nel LLVM-IR).Inoltro di argomenti in LLVM
Supponiamo di avere una funzione F
che viene richiamata all'inizio di tutte le altre funzioni nel modulo. Da F
ho bisogno di accedere (leggere) gli argomenti passati al suo immediato chiamante.
In questo momento per fare questo I box tutti gli argomenti del chiamante all'interno di una struct e passare un puntatore i8*
alla struttura per F
, accanto ad un racconto identificativo chiamante che F
viene chiamato da. F
ha quindi un interruttore gigante che si dirama al codice di unboxing appropriato. Questo deve essere fatto perché le funzioni nel modulo hanno firme diverse (argomento diverso/conteggio del valore di ritorno e tipi, anche convenzioni di chiamata diverse), ma è ovviamente subottimale (sia dal punto di vista delle prestazioni che del formato del codice) perché io è necessario allocare la struttura nello stack, copiare gli argomenti al suo interno, passare un puntatore aggiuntivo a F
e quindi eseguire l'unboxing.
Mi chiedevo se c'è un modo migliore per fare questo, cioè un modo per accedere da una funzione lo stack frame del suo immediato chiamante (conoscere, grazie alla identificativo, che chiama la funzione è stata chiamata da) o , più in generale, valori arbitrari definiti nel suo immediato chiamante. Eventuali suggerimenti?
nota: il punto di ciò che sto lavorando su sta avendo una funzione F
singolo che fa tutto questo; splitting/inlining/specializing/templating F
non è un'opzione.
per chiarire, supponiamo di avere le seguenti funzioni FuncA
e FuncB
(nota: Ciò che segue è solo pseudo-codice C, sempre ricordare che stiamo parlando di LLVM-IR!)
Type1 FuncA(Type2 ArgA1) {
F();
// ...
}
Type3 FuncB(Type4 ArgB1, Type5 ArgB2, Type6 ArgB3) {
F();
// ...
}
quello che mi serve è un modo efficace per la funzione F
per effettuare le seguenti operazioni:
void F() {
switch (caller) {
case FuncA:
// do something with ArgA1
break;
case FuncB:
// do something with ArgB1, ArgB2, ArgB3
break;
}
}
come ho spiegato nella prima parte, in questo momento il mio F
assomiglia a questo:
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;
}
}
e le due funzioni diventano:
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);
// ...
}
dtrace ha fatto esattamente lo stesso di CAFxX. – osgx