diff --git a/src/jit/Analysis.cpp b/src/jit/Analysis.cpp index df7317eb3..95f59c308 100644 --- a/src/jit/Analysis.cpp +++ b/src/jit/Analysis.cpp @@ -751,31 +751,36 @@ void JITCompiler::buildVariables(uint32_t requiredStackSize) VariableRef ref = *instr->getResult(0); VariableList::Variable& variable = m_variableList->variables[ref]; - if (variable.u.rangeStart == instr->id() && variable.rangeEnd == instr->id() + 1) { - ASSERT(instr->next()->isInstruction()); - Instruction* nextInstr = instr->next()->asInstruction(); - - switch (nextInstr->opcode()) { - case ByteCode::JumpIfTrueOpcode: - case ByteCode::JumpIfFalseOpcode: - // These instructions has only one argument. - ASSERT(*nextInstr->getParam(0) == VARIABLE_SET(ref, DependencyGenContext::Variable)); - variable.info |= VariableList::kIsImmediate; - variable.value = VARIABLE_SET_PTR(nullptr); - continue; - case ByteCode::SelectOpcode: - if (*nextInstr->getParam(2) == VARIABLE_SET(ref, DependencyGenContext::Variable)) { - variable.info |= VariableList::kIsImmediate; - variable.value = VARIABLE_SET_PTR(nullptr); - continue; - } - break; - default: + if (variable.u.rangeStart != instr->id() || variable.rangeEnd != instr->id() + 1) { + instr->clearInfo(Instruction::kIsMergeCompare); + continue; + } + + ASSERT(instr->next()->isInstruction()); + Instruction* nextInstr = instr->next()->asInstruction(); + + switch (nextInstr->opcode()) { + case ByteCode::JumpIfTrueOpcode: + case ByteCode::JumpIfFalseOpcode: + // These instructions has only one argument. + ASSERT(*nextInstr->getParam(0) == VARIABLE_SET(ref, DependencyGenContext::Variable)); + break; + case ByteCode::SelectOpcode: + if (*nextInstr->getParam(2) == VARIABLE_SET(ref, DependencyGenContext::Variable)) { break; } + FALLTHROUGH; + default: + instr->clearInfo(Instruction::kIsMergeCompare); + continue; } - instr->clearInfo(Instruction::kIsMergeCompare); + variable.info |= VariableList::kIsImmediate; + variable.value = VARIABLE_SET_PTR(nullptr); + + if (instr->group() == Instruction::Binary) { + instr->convertBinaryToCompare(); + } } } diff --git a/src/jit/ByteCodeParser.cpp b/src/jit/ByteCodeParser.cpp index 10673c52d..2b2997ed3 100644 --- a/src/jit/ByteCodeParser.cpp +++ b/src/jit/ByteCodeParser.cpp @@ -511,6 +511,9 @@ static void compileFunction(JITCompiler* compiler) group = Instruction::Binary; paramType = ParamTypes::ParamSrc2Dst; info = Instruction::kIs32Bit; + if (opcode == ByteCode::I32AndOpcode) { + info |= Instruction::kIsMergeCompare; + } requiredInit = OTOp2I32; break; } diff --git a/src/jit/Compiler.h b/src/jit/Compiler.h index a97d45ac7..4ee052b21 100644 --- a/src/jit/Compiler.h +++ b/src/jit/Compiler.h @@ -147,6 +147,12 @@ class InstructionListItem { return reinterpret_cast(this); } + void convertBinaryToCompare() + { + ASSERT(m_group == Binary); + m_group = Compare; + } + protected: explicit InstructionListItem(Group group) : m_next(nullptr) diff --git a/src/jit/IntMath32Inl.h b/src/jit/IntMath32Inl.h index 2dddd2250..c3b7520a6 100644 --- a/src/jit/IntMath32Inl.h +++ b/src/jit/IntMath32Inl.h @@ -1038,6 +1038,10 @@ static bool emitCompare(sljit_compiler* compiler, Instruction* instr) opcode = SLJIT_SUB | SLJIT_SET_GREATER_EQUAL; type = SLJIT_GREATER_EQUAL; break; + case ByteCode::I32AndOpcode: + opcode = SLJIT_AND | SLJIT_SET_Z; + type = SLJIT_NOT_ZERO; + break; default: RELEASE_ASSERT_NOT_REACHED(); break; @@ -1112,7 +1116,15 @@ static bool emitCompare(sljit_compiler* compiler, Instruction* instr) type ^= 0x1; } - sljit_jump* jump = sljit_emit_cmp(compiler, type, params[0].arg, params[0].argw, params[1].arg, params[1].argw); + sljit_jump* jump; + + if (instr->opcode() != ByteCode::I32AndOpcode) { + jump = sljit_emit_cmp(compiler, type, params[0].arg, params[0].argw, params[1].arg, params[1].argw); + } else { + sljit_emit_op2u(compiler, opcode, params[0].arg, params[0].argw, params[1].arg, params[1].argw); + jump = sljit_emit_jump(compiler, type); + } + nextInstr->asExtended()->value().targetLabel->jumpFrom(jump); return true; } diff --git a/src/jit/IntMath64Inl.h b/src/jit/IntMath64Inl.h index 8e846907a..b69c2da41 100644 --- a/src/jit/IntMath64Inl.h +++ b/src/jit/IntMath64Inl.h @@ -436,6 +436,10 @@ static bool emitCompare(sljit_compiler* compiler, Instruction* instr) opcode = SLJIT_SUB | SLJIT_SET_GREATER_EQUAL; type = SLJIT_GREATER_EQUAL; break; + case ByteCode::I32AndOpcode: + opcode = SLJIT_AND | SLJIT_SET_Z; + type = SLJIT_NOT_ZERO; + break; default: RELEASE_ASSERT_NOT_REACHED(); break; @@ -455,11 +459,23 @@ static bool emitCompare(sljit_compiler* compiler, Instruction* instr) type ^= 0x1; } - if (instr->info() & Instruction::kIs32Bit) { - type |= SLJIT_32; - } - sljit_jump* jump = sljit_emit_cmp(compiler, type, params[0].arg, params[0].argw, params[1].arg, params[1].argw); + sljit_jump* jump; + + if (instr->opcode() != ByteCode::I32AndOpcode) { + if (instr->info() & Instruction::kIs32Bit) { + type |= SLJIT_32; + } + + jump = sljit_emit_cmp(compiler, type, params[0].arg, params[0].argw, params[1].arg, params[1].argw); + } else { + if (instr->info() & Instruction::kIs32Bit) { + opcode |= SLJIT_32; + } + + sljit_emit_op2u(compiler, opcode, params[0].arg, params[0].argw, params[1].arg, params[1].argw); + jump = sljit_emit_jump(compiler, type); + } nextInstr->asExtended()->value().targetLabel->jumpFrom(jump); return true; } diff --git a/test/jit/binary-logical.wast b/test/jit/binary-logical.wast index 670c183a1..ecf8c84b4 100644 --- a/test/jit/binary-logical.wast +++ b/test/jit/binary-logical.wast @@ -19,6 +19,33 @@ (; 1080880403494997760, 18442521884633399280, 17361641481138401520 ;) ) + +(func (export "test2") (param i32 i32) (result i32) + block + local.get 0 + local.get 1 + i32.and + br_if 0 + i32.const 5 + return + end + + i32.const 6 +) + +(func (export "test3") (param i32 i32) (result i32) + i32.const 10 + i32.const 11 + + local.get 0 + local.get 1 + i32.and + select +) ) (assert_return (invoke "test1") (i64.const 1080880403494997760) (i64.const 18442521884633399280) (i64.const 17361641481138401520)) +(assert_return (invoke "test2" (i32.const 0x100) (i32.const 0x200)) (i32.const 5)) +(assert_return (invoke "test2" (i32.const 0x0ff0) (i32.const 0x1f)) (i32.const 6)) +(assert_return (invoke "test3" (i32.const 0xff) (i32.const 0xff00)) (i32.const 11)) +(assert_return (invoke "test3" (i32.const 0x1ff) (i32.const 0xff00)) (i32.const 10))