switching ARM modes and integrated-as

Does the integrated assembler in the ARM backend support switching
between ARM and Thumb modes in the same file? I'm having trouble with
the following assembly:

  .thumb_func
  @ Enter ARM mode
  adr r3, 1f
  bx r3
  .align 4
  .code 32
1: push {r7}
  mov r7, r12
  svc 0x0
  pop {r7}
  @ Enter thumb mode
  adr r3, 2f+1
  bx r3
  .code 16
2:
  bx lr

As a standalone .s file, GNU-as can compile it but with "clang
-integrated-as", I get errors. If using inline assembly in a C file,
no error is reported (when compiled targeting thumb 2), but the 32-bit
ARM instructions are encoded wrongly. The two 16-bit halves need to
be swapped. A bug, unsupported, or perhaps just user error?

Thanks,
Greg

Does the integrated assembler in the ARM backend support switching
between ARM and Thumb modes in the same file?

Yes.

I'm having trouble with
the following assembly:

.thumb_func
@ Enter ARM mode
adr r3, 1f
bx r3
.align 4

That .align is probably not what you want. ARM .align is a power of two, so you’re aligning at 16 bytes here, not 32-bits.

.code 32
1: push {r7}
mov r7, r12
svc 0x0
pop {r7}
@ Enter thumb mode
adr r3, 2f+1
bx r3
.code 16
2:
bx lr

As a standalone .s file, GNU-as can compile it but with "clang
-integrated-as", I get errors. If using inline assembly in a C file,
no error is reported (when compiled targeting thumb 2), but the 32-bit
ARM instructions are encoded wrongly. The two 16-bit halves need to
be swapped. A bug, unsupported, or perhaps just user error?

I just tried the above code in a .s file and it worked fine for me. Can you show exactly what you’re seeing that looks wrong? Note that Thumb2 wide instructions have the two half-words swapped from what one would expect. Possibly the disassembly isn’t identifying arm vs. thumb code and that’s what’s making things look wrong?

I just tried the above code in a .s file and it worked fine for me.
Can you show exactly what you’re seeing that looks wrong?

Thanks Jim. I can only reproduce the issue when that code is inline
assembly in a bitcode file. Attached is a bitcode file and Makefile
to demonstrate. Calling 'make' will dump two object files 'c.o' and
'asm.o'. The former is created with llc directly, whereas the latter
first generates an assembly file and then assembles it via llvm-mc.
The issue is only present when directly generating the object file.
You can see that the first ARM instruction, push {r7}, is encoded as
7004e52d and not e52d7004.

Thanks,
Greg

Makefile (599 Bytes)

c.ii (744 Bytes)

Looks like the bug here is that the InlineAsm parser and the ARM code
emitter point to two different TargetSubtargetInfo instances. The attached
patch corrects the issue, but is incomplete. For starters, how can I remove
that const_cast? Also, the patch does not restore the TargetSubtargetInfo
to its original state. So if you changed from Thumb to ARM mode, but not
back to Thumb, the code emitter will generate broken machine code.
Unfortunately, the TargetSubtargetInfo class does not expose a copy
constructor or a setFeatureBits() method. Should it? Or should we expect
the inline assembly to be responsible for restoring the mode itself?

Thanks,
Greg

arm-inline-asm.patch (1.73 KB)

Hi Greg,

Can you post any patches to the commits list, it'll have a better chance of
some of us seeing it and taking a look there.

Cheers,
Amara

Done, thanks. And added a code review here:

http://llvm-reviews.chandlerc.com/D2255

-Greg