Difference between --target=i386 and i686

classic Classic list List threaded Threaded
6 messages Options
Reply | Threaded
Open this post in threaded view
|

Difference between --target=i386 and i686

J.W. Jagersma
When compiling gcc (and binutils) for x86 targets, what is the difference
between specifying --target=i386 vs i486 vs i586 etc? How does it affect
code generation exactly?

As a test I've built toolchains with both i386 and i686, and compiled a
program with both. I'm looking for cmov instructions since a 386 wouldn't
support those.

i386-gcc            : no cmov
i686-gcc            : cmov
i386-gcc -march=i686: cmov
i686-gcc -march=i386: cmov (!)

So it looks like gcc compiled with --target=i686-* is incapable of producing
i386 code, and --target=i386-* is the most versatile option for backwards
compatibility with older cpus. Are there any disadvantages (reduced
optimization, etc) to using an i386-gcc with -march=i686 when compiling for
"newer" systems?
Reply | Threaded
Open this post in threaded view
|

Re: Difference between --target=i386 and i686

Jim Wilson-2
On Wed, Feb 12, 2020 at 9:10 AM J.W. Jagersma <[hidden email]> wrote:
> i686-gcc -march=i386: cmov (!)

Did you check to see where the cmov instruction is coming from?  The
compiler won't generate it with -march=i386, but there may be a
precompiled library like libgcc or libstdc++ that contains the cmov
instruction because they were compiled for i686.  In order to get the
right effect with -march=i386, you would need to build multiple copies
of the libraries, one of them with -march=i386.  We call this
multilibs.  This is normally done with -m32/-m64 so a single compiler
can generate both 32-bit and 64-bit code, but it is not normally done
with i386 and i686.  You would have to change the default
configuration to build multilibs based on -march.

The same thing happens in reverse when you configure for i386 and use
-march=i686, the compiler generated code will be i686, but the
precompiled libraries will be i386 code.

> So it looks like gcc compiled with --target=i686-* is incapable of producing
> i386 code, and --target=i386-* is the most versatile option for backwards
> compatibility with older cpus. Are there any disadvantages (reduced
> optimization, etc) to using an i386-gcc with -march=i686 when compiling for
> "newer" systems?

Besides the performance loss, i386 doesn't have cmpxchg which means
atomic support will be a problem.  Otherwise, it will probably work.

Jim
Reply | Threaded
Open this post in threaded view
|

Re: Difference between --target=i386 and i686

J.W. Jagersma
On 2020-02-19 00:16, Jim Wilson wrote:

> On Wed, Feb 12, 2020 at 9:10 AM J.W. Jagersma <[hidden email]> wrote:
>> i686-gcc -march=i386: cmov (!)
>
> Did you check to see where the cmov instruction is coming from?  The
> compiler won't generate it with -march=i386, but there may be a
> precompiled library like libgcc or libstdc++ that contains the cmov
> instruction because they were compiled for i686.  In order to get the
> right effect with -march=i386, you would need to build multiple copies
> of the libraries, one of them with -march=i386.  We call this
> multilibs.  This is normally done with -m32/-m64 so a single compiler
> can generate both 32-bit and 64-bit code, but it is not normally done
> with i386 and i686.  You would have to change the default
> configuration to build multilibs based on -march.

Ah, you're right. The cmovs only appear in library code. So the target
name only sets the default value for -march? Which is what I initially
expected.
Say I wanted to do build multilibs for x86, where would I start? I've
been looking through the configure/make files but I don't see how it's
done.

>> So it looks like gcc compiled with --target=i686-* is incapable of producing
>> i386 code, and --target=i386-* is the most versatile option for backwards
>> compatibility with older cpus. Are there any disadvantages (reduced
>> optimization, etc) to using an i386-gcc with -march=i686 when compiling for
>> "newer" systems?
>
> Besides the performance loss, i386 doesn't have cmpxchg which means
> atomic support will be a problem.  Otherwise, it will probably work.

I did notice that using i386, my program doesn't link at -O0 due to
undefined references to __atomic_* builtins. Somehow it works at -O1
and above. It seems the only atomic operations I use are compiled to
'lock add/sub' instructions.
Reply | Threaded
Open this post in threaded view
|

Re: Difference between --target=i386 and i686

J.W. Jagersma
On 2020-02-21 18:38, J.W. Jagersma wrote:

> On 2020-02-19 00:16, Jim Wilson wrote:
>> On Wed, Feb 12, 2020 at 9:10 AM J.W. Jagersma <[hidden email]> wrote:
>>> i686-gcc -march=i386: cmov (!)
>>
>> Did you check to see where the cmov instruction is coming from?  The
>> compiler won't generate it with -march=i386, but there may be a
>> precompiled library like libgcc or libstdc++ that contains the cmov
>> instruction because they were compiled for i686.  In order to get the
>> right effect with -march=i386, you would need to build multiple copies
>> of the libraries, one of them with -march=i386.  We call this
>> multilibs.  This is normally done with -m32/-m64 so a single compiler
>> can generate both 32-bit and 64-bit code, but it is not normally done
>> with i386 and i686.  You would have to change the default
>> configuration to build multilibs based on -march.
>
> Say I wanted to do build multilibs for x86, where would I start? I've
> been looking through the configure/make files but I don't see how it's
> done.

Nevermind that, I found it in the documentation here:
https://gcc.gnu.org/onlinedocs/gccint/Target-Fragment.html
Reply | Threaded
Open this post in threaded view
|

Re: Difference between --target=i386 and i686

Jim Wilson-2
In reply to this post by J.W. Jagersma
On Fri, Feb 21, 2020 at 9:38 AM J.W. Jagersma <[hidden email]> wrote:
> > Besides the performance loss, i386 doesn't have cmpxchg which means
> > atomic support will be a problem.  Otherwise, it will probably work.
>
> I did notice that using i386, my program doesn't link at -O0 due to
> undefined references to __atomic_* builtins. Somehow it works at -O1
> and above. It seems the only atomic operations I use are compiled to
> 'lock add/sub' instructions.

Atomics are probably inline expanded with optimization.  There is a
libatomic library you can link with, -latomic, that should implement
all atomics that aren't inline expanded.  But I'm not sure exactly how
this works with a i386 toolchain given that cmpxchg is missing.

Jim
Reply | Threaded
Open this post in threaded view
|

Re: Difference between --target=i386 and i686

J.W. Jagersma
On 2020-02-21 23:08, Jim Wilson wrote:

> On Fri, Feb 21, 2020 at 9:38 AM J.W. Jagersma <[hidden email]> wrote:
>>> Besides the performance loss, i386 doesn't have cmpxchg which means
>>> atomic support will be a problem.  Otherwise, it will probably work.
>>
>> I did notice that using i386, my program doesn't link at -O0 due to
>> undefined references to __atomic_* builtins. Somehow it works at -O1
>> and above. It seems the only atomic operations I use are compiled to
>> 'lock add/sub' instructions.
>
> Atomics are probably inline expanded with optimization.  There is a
> libatomic library you can link with, -latomic, that should implement
> all atomics that aren't inline expanded.  But I'm not sure exactly how
> this works with a i386 toolchain given that cmpxchg is missing.
>
> Jim

It seems libatomic is not available on x86, configure says the target
is unsupported.
I suppose on a single 386 (do 386 SMP systems even exist?) you could
emulate any atomic operation just by disabling interrupts. Except
maybe for memory-mapped devices where you do need a single
instruction. So far I haven't needed that yet, anyway.