aboutsummaryrefslogtreecommitdiff
path: root/backend/lib/Target/RISCV/RISCVSubtarget.cpp
blob: 89f6c61d49f8f39bed40b44eb977f9be382329f4 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
// SPDX-License-Identifier: GPL-3.0-or-later

#include "rcc/Target/RISCV/RISCVSubtarget.h"

#include "GISel/RISCVCallLowering.h"
#include "GISel/RISCVLegalizerInfo.h"
#include "GISel/RISCVRegisterBankInfo.h"
#include "RISCV.h"
#include "rcc/CodeGen/GlobalISel/InstructionSelector.h"

#include <array>
#include <cstddef>
#include <string_view>

namespace rcc::riscv {
namespace {

struct ExtensionName final {
  std::string_view Name;
  RISCVExtension Extension;
};

constexpr std::array ExtensionNames{
    ExtensionName{"i", RISCVExtension::I},
    ExtensionName{"m", RISCVExtension::M},
    ExtensionName{"a", RISCVExtension::A},
    ExtensionName{"f", RISCVExtension::F},
    ExtensionName{"d", RISCVExtension::D},
    ExtensionName{"c", RISCVExtension::C},
    ExtensionName{"zicsr", RISCVExtension::Zicsr},
    ExtensionName{"zifencei", RISCVExtension::Zifencei},
    ExtensionName{"zacas", RISCVExtension::Zacas},
    ExtensionName{"zabha", RISCVExtension::Zabha},
};

[[nodiscard]] constexpr std::uint16_t extensionBit(RISCVExtension Extension) noexcept {
  return static_cast<std::uint16_t>(std::uint16_t{1} << static_cast<std::uint8_t>(Extension));
}

[[nodiscard]] const ExtensionName *findExtension(std::string_view Name) noexcept {
  for (const ExtensionName &Entry : ExtensionNames) {
    if (Entry.Name == Name)
      return &Entry;
  }
  return nullptr;
}

} // namespace

Expected<RISCVSubtargetFeatures>
RISCVSubtargetFeatures::fromFeatureList(std::span<const std::string> Features) {
  std::uint16_t Enabled = extensionBit(RISCVExtension::I);
  for (const std::string &Feature : Features) {
    if (Feature.size() < 2 || (Feature.front() != '+' && Feature.front() != '-')) {
      return makeUnexpected(ErrorCode::InvalidInvocation,
                            "RISC-V target feature must use canonical +/- spelling");
    }
    const ExtensionName *Extension = findExtension(std::string_view(Feature).substr(1));
    if (Extension == nullptr) {
      return makeUnexpected(ErrorCode::InvalidInvocation,
                            "RISC-V backend does not support target feature '" + Feature + "'");
    }
    if (Feature.front() == '+')
      Enabled |= extensionBit(Extension->Extension);
    else
      Enabled &= static_cast<std::uint16_t>(~extensionBit(Extension->Extension));
  }

  RISCVSubtargetFeatures Result(Enabled);
  if (!Result.has(RISCVExtension::I)) {
    return makeUnexpected(ErrorCode::InvalidInvocation,
                          "RV64 target feature configuration cannot disable the base I extension");
  }
  if (Result.has(RISCVExtension::D) && !Result.has(RISCVExtension::F)) {
    return makeUnexpected(ErrorCode::InvalidInvocation,
                          "RISC-V D extension requires the F extension");
  }
  if ((Result.has(RISCVExtension::Zacas) || Result.has(RISCVExtension::Zabha)) &&
      !Result.has(RISCVExtension::A)) {
    return makeUnexpected(ErrorCode::InvalidInvocation,
                          "RISC-V Zacas and Zabha extensions require the A extension");
  }
  return Result;
}

RISCVSubtargetFeatures RISCVSubtargetFeatures::rv64gc() noexcept {
  return RISCVSubtargetFeatures(extensionBit(RISCVExtension::I) | extensionBit(RISCVExtension::M) |
                                extensionBit(RISCVExtension::A) | extensionBit(RISCVExtension::F) |
                                extensionBit(RISCVExtension::D) | extensionBit(RISCVExtension::C) |
                                extensionBit(RISCVExtension::Zicsr) |
                                extensionBit(RISCVExtension::Zifencei));
}

bool RISCVSubtargetFeatures::has(RISCVExtension Extension) const noexcept {
  if (Extension >= RISCVExtension::Count)
    return false;
  return (Enabled & extensionBit(Extension)) != 0;
}

RISCVSubtarget::RISCVSubtarget(RISCVSubtargetFeatures Features) : Features(Features) {}

RISCVSubtarget::~RISCVSubtarget() = default;

const TargetCallLowering *RISCVSubtarget::getCallLowering() const {
  if (!CallLoweringInfo)
    CallLoweringInfo = std::make_unique<RISCVCallLowering>();
  return CallLoweringInfo.get();
}

InstructionSelector *RISCVSubtarget::getInstructionSelector() const {
  if (!InstSelector)
    InstSelector.reset(createRISCVInstructionSelector(*this, *getRegBankInfo()));
  return InstSelector.get();
}

const LegalizerInfo *RISCVSubtarget::getLegalizerInfo() const {
  if (!Legalizer)
    Legalizer = std::make_unique<RISCVLegalizerInfo>(*this);
  return Legalizer.get();
}

const RISCVRegisterBankInfo *RISCVSubtarget::getRegBankInfo() const {
  if (!RegBankInfo)
    RegBankInfo = std::make_unique<RISCVRegisterBankInfo>();
  return RegBankInfo.get();
}

} // namespace rcc::riscv