llir / llvm

Library for interacting with LLVM IR in pure Go.
https://llir.github.io/document/
BSD Zero Clause License
1.18k stars 78 forks source link

unable to generate LLVM: structure, external , noundef and ptr #236

Closed dequeb closed 6 months ago

dequeb commented 6 months ago

Based on my test with clang I need to generate the following code :

%struct.GarbageCollector = type { ptr, i8, ptr, i64 }
@gc = external global %struct.GarbageCollector, align 8

declare void @gc_start(ptr noundef, ptr noundef) #1
declare i64 @gc_stop(ptr noundef) #1
declare ptr @gc_malloc(ptr noundef, i64 noundef) #1

define i32 @main(i32 %argc, i8** %argv) {
0:
    %1 = alloca i32
    store i32 %argc, i32* %1
    call void @gc_start(ptr noundef @gc, ptr noundef %1)
    %2 = call i64 @gc_stop(ptr noundef @gc)
    ret i32 0
}

I don't see how to generate structure, external, noundef and ptr. Do we have alternative to these in the current library or are they missing features? I so, could they be added? How could I help?

mewmew commented 6 months ago

Hi @dequeb,

Here's an example to get you started. It's not identical, but showcases how to get external global variables and add parameter attributes to the LLVM IR.

In general, remember to take a look at the ir/types and ir/enum packages, in addition to ir.

Note, however that llir/llvm does not yet support opaque pointers (see https://github.com/llir/llvm/issues/222#issuecomment-1202279183).

package main

import (
    "fmt"

    "github.com/llir/llvm/ir"
    "github.com/llir/llvm/ir/constant"
    "github.com/llir/llvm/ir/enum"
    "github.com/llir/llvm/ir/types"
)

func main() {
    i8 := types.I8
    i32 := types.I32
    i64 := types.I64
    ptrType := types.NewPointer(i8)
    m := ir.NewModule()

    // %struct.GarbageCollector type definition
    garbageCollectorType := types.NewStruct(ptrType, i8, ptrType, i64)
    m.NewTypeDef("struct.GarbageCollector", garbageCollectorType)

    // gc global
    gcGlobal := ir.NewGlobal("gc", garbageCollectorType)
    gcGlobal.Linkage = enum.LinkageExternal
    gcGlobal.Align = 8

    garbageCollectorPtrType := types.NewPointer(garbageCollectorType)

    // gc_start
    gcStartParam1 := ir.NewParam("param1", garbageCollectorPtrType)
    gcStartParam1.Attrs = append(gcStartParam1.Attrs, enum.ParamAttrNoUndef)
    gcStartParam2 := ir.NewParam("param2", ptrType)
    gcStartParam2.Attrs = append(gcStartParam2.Attrs, enum.ParamAttrNoUndef)
    gcStart := m.NewFunc("gc_start", types.Void, gcStartParam1, gcStartParam2)
    // gc_stop
    gcStopParam1 := ir.NewParam("param1", ptrType)
    gcStopParam1.Attrs = append(gcStopParam1.Attrs, enum.ParamAttrNoUndef)
    gcStop := m.NewFunc("gc_stop", i64, gcStopParam1)
    // gc_malloc
    gcMallocParam1 := ir.NewParam("param1", ptrType)
    gcMallocParam1.Attrs = append(gcMallocParam1.Attrs, enum.ParamAttrNoUndef)
    gcMallocParam2 := ir.NewParam("param2", ptrType)
    gcMallocParam2.Attrs = append(gcMallocParam2.Attrs, enum.ParamAttrNoUndef)
    gcMalloc := m.NewFunc("gc_malloc", ptrType, gcMallocParam1, gcMallocParam2)
    _ = gcStart
    _ = gcStop
    _ = gcMalloc

    // main function
    argcParam := ir.NewParam("argc", i32)
    argvType := types.NewPointer(types.NewPointer(i8))
    argvParam := ir.NewParam("argv", argvType)
    main := m.NewFunc("main", i32, argcParam, argvParam)
    entry := main.NewBlock("")
    localVar := entry.NewAlloca(i32)
    entry.NewStore(argcParam, localVar)
    entry.NewCall(gcStart, gcGlobal, localVar)
    entry.NewCall(gcStop, gcGlobal)
    zero := constant.NewInt(i32, 0)
    entry.NewRet(zero)
    // print LLVM IR module
    fmt.Println(m)
}

Output LLVM IR:

%struct.GarbageCollector = type { i8*, i8, i8*, i64 }

declare void @gc_start(%struct.GarbageCollector* noundef %param1, i8* noundef %param2)

declare i64 @gc_stop(i8* noundef %param1)

declare i8* @gc_malloc(i8* noundef %param1, i8* noundef %param2)

define i32 @main(i32 %argc, i8** %argv) {
0:
    %1 = alloca i32
    store i32 %argc, i32* %1
    call void @gc_start(%struct.GarbageCollector* @gc, i32* %1)
    %2 = call i64 @gc_stop(%struct.GarbageCollector* @gc)
    ret i32 0
}

Cheers, Robin