Kengo's blog

Technical articles about original projects, JVM, Static Analysis and TypeScript.

Hello, LLVM

LLVM3.2 on OSX.

quickstart

$ cat hello.cpp
#include <stdio.h>
int main()
{
  printf("Hello World!\n");
}
$ clang++ hello.cpp -emit-llvm -S -o hello.ll
$ cat hello.ll
; ModuleID = 'hello.cpp'
target datalayout = "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128-n8:16:32:64-S128"
target triple = "x86_64-apple-macosx10.8.0"

@.str = private unnamed_addr constant [14 x i8] c"Hello World!\0A\00", align 1

define i32 @main() uwtable ssp {
  %1 = call i32 (i8*, ...)* @printf(i8* getelementptr inbounds ([14 x i8]* @.str, i32 0, i32 0))
  ret i32 0
}

declare i32 @printf(i8*, ...)
$ lli hello.ll
Hello World!
$ clang++ hello.cpp -emit-llvm -S -o - | lli
Hello World!

note

Language reference is here.

uwtable:

This attribute indicates that the ABI being targeted requires that
an unwind table entry be produce for this function even if
we can show that no exceptions passes by it. This is normally
the case for the ELF x86-64 abi, but it can be disabled for some
compilation units.

ssp:

This attribute indicates that the function should emit a stack
smashing protector. It is in the form of a “canary” — a random
value placed on the stack before the local variables that’s
checked upon return from the function to see if it has been
overwritten. A heuristic is used to determine if a function needs
stack protectors or not. The heuristic used will enable protectors
for functions with:

* Character arrays larger than ssp-buffer-size (default 8).
* Aggregates containing character arrays larger than ssp-buffer-size.
* Calls to alloca() with variable sizes or constant sizes greater than ssp-buffer-size.

If a function that has an ssp attribute is inlined into a function
that doesn’t have an ssp attribute, then the resulting function
will have an ssp attribute.

unnamed_addr:

If the unnamed_addr attribute is given, the address is know to
not be significant and two identical functions can be merged.

FizzBuzz

$ cat fizzbuzz.cpp
#include <stdio.h>

int main()
{
  int i;

  for (i = 1; i < 20; ++i)
  {
    if (0 == i % 15)
    {
      printf("FizzBuzz¥n");
    }
    else if (0 == i % 5)
    {
      printf("Buzz¥n");
    }
    else if (0 == i % 3)
    {
      printf("Fizz¥n");
    }
    else
    {
      printf("%d¥n", i);
    }
  }

  return 0;
}
$
$ clang++ fizzbuzz.cpp -emit-llvm -S -o -
; ModuleID = 'fizzbuzz.cpp'
target datalayout = "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128-n8:16:32:64-S128"
target triple = "x86_64-apple-macosx10.8.0"

@.str = private unnamed_addr constant [10 x i8] c"FizzBuzz¥0A¥00", align 1
@.str1 = private unnamed_addr constant [6 x i8] c"Buzz¥0A¥00", align 1
@.str2 = private unnamed_addr constant [6 x i8] c"Fizz¥0A¥00", align 1
@.str3 = private unnamed_addr constant [4 x i8] c"%d¥0A¥00", align 1

define i32 @main() uwtable ssp {
  %1 = alloca i32, align 4
  %i = alloca i32, align 4
  store i32 0, i32* %1
  store i32 1, i32* %i, align 4
  br label %2

; <label>:2                                       ; preds = %29, %0
  %3 = load i32* %i, align 4
  %4 = icmp slt i32 %3, 20
  br i1 %4, label %5, label %32

; <label>:5                                       ; preds = %2
  %6 = load i32* %i, align 4
  %7 = srem i32 %6, 15
  %8 = icmp eq i32 0, %7
  br i1 %8, label %9, label %11

; <label>:9                                       ; preds = %5
  %10 = call i32 (i8*, ...)* @printf(i8* getelementptr inbounds ([10 x i8]* @.str, i32 0, i32 0))
  br label %28

; <label>:11                                      ; preds = %5
  %12 = load i32* %i, align 4
  %13 = srem i32 %12, 5
  %14 = icmp eq i32 0, %13
  br i1 %14, label %15, label %17

; <label>:15                                      ; preds = %11
  %16 = call i32 (i8*, ...)* @printf(i8* getelementptr inbounds ([6 x i8]* @.str1, i32 0, i32 0))
  br label %27

; <label>:17                                      ; preds = %11
  %18 = load i32* %i, align 4
  %19 = srem i32 %18, 3
  %20 = icmp eq i32 0, %19
  br i1 %20, label %21, label %23

; <label>:21                                      ; preds = %17
  %22 = call i32 (i8*, ...)* @printf(i8* getelementptr inbounds ([6 x i8]* @.str2, i32 0, i32 0))
  br label %26

; <label>:23                                      ; preds = %17
  %24 = load i32* %i, align 4
  %25 = call i32 (i8*, ...)* @printf(i8* getelementptr inbounds ([4 x i8]* @.str3, i32 0, i32 0), i32 %24)
  br label %26

; <label>:26                                      ; preds = %23, %21
  br label %27

; <label>:27                                      ; preds = %26, %15
  br label %28

; <label>:28                                      ; preds = %27, %9
  br label %29

; <label>:29                                      ; preds = %28
  %30 = load i32* %i, align 4
  %31 = add nsw i32 %30, 1
  store i32 %31, i32* %i, align 4
  br label %2

; <label>:32                                      ; preds = %2
  ret i32 0
}

declare i32 @printf(i8*, ...)
$ 
$ opt -S fizzbuzz.ll -dot-cfg
$ dot -Teps cfg.main.dot -o fizzbuzz.eps
$ open fizzbuzz.eps // here you can see PDF about operation flow