mini iLisp "hello world" - graeme-lockley/ilisp GitHub Wiki

The hello world of mini-iLisp is super simple.

(println "hello world)

A handful of constraints that need to be remembered:

  • When linking a binary the single public identifier main is called with arguments. The usual C declaration for main captures this.

    int main(int argc, char *argv[], char *envp[]) {
      ...
    }

    Compiling hello world as follows is sufficient:

    declare i32 @printf(i8*, ...) #1
    
    @.str = private unnamed_addr constant [14 x i8] c"hello worlds\0A\00", align 1
    
    define i32 @main() #0 {
      %1 = call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([14 x i8], [14 x i8]* @.str, i64 0, i64 0))
      ret i32 0
    }
  • In the code above is string is being represented as a pointer to a chunk of memory without any tagging. By virtue of mini-iLisp being a dynamically typed language it is necessary for every value to be tagged. Rewriting this into C we end up with:

    #include <stdio.h>
    
    #define INT_VALUE 0
    #define STR_VALUE 1
    
    struct Value
    {
      char type;
      union
      {
        int number;
        char *str;
      };
    };
    
    void print_value(struct Value *value)
    {
      switch (value->type)
      {
        case INT_VALUE:
          printf("%d", value->number);
          break;
    
        case STR_VALUE:
          printf("%s", value->str);
          break;
      }
    }
    
    int main()
    {
      struct Value v;
      v.type = STR_VALUE;
      v.str = "hello world";
    
      print_value(&v);
      printf("\n");
    }

    This is then translated into the following IR

    declare i32 @printf(i8*, ...) #1
    
    %struct.Value = type { i8, %union.anon }
    %union.anon = type { i8* }
    
    @.str = private unnamed_addr constant [3 x i8] c"%d\00", align 1
    @.str.1 = private unnamed_addr constant [3 x i8] c"%s\00", align 1
    @.str.2 = private unnamed_addr constant [12 x i8] c"hello world\00", align 1
    @.str.3 = private unnamed_addr constant [2 x i8] c"\0A\00", align 1
    
    define void @print_value(%struct.Value* %0) #0 {
      %2 = alloca %struct.Value*, align 8
      store %struct.Value* %0, %struct.Value** %2, align 8
      %3 = load %struct.Value*, %struct.Value** %2, align 8
      %4 = getelementptr inbounds %struct.Value, %struct.Value* %3, i32 0, i32 0
      %5 = load i8, i8* %4, align 8
      %6 = sext i8 %5 to i32
      switch i32 %6, label %19 [
        i32 0, label %7
        i32 1, label %13
      ]
    
    7:
      %8 = load %struct.Value*, %struct.Value** %2, align 8
      %9 = getelementptr inbounds %struct.Value, %struct.Value* %8, i32 0, i32 1
      %10 = bitcast %union.anon* %9 to i32*
      %11 = load i32, i32* %10, align 8
      %12 = call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([3 x i8], [3 x i8]* @.str, i64 0, i64 0), i32 %11)
      br label %19
    
    13:
      %14 = load %struct.Value*, %struct.Value** %2, align 8
      %15 = getelementptr inbounds %struct.Value, %struct.Value* %14, i32 0, i32 1
      %16 = bitcast %union.anon* %15 to i8**
      %17 = load i8*, i8** %16, align 8
      %18 = call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([3 x i8], [3 x i8]* @.str.1, i64 0, i64 0), i8* %17)
      br label %19
    
    19:
      ret void
    }
    
    define dso_local i32 @main() #0 {
      %1 = alloca %struct.Value, align 8
      %2 = getelementptr inbounds %struct.Value, %struct.Value* %1, i32 0, i32 0
      store i8 1, i8* %2, align 8
      %3 = getelementptr inbounds %struct.Value, %struct.Value* %1, i32 0, i32 1
      %4 = bitcast %union.anon* %3 to i32*
      store i32 ptrtoint ([12 x i8]* @.str.2 to i32), i32* %4, align 8
      call void @print_value(%struct.Value* %1)
      %5 = call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([2 x i8], [2 x i8]* @.str.3, i64 0, i64 0))
      ret i32 0
    }
  • The union will be extended to accommodate the different types as they are introduced in later sections.

  • The function print_value is dropped into a library and linked in.

⚠️ **GitHub.com Fallback** ⚠️