inline asm fails with -O2

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
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.
No, that does not help. :(
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.
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>
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
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.
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.
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
Topic archived. No new replies allowed.