From e0b2d04fb8a28e1e12a344b56a1651a9194462c0 Mon Sep 17 00:00:00 2001 From: Zoltan Herczeg Date: Mon, 22 Jul 2024 10:35:34 +0000 Subject: [PATCH] Support absolute address for memory computations Also adds minor code improvements Signed-off-by: Zoltan Herczeg zherczeg.u-szeged@partner.samsung.com --- src/jit/Backend.cpp | 7 +- src/jit/MemoryInl.h | 188 +++++++++------------------------------- src/jit/MemoryUtilInl.h | 149 +++++++++++++++++++++++++++++++ third_party/sljit | 2 +- 4 files changed, 196 insertions(+), 150 deletions(-) create mode 100644 src/jit/MemoryUtilInl.h diff --git a/src/jit/Backend.cpp b/src/jit/Backend.cpp index 033ef88a4..a90cd37d2 100644 --- a/src/jit/Backend.cpp +++ b/src/jit/Backend.cpp @@ -431,6 +431,7 @@ static void simdOperandToArg(sljit_compiler* compiler, Operand* operand, JITArg& #include "FloatConvInl.h" #include "CallInl.h" #include "MemoryInl.h" +#include "MemoryUtilInl.h" #include "TableInl.h" #include "TryCatchInl.h" @@ -1038,7 +1039,7 @@ void JITCompiler::compileFunction(JITFunction* jitFunc, bool isExternal) // Follows the declaration of FunctionDescriptor::ExternalDecl(). // Context stored in SLJIT_S0 (kContextReg) // Frame stored in SLJIT_S1 (kFrameReg) - sljit_emit_enter(m_compiler, 0, SLJIT_ARGS3(P, P, P, P_R), 3, 2, 0, 0, 0); + sljit_emit_enter(m_compiler, 0, SLJIT_ARGS3(P, P, P, P_R), 3, 2, 0); sljit_emit_icall(m_compiler, SLJIT_CALL_REG_ARG, SLJIT_ARGS0(P), SLJIT_R2, 0); sljit_label* returnToLabel = sljit_emit_label(m_compiler); sljit_emit_return(m_compiler, SLJIT_MOV_P, SLJIT_R0, 0); @@ -1486,8 +1487,8 @@ void JITCompiler::emitProlog() #endif /* !SLJIT_CONFIG_X86 */ sljit_emit_enter(m_compiler, options, SLJIT_ARGS0(P), - SLJIT_NUMBER_OF_SCRATCH_REGISTERS, m_savedIntegerRegCount + 2, - SLJIT_NUMBER_OF_SCRATCH_FLOAT_REGISTERS, m_savedFloatRegCount, sizeof(ExecutionContext::CallFrame)); + SLJIT_NUMBER_OF_SCRATCH_REGISTERS | SLJIT_ENTER_FLOAT(SLJIT_NUMBER_OF_SCRATCH_FLOAT_REGISTERS), + (m_savedIntegerRegCount + 2) | SLJIT_ENTER_FLOAT(m_savedFloatRegCount), sizeof(ExecutionContext::CallFrame)); // Setup new frame. sljit_emit_op1(m_compiler, SLJIT_MOV_P, SLJIT_R0, 0, SLJIT_MEM1(kContextReg), OffsetOfContextField(lastFrame)); diff --git a/src/jit/MemoryInl.h b/src/jit/MemoryInl.h index c4104b46d..8cf74ebac 100644 --- a/src/jit/MemoryInl.h +++ b/src/jit/MemoryInl.h @@ -29,6 +29,8 @@ struct MemAddress { #endif /* SLJIT_32BIT_ARCHITECTURE */ #if defined(ENABLE_EXTENDED_FEATURES) CheckNaturalAlignment = 1 << 5, + // Limits the resulting addressing mode to a base register with no offset. + AbsoluteAddress = 1 << 6, #endif /* ENABLE_EXTENDED_FEATURES */ }; @@ -108,6 +110,13 @@ void MemAddress::check(sljit_compiler* compiler, Operand* offsetOperand, sljit_u memArg.arg = SLJIT_MEM1(baseReg); memArg.argw = offset; load(compiler); + +#if defined(ENABLE_EXTENDED_FEATURES) + if (options & AbsoluteAddress) { + sljit_emit_op2(compiler, SLJIT_ADD, baseReg, 0, baseReg, 0, SLJIT_IMM, offset); + memArg.argw = 0; + } +#endif /* ENABLE_EXTENDED_FEATURES */ return; } @@ -134,6 +143,13 @@ void MemAddress::check(sljit_compiler* compiler, Operand* offsetOperand, sljit_u memArg.arg = SLJIT_MEM1(baseReg); memArg.argw = -static_cast(size); + +#if defined(ENABLE_EXTENDED_FEATURES) + if (options & AbsoluteAddress) { + sljit_emit_op2(compiler, SLJIT_SUB, baseReg, 0, baseReg, 0, SLJIT_IMM, static_cast(size)); + memArg.argw = 0; + } +#endif /* ENABLE_EXTENDED_FEATURES */ return; } @@ -180,23 +196,28 @@ void MemAddress::check(sljit_compiler* compiler, Operand* offsetOperand, sljit_u memArg.arg = SLJIT_MEM2(baseReg, offsetReg); memArg.argw = 0; -#if (defined SLJIT_32BIT_ARCHITECTURE && SLJIT_32BIT_ARCHITECTURE) - if (options & DontUseOffsetReg) { - sljit_emit_op2(compiler, SLJIT_ADD, baseReg, 0, baseReg, 0, offsetReg, 0); - memArg.arg = SLJIT_MEM1(baseReg); - } -#endif /* SLJIT_32BIT_ARCHITECTURE */ - #if defined(ENABLE_EXTENDED_FEATURES) if (options & CheckNaturalAlignment) { - if (SLJIT_IS_MEM2(memArg.arg)) { - sljit_emit_op2(compiler, SLJIT_ADD, baseReg, 0, baseReg, 0, offsetReg, 0); - memArg.arg = SLJIT_MEM1(baseReg); - } - sljit_emit_op2u(compiler, SLJIT_AND | SLJIT_SET_Z, baseReg, 0, SLJIT_IMM, size - 1); + sljit_emit_op2u(compiler, SLJIT_AND | SLJIT_SET_Z, offsetReg, 0, SLJIT_IMM, size - 1); context->appendTrapJump(ExecutionContext::UnalignedAtomicError, sljit_emit_jump(compiler, SLJIT_NOT_ZERO)); } #endif /* ENABLE_EXTENDED_FEATURES */ + + uint32_t checkedOptions = 0; +#if (defined SLJIT_32BIT_ARCHITECTURE && SLJIT_32BIT_ARCHITECTURE) + checkedOptions |= DontUseOffsetReg; +#endif /* SLJIT_32BIT_ARCHITECTURE */ + +#if defined(ENABLE_EXTENDED_FEATURES) + checkedOptions |= AbsoluteAddress; +#endif /* ENABLE_EXTENDED_FEATURES */ + +#if (defined SLJIT_32BIT_ARCHITECTURE && SLJIT_32BIT_ARCHITECTURE) || (defined(ENABLE_EXTENDED_FEATURES)) + if (options & checkedOptions) { + sljit_emit_op2(compiler, SLJIT_ADD, baseReg, 0, baseReg, 0, offsetReg, 0); + memArg.arg = SLJIT_MEM1(baseReg); + } +#endif /* SLJIT_32BIT_ARCHITECTURE || ENABLE_EXTENDED_FEATURES */ return; } @@ -207,13 +228,20 @@ void MemAddress::check(sljit_compiler* compiler, Operand* offsetOperand, sljit_u #if defined(ENABLE_EXTENDED_FEATURES) if (options & CheckNaturalAlignment) { - sljit_emit_op2u(compiler, SLJIT_AND | SLJIT_SET_Z, baseReg, 0, SLJIT_IMM, size - 1); + sljit_emit_op2u(compiler, SLJIT_AND | SLJIT_SET_Z, offsetReg, 0, SLJIT_IMM, size - 1); context->appendTrapJump(ExecutionContext::UnalignedAtomicError, sljit_emit_jump(compiler, SLJIT_NOT_ZERO)); } #endif /* ENABLE_EXTENDED_FEATURES */ memArg.arg = SLJIT_MEM1(baseReg); memArg.argw = -static_cast(size); + +#if defined(ENABLE_EXTENDED_FEATURES) + if (options & AbsoluteAddress) { + sljit_emit_op2(compiler, SLJIT_SUB, baseReg, 0, baseReg, 0, SLJIT_IMM, static_cast(size)); + memArg.argw = 0; + } +#endif /* ENABLE_EXTENDED_FEATURES */ } void MemAddress::load(sljit_compiler* compiler) @@ -261,7 +289,7 @@ static void atomicRmwStore64(uint64_t* shared_p, int64_t* value) static void emitAtomicLoadStore64(sljit_compiler* compiler, Instruction* instr) { - uint32_t options = MemAddress::CheckNaturalAlignment | MemAddress::DontUseOffsetReg; + uint32_t options = MemAddress::CheckNaturalAlignment | MemAddress::AbsoluteAddress; uint32_t size = 8; sljit_u32 offset; @@ -983,135 +1011,3 @@ static void emitStore(sljit_compiler* compiler, Instruction* instr) // TODO: sljit_emit_mem for unaligned access sljit_emit_op1(compiler, opcode, addr.memArg.arg, addr.memArg.argw, addr.loadArg.arg, addr.loadArg.argw); } - -static sljit_sw initMemory(uint32_t dstStart, uint32_t srcStart, uint32_t srcSize, ExecutionContext* context) -{ - Memory* memory = context->instance->memory(0); - DataSegment& sg = context->instance->dataSegment(*(sljit_u32*)&context->tmp1); - - if (!memory->checkAccess(dstStart, srcSize)) { - return ExecutionContext::OutOfBoundsMemAccessError; - } - - if (srcStart >= sg.sizeInByte() || srcStart + srcSize > sg.sizeInByte()) { - return ExecutionContext::OutOfBoundsMemAccessError; - } - - memory->initMemory(&sg, dstStart, srcStart, srcSize); - return ExecutionContext::NoError; -} - -static sljit_sw copyMemory(uint32_t dstStart, uint32_t srcStart, uint32_t size, ExecutionContext* context) -{ - Memory* memory = context->instance->memory(0); - - if (!memory->checkAccess(srcStart, size) || !memory->checkAccess(dstStart, size)) { - return ExecutionContext::OutOfBoundsMemAccessError; - } - - memory->copyMemory(dstStart, srcStart, size); - return ExecutionContext::NoError; -} - -static sljit_sw fillMemory(uint32_t start, uint32_t value, uint32_t size, ExecutionContext* context) -{ - Memory* memory = context->instance->memory(0); - - if (!memory->checkAccess(start, size)) { - return ExecutionContext::OutOfBoundsMemAccessError; - } - - memory->fillMemory(start, value, size); - return ExecutionContext::NoError; -} - -static sljit_s32 growMemory(uint32_t newSize, ExecutionContext* context) -{ - Memory* memory = context->instance->memory(0); - uint32_t oldSize = memory->sizeInPageSize(); - - if (memory->grow(static_cast(newSize) * Memory::s_memoryPageSize)) { - return static_cast(oldSize); - } - - return -1; -} - -static void emitMemory(sljit_compiler* compiler, Instruction* instr) -{ - CompileContext* context = CompileContext::get(compiler); - Operand* params = instr->operands(); - ByteCode::Opcode opcode = instr->opcode(); - - switch (opcode) { - case ByteCode::MemorySizeOpcode: { - ASSERT(!(instr->info() & Instruction::kIsCallback)); - - JITArg dstArg(params); - - sljit_emit_op2(compiler, SLJIT_LSHR32, dstArg.arg, dstArg.argw, - SLJIT_MEM1(kContextReg), OffsetOfContextField(memory0) + offsetof(Memory::TargetBuffer, sizeInByte), SLJIT_IMM, 16); - return; - } - case ByteCode::MemoryInitOpcode: - case ByteCode::MemoryCopyOpcode: - case ByteCode::MemoryFillOpcode: { - ASSERT(instr->info() & Instruction::kIsCallback); - - emitInitR0R1R2(compiler, SLJIT_MOV32, params); - sljit_emit_op1(compiler, SLJIT_MOV, SLJIT_R3, 0, kContextReg, 0); - - sljit_sw addr; - - if (opcode == ByteCode::MemoryInitOpcode) { - MemoryInit* memoryInit = reinterpret_cast(instr->byteCode()); - - sljit_emit_op1(compiler, SLJIT_MOV32, SLJIT_MEM1(kContextReg), OffsetOfContextField(tmp1), SLJIT_IMM, memoryInit->segmentIndex()); - addr = GET_FUNC_ADDR(sljit_sw, initMemory); - } else if (opcode == ByteCode::MemoryCopyOpcode) { - addr = GET_FUNC_ADDR(sljit_sw, copyMemory); - } else { - addr = GET_FUNC_ADDR(sljit_sw, fillMemory); - } - - sljit_emit_icall(compiler, SLJIT_CALL, SLJIT_ARGS4(W, 32, 32, 32, W), SLJIT_IMM, addr); - - sljit_jump* cmp = sljit_emit_cmp(compiler, SLJIT_NOT_EQUAL, SLJIT_R0, 0, SLJIT_IMM, ExecutionContext::NoError); - context->appendTrapJump(ExecutionContext::GenericTrap, cmp); - return; - } - default: { - ASSERT(opcode == ByteCode::MemoryGrowOpcode && (instr->info() & Instruction::kIsCallback)); - JITArg arg(params); - - MOVE_TO_REG(compiler, SLJIT_MOV32, SLJIT_R0, arg.arg, arg.argw); - sljit_emit_op1(compiler, SLJIT_MOV, SLJIT_R1, 0, kContextReg, 0); - - sljit_sw addr = GET_FUNC_ADDR(sljit_sw, growMemory); - sljit_emit_icall(compiler, SLJIT_CALL, SLJIT_ARGS2(32, 32, W), SLJIT_IMM, addr); - - arg.set(params + 1); - MOVE_FROM_REG(compiler, SLJIT_MOV32, arg.arg, arg.argw, SLJIT_R0); - return; - } - } -} - -static void dropData(uint32_t segmentIndex, ExecutionContext* context) -{ - DataSegment& sg = context->instance->dataSegment(segmentIndex); - sg.drop(); -} - -static void emitDataDrop(sljit_compiler* compiler, Instruction* instr) -{ - DataDrop* dataDrop = reinterpret_cast(instr->byteCode()); - - ASSERT(instr->info() & Instruction::kIsCallback); - - sljit_emit_op1(compiler, SLJIT_MOV32, SLJIT_R0, 0, SLJIT_IMM, static_cast(dataDrop->segmentIndex())); - sljit_emit_op1(compiler, SLJIT_MOV, SLJIT_R1, 0, kContextReg, 0); - - sljit_sw addr = GET_FUNC_ADDR(sljit_sw, dropData); - sljit_emit_icall(compiler, SLJIT_CALL, SLJIT_ARGS2V(32, W), SLJIT_IMM, addr); -} diff --git a/src/jit/MemoryUtilInl.h b/src/jit/MemoryUtilInl.h new file mode 100644 index 000000000..9f912cb7f --- /dev/null +++ b/src/jit/MemoryUtilInl.h @@ -0,0 +1,149 @@ +/* + * Copyright (c) 2022-present Samsung Electronics Co., Ltd + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* Only included by jit-backend.cc */ + +static sljit_sw initMemory(uint32_t dstStart, uint32_t srcStart, uint32_t srcSize, ExecutionContext* context) +{ + Memory* memory = context->instance->memory(0); + DataSegment& sg = context->instance->dataSegment(*(sljit_u32*)&context->tmp1); + + if (!memory->checkAccess(dstStart, srcSize)) { + return ExecutionContext::OutOfBoundsMemAccessError; + } + + if (srcStart >= sg.sizeInByte() || srcStart + srcSize > sg.sizeInByte()) { + return ExecutionContext::OutOfBoundsMemAccessError; + } + + memory->initMemory(&sg, dstStart, srcStart, srcSize); + return ExecutionContext::NoError; +} + +static sljit_sw copyMemory(uint32_t dstStart, uint32_t srcStart, uint32_t size, ExecutionContext* context) +{ + Memory* memory = context->instance->memory(0); + + if (!memory->checkAccess(srcStart, size) || !memory->checkAccess(dstStart, size)) { + return ExecutionContext::OutOfBoundsMemAccessError; + } + + memory->copyMemory(dstStart, srcStart, size); + return ExecutionContext::NoError; +} + +static sljit_sw fillMemory(uint32_t start, uint32_t value, uint32_t size, ExecutionContext* context) +{ + Memory* memory = context->instance->memory(0); + + if (!memory->checkAccess(start, size)) { + return ExecutionContext::OutOfBoundsMemAccessError; + } + + memory->fillMemory(start, value, size); + return ExecutionContext::NoError; +} + +static sljit_s32 growMemory(uint32_t newSize, ExecutionContext* context) +{ + Memory* memory = context->instance->memory(0); + uint32_t oldSize = memory->sizeInPageSize(); + + if (memory->grow(static_cast(newSize) * Memory::s_memoryPageSize)) { + return static_cast(oldSize); + } + + return -1; +} + +static void emitMemory(sljit_compiler* compiler, Instruction* instr) +{ + CompileContext* context = CompileContext::get(compiler); + Operand* params = instr->operands(); + ByteCode::Opcode opcode = instr->opcode(); + + switch (opcode) { + case ByteCode::MemorySizeOpcode: { + ASSERT(!(instr->info() & Instruction::kIsCallback)); + + JITArg dstArg(params); + + sljit_emit_op2(compiler, SLJIT_LSHR32, dstArg.arg, dstArg.argw, + SLJIT_MEM1(kContextReg), OffsetOfContextField(memory0) + offsetof(Memory::TargetBuffer, sizeInByte), SLJIT_IMM, 16); + return; + } + case ByteCode::MemoryInitOpcode: + case ByteCode::MemoryCopyOpcode: + case ByteCode::MemoryFillOpcode: { + ASSERT(instr->info() & Instruction::kIsCallback); + + emitInitR0R1R2(compiler, SLJIT_MOV32, params); + sljit_emit_op1(compiler, SLJIT_MOV, SLJIT_R3, 0, kContextReg, 0); + + sljit_sw addr; + + if (opcode == ByteCode::MemoryInitOpcode) { + MemoryInit* memoryInit = reinterpret_cast(instr->byteCode()); + + sljit_emit_op1(compiler, SLJIT_MOV32, SLJIT_MEM1(kContextReg), OffsetOfContextField(tmp1), SLJIT_IMM, memoryInit->segmentIndex()); + addr = GET_FUNC_ADDR(sljit_sw, initMemory); + } else if (opcode == ByteCode::MemoryCopyOpcode) { + addr = GET_FUNC_ADDR(sljit_sw, copyMemory); + } else { + addr = GET_FUNC_ADDR(sljit_sw, fillMemory); + } + + sljit_emit_icall(compiler, SLJIT_CALL, SLJIT_ARGS4(W, 32, 32, 32, W), SLJIT_IMM, addr); + + sljit_jump* cmp = sljit_emit_cmp(compiler, SLJIT_NOT_EQUAL, SLJIT_R0, 0, SLJIT_IMM, ExecutionContext::NoError); + context->appendTrapJump(ExecutionContext::GenericTrap, cmp); + return; + } + default: { + ASSERT(opcode == ByteCode::MemoryGrowOpcode && (instr->info() & Instruction::kIsCallback)); + JITArg arg(params); + + MOVE_TO_REG(compiler, SLJIT_MOV32, SLJIT_R0, arg.arg, arg.argw); + sljit_emit_op1(compiler, SLJIT_MOV, SLJIT_R1, 0, kContextReg, 0); + + sljit_sw addr = GET_FUNC_ADDR(sljit_sw, growMemory); + sljit_emit_icall(compiler, SLJIT_CALL, SLJIT_ARGS2(32, 32, W), SLJIT_IMM, addr); + + arg.set(params + 1); + MOVE_FROM_REG(compiler, SLJIT_MOV32, arg.arg, arg.argw, SLJIT_R0); + return; + } + } +} + +static void dropData(uint32_t segmentIndex, ExecutionContext* context) +{ + DataSegment& sg = context->instance->dataSegment(segmentIndex); + sg.drop(); +} + +static void emitDataDrop(sljit_compiler* compiler, Instruction* instr) +{ + DataDrop* dataDrop = reinterpret_cast(instr->byteCode()); + + ASSERT(instr->info() & Instruction::kIsCallback); + + sljit_emit_op1(compiler, SLJIT_MOV32, SLJIT_R0, 0, SLJIT_IMM, static_cast(dataDrop->segmentIndex())); + sljit_emit_op1(compiler, SLJIT_MOV, SLJIT_R1, 0, kContextReg, 0); + + sljit_sw addr = GET_FUNC_ADDR(sljit_sw, dropData); + sljit_emit_icall(compiler, SLJIT_CALL, SLJIT_ARGS2V(32, W), SLJIT_IMM, addr); +} diff --git a/third_party/sljit b/third_party/sljit index 3e5568bfc..8099661b5 160000 --- a/third_party/sljit +++ b/third_party/sljit @@ -1 +1 @@ -Subproject commit 3e5568bfcc1feddb8847b49028d823dd3c364dbd +Subproject commit 8099661b547c72be4012bd6801877426f1055efb