wa-lang.org/wazero@v1.0.2/internal/engine/compiler/compiler_conditional_save_test.go (about)

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