summaryrefslogtreecommitdiffstats
path: root/js/src/jit/riscv64/AssemblerMatInt.cpp
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-07 19:33:14 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-07 19:33:14 +0000
commit36d22d82aa202bb199967e9512281e9a53db42c9 (patch)
tree105e8c98ddea1c1e4784a60a5a6410fa416be2de /js/src/jit/riscv64/AssemblerMatInt.cpp
parentInitial commit. (diff)
downloadfirefox-esr-36d22d82aa202bb199967e9512281e9a53db42c9.tar.xz
firefox-esr-36d22d82aa202bb199967e9512281e9a53db42c9.zip
Adding upstream version 115.7.0esr.upstream/115.7.0esrupstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'js/src/jit/riscv64/AssemblerMatInt.cpp')
-rw-r--r--js/src/jit/riscv64/AssemblerMatInt.cpp217
1 files changed, 217 insertions, 0 deletions
diff --git a/js/src/jit/riscv64/AssemblerMatInt.cpp b/js/src/jit/riscv64/AssemblerMatInt.cpp
new file mode 100644
index 0000000000..81c7fa7c40
--- /dev/null
+++ b/js/src/jit/riscv64/AssemblerMatInt.cpp
@@ -0,0 +1,217 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
+ * vim: set ts=8 sts=2 et sw=2 tw=80:
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+//===- RISCVMatInt.cpp - Immediate materialisation -------------*- C++
+//-*--===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM
+// Exceptions. See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+#include "mozilla/MathAlgorithms.h"
+#include "mozilla/Maybe.h"
+
+#include "gc/Marking.h"
+#include "jit/AutoWritableJitCode.h"
+#include "jit/ExecutableAllocator.h"
+#include "jit/riscv64/Assembler-riscv64.h"
+#include "jit/riscv64/disasm/Disasm-riscv64.h"
+#include "vm/Realm.h"
+namespace js {
+namespace jit {
+void Assembler::RecursiveLi(Register rd, int64_t val) {
+ if (val > 0 && RecursiveLiImplCount(val) > 2) {
+ unsigned LeadingZeros = mozilla::CountLeadingZeroes64((uint64_t)val);
+ uint64_t ShiftedVal = (uint64_t)val << LeadingZeros;
+ int countFillZero = RecursiveLiImplCount(ShiftedVal) + 1;
+ if (countFillZero < RecursiveLiImplCount(val)) {
+ RecursiveLiImpl(rd, ShiftedVal);
+ srli(rd, rd, LeadingZeros);
+ return;
+ }
+ }
+ RecursiveLiImpl(rd, val);
+}
+
+int Assembler::RecursiveLiCount(int64_t val) {
+ if (val > 0 && RecursiveLiImplCount(val) > 2) {
+ unsigned LeadingZeros = mozilla::CountLeadingZeroes64((uint64_t)val);
+ uint64_t ShiftedVal = (uint64_t)val << LeadingZeros;
+ // Fill in the bits that will be shifted out with 1s. An example where
+ // this helps is trailing one masks with 32 or more ones. This will
+ // generate ADDI -1 and an SRLI.
+ int countFillZero = RecursiveLiImplCount(ShiftedVal) + 1;
+ if (countFillZero < RecursiveLiImplCount(val)) {
+ return countFillZero;
+ }
+ }
+ return RecursiveLiImplCount(val);
+}
+
+inline int64_t signExtend(uint64_t V, int N) {
+ return int64_t(V << (64 - N)) >> (64 - N);
+}
+
+void Assembler::RecursiveLiImpl(Register rd, int64_t Val) {
+ if (is_int32(Val)) {
+ // Depending on the active bits in the immediate Value v, the following
+ // instruction sequences are emitted:
+ //
+ // v == 0 : ADDI
+ // v[0,12) != 0 && v[12,32) == 0 : ADDI
+ // v[0,12) == 0 && v[12,32) != 0 : LUI
+ // v[0,32) != 0 : LUI+ADDI(W)
+ int64_t Hi20 = ((Val + 0x800) >> 12) & 0xFFFFF;
+ int64_t Lo12 = Val << 52 >> 52;
+
+ if (Hi20) {
+ lui(rd, (int32_t)Hi20);
+ }
+
+ if (Lo12 || Hi20 == 0) {
+ if (Hi20) {
+ addiw(rd, rd, Lo12);
+ } else {
+ addi(rd, zero_reg, Lo12);
+ }
+ }
+ return;
+ }
+
+ // In the worst case, for a full 64-bit constant, a sequence of 8
+ // instructions (i.e., LUI+ADDIW+SLLI+ADDI+SLLI+ADDI+SLLI+ADDI) has to be
+ // emitted. Note that the first two instructions (LUI+ADDIW) can contribute
+ // up to 32 bits while the following ADDI instructions contribute up to 12
+ // bits each.
+ //
+ // On the first glance, implementing this seems to be possible by simply
+ // emitting the most significant 32 bits (LUI+ADDIW) followed by as many
+ // left shift (SLLI) and immediate additions (ADDI) as needed. However, due
+ // to the fact that ADDI performs a sign extended addition, doing it like
+ // that would only be possible when at most 11 bits of the ADDI instructions
+ // are used. Using all 12 bits of the ADDI instructions, like done by GAS,
+ // actually requires that the constant is processed starting with the least
+ // significant bit.
+ //
+ // In the following, constants are processed from LSB to MSB but instruction
+ // emission is performed from MSB to LSB by recursively calling
+ // generateInstSeq. In each recursion, first the lowest 12 bits are removed
+ // from the constant and the optimal shift amount, which can be greater than
+ // 12 bits if the constant is sparse, is determined. Then, the shifted
+ // remaining constant is processed recursively and gets emitted as soon as
+ // it fits into 32 bits. The emission of the shifts and additions is
+ // subsequently performed when the recursion returns.
+
+ int64_t Lo12 = Val << 52 >> 52;
+ int64_t Hi52 = ((uint64_t)Val + 0x800ull) >> 12;
+ int ShiftAmount = 12 + mozilla::CountTrailingZeroes64((uint64_t)Hi52);
+ Hi52 = signExtend(Hi52 >> (ShiftAmount - 12), 64 - ShiftAmount);
+
+ // If the remaining bits don't fit in 12 bits, we might be able to reduce
+ // the shift amount in order to use LUI which will zero the lower 12 bits.
+ bool Unsigned = false;
+ if (ShiftAmount > 12 && !is_int12(Hi52)) {
+ if (is_int32((uint64_t)Hi52 << 12)) {
+ // Reduce the shift amount and add zeros to the LSBs so it will match
+ // LUI.
+ ShiftAmount -= 12;
+ Hi52 = (uint64_t)Hi52 << 12;
+ }
+ }
+ RecursiveLi(rd, Hi52);
+
+ if (Unsigned) {
+ } else {
+ slli(rd, rd, ShiftAmount);
+ }
+ if (Lo12) {
+ addi(rd, rd, Lo12);
+ }
+}
+
+int Assembler::RecursiveLiImplCount(int64_t Val) {
+ int count = 0;
+ if (is_int32(Val)) {
+ // Depending on the active bits in the immediate Value v, the following
+ // instruction sequences are emitted:
+ //
+ // v == 0 : ADDI
+ // v[0,12) != 0 && v[12,32) == 0 : ADDI
+ // v[0,12) == 0 && v[12,32) != 0 : LUI
+ // v[0,32) != 0 : LUI+ADDI(W)
+ int64_t Hi20 = ((Val + 0x800) >> 12) & 0xFFFFF;
+ int64_t Lo12 = Val << 52 >> 52;
+
+ if (Hi20) {
+ // lui(rd, (int32_t)Hi20);
+ count++;
+ }
+
+ if (Lo12 || Hi20 == 0) {
+ // unsigned AddiOpc = (IsRV64 && Hi20) ? RISCV::ADDIW : RISCV::ADDI;
+ // Res.push_back(RISCVMatInt::Inst(AddiOpc, Lo12));
+ count++;
+ }
+ return count;
+ }
+
+ // In the worst case, for a full 64-bit constant, a sequence of 8
+ // instructions (i.e., LUI+ADDIW+SLLI+ADDI+SLLI+ADDI+SLLI+ADDI) has to be
+ // emitted. Note that the first two instructions (LUI+ADDIW) can contribute
+ // up to 32 bits while the following ADDI instructions contribute up to 12
+ // bits each.
+ //
+ // On the first glance, implementing this seems to be possible by simply
+ // emitting the most significant 32 bits (LUI+ADDIW) followed by as many
+ // left shift (SLLI) and immediate additions (ADDI) as needed. However, due
+ // to the fact that ADDI performs a sign extended addition, doing it like
+ // that would only be possible when at most 11 bits of the ADDI instructions
+ // are used. Using all 12 bits of the ADDI instructions, like done by GAS,
+ // actually requires that the constant is processed starting with the least
+ // significant bit.
+ //
+ // In the following, constants are processed from LSB to MSB but instruction
+ // emission is performed from MSB to LSB by recursively calling
+ // generateInstSeq. In each recursion, first the lowest 12 bits are removed
+ // from the constant and the optimal shift amount, which can be greater than
+ // 12 bits if the constant is sparse, is determined. Then, the shifted
+ // remaining constant is processed recursively and gets emitted as soon as
+ // it fits into 32 bits. The emission of the shifts and additions is
+ // subsequently performed when the recursion returns.
+
+ int64_t Lo12 = Val << 52 >> 52;
+ int64_t Hi52 = ((uint64_t)Val + 0x800ull) >> 12;
+ int ShiftAmount = 12 + mozilla::CountTrailingZeroes64((uint64_t)Hi52);
+ Hi52 = signExtend(Hi52 >> (ShiftAmount - 12), 64 - ShiftAmount);
+
+ // If the remaining bits don't fit in 12 bits, we might be able to reduce
+ // the shift amount in order to use LUI which will zero the lower 12 bits.
+ bool Unsigned = false;
+ if (ShiftAmount > 12 && !is_int12(Hi52)) {
+ if (is_int32((uint64_t)Hi52 << 12)) {
+ // Reduce the shift amount and add zeros to the LSBs so it will match
+ // LUI.
+ ShiftAmount -= 12;
+ Hi52 = (uint64_t)Hi52 << 12;
+ }
+ }
+
+ count += RecursiveLiImplCount(Hi52);
+
+ if (Unsigned) {
+ } else {
+ // slli(rd, rd, ShiftAmount);
+ count++;
+ }
+ if (Lo12) {
+ // addi(rd, rd, Lo12);
+ count++;
+ }
+ return count;
+}
+
+} // namespace jit
+} // namespace js