"Fast-Regs" GCC extensions proposal: part #1

Benedetto Proietti benedetto73@iol.it
Thu May 24 14:08:00 GMT 2001


Dear GCC colleagues,
my name is Benedetto Proietti and Dynamic One s.a.s. is my own company.
I have worked at the APEmille supercomputer, project of INFN and DESY
(see down), for a while, where I had a chance to face some problems of
advanced cpus: those problems led to develop some GCC technology called
"Fast-Regs" that, here, I wish to present to you.
Contacts will be found at the end of the document.

The mail is so organized:

Presentation
Introduction
Register Structs
Register Structs' History
Example
Limits
Other technologies
Future
Thanks & Greetings
Contacts




INTRODUCTION

"Fast-regs" is a set of GCC extensions to better handle huge register
file cpus. Namely, some work has been done on "register
structs","register arrays" and "#for".
"Fast-Regs" extensions are only for the C language.

All these extensions will hopefully be GPL when finished, and donated to
the GNU GCC project, if accepted by the steering committee. The process
for these extensions to become "official" is not trivial neither short,
neverthless I believe they will be important for GCC, especially for
embedded systems targets.

"Register structs", discussed here, regards the possibility to declare
(and use) structures allocated in the register file.
"Register arrays", not discussed here because at early stage of
development, regards the possibility to declare (and use) arrays
allocated in the register file.
"#for", not discussed here because at early stage of development,
regards loop unrolling done at preprocessing time (or, anyway, before
compilation): this is useful together with register arrays.

Here we will just discuss register structs.


------------------------------------------------------------------------

REGISTER STRUCTs

"register" keyword used with structures, only automatic for now, in the
future also global.

Advantages:
1- "Burst" load and store where the hardware supports it, otherwise
loads and stores grouped together.
2- Values of "register struct" variables are never stored back to
memory, saving lots of time for intermediate results.


-------------------------------------------------------------------------

REGISTER STRUCTS' HISTORY
The APEmille experience

APEmille is a VLIW SIMD supercomputer built for Lattice QCD computations
by INFN (Italian National Institute for Nuclear Physics) and DESY
(Deutsches Elektronen Synchrotronen).
It's peak performance (in the 2048 processors configuration) is about 1
TeraFlops. It consists of a control processor and many numeric
processors, each having a register file of 512 32bit entries.
Each processor has got its own memory, there's no shared memory across
the whole machine, even if each processor can read the neighboroughs'
memories in some way.

In my thesis I developed a porting/extension of GCC (2.95.2) for the
APEmille machine: it worked, but the performance was not good at the
beginning. Infact the memory accesses in APEmille are very low, but
contiguous memory locations can be accessed in bursts (specifying
address and size to the memory controller), saving lots of cycles and
better scheduling the code. So, taking the idea from another language
used in APEmille, TAO, I studied and implemented the "register structs".
With them, the programmer can load a structure in a single burst,
copying it from the memory.
A simple example:

struct su3
{ float c11,c12,c13,c21,c22,c23,c31,c32,c33; };

struct su3 big_array[1000000];

void f()
{
   register struct su3 fast;   	// declaration of a register struct
   fast = big_array[123];    	// BURST load: whole structure loaded
   ...
   fast.c11 = some_function(fast.c22);  // calculations in the register
file
   ...
   big_array[456] = fast;	// BURST store: whole structure stored back
}

With this extensions excellent performance has been reached. For deeper
informations (or to know things from another point of view) you may ask
to the APEmille compiler project coordinator Huber Simma.

The register struct work is still going on, I can summarize what has
been done till now:

- C frontend has been extended to accept "register struct".
- RTL has been extended.
- The Machine Description has been added of a new pattern.
- Optimization modules of GCC has been extended.
- User interface: option added to GCC to enable fast-regs.

Some more details:

- C Frontend
GCC frontend rejects "register" keyword on non basic type variables. Now
it accepts them, allocating pseudo registers for automatic variables
and, in the future, hard registers for global ones.

- RTL
REGSET operand has been added. Let's see an rtx example:

(insn 15 12 17 (set (mem/s:BLK (symbol_ref:SI ("memo_variable")) 0)
        (regset:BLK[ 
                (reg:SI 15 r15)
                (reg:SI 14 r14)
                (reg:SI 13 r13)
                (reg:SI 12 r12)
                (reg:SI 11 r11)
                (reg:SI 10 r10)
            ] )) 61 {hard_movblk_from_regset} (nil)
    (nil))


REGSET is a vector of rtx, each of them being a REG or a REGSET.
Let's see the definition from rtl.def:

/* (REGSET a b c ...) represent a virtual concatenation on many
registers.
    This is used for "register struct" and "register arrays". */
DEF_RTL_EXPR(REGSTE, "regset", "E", 'x')

It is not possible right now to allocate contiguous registers in a
REGSET.
In the future it will be possible to allocate contiguous registers
REGSET, problably specifying it with an asm directive or an attribute.

-Machine Description:
A new "mov" has been added: movblk, with the following pattern:

(define_expand "movblk"
[(set (match_operand:BLK 0 "general_operand" "") 
      (match_operand:BLK 1 "general_operand" ""))]

An example of movblk definition (taken from amd29k fast-regs compiler
prototype) is:

(define_expand "movblk"
[(set (match_operand:BLK 0 "general_operand" "") 
      (match_operand:BLK 1 "general_operand" ""))]
""
"{
   if (GET_CODE(operands[0])==REGSET)
       operands[0] = RS_linearize_regset (operands[0]);
   if (GET_CODE(operands[1])==REGSET)
       operands[1] = RS_linearize_regset (operands[1]);
 }")

Where RS_linearize_regset simply converts nested REGSET in a linear
vector of REGs.

The movblk pattern is probably subject to change.

-Optimization modules:
Almost every GCC optimization module has been enhanced to handle
register structs, and much work must still be done. Infact many
programs, even simple, are broken with register structs.

-User interface
Usually an option "-mfast-regs" is added to cc1 and to cpp (yes, also to
cpp) to enable fast-regs extensions.

-------------------------------------------------------------------------

EXAMPLE
Inverting the Dirac operator

You can see in the attachments an example where register struct have
been successfully used.
There are two versions of the same function "dirac_qphi2"	with and
without register structs.
The essential differences in the two versions are some variable
definitions:

// dirac_qphi.c - WITHOUT register structs
  su3*        pu;
  su3_spinor  *pp, *pres;

// dirac_qphi_rs.c - WITH register structs
  register su3         pu;
  register su3_spinor  pp, pres;


and the their use:

// dirac_qphi.c - WITHOUT register structs
........
	  // contribution of the direction +1 (+x):
	  // --------------------------------------
	  pp = &phi[k][it][ipx];               
	  pu = &u[it][ix][1];
	  pres = &phi[j][it][ix];
	  *(pres) = phi[k][it][ix]; 
.............
	  V_M_V( CHI_A, (*pu), PSI_A );         // dereference pointer: read
from memory!
					                // (reads one field at the time)


// dirac_qphi_rs.c - WITH register structs
........
	  // contribution of the direction +1 (+x):
	  // --------------------------------------
	  pp = phi[k][it][ipx];    //load pp, burst load
	  pu = u[it][ix][1];       //load pu, burst load

	  pres = phi[k][it][ix];  //load pres, burst load
............
	  V_M_V( CHI_A, pu, PSI_A );            // use registers in "register
struct" variable!


Originally they store in pu, pp pointers to spinors, and the "strange"
macros dereferenced the pointers. (For instance, the meaning of the
macros is kind of: V_M_V  "Vector  = Matrix X Vector", you can read them
in the attached qcd.h).

With register struct we declared pp and pu as "register struct"
variable, and loaded (and stored) them in bursts.


Here you can see a piece from the rtl dump (.rtl, "-dr")


//WITHOUT "register struct" --------------------------------------------
..........
	MEMTOJ2	486:24	^0x216ca.18  !!burst in
	JTOMEM2	^0x0.19 	486:24 !!burst out
	MEMTOJ2 	34 :2 ^0x12.16 
	MEMTOJ2 	36 :2 ^0x0.16 
	JCNORM_PP 	44  8  34  36 
	JTOMEM2 	^0x0.FP 44  :2
	MEMTOJ2 	34 :2 ^0x14.16 
	MEMTOJ2 	36 :2 ^0x2.16 
	JCNORM_PP 	42  8  34  36 
	JTOMEM2 	^0x2.FP 42  :2
	MEMTOJ2 	34 :2 ^0x16.16 
	MEMTOJ2 	36 :2 ^0x4.16 
	JCNORM_PP 	38  8  34  36 
	JTOMEM2 	^0x4.FP 38  :2
	MEMTOJ2 	34 :2 ^0xc.16 
	MEMTOJ2 	36 :2 ^0x6.16 
	JCNORM_PP 	54  8  34  36 
	JTOMEM2 	^0x40.FP 54  :2
	MEMTOJ2 	34 :2 ^0xe.16 
	MEMTOJ2 	36 :2 ^0x8.16 
	JCNORM_PP 	50  8  34  36 
	JTOMEM2 	^0x42.FP 50  :2
	MEMTOJ2 	34 :2 ^0x10.16 
	MEMTOJ2 	36 :2 ^0xa.16 
	JCNORM_PP 	48  8  34  36 
	JTOMEM2 	^0x44.FP 48  :2
	MEMTOJ2 	34 :2 ^0x12.21 
	MEMTOJ2 	36 :2 ^0x2.17 
	JCNORM_PP 	36  36  42  0
	JCNORM_PP 	36  34  44  36 
	MEMTOJ2 	34 :2 ^0x4.17 
	JCNORM_PP 	56  34  38  36 
	JTOMEM2 	^0x80.FP 56  :2
	MEMTOJ2 	34 :2 ^0x6.17 
	MEMTOJ2 	36 :2 ^0x8.17 
	JCNORM_PP 	36  36  42  0
	JCNORM_PP 	36  34  44  36 
	MEMTOJ2 	34 :2 ^0xa.17 
	JCNORM_PP 	52  34  38  36 
	JTOMEM2 	^0x82.FP 52  :2
	MEMTOJ2 	34 :2 ^0xc.17 
	MEMTOJ2 	36 :2 ^0xe.17 
	JCNORM_PP 	36  36  42  0
	JCNORM_PP 	36  34  44  36 
	MEMTOJ2 	34 :2 ^0x10.17 
	JCNORM_PP 	46  34  38  36 
	JTOMEM2 	^0x84.FP 46  :2
	MEMTOJ2 	34 :2 ^0x12.21 
	MEMTOJ2 	36 :2 ^0x2.17 
	JCNORM_PP 	36  36  50  0
	JCNORM_PP 	36  34  54  36 
	MEMTOJ2 	34 :2 ^0x4.17 
	JCNORM_PP 	44  34  48  36 
	JTOMEM2 	^0xc0.FP 44  :2
	MEMTOJ2 	34 :2 ^0x6.17 
	MEMTOJ2 	36 :2 ^0x8.17 
	JCNORM_PP 	36  36  50  0
	JCNORM_PP 	36  34  54  36 
	MEMTOJ2 	34 :2 ^0xa.17 
	JCNORM_PP 	38  34  48  36 
	JTOMEM2 	^0xc2.FP 38  :2
	MEMTOJ2 	34 :2 ^0xc.17 
	MEMTOJ2 	36 :2 ^0xe.17 
	JCNORM_PP 	36  36  50  0
	JCNORM_PP 	36  34  54  36 
	MEMTOJ2 	34 :2 ^0x10.17 
	JCNORM_PP 	36  34  48  36 
	JTOMEM2 	^0xc4.FP 36  :2
	JCNORM_PP 	34  58  8  0
	JCNORM_PP 	42  34  56  56 
	JTOMEM2 	^0x0.FP 42  :2
	JCNORM_PP 	34  34  52  52 
	JTOMEM2 	^0x2.FP 34  :2
	JCNORM_PP 	34  58  8  0
	JCNORM_PP 	34  34  46  46 
	JTOMEM2 	^0x4.FP 34  :2
	JCNORM_PP 	34  58  8  0
	JCNORM_PP 	34  34  44  44 
	JTOMEM2 	^0x40.FP 34  :2
	JCNORM_PP 	34  58  8  0
	JCNORM_PP 	34  34  38  38 
	JTOMEM2 	^0x42.FP 34  :2
	JCNORM_PP 	34  58  8  0
	JCNORM_PP 	34  34  36  36 
	JTOMEM2 	^0x44.FP 34  :2
	MEMTOJ2 	34 :2 ^0x0.19 
	JCNORM_MM 	34  40  42  34 
	JTOMEM2 	^0x0.19  34  :2
	MEMTOJ2 	34 :2 ^0x2.FP
	MEMTOJ2 	36 :2 ^0x2.19 
	JCNORM_MM 	34  40  34  36 
	JTOMEM2 	^0x2.19  34  :2
	MEMTOJ2 	34 :2 ^0x4.FP
	MEMTOJ2 	36 :2 ^0x4.19 
	JCNORM_MM 	34  40  34  36 
	JTOMEM2 	^0x4.19  34  :2
	MEMTOJ2 	34 :2 ^0x40.FP
	MEMTOJ2 	36 :2 ^0x6.19 
	JCNORM_MM 	34  40  34  36 
	JTOMEM2 	^0x6.19  34  :2
	MEMTOJ2 	34 :2 ^0x42.FP
	MEMTOJ2 	36 :2 ^0x8.19 
	JCNORM_MM 	34  40  34  36 
	JTOMEM2 	^0x8.19  34  :2
	MEMTOJ2 	34 :2 ^0x44.FP
	MEMTOJ2 	36 :2 ^0xa.19 
	JCNORM_MM 	34  40  34  36 
	JTOMEM2 	^0xa.19  34  :2
	JCNORM_PP 	38  40  8  0
	MEMTOJ2 	34 :2 ^0x40.FP
	MEMTOJ2 	36 :2 ^0xc.19 
	JCNORM_PP 	34  38  34  36 
	JTOMEM2 	^0xc.19  34  :2
	MEMTOJ2 	34 :2 ^0x42.FP
	MEMTOJ2 	36 :2 ^0xe.19 
	JCNORM_PP 	34  38  34  36 
	JTOMEM2 	^0xe.19  34  :2
	MEMTOJ2 	34 :2 ^0x44.FP
	MEMTOJ2 	36 :2 ^0x10.19 
	JCNORM_PP 	34  38  34  36 
	JTOMEM2 	^0x10.19  34  :2
	MEMTOJ2 	34 :2 ^0x0.FP
	MEMTOJ2 	36 :2 ^0x12.19 
	JCNORM_PP 	34  38  34  36 
	JTOMEM2 	^0x12.19  34  :2
	MEMTOJ2 	34 :2 ^0x2.FP
	MEMTOJ2 	36 :2 ^0x14.19 
	JCNORM_PP 	34  38  34  36 
	JTOMEM2 	^0x14.19  34  :2
	MEMTOJ2 	34 :2 ^0x4.FP
	MEMTOJ2 	36 :2 ^0x16.19 
	JCNORM_PP 	34  38  34  36 
	JTOMEM2 	^0x16.19  34  :2
	TMULA 		16  37  26 
	TADD 		16  22  16 
	TADD 		18  24  41 
	TAGU2 		17  0x12.18 
	MEMTOJ2 	34 :2 ^0x12.16 
	MEMTOJ2 	36 :2 ^0x0.16 
	JCNORM_MM 	42  8  34  36 
	JTOMEM2 	^0x0.FP 42  :2
	MEMTOJ2 	34 :2 ^0x14.16 
	MEMTOJ2 	36 :2 ^0x2.16 
	JCNORM_MM 	44  8  34  36 
	JTOMEM2 	^0x2.FP 44  :2
	MEMTOJ2 	34 :2 ^0x16.16 
	MEMTOJ2 	36 :2 ^0x4.16 
	JCNORM_MM 	46  8  34  36 
	JTOMEM2 	^0x4.FP 46  :2
	MEMTOJ2 	34 :2 ^0xc.16 
	MEMTOJ2 	36 :2 ^0x6.16 
	JCNORM_MM 	50  8  34  36 
	JTOMEM2 	^0x40.FP 50  :2
	MEMTOJ2 	34 :2 ^0xe.16 
	MEMTOJ2 	36 :2 ^0x8.16 
	JCNORM_MM 	52  8  34  36 
	JTOMEM2 	^0x42.FP 52  :2
	MEMTOJ2 	34 :2 ^0x10.16 
	MEMTOJ2 	36 :2 ^0xa.16 
	JCNORM_MM 	54  8  34  36 
	JTOMEM2 	^0x44.FP 54  :2
...........
//--------------------------------------------------------------------

// WITH "register struct" --------------------------------------------

	PRAGMA_REGSET [ 108 109 110 111 112 113 114 115 116 117 118 119 120 121
122 123 124 125 126 127 128 129 130 131 ]
	MEMTOJ2 	REGSET 0x216ca.16 
	TMULA 		19  23  27 
	TADD 		20  25  19 
	PRAGMA_REGSET [ 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 ]
	MEMTOJ2 	REGSET 0x20014.20 
	TADD 		21  24  17 
	TADD 		16  21  18 
	PRAGMA_REGSET [ 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101
102 103 104 105 106 107 ]
	MEMTOJ2 	REGSET 0x216ca.16 
	JCNORM_PP 	40  8  126  108 
	JCNORM_PP 	42  8  128  110 
	JCNORM_PP 	44  8  130  112 
	JCNORM_PP 	48  8  120  114 
	JCNORM_PP 	52  8  122  116 
	JCNORM_PP 	54  8  124  118 
	JCNORM_PP 	34  68  42  0
	JCNORM_PP 	34  66  40  34 
	JCNORM_PP 	64  70  44  34 
	JCNORM_PP 	34  74  42  0
	JCNORM_PP 	34  72  40  34 
	JCNORM_PP 	60  76  44  34 
	JCNORM_PP 	34  80  42  0
	JCNORM_PP 	34  78  40  34 
	JCNORM_PP 	58  82  44  34 
	JCNORM_PP 	34  68  52  0
	JCNORM_PP 	34  66  48  34 
	JCNORM_PP 	56  70  54  34 
	JCNORM_PP 	34  74  52  0
	JCNORM_PP 	34  72  48  34 
	JCNORM_PP 	50  76  54  34 
	JCNORM_PP 	34  80  52  0
	JCNORM_PP 	34  78  48  34 
	JCNORM_PP 	38  82  54  34 
	JCNORM_PP 	34  62  8  0
	JCNORM_PP 	40  34  64  64 
	JCNORM_PP 	42  34  60  60 
	JCNORM_PP 	44  34  58  58 
	JCNORM_PP 	48  34  56  56 
	JCNORM_PP 	52  34  50  50 
	JCNORM_PP 	54  34  38  38 
	JCNORM_MM 	84  46  40  84 
	JCNORM_MM 	86  46  42  86 
	JCNORM_MM 	88  46  44  88 
	JCNORM_MM 	90  46  48  90 
	JCNORM_MM 	92  46  52  92 
	JCNORM_MM 	94  46  54  94 
	JCNORM_PP 	34  46  8  0
	JCNORM_PP 	96  34  48  96 
	JCNORM_PP 	98  34  52  98 
	JCNORM_PP 	100  34  54  100 
	JCNORM_PP 	102  34  40  102 
	JCNORM_PP 	104  34  42  104 
	JCNORM_PP 	106  34  44  106 
	TADD3 		16  36  17  18 
	PRAGMA_REGSET [ 108 109 110 111 112 113 114 115 116 117 118 119 120 121
122 123 124 125 126 127 128 129 130 131 ]
	MEMTOJ2 	REGSET 0x216ca.16 
	................
//--------------------------------------------------------------------------------------------------------------

The two above are the same piece of C code.
For the curious:
- MEMTOJ: MEMory to J1000, the numeric processors
- JCNORM_XY: J1000 Complex "NORMal". A normal operation is A*B+C.
APEmille can start a normal each cycle; also it handles natively complex
numbers (2*32bit contiguous registers). The _XY indicates the signs of C
and of the whole result.
- PRAGMA_REGSET: asm preprocessor directive: declares a SET of
REGisters.
- TADD: T1000 control processor addition. T1000 is used for flow
control, address generation, and little more.
- TMULA: T1000 multiplication that ignores bits 23-30. Why? If those
bits are set, each J1000 does not load data from its memory, but from
others' J1000 memories.

The improvement is easy to read even at the assembly level.
Being a VLIW machine, APEmille has got a binary scheduler post-compiler
(we called it "shaker"). After that pass the performance is
significantly increased with "register struct".

Here you can see some RTL dump (.rtl "-dr") associated to the structures
load, in both cases.
I leave you the task to find who is who!


//
------------------------------------------------------------------------------------------------------------
insn 443 441 445 (set (reg:SC 952)
        (mem/s:SC (plus:SI (reg/v:SI 790)
                (const_int 2 [0x2])) 10)) -1 (nil)
    (nil))

(insn 445 443 447 (set (reg:SC 953)
        (minus:SC (reg:SC 952)
            (reg:SC 951))) -1 (nil)
    (nil))

(insn 447 445 449 (set (mem/s:SC (plus:SI (reg/v:SI 790)
                (const_int 2 [0x2])) 10)
        (reg:SC 953)) -1 (nil)
    (nil))

(insn 449 447 451 (set (reg:SC 954)
        (mem/s:SC (plus:SI (reg:SI 769)
                (const_int 4 [0x4])) 10)) -1 (nil)
    (nil))
//
------------------------------------------------------------------------------------------------------------

//-------------------------------------------------------------------------------------------------------------

(insn 123 121 126 (parallel[ 
            (set (regset:BLK[ 
                        (regset:BLK[ 
                                (reg:SC 809)
                                (reg:SC 810)
                                (reg:SC 811)
                            ] )
                        (regset:BLK[ 
                                (reg:SC 812)
                                (reg:SC 813)
                                (reg:SC 814)
                            ] )
                        (regset:BLK[ 
                                (reg:SC 815)
                                (reg:SC 816)
                                (reg:SC 817)
                            ] )
                        (regset:BLK[ 
                                (reg:SC 818)
                                (reg:SC 819)
                                (reg:SC 820)
                            ] )
                    ] )
                (mem/s:BLK (plus:SI (const_int 136906 [0x216ca])
                        (reg:SI 855)) 0))
            (use (const_int 24 [0x18]))
            (use (const_int 2 [0x2]))
        ] ) -1 (nil)
    (nil))

(insn 126 123 128 (set (reg:SC 856)
        (mult:SC (reg/v:SC 264 8)
            (reg:SC 806))) -1 (nil)
    (nil))

(insn 128 126 130 (set (reg:SC 821)
        (plus:SC (reg:SC 797)
            (reg:SC 856))) -1 (nil)
    (nil))

(insn 130 128 132 (set (reg:SC 857)
        (mult:SC (reg/v:SC 264 8)
            (reg:SC 807))) -1 (nil)
    (nil))
//
-----------------------------------------------------------------------


For the curious:
-	APEmille GCC has been extended to allocate complex numbers in
contiguous (even) registers, as you can see from the "reg:SC"
-	In APEmille "register structs" I defined the REGSET mov pattern as a
movstrsi variant, as you could imagine from the code. Now I do it with
the movblk pattern, presented before.



LIMITS

Register struct development is far from being finished.
For instance, you cannot:
-	declare arrays inside a register struct.
-	use bitfields.
-	declare "char" fileds.
You CAN declare register struct inside register struct.


-----------------------------------------------------------------------

OTHER TECHNOLOGIES

You will probably and hopefully hear about register arrays, whose
meaning is easy to understand, and #for (I pronounce it "pound for"; say
as you prefer).
#for is a preliminarry prototype of preprocessing loop unroll, very
powerful with register arrays.

------------------------------------------------------------------------

FUTURE

The purpose of this mail is to open this work to everybody interested in
improving GCC, and free software in general.
There's lot of work to do in order to have production register structs,
and Fast-Regs in general.
Also, if the GNU GCC committee likes the idea of these extensions, there
will be lots of test and coding to make it acceptable by the committee.
I would like to share my work, and first of all to know considerations
and comments that you, GCC experts, may have. So please write.
A Dynamic One s.a.s. website is coming soon; there you will be able to
use some prototypes compiler on-line. Also, one (or more) mailing list
will be opened.

-----------------------------------------------------------------------

Thanks & Greetings

I wish to thank Cristiano De Michele, Hubert Simma, Michele Plaja,
Alberto Moriconi, Federico Di Carlo and Filippo Basso for their
suggestions, experience and help.

Thank to you for your attention, hope this could have helped or, at
least, given you something to think to.

Best Regards
Benedetto Proietti



-----------------------------------------------------------------------

CONTACTS

Benedetto Proietti      benedetto73@iol.it                 
Huber Simma             simma@ifh.de                       APE compile
project coordinator
Raffaele Tripiccione    raffaele.tripiccione@pi.infn.it    APE group
leader

APEmille                http://chimera.roma1.infn.it/ape.html
INFN                    http://www.infn.it
DESY                    http://www.desy.de
// -*- C++ -*-
//
// qcd.h  -- structures for
//           su3  (gauge links)
//           su3_vector
//           su3_spinor
//           macros for su3_vector operations 
//           and auxiliary IO functions
//
// hs 3/99
//
// $Id: qcd.h,v 1.4 2000/11/24 15:34:55 betto Exp $
// ---------------------------------------------------------
#ifndef __QCD_H__
#define __QCD_H__

#ifndef __APEmille__
#include <stdio.h>
#endif

#define SINGLE 

#ifdef SINGLE
#define FLOAT_TYPE  float
#define FLOAT_NAME "float"
#define RFMT "%f "
#else
#define FLOAT_TYPE  double
#define FLOAT_NAME "double"
#define RFMT "%lf "
#endif

#ifdef GCC_COMPLEX
#define COMPLEX_TYPE  __complex__  FLOAT_TYPE
#define COMPLEX_NAME "__complex__"
#else
struct complex { FLOAT_TYPE re, im; };
#define COMPLEX_TYPE complex
#define COMPLEX_NAME "struct"
#endif


// SU3:
// ----
typedef struct { COMPLEX_TYPE c11, c12, c13, c21, c22, c23, c31, c32, c33;} su3;
// su3_vector:
// -----------
typedef struct { COMPLEX_TYPE c1, c2, c3; } su3_vector;

// su3_spinor:
//------------
typedef struct { su3_vector v1, v2, v3, v4; } su3_spinor;


// Macros for su3_vectors:
// -----------------------

#ifdef GCC_COMPLEX
// Auxiliary Macros:
#if  (!defined(__APE_COMPLEX__) && defined(__APEmille__))
#error "APE_complex.h needed!"
#endif
#define MUL(A,B)     A*B
#define CMUL(A,B)    MUL((~A),B)        //(~A)*B

#ifndef __APEmille__
#define I(A)      1.0i*A
#define IR(R,A) R*1.0i*A
#else
#define I(A)      i_complex*A
#define IR(R,A) (R*i_complex*A)
#endif

// RE and IM only for read/write
#define RE(A)       __real__ A
#define IM(A)       __imag__ A

// Prototype Macro:  su3 =  su3 * su3
#define M_M_M(A,M,V) \
  A.c11 = MUL(M.c11,V.c11) + MUL(M.c12,V.c21) + MUL(M.c13,V.c31 ) ; \
  A.c12 = MUL(M.c11,V.c12) + MUL(M.c12,V.c22) + MUL(M.c13,V.c32 ) ; \
  A.c13 = MUL(M.c11,V.c13) + MUL(M.c12,V.c23) + MUL(M.c13,V.c33 ) ; \
  A.c21 = MUL(M.c21,V.c11) + MUL(M.c22,V.c21) + MUL(M.c23,V.c31 ); \
  A.c22 = MUL(M.c21,V.c12) + MUL(M.c22,V.c22) + MUL(M.c23,V.c32 ); \
  A.c23 = MUL(M.c21,V.c13) + MUL(M.c22,V.c23) + MUL(M.c23,V.c33 ); \
  A.c31 = MUL(M.c31,V.c11) + MUL(M.c32,V.c21) + MUL(M.c33,V.c31 ); \
  A.c32 = MUL(M.c31,V.c12) + MUL(M.c32,V.c22) + MUL(M.c33,V.c32 ); \
  A.c33 = MUL(M.c31,V.c13) + MUL(M.c32,V.c23) + MUL(M.c33,V.c33 ); 

// Prototype Macro:  su3_vector =  su3 * su3_vector
#define V_M_V(A,M,V) \
  A.c1 = MUL(M.c11,V.c1) + MUL(M.c12,V.c2) + MUL(M.c13,V.c3 ) ; \
  A.c2 = MUL(M.c21,V.c1) + MUL(M.c22,V.c2) + MUL(M.c23,V.c3 ); \
  A.c3 = MUL(M.c31,V.c1) + MUL(M.c32,V.c2) + MUL(M.c33,V.c3 ); 

// Prototype Macro:  su3_vector =  su3^\daggger * su3_vector
#define V_MC_V(A,M,V) \
  A.c1 = CMUL(M.c11,V.c1) + CMUL(M.c21,V.c2) + CMUL(M.c31,V.c3 ); \
  A.c2 = CMUL(M.c12,V.c1) + CMUL(M.c22,V.c2) + CMUL(M.c32,V.c3 ); \
  A.c3 = CMUL(M.c13,V.c1) + CMUL(M.c23,V.c2) + CMUL(M.c33,V.c3 ); 

//Betto Prototype Macro:  su3_vector =  su3^\daggger * su3_vector
//the *single* matrix elements have been already conjugated...
#define V_MXC_V(A,M,V) \
  A.c1 = MUL(M.c11,V.c1) + MUL(M.c21,V.c2) + MUL(M.c31,V.c3 ); \
  A.c2 = MUL(M.c12,V.c1) + MUL(M.c22,V.c2) + MUL(M.c32,V.c3 ); \
  A.c3 = MUL(M.c13,V.c1) + MUL(M.c23,V.c2) + MUL(M.c33,V.c3 ); 

// Prototype Macro:  su3_vector  su3_vector  F  ( R , su3_vector )
#define V_V_F_R_V(A,B,F,R,C) \
  A.c1 B.c1 F(R,C.c1); \
  A.c2 B.c2 F(R,C.c2); \
  A.c3 B.c3 F(R,C.c3); 

// Prototype Macro:  su3_vector  su3_vector  F  ( su3_vector )
#define V_V_F_V(A,B,F,C) \
  A.c1 B.c1 F( C.c1 ); \
  A.c2 B.c2 F( C.c2 ); \
  A.c3 B.c3 F( C.c3 ); 

// Prototype Macro:  su3_vector  F ( R, su3_vector ) )
#define V_F_R_V(A,F,R,B) \
  A.c1 F ( R, B.c1 ); \
  A.c2 F ( R, B.c2 ); \
  A.c3 F ( R, B.c3 ); 

// Prototype Macro:  su3_vector  F ( su3_vector ) )
#define V_F_V(A,F,B) \
  A.c1 F ( B.c1 ); \
  A.c2 F ( B.c2 ); \
  A.c3 F ( B.c3 ); 

// Prototype Macro:  su3_vector  su3_vector
#define V_V(A,B) \
  A.c1 B.c1 ; \
  A.c2 B.c2 ; \
  A.c3 B.c3 ; 

//by betto
#define V_OPC(A,c) \
  A.c1 c ; \
  A.c2 c ; \
  A.c3 c ; 



#else

// Auxiliary macros:
#define MULRE(A,B)  (A.re * B.re - A.im * B.im)
#define MULIM(A,B)  (A.re * B.im + A.im * B.re)
#define CMULRE(A,B) (A.re * B.re + A.im * B.im)
#define CMULIM(A,B) (A.re * B.im - A.im * B.re)

#define RE(A)       A.re
#define IM(A)       A.im
// i_times
#define IRE(A)     -A.im
#define IIM(A)      A.re
// i_times real
#define IRRE(R,A)  -R*A.im
#define IRIM(R,A)   R*A.re

// Prototype Macro:  su3_vector =  su3 * su3_vector
#define V_M_V(A,M,V) \
  A.c1.re = MULRE(M.c11,V.c1) + MULRE(M.c12,V.c2) + MULRE(M.c13,V.c3); \
  A.c1.im = MULIM(M.c11,V.c1) + MULIM(M.c12,V.c2) + MULIM(M.c13,V.c3); \
  A.c2.re = MULRE(M.c21,V.c1) + MULRE(M.c22,V.c2) + MULRE(M.c23,V.c3); \
  A.c2.im = MULIM(M.c21,V.c1) + MULIM(M.c22,V.c2) + MULIM(M.c23,V.c3); \
  A.c3.re = MULRE(M.c31,V.c1) + MULRE(M.c32,V.c2) + MULRE(M.c33,V.c3); \
  A.c3.im = MULIM(M.c31,V.c1) + MULIM(M.c32,V.c2) + MULIM(M.c33,V.c3); 

// Prototype Macro:  su3_vector =  su3^\daggger * su3_vector
#define V_MC_V(A,M,V) \
  A.c1.re = CMULRE(M.c11,V.c1) + CMULRE(M.c21,V.c2) + CMULRE(M.c31,V.c3);\
  A.c1.im = CMULIM(M.c11,V.c1) + CMULIM(M.c21,V.c2) + CMULIM(M.c31,V.c3);\
  A.c2.re = CMULRE(M.c12,V.c1) + CMULRE(M.c22,V.c2) + CMULRE(M.c32,V.c3);\
  A.c2.im = CMULIM(M.c12,V.c1) + CMULIM(M.c22,V.c2) + CMULIM(M.c32,V.c3);\
  A.c3.re = CMULRE(M.c13,V.c1) + CMULRE(M.c23,V.c2) + CMULRE(M.c33,V.c3);\
  A.c3.im = CMULIM(M.c13,V.c1) + CMULIM(M.c23,V.c2) + CMULIM(M.c33,V.c3); 

// Prototype Macro:  su3_vector  su3_vector  F  ( R , su3_vector )
#define V_V_F_R_V(A,B,F,R,C) \
  A.c1.re B.c1.re F##RE (R,C.c1); \
  A.c1.im B.c1.im F##IM (R,C.c1); \
  A.c2.re B.c2.re F##RE (R,C.c2); \
  A.c2.im B.c2.im F##IM (R,C.c2); \
  A.c3.re B.c3.re F##RE (R,C.c3); \
  A.c3.im B.c3.im F##IM (R,C.c3); 

// Prototype Macro:  su3_vector  su3_vector  F  ( su3_vector )
#define V_V_F_V(A,B,F,C) \
  A.c1.re B.c1.re F##RE ( C.c1 ); \
  A.c1.im B.c1.im F##IM ( C.c1 ); \
  A.c2.re B.c2.re F##RE ( C.c2 ); \
  A.c2.im B.c2.im F##IM ( C.c2 ); \
  A.c3.re B.c3.re F##RE ( C.c3 ); \
  A.c3.im B.c3.im F##IM ( C.c3 ); 

// Prototype Macro:  su3_vector  F ( R, su3_vector ) )
#define V_F_R_V(A,F,R,B) \
  A.c1.re F##RE ( R, B.c1 ); \
  A.c1.im F##IM ( R, B.c1 ); \
  A.c2.re F##RE ( R, B.c2 ); \
  A.c2.im F##IM ( R, B.c2 ); \
  A.c3.re F##RE ( R, B.c3 ); \
  A.c3.im F##IM ( R, B.c3 ); 

// Prototype Macro:  su3_vector  F ( su3_vector ) )
#define V_F_V(A,F,B) \
  A.c1.re F##RE ( B.c1 ); \
  A.c1.im F##IM ( B.c1 ); \
  A.c2.re F##RE ( B.c2 ); \
  A.c2.im F##IM ( B.c2 ); \
  A.c3.re F##RE ( B.c3 ); \
  A.c3.im F##IM ( B.c3 ); 

// Prototype Macro:  su3_vector  su3_vector
#define V_V(A,B) \
  A.c1.re B.c1.re ; \
  A.c1.im B.c1.im ; \
  A.c2.re B.c2.re ; \
  A.c2.im B.c2.im ; \
  A.c3.re B.c3.re ; \
  A.c3.im B.c3.im ; 

#endif

#ifndef __APEmille__
// Auxiliary IO functions:
// -----------------------
void freadu(FILE *fp, su3 *u);
void fwriteu(FILE *fp, su3 u);
void freadp(FILE *fp, su3_spinor *p);
void fwritep(FILE *fp, su3_spinor p);
#endif

#endif
//---------------------------  EOF  -------------------------------







More information about the Gcc mailing list