Title: [293092] trunk/Source/_javascript_Core
Revision
293092
Author
[email protected]
Date
2022-04-20 06:36:57 -0700 (Wed, 20 Apr 2022)

Log Message

[JSC] Accommodate the RISCV64 C calling convention
https://bugs.webkit.org/show_bug.cgi?id=236367
<rdar://problem/89026012>

Reviewed by Yusuke Suzuki.

The 64-bit RISC-V (RV64) calling convention requires 32-bit arguments
to be sign-extended to fill out the whole 64-bit register, fitting
nicely with different instructions in this ISA that operate on 32-bit
values, and differring from other 64-bit ISAs that provide partial-sized
registers (which are aliased to the whole register).

JSC JIT is tailored to the other ISAs, often taking shortcuts to pack
non-sign-extended values into registers that are then accessed for those
32-bit values through the partial-sized aliases. This can trip up RISC-V
execution when constructing calls that pass 32-bit values to native code
using the C calling convention.

To avoid this, arguments setup done through the CCallHelpers class is
enhanced to, after packing up arguments either into argument registers
or onto the stack, another pass of the argument types for the desired
operation is done, detecting whether the argument was supposed to be
packed into an GPR or an FPR destination. On RV64, when packed into a
GPR argument register that matches a 32-bit argument in the operation,
the additional sign extension is performed on that argument register.

GPR and FPR distinction for a given argument's register type is based
on whether or not the double type is used as the argument's type. All
non-double-typed arguments are passed as GPRs. Additional compile-time
validation is provided to ensure that's the case for every operation
that's having its arguments set up. This is relied upon when traversing
the operation's arguments and indexing every GPR argument along the way.

This approach only accommodates the RV64 calling convention for the
Baseline JIT level. For higher levels, similar but probably different
solutions will have to be crafted.

* jit/CCallHelpers.h:
(JSC::CCallHelpers::finalizeGPRArguments):
(JSC::CCallHelpers::gprArgsCount):
(JSC::CCallHelpers::fprArgsCount):
(JSC::CCallHelpers::setupArgumentsImpl):
(JSC::CCallHelpers::setupArgumentsEntryImpl):

Modified Paths

Diff

Modified: trunk/Source/_javascript_Core/ChangeLog (293091 => 293092)


--- trunk/Source/_javascript_Core/ChangeLog	2022-04-20 12:56:49 UTC (rev 293091)
+++ trunk/Source/_javascript_Core/ChangeLog	2022-04-20 13:36:57 UTC (rev 293092)
@@ -1,3 +1,49 @@
+2022-04-20  Zan Dobersek  <[email protected]>
+
+        [JSC] Accommodate the RISCV64 C calling convention
+        https://bugs.webkit.org/show_bug.cgi?id=236367
+        <rdar://problem/89026012>
+
+        Reviewed by Yusuke Suzuki.
+
+        The 64-bit RISC-V (RV64) calling convention requires 32-bit arguments
+        to be sign-extended to fill out the whole 64-bit register, fitting
+        nicely with different instructions in this ISA that operate on 32-bit
+        values, and differring from other 64-bit ISAs that provide partial-sized
+        registers (which are aliased to the whole register).
+
+        JSC JIT is tailored to the other ISAs, often taking shortcuts to pack
+        non-sign-extended values into registers that are then accessed for those
+        32-bit values through the partial-sized aliases. This can trip up RISC-V
+        execution when constructing calls that pass 32-bit values to native code
+        using the C calling convention.
+
+        To avoid this, arguments setup done through the CCallHelpers class is
+        enhanced to, after packing up arguments either into argument registers
+        or onto the stack, another pass of the argument types for the desired
+        operation is done, detecting whether the argument was supposed to be
+        packed into an GPR or an FPR destination. On RV64, when packed into a
+        GPR argument register that matches a 32-bit argument in the operation,
+        the additional sign extension is performed on that argument register.
+
+        GPR and FPR distinction for a given argument's register type is based
+        on whether or not the double type is used as the argument's type. All
+        non-double-typed arguments are passed as GPRs. Additional compile-time
+        validation is provided to ensure that's the case for every operation
+        that's having its arguments set up. This is relied upon when traversing
+        the operation's arguments and indexing every GPR argument along the way.
+
+        This approach only accommodates the RV64 calling convention for the
+        Baseline JIT level. For higher levels, similar but probably different
+        solutions will have to be crafted.
+
+        * jit/CCallHelpers.h:
+        (JSC::CCallHelpers::finalizeGPRArguments):
+        (JSC::CCallHelpers::gprArgsCount):
+        (JSC::CCallHelpers::fprArgsCount):
+        (JSC::CCallHelpers::setupArgumentsImpl):
+        (JSC::CCallHelpers::setupArgumentsEntryImpl):
+
 2022-04-20  Mikhail R. Gadelha  <[email protected]>
 
         Unify calls and checks for CellTag

Modified: trunk/Source/_javascript_Core/jit/CCallHelpers.h (293091 => 293092)


--- trunk/Source/_javascript_Core/jit/CCallHelpers.h	2022-04-20 12:56:49 UTC (rev 293091)
+++ trunk/Source/_javascript_Core/jit/CCallHelpers.h	2022-04-20 13:36:57 UTC (rev 293092)
@@ -677,14 +677,65 @@
 #undef CURRENT_ARGUMENT_TYPE
 #undef RESULT_TYPE
 
+    template<typename OperationType, unsigned gprIndex>
+    constexpr void finalizeGPRArguments(std::index_sequence<>)
+    {
+    }
+
+    template<typename OperationType, unsigned gprIndex, size_t arityIndex, size_t... remainingArityIndices>
+    constexpr void finalizeGPRArguments(std::index_sequence<arityIndex, remainingArityIndices...>)
+    {
+        using NextIndexSequenceType = std::index_sequence<remainingArityIndices...>;
+        using ArgumentType = typename FunctionTraits<OperationType>::template ArgumentType<arityIndex>;
+
+        // Every non-double-typed argument should be passed in through GPRRegs, and inversely only double-typed
+        // arguments should be passed through FPRRegs. This is asserted in the invocation of the lastly-called
+        // setupArgumentsImpl(ArgCollection<>) overload, by matching the number of handled GPR and FPR arguments
+        // with the corresponding count of properly-typed arguments for this operation.
+        if (!std::is_same_v<ArgumentType, double>) {
+            // RV64 calling convention requires all 32-bit values to be sign-extended into the whole register.
+            // JSC JIT is tailored for other ISAs that pass these values in 32-bit-wide registers, which RISC-V
+            // doesn't support, so any 32-bit value passed in argument registers has to be manually sign-extended.
+            if (isRISCV64() && gprIndex < GPRInfo::numberOfArgumentRegisters
+                && std::is_integral_v<ArgumentType> && sizeof(ArgumentType) == 4) {
+                GPRReg argReg = GPRInfo::toArgumentRegister(gprIndex);
+                signExtend32ToPtr(argReg, argReg);
+            }
+
+            finalizeGPRArguments<OperationType, gprIndex + 1>(NextIndexSequenceType());
+        } else
+            finalizeGPRArguments<OperationType, gprIndex>(NextIndexSequenceType());
+    }
+
+    template<typename ArgType> using GPRArgCountValue = std::conditional_t<std::is_same_v<ArgType, double>,
+        std::integral_constant<unsigned, 0>, std::integral_constant<unsigned, 1>>;
+    template<typename ArgType> using FPRArgCountValue = std::conditional_t<std::is_same_v<ArgType, double>,
+        std::integral_constant<unsigned, 1>, std::integral_constant<unsigned, 0>>;
+
+    template<typename OperationTraitsType, size_t... argIndices>
+    static constexpr unsigned gprArgsCount(std::index_sequence<argIndices...>)
+    {
+        return (0 + ... + (GPRArgCountValue<typename OperationTraitsType::template ArgumentType<argIndices>>::value));
+    }
+
+    template<typename OperationTraitsType, size_t... argIndices>
+    static constexpr unsigned fprArgsCount(std::index_sequence<argIndices...>)
+    {
+        return (0 + ... + (FPRArgCountValue<typename OperationTraitsType::template ArgumentType<argIndices>>::value));
+    }
+
     // Base case; set up the argument registers.
     template<typename OperationType, unsigned numGPRArgs, unsigned numGPRSources, unsigned numFPRArgs, unsigned numFPRSources, unsigned numCrossSources, unsigned extraGPRArgs, unsigned nonArgGPRs, unsigned extraPoke>
     ALWAYS_INLINE void setupArgumentsImpl(ArgCollection<numGPRArgs, numGPRSources, numFPRArgs, numFPRSources, numCrossSources, extraGPRArgs, nonArgGPRs, extraPoke> argSourceRegs)
     {
-        static_assert(FunctionTraits<OperationType>::arity == numGPRArgs + numFPRArgs, "One last sanity check");
+        using TraitsType = FunctionTraits<OperationType>;
+        static_assert(TraitsType::arity == numGPRArgs + numFPRArgs, "One last sanity check");
 #if USE(JSVALUE64)
-        static_assert(FunctionTraits<OperationType>::cCallArity() == numGPRArgs + numFPRArgs + extraPoke, "Check the CCall arity");
+        static_assert(TraitsType::cCallArity() == numGPRArgs + numFPRArgs + extraPoke, "Check the CCall arity");
 #endif
+        static_assert(gprArgsCount<TraitsType>(std::make_index_sequence<TraitsType::arity>()) == numGPRArgs);
+        static_assert(fprArgsCount<TraitsType>(std::make_index_sequence<TraitsType::arity>()) == numFPRArgs);
+
         setupStubArgs<numGPRSources, GPRReg>(clampArrayToSize<numGPRSources, GPRReg>(argSourceRegs.gprDestinations), clampArrayToSize<numGPRSources, GPRReg>(argSourceRegs.gprSources));
 #if CPU(MIPS) || (CPU(ARM_THUMB2) && !CPU(ARM_HARDFP))
         setupStubCrossArgs<numCrossSources>(argSourceRegs.crossDestinations, argSourceRegs.crossSources);
@@ -711,6 +762,8 @@
 #endif
             setupArgumentsImpl<OperationType>(argSourceRegs, args...);
         }
+
+        finalizeGPRArguments<OperationType, 0>(std::make_index_sequence<FunctionTraits<OperationType>::arity>());
     }
 
 public:
_______________________________________________
webkit-changes mailing list
[email protected]
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to