Article: ARM Goes 64-bit
By: Exophase (exophase.delete@this.gmail.com), August 17, 2012 8:30 am
Room: Moderated Discussions
Kenneth Jonsson (kj.delete@this.localhost.org) on August 17, 2012 2:41 am wrote:
> Its true one can make use of a large number of GPRs in
> hand-written assembler, I've done a lot of assembler programming on 68k and
> while the 8 addresser register was often enough, having just 8 data register was
> often a limitation. I've also done some assembler optimizations for ARM and my
> handwritten functions definitely uses more GPRs compared to the code generated
> by GCC.
>
> It has been suggested that the load/store nature of a RISC
> architecture will lead to usage of more GPRs compared to x86, but I cannot
> really see that when looking into code generated by compilers and registers are
> faster compared to pushing things to the stack even on the x86 so a optimizing
> compiler want to keep things i registers if possible.
>
> So why isn't more
> register used in code generated by compilers. I looked at fairly large code-base
> and got this register usage
>
> ARM.
> Number of instructions that refers to any
> of the r0-r12 registers: ~170k
> r10-r12 is not used
> r4-r7 are all used 5-6k
> times
> r8,r9 ~10k times
> r3 16k
> r2 23k
> r1 38k
> r0 69k
>
> So it seems that
> there is "enough" register in every single case in this program.
>
> I did the
> same thing on PPC and MIPS using mostly the same source code just to see what
> the compiler would do when there is more registers available. This source do
> include a small embedded OS-kernel and drivers so it is not a true
> apple-to-apple as the PPC card has more devices, hence will be
> bigger.
>
> PPC
> Number of instructions that refer to any register: ~300k
> Every
> single register is actually used.
> r2,r14-r18,r21-r23 are all used 1k-2k
> times
> r8,r10,r12-r13,r19-r20,r24-r26 are all used 3k-6k times
> r6-r7,r9,r27-r29
> are all used ~10k times
> r4-r5,r30-r31 are all used 20k-30k times
> r1 65k
> r0
> 81k
> r3 85k
>
> MIPS is similar, 4 of the temporary registers are used very
> sparsely while t0 and a0 are the most frequently used register (not too
> surprising).
These counts only tell part of the story because code isn't uniformly distributed during execution. Often a large part of the runtime is dominated by a small part of code. A lot of the code may consist of many branches and function calls that are difficult to allocate registers across, but some of the more performance critical sections may contain tight loops that can be more aggressively optimized. The ABIs can also inhibit register allocation when a lot of function calls are going on, especially to library functions. Although this is another strength for more registers: less need to pass part of a function's parameters on the stack.
That assembly coders can often make use of a lot of registers isn't just because they're finding more use than a compiler would (or are wasting registers) but because they've chosen to target critical functions.
> Number of registers is something that people tend to bring up
> quite a lot and suggest more is always better. IA32 is often frowned upon
> because it has so few GPRs.
>
> So to spin the question a bit: what are the
> downsides of a large number of GPRs? It has to be fairly big trade-offs to be
> made somewhere as very few architectures seem to move beyond 32 GPRs and AMD did
> for some reason settle at 16 GPRs when they designed x86_64. Not a perfect
> comparison, but the performance difference between IA32 and x86_64 is very small
> so IA32 cannot be held back too much by its lack of GPRs.
>
> One point of
> reference to compare IA32 vs x86_64 is . Looking at the single core results for
> C and Java show that some things are faster and some things are slower on IA32,
> but the results are with very few exceptions VERY similar.
>
> Sorry for a long
> post, interesting topic i.m.h.o :)
On the other hand, I've encountered programs that see a 15-20% performance delta from x86-32 to x86-64, for instance the emulator cores in bsnes. AFAIK this code doesn't use a lot of pointer heavy data structures so it's less penalized by the increase in pointer size. However it does heavily use software context switches for co-routines.
That's just one example, although it should be pretty representative of most emulators in general and emulators are often performance critical. I'd give it at least as much weight as the stuff they throw on the language shootout.
If the extra registers in x86-64 wasn't worth anything I'm sure AMD wouldn't have done it (and push come to shove, Intel may not have gone along with it). I'm sure they've researched this, just like I'm sure ARM has done its research.
Of course there are real disadvantages, encoding bits leave out other things you can do with the instructions and the registers have a real hardware cost. For a number of OoO implementations that cost will be in the RAT, not in the register file, since the physical register file won't necessarily be increased in size to accommodate more architectural registers (high end x86 implementations have used 128 physical registers for instance, even before x86-64)
> Its true one can make use of a large number of GPRs in
> hand-written assembler, I've done a lot of assembler programming on 68k and
> while the 8 addresser register was often enough, having just 8 data register was
> often a limitation. I've also done some assembler optimizations for ARM and my
> handwritten functions definitely uses more GPRs compared to the code generated
> by GCC.
>
> It has been suggested that the load/store nature of a RISC
> architecture will lead to usage of more GPRs compared to x86, but I cannot
> really see that when looking into code generated by compilers and registers are
> faster compared to pushing things to the stack even on the x86 so a optimizing
> compiler want to keep things i registers if possible.
>
> So why isn't more
> register used in code generated by compilers. I looked at fairly large code-base
> and got this register usage
>
> ARM.
> Number of instructions that refers to any
> of the r0-r12 registers: ~170k
> r10-r12 is not used
> r4-r7 are all used 5-6k
> times
> r8,r9 ~10k times
> r3 16k
> r2 23k
> r1 38k
> r0 69k
>
> So it seems that
> there is "enough" register in every single case in this program.
>
> I did the
> same thing on PPC and MIPS using mostly the same source code just to see what
> the compiler would do when there is more registers available. This source do
> include a small embedded OS-kernel and drivers so it is not a true
> apple-to-apple as the PPC card has more devices, hence will be
> bigger.
>
> PPC
> Number of instructions that refer to any register: ~300k
> Every
> single register is actually used.
> r2,r14-r18,r21-r23 are all used 1k-2k
> times
> r8,r10,r12-r13,r19-r20,r24-r26 are all used 3k-6k times
> r6-r7,r9,r27-r29
> are all used ~10k times
> r4-r5,r30-r31 are all used 20k-30k times
> r1 65k
> r0
> 81k
> r3 85k
>
> MIPS is similar, 4 of the temporary registers are used very
> sparsely while t0 and a0 are the most frequently used register (not too
> surprising).
These counts only tell part of the story because code isn't uniformly distributed during execution. Often a large part of the runtime is dominated by a small part of code. A lot of the code may consist of many branches and function calls that are difficult to allocate registers across, but some of the more performance critical sections may contain tight loops that can be more aggressively optimized. The ABIs can also inhibit register allocation when a lot of function calls are going on, especially to library functions. Although this is another strength for more registers: less need to pass part of a function's parameters on the stack.
That assembly coders can often make use of a lot of registers isn't just because they're finding more use than a compiler would (or are wasting registers) but because they've chosen to target critical functions.
> Number of registers is something that people tend to bring up
> quite a lot and suggest more is always better. IA32 is often frowned upon
> because it has so few GPRs.
>
> So to spin the question a bit: what are the
> downsides of a large number of GPRs? It has to be fairly big trade-offs to be
> made somewhere as very few architectures seem to move beyond 32 GPRs and AMD did
> for some reason settle at 16 GPRs when they designed x86_64. Not a perfect
> comparison, but the performance difference between IA32 and x86_64 is very small
> so IA32 cannot be held back too much by its lack of GPRs.
>
> One point of
> reference to compare IA32 vs x86_64 is . Looking at the single core results for
> C and Java show that some things are faster and some things are slower on IA32,
> but the results are with very few exceptions VERY similar.
>
> Sorry for a long
> post, interesting topic i.m.h.o :)
On the other hand, I've encountered programs that see a 15-20% performance delta from x86-32 to x86-64, for instance the emulator cores in bsnes. AFAIK this code doesn't use a lot of pointer heavy data structures so it's less penalized by the increase in pointer size. However it does heavily use software context switches for co-routines.
That's just one example, although it should be pretty representative of most emulators in general and emulators are often performance critical. I'd give it at least as much weight as the stuff they throw on the language shootout.
If the extra registers in x86-64 wasn't worth anything I'm sure AMD wouldn't have done it (and push come to shove, Intel may not have gone along with it). I'm sure they've researched this, just like I'm sure ARM has done its research.
Of course there are real disadvantages, encoding bits leave out other things you can do with the instructions and the registers have a real hardware cost. For a number of OoO implementations that cost will be in the RAT, not in the register file, since the physical register file won't necessarily be increased in size to accommodate more architectural registers (high end x86 implementations have used 128 physical registers for instance, even before x86-64)
Topic | Posted By | Date |
---|---|---|
New Article: ARM Goes 64-bit | David Kanter | 2012/08/13 11:04 PM |
New Article: ARM Goes 64-bit | none | 2012/08/13 11:44 PM |
New Article: ARM Goes 64-bit | David Kanter | 2012/08/14 12:04 AM |
MIPS MT-ASE | Paul A. Clayton | 2012/08/14 08:01 AM |
MONITOR/MWAIT | EduardoS | 2012/08/14 09:08 AM |
MWAIT not specifically MT | Paul A. Clayton | 2012/08/14 09:36 AM |
MWAIT not specifically MT | EduardoS | 2012/08/15 02:16 PM |
MONITOR/MWAIT | anonymou5 | 2012/08/14 10:07 AM |
MONITOR/MWAIT | EduardoS | 2012/08/15 02:20 PM |
MIPS MT-ASE | rwessel | 2012/08/14 09:14 AM |
New Article: ARM Goes 64-bit | SHK | 2012/08/14 01:01 AM |
New Article: ARM Goes 64-bit | anon | 2012/08/14 01:37 AM |
New Article: ARM Goes 64-bit | Richard Cownie | 2012/08/14 02:57 AM |
New Article: ARM Goes 64-bit | anon | 2012/08/14 03:29 AM |
New Article: ARM Goes 64-bit | none | 2012/08/14 03:44 AM |
New Article: ARM Goes 64-bit | anon | 2012/08/14 04:28 AM |
New Article: ARM Goes 64-bit | anon | 2012/08/14 04:32 AM |
New Article: ARM Goes 64-bit | EduardoS | 2012/08/14 05:06 AM |
New Article: ARM Goes 64-bit | none | 2012/08/14 04:40 AM |
AArch64 select better than cmov | Paul A. Clayton | 2012/08/14 05:08 AM |
New Article: ARM Goes 64-bit | anon | 2012/08/14 05:12 AM |
New Article: ARM Goes 64-bit | none | 2012/08/14 05:25 AM |
Predicated ld/store are useful | Paul A. Clayton | 2012/08/14 05:48 AM |
Predicated ld/store are useful | none | 2012/08/14 05:56 AM |
Predicated ld/store are useful | anon | 2012/08/14 06:07 AM |
Predicated stores might not be that bad | Paul A. Clayton | 2012/08/14 06:27 AM |
Predicated stores might not be that bad | David Kanter | 2012/08/15 12:14 AM |
Predicated stores might not be that bad | Michael S | 2012/08/15 10:41 AM |
Predicated stores might not be that bad | R Byron | 2012/08/17 03:09 AM |
New Article: ARM Goes 64-bit | anon | 2012/08/14 05:54 AM |
New Article: ARM Goes 64-bit | none | 2012/08/14 06:04 AM |
New Article: ARM Goes 64-bit | anon | 2012/08/14 06:43 AM |
New Article: ARM Goes 64-bit | EduardoS | 2012/08/14 05:07 AM |
New Article: ARM Goes 64-bit | anon | 2012/08/14 05:20 AM |
New Article: ARM Goes 64-bit | none | 2012/08/14 05:29 AM |
New Article: ARM Goes 64-bit | anon | 2012/08/14 06:00 AM |
New Article: ARM Goes 64-bit | Michael S | 2012/08/14 02:43 PM |
New Article: ARM Goes 64-bit | Richard Cownie | 2012/08/14 05:53 AM |
OT: Conrad's "Youth" | Richard Cownie | 2012/08/14 06:20 AM |
New Article: ARM Goes 64-bit | EduardoS | 2012/08/14 05:04 AM |
New Article: ARM Goes 64-bit | mpx | 2012/08/14 07:59 AM |
New Article: ARM Goes 64-bit | Antti-Ville Tuunainen | 2012/08/14 08:16 AM |
New Article: ARM Goes 64-bit | anonymou5 | 2012/08/14 10:03 AM |
New Article: ARM Goes 64-bit | name99 | 2012/11/17 02:31 PM |
Microarchitecting a counter register | Paul A. Clayton | 2012/11/17 06:37 PM |
New Article: ARM Goes 64-bit | bakaneko | 2012/08/14 03:21 AM |
New Article: ARM Goes 64-bit | name99 | 2012/11/17 02:40 PM |
New Article: ARM Goes 64-bit | EduardoS | 2012/11/17 03:52 PM |
New Article: ARM Goes 64-bit | Doug S | 2012/11/17 04:48 PM |
New Article: ARM Goes 64-bit | bakaneko | 2012/11/18 04:40 PM |
New Article: ARM Goes 64-bit | Wilco | 2012/11/19 06:59 AM |
New Article: ARM Goes 64-bit | EduardoS | 2012/11/19 07:23 AM |
New Article: ARM Goes 64-bit | Wilco | 2012/11/19 08:31 AM |
Downloading µarch-specific binaries? | Paul A. Clayton | 2012/11/19 10:21 AM |
New Article: ARM Goes 64-bit | EduardoS | 2012/11/19 10:41 AM |
New Article: ARM Goes 64-bit | Wilco | 2012/11/21 06:44 AM |
JIT vs. static compilation (Was: New Article: ARM Goes 64-bit) | VMguy | 2012/11/22 02:21 AM |
JIT vs. static compilation (Was: New Article: ARM Goes 64-bit) | David Kanter | 2012/11/22 11:12 AM |
JIT vs. static compilation (Was: New Article: ARM Goes 64-bit) | Gabriele Svelto | 2012/11/23 02:50 AM |
New Article: ARM Goes 64-bit | EduardoS | 2012/11/23 09:09 AM |
New Article: ARM Goes 64-bit | EBFE | 2012/11/26 12:24 AM |
New Article: ARM Goes 64-bit | Gabriele Svelto | 2012/11/26 02:33 AM |
New Article: ARM Goes 64-bit | EBFE | 2012/11/27 10:17 PM |
New Article: ARM Goes 64-bit | Gabriele Svelto | 2012/11/28 01:32 AM |
New Article: ARM Goes 64-bit | EduardoS | 2012/11/26 11:16 AM |
New Article: ARM Goes 64-bit | EBFE | 2012/11/27 11:33 PM |
New Article: ARM Goes 64-bit | EduardoS | 2012/11/28 04:53 AM |
New Article: ARM Goes 64-bit | Michael S | 2012/11/28 05:15 AM |
New Article: ARM Goes 64-bit | EduardoS | 2012/11/28 06:33 AM |
New Article: ARM Goes 64-bit | Michael S | 2012/11/28 08:16 AM |
New Article: ARM Goes 64-bit | EduardoS | 2012/11/28 08:53 AM |
New Article: ARM Goes 64-bit | Eugene Nalimov | 2012/11/28 04:58 PM |
Amazing! | EduardoS | 2012/11/28 06:25 PM |
Amazing! (non-italic response) | EduardoS | 2012/11/28 06:25 PM |
Amazing! | EBFE | 2012/11/28 07:20 PM |
Undefined behaviour doubles down | EduardoS | 2012/11/28 08:10 PM |
New Article: ARM Goes 64-bit | EBFE | 2012/11/28 06:54 PM |
New Article: ARM Goes 64-bit | EduardoS | 2012/11/28 08:21 PM |
Have you heard of Transmeta? | David Kanter | 2012/11/19 02:47 PM |
New Article: ARM Goes 64-bit | bakaneko | 2012/11/19 08:08 AM |
New Article: ARM Goes 64-bit | David Kanter | 2012/11/19 02:40 PM |
Semantic Dictionary Encoding | Ray | 2012/11/19 09:37 PM |
New Article: ARM Goes 64-bit | Rohit | 2012/11/20 03:48 PM |
New Article: ARM Goes 64-bit | David Kanter | 2012/11/20 10:07 PM |
New Article: ARM Goes 64-bit | Wilco | 2012/11/21 05:41 AM |
New Article: ARM Goes 64-bit | David Kanter | 2012/11/21 09:12 AM |
A JIT example | Mark Roulo | 2012/11/21 09:30 AM |
A JIT example | Wilco | 2012/11/21 06:04 PM |
A JIT example | rwessel | 2012/11/21 08:05 PM |
A JIT example | Gabriele Svelto | 2012/11/23 02:53 AM |
A JIT example | EduardoS | 2012/11/23 09:13 AM |
A JIT example | Wilco | 2012/11/23 12:41 PM |
A JIT example | EduardoS | 2012/11/23 01:06 PM |
A JIT example | Gabriele Svelto | 2012/11/23 03:09 PM |
A JIT example | Symmetry | 2012/11/26 04:58 AM |
New Article: ARM Goes 64-bit | Ray | 2012/11/19 09:27 PM |
New Article: ARM Goes 64-bit | David Kanter | 2012/08/14 08:11 AM |
v7-M is Thumb-only | Paul A. Clayton | 2012/08/14 05:58 AM |
Minor suggested correction | Paul A. Clayton | 2012/08/14 07:33 AM |
Minor suggested correction | anon | 2012/08/14 07:57 AM |
New Article: ARM Goes 64-bit | Exophase | 2012/08/14 07:33 AM |
New Article: ARM Goes 64-bit | David Kanter | 2012/08/14 08:16 AM |
New Article: ARM Goes 64-bit | jigal | 2012/08/15 12:49 PM |
Correction re ARM and BBC Micro | Paul | 2012/08/14 07:59 PM |
Correction re ARM and BBC Micro | Per Hesselgren | 2012/08/15 02:27 AM |
Memory BW so low | Per Hesselgren | 2012/08/15 02:14 AM |
Memory BW so low | none | 2012/08/15 10:16 AM |
New Article: ARM Goes 64-bit | dado | 2012/08/15 09:25 AM |
Number of GPRs | Kenneth Jonsson | 2012/08/16 01:35 PM |
Number of GPRs | Exophase | 2012/08/16 01:52 PM |
Number of GPRs | Kenneth Jonsson | 2012/08/17 01:41 AM |
Ooops, missing link... | Kenneth Jonsson | 2012/08/17 01:44 AM |
64-bit pointers eat some performance | Paul A. Clayton | 2012/08/17 05:19 AM |
64-bit pointers eat some performance | bakaneko | 2012/08/17 07:37 AM |
Brute force seems to work | Paul A. Clayton | 2012/08/17 09:08 AM |
Brute force seems to work | bakaneko | 2012/08/17 10:15 AM |
64-bit pointers eat some performance | Richard Cownie | 2012/08/17 07:46 AM |
Pointer compression is atypical | Paul A. Clayton | 2012/08/17 09:43 AM |
Pointer compression is atypical | Richard Cownie | 2012/08/17 11:57 AM |
Pointer compression is atypical | Howard Chu | 2012/08/22 09:17 PM |
Pointer compression is atypical | Richard Cownie | 2012/08/23 03:48 AM |
Pointer compression is atypical | Howard Chu | 2012/08/23 05:51 AM |
Pointer compression is atypical | Wilco | 2012/08/17 01:41 PM |
Pointer compression is atypical | Richard Cownie | 2012/08/17 03:13 PM |
Pointer compression is atypical | Ricardo B | 2012/08/19 09:44 AM |
Pointer compression is atypical | Howard Chu | 2012/08/22 09:08 PM |
Unified libraries? | Paul A. Clayton | 2012/08/23 06:49 AM |
Pointer compression is atypical | Richard Cownie | 2012/08/23 07:44 AM |
Pointer compression is atypical | Howard Chu | 2012/08/23 04:17 PM |
Pointer compression is atypical | anon | 2012/08/23 07:15 PM |
Pointer compression is atypical | Howard Chu | 2012/08/23 08:33 PM |
64-bit pointers eat some performance | Foo_ | 2012/08/18 11:09 AM |
64-bit pointers eat some performance | Richard Cownie | 2012/08/18 04:25 PM |
64-bit pointers eat some performance | Richard Cownie | 2012/08/18 04:32 PM |
Page-related benefit of small pointers | Paul A. Clayton | 2012/08/23 07:36 AM |
Number of GPRs | Wilco | 2012/08/17 05:31 AM |
Number of GPRs | Kenneth Jonsson | 2012/08/17 10:54 AM |
Number of GPRs | Exophase | 2012/08/17 11:44 AM |
Number of GPRs | Kenneth Jonsson | 2012/08/17 12:22 PM |
Number of GPRs | Wilco | 2012/08/17 01:53 PM |
What about dynamic utilization? | Exophase | 2012/08/17 08:30 AM |
Compiler vs. assembly aliasing knowledge? | Paul A. Clayton | 2012/08/17 09:20 AM |
Compiler vs. assembly aliasing knowledge? | Exophase | 2012/08/17 10:09 AM |
Compiler vs. assembly aliasing knowledge? | anon | 2012/08/18 01:23 AM |
Compiler vs. assembly aliasing knowledge? | Ricardo B | 2012/08/19 10:02 AM |
Compiler vs. assembly aliasing knowledge? | anon | 2012/08/19 05:07 PM |
Compiler vs. assembly aliasing knowledge? | Ricardo B | 2012/08/19 06:26 PM |
Compiler vs. assembly aliasing knowledge? | anon | 2012/08/19 09:03 PM |
Compiler vs. assembly aliasing knowledge? | anon | 2012/08/20 12:59 AM |
Number of GPRs | David Kanter | 2012/08/17 11:46 AM |
RAT issues as part of reason 1 | Paul A. Clayton | 2012/08/17 01:18 PM |
Number of GPRs | name99 | 2012/11/17 05:37 PM |
Large ARFs increase renaming cost | Paul A. Clayton | 2012/11/17 08:23 PM |
Number of GPRs | David Kanter | 2012/08/16 02:31 PM |
Number of GPRs | Richard Cownie | 2012/08/16 04:17 PM |
32 GPRs ~2-3% | Paul A. Clayton | 2012/08/16 05:27 PM |
Oops, Message-ID: aaed6e38-c7bd-467e-ba41-f40cf1020e5e@googlegroups.com (NT) | Paul A. Clayton | 2012/08/16 05:29 PM |
32 GPRs ~2-3% | Exophase | 2012/08/16 09:06 PM |
R31 as SP/zero is kind of neat (NT) | Paul A. Clayton | 2012/08/17 05:23 AM |
32 GPRs ~2-3% | rwessel | 2012/08/17 07:24 AM |
32 GPRs ~2-3% | Exophase | 2012/08/17 08:16 AM |
32 GPRs ~2-3% | Max | 2012/08/17 03:19 PM |
32 GPRs ~2-3% | name99 | 2012/11/17 06:43 PM |
Number of GPRs | mpx | 2012/08/17 12:11 AM |
Latency and power | Paul A. Clayton | 2012/08/17 05:54 AM |
Number of GPRs | bakaneko | 2012/08/17 02:09 AM |
New Article: ARM Goes 64-bit | Steve | 2012/08/17 01:12 PM |
New Article: ARM Goes 64-bit | David Kanter | 2012/08/19 11:42 AM |
New Article: ARM Goes 64-bit | Doug S | 2012/08/19 01:02 PM |
New Article: ARM Goes 64-bit | Anon | 2012/08/19 06:16 PM |
New Article: ARM Goes 64-bit | Steve | 2012/08/30 06:51 AM |
Scalar vs Vector registers | Robert David Graham | 2012/08/19 04:19 PM |
Scalar vs Vector registers | David Kanter | 2012/08/19 04:29 PM |
New Article: ARM Goes 64-bit | Baserock ARM servers | 2012/08/21 03:13 PM |
Baserock ARM servers | Sysanon | 2012/08/21 03:14 PM |
A-15 virtualization and LPAE? | Paul A. Clayton | 2012/08/21 05:13 PM |
A-15 virtualization and LPAE? | Anon | 2012/08/21 06:13 PM |
Half-depth advantages? | Paul A. Clayton | 2012/08/21 07:42 PM |
Half-depth advantages? | Anon | 2012/08/22 02:33 PM |
Thanks for the information (NT) | Paul A. Clayton | 2012/08/22 03:04 PM |
A-15 virtualization and LPAE? | C. Ladisch | 2012/08/23 10:12 AM |
A-15 virtualization and LPAE? | Paul | 2012/08/23 02:17 PM |
Excessive pessimism | Paul A. Clayton | 2012/08/23 03:08 PM |
Excessive pessimism | David Kanter | 2012/08/23 04:05 PM |
New Article: ARM Goes 64-bit | Michael S | 2012/08/22 06:12 AM |
BTW, Baserock==product, Codethink==company (NT) | Paul A. Clayton | 2012/08/22 07:56 AM |
New Article: ARM Goes 64-bit | Reinoud Zandijk | 2012/08/21 10:27 PM |