modification d'une instruction de GCC

Par Wilfrid et Michel

Application : modifier une instruction du FR30

Le schéma présente une vue de l’ensemble des programmes et fichiers rentrant en jeu pour l’élaboration du compilateur GCC pour une cible particulière. On remarque en vert les fichiers à modifier, en jaune les fichiers et/ou programmes intermédiaires et finalement les exécutables en orange.

Voici maintenant un exmple détaillé de modification de code afin d'intégrer une "nouvelle" instruction à GCC. Dans cette partie, <arch> correspond au FR30 de Fujitsu. Pour cela, nous modifions directement les fichiers opcodes. Cette procédure aurait pu se faire en modifiant le fichiers '<arch>.cpu'. Mais pour des raisons de simplicité, nous modifierons directement les fichiers générés.

Nous allons présenter les 4 grands points nécessaires à la réalisation.

1. Modification des fichiers opcode.
2. Compilation des binutils.
3. Modification du fichier de description '<arch>.md' de GCC.
4. Compilation finale de GCC.

La modification des fichiers opcode se fait par l'intermédiaire de '<arch>-desc.c'. Nous déciderons arbitrairement de modifier la multiplication.

Les fonctions sont représentées par le type CGEN_IBASE. Ces représentations sont structurées sous formes de tableaux.

typedef struct
{
  int num;
  const char *name;
  const char *mnemonic;
  int bitsize;
  CGEN_INSN_ATTR_TYPE attr;
} CGEN_IBASE;

Voici la fonction originale (celle du FR30 ligne 766)

/* mul $Rj,$Ri originale */
{
  FR30_INSN_MUL, "mul", "mul", 16,
  { 0|A(NOT_IN_DELAY_SLOT), { (1<<MACH_BASE) } }
},

Nous pouvons constater que la fonction est encapsulée par des accolades et des virgules car CGEN a créé un tableau de fonctions.

Voici maintenant la fonction modifiée.

/* mul $Rj,$Ri modifiée*/
  {
    FR30_INSN_MUL, "ISIMA", "ISIMA", 16,
    { 0|A(NOT_IN_DELAY_SLOT), { (1<<MACH_BASE) } }
  },

Ainsi, nous avons uniquement changé le mnémonique de la multiplication. Nous avons donné le même nom pour faciliter le travail et éviter les confusions entre nom et mnémonique. Le numéro de la fonction reste identique à savoir la valeur énumérée FR30_INSN_MUL.

La deuxième étape consiste à compiler les sources des binutils. Ci après nous indiquons les commandes à exécuter. Attention, il faut respecter la configuration des dossiers. Le temps de compilation peut être de 10 min à 1 heure en fonction de la puissance de l'ordinateur.

root@xdoofy:/usr/binutilsFR30# ./binutils-2.16.1/configure --target=fr30-fujitsu-elf --prefix=/usr/gcctemp root@xdoofy:/usr/binutilsFR30# make root@xdoofy:/usr/binutilsFR30# make install

Pendant que l'ordinateur compile les binutils, nous pouvons modifier les fichiers de description de GCC à savoir 'gcc/config/<arch>/<arch>.md'.
Nous rappelons que les informations contenues dans ces fichiers sont au format Lisp. Après avoir identifier le vecteur d'expressions correspondant à la multiplication.

Voici la fonction originale (celle du FR30 ligne 788)

;; Signed multiplication producing 32 bit result from 32 bit inputs
(define_insn "mulsi3"
  [(set (match_operand:SI 0 "register_operand"             "=r")
           (mult:SI (match_operand:SI 1 "register_operand" "%r")
                    (match_operand:SI 2 "register_operand"  "r")))
   (clobber (reg:CC 16))]
  ""
  "mul  %2, %1\\n\\tmov\\tmdl, %0"
  [(set_attr "length" "4")]
)

Maintenant, modifions le mnémonique mul par ISIMA.

;; Signed multiplication producing 32 bit result from 32 bit inputs
(define_insn "mulsi3"
  [(set (match_operand:SI 0 "register_operand"             "=r")
           (mult:SI (match_operand:SI 1 "register_operand" "%r")
                    (match_operand:SI 2 "register_operand"  "r")))
   (clobber (reg:CC 16))]
  ""
  "ISIMA  %2, %1\\n\\tmov\\tmdl, %0"
  [(set_attr "length" "4")]
)

Après cette modification, et une fois la compilation précédente achevée, nous pouvons compiler GCC à proprement dit. Pour cela, nous exécutons les commandes suivantes :

root@xdoofy:/usr/gccFR30# ./gcc-3.4.5/configure --prefix=/usr/gcctemp --enable-languages="c" --target=fr30-fujitsu-elf

Une fois la configuration faite, il faut penser à modifier le PATH en incluant le chemin d'accès du dossier qui contient les exécutables créés lors de la compilation des binutils.

root@xdoofy:/usr/gccFR30# export PATH=$PATH:/usr/gcctemp/bin/

Ensuite, il ne reste plus qu'à créer l'exécutable GCC.

root@xdoofy:/usr/gccFR30# make root@xdoofy:/usr/gccFR30# make install

Maintenant, nous allons tester notre nouveau compilateur. Pour cela, nous allons créer un code C utilisant la multiplication.

root@xdoofy:/usr/exemple#Fujitsu-FR30-gcc-3.4.5 -s test.c

Nous allons tester le code suivant :

int main(void){
int a=323;
int b=467653;
return a*b;}

Voici le résultat avant la manipulation :

...
    ld        @r2, r2
    ld        @r1, r1
    mul       r1, r2
    mov       mdl, r1
    mov       r1, r4
...

et après :

...
    ld        @r2, r2
    ld        @r1, r1
    ISIMA     r1, r2
    mov       mdl, r1
    mov       r1, r4
...
Simple-Cpu The Simple CPU project The Simple CPU project
Un projet de disk91
Small CPU project