From 5e24b88bda8b064fbfd46743c8c5fc31b1d848b1 Mon Sep 17 00:00:00 2001 From: George Kuan Date: Sun, 27 Mar 2016 17:51:03 -0700 Subject: [PATCH] Wasm: f32 min and max codegen --- lib/Backend/IRBuilderAsmJs.cpp | 8 ++++ lib/Backend/Lower.cpp | 4 +- lib/Backend/LowerMDShared.cpp | 38 ++++++++++++------ lib/Common/Common/NumberUtilitiesBase.h | 3 +- lib/Runtime/ByteCode/OpCodes.h | 6 +-- lib/Runtime/ByteCode/OpCodesAsmJs.h | 7 ++-- .../Language/InterpreterHandlerAsmJs.inl | 6 ++- lib/Runtime/Library/JavascriptNumber.h | 2 +- lib/Runtime/Math/AsmJsMath.inl | 37 +++++++++++------ lib/WasmReader/WasmBinaryOpCodes.h | 4 +- lib/WasmReader/WasmKeywords.h | 4 +- test/wasm/f32.baseline | 9 +++++ test/wasm/f32.js | 18 +++++++++ test/wasm/f32.wasm | Bin 0 -> 78 bytes test/wasm/f32.wast | 15 +++++++ test/wasm/rlexe.xml | 7 ++++ 16 files changed, 127 insertions(+), 41 deletions(-) create mode 100644 test/wasm/f32.baseline create mode 100644 test/wasm/f32.js create mode 100644 test/wasm/f32.wasm create mode 100644 test/wasm/f32.wast diff --git a/lib/Backend/IRBuilderAsmJs.cpp b/lib/Backend/IRBuilderAsmJs.cpp index 9aec9fb3f30..ba5b0f75363 100644 --- a/lib/Backend/IRBuilderAsmJs.cpp +++ b/lib/Backend/IRBuilderAsmJs.cpp @@ -2921,6 +2921,14 @@ IRBuilderAsmJs::BuildFloat3(Js::OpCodeAsmJs newOpcode, uint32 offset, Js::RegSlo instr = IR::Instr::New(Js::OpCode::Copysign_A, dstOpnd, src1Opnd, src2Opnd, m_func); break; + case Js::OpCodeAsmJs::Min_Flt: + instr = IR::Instr::New(Js::OpCode::InlineMathMin, dstOpnd, src1Opnd, src2Opnd, m_func); + break; + + case Js::OpCodeAsmJs::Max_Flt: + instr = IR::Instr::New(Js::OpCode::InlineMathMax, dstOpnd, src1Opnd, src2Opnd, m_func); + break; + default: Assume(UNREACHED); } diff --git a/lib/Backend/Lower.cpp b/lib/Backend/Lower.cpp index 4bc2aa4dc23..95f5271d354 100644 --- a/lib/Backend/Lower.cpp +++ b/lib/Backend/Lower.cpp @@ -13557,9 +13557,9 @@ IR::BranchInstr *Lowerer::InsertCompareBranch( Func *const func = insertBeforeInstr->m_func; - if(compareSrc1->IsFloat64()) + if(compareSrc1->IsFloat()) { - Assert(compareSrc2->IsFloat64()); + Assert(compareSrc2->IsFloat()); Assert(!isUnsigned); IR::BranchInstr *const instr = IR::BranchInstr::New(branchOpCode, target, compareSrc1, compareSrc2, func); insertBeforeInstr->InsertBefore(instr); diff --git a/lib/Backend/LowerMDShared.cpp b/lib/Backend/LowerMDShared.cpp index b97a01dbcc0..b5fc7b3559e 100644 --- a/lib/Backend/LowerMDShared.cpp +++ b/lib/Backend/LowerMDShared.cpp @@ -9274,16 +9274,15 @@ void LowererMD::GenerateFastInlineBuiltInCall(IR::Instr* instr, IR::JnHelperMeth instr->InsertBefore(branchInstr); LowererMDArch::EmitInt4Instr(branchInstr); } - // MOV dst, src1 - this->m_lowerer->InsertMove(dst, src1, instr); + // MOV dst, src1 + this->m_lowerer->InsertMove(dst, src1, instr); } - - else if(dst->IsFloat64()) + else if(dst->IsFloat()) { - // COMISD src1 (src2), src2 (src1) + // COMISD/COMISS src1 (src2), src2 (src1) // JA $doneLabel // JEQ $labelNegZeroAndNaNCheckHelper - // MOVSD dst, src2 + // MOVSD/MOVSS dst, src2 // JMP $doneLabel // // $labelNegZeroAndNaNCheckHelper @@ -9291,24 +9290,24 @@ void LowererMD::GenerateFastInlineBuiltInCall(IR::Instr* instr, IR::JnHelperMeth // if(min) // { // if(src2 == -0.0) - // MOVSD dst, src2 + // MOVSD/MOVSS dst, src2 // } // else // { // if(src1 == -0.0) - // MOVSD dst, src2 + // MOVSD/MOVSS dst, src2 // } // JMP $doneLabel // // $labelNaNHelper - // MOVSD dst, NaN + // MOVSD/MOVSS dst, NaN // // $doneLabel - //MOVSD dst, src1; + //MOVSD/MOVSS dst, src1; Assert(!dst->IsEqual(src1)); - this->m_lowerer->InsertMove(dst, src1, instr); + this->m_lowerer->InsertMove(dst, src1, instr); if(min) { this->m_lowerer->InsertCompareBranch(src1, src2, Js::OpCode::BrLt_A, doneLabel, instr); // Lowering of BrLt_A for floats is done to JA with operands swapped @@ -9343,7 +9342,17 @@ void LowererMD::GenerateFastInlineBuiltInCall(IR::Instr* instr, IR::JnHelperMeth instr->InsertBefore(IR::BranchInstr::New(Js::OpCode::JMP, doneLabel, instr->m_func)); instr->InsertBefore(labelNaNHelper); - IR::Opnd * opndNaN = IR::MemRefOpnd::New((double*)&(Js::JavascriptNumber::k_Nan), IRType::TyFloat64, this->m_func); + IR::Opnd * opndNaN = nullptr; + + if (dst->IsFloat32()) + { + opndNaN = IR::MemRefOpnd::New((float*)&(Js::JavascriptNumber::k_Nan32), IRType::TyFloat32, this->m_func); + } + else + { + opndNaN = IR::MemRefOpnd::New((double*)&(Js::JavascriptNumber::k_Nan), IRType::TyFloat64, this->m_func); + } + this->m_lowerer->InsertMove(dst, opndNaN, instr); } instr->InsertBefore(doneLabel); @@ -9362,7 +9371,10 @@ IR::Opnd* LowererMD::IsOpndNegZero(IR::Opnd* opnd, IR::Instr* instr) { IR::Opnd * isNegZero = IR::RegOpnd::New(TyInt32, this->m_func); - LoadDoubleHelperArgument(instr, opnd); + if (opnd->IsFloat64()) + LoadDoubleHelperArgument(instr, opnd); + else + LoadFloatHelperArgument(instr, opnd); IR::Instr * helperCallInstr = IR::Instr::New(Js::OpCode::CALL, isNegZero, this->m_func); instr->InsertBefore(helperCallInstr); this->ChangeToHelperCall(helperCallInstr, IR::HelperIsNegZero); diff --git a/lib/Common/Common/NumberUtilitiesBase.h b/lib/Common/Common/NumberUtilitiesBase.h index ba9a6c0adac..d4bbcf9addd 100644 --- a/lib/Common/Common/NumberUtilitiesBase.h +++ b/lib/Common/Common/NumberUtilitiesBase.h @@ -1,5 +1,5 @@ //------------------------------------------------------------------------------------------------------- -// Copyright (C) Microsoft. All rights reserved. +// Copyright (C) Microsoft Corporation and contributors. All rights reserved. // Licensed under the MIT license. See LICENSE.txt file in the project root for full license information. //------------------------------------------------------------------------------------------------------- ////////////////////////////////////////////////////////// @@ -13,6 +13,7 @@ namespace Js { public: static const UINT64 k_Nan = 0xFFF8000000000000ull; + static const UINT32 k_Nan32 = 0x7FFF8000ul; }; class NumberUtilitiesBase diff --git a/lib/Runtime/ByteCode/OpCodes.h b/lib/Runtime/ByteCode/OpCodes.h index 6912582b3e8..dabab16cd1d 100644 --- a/lib/Runtime/ByteCode/OpCodes.h +++ b/lib/Runtime/ByteCode/OpCodes.h @@ -752,9 +752,9 @@ MACRO_BACKEND_ONLY( SlotArrayCheck, Empty, OpCanCSE) MACRO_BACKEND_ONLY( FrameDisplayCheck, Empty, OpCanCSE) MACRO_EXTEND( BeginBodyScope, Empty, OpSideEffect) -MACRO_BACKEND_ONLY( Copysign_A, Empty, OpTempNumberSources | OpCanCSE | OpProducesNumber) -MACRO_BACKEND_ONLY( Trunc_A, Empty, OpTempNumberSources | OpCanCSE | OpProducesNumber) -MACRO_BACKEND_ONLY( Nearest_A, Empty, OpTempNumberSources | OpCanCSE | OpProducesNumber) +MACRO_BACKEND_ONLY( Copysign_A, Empty, OpTempNumberSources|OpCanCSE|OpProducesNumber) +MACRO_BACKEND_ONLY( Trunc_A, Empty, OpTempNumberSources|OpCanCSE|OpProducesNumber) +MACRO_BACKEND_ONLY( Nearest_A, Empty, OpTempNumberSources|OpCanCSE|OpProducesNumber) // All SIMD ops are backend only for non-asmjs. #define MACRO_SIMD(opcode, asmjsLayout, opCodeAttrAsmJs, OpCodeAttr, ...) MACRO_BACKEND_ONLY(opcode, Empty, OpCodeAttr) diff --git a/lib/Runtime/ByteCode/OpCodesAsmJs.h b/lib/Runtime/ByteCode/OpCodesAsmJs.h index 8aef5024b84..579ba6816d6 100644 --- a/lib/Runtime/ByteCode/OpCodesAsmJs.h +++ b/lib/Runtime/ByteCode/OpCodesAsmJs.h @@ -215,16 +215,17 @@ MACRO_WMS ( Sqrt_Flt , Float2 , None ) MACRO_WMS ( Abs_Flt , Float2 , None ) MACRO_WMS ( Atan2_Db , Double3 , None ) MACRO_WMS ( Min_Db , Double3 , None ) +MACRO_WMS ( Min_Flt , Float3 , None ) MACRO_WMS ( Max_Db , Double3 , None ) +MACRO_WMS ( Max_Flt , Float3 , None ) // Fround MACRO_WMS ( Fround_Flt , Float2 , None ) MACRO_WMS ( Fround_Db , Float1Double1 , None ) MACRO_WMS ( Fround_Int , Float1Int1 , None ) -MACRO_WMS(Copysign_Db, Double3, None) -MACRO_WMS(Copysign_Flt, Float3, None) - +MACRO_EXTEND_WMS(Copysign_Db, Double3, None) +MACRO_EXTEND_WMS(Copysign_Flt, Float3, None) MACRO_EXTEND_WMS(Trunc_Db, Double2, None) MACRO_EXTEND_WMS(Trunc_Flt, Float2, None) MACRO_EXTEND_WMS(Nearest_Db, Double2, None) diff --git a/lib/Runtime/Language/InterpreterHandlerAsmJs.inl b/lib/Runtime/Language/InterpreterHandlerAsmJs.inl index e58ceca7ea7..5d8195b710e 100644 --- a/lib/Runtime/Language/InterpreterHandlerAsmJs.inl +++ b/lib/Runtime/Language/InterpreterHandlerAsmJs.inl @@ -164,13 +164,15 @@ EXDEF2 (NOPASMJS , NopEx , Empty DEF2_WMS( F1toF1Mem , Abs_Flt , ::fabsf ) DEF2_WMS( D2toD1Mem , Atan2_Db , Math::Atan2 ) DEF2_WMS( D2toD1Mem , Min_Db , AsmJsMath::Min ) + DEF2_WMS( F2toF1Mem , Min_Flt , AsmJsMath::Min ) DEF2_WMS( D2toD1Mem , Max_Db , AsmJsMath::Max ) + DEF2_WMS( F2toF1Mem , Max_Flt , AsmJsMath::Max ) DEF2_WMS( F1toF1Mem , Fround_Flt , (float) ) DEF2_WMS( D1toF1Mem , Fround_Db , (float) ) DEF2_WMS( I1toF1Mem , Fround_Int , (float) ) - DEF2_WMS( F2toF1Mem , Copysign_Flt , Wasm::WasmMath::Copysign ) - DEF2_WMS( D2toD1Mem , Copysign_Db , Wasm::WasmMath::Copysign ) + EXDEF2_WMS( F2toF1Mem , Copysign_Flt , Wasm::WasmMath::Copysign ) + EXDEF2_WMS( D2toD1Mem , Copysign_Db , Wasm::WasmMath::Copysign ) EXDEF2_WMS( F1toF1Mem , Trunc_Flt , Wasm::WasmMath::Trunc ) EXDEF2_WMS( F1toF1Mem , Nearest_Flt , Wasm::WasmMath::Nearest ) diff --git a/lib/Runtime/Library/JavascriptNumber.h b/lib/Runtime/Library/JavascriptNumber.h index 0baf56ab74b..98db24a7e22 100644 --- a/lib/Runtime/Library/JavascriptNumber.h +++ b/lib/Runtime/Library/JavascriptNumber.h @@ -48,7 +48,7 @@ namespace Js static bool TryToVarFast(int32 nValue, Var* result); static bool TryToVarFastWithCheck(double value, Var* result); - inline static bool IsNan(double value) { return NumberUtilities::IsNan(value); } + inline static BOOL IsNan(double value) { return NumberUtilities::IsNan(value); } static bool IsZero(double value); static BOOL IsNegZero(double value); static bool IsPosInf(double value); diff --git a/lib/Runtime/Math/AsmJsMath.inl b/lib/Runtime/Math/AsmJsMath.inl index 1292205a625..866945c0e84 100644 --- a/lib/Runtime/Math/AsmJsMath.inl +++ b/lib/Runtime/Math/AsmJsMath.inl @@ -4,38 +4,51 @@ //------------------------------------------------------------------------------------------------------- namespace Js { + template - inline T AsmJsMath::Min(T aLeft, T aRight) + inline T minCheckNan(T aLeft, T aRight) { + if (NumberUtilities::IsNan(aLeft) || NumberUtilities::IsNan(aRight)) + { + return (T)NumberConstants::NaN; + } return aLeft < aRight ? aLeft : aRight; } template<> inline double AsmJsMath::Min(double aLeft, double aRight) { - if (NumberUtilities::IsNan(aLeft) || NumberUtilities::IsNan(aRight)) - { - return NumberConstants::NaN; - } - return aLeft < aRight ? aLeft : aRight; + return minCheckNan(aLeft, aRight); } - template - inline T AsmJsMath::Max(T aLeft, T aRight) + template<> + inline float AsmJsMath::Min(float aLeft, float aRight) { - return aLeft > aRight ? aLeft : aRight; + return minCheckNan(aLeft, aRight); } - template<> - inline double AsmJsMath::Max(double aLeft, double aRight) + template + inline T maxCheckNan(T aLeft, T aRight) { if (NumberUtilities::IsNan(aLeft) || NumberUtilities::IsNan(aRight)) { - return NumberConstants::NaN; + return (T)NumberConstants::NaN; } return aLeft > aRight ? aLeft : aRight; } + template<> + inline double AsmJsMath::Max(double aLeft, double aRight) + { + return maxCheckNan(aLeft, aRight); + } + + template<> + inline float AsmJsMath::Max(float aLeft, float aRight) + { + return maxCheckNan(aLeft, aRight); + } + template inline T AsmJsMath::Add( T aLeft, T aRight ) { diff --git a/lib/WasmReader/WasmBinaryOpCodes.h b/lib/WasmReader/WasmBinaryOpCodes.h index 4d8b1e86747..efa10a52a3f 100644 --- a/lib/WasmReader/WasmBinaryOpCodes.h +++ b/lib/WasmReader/WasmBinaryOpCodes.h @@ -175,8 +175,8 @@ WASM_SIMPLE_OPCODE(F32Add, 0x75, ADD_F32, F_FF) WASM_SIMPLE_OPCODE(F32Sub, 0x76, SUB_F32, F_FF) WASM_SIMPLE_OPCODE(F32Mul, 0x77, MUL_F32, F_FF) WASM_SIMPLE_OPCODE(F32DIv, 0x78, DIV_F32, F_FF) -WASM_SIMPLE_OPCODE(F32Min, 0x79, NYI, F_FF) -WASM_SIMPLE_OPCODE(F32Max, 0x7a, NYI, F_FF) +WASM_SIMPLE_OPCODE(F32Min, 0x79, MIN_F32, F_FF) +WASM_SIMPLE_OPCODE(F32Max, 0x7a, MAX_F32, F_FF) WASM_SIMPLE_OPCODE(F32Abs, 0x7b, ABS_F32, F_F) WASM_SIMPLE_OPCODE(F32Neg, 0x7c, NEG_F32, F_F) WASM_SIMPLE_OPCODE(F32CopySign, 0x7d, COPYSIGN_F32, F_FF) diff --git a/lib/WasmReader/WasmKeywords.h b/lib/WasmReader/WasmKeywords.h index f8305315300..fa87c8ba910 100644 --- a/lib/WasmReader/WasmKeywords.h +++ b/lib/WasmReader/WasmKeywords.h @@ -114,10 +114,10 @@ WASM_KEYWORD_BIN_MATH_I(ROL, rotl, Rol_Int) WASM_KEYWORD_BIN_MATH_FD(DIV, div, Div) WASM_KEYWORD_BIN_MATH_FD(COPYSIGN, copysign, Copysign) +WASM_KEYWORD_BIN_MATH_FD(MIN, min, Min) +WASM_KEYWORD_BIN_MATH_FD(MAX, max, Max) WASM_KEYWORD_BIN_MATH_D(MOD, mod, Rem_Db) -WASM_KEYWORD_BIN_MATH_D(MIN, min, Min_Db) -WASM_KEYWORD_BIN_MATH_D(MAX, max, Max_Db) // compare ops diff --git a/test/wasm/f32.baseline b/test/wasm/f32.baseline new file mode 100644 index 00000000000..359e97797b1 --- /dev/null +++ b/test/wasm/f32.baseline @@ -0,0 +1,9 @@ +11 +11.010000228881836 +NaN +NaN +NaN +Infinity +NaN +NaN +NaN diff --git a/test/wasm/f32.js b/test/wasm/f32.js new file mode 100644 index 00000000000..7d592d4db4e --- /dev/null +++ b/test/wasm/f32.js @@ -0,0 +1,18 @@ +//------------------------------------------------------------------------------------------------------- +// Copyright (C) Microsoft Corporation and contributors. All rights reserved. +// Licensed under the MIT license. See LICENSE.txt file in the project root for full license information. +//------------------------------------------------------------------------------------------------------- + +const blob = WScript.LoadBinaryFile('f32.wasm'); +const moduleBytesView = new Uint8Array(blob); +var a = Wasm.instantiateModule(moduleBytesView, {}).exports; +print(a.min(11, 11.01)); // 11 +print(a.max(11, 11.01)); // 11.010000228881836 +print(a.min(NaN, 11.01)); // NaN +print(a.max(NaN, 11.01)); // NaN +print(a.min(11, NaN)); // NaN +print(a.max(1/0, 11.01)); // Infinity +print(a.max(11.01, 0/0)); // NaN +print(a.max(0/0, 11.01)); // NaN +print(a.max(NaN, -NaN)); // NaN + diff --git a/test/wasm/f32.wasm b/test/wasm/f32.wasm new file mode 100644 index 0000000000000000000000000000000000000000..fe9fd2c342300202cf6e651daf2fc828b7a324d1 GIT binary patch literal 78 zcmXBGI}UCy=uyF?+Bav-ll5EBYMQB1(oTR7Fg-`N6CeYUvL&LSlGd`jr47GYqC bqt&ZhhU8R8vL7ncBW|qW;Ak59^BVd9k8Te= literal 0 HcmV?d00001 diff --git a/test/wasm/f32.wast b/test/wasm/f32.wast new file mode 100644 index 00000000000..160edbc6f0e --- /dev/null +++ b/test/wasm/f32.wast @@ -0,0 +1,15 @@ +;;------------------------------------------------------------------------------------------------------- +;; Copyright (C) Microsoft Corporation and contributors. All rights reserved. +;; Licensed under the MIT license. See LICENSE.txt file in the project root for full license information. +;;------------------------------------------------------------------------------------------------------- + +(module + (func (param f32) (param f32) (result f32) + (return (f32.min (get_local 0) (get_local 1))) + ) + (func (param f32) (param f32) (result f32) + (return (f32.max (get_local 0) (get_local 1))) + ) + (export "min" 0) + (export "max" 1) +) diff --git a/test/wasm/rlexe.xml b/test/wasm/rlexe.xml index 99d9371af0a..1370d1dc392 100644 --- a/test/wasm/rlexe.xml +++ b/test/wasm/rlexe.xml @@ -21,4 +21,11 @@ -on:wasm + + + f32.js + f32.baseline + -on:Wasm + +