Welcome, Guest. Please login or register.

Author Topic: GCC asm() warning suppression options?  (Read 9520 times)

Description:

0 Members and 1 Guest are viewing this topic.

Offline KarlosTopic starter

  • Sockologist
  • Global Moderator
  • Hero Member
  • *****
  • Join Date: Nov 2002
  • Posts: 16867
  • Country: gb
  • Thanked: 4 times
    • Show only replies by Karlos
GCC asm() warning suppression options?
« on: June 27, 2009, 10:58:40 PM »
Hi,

I've pulled out my dusty coding hat and started reviewing years old code I was working on. I have a set of functions that perform bitwise rotate operations using various combinations of ROR/ROL/SWAP:

Code: [Select]

namespace Machine {

  // ...

  template<const uint32 N> inline uint32 rotRight32(uint32 val)
  {
    // N is shift size
    if (!(N&31)) {
      return val;
    }
    if (N<9) {
      asm(&quot;ror.l %1, %0&quot; : &quot;=d&quot;(val) : &quot;I&quot;(N), &quot;0&quot;(val) : &quot;cc&quot;);
    }
    else if (N==16) {
      asm(&quot;swap %0&quot; : &quot;=d&quot;(val) : &quot;0&quot;(val) : &quot;cc&quot;);
    }
    else if (N>23) {
      asm(&quot;rol.l %1, %0&quot; : &quot;=d&quot;(val) : &quot;I&quot;(32-N), &quot;0&quot;(val) : &quot;cc&quot;);
    }
    else {
      asm(&quot;ror.l %1, %0&quot; : &quot;=d&quot;(val) : &quot;d&quot;(N), &quot;0&quot;(val) : &quot;cc&quot;);
    }
    return val;
  }

  // ...

}



Now, without getting too much into it, the above template function is designed to emit optimal rotate code for compile-time known shift values. Despite the seemingly large chain of if/else, the fact the code is inline and N is constant means the basic assembler is emitted fine, for all values of N from 0-32. It goes without saying that the behaviour for N>32 is not well defined (actually it is the last branch of the code but that might not be the expected behaviour for all N), but as N is a compile time constant, that doesn't matter. If you need a variable rotate, there is a different non-template function.

Unfortunately, you do get a lot of warning diagnostics of the form "asm operand 0 probably doesn't match constraints" when compiling with gcc.

Does anybody know what option there is to suppress this particular warning or just warnings emitted from the use of asm() in general?
int p; // A
 

Offline Trev

  • Zero
  • Hero Member
  • *****
  • Join Date: May 2003
  • Posts: 1550
  • Country: 00
    • Show only replies by Trev
Re: GCC asm() warning suppression options?
« Reply #1 on: June 28, 2009, 12:13:56 AM »
Is the warning thrown for all values of N or just values outside the range (0..31) of the I constraint? Can you use N%32? EDIT: A value outside 0..31 might throw "error: impossible constraint in `asm'" in addition to the warning, depending on your version of GCC.

I don't know if that particular warning can be suppressed. Does it show up when optimizations are disabled?
« Last Edit: June 28, 2009, 12:16:08 AM by Trev »
 

Offline KarlosTopic starter

  • Sockologist
  • Global Moderator
  • Hero Member
  • *****
  • Join Date: Nov 2002
  • Posts: 16867
  • Country: gb
  • Thanked: 4 times
    • Show only replies by Karlos
Re: GCC asm() warning suppression options?
« Reply #2 on: June 28, 2009, 12:22:50 AM »
Quote from: Trev;513629
Is the warning thrown for all values of N or just values outside the range (0..31) of the I constraint? Can you use N%32? EDIT: A value outside 0..31 might throw "error: impossible constraint in `asm'" in addition to the warning, depending on your version of GCC.

I don't know if that particular warning can be suppressed. Does it show up when optimizations are disabled?


All legal values of N produce the warning, impossible values (>32) produce an error from the assembler stage. I have tried limiting N in the code by changing all instances to (N&31) (you can't do N &= 31 first since a constant literal isn't a legal lvalue, of course).

Turning off optimisations would somewhat defeat the purpose of this code. Dead code elimination at the very least is required to ensure the inlining only emits the one branch of the code.
int p; // A
 

Offline Trev

  • Zero
  • Hero Member
  • *****
  • Join Date: May 2003
  • Posts: 1550
  • Country: 00
    • Show only replies by Trev
Re: GCC asm() warning suppression options?
« Reply #3 on: June 28, 2009, 12:31:06 AM »
Quote from: Karlos;513631
Turning off optimisations would somewhat defeat the purpose of this code. Dead code elimination at the very least is required to ensure the inlining only emits the one branch of the code.


I was just thinking GCC might have a bug in the parser when optimizations are enabled. It's been noted on x86 and Alpha. What does the preproccesed output look like for each possible branch?
 

Offline KarlosTopic starter

  • Sockologist
  • Global Moderator
  • Hero Member
  • *****
  • Join Date: Nov 2002
  • Posts: 16867
  • Country: gb
  • Thanked: 4 times
    • Show only replies by Karlos
Re: GCC asm() warning suppression options?
« Reply #4 on: June 28, 2009, 12:31:51 AM »
Interestingly, at -O0, the template code doesn't compile at all :lol:
int p; // A
 

Offline KarlosTopic starter

  • Sockologist
  • Global Moderator
  • Hero Member
  • *****
  • Join Date: Nov 2002
  • Posts: 16867
  • Country: gb
  • Thanked: 4 times
    • Show only replies by Karlos
Re: GCC asm() warning suppression options?
« Reply #5 on: June 28, 2009, 12:36:25 AM »
Quote from: Trev;513633
I was just thinking GCC might have a bug in the parser when optimizations are enabled. It's been noted on x86 and Alpha. What does the preproccesed output look like for each possible branch?

for the following test code
Code: [Select]
 uint32 x = 0xAABBCCDD, y=0;

  y = Machine::rotLeft32<0>(x);
  std::printf(&quot;%08X -> %08X\n&quot;, (unsigned)x, (unsigned)y);
  y = Machine::rotLeft32<4>(x);
  std::printf(&quot;%08X -> %08X\n&quot;, (unsigned)x, (unsigned)y);
  y = Machine::rotLeft32<8>(x);
  std::printf(&quot;%08X -> %08X\n&quot;, (unsigned)x, (unsigned)y);
  y = Machine::rotLeft32<12>(x);
  std::printf(&quot;%08X -> %08X\n&quot;, (unsigned)x, (unsigned)y);
  y = Machine::rotLeft32<16>(x);
  std::printf(&quot;%08X -> %08X\n&quot;, (unsigned)x, (unsigned)y);
  y = Machine::rotLeft32<20>(x);
  std::printf(&quot;%08X -> %08X\n&quot;, (unsigned)x, (unsigned)y);
  y = Machine::rotLeft32<24>(x);
  std::printf(&quot;%08X -> %08X\n&quot;, (unsigned)x, (unsigned)y);
  y = Machine::rotLeft32<28>(x);
  std::printf(&quot;%08X -> %08X\n&quot;, (unsigned)x, (unsigned)y);
  y = Machine::rotLeft32<32>(x);
  std::printf(&quot;%08X -> %08X\n&quot;, (unsigned)x, (unsigned)y);
  y = Machine::rotRight32<0>(x);
  std::printf(&quot;%08X -> %08X\n&quot;, (unsigned)x, (unsigned)y);
  y = Machine::rotRight32<4>(x);
  std::printf(&quot;%08X -> %08X\n&quot;, (unsigned)x, (unsigned)y);
  y = Machine::rotRight32<8>(x);
  std::printf(&quot;%08X -> %08X\n&quot;, (unsigned)x, (unsigned)y);
  y = Machine::rotRight32<12>(x);
  std::printf(&quot;%08X -> %08X\n&quot;, (unsigned)x, (unsigned)y);
  y = Machine::rotRight32<16>(x);
  std::printf(&quot;%08X -> %08X\n&quot;, (unsigned)x, (unsigned)y);
  y = Machine::rotRight32<20>(x);
  std::printf(&quot;%08X -> %08X\n&quot;, (unsigned)x, (unsigned)y);
  y = Machine::rotRight32<24>(x);
  std::printf(&quot;%08X -> %08X\n&quot;, (unsigned)x, (unsigned)y);
  y = Machine::rotRight32<28>(x);
  std::printf(&quot;%08X -> %08X\n&quot;, (unsigned)x, (unsigned)y);
  y = Machine::rotRight32<32>(x);
  std::printf(&quot;%08X -> %08X\n&quot;, (unsigned)x, (unsigned)y);

I get (at -O1 - the least level it works at)
Code: [Select]
movel #-1430532899,d4
[B] movel d4,sp@- <-   y = Machine::rotLeft32<0>(x);[/b]
movel d4,sp@-
pea LC5
lea _printf,a2
jbsr a2@
addw #12,sp
[B] movel d4,d0 <-   y = Machine::rotLeft32<4>(x);
#APP
rol.l #4, d0
#NO_APP[/B]
movel d0,sp@-
movel d4,sp@-
pea LC5
jbsr a2@
addw #12,sp
[B] movel d4,d0 <-   y = Machine::rotLeft32<8>(x);
#APP
rol.l #8, d0
#NO_APP[/B]
movel d0,sp@-
movel d4,sp@-
pea LC5
jbsr a2@
addw #12,sp
[B] moveq #12,d3 <-   y = Machine::rotLeft32<12>(x);
movel d4,d0
#APP
rol.l d3, d0
#NO_APP[/B]
movel d0,sp@-
movel d4,sp@-
pea LC5
jbsr a2@
addw #12,sp
[B] movel d4,d0 <-   y = Machine::rotLeft32<16>(x);
#APP
swap d0
#NO_APP[/B]
movel d0,sp@-
movel d4,sp@-
pea LC5
jbsr a2@
addw #12,sp
[B] moveq #20,d2 <-   y = Machine::rotLeft32<20>(x);
movel d4,d0
#APP
rol.l d2, d0
#NO_APP[/B]
movel d0,sp@-
movel d4,sp@-
pea LC5
jbsr a2@
addw #12,sp
[B] movel d4,d0 <-   y = Machine::rotLeft32<24>(x);
#APP
ror.l #8, d0
#NO_APP[/B]
movel d0,sp@-
movel d4,sp@-
pea LC5
jbsr a2@
addw #12,sp
[B] movel d4,d0 <-   y = Machine::rotLeft32<28>(x);
#APP
ror.l #4, d0
#NO_APP[/B]
movel d0,sp@-
movel d4,sp@-
pea LC5
jbsr a2@
addqw #8,sp
[B] movel d4,sp@ <-   y = Machine::rotLeft32<32>(x);[/b]
movel d4,sp@-
pea LC5
jbsr a2@
addqw #8,sp
[B] movel d4,sp@ <-   y = Machine::rotRight32<0>(x); [/b]
movel d4,sp@-
pea LC5
jbsr a2@
addw #12,sp
[B] movel d4,d0 <- y = Machine::rotRight32<4>(x);
#APP
ror.l #4, d0
#NO_APP[/B]
movel d0,sp@-
movel d4,sp@-
pea LC5
jbsr a2@
addw #12,sp
[B] movel d4,d0 <- y = Machine::rotRight32<8>(x);
#APP
ror.l #8, d0
#NO_APP[/B]
movel d0,sp@-
movel d4,sp@-
pea LC5
jbsr a2@
addw #12,sp
[B] movel d4,d0 <- y = Machine::rotRight32<12>(x);
#APP
ror.l d3, d0
#NO_APP[/B]
movel d0,sp@-
movel d4,sp@-
pea LC5
jbsr a2@
addw #12,sp
[B] movel d4,d0 <- y = Machine::rotRight32<16>(x);
#APP
swap d0
#NO_APP[/B]
movel d0,sp@-
movel d4,sp@-
pea LC5
jbsr a2@
addw #12,sp
[B] movel d4,d0 <- y = Machine::rotRight32<20>(x);
#APP
ror.l d2, d0
#NO_APP[/B]
movel d0,sp@-
movel d4,sp@-
pea LC5
jbsr a2@
addw #12,sp
[B] movel d4,d0 <- y = Machine::rotRight32<24>(x);
#APP
rol.l #8, d0
#NO_APP[/B]
movel d0,sp@-
movel d4,sp@-
pea LC5
jbsr a2@
addw #12,sp
[B] movel d4,d0 <- y = Machine::rotRight32<28>(x);
#APP
rol.l #4, d0
#NO_APP[/B]
movel d0,sp@-
movel d4,sp@-
pea LC5
jbsr a2@
addqw #8,sp
[B] movel d4,sp@ <- y = Machine::rotRight32<32>(x);[/b]
movel d4,sp@-
pea LC5
jbsr a2@
addw #12,sp
« Last Edit: June 28, 2009, 12:52:15 AM by Karlos »
int p; // A
 

Offline KarlosTopic starter

  • Sockologist
  • Global Moderator
  • Hero Member
  • *****
  • Join Date: Nov 2002
  • Posts: 16867
  • Country: gb
  • Thanked: 4 times
    • Show only replies by Karlos
Re: GCC asm() warning suppression options?
« Reply #6 on: June 28, 2009, 12:50:58 AM »
I should point out it's always bugged me that C never had operators for integer rotate :lol:

It's pretty obvious that gcc is fretting because the value for N is clearly capable of exceeding the limit for the I (immediate) constraint, though the template code is designed to minimize that. If N is outside the range, this is considered a programming error and I'm happy for it to fail compilation.
« Last Edit: June 28, 2009, 12:57:53 AM by Karlos »
int p; // A
 

Offline Trev

  • Zero
  • Hero Member
  • *****
  • Join Date: May 2003
  • Posts: 1550
  • Country: 00
    • Show only replies by Trev
Re: GCC asm() warning suppression options?
« Reply #7 on: June 28, 2009, 12:56:25 AM »
Quote from: Karlos;513622

Code: [Select]

namespace Machine {

  // ...

  template<const uint32 N> inline uint32 rotRight32(uint32 val)
  {
    // N is shift size
    if (!(N&31)) {
      return val;
    }
    if (N<9) {
      asm(&quot;ror.l %1, %0&quot; : &quot;=d&quot;(val) : &quot;I&quot;(N), &quot;0&quot;(val) : &quot;cc&quot;);
    }
    else if (N==16) {
      asm(&quot;swap %0&quot; : &quot;=d&quot;(val) : &quot;0&quot;(val) : &quot;cc&quot;);
    }
    else if (N>23) {
      asm(&quot;rol.l %1, %0&quot; : &quot;=d&quot;(val) : &quot;I&quot;(32-N), &quot;0&quot;(val) : &quot;cc&quot;);
    }
    else {
      [b]asm(&quot;ror.l %1, %0&quot; : &quot;=d&quot;(val) : &quot;d&quot;(N), &quot;0&quot;(val) : &quot;cc&quot;);[/b]
    }
    return val;
  }

  // ...

}



Shouldn't the bold line be the same as the N<9 branch, or is your intent to use a data register if N<9 || N>23? If so, don't you need to move.l the value first?
 

Offline KarlosTopic starter

  • Sockologist
  • Global Moderator
  • Hero Member
  • *****
  • Join Date: Nov 2002
  • Posts: 16867
  • Country: gb
  • Thanked: 4 times
    • Show only replies by Karlos
Re: GCC asm() warning suppression options?
« Reply #8 on: June 28, 2009, 01:00:04 AM »
Quote from: Trev;513640
Shouldn't the bold line be the same as the N<9 branch, or is your intent to use a data register if N<9 || N>23? If so, don't you need to move.l the value first?

Yes, register use is intended for that final operation (which is not for N<9 | N>23 but for the intermediate ranges between 8 and 16 bit either direction) since it's probably faster than a pair of rotates. Moving the value to the register is performed automatically by the compiler thanks to the "d" constraint. See the output asm in my earlier post. The N = 9-15 and N = 17-23 are handled by a ROX.l dX, DY type operation, everything else is done with immediate rotates (or a swap in the N=16 case)
« Last Edit: June 28, 2009, 01:03:59 AM by Karlos »
int p; // A
 

Offline Trev

  • Zero
  • Hero Member
  • *****
  • Join Date: May 2003
  • Posts: 1550
  • Country: 00
    • Show only replies by Trev
Re: GCC asm() warning suppression options?
« Reply #9 on: June 28, 2009, 01:01:57 AM »
Quote from: Karlos;513638
I should point out it's always bugged me that C never had operators for integer rotate :lol:


Yeah, I think it's a common gripe. A lot of compilers implement rotation as intrinsic functions.

Quote
If N is outside the range, this is considered a programming error and I'm happy for it to fail compilation.


Good call.
 

Offline KarlosTopic starter

  • Sockologist
  • Global Moderator
  • Hero Member
  • *****
  • Join Date: Nov 2002
  • Posts: 16867
  • Country: gb
  • Thanked: 4 times
    • Show only replies by Karlos
Re: GCC asm() warning suppression options?
« Reply #10 on: June 28, 2009, 01:10:00 AM »
Quote from: Trev;513642
Yeah, I think it's a common gripe. A lot of compilers implement rotation as intrinsic functions.



Good call.

Anyway, to cut the story short, as a construct it works just fine (save the -O0 case which needs a spot of investigation, not that I ever use -O0, even when debugging):

AABBCCDD -> AABBCCDD
AABBCCDD -> ABBCCDDA
AABBCCDD -> BBCCDDAA
AABBCCDD -> BCCDDAAB
AABBCCDD -> CCDDAABB
AABBCCDD -> CDDAABBC
AABBCCDD -> DDAABBCC
AABBCCDD -> DAABBCCD
AABBCCDD -> AABBCCDD

AABBCCDD -> AABBCCDD
AABBCCDD -> DAABBCCD
AABBCCDD -> DDAABBCC
AABBCCDD -> CDDAABBC
AABBCCDD -> CCDDAABB
AABBCCDD -> BCCDDAAB
AABBCCDD -> BBCCDDAA
AABBCCDD -> ABBCCDDA
AABBCCDD -> AABBCCDD


...but the warnings are a PITA. As the code is in a header and not a translation unit, it isn't as if I can just disable warnings for the one file.
« Last Edit: June 28, 2009, 01:13:25 AM by Karlos »
int p; // A
 

Offline Trev

  • Zero
  • Hero Member
  • *****
  • Join Date: May 2003
  • Posts: 1550
  • Country: 00
    • Show only replies by Trev
Re: GCC asm() warning suppression options?
« Reply #11 on: June 28, 2009, 01:19:42 AM »
Which version of gcc are you using? Native or cross?

You could also specialize your templates a bit to perhaps make things a bit clearer:

Code: [Select]

template <uint32 N> inline uint32 rotRight32(uint32 val)
{
  if (N%32 < 9) {
    asm(&quot;ror.l %1, %0;&quot; : &quot;=d&quot;(val) : &quot;I&quot;(N%32), &quot;0&quot;(val) : &quot;cc&quot;);
  }
  else if (N%32 > 23) {
    asm(&quot;rol.l %1, %0;&quot; : &quot;=d&quot;(val) : &quot;I&quot;(32-(N%32)), &quot;0&quot;(val) : &quot;cc&quot;);
  }
  else {
    asm(&quot;ror.l %1, %0;&quot; : &quot;=d&quot;(val) : &quot;d&quot;(N%32), &quot;0&quot;(val) : &quot;cc&quot;);
  }

  return val;
}

template <> inline uint32 rotRight32<0>(uint32 val)
{
  return val;
}

template <> inline uint32 rotRight32<16>(uint32 val)
{
  asm(&quot;swap %0;&quot; : &quot;=d&quot;(val) : &quot;0&quot;(val) : &quot;cc&quot;);
  return val;
}


EDIT: For extra credit, let's do , too, i.e. rotRight32(-1) rotates left 1 bit. You could then generalize it as rotate(), where the sign of the operand determines the direction. Anyway....
« Last Edit: June 28, 2009, 01:31:47 AM by Trev »
 

Offline Trev

  • Zero
  • Hero Member
  • *****
  • Join Date: May 2003
  • Posts: 1550
  • Country: 00
    • Show only replies by Trev
Re: GCC asm() warning suppression options?
« Reply #12 on: June 28, 2009, 01:24:12 AM »
Quote from: Karlos;513641
(which is not for N<9 | N>23 but for the intermediate ranges between 8 and 16 bit either direction)


Yeah, I'm not doing so well with the ranges today.
 

Offline KarlosTopic starter

  • Sockologist
  • Global Moderator
  • Hero Member
  • *****
  • Join Date: Nov 2002
  • Posts: 16867
  • Country: gb
  • Thanked: 4 times
    • Show only replies by Karlos
Re: GCC asm() warning suppression options?
« Reply #13 on: June 28, 2009, 01:24:45 AM »
Quote from: Trev;513644
Which version of gcc are you using? Native or cross?


Native and pretty ancient (2.95.x)

Quote
You could also specialize your templates a bit to perhaps make things a bit clearer


Yeah, that certainly looks better but I wasn't about to push that old version to the point of template specialisations. It just about does template functions as it is ;)

BTW, I did actually try with a modulus applied to N as per your example above but it didn't really make a difference to the warning diagnostic.
int p; // A
 

Offline KarlosTopic starter

  • Sockologist
  • Global Moderator
  • Hero Member
  • *****
  • Join Date: Nov 2002
  • Posts: 16867
  • Country: gb
  • Thanked: 4 times
    • Show only replies by Karlos
Re: GCC asm() warning suppression options?
« Reply #14 on: June 28, 2009, 01:26:55 AM »
Quote from: Trev;513645
Yeah, I'm not doing so well with the ranges today.

I'm just happy to have some miggy coding time at all. Perverting C++ (in ANSI mode) with inline assembler always felt good :lol: If you think this is bad, you should see the divide by zero exception trick ;)

All I need now is to find an -fno-worry-about-asm-immediate-sizes option...
« Last Edit: June 28, 2009, 01:31:37 AM by Karlos »
int p; // A