Skip to content

Commit

Permalink
CORE: By default use a custom fireball struct layout which re-orders …
Browse files Browse the repository at this point in the history
…fields to minimize padding

CORE: Add C struct attribute to use the C layout
  • Loading branch information
MineGame159 committed Feb 8, 2024
1 parent 548b40e commit d5ae248
Show file tree
Hide file tree
Showing 13 changed files with 239 additions and 110 deletions.
55 changes: 55 additions & 0 deletions core/abi/fb_layout.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
package abi

import (
"fireball/core/ast"
"slices"
)

var FbLayout Layout = &fbLayout{}

type fbLayout struct{}

func (f *fbLayout) Size(abi Abi, decl *ast.Struct) uint32 {
fields := f.sorted(abi, decl)

layout := cFieldAligner{}

for _, field := range fields {
layout.add(abi.Size(field.Type), abi.Align(field.Type))
}

return layout.size()
}

func (f *fbLayout) Fields(abi Abi, decl *ast.Struct) ([]*ast.Field, []uint32) {
fields := f.sorted(abi, decl)

layout := cFieldAligner{}
offsets := make([]uint32, len(fields))

for i, field := range fields {
offsets[i] = layout.add(abi.Size(field.Type), abi.Align(field.Type))
}

return fields, offsets
}

func (f *fbLayout) sorted(abi Abi, decl *ast.Struct) []*ast.Field {
fields := make([]*ast.Field, len(decl.Fields))
copy(fields, decl.Fields)

slices.SortStableFunc(fields, func(f1, f2 *ast.Field) int {
a1 := abi.Align(f1.Type)
a2 := abi.Align(f2.Type)

if a1 < a2 {
return +1
}
if a1 > a2 {
return -1
}
return 0
})

return fields
}
8 changes: 7 additions & 1 deletion core/abi/layout.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,5 +9,11 @@ type Layout interface {
}

func GetStructLayout(s *ast.Struct) Layout {
return CLayout
for _, attribute := range s.Attributes {
if attribute.Name.String() == "C" {
return CLayout
}
}

return FbLayout
}
5 changes: 3 additions & 2 deletions core/ast/cst2ast/declarations.go
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,7 @@ func (c *converter) convertNamespaceName(node cst.Node) *ast.NamespaceName {
// Struct

func (c *converter) convertStructDecl(node cst.Node) ast.Decl {
var attributes []*ast.Attribute
var name *ast.Token
var fields []*ast.Field
var staticFields []*ast.Field
Expand All @@ -110,11 +111,11 @@ func (c *converter) convertStructDecl(node cst.Node) ast.Decl {
}
}
} else if child.Kind == cst.AttributesNode {
c.error(child.Children[0], "Structs cannot have attributes")
attributes = c.convertAttributes(child)
}
}

if s := ast.NewStruct(node, name, fields, staticFields); s != nil {
if s := ast.NewStruct(node, attributes, name, fields, staticFields); s != nil {
return s
}

Expand Down
17 changes: 15 additions & 2 deletions core/ast/declarations.go
Original file line number Diff line number Diff line change
Expand Up @@ -184,23 +184,28 @@ type Struct struct {
cst cst.Node
parent Node

Attributes []*Attribute
Name *Token
Fields []*Field
StaticFields []*Field
}

func NewStruct(node cst.Node, name *Token, fields []*Field, staticfields []*Field) *Struct {
if name == nil && fields == nil && staticfields == nil {
func NewStruct(node cst.Node, attributes []*Attribute, name *Token, fields []*Field, staticfields []*Field) *Struct {
if attributes == nil && name == nil && fields == nil && staticfields == nil {
return nil
}

s := &Struct{
cst: node,
Attributes: attributes,
Name: name,
Fields: fields,
StaticFields: staticfields,
}

for _, child := range attributes {
child.SetParent(s)
}
if name != nil {
name.SetParent(s)
}
Expand Down Expand Up @@ -239,6 +244,9 @@ func (s *Struct) SetParent(parent Node) {
}

func (s *Struct) AcceptChildren(visitor Visitor) {
for _, child := range s.Attributes {
visitor.VisitNode(child)
}
if s.Name != nil {
visitor.VisitNode(s.Name)
}
Expand All @@ -255,6 +263,11 @@ func (s *Struct) Clone() Node {
cst: s.cst,
}

s2.Attributes = make([]*Attribute, len(s.Attributes))
for i, child := range s2.Attributes {
s2.Attributes[i] = child.Clone().(*Attribute)
s2.Attributes[i].SetParent(s2)
}
if s.Name != nil {
s2.Name = s.Name.Clone().(*Token)
s2.Name.SetParent(s2)
Expand Down
146 changes: 73 additions & 73 deletions core/ast/expressions.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import (

type ExprVisitor interface {
VisitParen(expr *Paren)
VisitLiteral(expr *Literal)
VisitUnary(expr *Unary)
VisitBinary(expr *Binary)
VisitLogical(expr *Logical)
Expand All @@ -23,7 +24,6 @@ type ExprVisitor interface {
VisitArrayInitializer(expr *ArrayInitializer)
VisitAllocateArray(expr *AllocateArray)
VisitIdentifier(expr *Identifier)
VisitLiteral(expr *Literal)
}

type Expr interface {
Expand Down Expand Up @@ -117,6 +117,78 @@ func (p *Paren) Result() *ExprResult {
return &p.result
}

// Literal

type Literal struct {
cst cst.Node
parent Node

Token_ scanner.Token

result ExprResult
}

func NewLiteral(node cst.Node, token scanner.Token) *Literal {
if token.IsEmpty() {
return nil
}

l := &Literal{
cst: node,
Token_: token,
}

return l
}

func (l *Literal) Cst() *cst.Node {
if l.cst.Kind == cst.UnknownNode {
return nil
}

return &l.cst
}

func (l *Literal) Token() scanner.Token {
return l.Token_
}

func (l *Literal) Parent() Node {
return l.parent
}

func (l *Literal) SetParent(parent Node) {
if parent != nil && l.parent != nil {
panic("ast.Literal.SetParent() - Parent is already set")
}

l.parent = parent
}

func (l *Literal) AcceptChildren(visitor Visitor) {
}

func (l *Literal) Clone() Node {
l2 := &Literal{
cst: l.cst,
Token_: l.Token_,
}

return l2
}

func (l *Literal) String() string {
return l.Token_.String()
}

func (l *Literal) AcceptExpr(visitor ExprVisitor) {
visitor.VisitLiteral(l)
}

func (l *Literal) Result() *ExprResult {
return &l.result
}

// Unary

type Unary struct {
Expand Down Expand Up @@ -1468,75 +1540,3 @@ func (i *Identifier) AcceptExpr(visitor ExprVisitor) {
func (i *Identifier) Result() *ExprResult {
return &i.result
}

// Literal

type Literal struct {
cst cst.Node
parent Node

Token_ scanner.Token

result ExprResult
}

func NewLiteral(node cst.Node, token scanner.Token) *Literal {
if token.IsEmpty() {
return nil
}

l := &Literal{
cst: node,
Token_: token,
}

return l
}

func (l *Literal) Cst() *cst.Node {
if l.cst.Kind == cst.UnknownNode {
return nil
}

return &l.cst
}

func (l *Literal) Token() scanner.Token {
return l.Token_
}

func (l *Literal) Parent() Node {
return l.parent
}

func (l *Literal) SetParent(parent Node) {
if parent != nil && l.parent != nil {
panic("ast.Literal.SetParent() - Parent is already set")
}

l.parent = parent
}

func (l *Literal) AcceptChildren(visitor Visitor) {
}

func (l *Literal) Clone() Node {
l2 := &Literal{
cst: l.cst,
Token_: l.Token_,
}

return l2
}

func (l *Literal) String() string {
return l.Token_.String()
}

func (l *Literal) AcceptExpr(visitor ExprVisitor) {
visitor.VisitLiteral(l)
}

func (l *Literal) Result() *ExprResult {
return &l.result
}
20 changes: 0 additions & 20 deletions core/ast/helpers.go
Original file line number Diff line number Diff line change
Expand Up @@ -84,26 +84,6 @@ func (f *Field) IsStatic() bool {
return false
}

func (f *Field) Index() int {
if f.IsStatic() {
for i, field := range f.Parent().(*Struct).StaticFields {
if field == f {
return i
}
}

panic("ast.Field.Index() - Static field not found")
}

for i, field := range f.Parent().(*Struct).Fields {
if field == f {
return i
}
}

panic("ast.Field.Index() - Field not found")
}

func (f *Field) MangledName() string {
sb := strings.Builder{}
sb.WriteString("fb$")
Expand Down
4 changes: 2 additions & 2 deletions core/ast/other.go
Original file line number Diff line number Diff line change
Expand Up @@ -706,6 +706,8 @@ func IsNil(node Node) bool {
return node == nil
case *Paren:
return node == nil
case *Literal:
return node == nil
case *Unary:
return node == nil
case *Binary:
Expand Down Expand Up @@ -734,8 +736,6 @@ func IsNil(node Node) bool {
return node == nil
case *Identifier:
return node == nil
case *Literal:
return node == nil
case *File:
return node == nil
case *NamespaceName:
Expand Down
20 changes: 18 additions & 2 deletions core/checker/attributes.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,23 @@ package checker

import "fireball/core/ast"

func (c *checker) visitAttribute(decl *ast.Func, attribute *ast.Attribute) {
func (c *checker) visitStructAttribute(attribute *ast.Attribute) {
if attribute.Name == nil {
return
}

switch attribute.Name.String() {
case "C":
if len(attribute.Args) > 0 {
c.error(attribute.Name, "C doesn't have any arguments")
}

default:
c.error(attribute.Name, "Struct attribute with this name doesn't exist")
}
}

func (c *checker) visitFuncAttribute(decl *ast.Func, attribute *ast.Attribute) {
if attribute.Name == nil {
return
}
Expand Down Expand Up @@ -39,7 +55,7 @@ func (c *checker) visitAttribute(decl *ast.Func, attribute *ast.Attribute) {
}

default:
c.error(attribute.Name, "Attribute with this name doesn't exist")
c.error(attribute.Name, "Function attribute with this name doesn't exist")
}
}

Expand Down
Loading

0 comments on commit d5ae248

Please sign in to comment.