Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

sizeof? #190

Open
Nv7-GitHub opened this issue Jun 14, 2021 · 4 comments
Open

sizeof? #190

Nv7-GitHub opened this issue Jun 14, 2021 · 4 comments

Comments

@Nv7-GitHub
Copy link
Contributor

How do you call the sizeof function from LLVM? When C code using sizeof is generated, the code generated just has a constant. Is there a way to find the size of an object from LLVM?

@mewmew
Copy link
Member

mewmew commented Jun 14, 2021

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).

@Nv7-GitHub
Copy link
Contributor Author

Are there any examples on using irutil.Layout?

@mewmew
Copy link
Member

mewmew commented Jun 14, 2021

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 mewmew added the howto label Jun 14, 2021
@dannypsnl
Copy link
Member

@mewmew Probably we can merge these howto to document?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

3 participants