github.com/wasilibs/wazerox@v0.0.0-20240124024944-4923be63ab5f/internal/engine/compiler/compiler_conditional_save_test.go (about)

     1  package compiler
     2  
     3  import (
     4  	"testing"
     5  
     6  	"github.com/wasilibs/wazerox/internal/asm"
     7  	"github.com/wasilibs/wazerox/internal/testing/require"
     8  	"github.com/wasilibs/wazerox/internal/wasm"
     9  	"github.com/wasilibs/wazerox/internal/wazeroir"
    10  )
    11  
    12  // TestCompiler_conditional_value_saving ensure that saving conditional register works correctly even if there's
    13  // no free registers available.
    14  func TestCompiler_conditional_value_saving(t *testing.T) {
    15  	env := newCompilerEnvironment()
    16  	compiler := env.requireNewCompiler(t, &wasm.FunctionType{}, newCompiler, nil)
    17  	err := compiler.compilePreamble()
    18  	require.NoError(t, err)
    19  
    20  	// Place the f32 local.
    21  	err = compiler.compileConstF32(operationPtr(wazeroir.NewOperationConstF32(1.0)))
    22  	require.NoError(t, err)
    23  
    24  	// Generate constants to occupy all the unreserved GP registers.
    25  	for i := 0; i < len(unreservedGeneralPurposeRegisters); i++ {
    26  		err = compiler.compileConstI32(operationPtr(wazeroir.NewOperationConstI32(100)))
    27  		require.NoError(t, err)
    28  	}
    29  
    30  	// Pick the f32 floating point local (1.0) twice.
    31  	// Note that the f32 (function local variable in general) is placed above the call frame.
    32  	err = compiler.compilePick(operationPtr(wazeroir.NewOperationPick(int(compiler.runtimeValueLocationStack().sp-1-callFrameDataSizeInUint64), false)))
    33  
    34  	require.NoError(t, err)
    35  	err = compiler.compilePick(operationPtr(wazeroir.NewOperationPick(int(compiler.runtimeValueLocationStack().sp-1-callFrameDataSizeInUint64), false)))
    36  
    37  	require.NoError(t, err)
    38  	// Generate conditional flag via floating point comparisons.
    39  	err = compiler.compileLe(operationPtr(wazeroir.NewOperationLe(wazeroir.SignedTypeFloat32)))
    40  	require.NoError(t, err)
    41  
    42  	// Ensures that we have conditional value at top of stack.
    43  	l := compiler.runtimeValueLocationStack().peek()
    44  	require.True(t, l.onConditionalRegister())
    45  
    46  	// Ensures that no free registers are available.
    47  	_, ok := compiler.runtimeValueLocationStack().takeFreeRegister(registerTypeGeneralPurpose)
    48  	require.False(t, ok)
    49  
    50  	// We should be able to use the conditional value (an i32 value in Wasm) as an operand for, say, i32.add.
    51  	err = compiler.compileAdd(operationPtr(wazeroir.NewOperationAdd(wazeroir.UnsignedTypeI32)))
    52  	require.NoError(t, err)
    53  
    54  	err = compiler.compileReturnFunction()
    55  	require.NoError(t, err)
    56  
    57  	code := asm.CodeSegment{}
    58  	defer func() { require.NoError(t, code.Unmap()) }()
    59  
    60  	// Generate and run the code under test.
    61  	_, err = compiler.compile(code.NextCodeSection())
    62  	require.NoError(t, err)
    63  	env.exec(code.Bytes())
    64  
    65  	// expect 101 = 100(== the integer const) + 1 (== flag value == the result of (1.0 <= 1.0))
    66  	require.Equal(t, uint32(101), env.stackTopAsUint32())
    67  }