Subject: gcc4 asm constraint warnings
To: tech-toolchain@NetBSD.org, <port-m68k@NetBSD.org>
From: Michael L. Hitch <mhitch@lightning.msu.montana.edu>
List: tech-toolchain
Date: 06/30/2006 11:20:57
While attempting a build with gcc4 for the amiga, I ran into warnings
for several asm() statements:
warning: matching constraint does not allow a register
I first ran into these building the X server, and they were coming from
macros using asm() statements for the bit-field insert instruction used
in Xserver/mfb and Xserver/cfb. I later ran into a similar problem with
single_inst_bclr_b() and single_instr_bset_b() macros in the amiga
clock code.
Izumi Tsutsui also ran into the same problem on the hp300 clock code.
He committed a change to arch/m68k/include/asm_single.h, which I did not
think was quite correct (although I'm not all that knowledgeable about
the usage of constraints). He backed out his change, and both of us
are looking for someone who might know more about the solution to this
than we are.
The problem is the use of matching contraints for instructions that
modify memory directly. In the case of m68k/include/asm_single.h,
these are 'or' and 'and' instructions to set and clear bits in a
memory variable, used as atomic instructions for single processor
systems.
One specific example is:
#define single_inst_bset_b(var, bit) \
__asm volatile ("orb %1,%0" \
: "=m" (var) \
: "di" ((u_char)bit), "0" (var))
In this case, the input operand "var" is specified as a matching
operand for the output operand (since the instruction effectively
loads the byte from memory, modifies it, and writes the byte back
to memory). Gcc4 now generates a warning that the matching constraint
doesn't allow a register.
The gcc4 documentation doesn't seem to mention this about matching
constraints, but some of the information I've found about this seems
to indicate that a matching contraint only pertains to operands in
registers, and that prior versions of gcc just did not check this.
I found several different ways other people had addressed this. One
way was to make the same change Izumi Tsutsui did - changing the "0" to
"m":
#define single_inst_bset_b(var, bit) \
__asm volatile ("orb %1,%0" \
: "=m" (var) \
: "di" ((u_char)bit), "m" (var))
I wasn't sure if this is correct; it seems to me that the '"m" (var)'
constraint now refers to the 2nd input operand (which would be %2 in the
instruction template), which is not referenced in the template.
I also saw some people talking about changing this to:
#define single_inst_bset_b(var, bit) \
__asm volatile ("orb %1,%0" \
: "+m" (var) \
: "di" ((u_char)bit))
The "+m" constraint indicates that the operand is both read and written,
which matches the use of the memory operand in this case, and seems like
the best choice to me.
One other alternative would be to just remove the matching constraint,
but since that doesn't address the use of the operand as an input operand,
that doesn't seem like a good choice (assuming that gcc actually
distinguishes between the "=" and "+" modifier for the m68k). At this
point, I would lean toward using the "+m" change as above.
Any experts have any opinions on the correct fix for this?
While testing this on a simple program, I did notice that using
"=m" generated slightly different code than "+m for one particular
example. Both are correct, and generate the same number of bytes of
code, but the "+m" generated one additional instruction.
The source line (from the amiga clock.c code) was:
single_inst_bset_b(draco_ioctl->io_status2, 0x40);
The assembly generated using "=m" was:
#NO_APP
move.l draco_ioctl,%a0
#APP
orb #64,4(%a0)
#NO_APP
And the assembly generated with "+m" was:
#NO_APP
move.l draco_ioctl,%a0
addq.l #4,%a0
#APP
orb #64,(%a0)
--
Michael L. Hitch mhitch@montana.edu
Computer Consultant
Information Technology Center
Montana State University Bozeman, MT USA