inline asm fails with -O2

Mar 4, 2010 at 2:54pm
the following simple piece of code fails to work
1
2
3
4
5
6
7
8
inline unsigned next_exp2(unsigned x)
{
	unsigned n;
	asm("bsr %0, %1" : "=r" (n) : "r" (x));
// 	std::cerr << "n = " << n << std::endl << std::flush;
	if(x > (1u << n)) n += 1u;
	return(n);
}

but if I uncomment the line with std::bla-bla, or compile it with -g (debug compile) everything mysteriously starts to work properly! I figured out the shit happens in `if' line, but can not find the way around. I am not really experienced with mixing C and asm, but it looks like a bug to me. ???

gcc 4.3.4
Mar 4, 2010 at 3:04pm
I think you need to add 'volatile' to asm statement. This way the compiler won't be allowed to move it, what seems to cause this problem.
Mar 4, 2010 at 3:33pm
No, that does not help. :(
Mar 4, 2010 at 5:18pm
closed account (S6k9GNh0)
http://msdn.microsoft.com/en-us/library/45yd4tzz%28VS.80%29.aspx

http://www.ibiblio.org/gferg/ldp/GCC-Inline-Assembly-HOWTO.html#s3

Never really seen asm(); before. I've always seen _asm and then a block of assembly and what not.
Mar 4, 2010 at 5:29pm
computerquip
That is not the problem. BTW, have you actually read the articles you referenced? <hint> __asm is ms specific, while asm is the standard keyword</hint>
Mar 4, 2010 at 5:35pm
closed account (S6k9GNh0)
One is for GCC and the other mentions that it is MS specific before the article begins. Both provide help and the GCC article mentions use of volatile. I don't know what you're using. I personally glanced at both but I don't feel the need yet to learn to relate place ASM into my C++.
Last edited on Mar 4, 2010 at 5:51pm
Mar 4, 2010 at 5:57pm
Quip, tell me as one writer to another.... can you read? :))
OK, I put here the simple example, so people please tell me what results you get on which compiler
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
#include<iostream>

inline unsigned next_exp2(unsigned x)
{
	unsigned n;
	asm volatile("bsr %0, %1" : "=r" (n) : "r" (x)); // most significant bit
	return((x == (1u << n)) ? n : n);
};
inline unsigned next_exp2_(unsigned x)
{
	unsigned n;
	asm volatile("bsr %0, %1" : "=r" (n) : "r" (x)); // most significant bit
	return((x == (1u << n)) ? n : n+1);
};

int main()
{
	unsigned x = 1025;
	std::cout << "n1 = " << next_exp2(x) << std::endl;
	std::cout << "n2 = " << next_exp2_(x) << std::endl;
	
	return(0);
}

The difference between two function is n+1 returned from the underscored version.
My output is (I repeat, gcc 4.3.4):
1
2
n1 = 10
n2 = 3078596801

while I would expect n2=11.
In particular I am interesed in gcc 4.3 and 4.4 results.
Mar 4, 2010 at 7:05pm
With -O2 I get garbage output with both gcc 3.3.3 and 4.1.2.

FWIW:

g++ --version
g++ (GCC) 4.1.2 20080704 (Red Hat 4.1.2-44)
Copyright (C) 2006 Free Software Foundation, Inc.
This is free software; see the source for copying conditions. There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

g++ foo.cpp -O2
a.out
n1 = 12685300
n2 = 12685301


----------------------------

g++ --version
g++ (GCC) 3.3.3 20040412 (Red Hat Linux 3.3.3-7)
Copyright (C) 2003 Free Software Foundation, Inc.
This is free software; see the source for copying conditions. There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

g++ foo.cpp -O2
a.out
n1 = 134514876
n2 = 33


Without -O2 both output the right answer.
Mar 4, 2010 at 9:42pm
Thank you. I am going to submit a bug at gcc.


------- Comment #1 From Andrew Pinski 2010-03-04 22:08 [reply] -------

The problem you are seeing is Intel vs AT&T asm formats. GNU as defaults to
AT&T format in that it is src, dst. So you have the operands swapped. Note
also you also don't clobber the flags register as bsr sets the Zero flag.
asm volatile("bsr %1, %0" : "=r" (n) : "r" (x) : "flags");
Is the correct code you want. It just happened to work at -O0 because the
register allocator used the same registers for the input and output.
Last edited on Mar 4, 2010 at 10:28pm
Topic archived. No new replies allowed.