-1

I want to set a bit at position p without using btsl instruction with inline asm gcc c code. Using btsl instruction is simple:

int n,p;
scanf("%d%d",&n,&p);
asm("btsl %1, %0"
:"=m"(n)
:"Ir"(p)
:"cc");

I know for setting bit it can be done:

n|=1<<p;

Now, I'm doing so with inline asm:

  asm("movl %1, %%eax;"
      "movl %2, %%ebx;" 
      "shl $1, %%ebx;"
      "orl %%ebx, %%eax;"
      "movl %%eax, %0;"
      
  :"=b"(n)
  :"a"(n), "b"(p)
  :"cc");
  printf("%d\n",n);

It seems to me shl instruction doesn't work. For instance n=20=10100. When I try to set the first bit p=1 the result is 22=10110 instead of 21=10101

Peter Cordes
  • 328,167
  • 45
  • 605
  • 847
  • Are you counting bits from 0 or 1? Normally the p'th bit would be set using `x |= 1<

    – Paul Hankin Aug 18 '20 at 13:46
  • When I do 20 | 1 the result is 22 instead of 21. However you are right about p-1, p is correct, but it doesn't work anyway – Massimiliano Di Cavio Aug 18 '20 at 13:52
  • But 22 is correct, if you do the equivalent of `20 | (1 << 1)`. So, *how does it not work for you?* Please [edit] your question with additional information, this is not a forum. – the busybee Aug 18 '20 at 14:02
  • 5
    Also `shl $1, %%ebx` doesn't do what you think it does. It shifts `ebx` by `1` not `1` by `ebx`. PS: do not use `mov` in inline asm, use only the appropriate constraint instead. You already specified `b` for `p` as input so the compiler already placed it into `ebx`. So `movl %2, %%ebx` just expands to a pointless `movl %ebx, %ebx`. Same for `n`. You forgot to specify `%eax` as output/clobber too. – Jester Aug 18 '20 at 14:43
  • 1
    Note that you specify `eax` to be an input register but then proceed to overwrite it. This is not permitted. – fuz Aug 18 '20 at 14:51
  • eax is overwritten in this link https://www.codeproject.com/Articles/15971/Using-Inline-Assembly-in-C-C. Euclid's Algorithm, and also movl instruction. – Massimiliano Di Cavio Aug 18 '20 at 15:40
  • 1
    You can overwrite it if you specify it as output (or a clobber but that's not supported if it's already an input). Your code really should just have `shl` and `or` inside it and use constraints for the inputs and outputs. – Jester Aug 18 '20 at 15:44
  • 1
    Why did you use a redundant `l` operand-size suffix on every instruction except `shl`? Anyway, hardly matters, I don't see any point to doing this with inline asm. Just compile `x|=1<

    – Peter Cordes Aug 18 '20 at 17:34
  • 1
    What's wrong with btsl? If it's broken on your CPU, you should just replace the CPU. – Raymond Chen Aug 19 '20 at 05:25
  • Don't make your question worse by removing details of actual output from your [mcve]. Instead of downvoting, I rolled back your edit that changed the description to just "[doesn't work](https://idownvotedbecau.se/itsnotworking/)". – Peter Cordes Aug 20 '20 at 17:40

1 Answers1

-1

Folowing Michael's example, I've done clear and toggle as well as set:

unsigned long bitset(unsigned long value, uint8_t shift)
{
    unsigned long tmp;

    asm ("mov $0x1, %[tempreg]\n\t"
         "shl %[shift], %[tempreg]\n\t"
         "or %[tempreg], %[val]"
    : [val]"+r"(value),
      [tempreg]"=&r"(tmp)
    : [shift]"cN"(shift));

    return value;
}


unsigned long bitclear(unsigned long value, uint8_t shift)
{
    unsigned long tmp;

    asm ("mov $0x1, %[tempreg]\n\t"
         "shl %[shift], %[tempreg]\n\t"
         "not %[tempreg]\n\t"
         "and %[tempreg], %[val]\n\t"
    : [val]"+r"(value),
      [tempreg]"=&r"(tmp)
    : [shift]"cN"(shift));

    return value;
}
unsigned long toggle(unsigned long value, uint8_t shift)
{
    unsigned long tmp;

    asm ("mov $0x1, %[tempreg]\n\t"
         "shl %[shift], %[tempreg]\n\t"
         "xor %[tempreg], %[val]"
    : [val]"+r"(value),
      [tempreg]"=&r"(tmp)
    : [shift]"cN"(shift));

    return value;
}
  • Why are you using EBX at all? That's just pointless. It's also pointless to start and end with `mov` instructions, just tell the compiler the correct registers where you leave stuff, and ask for it in the right register to start with (i.e. the count in ECX). Also, this is buggy: you write ECX without declaring a clobber on it. (Downvoted for that bug; inline asm is hard enough to get right without dangerous examples of using it wrong. I'd be happy to remove it if you reduce this to just the 3 instructions "necessary", or grudgingly if you just make it safe but still inefficient garbage.) – Peter Cordes Aug 20 '20 at 09:33
  • 2
    If you are really intent on using those 3 instruction (a mov/shl/or) then you can do it this way : https://godbolt.org/z/MvKnsa – Michael Petch Aug 20 '20 at 10:10
  • 1
    bitclear still only needs 3 instructions; you can rotate `0xFFFFFFFE` to put the zero where you want it. – Peter Cordes Aug 21 '20 at 19:19
  • @Peter Cordes, Could you just write this example? I've never seen such as method to clear. – Massimiliano Di Cavio Aug 24 '20 at 11:36