Open Nv7-GitHub opened 3 years ago
Hi @Nv7-GitHub,
There is an initial implementation for handling basic types (e.g. int, float, etc). See irutil.Layout and irutil.DefaultLayout.SizeOf. Note that the implementation does not yet handle calculating the size of composite types (e.g. arrays, structs, etc) as they depend on padding of the memory layout.
The intention is to parse LLVM data layout strings to determine the handling of padding in structs, arrays, etc. This would be used to implement the irutil.Layout
interface and have it determine the size of composite types. This is tracked by issue #189.
For added background, see #66 for further background.
Cheers, Robin
Edit: @Nv7-GitHub should you feel like getting more involved with the llir/llvm
project, consider implementing a parser for the LLVM data layout string. This would go a long way to adding support for determining the size of composite types (as covered by issue #189).
Are there any examples on using irutil.Layout
?
Are there any examples on using irutil.Layout?
Here is a rough usage example. It assumes 1-byte memory alignment. Preferably such information should be parsed from the LLVM IR data layout string (i.e. llir/llvm/ir.Module.DataLayout).
package main
import (
"fmt"
"github.com/llir/irutil"
"github.com/llir/llvm/ir/types"
)
func main() {
foo()
// Output:
//
// type: i8 (size: 8 bits)
// panic: support for size of on type *types.ArrayType not yet implemented
bar()
// Output:
//
// type: i8 (size: 8 bits)
// type: [123 x i8] (size: 984 bits)
}
func foo() {
defer func() {
e := recover() // recover from panic "support for size of on type *types.ArrayType not yet implemented"
if e != nil {
fmt.Printf("recovered from panic: %v\n", e)
}
}()
layout := irutil.DefaultLayout{}
i8Type := types.I8
i8Size := layout.SizeOf(i8Type)
fmt.Printf("type: %v (size: %d bits)\n", i8Type, i8Size)
// Output:
//
// type: i8 (size: 8 bits)
arrayType := types.NewArray(123, i8Type)
arraySize := layout.SizeOf(arrayType)
fmt.Printf("type: %v (size: %d bits)\n", arrayType, arraySize)
// Output:
//
// panic: support for size of on type *types.ArrayType not yet implemented
}
// Layout specifies how data is to be laid out in memory, using one-byte memory
// alignment for padding of struct fields and array elements.
type Layout struct {
irutil.DefaultLayout
}
// SizeOf returns the size of the given type in number of bits.
func (l Layout) SizeOf(typ types.Type) int {
const pointerSize = 8 // assume 8 byte pointer size
switch typ := typ.(type) {
case *types.VoidType:
return 0
case *types.FuncType:
return pointerSize // assume function types are represented as pointers.
case *types.MMXType:
return 64 // MMX registers are 64 bits in size.
case *types.PointerType:
return pointerSize
case *types.VectorType:
return l.SizeOf(typ.ElemType) * int(typ.Len)
case *types.LabelType:
return 0 // TODO: figure out how to handle size of on label types.
case *types.TokenType:
return 0 // TODO: figure out how to handle size of on token types.
case *types.MetadataType:
return 0 // TODO: figure out how to handle size of on metadata types.
case *types.ArrayType:
return l.SizeOf(typ.ElemType) * int(typ.Len)
case *types.StructType:
total := 0
// TODO: figure out how to handle Opaque struct types.
// TODO: handle padding between struct fields if using other memory
// alignment than 1 byte.
align := 1 // TODO: read alignment from data layout of LLVM IR module.
if typ.Packed {
align = 1
}
for _, field := range typ.Fields {
fieldSize := l.SizeOf(field)
_ = align // TODO: handle alignment in between fields.
total += fieldSize
}
return total
}
//case *types.IntType: // handled by irutil.DefaultLayout
//case *types.FloatType: // handled by irutil.DefaultLayout
return l.DefaultLayout.SizeOf(typ)
}
func bar() {
layout := Layout{}
i8Type := types.I8
i8Size := layout.SizeOf(i8Type)
fmt.Printf("type: %v (size: %d bits)\n", i8Type, i8Size)
// Output:
//
// type: i8 (size: 8 bits)
arrayType := types.NewArray(123, i8Type)
arraySize := layout.SizeOf(arrayType)
fmt.Printf("type: %v (size: %d bits)\n", arrayType, arraySize)
// Output:
//
// type: [123 x i8] (size: 984 bits)
}
@mewmew Probably we can merge these howto to document?
How do you call the
sizeof
function from LLVM? When C code usingsizeof
is generated, the code generated just has a constant. Is there a way to find the size of an object from LLVM?