Twitter iPhone pliant OnePlus 11 PS5 Disney+ Orange Livebox Windows 11

Portabilité du *concept* des fonctions "naked"

40 réponses
Avatar
Patrick Brunet
Bonjour.

Je voudrais faire un tour des différentes plates-formes sous C pour savoir
s'il y existe des équivalents d'une extension Microsoft, les fonctions
"naked".

Une fonction dotée de cet attribut est appelée extérieurement selon la
convention dite cdecl (le code appelant empile les arguments puis la partie
externe de la stackframe, et fait le ménage au retour), mais par contre
aucune stackframe n'est créée du côté interne.

Le but est de laisser le programmeur faire ce qu'il veut ex-nihilo,
généralement avec de l'assembleur inline. C'est très utile dans certains
contextes (drivers par exemple).

Pour ma part, j'y vois une possibilité d'implémentation de la technique
d'enfilage de pseudo-instructions, avec par rapport au goto l'avantage de la
récursivité.

Merci de me dire si vous connaissez des concepts similaires sur les
principales plates-formes (système + compilo) autres que (Windows + Cµsoft).

Merci beaucoup de votre aide.
Cordialement,

Patrick Brunet

10 réponses

1 2 3 4
Avatar
Patrick Brunet
"Richard Delorme" a écrit dans le message news:
3f530866$0$20944$

Voilà une petite maquette pour préciser les idées :
<...>



Pourquoi pas un switch case ?

for(;;) {
switch(next) {
case INSTRUCTION_1:
/* Code for p-instruction 1 */
/* operates on WorkSpace[] at pxCurrentPosition
then prepares them for the next p-instruction
then computes the result for the next case : */
break;
case INSTRUCTION_2:
/* Code for p-instruction 2 */
break;

...
case INSTRUCTION_N:
/* Code for p-instruction n */
break;
default: /* termination */
return;
}
}



Gulp ! C'est vrai que je n'y avais même pas pensé (OH le NULL). 12 ans de
codage pour ça !

Quand on avait fait de l'enfilage en assembleur pour un moteur Prolog, les
performances étaient si importantes, et le switch() a une telle réputation
d'inefficacité, que j'ai dû l'éliminer instinctivement.

Oui, fonctionnellement, c'est sans bavure, et même si le compilo l'optimise
mal, ça ne peut pas être pire que des appels de fonctions par indirections.

Ben ... Toutes mes excuses, faut vraiment que je cesse de prendre certaines
vitamines :-{

PB


Avatar
Patrick Brunet
Bonjour.

"Emmanuel Delahaye" a écrit dans le message news:

In 'fr.comp.lang.c', "Patrick Brunet" <Patrick.Brunet @ cned.fr> wrote:

Pas moyen de faire ça localement avec un pragma ?


Les pragmas sont des extensions des compilateurs, donc par définition non
portables.

De toute manière, le contexte l'est aussi, seul le concept devait l'être.

J'ai une technique de codage pour mettre du non-portable dans du strictement
portable.
Mais bon, de toute manière, je crois que le switch emporte le morceau (oh la
honte !!!).

Merci.

Cordialement,
PB


Avatar
Laurent Deniau
Patrick Brunet wrote:
"Richard Delorme" a écrit dans le message news:
3f530866$0$20944$



Voilà une petite maquette pour préciser les idées :


<...>


Pourquoi pas un switch case ?

for(;;) {
switch(next) {
case INSTRUCTION_1:
/* Code for p-instruction 1 */
/* operates on WorkSpace[] at pxCurrentPosition
then prepares them for the next p-instruction
then computes the result for the next case : */
break;
case INSTRUCTION_2:
/* Code for p-instruction 2 */
break;

...
case INSTRUCTION_N:
/* Code for p-instruction n */
break;
default: /* termination */
return;
}
}




Gulp ! C'est vrai que je n'y avais même pas pensé (OH le NULL). 12 ans de
codage pour ça !

Quand on avait fait de l'enfilage en assembleur pour un moteur Prolog, les
performances étaient si importantes, et le switch() a une telle réputation
d'inefficacité, que j'ai dû l'éliminer instinctivement.

Oui, fonctionnellement, c'est sans bavure, et même si le compilo l'optimise
mal, ça ne peut pas être pire que des appels de fonctions par indirections.


Pour info, j'avais dans le cadre d'un interpreteur rapide (~ 1 a 3 fois plus
lent que le C equivalent compile), j'avais mesure sur plusieurs achitectures
(x86, Sparc, RS6000) et plusieurs compilateurs (GCC, CC, CC AIX), les
performances d'un switch vs void(*)(void). La conclusion etait que les deux se
valent (a +/-5%). J'avais choisi les void(*)(void) pour leur elegance, leur
simplicite et la facilite d'extension des instructions.

a+, ld.

--
[ Laurent Deniau -- Scientific Computing & Data Analysis ]
[ CERN -- European Center for Nuclear Research ]
[ - http://cern.ch/Laurent.Deniau ]
[ -- One becomes old when dreams become regrets -- ]



Avatar
Patrick Brunet
Bonjour.

"Laurent Deniau" a écrit dans le message news:


<...>

Pour info, j'avais dans le cadre d'un interpreteur rapide (~ 1 a 3 fois
plus

lent que le C equivalent compile), j'avais mesure sur plusieurs
achitectures

(x86, Sparc, RS6000) et plusieurs compilateurs (GCC, CC, CC AIX), les
performances d'un switch vs void(*)(void). La conclusion etait que les
deux se

valent (a +/-5%). J'avais choisi les void(*)(void) pour leur elegance,
leur

simplicite et la facilite d'extension des instructions.

--
[ Laurent Deniau -- Scientific Computing & Data Analysis ]
[ CERN -- European Center for Nuclear Research ]
[ - http://cern.ch/Laurent.Deniau ]
[ -- One becomes old when dreams become regrets -- ]



Info très intéressante, merci.

En effet, je me suis toujours demandé si l'implémentation standard (la plus
générale) du switch() ressemble plutôt à un goto calculé (accès direct) ou à
une chaîne if-else if-else if... (accès itératif). Le second choix serait
évidemment très décevant...

Cordialement,

PZB

Avatar
Erwan David
"Patrick Brunet" <Patrick.Brunet @ cned.fr> écrivait :


En effet, je me suis toujours demandé si l'implémentation standard (la plus
générale) du switch() ressemble plutôt à un goto calculé (accès direct) ou à
une chaîne if-else if-else if... (accès itératif). Le second choix serait
évidemment très décevant...


Ça dépend des compilateurs, mais en général plutôt qu'un goto calculé
une table de sauts sera plus efficace. Ou alors une approche mixte en
particulier si le nombre de cas non défauts contient des trous.

Avatar
Vincent Lefevre
Dans l'article <3f5447a3$0$1144$,
Patrick Brunet <Patrick.Brunet @ cned.fr> écrit:

En effet, je me suis toujours demandé si l'implémentation standard
(la plus générale) du switch() ressemble plutôt à un goto calculé
(accès direct) ou à une chaîne if-else if-else if... (accès
itératif). Le second choix serait évidemment très décevant...


Pas forcément. Il se peut que le premier cas soit largement
majoritaire face aux autres.

--
Vincent Lefèvre - Web: <http://www.vinc17.org/> - 100%
validated (X)HTML - Acorn Risc PC, Yellow Pig 17, Championnat International
des Jeux Mathématiques et Logiques, TETRHEX, etc.
Work: CR INRIA - computer arithmetic / SPACES project at LORIA

Avatar
Patrick Brunet
Bonjour.

"Erwan David" a écrit dans le message news:

"Patrick Brunet" <Patrick.Brunet @ cned.fr> écrivait :


En effet, je me suis toujours demandé si l'implémentation standard (la
plus


générale) du switch() ressemble plutôt à un goto calculé (accès direct)
ou à


une chaîne if-else if-else if... (accès itératif). Le second choix
serait


évidemment très décevant...


Ça dépend des compilateurs, mais en général plutôt qu'un goto calculé
une table de sauts sera plus efficace. Ou alors une approche mixte en
particulier si le nombre de cas non défauts contient des trous.


C'est ça, idéalement le compilo devrait être capable de changer de stratégie
en fonction des cas possibles :
- si ce sont des entiers qui se suivent, un tableau d'indirections + test
des hors bornes, est idéal,
- sinon et si le nombre de cas est faible, la structure if-else if est
supportable,
- dans le cas le plus quelconque, je verrais peut-être une structure
d'indirections câblée sur un B-tree.

J'avoue que je me remets à douter que le switch soit la bonne implémentation
pour mon système d'enfilage...

Cordialement,

PZB


Avatar
Emmanuel Delahaye
In 'fr.comp.lang.c', "Patrick Brunet" <Patrick.Brunet @ cned.fr> wrote:

En effet, je me suis toujours demandé si l'implémentation standard (la


Il n'y a pas d'implémentation standard. Tout ce qu'on peut dire c'est que
l'expérience montre qu'un switch codé avec des constantes régulièrement
espacée et ordonnées donne généralement les meilleures performances possibles
(jump calculé selon une loi simple du type y = ax + b).

plus générale) du switch() ressemble plutôt à un goto calculé (accès
direct) ou à une chaîne if-else if-else if... (accès itératif). Le
second choix serait évidemment très décevant...


Carrément horrible, oui. Mais il peut suffire dans des cas simples (2 ou 3
cases + un default).

En tout état de cause, on ne peut savoir ce qui se passe vraiment qu'en
faisant des mesures réelles. Se méfier des spéculations. Se rappeler aussi
que les performamces ne sont pas portables.

--
-ed- [remove YOURBRA before answering me]
The C-language FAQ: http://www.eskimo.com/~scs/C-faq/top.html
<blank line>
FAQ de f.c.l.c : http://www.isty-info.uvsq.fr/~rumeau/fclc/

Avatar
Emmanuel Delahaye
In 'fr.comp.lang.c', "Patrick Brunet" <Patrick.Brunet @ cned.fr> wrote:

J'avoue que je me remets à douter que le switch soit la bonne
implémentation pour mon système d'enfilage...


Fait des mesures.

--
-ed- [remove YOURBRA before answering me]
The C-language FAQ: http://www.eskimo.com/~scs/C-faq/top.html
<blank line>
FAQ de f.c.l.c : http://www.isty-info.uvsq.fr/~rumeau/fclc/

Avatar
Patrick Brunet
Bonjour.

"Emmanuel Delahaye" a écrit dans le message news:

In 'fr.comp.lang.c', "Patrick Brunet" <Patrick.Brunet @ cned.fr> wrote:

En effet, je me suis toujours demandé si l'implémentation standard (la


Il n'y a pas d'implémentation standard. Tout ce qu'on peut dire c'est que
l'expérience montre qu'un switch codé avec des constantes régulièrement
espacée et ordonnées donne généralement les meilleures performances
possibles

(jump calculé selon une loi simple du type y = ax + b).

plus générale) du switch() ressemble plutôt à un goto calculé (accès
direct) ou à une chaîne if-else if-else if... (accès itératif). Le
second choix serait évidemment très décevant...


Carrément horrible, oui. Mais il peut suffire dans des cas simples (2 ou 3
cases + un default).

En tout état de cause, on ne peut savoir ce qui se passe vraiment qu'en
faisant des mesures réelles. Se méfier des spéculations. Se rappeler aussi
que les performamces ne sont pas portables.



C'est bien ce que je craignais:
- il n'y a pas d'implémentation standard,
- je crains fort que l'implémentation adaptative que je décris dans mon post
précédent ne soit pas vraiment d'actualité.

Or utiliser le C comme solution de portabilité universelle suppose de
pouvoir compter sur le compilateur C sur des plates-formes diverses et
variées, présentes et à venir.
Cela vaut pour la syntaxe, certes, mais dans mon cas aussi pour des
performances minimales.
Je ne peux pas me baser sur des benchs parce que je n'ai pas accès à la
totalité de ces plates-formes, et si je l'avais je pourrais tout autant
générer du code natif spécifique, créant des couches de portage classiques
pour mes p-instructions.

Conclusion :
Comme je peux maîtriser la valeur des "cases" et donc choisir la formule
optimale du tableau d'indirection, je vais procéder ainsi a priori, avec
donc des pointeurs de fonctions ordinaires à signature void( void). Ca offre
au moins la garantie de la double portabilité en syntaxe et optimalité des
performances par rapport à la machine.

Merci,
Cordialement,

PZB


1 2 3 4