llvm icon indicating copy to clipboard operation
llvm copied to clipboard

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

Open dequeb opened this issue 1 year ago • 1 comments

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?

dequeb avatar Mar 15 '24 13:03 dequeb

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

mewmew avatar Mar 16 '24 18:03 mewmew