Compiling and executing LLVM IR generated by Swift compiler causes segmentation fault

For a project I need to obtain the LLVM IR emitted by the Swift compiler, instrument it and run it. For that, I want to use either clang or llvms llc. However when I execute the program I get a segmentation fault and I have no idea what is causing this. Here is a replicable example of what I did.

I should say this only happens when I include arrays in my program so it must have something to do with the array standard library I assume. Also I use Swift 5.1
Here is a simple example:

var arr = [1, 2, 3]; 

for i in 0...arr.count-1 {
    arr[i] = 0; 

I then get the IR with swiftc -emit-ir filename.swift -o filename.ll

With lld on the executable I get the required dynamic libraries. Then I do

clang-8 arr_test.ll -L /usr/lib/swift/linux/ -lswiftCore -lswiftSwiftOnoneSupport -licudataswift

and then I run the obtained executable which always gives me a core dump. This should work however and I cant see why it should not, it does for all kinds of programs I have tested but not for arrays. I first thought this is due to the instrumentation I did but it is the same behavior even if I do not touch the IR at all.


I tried the same example with version 5.6 and the appropriate libraries and the error did not occur there. Is this a known problem in the 5.1 version or did I do something wrong here? of course compiling and executing the program directly also works so that makes me think I am using the wrong libs or something?

1 Like

LLVM IR is not a stable format, and the IR that the Swift compiler emits is not guaranteed to be usable by any version of LLVM other than the one that the Swift compiler you used was compiled with. If you want to experiment with the LLVM IR generated by Swift, or really any LLVM-based compiler, I would say your best bet is to build LLVM, Clang, and Swift from source, so that you know you have the correct LLVM/Clang corresponding to your locally-built compiler. Alternatively, if that isn't practical for you, use the clang that is inside the same Swift toolchain you used to compile the Swift code rather than a system clang that may use a different LLVM version.

so is it purely about the version? I looked up on this site Xcode - Wikipedia

what llvm version swift 5.1.5 is based on. based on that I have used swift version 5.1 which is based on llvm 8.0.1 and I used the clang that comes with that. where in the repository can I find the exact version used in the swift version 5.1.5?

thank you

edit: I used the clang that was included in my swift bin directory which turned out to be version 7.0.0 but it still caused a segmentation fault upon execution. So I used only binaries from the swift installation and it caused segmentation fault

There isn't really a clean mapping of Swift versions to LLVM "versions" per se, because LLVM is under continuous development. Swift follows the top-of-tree main development branch of LLVM and forks LLVM at the point we start preparing a release. If you are doing LLVM development, I would not recommend working with an older version of Swift or LLVM since these are generally not actively developed and at best only receive maintenance patches, and active development happens on top-of-tree, so if you run into issues you are more likely to get help if you work on the actively developed branch.

1 Like

I understand. my problem is that I am working with an existing project that was built based on LLVM 8 and when I now use the optimizer for a later version and run a pass developed for an older version it will cause problems too. normally I noticed incompatibilities when I run the opt tool because of different IR constructs or syntax. I did not expect it during linking or execution and why it would cause a segfault. it is also strange that it works for all other versions and only does not work when I use arrays in the swift code. I find that strange. also the team that worked on this project and did with C/C++what I try with swift never experienced something like this so is it different with clang as in they use the llvm version from the day of the release of that version?

so you think what I would need to do then is to clone the LLVM from the state of the 5.1 swift release and compile it myself?

I see. Unfortunately you're kind of out of the golden path doing this sort of thing, but if Swift 5.1, or other versions of similar vintage to LLVM 8, manage to generate IR that's generally acceptable by the LLVM 8 toolchain, that might be your best bet if you have a hard dependency on LLVM 8 exactly. You could also try checking out the 5.1 branch of Swift and compiling it against LLVM 8, but that will likely require build system and source modifications that might be beyond the scope of your project.

so after some experimenting I noticed something interesting:

when instead of compiling the IR to an executable and running it I use LLVMs lli tool which is basically an interpreter/jit it works. Thats good for my project however I am now even more confused on what is actually going on. the lli command is from the same versioned package as the clang I used to link against the shared libraries

lli-8 -load="/usr/lib/swift/linux/" -load="/usr/lib/swift/linux/" array.ll