package backend
import (
"fmt"
"github.com/tetratelabs/wazero/internal/engine/wazevo/backend/regalloc"
"github.com/tetratelabs/wazero/internal/engine/wazevo/ssa"
)
type (
FunctionABI struct {
Initialized bool
Args, Rets []ABIArg
ArgStackSize, RetStackSize int64
ArgIntRealRegs byte
ArgFloatRealRegs byte
RetIntRealRegs byte
RetFloatRealRegs byte
}
ABIArg struct {
Index int
Kind ABIArgKind
Reg regalloc .VReg
Offset int64
Type ssa .Type
}
ABIArgKind byte
)
const (
ABIArgKindReg = iota
ABIArgKindStack
)
func (a *ABIArg ) String () string {
return fmt .Sprintf ("args[%d]: %s" , a .Index , a .Kind )
}
func (a ABIArgKind ) String () string {
switch a {
case ABIArgKindReg :
return "reg"
case ABIArgKindStack :
return "stack"
default :
panic ("BUG" )
}
}
func (a *FunctionABI ) Init (sig *ssa .Signature , argResultInts , argResultFloats []regalloc .RealReg ) {
if len (a .Rets ) < len (sig .Results ) {
a .Rets = make ([]ABIArg , len (sig .Results ))
}
a .Rets = a .Rets [:len (sig .Results )]
a .RetStackSize = a .setABIArgs (a .Rets , sig .Results , argResultInts , argResultFloats )
if argsNum := len (sig .Params ); len (a .Args ) < argsNum {
a .Args = make ([]ABIArg , argsNum )
}
a .Args = a .Args [:len (sig .Params )]
a .ArgStackSize = a .setABIArgs (a .Args , sig .Params , argResultInts , argResultFloats )
a .ArgIntRealRegs , a .ArgFloatRealRegs = 0 , 0
a .RetIntRealRegs , a .RetFloatRealRegs = 0 , 0
for i := range a .Rets {
r := &a .Rets [i ]
if r .Kind == ABIArgKindReg {
if r .Type .IsInt () {
a .RetIntRealRegs ++
} else {
a .RetFloatRealRegs ++
}
}
}
for i := range a .Args {
arg := &a .Args [i ]
if arg .Kind == ABIArgKindReg {
if arg .Type .IsInt () {
a .ArgIntRealRegs ++
} else {
a .ArgFloatRealRegs ++
}
}
}
a .Initialized = true
}
func (a *FunctionABI ) setABIArgs (s []ABIArg , types []ssa .Type , ints , floats []regalloc .RealReg ) (stackSize int64 ) {
il , fl := len (ints ), len (floats )
var stackOffset int64
intParamIndex , floatParamIndex := 0 , 0
for i , typ := range types {
arg := &s [i ]
arg .Index = i
arg .Type = typ
if typ .IsInt () {
if intParamIndex >= il {
arg .Kind = ABIArgKindStack
const slotSize = 8
arg .Offset = stackOffset
stackOffset += slotSize
} else {
arg .Kind = ABIArgKindReg
arg .Reg = regalloc .FromRealReg (ints [intParamIndex ], regalloc .RegTypeInt )
intParamIndex ++
}
} else {
if floatParamIndex >= fl {
arg .Kind = ABIArgKindStack
slotSize := int64 (8 )
if typ .Bits () == 128 {
slotSize = 16
}
arg .Offset = stackOffset
stackOffset += slotSize
} else {
arg .Kind = ABIArgKindReg
arg .Reg = regalloc .FromRealReg (floats [floatParamIndex ], regalloc .RegTypeFloat )
floatParamIndex ++
}
}
}
return stackOffset
}
func (a *FunctionABI ) AlignedArgResultStackSlotSize () uint32 {
stackSlotSize := a .RetStackSize + a .ArgStackSize
stackSlotSize = (stackSlotSize + 15 ) &^ 15
if stackSlotSize > 0xFFFFFFFF {
panic ("ABI stack slot size overflow" )
}
return uint32 (stackSlotSize )
}
func (a *FunctionABI ) ABIInfoAsUint64 () uint64 {
return uint64 (a .ArgIntRealRegs )<<56 |
uint64 (a .ArgFloatRealRegs )<<48 |
uint64 (a .RetIntRealRegs )<<40 |
uint64 (a .RetFloatRealRegs )<<32 |
uint64 (a .AlignedArgResultStackSlotSize ())
}
func ABIInfoFromUint64 (info uint64 ) (argIntRealRegs , argFloatRealRegs , retIntRealRegs , retFloatRealRegs byte , stackSlotSize uint32 ) {
return byte (info >> 56 ), byte (info >> 48 ), byte (info >> 40 ), byte (info >> 32 ), uint32 (info )
}
The pages are generated with Golds v0.8.2 . (GOOS=linux GOARCH=amd64)
Golds is a Go 101 project developed by Tapir Liu .
PR and bug reports are welcome and can be submitted to the issue list .
Please follow @zigo_101 (reachable from the left QR code) to get the latest news of Golds .