Table of Contents
Documentation
LDC has a few differences from the D specification and some extra features. These will be documented here.
Command line options
The behavior of the output command line options may not be completely intuitive.
Runtime interface
LDC uses a slightly different runtime interface compared to DMD, it has beginning documentation on its own page
DMD incompatibilities
LDC fixes some bugs that still exist in DMD. This can make code that works with DMD fail with LDC and vice versa.
- 313, 314: import visibility
- 929: resizing U[V][] causes infinite loop
- 2061: wrong vtable call with multiple interface inheritance
- 2206: unnamed template mixin of class inside function or class has incorrect classinfo and mangleof
- 2468: result type of AndAndExp? and OrOrExp? deduced incorrectly
Violations of the specification
Some parts of the D specification are hard or impossible to implement with LLVM, they should be listed here.
Inline assembler
Implementing inline assembler as specified, in particular 'naked' and asm flow control needs a specialist with inline asm and LLVM. While quite a bit of it works as expected, we do not define D_InlineAsm_X86. Instead we define LLVM_InlineAsm_X86. One thing the D spec isn't clear about at all is how asm blocks mixed with normal D code (for example code between two asm blocks) interacts.
Specific issues are:
naked is not supported
Currently 'naked' in D is treated as a compile time error in LDC. Reason for this is that LLVM does not support directly controlling prologue/epilogue generation. Also the documentation from the D spec on this topic is extremely limited and doesn't mention anything about how normal D code in a naked function works. In particular local (stack) variables are unclear, also accessing named parameters etc.
ret
In short, LLVM inline assembler is not allowed to control program flow outside of the asm blocks, see below for a bit more information.
Gotos into inline assembly
For labels inside inline asm blocks, the D spec says "They can be the target of goto statements.", this is not supported at the moment. Basically, LLVM does not allow jumping in to or out of an asm block. We work around this for jumping out of asm by converting these branches to assignments to a temporary that is then used in a switch statement right after the inline asm block to jump to the final destination. This same workaround could be applied for jumping into inline assembly.
Zero-length static arrays
The D spec says that T[0] val; does not require storage but has an address. LDC currently allocates one bit for such a construct.
Deviations from the D ABI
The D spec only specifies an ABI for x86 processors on Windows and Linux. On other architectures and platforms LDC is free to do as it pleases, and does. However, on x86 the only parts of the ABI currently implemented is:
- the callee clears any parameters from the stack
- floating point values are returned on the x87 FPU stack
- reversing order of parameters
- returning delegates and dynamic arrays in EAX/EDX.
- passing last argument in EAX (currently disabled as it seems to be buggy)
This is still a work in progress and will most likely improve a lot during the coming months. The LLVM developers have so far been very helpful in explaining what is needed to implement this ABI properly.
Versions
Besides the predefined versions from the D 1.0 spec, LDC provides a few more.
- LLVM - always defined
- LLVM64 - compiling for a 64bit target
- LDC - always defined
- LLVM_InlineAsm_X86 - compiling for x86-32 with inline asm support
- PPC - target is 32bit PowerPC
- PPC64 - target is 64bit PowerPC
- ARM - target is ARM
- Thumb - target is Thumb
- darwin - when compiling for Mac OS X
- freebsd - when compiling for FreeBSD
- Posix - target is POSIX-compliant
Pragmas
LLVM provides pragmas to access internal functions and can be used to tweak certain behaviour, they are also subject to change!
intrinsic
The intrinsic pragma provides access to LLVM's built-in intrinsic functions. It requires a single string literal parameter with full name of the intrinsic. For example "llvm.sqrt.f32".
- It can only be used on function declarations or funtion template declarations.
- Any affected function declarations are not allowed to have bodies.
- The functions must translate to the same signature as the intrinsic.
- You may not take the address of intrinsics.
Any calls to the affected functions will generate direct calls to the llvm intrinsics.
Example:
// provide square root intrinsics pragma(intrinsic, "llvm.sqrt.f32") float sqrt(float); pragma(intrinsic, "llvm.sqrt.f64") double sqrt(double); pragma(intrinsic, "llvm.sqrt.f80") real sqrt(real); // x86 only
Overloaded intrinsics can also be accessed more easily with a templated version instead, currently only one overloaded type is supported.
Example:
// templated atomic swap intrinsic pragma(intrinsic, "llvm.atomic.swap.i#.p0i#") T llvm_atomic_swap(T)(T* ptr, T val);
The # mark in the name is replaced with the size in bits of the type of the template parameter.
no_typeinfo
You can use this pragma to stop typeinfo from being implicitly generated for a declaration.
Example:
pragma(no_typeinfo) { struct Opaque {} }
no_moduleinfo
You can use this pragma to stop moduleinfo from being implicitly generated for a declaration.
alloca
This pragma allows you to access the alloca instruction of LLVM directly. It only applies to function declarations and the final LLVM type for that declaration must be: i8* (i32/i64). The size parameter will be truncated to i32 if necessary.
Example:
pragma(alloca) void* alloca(size_t);
variadic argument handling intrinsics
Example:
alias void* va_list; pragma(va_start) void va_start(T)(va_list ap, ref T); pragma(va_arg) T va_arg(T)(va_list ap); pragma(va_end) void va_end(va_list args); pragma(va_copy) void va_copy(va_list dst, va_list src);

