TC-L FAQ

What is a PHI node?

LLVM instructions are represented in the SSA (Static Single Assignment) form.

Let’s take an example:

let
  var v := 10
  var a := 1
  var b := 0
in
  if (v < 10) then
    a := 2;
  b := a
end

The whole point of The SSA form is to create a variable each time a variable is assigned more than once to enforce the single static assignment, so we cannot assign 2 to a.

In that case, LLVM is going to create two a’s, and the assignment has to pick the desired version.

Using a PHI node, the assignment will depend on the original path of the code, and using that information, it can decide which version of a should be picked.

You can use the opt tool in order to display the control-flow graph.

opt -dot-cfg fact.ll

This generates two files: cfg.tc_main.dot and cfg.fact_18.dot, corresponding to the main function and the fact function.

I don’t understand all the acronyms used in LLVM.

Where can I find their meaning? You can find it in The LLVM Lexicon.

Can I output the LLVM IR of a C/C++ program?

Yes, you can. Clang, A C language family front end for LLVM allows you to do it using the flags -S -emit-llvm.

clang-example.c
int main(void)
{
  int a = 1 + 2 * 3;
  return a;
}
clang -m32 -S -emit-llvm -o - clang-example.c
$ clang -m32 -S -emit-llvm -o - clang-example.c
; ModuleID = 'clang-example.c'
source_filename = "clang-example.c"
target datalayout = "e-m:e-p:32:32-p270:32:32-p271:32:32-p272:64:64-f64:32:64-f80:32-n8:16:32-S128"
target triple = "i386-pc-linux-gnu"

; Function Attrs: noinline nounwind optnone uwtable
define dso_local i32 @main() #0 {
  %1 = alloca i32, align 4
  %2 = alloca i32, align 4
  store i32 0, i32* %1, align 4
  store i32 7, i32* %2, align 4
  %3 = load i32, i32* %2, align 4
  ret i32 %3
}

attributes #0 = { noinline nounwind optnone uwtable "frame-pointer"="all" "min-legal-vector-width"="0" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-cpu"="i686" "target-features"="+cx8,+x87" "tune-cpu"="generic" }

!llvm.module.flags = !{!0, !1, !2, !3, !4, !5}
!llvm.ident = !{!6}

!0 = !{i32 1, !"NumRegisterParameters", i32 0}
!1 = !{i32 1, !"wchar_size", i32 4}
!2 = !{i32 7, !"PIC Level", i32 2}
!3 = !{i32 7, !"PIE Level", i32 2}
!4 = !{i32 7, !"uwtable", i32 1}
!5 = !{i32 7, !"frame-pointer", i32 2}
!6 = !{!"Debian clang version 14.0.6"}
$ echo $?
0
The build failed on my machine

If the following error occurs:

  CXXLD    src/tc
src/.libs/libtc.a(lt14-translator.o):(.rodata._ZTIN4llvm17GetElementPtrInstE[_ZTIN4llvm17GetElementPtrInstE]+0x10): undefined reference to `typeinfo for llvm::Instruction'
src/.libs/libtc.a(lt14-translator.o):(.rodata._ZTIN4llvm8ICmpInstE[_ZTIN4llvm8ICmpInstE]+0x10): undefined reference to `typeinfo for llvm::CmpInst'
src/.libs/libtc.a(lt14-translator.o):(.rodata._ZTIN4llvm7PHINodeE[_ZTIN4llvm7PHINodeE]+0x10): undefined reference to `typeinfo for llvm::Instruction'
collect2: error: ld returned 1 exit status
Makefile:2992: recipe for target 'src/tc' failed
make: *** [src/tc] Error 1

then you are using an old version of LLVM. The version required is 3.8 or more.

If you still want to use LLVM 3.7, then the LLVM build you are using is compiled without RTTI.

In order to make it work, you have two choices:

  • If you are building LLVM 3.7 from the source code, apply this patch to fix the compilation.

  • Build LLVM with RTTI enabled. In order to build LLVM with RTTI enabled, follow these steps, assuming the current directory is the root of LLVM:

    • mkdir _build

    • cd _build

    • cmake .. -DLLVM_REQUIRES_RTTI=ON -DCMAKE_BUILD_TYPE=Release

    • make install

LLVM builds with RTTI disabled by default. They use their own RTTI-like system. Tiger is compiled using RTTI, and actually uses it quite a lot (dynamic_cast). In order to make them work together, LLVM has to emit the vtables of its classes in their own translation unit.

This regression appeared in LLVM 3.7 when a virtual destructor was inlined, so the vtables were emitted in every translation unit. It was the following classes: llvm::GetElementPtrInst, llvm::ICmpInst and llvm::PHINode.

In order to solve the problem, LLVM uses a dedicated member function called anchor, that is going to force the emission to happen in its own translation unit.

As of today, here are some packages of LLVM 3.7 that work/don’t work: - ArchLinux (pacman) - RTTI enabled.

  • OS X (brew) - RTTI enabled.

  • OS X (macports) - RTTI disabled. Does not compile.

  • Ubuntu (apt) - RTTI enabled.

Your compiler crashes when llvm::Linker::linkModules is called

When using --llvm-runtime-display, this behavior can occur when the linker is asked to link two LLVM IR modules that may have been compiled with two different LLVM IR versions.

Since the runtime is compiled with Clang, A C language family front end for LLVM, from C to LLVM IR, you have to make sure that the Clang, A C language family front end for LLVM version and the LLVM version are exactly the same.

This crash currently occurs with Clang, A C language family front end for LLVM 3.6 and LLVM 3.8.