1 /*
2  * Copyright (C) 2023 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #include "instruction_set_features_riscv64.h"
18 
19 #include <fstream>
20 #include <sstream>
21 
22 #include "android-base/stringprintf.h"
23 #include "android-base/strings.h"
24 #include "base/logging.h"
25 
26 namespace art HIDDEN {
27 
28 using android::base::StringPrintf;
29 
30 // Basic feature set is rv64gcv_zba_zbb_zbs, aka rv64imafdcv_zba_zbb_zbs.
BasicFeatures()31 constexpr uint32_t BasicFeatures() {
32   return Riscv64InstructionSetFeatures::kExtGeneric |
33          Riscv64InstructionSetFeatures::kExtCompressed |
34          Riscv64InstructionSetFeatures::kExtVector |
35          Riscv64InstructionSetFeatures::kExtZba |
36          Riscv64InstructionSetFeatures::kExtZbb |
37          Riscv64InstructionSetFeatures::kExtZbs;
38 }
39 
FromVariant(const std::string & variant,std::string * error_msg)40 Riscv64FeaturesUniquePtr Riscv64InstructionSetFeatures::FromVariant(
41     const std::string& variant, [[maybe_unused]] std::string* error_msg) {
42   if (variant != "generic") {
43     LOG(WARNING) << "Unexpected CPU variant for Riscv64 using defaults: " << variant;
44   }
45   return Riscv64FeaturesUniquePtr(new Riscv64InstructionSetFeatures(BasicFeatures()));
46 }
47 
FromBitmap(uint32_t bitmap)48 Riscv64FeaturesUniquePtr Riscv64InstructionSetFeatures::FromBitmap(uint32_t bitmap) {
49   return Riscv64FeaturesUniquePtr(new Riscv64InstructionSetFeatures(bitmap));
50 }
51 
FromCppDefines()52 Riscv64FeaturesUniquePtr Riscv64InstructionSetFeatures::FromCppDefines() {
53   // Assume kExtGeneric is always present.
54   uint32_t bits = kExtGeneric;
55 #ifdef __riscv_c
56   bits |= kExtCompressed;
57 #endif
58 #ifdef __riscv_v
59   bits |= kExtVector;
60 #endif
61 #ifdef __riscv_zba
62   bits |= kExtZba;
63 #endif
64 #ifdef __riscv_zbb
65   bits |= kExtZbb;
66 #endif
67 #ifdef __riscv_zbs
68   bits |= kExtZbs;
69 #endif
70   return FromBitmap(bits);
71 }
72 
FromCpuInfo()73 Riscv64FeaturesUniquePtr Riscv64InstructionSetFeatures::FromCpuInfo() {
74   UNIMPLEMENTED(WARNING);
75   return FromCppDefines();
76 }
77 
FromHwcap()78 Riscv64FeaturesUniquePtr Riscv64InstructionSetFeatures::FromHwcap() {
79   UNIMPLEMENTED(WARNING);
80   return FromCppDefines();
81 }
82 
FromAssembly()83 Riscv64FeaturesUniquePtr Riscv64InstructionSetFeatures::FromAssembly() {
84   UNIMPLEMENTED(WARNING);
85   return FromCppDefines();
86 }
87 
FromCpuFeatures()88 Riscv64FeaturesUniquePtr Riscv64InstructionSetFeatures::FromCpuFeatures() {
89   UNIMPLEMENTED(WARNING);
90   return FromCppDefines();
91 }
92 
Equals(const InstructionSetFeatures * other) const93 bool Riscv64InstructionSetFeatures::Equals(const InstructionSetFeatures* other) const {
94   if (InstructionSet::kRiscv64 != other->GetInstructionSet()) {
95     return false;
96   }
97   return bits_ == other->AsRiscv64InstructionSetFeatures()->bits_;
98 }
99 
AsBitmap() const100 uint32_t Riscv64InstructionSetFeatures::AsBitmap() const { return bits_; }
101 
102 static const std::pair<uint32_t, std::string> kExtensionList[] = {
103     {Riscv64InstructionSetFeatures::kExtGeneric, "rv64g"},
104     {Riscv64InstructionSetFeatures::kExtCompressed, "c"},
105     {Riscv64InstructionSetFeatures::kExtVector, "v"},
106     {Riscv64InstructionSetFeatures::kExtZba, "_zba"},
107     {Riscv64InstructionSetFeatures::kExtZbb, "_zbb"},
108     {Riscv64InstructionSetFeatures::kExtZbs, "_zbs"},
109 };
110 
GetFeatureString() const111 std::string Riscv64InstructionSetFeatures::GetFeatureString() const {
112   std::string result = "";
113   for (auto&& [ext_bit, ext_string] : kExtensionList) {
114     if (bits_ & ext_bit) {
115       result += ext_string;
116     }
117   }
118   return result;
119 }
120 
121 std::unique_ptr<const InstructionSetFeatures>
AddFeaturesFromSplitString(const std::vector<std::string> & features,std::string * error_msg) const122 Riscv64InstructionSetFeatures::AddFeaturesFromSplitString(const std::vector<std::string>& features,
123                                                           std::string* error_msg) const {
124   uint32_t bits = bits_;
125   if (!features.empty()) {
126     // There should be only one feature, the ISA string.
127     DCHECK_EQ(features.size(), 1U);
128     std::string_view isa_string = features.front();
129     bits = 0;
130     for (auto&& [ext_bit, ext_string] : kExtensionList) {
131       if (isa_string.substr(0, ext_string.length()) == ext_string) {
132         isa_string.remove_prefix(ext_string.length());
133         bits |= ext_bit;
134       }
135     }
136     if (!isa_string.empty()) {
137       *error_msg = StringPrintf("Unknown extension in ISA string: '%s'", features.front().c_str());
138       return nullptr;
139     }
140     DCHECK(bits & kExtGeneric);
141   }
142   return FromBitmap(bits);
143 }
144 
145 }  // namespace art
146