Changeset View
Changeset View
Standalone View
Standalone View
llvm/lib/Target/RISCV/MCTargetDesc/RISCVMatInt.cpp
//===- RISCVMatInt.cpp - Immediate materialisation -------------*- C++ -*--===// | //===- RISCVMatInt.cpp - Immediate materialisation -------------*- C++ -*--===// | ||||
// | // | ||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | ||||
// See https://llvm.org/LICENSE.txt for license information. | // See https://llvm.org/LICENSE.txt for license information. | ||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | ||||
// | // | ||||
//===----------------------------------------------------------------------===// | //===----------------------------------------------------------------------===// | ||||
#include "RISCVMatInt.h" | #include "RISCVMatInt.h" | ||||
#include "MCTargetDesc/RISCVMCTargetDesc.h" | #include "MCTargetDesc/RISCVMCTargetDesc.h" | ||||
#include "llvm/ADT/APInt.h" | #include "llvm/ADT/APInt.h" | ||||
#include "llvm/Support/MathExtras.h" | #include "llvm/Support/MathExtras.h" | ||||
using namespace llvm; | using namespace llvm; | ||||
static int getInstSeqCost(RISCVMatInt::InstSeq &Res, bool HasRVC = true, | |||||
bool OptSize = false) { | |||||
if (!HasRVC) | |||||
return Res.size(); | |||||
int Cost = 0; | |||||
for (auto Instr : Res) { | |||||
bool Compressed; | |||||
switch (Instr.Opc) { | |||||
case RISCV::SLLI: | |||||
case RISCV::SRLI: | |||||
Compressed = true; | |||||
break; | |||||
case RISCV::ADDI: | |||||
case RISCV::ADDIW: | |||||
case RISCV::LUI: | |||||
Compressed = isInt<6>(Instr.Imm); | |||||
break; | |||||
default: | |||||
Compressed = false; | |||||
break; | |||||
} | |||||
// Two RVC instructions take the same space as one RVI instruction, but | |||||
// can take longer to execute than the single RVI instruction. Thus, we | |||||
// consider that two RVC instruction are slightly more costly than one | |||||
// RVI instruction. For longer sequences of RVC instructions the space | |||||
// savings can be worth it, though. The costs below try to model that. | |||||
if (!Compressed) | |||||
Cost += 100; // Baseline cost of one RVI instruction: 100%. | |||||
else { | |||||
// We prefer three RVC instructions to two RVI instructions when | |||||
// optimizing for size. | |||||
Cost += OptSize ? 60 : 70; // 60 or 70% cost of baseline. | |||||
} | |||||
} | |||||
return Cost; | |||||
} | |||||
// Recursively generate a sequence for materializing an integer. | // Recursively generate a sequence for materializing an integer. | ||||
static void generateInstSeqImpl(int64_t Val, | static void generateInstSeqImpl(int64_t Val, | ||||
const FeatureBitset &ActiveFeatures, | const FeatureBitset &ActiveFeatures, | ||||
RISCVMatInt::InstSeq &Res) { | RISCVMatInt::InstSeq &Res) { | ||||
bool IsRV64 = ActiveFeatures[RISCV::Feature64Bit]; | bool IsRV64 = ActiveFeatures[RISCV::Feature64Bit]; | ||||
if (isInt<32>(Val)) { | if (isInt<32>(Val)) { | ||||
// Depending on the active bits in the immediate Value v, the following | // Depending on the active bits in the immediate Value v, the following | ||||
▲ Show 20 Lines • Show All 79 Lines • ▼ Show 20 Lines | if (Val > 0 && Res.size() > 2) { | ||||
// ADDI -1 and an SRLI. | // ADDI -1 and an SRLI. | ||||
ShiftedVal |= maskTrailingOnes<uint64_t>(LeadingZeros); | ShiftedVal |= maskTrailingOnes<uint64_t>(LeadingZeros); | ||||
RISCVMatInt::InstSeq TmpSeq; | RISCVMatInt::InstSeq TmpSeq; | ||||
generateInstSeqImpl(ShiftedVal, ActiveFeatures, TmpSeq); | generateInstSeqImpl(ShiftedVal, ActiveFeatures, TmpSeq); | ||||
TmpSeq.push_back(RISCVMatInt::Inst(RISCV::SRLI, LeadingZeros)); | TmpSeq.push_back(RISCVMatInt::Inst(RISCV::SRLI, LeadingZeros)); | ||||
// Keep the new sequence if it is an improvement. | // Keep the new sequence if it is an improvement. | ||||
if (TmpSeq.size() < Res.size()) { | if (getInstSeqCost(TmpSeq) < getInstSeqCost(Res)) { | ||||
Res = TmpSeq; | Res = TmpSeq; | ||||
// A 2 instruction sequence is the best we can do. | // A 2 instruction sequence is the best we can do. | ||||
if (Res.size() <= 2) | if (Res.size() <= 2) | ||||
return Res; | return Res; | ||||
} | } | ||||
// Some cases can benefit from filling the lower bits with zeros instead. | // Some cases can benefit from filling the lower bits with zeros instead. | ||||
ShiftedVal &= maskTrailingZeros<uint64_t>(LeadingZeros); | ShiftedVal &= maskTrailingZeros<uint64_t>(LeadingZeros); | ||||
TmpSeq.clear(); | TmpSeq.clear(); | ||||
generateInstSeqImpl(ShiftedVal, ActiveFeatures, TmpSeq); | generateInstSeqImpl(ShiftedVal, ActiveFeatures, TmpSeq); | ||||
TmpSeq.push_back(RISCVMatInt::Inst(RISCV::SRLI, LeadingZeros)); | TmpSeq.push_back(RISCVMatInt::Inst(RISCV::SRLI, LeadingZeros)); | ||||
// Keep the new sequence if it is an improvement. | // Keep the new sequence if it is an improvement. | ||||
if (TmpSeq.size() < Res.size()) { | if (getInstSeqCost(TmpSeq) < getInstSeqCost(Res)) { | ||||
Res = TmpSeq; | Res = TmpSeq; | ||||
// A 2 instruction sequence is the best we can do. | // A 2 instruction sequence is the best we can do. | ||||
if (Res.size() <= 2) | if (Res.size() <= 2) | ||||
return Res; | return Res; | ||||
} | } | ||||
// If we have exactly 32 leading zeros and Zba, we can try using zext.w at | // If we have exactly 32 leading zeros and Zba, we can try using zext.w at | ||||
// the end of the sequence. | // the end of the sequence. | ||||
if (LeadingZeros == 32 && ActiveFeatures[RISCV::FeatureExtZba]) { | if (LeadingZeros == 32 && ActiveFeatures[RISCV::FeatureExtZba]) { | ||||
// Try replacing upper bits with 1. | // Try replacing upper bits with 1. | ||||
uint64_t LeadingOnesVal = Val | maskLeadingOnes<uint64_t>(LeadingZeros); | uint64_t LeadingOnesVal = Val | maskLeadingOnes<uint64_t>(LeadingZeros); | ||||
TmpSeq.clear(); | TmpSeq.clear(); | ||||
generateInstSeqImpl(LeadingOnesVal, ActiveFeatures, TmpSeq); | generateInstSeqImpl(LeadingOnesVal, ActiveFeatures, TmpSeq); | ||||
TmpSeq.push_back(RISCVMatInt::Inst(RISCV::ADDUW, 0)); | TmpSeq.push_back(RISCVMatInt::Inst(RISCV::ADDUW, 0)); | ||||
// Keep the new sequence if it is an improvement. | // Keep the new sequence if it is an improvement. | ||||
if (TmpSeq.size() < Res.size()) { | if (getInstSeqCost(TmpSeq) < getInstSeqCost(Res)) { | ||||
Res = TmpSeq; | Res = TmpSeq; | ||||
// A 2 instruction sequence is the best we can do. | // A 2 instruction sequence is the best we can do. | ||||
if (Res.size() <= 2) | if (Res.size() <= 2) | ||||
return Res; | return Res; | ||||
} | } | ||||
} | } | ||||
} | } | ||||
return Res; | return Res; | ||||
} | } | ||||
int getIntMatCost(const APInt &Val, unsigned Size, | int getIntMatCost(const APInt &Val, unsigned Size, | ||||
const FeatureBitset &ActiveFeatures) { | const FeatureBitset &ActiveFeatures) { | ||||
bool IsRV64 = ActiveFeatures[RISCV::Feature64Bit]; | bool IsRV64 = ActiveFeatures[RISCV::Feature64Bit]; | ||||
int PlatRegSize = IsRV64 ? 64 : 32; | int PlatRegSize = IsRV64 ? 64 : 32; | ||||
// Split the constant into platform register sized chunks, and calculate cost | // Split the constant into platform register sized chunks, and calculate cost | ||||
// of each chunk. | // of each chunk. | ||||
int Cost = 0; | int Cost = 0; | ||||
for (unsigned ShiftVal = 0; ShiftVal < Size; ShiftVal += PlatRegSize) { | for (unsigned ShiftVal = 0; ShiftVal < Size; ShiftVal += PlatRegSize) { | ||||
APInt Chunk = Val.ashr(ShiftVal).sextOrTrunc(PlatRegSize); | APInt Chunk = Val.ashr(ShiftVal).sextOrTrunc(PlatRegSize); | ||||
InstSeq MatSeq = generateInstSeq(Chunk.getSExtValue(), ActiveFeatures); | InstSeq MatSeq = generateInstSeq(Chunk.getSExtValue(), ActiveFeatures); | ||||
Cost += MatSeq.size(); | Cost += getInstSeqCost(MatSeq); | ||||
} | } | ||||
return std::max(1, Cost); | return std::max(1, Cost); | ||||
} | } | ||||
} // namespace RISCVMatInt | } // namespace RISCVMatInt | ||||
} // namespace llvm | } // namespace llvm |