wazevo: adds tests for high register pressure (#1686)
Signed-off-by: Takeshi Yoneda <t.y.mathetake@gmail.com>
This commit is contained in:
@@ -1,6 +1,7 @@
|
||||
package backend_test
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/hex"
|
||||
"fmt"
|
||||
"os"
|
||||
@@ -80,10 +81,14 @@ L1 (SSA Block: blk0):
|
||||
name: "consts", m: testcases.Constants.Module,
|
||||
afterLoweringARM64: `
|
||||
L1 (SSA Block: blk0):
|
||||
ldr d1, #8; b 16; data.f64 64.000000
|
||||
ldr s0, #8; b 8; data.f32 32.000000
|
||||
orr x1, xzr, #0x2
|
||||
orr w0, wzr, #0x1
|
||||
ldr d5?, #8; b 16; data.f64 64.000000
|
||||
mov v1.8b, v5?.8b
|
||||
ldr s4?, #8; b 8; data.f32 32.000000
|
||||
mov v0.8b, v4?.8b
|
||||
orr x3?, xzr, #0x2
|
||||
mov x1, x3?
|
||||
orr w2?, wzr, #0x1
|
||||
mov x0, x2?
|
||||
ret
|
||||
`,
|
||||
afterFinalizeARM64: `
|
||||
@@ -169,7 +174,8 @@ L1 (SSA Block: blk0):
|
||||
afterLoweringARM64: `
|
||||
L1 (SSA Block: blk0):
|
||||
mov x2?, x2
|
||||
mov x1, xzr
|
||||
mov x3?, xzr
|
||||
mov x1, x3?
|
||||
mov x0, x2?
|
||||
ret
|
||||
`,
|
||||
@@ -411,10 +417,12 @@ L1 (SSA Block: blk0):
|
||||
cbnz w4?, L2
|
||||
L3 (SSA Block: blk2):
|
||||
L4 (SSA Block: blk3):
|
||||
mov x0, xzr
|
||||
mov x2?, xzr
|
||||
mov x0, x2?
|
||||
ret
|
||||
L2 (SSA Block: blk1):
|
||||
mov x0, xzr
|
||||
mov x3?, xzr
|
||||
mov x0, x3?
|
||||
ret
|
||||
`,
|
||||
afterFinalizeARM64: `
|
||||
@@ -493,7 +501,8 @@ L4 (SSA Block: blk5):
|
||||
L3 (SSA Block: blk4):
|
||||
L5 (SSA Block: blk3):
|
||||
L6 (SSA Block: blk2):
|
||||
mov x0, xzr
|
||||
mov x3?, xzr
|
||||
mov x0, x3?
|
||||
ret
|
||||
`,
|
||||
afterFinalizeARM64: `
|
||||
@@ -2974,27 +2983,33 @@ L2 (SSA Block: blk7):
|
||||
b L9
|
||||
L3 (SSA Block: blk8):
|
||||
L10 (SSA Block: blk5):
|
||||
orr w0, wzr, #0xc
|
||||
orr w3?, wzr, #0xc
|
||||
mov x0, x3?
|
||||
ret
|
||||
L4 (SSA Block: blk9):
|
||||
L11 (SSA Block: blk4):
|
||||
movz w0, #0xd, lsl 0
|
||||
movz w4?, #0xd, lsl 0
|
||||
mov x0, x4?
|
||||
ret
|
||||
L5 (SSA Block: blk10):
|
||||
L12 (SSA Block: blk3):
|
||||
orr w0, wzr, #0xe
|
||||
orr w5?, wzr, #0xe
|
||||
mov x0, x5?
|
||||
ret
|
||||
L6 (SSA Block: blk11):
|
||||
L13 (SSA Block: blk2):
|
||||
orr w0, wzr, #0xf
|
||||
orr w6?, wzr, #0xf
|
||||
mov x0, x6?
|
||||
ret
|
||||
L7 (SSA Block: blk12):
|
||||
L14 (SSA Block: blk1):
|
||||
orr w0, wzr, #0x10
|
||||
orr w7?, wzr, #0x10
|
||||
mov x0, x7?
|
||||
ret
|
||||
L8 (SSA Block: blk13):
|
||||
L9 (SSA Block: blk6):
|
||||
movz w0, #0xb, lsl 0
|
||||
movz w8?, #0xb, lsl 0
|
||||
mov x0, x8?
|
||||
ret
|
||||
`,
|
||||
afterFinalizeARM64: `
|
||||
@@ -3045,7 +3060,7 @@ L9 (SSA Block: blk6):
|
||||
fc := frontend.NewFrontendCompiler(tc.m, ssab, &offset)
|
||||
machine := newMachine()
|
||||
machine.DisableStackCheck()
|
||||
be := backend.NewCompiler(machine, ssab)
|
||||
be := backend.NewCompiler(context.Background(), machine, ssab)
|
||||
|
||||
// Lowers the Wasm to SSA.
|
||||
typeIndex := tc.m.FunctionSection[tc.targetIndex]
|
||||
|
||||
@@ -11,18 +11,23 @@ import (
|
||||
)
|
||||
|
||||
// NewCompiler returns a new Compiler that can generate a machine code.
|
||||
func NewCompiler(mach Machine, builder ssa.Builder) Compiler {
|
||||
return newCompiler(mach, builder)
|
||||
func NewCompiler(ctx context.Context, mach Machine, builder ssa.Builder) Compiler {
|
||||
return newCompiler(ctx, mach, builder)
|
||||
}
|
||||
|
||||
func newCompiler(mach Machine, builder ssa.Builder) *compiler {
|
||||
func newCompiler(ctx context.Context, mach Machine, builder ssa.Builder) *compiler {
|
||||
registerSetDebug := false
|
||||
if wazevoapi.RegAllocValidationEnabled {
|
||||
registerSetDebug = wazevoapi.IsHighRegisterPressure(ctx)
|
||||
}
|
||||
|
||||
c := &compiler{
|
||||
mach: mach, ssaBuilder: builder,
|
||||
alreadyLowered: make(map[*ssa.Instruction]bool),
|
||||
vRegSet: make(map[regalloc.VReg]bool),
|
||||
ssaTypeOfVRegID: make(map[regalloc.VRegID]ssa.Type),
|
||||
nextVRegID: 0,
|
||||
regAlloc: regalloc.NewAllocator(mach.RegisterInfo()),
|
||||
regAlloc: regalloc.NewAllocator(mach.RegisterInfo(registerSetDebug)),
|
||||
}
|
||||
mach.SetCompiler(c)
|
||||
return c
|
||||
@@ -147,21 +152,21 @@ type compiler struct {
|
||||
func (c *compiler) Compile(ctx context.Context) ([]byte, []RelocationInfo, int, error) {
|
||||
c.Lower()
|
||||
if wazevoapi.PrintSSAToBackendIRLowering {
|
||||
fmt.Printf("[[[after lowering]]]%s\n", c.Format())
|
||||
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 {
|
||||
fmt.Printf("[[[after regalloc]]]%s\n", c.Format())
|
||||
fmt.Printf("[[[after regalloc for %s]]]%s\n", wazevoapi.GetCurrentFunctionName(ctx), c.Format())
|
||||
}
|
||||
if wazevoapi.DeterministicCompilationVerifierEnabled {
|
||||
wazevoapi.VerifyOrSetDeterministicCompilationContextValue(ctx, "After Register Allocation", c.Format())
|
||||
}
|
||||
c.Finalize()
|
||||
if wazevoapi.PrintFinalizedMachineCode {
|
||||
fmt.Printf("[[[after finalize]]]%s\n", c.Format())
|
||||
fmt.Printf("[[[after finalize for %s]]]%s\n", wazevoapi.GetCurrentFunctionName(ctx), c.Format())
|
||||
}
|
||||
if wazevoapi.DeterministicCompilationVerifierEnabled {
|
||||
wazevoapi.VerifyOrSetDeterministicCompilationContextValue(ctx, "After Finalization", c.Format())
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package backend
|
||||
|
||||
import (
|
||||
"context"
|
||||
"testing"
|
||||
|
||||
"github.com/tetratelabs/wazero/internal/engine/wazevo/backend/regalloc"
|
||||
@@ -51,7 +52,7 @@ func TestCompiler_lowerBlockArguments(t *testing.T) {
|
||||
},
|
||||
}
|
||||
|
||||
c := newCompiler(m, builder)
|
||||
c := newCompiler(context.Background(), m, builder)
|
||||
c.ssaValueDefinitions = []SSAValueDefinition{{Instr: i1}, {Instr: i2}, {Instr: f1}, {Instr: f2}}
|
||||
c.ssaValueToVRegs = []regalloc.VReg{0, 1, 2, 3, 4, 5, 6, 7}
|
||||
return c, []ssa.Value{i1.Return(), i2.Return(), f1.Return(), f2.Return()}, succ, func(t *testing.T) {
|
||||
@@ -79,7 +80,7 @@ func TestCompiler_lowerBlockArguments(t *testing.T) {
|
||||
m := &mockMachine{insertMove: func(dst, src regalloc.VReg) {
|
||||
insertMoves = append(insertMoves, struct{ src, dst regalloc.VReg }{src: src, dst: dst})
|
||||
}}
|
||||
c := newCompiler(m, builder)
|
||||
c := newCompiler(context.Background(), m, builder)
|
||||
c.ssaValueDefinitions = []SSAValueDefinition{{}, {}, {}, {}}
|
||||
c.ssaValueToVRegs = []regalloc.VReg{0, 1, 2, 3}
|
||||
c.nextVRegID = 100 // Temporary reg should start with 100.
|
||||
@@ -117,7 +118,7 @@ func TestCompiler_lowerBlockArguments(t *testing.T) {
|
||||
m := &mockMachine{insertMove: func(dst, src regalloc.VReg) {
|
||||
insertMoves = append(insertMoves, struct{ src, dst regalloc.VReg }{src: src, dst: dst})
|
||||
}}
|
||||
c := newCompiler(m, builder)
|
||||
c := newCompiler(context.Background(), m, builder)
|
||||
c.ssaValueDefinitions = []SSAValueDefinition{{}, {}}
|
||||
c.ssaValueToVRegs = []regalloc.VReg{0, 1}
|
||||
return c, []ssa.Value{add.Return()}, blk, func(t *testing.T) {
|
||||
|
||||
@@ -210,8 +210,7 @@ func (a *abiImpl) CalleeGenVRegsToFunctionReturns(rets []ssa.Value) {
|
||||
if def := a.m.compiler.ValueDefinition(ret); def.IsFromInstr() {
|
||||
// Constant instructions are inlined.
|
||||
if inst := def.Instr; inst.Constant() {
|
||||
a.m.InsertLoadConstant(inst, r.Reg)
|
||||
continue
|
||||
a.m.InsertLoadConstant(inst, reg)
|
||||
}
|
||||
}
|
||||
if r.Kind == backend.ABIArgKindReg {
|
||||
|
||||
@@ -1761,11 +1761,17 @@ func (i *instruction) size() int64 {
|
||||
case nop0:
|
||||
return 0
|
||||
case loadFpuConst32:
|
||||
if i.u1 == 0 {
|
||||
return 4 // zero loading can be encoded as a single instruction.
|
||||
}
|
||||
return 4 + 4 + 4
|
||||
case loadFpuConst64:
|
||||
if i.u1 == 0 {
|
||||
return 4 // zero loading can be encoded as a single instruction.
|
||||
}
|
||||
return 4 + 4 + 8
|
||||
case loadFpuConst128:
|
||||
return 4 + 4 + 12
|
||||
panic("TODO")
|
||||
case brTableSequence:
|
||||
return 4*4 + int64(len(i.targets))*4
|
||||
default:
|
||||
|
||||
@@ -106,9 +106,19 @@ func (i *instruction) encode(c backend.Compiler) {
|
||||
}
|
||||
c.Emit4Bytes(encodePreOrPostIndexLoadStorePair64(pre, kind == loadP64, rn, rt, rt2, amode.imm))
|
||||
case loadFpuConst32:
|
||||
encodeLoadFpuConst32(c, regNumberInEncoding[i.rd.realReg()], i.u1)
|
||||
rd := regNumberInEncoding[i.rd.realReg()]
|
||||
if i.u1 == 0 {
|
||||
c.Emit4Bytes(encodeVecRRR(vecOpEOR, rd, rd, rd, vecArrangement8B))
|
||||
} else {
|
||||
encodeLoadFpuConst32(c, rd, i.u1)
|
||||
}
|
||||
case loadFpuConst64:
|
||||
encodeLoadFpuConst64(c, regNumberInEncoding[i.rd.realReg()], i.u1)
|
||||
rd := regNumberInEncoding[i.rd.realReg()]
|
||||
if i.u1 == 0 {
|
||||
c.Emit4Bytes(encodeVecRRR(vecOpEOR, rd, rd, rd, vecArrangement8B))
|
||||
} else {
|
||||
encodeLoadFpuConst64(c, regNumberInEncoding[i.rd.realReg()], i.u1)
|
||||
}
|
||||
case aluRRRR:
|
||||
c.Emit4Bytes(encodeAluRRRR(
|
||||
aluOp(i.u1),
|
||||
@@ -591,7 +601,7 @@ func encodeLoadFpuConst32(c backend.Compiler, rd uint32, rawF32 uint64) {
|
||||
|
||||
// encodeLoadFpuConst64 encodes the following three instructions:
|
||||
//
|
||||
// ldr x8, #8 ;; literal load of data.f64
|
||||
// ldr d8, #8 ;; literal load of data.f64
|
||||
// b 12 ;; skip the data
|
||||
// data.f64 xxxxxxx
|
||||
func encodeLoadFpuConst64(c backend.Compiler, rd uint32, rawF64 uint64) {
|
||||
|
||||
@@ -178,9 +178,11 @@ func TestInstruction_encode(t *testing.T) {
|
||||
}},
|
||||
{want: "30000010", setup: func(i *instruction) { i.asAdr(v16VReg, 4) }},
|
||||
{want: "50050030", setup: func(i *instruction) { i.asAdr(v16VReg, 169) }},
|
||||
{want: "101e302e", setup: func(i *instruction) { i.asLoadFpuConst32(v16VReg, uint64(math.Float32bits(0))) }},
|
||||
{want: "5000001c020000140000803f", setup: func(i *instruction) {
|
||||
i.asLoadFpuConst32(v16VReg, uint64(math.Float32bits(1.0)))
|
||||
}},
|
||||
{want: "101e302e", setup: func(i *instruction) { i.asLoadFpuConst64(v16VReg, uint64(math.Float32bits(0))) }},
|
||||
{want: "5000005c03000014000000000000f03f", setup: func(i *instruction) {
|
||||
i.asLoadFpuConst64(v16VReg, math.Float64bits(1.0))
|
||||
}},
|
||||
|
||||
@@ -28,21 +28,11 @@ func (m *machine) InsertLoadConstant(instr *ssa.Instruction, vr regalloc.VReg) {
|
||||
switch valType {
|
||||
case ssa.TypeF32:
|
||||
loadF := m.allocateInstr()
|
||||
if v == 0 {
|
||||
// Fast path for zero. Use v30VReg (least likely to be allocated real register) so that we don't put pressure on the register allocator.
|
||||
loadF.asVecRRR(vecOpEOR, operandNR(vr), operandNR(v30VReg), operandNR(v30VReg), vecArrangement8B)
|
||||
} else {
|
||||
loadF.asLoadFpuConst32(vr, v)
|
||||
}
|
||||
loadF.asLoadFpuConst32(vr, v)
|
||||
m.insert(loadF)
|
||||
case ssa.TypeF64:
|
||||
loadF := m.allocateInstr()
|
||||
if v == 0 {
|
||||
// Fast path for zero. Use v30VReg (least likely to be allocated real register) so that we don't put pressure on the register allocator.
|
||||
loadF.asVecRRR(vecOpEOR, operandNR(vr), operandNR(v30VReg), operandNR(v30VReg), vecArrangement8B)
|
||||
} else {
|
||||
loadF.asLoadFpuConst64(vr, v)
|
||||
}
|
||||
loadF.asLoadFpuConst64(vr, v)
|
||||
m.insert(loadF)
|
||||
case ssa.TypeI32:
|
||||
if v == 0 {
|
||||
|
||||
@@ -220,7 +220,20 @@ func (r *regAllocInstrImpl) IsCopy() bool {
|
||||
}
|
||||
|
||||
// RegisterInfo implements backend.Machine.
|
||||
func (m *machine) RegisterInfo() *regalloc.RegisterInfo {
|
||||
func (m *machine) RegisterInfo(debug bool) *regalloc.RegisterInfo {
|
||||
if debug {
|
||||
regInfoDebug := ®alloc.RegisterInfo{}
|
||||
regInfoDebug.CalleeSavedRegisters = regInfo.CalleeSavedRegisters
|
||||
regInfoDebug.CallerSavedRegisters = regInfo.CallerSavedRegisters
|
||||
regInfoDebug.RealRegToVReg = regInfo.RealRegToVReg
|
||||
regInfoDebug.RealRegName = regInfo.RealRegName
|
||||
regInfoDebug.AllocatableRegisters[regalloc.RegTypeFloat] = []regalloc.RealReg{
|
||||
v7, v6, v5, v4, v3, v2, v1, v0, // Allocatable sets == Argument registers.
|
||||
}
|
||||
// TODO: tests for high pressured int registers.
|
||||
regInfoDebug.AllocatableRegisters[regalloc.RegTypeInt] = regInfo.AllocatableRegisters[regalloc.RegTypeInt]
|
||||
return regInfoDebug
|
||||
}
|
||||
return regInfo
|
||||
}
|
||||
|
||||
|
||||
@@ -25,7 +25,7 @@ func formatEmittedInstructionsInCurrentBlock(m *machine) string {
|
||||
func newSetup() (ssa.Builder, *machine) {
|
||||
m := NewBackend().(*machine)
|
||||
ssaB := ssa.NewBuilder()
|
||||
backend.NewCompiler(m, ssaB)
|
||||
backend.NewCompiler(context.Background(), m, ssaB)
|
||||
blk := ssaB.AllocateBasicBlock()
|
||||
ssaB.SetCurrentBlock(blk)
|
||||
return ssaB, m
|
||||
|
||||
@@ -14,7 +14,9 @@ type (
|
||||
|
||||
// RegisterInfo returns the set of registers that can be used for register allocation.
|
||||
// This is only called once, and the result is shared across all compilations.
|
||||
RegisterInfo() *regalloc.RegisterInfo
|
||||
//
|
||||
// If debug is true, this returns the register set for debugging purpose.
|
||||
RegisterInfo(debug bool) *regalloc.RegisterInfo
|
||||
|
||||
// InitializeABI initializes the FunctionABI for the given signature.
|
||||
InitializeABI(sig *ssa.Signature)
|
||||
|
||||
@@ -52,7 +52,7 @@ func (m mockMachine) ResolveRelativeAddresses() {}
|
||||
func (m mockMachine) Function() (f regalloc.Function) { return }
|
||||
|
||||
// RegisterInfo implements Machine.RegisterInfo.
|
||||
func (m mockMachine) RegisterInfo() *regalloc.RegisterInfo {
|
||||
func (m mockMachine) RegisterInfo(bool) *regalloc.RegisterInfo {
|
||||
if m.rinfo != nil {
|
||||
return m.rinfo
|
||||
}
|
||||
|
||||
@@ -55,8 +55,10 @@ type (
|
||||
// Allocator is a register allocator.
|
||||
Allocator struct {
|
||||
// regInfo is static per ABI/ISA, and is initialized by the machine during Machine.PrepareRegisterAllocator.
|
||||
regInfo *RegisterInfo
|
||||
allocatableSet map[RealReg]struct{}
|
||||
regInfo *RegisterInfo
|
||||
// allocatableSet is a set of allocatable RealReg derived from regInfo. Static per ABI/ISA.
|
||||
allocatableSet map[RealReg]struct{}
|
||||
// allocatedRegSet is a set of RealReg that are allocated during the allocation phase. This is reset per function.
|
||||
allocatedRegSet map[RealReg]struct{}
|
||||
allocatedCalleeSavedRegs []VReg
|
||||
nodePool wazevoapi.Pool[node]
|
||||
@@ -473,13 +475,6 @@ func (a *Allocator) Reset() {
|
||||
a.vRegIDToNode[i] = nil
|
||||
}
|
||||
rr := a.realRegs[:0]
|
||||
for r := range a.allocatableSet {
|
||||
rr = append(rr, r)
|
||||
}
|
||||
for _, r := range rr {
|
||||
delete(a.allocatableSet, r)
|
||||
}
|
||||
rr = rr[:0]
|
||||
for r := range a.allocatedRegSet {
|
||||
rr = append(rr, r)
|
||||
}
|
||||
|
||||
@@ -12,6 +12,7 @@ import (
|
||||
"github.com/tetratelabs/wazero/api"
|
||||
"github.com/tetratelabs/wazero/internal/engine/wazevo"
|
||||
"github.com/tetratelabs/wazero/internal/engine/wazevo/testcases"
|
||||
"github.com/tetratelabs/wazero/internal/engine/wazevo/wazevoapi"
|
||||
"github.com/tetratelabs/wazero/internal/filecache"
|
||||
"github.com/tetratelabs/wazero/internal/integration_test/spectest"
|
||||
v1 "github.com/tetratelabs/wazero/internal/integration_test/spectest/v1"
|
||||
@@ -108,8 +109,15 @@ func TestSpectestV1(t *testing.T) {
|
||||
{name: "unwind"},
|
||||
} {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
spectest.RunCase(t, v1.Testcases, tc.name, context.Background(), config,
|
||||
-1, 0, math.MaxInt)
|
||||
t.Run("normal", func(t *testing.T) {
|
||||
spectest.RunCase(t, v1.Testcases, tc.name, context.Background(), config,
|
||||
-1, 0, math.MaxInt)
|
||||
})
|
||||
t.Run("reg high pressure", func(t *testing.T) {
|
||||
ctx := wazevoapi.EnableHighRegisterPressure(context.Background())
|
||||
spectest.RunCase(t, v1.Testcases, tc.name, ctx, config,
|
||||
-1, 0, math.MaxInt)
|
||||
})
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -65,9 +65,9 @@ func (c compiledFunctionOffset) nativeBegin() int {
|
||||
var _ wasm.Engine = (*engine)(nil)
|
||||
|
||||
// NewEngine returns the implementation of wasm.Engine.
|
||||
func NewEngine(_ context.Context, _ api.CoreFeatures, _ filecache.Cache) wasm.Engine {
|
||||
func NewEngine(ctx context.Context, _ api.CoreFeatures, _ filecache.Cache) wasm.Engine {
|
||||
e := &engine{compiledModules: make(map[wasm.ModuleID]*compiledModule), refToBinaryOffset: make(map[ssa.FuncRef]int)}
|
||||
e.compileBuiltinFunctions()
|
||||
e.compileBuiltinFunctions(ctx)
|
||||
return e
|
||||
}
|
||||
|
||||
@@ -98,7 +98,7 @@ func (e *engine) compileModule(ctx context.Context, module *wasm.Module, listene
|
||||
cm := &compiledModule{offsets: wazevoapi.NewModuleContextOffsetData(module)}
|
||||
|
||||
if module.IsHostModule {
|
||||
return e.compileHostModule(module)
|
||||
return e.compileHostModule(ctx, module)
|
||||
}
|
||||
|
||||
importedFns, localFns := int(module.ImportFunctionCount), len(module.FunctionSection)
|
||||
@@ -124,7 +124,7 @@ func (e *engine) compileModule(ctx context.Context, module *wasm.Module, listene
|
||||
ssaBuilder := ssa.NewBuilder()
|
||||
fe := frontend.NewFrontendCompiler(module, ssaBuilder, &cm.offsets)
|
||||
machine := newMachine()
|
||||
be := backend.NewCompiler(machine, ssaBuilder)
|
||||
be := backend.NewCompiler(ctx, machine, ssaBuilder)
|
||||
|
||||
totalSize := 0 // Total binary size of the executable.
|
||||
cm.functionOffsets = make([]compiledFunctionOffset, localFns)
|
||||
@@ -136,6 +136,15 @@ func (e *engine) compileModule(ctx context.Context, module *wasm.Module, listene
|
||||
|
||||
fidx := wasm.Index(i + importedFns)
|
||||
|
||||
if wazevoapi.NeedFunctionNameInContext {
|
||||
def := module.FunctionDefinition(fidx)
|
||||
name := def.DebugName()
|
||||
if len(def.ExportNames()) > 0 {
|
||||
name = def.ExportNames()[0]
|
||||
}
|
||||
ctx = wazevoapi.SetCurrentFunctionName(ctx, fmt.Sprintf("[%d/%d] \"%s\"", i, len(module.CodeSection)-1, name))
|
||||
}
|
||||
|
||||
_, needGoEntryPreamble := exportedFnIndex[fidx]
|
||||
if sf := module.StartSection; sf != nil && *sf == fidx {
|
||||
needGoEntryPreamble = true
|
||||
@@ -169,8 +178,7 @@ func (e *engine) compileModule(ctx context.Context, module *wasm.Module, listene
|
||||
bodies[i] = body
|
||||
totalSize += len(body)
|
||||
if wazevoapi.PrintMachineCodeHexPerFunction {
|
||||
fmt.Printf("[[[machine code SSA for %d/%d %s]]]\n%s\n",
|
||||
i, len(module.CodeSection)-1, exportedFnIndex[fidx], hex.EncodeToString(body))
|
||||
fmt.Printf("[[[machine code for %s]]]\n%s\n\n", wazevoapi.GetCurrentFunctionName(ctx), hex.EncodeToString(body))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -228,17 +236,10 @@ func (e *engine) compileLocalWasmFunction(
|
||||
}
|
||||
|
||||
if wazevoapi.PrintSSA {
|
||||
def := module.FunctionDefinition(functionIndex)
|
||||
fmt.Printf("[[[SSA for %d/%d %s]]]%s\n", localFunctionIndex, len(module.CodeSection)-1, def.Debugname, ssaBuilder.Format())
|
||||
fmt.Printf("[[[SSA for %s]]]%s\n", wazevoapi.GetCurrentFunctionName(ctx), ssaBuilder.Format())
|
||||
}
|
||||
|
||||
if wazevoapi.DeterministicCompilationVerifierEnabled {
|
||||
def := module.FunctionDefinition(functionIndex)
|
||||
name := def.DebugName()
|
||||
if len(def.ExportNames()) > 0 {
|
||||
name = def.ExportNames()[0]
|
||||
}
|
||||
ctx = wazevoapi.DeterministicCompilationVerifierSetCurrentFunctionName(ctx, fmt.Sprintf("[%d/%d]:\"%s\"", localFunctionIndex, len(module.CodeSection)-1, name))
|
||||
wazevoapi.VerifyOrSetDeterministicCompilationContextValue(ctx, "SSA", ssaBuilder.Format())
|
||||
}
|
||||
|
||||
@@ -246,8 +247,7 @@ func (e *engine) compileLocalWasmFunction(
|
||||
ssaBuilder.RunPasses()
|
||||
|
||||
if wazevoapi.PrintOptimizedSSA {
|
||||
def := module.FunctionDefinition(functionIndex)
|
||||
fmt.Printf("[[[Optimized SSA for %d/%d %s]]]%s\n", localFunctionIndex, len(module.CodeSection)-1, def.Debugname, ssaBuilder.Format())
|
||||
fmt.Printf("[[[Optimized SSA for %s]]]%s\n", wazevoapi.GetCurrentFunctionName(ctx), ssaBuilder.Format())
|
||||
}
|
||||
|
||||
if wazevoapi.DeterministicCompilationVerifierEnabled {
|
||||
@@ -258,8 +258,7 @@ func (e *engine) compileLocalWasmFunction(
|
||||
ssaBuilder.LayoutBlocks()
|
||||
|
||||
if wazevoapi.PrintBlockLaidOutSSA {
|
||||
def := module.FunctionDefinition(functionIndex)
|
||||
fmt.Printf("[[[Laidout SSA for %d/%d %s]]]%s\n", localFunctionIndex, len(module.CodeSection)-1, def.Debugname, ssaBuilder.Format())
|
||||
fmt.Printf("[[[Laidout SSA for %s]]]%s\n", wazevoapi.GetCurrentFunctionName(ctx), ssaBuilder.Format())
|
||||
}
|
||||
|
||||
if wazevoapi.DeterministicCompilationVerifierEnabled {
|
||||
@@ -279,9 +278,9 @@ func (e *engine) compileLocalWasmFunction(
|
||||
return copied, rels, goPreambleSize, nil
|
||||
}
|
||||
|
||||
func (e *engine) compileHostModule(module *wasm.Module) (*compiledModule, error) {
|
||||
func (e *engine) compileHostModule(ctx context.Context, module *wasm.Module) (*compiledModule, error) {
|
||||
machine := newMachine()
|
||||
be := backend.NewCompiler(machine, ssa.NewBuilder())
|
||||
be := backend.NewCompiler(ctx, machine, ssa.NewBuilder())
|
||||
|
||||
num := len(module.CodeSection)
|
||||
cm := &compiledModule{}
|
||||
@@ -429,9 +428,9 @@ func (e *engine) NewModuleEngine(m *wasm.Module, mi *wasm.ModuleInstance) (wasm.
|
||||
return me, nil
|
||||
}
|
||||
|
||||
func (e *engine) compileBuiltinFunctions() {
|
||||
func (e *engine) compileBuiltinFunctions(ctx context.Context) {
|
||||
machine := newMachine()
|
||||
be := backend.NewCompiler(machine, ssa.NewBuilder())
|
||||
be := backend.NewCompiler(ctx, machine, ssa.NewBuilder())
|
||||
e.builtinFunctions = &builtinFunctions{}
|
||||
|
||||
{
|
||||
|
||||
@@ -96,11 +96,6 @@ func DeterministicCompilationVerifierGetRandomizedLocalFunctionIndex(ctx context
|
||||
return ret
|
||||
}
|
||||
|
||||
// DeterministicCompilationVerifierSetCurrentFunctionName sets the current function name to the given `functionName`.
|
||||
func DeterministicCompilationVerifierSetCurrentFunctionName(ctx context.Context, functionName string) context.Context {
|
||||
return context.WithValue(ctx, currentFunctionNameKey{}, functionName)
|
||||
}
|
||||
|
||||
// VerifyOrSetDeterministicCompilationContextValue verifies that the `newValue` is the same as the previous value for the given `scope`
|
||||
// and the current function name. If the previous value doesn't exist, it sets the value to the given `newValue`.
|
||||
//
|
||||
@@ -133,3 +128,38 @@ This is mostly due to (but might not be limited to):
|
||||
os.Exit(1)
|
||||
}
|
||||
}
|
||||
|
||||
// nolint
|
||||
const NeedFunctionNameInContext = PrintSSA ||
|
||||
PrintOptimizedSSA ||
|
||||
PrintBlockLaidOutSSA ||
|
||||
PrintSSAToBackendIRLowering ||
|
||||
PrintRegisterAllocated ||
|
||||
PrintFinalizedMachineCode ||
|
||||
PrintMachineCodeHexPerFunction ||
|
||||
DeterministicCompilationVerifierEnabled
|
||||
|
||||
// SetCurrentFunctionName sets the current function name to the given `functionName`.
|
||||
func SetCurrentFunctionName(ctx context.Context, functionName string) context.Context {
|
||||
return context.WithValue(ctx, currentFunctionNameKey{}, functionName)
|
||||
}
|
||||
|
||||
// GetCurrentFunctionName returns the current function name.
|
||||
func GetCurrentFunctionName(ctx context.Context) string {
|
||||
return ctx.Value(currentFunctionNameKey{}).(string)
|
||||
}
|
||||
|
||||
// ----- High Register Pressure -----
|
||||
|
||||
type highRegisterPressureContextKey struct{}
|
||||
|
||||
// EnableHighRegisterPressure enables the high register pressure mode.
|
||||
func EnableHighRegisterPressure(ctx context.Context) context.Context {
|
||||
ctx = context.WithValue(ctx, highRegisterPressureContextKey{}, true)
|
||||
return ctx
|
||||
}
|
||||
|
||||
// IsHighRegisterPressure returns true if the current compilation is under high register pressure.
|
||||
func IsHighRegisterPressure(ctx context.Context) bool {
|
||||
return ctx.Value(highRegisterPressureContextKey{}) != nil
|
||||
}
|
||||
Reference in New Issue
Block a user