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 }