150

1. C'est génant si on passe une partie des arguments par registres, une autre par la pile (obligé, avec une va_list) ? Il suffit de ne préciser des registres que là où on en utilise et ça va ?
2. C'est gênant si on utilise des registres >= a2 ?

151

C'est génant si on passe une partie des arguments par registres, une autre par la pile

Là aussi, ExtGraph utilise de nombreuses telles fonctions (même s'il n'y a aucune va_list): regarde les headers wink
2. C'est gênant si on utilise des registres >= a2 ?

Mieux vaut ne pas en abuser car dans les programmes client compliqués, les registres d'adresse a2-a6 (moins ceux qui sont utilisés par le frame pointer / la global register variable) sont les meilleurs moyens de stocker des variables pointeurs à longue vie.
Ceci dit, plusieurs fonctions d'ExtGraph et TIGCCLIB, plutôt parmi les moins courantes, utilisent des registres >= a2.
avatar
Membre de la TI-Chess Team.
Co-mainteneur de GCC4TI (documentation en ligne de GCC4TI), TIEmu et TILP.
Co-admin de TI-Planet.

152

short TestCollide8_R(short x0 asm("%d0"), short y0 asm("%d1"), short x1 asm("%d2"), short y1 asm("%d3"), unsigned short height,
const unsigned char* data0 asm("%a0"), const unsigned char* data1 asm("%a1")) __attribute__((__stkparm__));

Bon, si je comprends bien, ici c'est la totale ?
- Passage d'arguments par registre (tiens au fait, faut mettre les '%' ??)
- Utilisation de d3
- Passage d'arguments par la pile

Le stkparm sert à quoi ? Ce n'est pas évident que les arguments sans 'asm("...")' sont passés par la pile ? Ou alors il est obligatoire parce qu'on a aussi des passages par registre ?
Et est-ce que ça veut dire qu'un programme utilisant d3 comme variable globale déconnerait en utilisant une telle fonction ?

153

(tiens au fait, faut mettre les '%' ??)

Non, ça n'est pas obligatoire smile
Le stkparm sert à quoi ?

L'idée est de forcer le compilo à passer height sur la pile:
Ce n'est pas évident que les arguments sans 'asm("...")' sont passés par la pile ?

Pas forcément, si l'utilisateur utilise un réglage du genre "-mregparm=9" (déconseillé par la doc). De mémoire (ça fait fort longtemps que le code est comme ça et qu'il fonctionne grin), c'est pour ça que j'ai mis un stkparm explicite.
Et est-ce que ça veut dire qu'un programme utilisant d3 comme variable globale déconnerait en utilisant une telle fonction ?

Si ni le compilo (sauvegarde/restauration automatique) ni toi (sauvegarde/restauration explicite si le compilo ne le fait pas) ne font attention, ça devrait merder, oui.
avatar
Membre de la TI-Chess Team.
Co-mainteneur de GCC4TI (documentation en ligne de GCC4TI), TIEmu et TILP.
Co-admin de TI-Planet.

154

Ok, merci beaucoup pour tout.
J'ai déjà réécrit ma fonction en utilisant ces features (mais sans utiliser a2+/d3+).
J'ai un proto de ce genre maintenant :
;       int pdtlib__ManageCmdline (CMDLINE* CmdLine, void* Data, const char* OptList, int (*Callback)(void* Data asm("a0"), int Status asm("d0")),
;                                  void (*SwitchFunc)(void* Data asm ("a0"), char Sign asm ("d0")), ...);

C'est fou ce que je gagne en asm. J'ai réécrit (je sais, pas bien fear) en ~410 octets d'assembleur une lib C qui en fait 625. Et niveau vitesse on en parle même pas.

Rectif hic à tiffes : 399 love

155

Folco (./150) :
1. C'est génant si on passe une partie des arguments par registres, une autre par la pile (obligé, avec une va_list) ? Il suffit de ne préciser des registres que là où on en utilise et ça va ?

Oui, mais tu devrais aussi mettre __attribute__((stkparm)) pour que ça marche aussi quand le programme qui utilisera la lib est compilé avec -mregparm.
2. C'est gênant si on utilise des registres >= a2 ?

Non, sauf %a6 (%fp) et %a7 (%sp). (J'éviterais aussi %a5 (OPTIMIZE_ROM_CALLS), mais pour une lib kernel, ce n'est pas si important que ça.)
Folco (./152) :
Et est-ce que ça veut dire qu'un programme utilisant d3 comme variable globale déconnerait en utilisant une telle fonction ?

Oui. (Et non, Lionel, GCC ne gère pas ça.) C'est une des raisons pour lesquelles les global register variables sont une mauvaise idée.
avatar
Mes news pour calculatrices TI: Ti-Gen
Mes projets PC pour calculatrices TI: TIGCC, CalcForge (CalcForgeLP, Emu-TIGCC)
Mes chans IRC: #tigcc et #inspired sur irc.freequest.net (UTF-8)

Liberté, Égalité, Fraternité

156

les global register variables sont une mauvaise idée.

Ne sois pas si général dans tes affirmations wink
Tu sais bien qu'en ASM, Martial utilise souvent, pour plusieurs raisons qui vont dans le même sens (plus grande efficacité du code + absence de relocations), une global register variable pointeur vers les données internes du programme. Pattern shared memory: priorité à l'efficacité, au détriment du couplage, de la cohésion et de la maintenabilité.

[EDIT: dernière phrase: ajout du couplage]
avatar
Membre de la TI-Chess Team.
Co-mainteneur de GCC4TI (documentation en ligne de GCC4TI), TIEmu et TILP.
Co-admin de TI-Planet.

157

Merci bien pour tout. smile

158

Il y a un moyen de dire à GCC qu'une fonction ne détruit que, par exemple, a0, afin de favoriser l'optimisation ?

159

Ca ne me dit rien, en tout cas rien de direct (peut-être avec de l'ASM inline).

Ceci dit, comme tu le sais, ce genre de micro-optimisations, même en ASM pur, est une pente fort glissante grin
avatar
Membre de la TI-Chess Team.
Co-mainteneur de GCC4TI (documentation en ligne de GCC4TI), TIEmu et TILP.
Co-admin de TI-Planet.

160

Ben tant qu'à être au fond du trou tu sais grin

Mais ok, merci hehe

161

Peut-on créer une table d'offsets en C ? De type de celles qu'on utilise pour avoir une table de sauts pc-relatifs en assembleur.
Ca serait du genre :
const short OffsetsTable [] = {Func1-&OffsetTable, Func2-&OffsetTable, ...};
void Func1() {}
void Func2() {}

int main ()
{ LibCall(OffsetTable);}

C'est faisable et fiable ?

162

Déjà, est-ce que ça compile, ça ?
avatar
Zeroblog

« Tout homme porte sur l'épaule gauche un singe et, sur l'épaule droite, un perroquet. » — Jean Cocteau
« Moi je cherche plus de logique non plus. C'est surement pour cela que j'apprécie les Ataris, ils sont aussi logiques que moi ! » — GT Turbo

163

Tu poses la même question que Lionel grin J'ai pas essayé, mais en castant comme il faut, à mon avis oui. J'essaye de ce pas. Je voulais surtout savoir si ça produit du code parfaitement fiable, autorisé toussa toussa.

164

Ça ne compile même pas.
avatar
Mes news pour calculatrices TI: Ti-Gen
Mes projets PC pour calculatrices TI: TIGCC, CalcForge (CalcForgeLP, Emu-TIGCC)
Mes chans IRC: #tigcc et #inspired sur irc.freequest.net (UTF-8)

Liberté, Égalité, Fraternité

165

Kevin, c'était du C-like bien évidemment.
En vrai C-kikompile:
#include "kernel.h"

#define    USE_TI89

void func1 (void)
{
}

void func2 (void)
{
}

int pwet (unsigned short* Table)
{
    return Table[0] = Table[1];
}

int _main (void)
{
    unsigned short Table [] =
    {
        (unsigned short)((long)func2 - (long)Table),
        (unsigned short)((long)func1 - (long)Table),
    };
    return pwet(Table);
}

Compilation :
tigcc -Wall -W --save-temps --optimize-code --optimize-relocs --cut-ranges -v pwet.c -o pwet
Asm produit :
func1:
    link.w %fp,#0
    unlk %fp
    rts
    .even
    .globl    func2
func2:
    link.w %fp,#0
    unlk %fp
    rts
    .even
    .globl    pwet
pwet:
    link.w %fp,#0
    move.l 8(%fp),%a0
    addq.l #2,%a0
    move.w (%a0),%d0
    move.l 8(%fp),%a0
    move.w %d0,(%a0)
    move.l 8(%fp),%a0
    move.w (%a0),%d0
    unlk %fp
    rts
    .even
    .globl    _main
_main:
    link.w %fp,#-4
    move.l #func2,%d0
    move.w %d0,%d1
    move.l %fp,%d0
    subq.l #4,%d0
    move.w %d0,%d0
    move.w %d1,%a0
    sub.w %d0,%a0
    move.w %a0,%d0
    move.w %d0,-4(%fp)
    move.l #func1,%d0
    move.w %d0,%d1
    move.l %fp,%d0
    subq.l #4,%d0
    move.w %d0,%d0
    move.w %d1,%a0
    sub.w %d0,%a0
    move.w %a0,%d0
    move.w %d0,-2(%fp)
    move.l %fp,%d0
    subq.l #4,%d0
    move.l %d0,-(%sp)
    jbsr pwet
    addq.l #4,%sp
    unlk %fp
    rts

J'ai pas regardé ce qu'il merdouille, mais il est déjà évident qu'il reloge les adresses des fonctions, qu'il ne crée pas de table de donnée etc...
Sauf s'il y a un moyen de lui faire comprendre exactement ce que je veux, je suis cuit. sad

On aura au passage noté les optimisations spectaculaires effectuées sur les fonction vides, les link an,#0 magistraux etc...

166

Tu as oublié de spécifier le -O c'est sans doute pour ça. (Il faut mettre -O2 ou -Os suivant que tu veux optimiser en vitesse ou en taille, sinon il n'optimise pas du tout. Enfin il me semble.)
avatar
« Le bonheur, c'est une carte de bibliothèque ! » — The gostak distims the doshes.
Membrane fondatrice de la confrérie des artistes flous.
L'univers est-il un dodécaèdre de Poincaré ?
(``·\ powaaaaaaaaa ! #love#

167

J'ai essayé de déclarer el tableau en volatile, en me disant que si "autre chose" pouvait accéder à ce tableau, le compilateur serait bien obligé de lui donner la forme attendue (un véritable tableau de unsigned short). Mais j'ai cette erreur :
pwet.c:20: error: initializer element is not constant (near initialization for 'Table[0]')
pwet.c:21: error: initializer element is not constant (near initialization for 'Table[1]')

Il me dit ça pour les deux lignes du tableau... (comme si je déclare le tableau static d'ailleurs).

cross -> oups merci ^^ => même taille de binaire et à vue de nez même code cheeky

168

volatile ?

Je ne comprends pas ce qu'il ne fait pas bien dans le code assembleur que tu as mis, ça me semble correct. Il crée un tableau de deux cases sur la pile (link.w %fp,#-4) et il y met ce que tu lui as dit autant que je puisse en juger (enfin il convertit les adresses en short avant de faire la soustraction et non après, mais ça change rien il me semble, tu ne peux pas avoir de retenue de la partie de poids fort vers celle de poids faible)

sinon si tu veux éviter les link il me semble qu'il faut mettre -fomit_frame_pointer
avatar
« Le bonheur, c'est une carte de bibliothèque ! » — The gostak distims the doshes.
Membrane fondatrice de la confrérie des artistes flous.
L'univers est-il un dodécaèdre de Poincaré ?
(``·\ powaaaaaaaaa ! #love#

169

static peut-etre plutot non ?
avatar
Proud to be CAKE©®™


GCC4TI importe qui a problème en Autriche, pour l'UE plus et une encore de correspours nucléaire, ce n'est pas ytre d'instérier. L'état très même contraire, toujours reconstruire un pouvoir une choyer d'aucrée de compris le plus mite de genre, ce n'est pas moins)
Stalin est l'élection de la langie.

170

Ah oui tu voudrais que le tableau ne soit pas sur la pile ? dans ce cas il faut effectivement le déclarer soit static soit comme une variable globale (dans les deux cas il sera créé à la compilation et non au runtime), par contre dans ce cas il essaye de calculer la valeur de l'initialiseur au moment de la compilation, et en l'occurrence il ne peut pas puisqu'il ne connaît pas les adresses, c'est pour ça qu'il n'est pas content. Il suffit que tu sépares la déclaration et l'initialisation, ainsi dans le fichier le tableau ne sera pas initialisé et ensuite il le sera au runtime.

Edit : mais si ton but était qu'il précalcule le contenu du tableau, je ne pense pas que ce soit possible, parce qu'il ne peut pas connaître l'offset avant d'avoir compilé. Il faudrait une étape de bootstrap pour pouvoir faire ça ^^
avatar
« Le bonheur, c'est une carte de bibliothèque ! » — The gostak distims the doshes.
Membrane fondatrice de la confrérie des artistes flous.
L'univers est-il un dodécaèdre de Poincaré ?
(``·\ powaaaaaaaaa ! #love#

171

Bah, j'aurais dû expliciter mon ./164: on avait déjà cette discussion! Une différence d'adresses n'est pas une constante en C (sauf dans le cas particulier où ce sont 2 champs de la même structure), donc 1. tu ne peux pas l'utiliser dans une variable globale ou statique et 2. dans une variable locale, c'est calculé à coup de relogements. Le compilateur C ne sait pas où se situent les fonctions et beaucoup de formats objet ne prévoient pas de relogement différence d'adresses. Ce serait théoriquement implémentable dans TIGCC en fonction des paires de relogements positif/négatif gérées par ld-tigcc, mais pour ça il faudrait modifier GCC et je ne peux pas dire a priori l'ampleur des modifications nécessaires.
avatar
Mes news pour calculatrices TI: Ti-Gen
Mes projets PC pour calculatrices TI: TIGCC, CalcForge (CalcForgeLP, Emu-TIGCC)
Mes chans IRC: #tigcc et #inspired sur irc.freequest.net (UTF-8)

Liberté, Égalité, Fraternité

172

Godzil (./169) :
static peut-etre plutot non ?

C'est ce que j'ai commencé par essayer, sans succès.
Sally (./170) :
dans ce cas il faut effectivement le déclarer soit static soit comme une variable globale (dans les deux cas il sera créé à la compilation et non au runtime)

J'ai essayé aussi.
Kevin Kofler (./171) :
Bah, j'aurais dû expliciter mon ./164: on avait déjà cette discussion! Une différence d'adresses n'est pas une constante en C (sauf dans le cas particulier où ce sont 2 champs de la même structure)

Je m'en souviens bien, je n'avais tout simplement pas fait le lien entre les deux. Merci de l'explication.


Bon ben tant pis, je laisse tomber cette idée, merci pour tout. smile

173

Bon, je ressors ce topic un peu au hasard, il fera l'affaire.


Il y a un truc que je ne comprends pas du tout avec l'arithmétique des pointeurs void :
Soit ce code :
void* ArcPtr;
void* ArcBasePtr;
long Offset;

// initialisations toussa

ArcPtr = ArcBasePtr + Offset;

Ben... Ca marche bigeyes

J'arrive à additionner un long à un void* sans qu'il ne trouve rien à redire. Il est magicien ? Si je regarde mon bouquin, il y est explicitement dit que :
Le type void* ne peut pas être soumis à des calculs arithmétiques

Exemple :
void *ad1, *ad2;
ad1 ++; // interdit
ad2 = ad1 + 5; // interdit

On notera que ces interdictions sont justifiées si l'on part du principe qu'un pointeur générique est simplement destiné à être manipulé en tant que tel, par exemple pour être transmis d'une fonction à une autre. En revanche, elles le sont moins si l'on considère qu'un tel pointeur peut aussi servir à manipuler des octets successifs ; dans ce cas, il faudra quand même recourir au type char*.


Je ne comprends donc pas :
- ça compile
- ça semblerait malgré tout interdit (et ça semble logique... encore que... niveau assembleur c'est bateau comme opération)

Je ne sais pas par contre ce que ça génère, et surtout si c'est safe, quelles sont les règle en la matière !

Merci de vos éclaircissations. smile

174

Je crois que des paramètres de compilation peuvent être utilisés pour autoriser ou interdire l'arithmétique sur les pointeurs void. Pour ce que ça fait, je suppose que ça incrémente comme s'il s'agissait d'un char*, mais c'est à vérifier.
Tu compiles en -Wall ?
avatar
Que cache le pays des Dieux ? - Forum Ghibli - Forum Littéraire

La fin d'un monde souillé est venue. L'oiseau blanc plane dans le ciel annonçant le début d'une longue ère de purification. Détachons-nous à jamais de notre vie dans ce monde de souffrance. Ô toi l'oiseau blanc, l'être vêtu de bleu, guide nous vers ce monde de pureté. - Sutra originel dork.

175

Ca, c'est une extension de GCC au standard C. Ton livre documente le C standard - et donc, pas cette extension non standard smile

Il y a des gens qui adorent l'arithmétique sur les pointeurs void.
Il y en a qui ne voient pas trop l'intérêt par rapport à l'utilisation de char * / unsigned char * / int8_t * / uint8_t * ou types équivalents (pointeur vers octet).
Il y en a qui trouvent foutrement stupide cette extension non portable et le fait que sizeof(void) == 1.

A toi de voir grin
avatar
Membre de la TI-Chess Team.
Co-mainteneur de GCC4TI (documentation en ligne de GCC4TI), TIEmu et TILP.
Co-admin de TI-Planet.

176

Ximoon (./174) :
Tu compiles en -Wall ?

-Wall -W

J'ai renoncé à -pedantic devant la volée de warnings déclenchés par (gcc4)ti(gcc)lib sad
Lionel Debroux (./175) :
Ca, c'est une extension de GCC au standard C. Ton livre documente le C standard - et donc, pas cette extension non standard smile.gif

Ah ok merci. Plus qu'à trouver la doc de cette extension pour savoir précisément ce qu'elle fait (void* -> char* implicite j'imagine).
Ximoon (./174) :
je suppose que ça incrémente comme s'il s'agissait d'un char*, mais c'est à vérifier.

Oué voilà, à vérifier. En tout cas, ça serait con qu'il en soit autrement, transcrit littéralement en assembleur c'est ce que ça donne...
Lionel Debroux (./175) :
Il y en a qui ne voient pas trop l'intérêt par rapport à l'utilisation de char * / unsigned char * / int8_t * / uint8_t * ou types équivalents (pointeur vers octet).

Quand tu parcours un fichier AMS de type aléatoire, je ne vois pas en vertu de quoi je dirais que mon pointeurs est plus un char* qu'un short* ou qu'un mékooyes*.

Même si char* parait plus propre, ça reste de toute façon un hack, et ça nécessitera aussi des casts dans tous les sens.


Merci encore de vos réponses. smile

177

Oh, key :
http://tigcc.ticalc.org/doc/gnuexts.html#SEC79
http://gcc.gnu.org/onlinedocs/gcc-2.95.3/gcc_4.html#SEC78

Sanqse euguèine.

C'est pas mal pour s'affranchir de pas mal de casts casse-bonbons : FileInfo->Tag = *(char*)(ArcPtr + *(short*) ArcPtr + 1);

178

Hmm, ya quand même un truc que j'ai du mal à visualiser :
*(unsigned short*)(ArcPtr + 1)
Avec ArcPtr qui est un void*.

Alors, comment ça se passe ?
1ère idée : On fait l'addition dans la parenthèse, donc en asm je vais avoir un addq.l #1,a0. Puis on cast en (unsigned short*). Ca pue l'address error à des kilomètres.
2ème idée : On caste le contenu de la parenthèse en (unsigned short*). Puis on résoud l'addition, donc en asm on fait un addq.l #2,a0.

J'arrive pas à savoir comment le compilateur va conidérer les choses. Que choisit-il comme solution ?

179

Les deux.
Enfin plus sérieusement comme tu l'as dit pour la solution deux « On caste le contenu de la parenthèse en (unsigned short*) »… Conclusion la solution 1 est la bonne, mais la 2 aussi sauf que tu ne l'a pas interprétée correctement (ça donne aussi addq.l #1,a0… Ta deuxième phrase est une contradiction avec la première selon les principes du langage C tongue)

La règle à appliquer, comme à peu près pour tout en C, c'est la priorité des opérateurs, dont découle l'ordre d'évaluation des expressions.

Deux choses ici:
On applique le cast sur le contenu de la parenthèse.
Les parenthèses ont priorité absolue. (Comme en maths… Bien sur le groupe le plus imbriqué est le plus prioritaire, mais il n'y a pas d'imbrication ici)

Par conséquent, le contenu de la parenthèse est évalué en premier puis ensuite on lui applique le cast, qui est un opérateur unaire de priorité inférieure. C'est à dire la solution 1 tongue

C'est assez simple, et il n'y a jamais d'exception (enfin je suis pas sur que que cas des pointeurs de fonctions rentre parfaitement là dedans, mais admettons que si parce que j'ai la flemme de vérifier).

PS: en gras la version simple tongue
avatar
Le scénario de notre univers a été rédigée par un bataillon de singes savants. Tout s'explique enfin.
T'as un problème ? Tu veux un bonbon ?
[CrystalMPQ] C# MPQ Library/Tools - [CrystalBoy] C# GB Emulator - [Monoxide] C# OSX library - M68k Opcodes

180

Pour faire de l'arithmétique de pointeurs, l'utilisation de char * au lieu de void * peut en effet nécessiter davantage de casts.
Cependant, c'est comme ça qu'on fait en C standard. Ici, tu ne te soucies pas de portabilité entre les principaux compilos existants, mais dans le cas général, cette extension non standard casse la compatibilité avec certains des principaux compilos.
avatar
Membre de la TI-Chess Team.
Co-mainteneur de GCC4TI (documentation en ligne de GCC4TI), TIEmu et TILP.
Co-admin de TI-Planet.