diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-07 19:33:14 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-07 19:33:14 +0000 |
commit | 36d22d82aa202bb199967e9512281e9a53db42c9 (patch) | |
tree | 105e8c98ddea1c1e4784a60a5a6410fa416be2de /js/src/jit/riscv64/AssemblerMatInt.cpp | |
parent | Initial commit. (diff) | |
download | firefox-esr-upstream.tar.xz firefox-esr-upstream.zip |
Adding upstream version 115.7.0esr.upstream/115.7.0esrupstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to '')
-rw-r--r-- | js/src/jit/riscv64/AssemblerMatInt.cpp | 217 |
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 |