MSP430 code generation from LLVM IR


While trying to find out why the LDC compiler refuses to generate object code for MSP430 targets (but generates MSP430 assembly or LLVM IR/bitcode), I came across the following apparent inconsistency.

This works:

$ clang --target=msp430 -c test.c

This doesn’t work:

$ clang --target=msp430 -S -emit-llvm test.c
$ llc -filetype=obj test.ll
/opt/msp430/bin/llc: target does not support generation of this file type!

That sequence works fine for x86.

Could someone help shed some light into this discrepancy? (Maybe it will also help me figure out why LDC refuses to directly generate MSP430 object files [1]).


[1] $ ldc2 -mtriple=msp430 -c test.d
no support for asm output
UNREACHABLE executed at …/driver/toobj.cpp:130!
0 ldc2 0x0000000107e19c9c llvm::sys::PrintStackTrace(llvm::raw_ostream&) + 60
1 ldc2 0x0000000107e1a1e9 PrintStackTraceSignalHandler(void*) + 25
2 ldc2 0x0000000107e16139 llvm::sys::RunSignalHandlers() + 425
3 ldc2 0x0000000107e1a642 SignalHandler(int) + 354
4 libsystem_platform.dylib 0x00007fffa0ad5b3a _sigtramp + 26
5 libsystem_platform.dylib 0x0000000000000003 _sigtramp + 1599251683
6 libsystem_c.dylib 0x00007fffa095a420 abort + 129
7 ldc2 0x0000000107d246c0 LLVMInstallFatalErrorHandler + 0
8 ldc2 0x0000000105efd2a7 codegenModule(llvm::TargetMachine&, llvm::Module&, llvm::raw_fd_ostream&, llvm::TargetMachine::CodeGenFileType) + 391
9 ldc2 0x0000000105f00ab9 (anonymous namespace)::writeObjectFile(llvm::Module*, char const*) + 377
10 ldc2 0x0000000105efcc05 writeModule(llvm::Module*, char const*) + 10517
11 ldc2 0x0000000105ee6162 ldc::CodeGenerator::writeAndFreeLLModule(char const*) + 1602
12 ldc2 0x0000000105ee6a82 ldc::CodeGenerator::finishLLModule(Module*) + 130
13 ldc2 0x0000000105ee880c ldc::CodeGenerator::emit(Module*) + 1420
14 ldc2 0x0000000105f36e4e codegenModules(Array<Module*>&) + 574
15 ldc2 0x0000000105bf2a00 mars_mainBody(Array<char const*>&, Array<char const*>&) + 5120
Abort trap: 6

There is no direct object emission support in MSP430 backend. clang
executed assembler under the hood.

Luís, try using the -no-integrated-as flag to execute the assembler for you.
We should probably make that the default for MSP430.


Cool. When I did that on macOS, LDC generated a lot of complaints, possibly
because it is assuming mach-o files. I tried changing from -mtriple=msp430
to -mtriple=msp430-unknown-elf, to no avail. E.g.:

$ ldc2 -mtriple=msp430-unknown-elf -c -no-integrated-as qosd.d
ldc-ad1c8f0.s:3:11: error: mach-o section specifier requires a segment
whose length is between 1 and 16 characters
ldc-ad1c8f0.s:6:2: error: unknown directive
        .type _D4qosd3fooFZi,@function
ldc-ad1c8f0.s:8:2: error: invalid instruction mnemonic 'mov.w'
        mov.w #42, r14


I didn't try it in a Linux host. I imagine a lot of the errors will go away
there (because it assumes ELF), but possibly not the ones about 'mov.w'.

Clang has a bunch of complicated logic to find the correct assembler
if it's installed (in this case I'd expect "msp430-unknown-elf-as").
It's quite possible LDC doesn't have this since its main targets use
the integrated-assembler. Your errors certainly look consistent with
the macOS system "as" being called on ELF MSP430 output.

I know that in Clang you can add "-###" so that Clang will tell you
the exact commands it would run (or -v to both tell you and do it).
I'd hope LDC has some equivalent.



Yup, it's using /usr/bin/gcc as the assembler driver.

If you want to hack it straight away

make changes to
in particular change the getGcc in line 186
int R = executeToolAndWait(getGcc(), args, global.params.verbose);

to wherever you assembler is located.
You may have to change the arguments passed to the assembler as well.

I’ll provide a pull request. Since MSP430 code is always cross-compiled we can assume that ‘gcc’ is always wrong. The only names I’ve ever seen used are ‘msp430-gcc’ (nearly all I’ve seen) and ‘msp430-elf-gcc’ (TI’s prebuilt toolchain). So, for now, we can avoid the “complicated logic” that clang uses without hardcoding it too much.