llir / llvm

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

Hello 10 instead of Hello world. Passing a IntPtr to printf (go - LLIR/LLVM) #234

Closed ghost closed 8 months ago

ghost commented 8 months ago

I, I'm new to LLIR/LLVM Based on the example Hello Word, I'd like to pass other types of variables (like int here). The following program crashes at line 25 with the error invalid gep source type; expected pointer or vector of pointers type, got *types.IntType. Could someone help me?

package irgen

import (
    "fmt"
    "testing"

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

func TestIntGEN(*testing.T) {
    // Create a new LLVM IR module.
    m := ir.NewModule()
    hello := constant.NewCharArrayFromString("Hello, %d!\n\x00")
    ten := constant.NewInt(types.I32, 10)
    str := m.NewGlobalDef("str", hello)
    // Add external function declaration of printf.
    printf := m.NewFunc("printf", types.I32, ir.NewParam("", types.NewPointer(types.I8)))
    printf.Sig.Variadic = true
    main := m.NewFunc("main", types.I32)
    entry := main.NewBlock("")
    // Cast *[15]i8 to *i8.
    zero := constant.NewInt(types.I64, 0)
    tenPtr := constant.NewGetElementPtr(ten.Typ, ten, zero, zero)
    gep := constant.NewGetElementPtr(hello.Typ, str, zero, zero)
    entry.NewCall(printf, gep, tenPtr)
    entry.NewRet(constant.NewInt(types.I32, 0))
    fmt.Println(m)
}
ghost commented 8 months ago

I modified my code. It compiles but the result is not what is expected:

func TestIntGEN(*testing.T) {
    // Create a new LLVM IR module.
    m := ir.NewModule()
    hello := constant.NewCharArrayFromString("Hello, %d!\n\x00")
    ten := constant.NewInt(types.I32, 10)
    numb := m.NewGlobalDef("ten", ten)
    str := m.NewGlobalDef("str", hello)
    // Add external function declaration of printf.
    printf := m.NewFunc("printf", types.I32, ir.NewParam("", types.NewPointer(types.I8)))
    printf.Sig.Variadic = true
    main := m.NewFunc("main", types.I32)
    entry := main.NewBlock("")
    // Cast *[15]i8 to *i8.
    zero := constant.NewInt(types.I64, 0)
    // allocate memory for ten
    tenPtr := entry.NewAlloca(numb.Typ)
    // store the pointer to ten in tenPtr
    entry.NewStore(numb, tenPtr)
    gep := constant.NewGetElementPtr(hello.Typ, str, zero, zero)
    entry.NewCall(printf, gep, tenPtr)
    entry.NewRet(constant.NewInt(types.I32, 0))
    fmt.Println(m)
}

It looks like the pointer is accessing a random value instead. Someone could help?

The resulting LLVM-IR is:

@ten = global i32 10
@str = global [12 x i8] c"Hello, %d!\0A\00"

declare i32 @printf(i8* %0, ...)

define i32 @main() {
0:
        %1 = alloca i32*
        store i32* @ten, i32** %1
        %2 = call i32 (i8*, ...) @printf(i8* getelementptr ([12 x i8], [12 x i8]* @str, i64 0, i64 0), i32** %1)
        ret i32 0
}
mewmew commented 8 months ago

Hi @dequeb,

I updated the example code you posted to make it print "Hello, 10!". The random value that was printed was the pointer address, rather than the value stored within the local variable. Hope this helps!

Contents of foo.go:

package main

import (
    "fmt"

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

func main() {
    // Create a new LLVM IR module.
    m := ir.NewModule()
    hello := constant.NewCharArrayFromString("Hello, %d!\n\x00")
    ten := constant.NewInt(types.I32, 10)
    numb := m.NewGlobalDef("ten", ten)
    str := m.NewGlobalDef("str", hello)
    // Add external function declaration of printf.
    printf := m.NewFunc("printf", types.I32, ir.NewParam("", types.NewPointer(types.I8)))
    printf.Sig.Variadic = true
    main := m.NewFunc("main", types.I32)
    entry := main.NewBlock("")
    // Cast *[15]i8 to *i8.
    zero := constant.NewInt(types.I64, 0)
    // load value of global variable to local variable.
    tenVal := entry.NewLoad(types.I32, numb)
    gep := constant.NewGetElementPtr(hello.Typ, str, zero, zero)
    entry.NewCall(printf, gep, tenVal)
    entry.NewRet(constant.NewInt(types.I32, 0))
    fmt.Println(m)
}

Output LLVM IR (foo.ll):

@ten = global i32 10
@str = global [12 x i8] c"Hello, %d!\0A\00"

declare i32 @printf(i8* %0, ...)

define i32 @main() {
0:
    %1 = load i32, i32* @ten
    %2 = call i32 (i8*, ...) @printf(i8* getelementptr ([12 x i8], [12 x i8]* @str, i64 0, i64 0), i32 %1)
    ret i32 0
}

Output from lli:

$ go run foo.go > foo.ll
$ lli foo.ll
Hello, 10!
ghost commented 8 months ago

Thank you.


De : Robin @.> Envoyé : Sunday, March 10, 2024 8:38:13 PM À : llir/llvm @.> Cc : dequeb @.>; Mention @.> Objet : Re: [llir/llvm] Hello 10 instead of Hello world. Passing a IntPtr to printf (go - LLIR/LLVM) (Issue #234)

Hi @dequebhttps://github.com/dequeb,

I updated the example code you posted to make it print "Hello, 10!". The random value that was printed was the pointer address, rather than the value stored within the local variable. Hope this helps!

Contents of foo.go:

package main

import ( "fmt"

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

)

func main() { // Create a new LLVM IR module. m := ir.NewModule() hello := constant.NewCharArrayFromString("Hello, %d!\n\x00") ten := constant.NewInt(types.I32, 10) numb := m.NewGlobalDef("ten", ten) str := m.NewGlobalDef("str", hello) // Add external function declaration of printf. printf := m.NewFunc("printf", types.I32, ir.NewParam("", types.NewPointer(types.I8))) printf.Sig.Variadic = true main := m.NewFunc("main", types.I32) entry := main.NewBlock("") // Cast [15]i8 to i8. zero := constant.NewInt(types.I64, 0) // allocate memory for ten tenVal := entry.NewLoad(types.I32, numb) gep := constant.NewGetElementPtr(hello.Typ, str, zero, zero) entry.NewCall(printf, gep, tenVal) entry.NewRet(constant.NewInt(types.I32, 0)) fmt.Println(m) }

Output LLVM IR (foo.ll):

@ten = global i32 10 @str = global [12 x i8] c"Hello, %d!\0A\00"

declare i32 @printf(i8* %0, ...)

define i32 @main() { 0: %1 = load i32, i32 @ten %2 = call i32 (i8, ...) @printf(i8 getelementptr ([12 x i8], [12 x i8] @str, i64 0, i64 0), i32 %1) ret i32 0 }

Output from lli:

$ go run foo.go > foo.ll $ lli foo.ll Hello, 10!

— Reply to this email directly, view it on GitHubhttps://github.com/llir/llvm/issues/234#issuecomment-1987439311, or unsubscribehttps://github.com/notifications/unsubscribe-auth/AUS3HCKCTOUX6WEXWVAMXFDYXT4HLAVCNFSM6AAAAABEOEBDY6VHI2DSMVQWIX3LMV43OSLTON2WKQ3PNVWWK3TUHMYTSOBXGQZTSMZRGE. You are receiving this because you were mentioned.Message ID: @.***>