-
Notifications
You must be signed in to change notification settings - Fork 2
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
CORE: Add abstraction for different ABIs
CORE: Add the System V AMD64 ABI
- Loading branch information
1 parent
792b674
commit 96d2714
Showing
38 changed files
with
1,560 additions
and
516 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,59 @@ | ||
package abi | ||
|
||
import ( | ||
"fireball/core/ast" | ||
"runtime" | ||
) | ||
|
||
type ClassKind uint8 | ||
|
||
const ( | ||
None ClassKind = iota | ||
Integer | ||
SSE | ||
Memory | ||
) | ||
|
||
type Arg struct { | ||
Class ClassKind | ||
Bits uint32 | ||
} | ||
|
||
func (a Arg) Bytes() uint32 { | ||
return max(a.Bits, 8) / 8 | ||
} | ||
|
||
type Abi interface { | ||
Size(type_ ast.Type) uint32 | ||
Align(type_ ast.Type) uint32 | ||
|
||
Fields(decl *ast.Struct) ([]*ast.Field, []uint32) | ||
|
||
Classify(type_ ast.Type, args []Arg) []Arg | ||
} | ||
|
||
func GetTargetAbi() Abi { | ||
switch runtime.GOOS { | ||
case "linux", "darwin": | ||
return AMD64 | ||
|
||
default: | ||
panic("abi.GetTargetAbi() - Not implemented") | ||
} | ||
} | ||
|
||
func GetStructAbi(decl *ast.Struct) Abi { | ||
return GetTargetAbi() | ||
} | ||
|
||
func GetFuncAbi(decl *ast.Func) Abi { | ||
return GetTargetAbi() | ||
|
||
/*for _, attribute := range decl.Attributes { | ||
if attribute.Name.String() == "Extern" { | ||
return GetTargetAbi() | ||
} | ||
} | ||
return FB*/ | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,168 @@ | ||
package abi | ||
|
||
import ( | ||
"fireball/core/ast" | ||
) | ||
|
||
var AMD64 Abi = &amd64{} | ||
|
||
type amd64 struct{} | ||
|
||
func (a *amd64) Size(type_ ast.Type) uint32 { | ||
if type_, ok := ast.As[*ast.Struct](type_); ok { | ||
layout := cLayout{} | ||
|
||
for _, field := range type_.Fields { | ||
layout.add(a.Size(field.Type), a.Align(field.Type)) | ||
} | ||
|
||
return layout.size() | ||
} | ||
|
||
return getX64Size(a, type_) | ||
} | ||
|
||
func (a *amd64) Align(type_ ast.Type) uint32 { | ||
return getX64Align(type_) | ||
} | ||
|
||
func (a *amd64) Fields(decl *ast.Struct) ([]*ast.Field, []uint32) { | ||
layout := cLayout{} | ||
offsets := make([]uint32, len(decl.Fields)) | ||
|
||
for i, field := range decl.Fields { | ||
offsets[i] = layout.add(a.Size(field.Type), a.Align(field.Type)) | ||
} | ||
|
||
return decl.Fields, offsets | ||
} | ||
|
||
func (a *amd64) Classify(type_ ast.Type, args []Arg) []Arg { | ||
switch type_ := type_.Resolved().(type) { | ||
case *ast.Primitive: | ||
var arg Arg | ||
|
||
switch type_.Kind { | ||
case ast.Bool: | ||
arg = i1 | ||
|
||
case ast.U8, ast.I8: | ||
arg = i8 | ||
case ast.U16, ast.I16: | ||
arg = i16 | ||
case ast.U32, ast.I32: | ||
arg = i32 | ||
case ast.U64, ast.I64: | ||
arg = i64 | ||
|
||
case ast.F32: | ||
arg = f32 | ||
case ast.F64: | ||
arg = f64 | ||
|
||
default: | ||
return args | ||
} | ||
|
||
return append(args, arg) | ||
|
||
case *ast.Pointer: | ||
return append(args, ptr) | ||
|
||
case *ast.Struct, *ast.Array: | ||
if a.Size(type_) > 64 { | ||
return append(args, memory) | ||
} | ||
|
||
args = a.flatten(type_, getSize(args), args) | ||
size := getSize(args) | ||
|
||
if size > 16 { | ||
args = args[0:0] | ||
return append(args, memory) | ||
} | ||
|
||
for _, arg := range args { | ||
if arg.Class == Memory { | ||
args = args[0:0] | ||
return append(args, memory) | ||
} | ||
} | ||
|
||
return args | ||
|
||
case *ast.Enum: | ||
return a.Classify(type_.ActualType, args) | ||
|
||
case *ast.Interface: | ||
args = append(args, ptr) | ||
return append(args, ptr) | ||
|
||
case *ast.Func: | ||
return append(args, ptr) | ||
|
||
default: | ||
return args | ||
} | ||
} | ||
|
||
func (a *amd64) flatten(type_ ast.Type, baseOffset uint32, args []Arg) []Arg { | ||
switch type_ := type_.Resolved().(type) { | ||
case *ast.Array: | ||
baseSize := a.Size(type_.Base) | ||
baseAlign := a.Align(type_.Base) | ||
|
||
for i := uint32(0); i < type_.Count; i++ { | ||
offset := alignBytes(baseOffset+baseSize*i, baseAlign) | ||
args = a.flatten(type_.Base, offset, args) | ||
} | ||
|
||
return args | ||
|
||
case *ast.Struct: | ||
fields, offsets := a.Fields(type_) | ||
|
||
for i, field := range fields { | ||
offset := baseOffset + offsets[i] | ||
args = a.flatten(field.Type, offset, args) | ||
} | ||
|
||
return args | ||
|
||
case *ast.Interface: | ||
void := ast.Primitive{Kind: ast.Void} | ||
ptr := ast.Pointer{Pointee: &void} | ||
|
||
args = a.flatten(&ptr, baseOffset, args) | ||
return a.flatten(&ptr, baseOffset+8, args) | ||
|
||
default: | ||
typeArgs := a.Classify(type_, nil) | ||
if len(typeArgs) != 1 { | ||
panic("abi.amd64.flatten() - Failed to flatten type") | ||
} | ||
|
||
arg := typeArgs[0] | ||
offset := alignBytes(baseOffset, a.Align(type_)) | ||
|
||
var finalArg *Arg | ||
args = getArg(args, offset, &finalArg) | ||
|
||
if finalArg.Class == None { | ||
*finalArg = arg | ||
} else if finalArg.Class == arg.Class { | ||
finalArg.Bits += arg.Bits | ||
} else if finalArg.Class == Memory || arg.Class == Memory { | ||
finalArg.Class = Memory | ||
finalArg.Bits += arg.Bits | ||
} else if finalArg.Class == Integer || arg.Class == Integer { | ||
finalArg.Class = Integer | ||
finalArg.Bits += arg.Bits | ||
} else { | ||
finalArg.Class = SSE | ||
finalArg.Bits += arg.Bits | ||
} | ||
|
||
return args | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,23 @@ | ||
package abi | ||
|
||
type cLayout struct { | ||
biggestAlign uint32 | ||
offset uint32 | ||
} | ||
|
||
func (l *cLayout) add(size, align uint32) uint32 { | ||
l.biggestAlign = max(l.biggestAlign, align) | ||
|
||
offset := alignBytes(l.offset, align) | ||
l.offset = offset + size | ||
|
||
return offset | ||
} | ||
|
||
func (l *cLayout) size() uint32 { | ||
if l.offset == 0 { | ||
return 0 | ||
} | ||
|
||
return alignBytes(l.offset, l.biggestAlign) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,43 @@ | ||
package abi | ||
|
||
import "fireball/core/ast" | ||
|
||
var FB Abi = &fb{} | ||
|
||
type fb struct{} | ||
|
||
func (f *fb) Size(type_ ast.Type) uint32 { | ||
if type_, ok := ast.As[*ast.Struct](type_); ok { | ||
layout := cLayout{} | ||
|
||
for _, field := range type_.Fields { | ||
layout.add(f.Size(field.Type), f.Align(field.Type)) | ||
} | ||
|
||
return layout.size() | ||
} | ||
|
||
return getX64Size(f, type_) | ||
} | ||
|
||
func (f *fb) Align(type_ ast.Type) uint32 { | ||
return getX64Align(type_) | ||
} | ||
|
||
func (f *fb) Fields(decl *ast.Struct) ([]*ast.Field, []uint32) { | ||
layout := cLayout{} | ||
offsets := make([]uint32, len(decl.Fields)) | ||
|
||
for i, field := range decl.Fields { | ||
offsets[i] = layout.add(f.Size(field.Type), f.Align(field.Type)) | ||
} | ||
|
||
return decl.Fields, offsets | ||
} | ||
|
||
func (f *fb) Classify(type_ ast.Type, args []Arg) []Arg { | ||
switch type_.Resolved().(type) { | ||
default: | ||
panic("abi.amd64.Classify() - Not implemented") | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,44 @@ | ||
package abi | ||
|
||
var i1 = Arg{Class: Integer, Bits: 1} | ||
|
||
var i8 = Arg{Class: Integer, Bits: 8} | ||
var i16 = Arg{Class: Integer, Bits: 16} | ||
var i32 = Arg{Class: Integer, Bits: 32} | ||
var i64 = Arg{Class: Integer, Bits: 64} | ||
|
||
var f32 = Arg{Class: SSE, Bits: 32} | ||
var f64 = Arg{Class: SSE, Bits: 64} | ||
|
||
var ptr = Arg{Class: Integer, Bits: 64} | ||
var memory = Arg{Class: Memory, Bits: 64} | ||
|
||
func alignBytes(bytes, align uint32) uint32 { | ||
if bytes%align != 0 { | ||
bytes += align - (bytes % align) | ||
} | ||
|
||
return bytes | ||
} | ||
|
||
func getSize(args []Arg) uint32 { | ||
length := uint32(len(args)) | ||
|
||
if length == 0 { | ||
return 0 | ||
} | ||
|
||
return (length-1)*8 + args[length-1].Bytes() | ||
} | ||
|
||
func getArg(args []Arg, offset uint32, arg **Arg) []Arg { | ||
i := offset / 8 | ||
|
||
for i >= uint32(len(args)) { | ||
args = append(args, Arg{}) | ||
} | ||
|
||
*arg = &args[i] | ||
|
||
return args | ||
} |
Oops, something went wrong.