ASM appears to be incorrect from llc

Hi,
I’m trying to compile an intermediate representation file to ASM (intel style), and I believe that the resultant ASM is invalid. The IR is:

; ModuleID = ‘test.u’

%vec2 = type { float, float }
@t = global %vec2 zeroinitializer
@x = global i32 0

define i32 @main__i__v() nounwind {
locals:
%0 = load float* getelementptr inbounds (%vec2* @t, i32 0, i32 0)
%1 = fptosi float %0 to i64
%2 = trunc i64 %1 to i32
store i32 %2, i32* @x
ret i32 0
}

Now, I know no memory is allocated for t (ignore that), we’ll just expect the final program to crash

Running this through
llvm-as.exe test.trunk.ll -f -o test.bc
and then
llc -x86-asm-syntax=intel -o test.trunk.S test.bc

yields:

.def _main__i__v;
.scl 2;
.type 32;
.endef
.text
.globl _main__i__v
.align 16, 0x90
_main__i__v: # @main__i__v

BB#0: # %locals

sub ESP, 20
movss XMM0, DWORD PTR [_t]
movss DWORD PTR [ESP + 8], XMM0
fld DWORD PTR [ESP + 8]
fisttp QWORD PTR [ESP]
mov EAX, DWORD PTR [ESP]
mov _x, EAX
xor EAX, EAX
add ESP, 20
ret

.data
.globl _t # @t
.align 8
_t:
.zero 8

.globl _x # @x
.align 4
_x:
.long 0 # 0x0

Now, the bit I think is wrong is
mov _x,EAX

I think it should be
mov [_x], eax

Thoughts?

Cheers

Matthew

What makes you think it's wrong?

-Eli

Hi,
It doesn’t compile with yasm, or nasm (reports invalid combination of opcode and operands), and

mov _x,EAX

is meaningless as _x is just a label (an numeric constant that happens to be an address), so it would have to be dereferenced to get to the memory at that address, otherwise it’s like saying

mov 0x12341234, EAX

Now, my asm skills are not that great, so I’m prepared to be told I’m talking bollocks, but that’s how I have interpreted everything I’ve read today.

Cheers

Matthew

Hmm... okay, that makes sense. gas actually does accept the given
syntax, which is probably why nobody noticed...

-Eli

Hi Matthew,

Hi,
  It doesn't compile with yasm, or nasm

Where did you get the idea that "Intel syntax" means NASM? LLVM actually produces assembly files that can be fed to GAS, or to LLVM's MC framework. (In fact, it's missing a .intel_syntax directive so GAS knows it needs to assemble instructions according to Intel syntax.)

(reports invalid combination of opcode and operands), and

mov _x,EAX

is meaningless as _x is just a label (an numeric constant that happens to be an address), so it would have to be dereferenced to get to the memory at that address, otherwise it's like saying

mov 0x12341234, EAX

That's only true of NASM/YASM.

x86 assembly is sort of like the Chinese language. There's a traditional variant--the one devised by Intel themselves and used in Intel's and Microsoft's assemblers; and a simplified variant--the one devised by the NASM developers based on Intel's variant. (Then there's the AT&T variant, which is really different from either Intel or NASM.) One of the key differences is that in traditional syntax, labels automatically get dereferenced. If you want the offset, you have to use the 'offset' operator. In simplified syntax, on the other hand, labels are not automatically dereferenced, and you don't need the 'offset' operator; you do, however, need to use square brackets to dereference the label.

Hope that helps clear this up.

Chip

Then you had some old assemblers that were REALLY silly:
mov WORD PTR [Buffer + bp], dx

Let's make sure that we all know that we're placing a 16 bit register into a 16 bit location. Thankfully it took care of defaulting the segment register to ds. The miracles of automation. :wink:

-Gordon