github.com/bananabytelabs/wazero@v0.0.0-20240105073314-54b22a776da8/internal/engine/wazevo/backend/isa/arm64/abi_test.go (about) 1 package arm64 2 3 import ( 4 "testing" 5 6 "github.com/bananabytelabs/wazero/internal/engine/wazevo/backend" 7 "github.com/bananabytelabs/wazero/internal/engine/wazevo/backend/regalloc" 8 "github.com/bananabytelabs/wazero/internal/engine/wazevo/ssa" 9 "github.com/bananabytelabs/wazero/internal/testing/require" 10 ) 11 12 func TestAbiImpl_init(t *testing.T) { 13 for _, tc := range []struct { 14 name string 15 sig *ssa.Signature 16 exp abiImpl 17 }{ 18 { 19 name: "empty sig", 20 sig: &ssa.Signature{}, 21 exp: abiImpl{}, 22 }, 23 { 24 name: "small sig", 25 sig: &ssa.Signature{ 26 Params: []ssa.Type{ssa.TypeI32, ssa.TypeF32, ssa.TypeI32}, 27 Results: []ssa.Type{ssa.TypeI64, ssa.TypeF64}, 28 }, 29 exp: abiImpl{ 30 m: nil, 31 args: []backend.ABIArg{ 32 {Index: 0, Kind: backend.ABIArgKindReg, Reg: x0VReg, Type: ssa.TypeI32}, 33 {Index: 1, Kind: backend.ABIArgKindReg, Reg: v0VReg, Type: ssa.TypeF32}, 34 {Index: 2, Kind: backend.ABIArgKindReg, Reg: x1VReg, Type: ssa.TypeI32}, 35 }, 36 rets: []backend.ABIArg{ 37 {Index: 0, Kind: backend.ABIArgKindReg, Reg: x0VReg, Type: ssa.TypeI64}, 38 {Index: 1, Kind: backend.ABIArgKindReg, Reg: v0VReg, Type: ssa.TypeF64}, 39 }, 40 argRealRegs: []regalloc.VReg{x0VReg, v0VReg, x1VReg}, 41 retRealRegs: []regalloc.VReg{x0VReg, v0VReg}, 42 }, 43 }, 44 { 45 name: "regs stack mix and match", 46 sig: &ssa.Signature{ 47 Params: []ssa.Type{ 48 ssa.TypeI32, ssa.TypeF32, 49 ssa.TypeI64, ssa.TypeF64, 50 ssa.TypeI32, ssa.TypeF32, 51 ssa.TypeI64, ssa.TypeF64, 52 ssa.TypeI32, ssa.TypeF32, 53 ssa.TypeI64, ssa.TypeF64, 54 ssa.TypeI32, ssa.TypeF32, 55 ssa.TypeI64, ssa.TypeF64, 56 ssa.TypeI32, ssa.TypeF32, 57 ssa.TypeI64, ssa.TypeF64, 58 ssa.TypeI32, ssa.TypeF32, 59 ssa.TypeI64, ssa.TypeF64, 60 ssa.TypeI32, ssa.TypeF32, 61 ssa.TypeI64, ssa.TypeF64, 62 ssa.TypeI32, ssa.TypeF32, 63 ssa.TypeI64, ssa.TypeF64, 64 }, 65 Results: []ssa.Type{ 66 ssa.TypeI32, ssa.TypeF32, 67 ssa.TypeI64, ssa.TypeF64, 68 ssa.TypeI32, ssa.TypeF32, 69 ssa.TypeI64, ssa.TypeF64, 70 ssa.TypeI32, ssa.TypeF32, 71 ssa.TypeI64, ssa.TypeF64, 72 ssa.TypeI32, ssa.TypeF32, 73 ssa.TypeI64, ssa.TypeF64, 74 ssa.TypeI32, ssa.TypeF32, 75 ssa.TypeI64, ssa.TypeF64, 76 ssa.TypeI32, ssa.TypeF32, 77 ssa.TypeI64, ssa.TypeF64, 78 ssa.TypeI32, ssa.TypeF32, 79 ssa.TypeI64, ssa.TypeF64, 80 ssa.TypeI32, ssa.TypeF32, 81 ssa.TypeI64, ssa.TypeF64, 82 }, 83 }, 84 exp: abiImpl{ 85 argStackSize: 128, retStackSize: 128, 86 args: []backend.ABIArg{ 87 {Index: 0, Kind: backend.ABIArgKindReg, Reg: x0VReg, Type: ssa.TypeI32}, 88 {Index: 1, Kind: backend.ABIArgKindReg, Reg: v0VReg, Type: ssa.TypeF32}, 89 {Index: 2, Kind: backend.ABIArgKindReg, Reg: x1VReg, Type: ssa.TypeI64}, 90 {Index: 3, Kind: backend.ABIArgKindReg, Reg: v1VReg, Type: ssa.TypeF64}, 91 {Index: 4, Kind: backend.ABIArgKindReg, Reg: x2VReg, Type: ssa.TypeI32}, 92 {Index: 5, Kind: backend.ABIArgKindReg, Reg: v2VReg, Type: ssa.TypeF32}, 93 {Index: 6, Kind: backend.ABIArgKindReg, Reg: x3VReg, Type: ssa.TypeI64}, 94 {Index: 7, Kind: backend.ABIArgKindReg, Reg: v3VReg, Type: ssa.TypeF64}, 95 {Index: 8, Kind: backend.ABIArgKindReg, Reg: x4VReg, Type: ssa.TypeI32}, 96 {Index: 9, Kind: backend.ABIArgKindReg, Reg: v4VReg, Type: ssa.TypeF32}, 97 {Index: 10, Kind: backend.ABIArgKindReg, Reg: x5VReg, Type: ssa.TypeI64}, 98 {Index: 11, Kind: backend.ABIArgKindReg, Reg: v5VReg, Type: ssa.TypeF64}, 99 {Index: 12, Kind: backend.ABIArgKindReg, Reg: x6VReg, Type: ssa.TypeI32}, 100 {Index: 13, Kind: backend.ABIArgKindReg, Reg: v6VReg, Type: ssa.TypeF32}, 101 {Index: 14, Kind: backend.ABIArgKindReg, Reg: x7VReg, Type: ssa.TypeI64}, 102 {Index: 15, Kind: backend.ABIArgKindReg, Reg: v7VReg, Type: ssa.TypeF64}, 103 {Index: 16, Kind: backend.ABIArgKindStack, Type: ssa.TypeI32, Offset: 0}, 104 {Index: 17, Kind: backend.ABIArgKindStack, Type: ssa.TypeF32, Offset: 8}, 105 {Index: 18, Kind: backend.ABIArgKindStack, Type: ssa.TypeI64, Offset: 16}, 106 {Index: 19, Kind: backend.ABIArgKindStack, Type: ssa.TypeF64, Offset: 24}, 107 {Index: 20, Kind: backend.ABIArgKindStack, Type: ssa.TypeI32, Offset: 32}, 108 {Index: 21, Kind: backend.ABIArgKindStack, Type: ssa.TypeF32, Offset: 40}, 109 {Index: 22, Kind: backend.ABIArgKindStack, Type: ssa.TypeI64, Offset: 48}, 110 {Index: 23, Kind: backend.ABIArgKindStack, Type: ssa.TypeF64, Offset: 56}, 111 {Index: 24, Kind: backend.ABIArgKindStack, Type: ssa.TypeI32, Offset: 64}, 112 {Index: 25, Kind: backend.ABIArgKindStack, Type: ssa.TypeF32, Offset: 72}, 113 {Index: 26, Kind: backend.ABIArgKindStack, Type: ssa.TypeI64, Offset: 80}, 114 {Index: 27, Kind: backend.ABIArgKindStack, Type: ssa.TypeF64, Offset: 88}, 115 {Index: 28, Kind: backend.ABIArgKindStack, Type: ssa.TypeI32, Offset: 96}, 116 {Index: 29, Kind: backend.ABIArgKindStack, Type: ssa.TypeF32, Offset: 104}, 117 {Index: 30, Kind: backend.ABIArgKindStack, Type: ssa.TypeI64, Offset: 112}, 118 {Index: 31, Kind: backend.ABIArgKindStack, Type: ssa.TypeF64, Offset: 120}, 119 }, 120 rets: []backend.ABIArg{ 121 {Index: 0, Kind: backend.ABIArgKindReg, Reg: x0VReg, Type: ssa.TypeI32}, 122 {Index: 1, Kind: backend.ABIArgKindReg, Reg: v0VReg, Type: ssa.TypeF32}, 123 {Index: 2, Kind: backend.ABIArgKindReg, Reg: x1VReg, Type: ssa.TypeI64}, 124 {Index: 3, Kind: backend.ABIArgKindReg, Reg: v1VReg, Type: ssa.TypeF64}, 125 {Index: 4, Kind: backend.ABIArgKindReg, Reg: x2VReg, Type: ssa.TypeI32}, 126 {Index: 5, Kind: backend.ABIArgKindReg, Reg: v2VReg, Type: ssa.TypeF32}, 127 {Index: 6, Kind: backend.ABIArgKindReg, Reg: x3VReg, Type: ssa.TypeI64}, 128 {Index: 7, Kind: backend.ABIArgKindReg, Reg: v3VReg, Type: ssa.TypeF64}, 129 {Index: 8, Kind: backend.ABIArgKindReg, Reg: x4VReg, Type: ssa.TypeI32}, 130 {Index: 9, Kind: backend.ABIArgKindReg, Reg: v4VReg, Type: ssa.TypeF32}, 131 {Index: 10, Kind: backend.ABIArgKindReg, Reg: x5VReg, Type: ssa.TypeI64}, 132 {Index: 11, Kind: backend.ABIArgKindReg, Reg: v5VReg, Type: ssa.TypeF64}, 133 {Index: 12, Kind: backend.ABIArgKindReg, Reg: x6VReg, Type: ssa.TypeI32}, 134 {Index: 13, Kind: backend.ABIArgKindReg, Reg: v6VReg, Type: ssa.TypeF32}, 135 {Index: 14, Kind: backend.ABIArgKindReg, Reg: x7VReg, Type: ssa.TypeI64}, 136 {Index: 15, Kind: backend.ABIArgKindReg, Reg: v7VReg, Type: ssa.TypeF64}, 137 {Index: 16, Kind: backend.ABIArgKindStack, Type: ssa.TypeI32, Offset: 0}, 138 {Index: 17, Kind: backend.ABIArgKindStack, Type: ssa.TypeF32, Offset: 8}, 139 {Index: 18, Kind: backend.ABIArgKindStack, Type: ssa.TypeI64, Offset: 16}, 140 {Index: 19, Kind: backend.ABIArgKindStack, Type: ssa.TypeF64, Offset: 24}, 141 {Index: 20, Kind: backend.ABIArgKindStack, Type: ssa.TypeI32, Offset: 32}, 142 {Index: 21, Kind: backend.ABIArgKindStack, Type: ssa.TypeF32, Offset: 40}, 143 {Index: 22, Kind: backend.ABIArgKindStack, Type: ssa.TypeI64, Offset: 48}, 144 {Index: 23, Kind: backend.ABIArgKindStack, Type: ssa.TypeF64, Offset: 56}, 145 {Index: 24, Kind: backend.ABIArgKindStack, Type: ssa.TypeI32, Offset: 64}, 146 {Index: 25, Kind: backend.ABIArgKindStack, Type: ssa.TypeF32, Offset: 72}, 147 {Index: 26, Kind: backend.ABIArgKindStack, Type: ssa.TypeI64, Offset: 80}, 148 {Index: 27, Kind: backend.ABIArgKindStack, Type: ssa.TypeF64, Offset: 88}, 149 {Index: 28, Kind: backend.ABIArgKindStack, Type: ssa.TypeI32, Offset: 96}, 150 {Index: 29, Kind: backend.ABIArgKindStack, Type: ssa.TypeF32, Offset: 104}, 151 {Index: 30, Kind: backend.ABIArgKindStack, Type: ssa.TypeI64, Offset: 112}, 152 {Index: 31, Kind: backend.ABIArgKindStack, Type: ssa.TypeF64, Offset: 120}, 153 }, 154 retRealRegs: []regalloc.VReg{x0VReg, v0VReg, x1VReg, v1VReg, x2VReg, v2VReg, x3VReg, v3VReg, x4VReg, v4VReg, x5VReg, v5VReg, x6VReg, v6VReg, x7VReg, v7VReg}, 155 argRealRegs: []regalloc.VReg{x0VReg, v0VReg, x1VReg, v1VReg, x2VReg, v2VReg, x3VReg, v3VReg, x4VReg, v4VReg, x5VReg, v5VReg, x6VReg, v6VReg, x7VReg, v7VReg}, 156 }, 157 }, 158 { 159 name: "all regs", 160 sig: &ssa.Signature{ 161 Params: []ssa.Type{ 162 ssa.TypeI32, ssa.TypeF32, 163 ssa.TypeI64, ssa.TypeF64, 164 ssa.TypeI32, ssa.TypeF32, 165 ssa.TypeI64, ssa.TypeF64, 166 ssa.TypeI32, ssa.TypeF32, 167 ssa.TypeI64, ssa.TypeF64, 168 ssa.TypeI32, ssa.TypeF32, 169 ssa.TypeI64, ssa.TypeF64, 170 }, 171 Results: []ssa.Type{ 172 ssa.TypeI32, ssa.TypeF32, 173 ssa.TypeI64, ssa.TypeF64, 174 ssa.TypeI32, ssa.TypeF32, 175 ssa.TypeI64, ssa.TypeF64, 176 ssa.TypeI32, ssa.TypeF32, 177 ssa.TypeI64, ssa.TypeF64, 178 ssa.TypeI32, ssa.TypeF32, 179 ssa.TypeI64, ssa.TypeF64, 180 }, 181 }, 182 exp: abiImpl{ 183 args: []backend.ABIArg{ 184 {Index: 0, Kind: backend.ABIArgKindReg, Reg: x0VReg, Type: ssa.TypeI32}, 185 {Index: 1, Kind: backend.ABIArgKindReg, Reg: v0VReg, Type: ssa.TypeF32}, 186 {Index: 2, Kind: backend.ABIArgKindReg, Reg: x1VReg, Type: ssa.TypeI64}, 187 {Index: 3, Kind: backend.ABIArgKindReg, Reg: v1VReg, Type: ssa.TypeF64}, 188 {Index: 4, Kind: backend.ABIArgKindReg, Reg: x2VReg, Type: ssa.TypeI32}, 189 {Index: 5, Kind: backend.ABIArgKindReg, Reg: v2VReg, Type: ssa.TypeF32}, 190 {Index: 6, Kind: backend.ABIArgKindReg, Reg: x3VReg, Type: ssa.TypeI64}, 191 {Index: 7, Kind: backend.ABIArgKindReg, Reg: v3VReg, Type: ssa.TypeF64}, 192 {Index: 8, Kind: backend.ABIArgKindReg, Reg: x4VReg, Type: ssa.TypeI32}, 193 {Index: 9, Kind: backend.ABIArgKindReg, Reg: v4VReg, Type: ssa.TypeF32}, 194 {Index: 10, Kind: backend.ABIArgKindReg, Reg: x5VReg, Type: ssa.TypeI64}, 195 {Index: 11, Kind: backend.ABIArgKindReg, Reg: v5VReg, Type: ssa.TypeF64}, 196 {Index: 12, Kind: backend.ABIArgKindReg, Reg: x6VReg, Type: ssa.TypeI32}, 197 {Index: 13, Kind: backend.ABIArgKindReg, Reg: v6VReg, Type: ssa.TypeF32}, 198 {Index: 14, Kind: backend.ABIArgKindReg, Reg: x7VReg, Type: ssa.TypeI64}, 199 {Index: 15, Kind: backend.ABIArgKindReg, Reg: v7VReg, Type: ssa.TypeF64}, 200 }, 201 rets: []backend.ABIArg{ 202 {Index: 0, Kind: backend.ABIArgKindReg, Reg: x0VReg, Type: ssa.TypeI32}, 203 {Index: 1, Kind: backend.ABIArgKindReg, Reg: v0VReg, Type: ssa.TypeF32}, 204 {Index: 2, Kind: backend.ABIArgKindReg, Reg: x1VReg, Type: ssa.TypeI64}, 205 {Index: 3, Kind: backend.ABIArgKindReg, Reg: v1VReg, Type: ssa.TypeF64}, 206 {Index: 4, Kind: backend.ABIArgKindReg, Reg: x2VReg, Type: ssa.TypeI32}, 207 {Index: 5, Kind: backend.ABIArgKindReg, Reg: v2VReg, Type: ssa.TypeF32}, 208 {Index: 6, Kind: backend.ABIArgKindReg, Reg: x3VReg, Type: ssa.TypeI64}, 209 {Index: 7, Kind: backend.ABIArgKindReg, Reg: v3VReg, Type: ssa.TypeF64}, 210 {Index: 8, Kind: backend.ABIArgKindReg, Reg: x4VReg, Type: ssa.TypeI32}, 211 {Index: 9, Kind: backend.ABIArgKindReg, Reg: v4VReg, Type: ssa.TypeF32}, 212 {Index: 10, Kind: backend.ABIArgKindReg, Reg: x5VReg, Type: ssa.TypeI64}, 213 {Index: 11, Kind: backend.ABIArgKindReg, Reg: v5VReg, Type: ssa.TypeF64}, 214 {Index: 12, Kind: backend.ABIArgKindReg, Reg: x6VReg, Type: ssa.TypeI32}, 215 {Index: 13, Kind: backend.ABIArgKindReg, Reg: v6VReg, Type: ssa.TypeF32}, 216 {Index: 14, Kind: backend.ABIArgKindReg, Reg: x7VReg, Type: ssa.TypeI64}, 217 {Index: 15, Kind: backend.ABIArgKindReg, Reg: v7VReg, Type: ssa.TypeF64}, 218 }, 219 retRealRegs: []regalloc.VReg{x0VReg, v0VReg, x1VReg, v1VReg, x2VReg, v2VReg, x3VReg, v3VReg, x4VReg, v4VReg, x5VReg, v5VReg, x6VReg, v6VReg, x7VReg, v7VReg}, 220 argRealRegs: []regalloc.VReg{x0VReg, v0VReg, x1VReg, v1VReg, x2VReg, v2VReg, x3VReg, v3VReg, x4VReg, v4VReg, x5VReg, v5VReg, x6VReg, v6VReg, x7VReg, v7VReg}, 221 }, 222 }, 223 } { 224 tc := tc 225 t.Run(tc.name, func(t *testing.T) { 226 abi := abiImpl{} 227 abi.init(tc.sig) 228 require.Equal(t, tc.exp.args, abi.args) 229 require.Equal(t, tc.exp.rets, abi.rets) 230 require.Equal(t, tc.exp.argStackSize, abi.argStackSize) 231 require.Equal(t, tc.exp.retStackSize, abi.retStackSize) 232 require.Equal(t, tc.exp.retRealRegs, abi.retRealRegs) 233 require.Equal(t, tc.exp.argRealRegs, abi.argRealRegs) 234 }) 235 } 236 } 237 238 func TestMachine_insertAddOrSubStackPointer(t *testing.T) { 239 t.Run("add/small", func(t *testing.T) { 240 _, _, m := newSetupWithMockContext() 241 m.insertAddOrSubStackPointer(spVReg, 0x10, true) 242 require.Equal(t, `add sp, sp, #0x10`, formatEmittedInstructionsInCurrentBlock(m)) 243 }) 244 t.Run("add/large stack", func(t *testing.T) { 245 _, _, m := newSetupWithMockContext() 246 m.insertAddOrSubStackPointer(spVReg, 0xffffffff_8, true) 247 require.Equal(t, `orr x27, xzr, #0xffffffff8 248 add sp, sp, x27`, formatEmittedInstructionsInCurrentBlock(m)) 249 }) 250 t.Run("sub/small", func(t *testing.T) { 251 _, _, m := newSetupWithMockContext() 252 m.insertAddOrSubStackPointer(spVReg, 0x10, false) 253 require.Equal(t, `sub sp, sp, #0x10`, formatEmittedInstructionsInCurrentBlock(m)) 254 }) 255 t.Run("sub/large stack", func(t *testing.T) { 256 _, _, m := newSetupWithMockContext() 257 m.insertAddOrSubStackPointer(spVReg, 0xffffffff_8, false) 258 require.Equal(t, `orr x27, xzr, #0xffffffff8 259 sub sp, sp, x27`, formatEmittedInstructionsInCurrentBlock(m)) 260 }) 261 } 262 263 func TestAbiImpl_callerGenVRegToFunctionArg_constant_inlining(t *testing.T) { 264 _, builder, m := newSetupWithMockContext() 265 266 i64 := builder.AllocateInstruction().AsIconst64(10).Insert(builder) 267 f64 := builder.AllocateInstruction().AsF64const(3.14).Insert(builder) 268 abi := m.getOrCreateABIImpl(&ssa.Signature{Params: []ssa.Type{ssa.TypeI64, ssa.TypeF64}}) 269 abi.callerGenVRegToFunctionArg(0, regalloc.VReg(100).SetRegType(regalloc.RegTypeInt), &backend.SSAValueDefinition{Instr: i64, RefCount: 1}, 0) 270 abi.callerGenVRegToFunctionArg(1, regalloc.VReg(50).SetRegType(regalloc.RegTypeFloat), &backend.SSAValueDefinition{Instr: f64, RefCount: 1}, 0) 271 require.Equal(t, `movz x100?, #0xa, lsl 0 272 mov x0, x100? 273 ldr d50?, #8; b 16; data.f64 3.140000 274 mov v0.8b, v50?.8b`, formatEmittedInstructionsInCurrentBlock(m)) 275 }