package backend
import (
"context"
"fmt"
"github.com/tetratelabs/wazero/internal/engine/wazevo/backend/regalloc"
"github.com/tetratelabs/wazero/internal/engine/wazevo/ssa"
"github.com/tetratelabs/wazero/internal/engine/wazevo/wazevoapi"
)
func NewCompiler (ctx context .Context , mach Machine , builder ssa .Builder ) Compiler {
return newCompiler (ctx , mach , builder )
}
func newCompiler(_ context .Context , mach Machine , builder ssa .Builder ) *compiler {
argResultInts , argResultFloats := mach .ArgsResultsRegs ()
c := &compiler {
mach : mach , ssaBuilder : builder ,
nextVRegID : regalloc .VRegIDNonReservedBegin ,
argResultInts : argResultInts ,
argResultFloats : argResultFloats ,
}
mach .SetCompiler (c )
return c
}
type Compiler interface {
SSABuilder () ssa .Builder
Compile (ctx context .Context ) (_ []byte , _ []RelocationInfo , _ error )
Lower ()
RegAlloc ()
Finalize (ctx context .Context ) error
Buf () []byte
BufPtr () *[]byte
Format () string
Init ()
AllocateVReg (typ ssa .Type ) regalloc .VReg
ValueDefinition (ssa .Value ) SSAValueDefinition
VRegOf (value ssa .Value ) regalloc .VReg
TypeOf (regalloc .VReg ) ssa .Type
MatchInstr (def SSAValueDefinition , opcode ssa .Opcode ) bool
MatchInstrOneOf (def SSAValueDefinition , opcodes []ssa .Opcode ) ssa .Opcode
AddRelocationInfo (funcRef ssa .FuncRef )
AddSourceOffsetInfo (executableOffset int64 , sourceOffset ssa .SourceOffset )
SourceOffsetInfo () []SourceOffsetInfo
EmitByte (b byte )
Emit4Bytes (b uint32 )
Emit8Bytes (b uint64 )
GetFunctionABI (sig *ssa .Signature ) *FunctionABI
}
type RelocationInfo struct {
Offset int64
FuncRef ssa .FuncRef
}
type compiler struct {
mach Machine
currentGID ssa .InstructionGroupID
ssaBuilder ssa .Builder
nextVRegID regalloc .VRegID
ssaValueToVRegs [] regalloc .VReg
ssaValuesInfo []ssa .ValueInfo
returnVRegs []regalloc .VReg
varEdges [][2 ]regalloc .VReg
varEdgeTypes []ssa .Type
constEdges []struct {
cInst *ssa .Instruction
dst regalloc .VReg
}
vRegSet []bool
vRegIDs []regalloc .VRegID
tempRegs []regalloc .VReg
tmpVals []ssa .Value
ssaTypeOfVRegID [] ssa .Type
buf []byte
relocations []RelocationInfo
sourceOffsets []SourceOffsetInfo
abis []FunctionABI
argResultInts, argResultFloats []regalloc .RealReg
}
type SourceOffsetInfo struct {
SourceOffset ssa .SourceOffset
ExecutableOffset int64
}
func (c *compiler ) Compile (ctx context .Context ) ([]byte , []RelocationInfo , error ) {
c .Lower ()
if wazevoapi .PrintSSAToBackendIRLowering && wazevoapi .PrintEnabledIndex (ctx ) {
fmt .Printf ("[[[after lowering for %s ]]]%s\n" , wazevoapi .GetCurrentFunctionName (ctx ), c .Format ())
}
if wazevoapi .DeterministicCompilationVerifierEnabled {
wazevoapi .VerifyOrSetDeterministicCompilationContextValue (ctx , "After lowering to ISA specific IR" , c .Format ())
}
c .RegAlloc ()
if wazevoapi .PrintRegisterAllocated && wazevoapi .PrintEnabledIndex (ctx ) {
fmt .Printf ("[[[after regalloc for %s]]]%s\n" , wazevoapi .GetCurrentFunctionName (ctx ), c .Format ())
}
if wazevoapi .DeterministicCompilationVerifierEnabled {
wazevoapi .VerifyOrSetDeterministicCompilationContextValue (ctx , "After Register Allocation" , c .Format ())
}
if err := c .Finalize (ctx ); err != nil {
return nil , nil , err
}
if wazevoapi .PrintFinalizedMachineCode && wazevoapi .PrintEnabledIndex (ctx ) {
fmt .Printf ("[[[after finalize for %s]]]%s\n" , wazevoapi .GetCurrentFunctionName (ctx ), c .Format ())
}
if wazevoapi .DeterministicCompilationVerifierEnabled {
wazevoapi .VerifyOrSetDeterministicCompilationContextValue (ctx , "After Finalization" , c .Format ())
}
return c .buf , c .relocations , nil
}
func (c *compiler ) RegAlloc () {
c .mach .RegAlloc ()
}
func (c *compiler ) Finalize (ctx context .Context ) error {
c .mach .PostRegAlloc ()
return c .mach .Encode (ctx )
}
func (c *compiler ) setCurrentGroupID (gid ssa .InstructionGroupID ) {
c .currentGID = gid
}
func (c *compiler ) assignVirtualRegisters () {
builder := c .ssaBuilder
c .ssaValuesInfo = builder .ValuesInfo ()
if diff := len (c .ssaValuesInfo ) - len (c .ssaValueToVRegs ); diff > 0 {
c .ssaValueToVRegs = append (c .ssaValueToVRegs , make ([]regalloc .VReg , diff +1 )...)
}
for blk := builder .BlockIteratorReversePostOrderBegin (); blk != nil ; blk = builder .BlockIteratorReversePostOrderNext () {
for i := 0 ; i < blk .Params (); i ++ {
p := blk .Param (i )
pid := p .ID ()
typ := p .Type ()
vreg := c .AllocateVReg (typ )
c .ssaValueToVRegs [pid ] = vreg
c .ssaTypeOfVRegID [vreg .ID ()] = p .Type ()
}
for cur := blk .Root (); cur != nil ; cur = cur .Next () {
r , rs := cur .Returns ()
if r .Valid () {
id := r .ID ()
ssaTyp := r .Type ()
typ := r .Type ()
vReg := c .AllocateVReg (typ )
c .ssaValueToVRegs [id ] = vReg
c .ssaTypeOfVRegID [vReg .ID ()] = ssaTyp
}
for _ , r := range rs {
id := r .ID ()
ssaTyp := r .Type ()
vReg := c .AllocateVReg (ssaTyp )
c .ssaValueToVRegs [id ] = vReg
c .ssaTypeOfVRegID [vReg .ID ()] = ssaTyp
}
}
}
for i , retBlk := 0 , builder .ReturnBlock (); i < retBlk .Params (); i ++ {
typ := retBlk .Param (i ).Type ()
vReg := c .AllocateVReg (typ )
c .returnVRegs = append (c .returnVRegs , vReg )
c .ssaTypeOfVRegID [vReg .ID ()] = typ
}
}
func (c *compiler ) AllocateVReg (typ ssa .Type ) regalloc .VReg {
regType := regalloc .RegTypeOf (typ )
r := regalloc .VReg (c .nextVRegID ).SetRegType (regType )
id := r .ID ()
if int (id ) >= len (c .ssaTypeOfVRegID ) {
c .ssaTypeOfVRegID = append (c .ssaTypeOfVRegID , make ([]ssa .Type , id +1 )...)
}
c .ssaTypeOfVRegID [id ] = typ
c .nextVRegID ++
return r
}
func (c *compiler ) Init () {
c .currentGID = 0
c .nextVRegID = regalloc .VRegIDNonReservedBegin
c .returnVRegs = c .returnVRegs [:0 ]
c .mach .Reset ()
c .varEdges = c .varEdges [:0 ]
c .constEdges = c .constEdges [:0 ]
c .buf = c .buf [:0 ]
c .sourceOffsets = c .sourceOffsets [:0 ]
c .relocations = c .relocations [:0 ]
}
func (c *compiler ) ValueDefinition (value ssa .Value ) SSAValueDefinition {
return SSAValueDefinition {
V : value ,
Instr : c .ssaBuilder .InstructionOfValue (value ),
RefCount : c .ssaValuesInfo [value .ID ()].RefCount ,
}
}
func (c *compiler ) VRegOf (value ssa .Value ) regalloc .VReg {
return c .ssaValueToVRegs [value .ID ()]
}
func (c *compiler ) Format () string {
return c .mach .Format ()
}
func (c *compiler ) TypeOf (v regalloc .VReg ) ssa .Type {
return c .ssaTypeOfVRegID [v .ID ()]
}
func (c *compiler ) MatchInstr (def SSAValueDefinition , opcode ssa .Opcode ) bool {
instr := def .Instr
return def .IsFromInstr () &&
instr .Opcode () == opcode &&
instr .GroupID () == c .currentGID &&
def .RefCount < 2
}
func (c *compiler ) MatchInstrOneOf (def SSAValueDefinition , opcodes []ssa .Opcode ) ssa .Opcode {
instr := def .Instr
if !def .IsFromInstr () {
return ssa .OpcodeInvalid
}
if instr .GroupID () != c .currentGID {
return ssa .OpcodeInvalid
}
if def .RefCount >= 2 {
return ssa .OpcodeInvalid
}
opcode := instr .Opcode ()
for _ , op := range opcodes {
if opcode == op {
return opcode
}
}
return ssa .OpcodeInvalid
}
func (c *compiler ) SSABuilder () ssa .Builder {
return c .ssaBuilder
}
func (c *compiler ) AddSourceOffsetInfo (executableOffset int64 , sourceOffset ssa .SourceOffset ) {
c .sourceOffsets = append (c .sourceOffsets , SourceOffsetInfo {
SourceOffset : sourceOffset ,
ExecutableOffset : executableOffset ,
})
}
func (c *compiler ) SourceOffsetInfo () []SourceOffsetInfo {
return c .sourceOffsets
}
func (c *compiler ) AddRelocationInfo (funcRef ssa .FuncRef ) {
c .relocations = append (c .relocations , RelocationInfo {
Offset : int64 (len (c .buf )),
FuncRef : funcRef ,
})
}
func (c *compiler ) Emit8Bytes (b uint64 ) {
c .buf = append (c .buf , byte (b ), byte (b >>8 ), byte (b >>16 ), byte (b >>24 ), byte (b >>32 ), byte (b >>40 ), byte (b >>48 ), byte (b >>56 ))
}
func (c *compiler ) Emit4Bytes (b uint32 ) {
c .buf = append (c .buf , byte (b ), byte (b >>8 ), byte (b >>16 ), byte (b >>24 ))
}
func (c *compiler ) EmitByte (b byte ) {
c .buf = append (c .buf , b )
}
func (c *compiler ) Buf () []byte {
return c .buf
}
func (c *compiler ) BufPtr () *[]byte {
return &c .buf
}
func (c *compiler ) GetFunctionABI (sig *ssa .Signature ) *FunctionABI {
if int (sig .ID ) >= len (c .abis ) {
c .abis = append (c .abis , make ([]FunctionABI , int (sig .ID )+1 )...)
}
abi := &c .abis [sig .ID ]
if abi .Initialized {
return abi
}
abi .Init (sig , c .argResultInts , c .argResultFloats )
return abi
}
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 .