Skip to content

Commit

Permalink
Improve integer to floating point conversion
Browse files Browse the repository at this point in the history
Signed-off-by: Zoltan Herczeg zherczeg.u-szeged@partner.samsung.com
  • Loading branch information
Zoltan Herczeg committed Dec 1, 2023
1 parent 87027ae commit 8cd6606
Show file tree
Hide file tree
Showing 3 changed files with 177 additions and 11 deletions.
5 changes: 5 additions & 0 deletions src/jit/Backend.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -213,6 +213,7 @@ class SlowCase {
SignedDivide32,
SignedModulo,
SignedModulo32,
ConvertIntFromFloat,
};

SlowCase(Type type, sljit_jump* jump_from, sljit_label* resume_label, Instruction* instr)
Expand Down Expand Up @@ -464,6 +465,10 @@ void SlowCase::emit(sljit_compiler* compiler)
sljit_set_label(sljit_emit_jump(compiler, SLJIT_JUMP), m_resumeLabel);
return;
}
case Type::ConvertIntFromFloat: {
reinterpret_cast<ConvertIntFromFloatSlowCase*>(this)->emitSlowCase(compiler);
return;
}
default: {
RELEASE_ASSERT_NOT_REACHED();
break;
Expand Down
181 changes: 171 additions & 10 deletions src/jit/FloatConvInl.h
Original file line number Diff line number Diff line change
Expand Up @@ -39,15 +39,16 @@ enum FloatConversionFlags : uint32_t {
return ExecutionContext::NoError; \
}

CONVERT_FROM_FLOAT(convertF32ToS32, sljit_f32, int32_t)
CONVERT_FROM_FLOAT(convertF32ToU32, sljit_f32, uint32_t)
CONVERT_FROM_FLOAT(convertF64ToS32, sljit_f64, int32_t)
CONVERT_FROM_FLOAT(convertF64ToU32, sljit_f64, uint32_t)
CONVERT_FROM_FLOAT(convertF32ToS64, sljit_f32, int64_t)
CONVERT_FROM_FLOAT(convertF32ToU64, sljit_f32, uint64_t)
CONVERT_FROM_FLOAT(convertF64ToS64, sljit_f64, int64_t)
CONVERT_FROM_FLOAT(convertF64ToU64, sljit_f64, uint64_t)

#if (defined SLJIT_32BIT_ARCHITECTURE && SLJIT_32BIT_ARCHITECTURE)
CONVERT_FROM_FLOAT(convertF32ToS64, sljit_f32, int64_t)
CONVERT_FROM_FLOAT(convertF64ToS64, sljit_f64, int64_t)
#endif /* SLJIT_32BIT_ARCHITECTURE */

#define TRUNC_SAT(name, arg_type, result_type) \
static result_type name(arg_type arg) \
{ \
Expand Down Expand Up @@ -129,6 +130,158 @@ static void emitConvertFloatFromInteger(sljit_compiler* compiler, Instruction* i
sljit_emit_fop1(compiler, opcode, dstArg.arg, dstArg.argw, srcArg.arg, srcArg.argw);
}

class ConvertIntFromFloatSlowCase : public SlowCase {
public:
ConvertIntFromFloatSlowCase(Type type, sljit_jump* jumpFrom, sljit_label* resumeLabel, Instruction* instr,
sljit_s32 opcode, sljit_s32 sourceReg, sljit_s32 resultReg)
: SlowCase(type, jumpFrom, resumeLabel, instr)
, m_opcode(opcode)
, m_sourceReg(sourceReg)
, m_resultReg(resultReg)
{
}

void emitSlowCase(sljit_compiler* compiler);

private:
sljit_s32 m_opcode;
sljit_s32 m_sourceReg;
sljit_s32 m_resultReg;
};

static void emitConvertIntegerFromFloat(sljit_compiler* compiler, Instruction* instr, sljit_s32 opcode)
{
CompileContext* context = CompileContext::get(compiler);
Operand* operands = instr->operands();

JITArg srcArg;
JITArg dstArg(operands + 1);

floatOperandToArg(compiler, operands, srcArg, SLJIT_FR0);

sljit_s32 sourceReg = GET_SOURCE_REG(srcArg.arg, SLJIT_FR0);
sljit_s32 resultReg = GET_TARGET_REG(dstArg.arg, SLJIT_R0);
sljit_s32 tmpReg = SLJIT_R1;

MOVE_TO_FREG(compiler, SLJIT_MOV_F64 | (opcode & SLJIT_32), sourceReg, srcArg.arg, srcArg.argw);
sljit_emit_op1(compiler, SLJIT_MOV, SLJIT_R2, 0, SLJIT_IMM, ExecutionContext::InvalidConversionToIntegerError);

sljit_jump* cmp = sljit_emit_fcmp(compiler, SLJIT_UNORDERED | (opcode & SLJIT_32), sourceReg, 0, sourceReg, 0);
sljit_set_label(cmp, context->trapLabel);

sljit_emit_fop1(compiler, opcode, resultReg, 0, sourceReg, 0);

#if (defined SLJIT_32BIT_ARCHITECTURE && SLJIT_32BIT_ARCHITECTURE)
ASSERT((opcode | SLJIT_32) != SLJIT_CONV_SW_FROM_F32);
sljit_s32 flag32 = 0;
#else /* !SLJIT_32BIT_ARCHITECTURE */
sljit_s32 flag32 = (opcode | SLJIT_32) == SLJIT_CONV_S32_FROM_F32 ? SLJIT_32 : 0;
#endif /* SLJIT_32BIT_ARCHITECTURE */

#if SLJIT_CONV_MAX_FLOAT != SLJIT_CONV_MIN_FLOAT
sljit_emit_op2(compiler, SLJIT_ADD | flag32, resultReg, 0, resultReg, 0, SLJIT_IMM, 1);
sljit_emit_op2(compiler, SLJIT_SUB | flag32, tmpReg, 0, resultReg, 0, SLJIT_IMM, 2);
cmp = sljit_emit_cmp(compiler, SLJIT_SIG_LESS | flag32, resultReg, 0, tmpReg, 0);
#elif SLJIT_CONV_MAX_FLOAT == SLJIT_CONV_RESULT_MAX_INT
sljit_emit_op2(compiler, SLJIT_ADD | flag32, tmpReg, 0, resultReg, 0, SLJIT_IMM, 1);
cmp = sljit_emit_cmp(compiler, SLJIT_SIG_LESS | flag32, tmpReg, 0, resultReg, 0);
#else /* SLJIT_CONV_MAX_FLOAT != SLJIT_CONV_RESULT_MAX_INT */
sljit_emit_op2(compiler, SLJIT_SUB | flag32, tmpReg, 0, resultReg, 0, SLJIT_IMM, 1);
cmp = sljit_emit_cmp(compiler, SLJIT_SIG_LESS | flag32, resultReg, 0, tmpReg, 0);
#endif /* SLJIT_CONV_MAX_FLOAT != SLJIT_CONV_RESULT_MAX_INT */

sljit_label* resumeLabel = sljit_emit_label(compiler);

#if SLJIT_CONV_MAX_FLOAT != SLJIT_CONV_MIN_FLOAT
sljit_emit_op2(compiler, SLJIT_SUB | flag32, resultReg, 0, resultReg, 0, SLJIT_IMM, 1);
#endif /* SLJIT_CONV_MAX_FLOAT != SLJIT_CONV_MIN_FLOAT */

context->add(new ConvertIntFromFloatSlowCase(SlowCase::Type::ConvertIntFromFloat,
cmp, resumeLabel, instr, opcode, sourceReg, resultReg));

MOVE_FROM_REG(compiler, flag32 ? SLJIT_MOV32 : SLJIT_MOV, dstArg.arg, dstArg.argw, resultReg);
}

void ConvertIntFromFloatSlowCase::emitSlowCase(sljit_compiler* compiler)
{
CompileContext* context = CompileContext::get(compiler);
sljit_s32 tmpFReg = SLJIT_FR1;

if (m_opcode != SLJIT_CONV_S32_FROM_F64) {
#if SLJIT_CONV_MAX_FLOAT != SLJIT_CONV_MIN_FLOAT

#if (defined SLJIT_32BIT_ARCHITECTURE && SLJIT_32BIT_ARCHITECTURE)
sljit_emit_fset32(compiler, tmpFReg, -2147483648.f);
#else /* !SLJIT_32BIT_ARCHITECTURE */
switch (m_opcode) {
case SLJIT_CONV_S32_FROM_F32:
sljit_emit_fset32(compiler, tmpFReg, -2147483648.f);
break;
case SLJIT_CONV_SW_FROM_F64:
sljit_emit_fset64(compiler, tmpFReg, -9223372036854775808.);
break;
default:
ASSERT(m_opcode == SLJIT_CONV_SW_FROM_F32);
sljit_emit_fset32(compiler, tmpFReg, -9223372036854775808.f);
break;
}
#endif /* SLJIT_32BIT_ARCHITECTURE */

sljit_jump* cmp = sljit_emit_fcmp(compiler, SLJIT_F_EQUAL | (m_opcode & SLJIT_32), m_sourceReg, 0, tmpFReg, 0);
sljit_set_label(cmp, m_resumeLabel);
#elif SLJIT_CONV_MAX_FLOAT != SLJIT_CONV_RESULT_MAX_INT

#if (defined SLJIT_32BIT_ARCHITECTURE && SLJIT_32BIT_ARCHITECTURE)
sljit_s32 convOpcode = SLJIT_CONV_F32_FROM_S32;
#else /* !SLJIT_32BIT_ARCHITECTURE */
sljit_s32 convOpcode;

switch (m_opcode) {
case SLJIT_CONV_S32_FROM_F32:
convOpcode = SLJIT_CONV_F32_FROM_S32;
break;
case SLJIT_CONV_SW_FROM_F64:
convOpcode = SLJIT_CONV_F64_FROM_SW;
break;
default:
ASSERT(m_opcode == SLJIT_CONV_SW_FROM_F32);
convOpcode = SLJIT_CONV_F32_FROM_SW;
break;
}
#endif /* SLJIT_32BIT_ARCHITECTURE */

sljit_emit_fop1(compiler, convOpcode, tmpFReg, 0, m_resultReg, 0);
sljit_jump* cmp = sljit_emit_fcmp(compiler, SLJIT_F_EQUAL | (m_opcode & SLJIT_32), m_sourceReg, 0, tmpFReg, 0);
sljit_set_label(cmp, m_resumeLabel);
#endif /* SLJIT_CONV_MAX_FLOAT != SLJIT_CONV_RESULT_MAX_INT */

sljit_emit_op1(compiler, SLJIT_MOV, SLJIT_R2, 0, SLJIT_IMM, ExecutionContext::IntegerOverflowError);
sljit_set_label(sljit_emit_jump(compiler, SLJIT_JUMP), context->trapLabel);
return;
}

sljit_emit_op1(compiler, SLJIT_MOV, SLJIT_R2, 0, SLJIT_IMM, ExecutionContext::IntegerOverflowError);

#if (SLJIT_CONV_MAX_FLOAT == SLJIT_CONV_MIN_FLOAT) && (SLJIT_CONV_MAX_FLOAT == SLJIT_CONV_RESULT_MAX_INT)
sljit_emit_fset64(compiler, tmpFReg, 0);
#else /* (SLJIT_CONV_MAX_FLOAT != SLJIT_CONV_MIN_FLOAT) || (SLJIT_CONV_MAX_FLOAT != SLJIT_CONV_RESULT_MAX_INT) */
sljit_emit_fset64(compiler, tmpFReg, -2147483649.);
#endif /* (SLJIT_CONV_MAX_FLOAT == SLJIT_CONV_MIN_FLOAT) && (SLJIT_CONV_MAX_FLOAT == SLJIT_CONV_RESULT_MAX_INT) */

sljit_jump* cmp = sljit_emit_fcmp(compiler, SLJIT_F_LESS_EQUAL, m_sourceReg, 0, tmpFReg, 0);
sljit_set_label(cmp, context->trapLabel);

#if (SLJIT_CONV_MAX_FLOAT == SLJIT_CONV_MIN_FLOAT) && (SLJIT_CONV_MAX_FLOAT == SLJIT_CONV_RESULT_MIN_INT)
sljit_emit_fset64(compiler, tmpFReg, 0.);
#else /* (SLJIT_CONV_MAX_FLOAT != SLJIT_CONV_MIN_FLOAT) || (SLJIT_CONV_MAX_FLOAT != SLJIT_CONV_RESULT_MIN_INT) */
sljit_emit_fset64(compiler, tmpFReg, 2147483648.);
#endif /* (SLJIT_CONV_MAX_FLOAT == SLJIT_CONV_MIN_FLOAT) && (SLJIT_CONV_MAX_FLOAT == SLJIT_CONV_RESULT_MIN_INT) */

cmp = sljit_emit_fcmp(compiler, SLJIT_F_GREATER_EQUAL, m_sourceReg, 0, tmpFReg, 0);
sljit_set_label(cmp, context->trapLabel);
sljit_set_label(sljit_emit_jump(compiler, SLJIT_JUMP), m_resumeLabel);
}

static void checkConvertResult(sljit_compiler* compiler)
{
sljit_emit_op1(compiler, SLJIT_MOV, SLJIT_R2, 0, SLJIT_R0, 0);
Expand All @@ -144,39 +297,47 @@ static void emitConvertFloat(sljit_compiler* compiler, Instruction* instr)

switch (instr->opcode()) {
case ByteCode::I32TruncF32SOpcode: {
flags = SourceIsFloat;
addr = GET_FUNC_ADDR(sljit_sw, convertF32ToS32);
break;
emitConvertIntegerFromFloat(compiler, instr, SLJIT_CONV_S32_FROM_F32);
return;
}
case ByteCode::I32TruncF32UOpcode: {
flags = SourceIsFloat;
addr = GET_FUNC_ADDR(sljit_sw, convertF32ToU32);
break;
}
case ByteCode::I32TruncF64SOpcode: {
flags = SourceIsFloat | SourceIs64Bit;
addr = GET_FUNC_ADDR(sljit_sw, convertF64ToS32);
break;
emitConvertIntegerFromFloat(compiler, instr, SLJIT_CONV_S32_FROM_F64);
return;
}
case ByteCode::I32TruncF64UOpcode: {
flags = SourceIsFloat | SourceIs64Bit;
addr = GET_FUNC_ADDR(sljit_sw, convertF64ToU32);
break;
}
case ByteCode::I64TruncF32SOpcode: {
#if (defined SLJIT_32BIT_ARCHITECTURE && SLJIT_32BIT_ARCHITECTURE)
flags = SourceIsFloat | DestinationIs64Bit;
addr = GET_FUNC_ADDR(sljit_sw, convertF32ToS64);
break;
#else /* !SLJIT_32BIT_ARCHITECTURE */
emitConvertIntegerFromFloat(compiler, instr, SLJIT_CONV_SW_FROM_F32);
return;
#endif /* SLJIT_32BIT_ARCHITECTURE */
}
case ByteCode::I64TruncF32UOpcode: {
flags = SourceIsFloat | DestinationIs64Bit;
addr = GET_FUNC_ADDR(sljit_sw, convertF32ToU64);
break;
}
case ByteCode::I64TruncF64SOpcode: {
#if (defined SLJIT_32BIT_ARCHITECTURE && SLJIT_32BIT_ARCHITECTURE)
flags = SourceIsFloat | SourceIs64Bit | DestinationIs64Bit;
addr = GET_FUNC_ADDR(sljit_sw, convertF64ToS64);
break;
#else /* !SLJIT_32BIT_ARCHITECTURE */
emitConvertIntegerFromFloat(compiler, instr, SLJIT_CONV_SW_FROM_F64);
return;
#endif /* SLJIT_32BIT_ARCHITECTURE */
}
case ByteCode::I64TruncF64UOpcode: {
flags = SourceIsFloat | SourceIs64Bit | DestinationIs64Bit;
Expand Down

0 comments on commit 8cd6606

Please sign in to comment.