1 /*
2  * Copyright (C) 2024 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 #ifndef BERBERIS_ASSEMBLER_COMMON_RISCV_H_
18 #define BERBERIS_ASSEMBLER_COMMON_RISCV_H_
19 
20 #include <cstddef>  // std::size_t
21 #include <cstdint>
22 #include <type_traits>  // std::enable_if, std::is_integral
23 
24 #include "berberis/assembler/common.h"
25 #include "berberis/base/bit_util.h"
26 #include "berberis/base/checks.h"
27 
28 namespace berberis {
29 
30 namespace rv32e {
31 
32 class Assembler;
33 
34 }  // namespace rv32e
35 
36 namespace rv32i {
37 
38 class Assembler;
39 
40 }  // namespace rv32i
41 
42 namespace rv64i {
43 
44 class Assembler;
45 
46 }  // namespace rv64i
47 
48 // riscv::Assembler includes implementation of most Risc V assembler instructions.
49 //
50 // RV32 and RV64 assemblers are nearly identical, but difference lies in handling
51 // of some instructions: RV32 uses certain encodings differently to handle compressed
52 // instructions, while RV64 adds some extra instructions to handle 32bit quantities
53 // (*not* 64bit quantities as the name implies, instead there are width-native instructions
54 // and extra 32bit ones for RV64).
55 //
56 // To handle that difference efficiently riscv::Assembler is CRTP class: it's parameterized
57 // by its own descendant and pull certain functions from its implementation.
58 
59 namespace riscv {
60 
61 template <typename DerivedAssemblerType>
62 class Assembler;
63 
64 enum class Condition {
65   kInvalidCondition = -1,
66 
67   kEqual = 0,
68   kNotEqual = 1,
69   kLess = 4,
70   kGreaterEqual = 5,
71   kBelow = 6,
72   kAboveEqual = 7,
73   kAlways = 8,
74   kNever = 9,
75 
76   // aka...
77   kCarry = kBelow,
78   kNotCarry = kAboveEqual,
79   kZero = kEqual,
80   kNotZero = kNotEqual
81 };
82 
83 enum class Csr {
84   kFFlags = 0b00'00'0000'0001,
85   kFrm = 0b00'00'0000'0010,
86   kFCsr = 0b00'00'0000'0011,
87   kVstart = 0b00'00'0000'1000,
88   kVxsat = 0b00'00'0000'1001,
89   kVxrm = 0b00'00'0000'1010,
90   kVcsr = 0b00'00'0000'1111,
91   kCycle = 0b11'00'0000'0000,
92   kVl = 0b11'00'0010'0000,
93   kVtype = 0b11'00'0010'0001,
94   kVlenb = 0b11'00'0010'0010,
95 };
96 
97 enum class Rounding { kRne = 0, kRtz = 1, kRdn = 2, kRup = 3, kRmm = 4, kDyn = 7 };
98 
99 // Immediates are kept in a form ready to be used with emitter.
100 class BImmediate;
101 class CsrImmediate;
102 class IImmediate;
103 using Immediate = IImmediate;
104 class JImmediate;
105 // In RISC V manual shifts are described as using I-format with complex restrictions for which
106 // immediates are accepted and allowed (with parts of what manual classifies as “immediate” used
107 // to determine the actual instruction used and rules which differ between RV32 and RV64!).
108 //
109 // Instead of doing special handling for the instructions in python scripts we just reclassify
110 // these parts of immediate as “opcode” and reclassify these instructions as “Shift32-type” and
111 // “Shift64-type”.
112 //
113 // This also means that the same instructions for RV32 and RV64 would have different types, but
114 // since we don't have a goal to make RV32 a strict subset of RV64 that's acceptable.
115 //
116 // In addition we provide aliases in RV32 and RV64 assemblers to make sure users of assembler may
117 // still use ShiftImmediate and MakeShiftImmediate for native width without thinking about
118 // details of implementation.
119 class Shift32Immediate;
120 class Shift64Immediate;
121 class PImmediate;
122 class SImmediate;
123 class UImmediate;
124 
125 // Don't use templates here to enable implicit conversions.
126 #define BERBERIS_DEFINE_MAKE_IMMEDIATE(Immediate, MakeImmediate)    \
127   constexpr std::optional<Immediate> MakeImmediate(int8_t value);   \
128   constexpr std::optional<Immediate> MakeImmediate(uint8_t value);  \
129   constexpr std::optional<Immediate> MakeImmediate(int16_t value);  \
130   constexpr std::optional<Immediate> MakeImmediate(uint16_t value); \
131   constexpr std::optional<Immediate> MakeImmediate(int32_t value);  \
132   constexpr std::optional<Immediate> MakeImmediate(uint32_t value); \
133   constexpr std::optional<Immediate> MakeImmediate(int64_t value);  \
134   constexpr std::optional<Immediate> MakeImmediate(uint64_t value)
135 BERBERIS_DEFINE_MAKE_IMMEDIATE(BImmediate, MakeBImmediate);
136 BERBERIS_DEFINE_MAKE_IMMEDIATE(CsrImmediate, MakeCsrImmediate);
137 BERBERIS_DEFINE_MAKE_IMMEDIATE(IImmediate, MakeImmediate);
138 BERBERIS_DEFINE_MAKE_IMMEDIATE(IImmediate, MakeIImmediate);
139 BERBERIS_DEFINE_MAKE_IMMEDIATE(JImmediate, MakeJImmediate);
140 BERBERIS_DEFINE_MAKE_IMMEDIATE(PImmediate, MakePImmediate);
141 BERBERIS_DEFINE_MAKE_IMMEDIATE(Shift32Immediate, MakeShift32Immediate);
142 BERBERIS_DEFINE_MAKE_IMMEDIATE(Shift64Immediate, MakeShift64Immediate);
143 BERBERIS_DEFINE_MAKE_IMMEDIATE(SImmediate, MakeSImmediate);
144 BERBERIS_DEFINE_MAKE_IMMEDIATE(UImmediate, MakeUImmediate);
145 #undef BERBERIS_DEFINE_MAKE_IMMEDIATE
146 
147 // RawImmediate is used to bypass checks in constructor. It's not supposed to be used directly.
148 class RawImmediate {
149  private:
150   friend class BImmediate;
151   friend class CsrImmediate;
152   friend class IImmediate;
153   friend class JImmediate;
154   friend class Shift32Immediate;
155   friend class Shift64Immediate;
156   friend class PImmediate;
157   friend class SImmediate;
158   friend class UImmediate;
159   template <typename DerivedAssemblerType>
160   friend class Assembler;
161 
RawImmediate(int32_t value)162   constexpr RawImmediate(int32_t value) : value_(value) {}
163   int32_t value_;
164 };
165 
166 #define BERBERIS_DEFINE_IMMEDIATE_CONSTRUCTOR(Immediate, IntType)  \
167   constexpr Immediate(IntType value) : Immediate(MakeRaw(value)) { \
168     CHECK(AccetableValue(value));                                  \
169   }
170 #define BERBERIS_DEFINE_IMMEDIATE(Immediate, MakeImmediate, kMaskValue, ...)                     \
171   class Immediate {                                                                              \
172    public:                                                                                       \
173     static constexpr int32_t kMask = static_cast<int32_t>(kMaskValue);                           \
174                                                                                                  \
175     BERBERIS_DEFINE_IMMEDIATE_CONSTRUCTOR(Immediate, int8_t)                                     \
176     BERBERIS_DEFINE_IMMEDIATE_CONSTRUCTOR(Immediate, uint8_t)                                    \
177     BERBERIS_DEFINE_IMMEDIATE_CONSTRUCTOR(Immediate, int16_t)                                    \
178     BERBERIS_DEFINE_IMMEDIATE_CONSTRUCTOR(Immediate, uint16_t)                                   \
179     BERBERIS_DEFINE_IMMEDIATE_CONSTRUCTOR(Immediate, int32_t)                                    \
180     BERBERIS_DEFINE_IMMEDIATE_CONSTRUCTOR(Immediate, uint32_t)                                   \
181     BERBERIS_DEFINE_IMMEDIATE_CONSTRUCTOR(Immediate, int64_t)                                    \
182     BERBERIS_DEFINE_IMMEDIATE_CONSTRUCTOR(Immediate, uint64_t)                                   \
183                                                                                                  \
184     constexpr Immediate() : value_(0) {}                                                         \
185                                                                                                  \
186     constexpr int32_t EncodedValue() {                                                           \
187       return value_;                                                                             \
188     }                                                                                            \
189                                                                                                  \
190     friend bool operator==(Immediate const&, Immediate const&) = default;                        \
191                                                                                                  \
192     template <typename DerivedAssemblerType>                                                     \
193     friend class Assembler;                                                                      \
194     friend constexpr std::optional<Immediate> MakeImmediate(int8_t value);                       \
195     friend constexpr std::optional<Immediate> MakeImmediate(uint8_t value);                      \
196     friend constexpr std::optional<Immediate> MakeImmediate(int16_t value);                      \
197     friend constexpr std::optional<Immediate> MakeImmediate(uint16_t value);                     \
198     friend constexpr std::optional<Immediate> MakeImmediate(int32_t value);                      \
199     friend constexpr std::optional<Immediate> MakeImmediate(uint32_t value);                     \
200     friend constexpr std::optional<Immediate> MakeImmediate(int64_t value);                      \
201     friend constexpr std::optional<Immediate> MakeImmediate(uint64_t value);                     \
202     __VA_ARGS__                                                                                  \
203                                                                                                  \
204    private:                                                                                      \
205     constexpr Immediate(RawImmediate raw) : value_(raw.value_) {}                                \
206     /* Return true if value would fit into immediate. */                                         \
207     template <typename IntType>                                                                  \
208     static constexpr bool AccetableValue(IntType value);                                         \
209     /* Make RawImmediate from immediate value. */                                                \
210     /* Note: value is not checked for correctness! Public interface is MakeImmediate factory. */ \
211     template <typename IntType>                                                                  \
212     static constexpr RawImmediate MakeRaw(IntType value);                                        \
213                                                                                                  \
214     int32_t value_;                                                                              \
215   }
216 BERBERIS_DEFINE_IMMEDIATE(
217     BImmediate,
218     MakeBImmediate,
219     0xfe00'0f80,
220     explicit constexpr operator int16_t() const {
221       return ((value_ >> 7) & 0x001e) | ((value_ >> 20) & 0xf7e0) |
222              ((value_ << 4) & 0x0800);
223     }
224     explicit constexpr operator int32_t() const {
225       return ((value_ >> 7) & 0x0000'001e) | ((value_ >> 20) & 0xffff'f7e0) |
226              ((value_ << 4) & 0x0000'0800);
227     }
228     explicit constexpr operator int64_t() const {
229       return ((value_ >> 7) & 0x0000'0000'0000'001e) | ((value_ >> 20) & 0xffff'ffff'ffff'f7e0) |
230              ((value_ << 4) & 0x0000'0000'0000'0800);
231     });
232 BERBERIS_DEFINE_IMMEDIATE(
233     CsrImmediate,
234     MakeCsrImmediate,
235     0x000f'8000,
236     explicit constexpr operator int8_t() const { return value_ >> 15; }
237     explicit constexpr operator uint8_t() const { return value_ >> 15; }
238     explicit constexpr operator int16_t() const { return value_ >> 15; }
239     explicit constexpr operator uint16_t() const { return value_ >> 15; }
240     explicit constexpr operator int32_t() const { return value_ >> 15; }
241     explicit constexpr operator uint32_t() const { return value_ >> 15; }
242     explicit constexpr operator int64_t() const { return value_ >> 15;}
243     explicit constexpr operator uint64_t() const { return value_ >> 15; });
244 BERBERIS_DEFINE_IMMEDIATE(
245     IImmediate, MakeIImmediate, 0xfff0'0000, constexpr IImmediate(SImmediate s_imm);
246 
247     explicit constexpr operator int16_t() const { return value_ >> 20; }
248     explicit constexpr operator int32_t() const { return value_ >> 20; }
249     explicit constexpr operator int64_t() const { return value_ >> 20; }
250 
251     friend SImmediate;);
252 BERBERIS_DEFINE_IMMEDIATE(
253     JImmediate,
254     MakeJImmediate,
255     0xffff'f000,
256     explicit constexpr operator int32_t() const {
257       return ((value_ >> 20) & 0xfff0'07fe) | ((value_ >> 9) & 0x0000'0800) |
258              (value_ & 0x000f'f000);
259     }
260     explicit constexpr operator int64_t() const {
261       return ((value_ >> 20) & 0xffff'ffff'fff0'07fe) | ((value_ >> 9) & 0x0000'0000'0000'0800) |
262              (value_ & 0x0000'0000'000f'f000);
263     });
264 BERBERIS_DEFINE_IMMEDIATE(
265     PImmediate,
266     MakePImmediate,
267     0xfe00'0000,
268     explicit constexpr
269     operator int16_t() const { return value_ >> 20; }
270     explicit constexpr operator int32_t() const { return value_ >> 20; }
271     explicit constexpr operator int64_t() const { return value_ >> 20; });
272 BERBERIS_DEFINE_IMMEDIATE(
273     Shift32Immediate,
274     MakeShift32Immediate,
275     0x01f0'0000,
276     explicit constexpr operator int8_t() const { return value_ >> 20; }
277     explicit constexpr operator uint8_t() const { return value_ >> 20; }
278     explicit constexpr operator int16_t() const { return value_ >> 20; }
279     explicit constexpr operator uint16_t() const { return value_ >> 20; }
280     explicit constexpr operator int32_t() const { return value_ >> 20; }
281     explicit constexpr operator uint32_t() const { return value_ >> 20; }
282     explicit constexpr operator int64_t() const { return value_ >> 20;}
283     explicit constexpr operator uint64_t() const { return value_ >> 20; });
284 BERBERIS_DEFINE_IMMEDIATE(
285     Shift64Immediate,
286     MakeShift64Immediate,
287     0x03f0'0000,
288     explicit constexpr operator int8_t() const { return value_ >> 20; }
289     explicit constexpr operator uint8_t() const { return value_ >> 20; }
290     explicit constexpr operator int16_t() const { return value_ >> 20; }
291     explicit constexpr operator uint16_t() const { return value_ >> 20; }
292     explicit constexpr operator int32_t() const { return value_ >> 20; }
293     explicit constexpr operator uint32_t() const { return value_ >> 20; }
294     explicit constexpr operator int64_t() const { return value_ >> 20;}
295     explicit constexpr operator uint64_t() const { return value_ >> 20; });
296 BERBERIS_DEFINE_IMMEDIATE(
297     SImmediate, MakeSImmediate, 0xfe00'0f80, constexpr SImmediate(Immediate imm);
298 
299     explicit constexpr operator int16_t() const {
300       return ((value_ >> 7) & 0x0000'001f) | (value_ >> 20);
301     }
302     explicit constexpr operator int32_t() const {
303       return ((value_ >> 7) & 0x0000'001f) | (value_ >> 20);
304     }
305     explicit constexpr operator int64_t() const {
306       return ((value_ >> 7) & 0x0000'001f) | (value_ >> 20);
307     }
308 
309     friend class IImmediate;);
310 BERBERIS_DEFINE_IMMEDIATE(
311     UImmediate,
312     MakeUImmediate,
313     0xffff'f000,
314     explicit constexpr operator int32_t() const { return value_; }
315     explicit constexpr operator int64_t() const { return value_; });
316 #undef BERBERIS_DEFINE_IMMEDIATE
317 #undef BERBERIS_DEFINE_IMMEDIATE_CONSTRUCTOR
318 
IImmediate(SImmediate s_imm)319 constexpr IImmediate::IImmediate(SImmediate s_imm)
320     : value_((s_imm.value_ & 0xfe00'0000) | ((s_imm.value_ & 0x0000'0f80) << 13)) {}
321 
SImmediate(Immediate imm)322 constexpr SImmediate::SImmediate(Immediate imm)
323     : value_((imm.value_ & 0xfe00'0000) | ((imm.value_ & 0x01f0'0000) >> 13)) {}
324 
325 #define BERBERIS_DEFINE_MAKE_IMMEDIATE(Immediate, MakeImmediate, IntType) \
326   constexpr std::optional<Immediate> MakeImmediate(IntType value) {       \
327     if (!Immediate::AccetableValue(value)) {                              \
328       return std::nullopt;                                                \
329     }                                                                     \
330     return Immediate{Immediate::MakeRaw(value)};                          \
331   }
332 #define BERBERIS_DEFINE_MAKE_IMMEDIATE_SET(Immediate, MakeImmediate) \
333   BERBERIS_DEFINE_MAKE_IMMEDIATE(Immediate, MakeImmediate, int8_t)   \
334   BERBERIS_DEFINE_MAKE_IMMEDIATE(Immediate, MakeImmediate, uint8_t)  \
335   BERBERIS_DEFINE_MAKE_IMMEDIATE(Immediate, MakeImmediate, int16_t)  \
336   BERBERIS_DEFINE_MAKE_IMMEDIATE(Immediate, MakeImmediate, uint16_t) \
337   BERBERIS_DEFINE_MAKE_IMMEDIATE(Immediate, MakeImmediate, int32_t)  \
338   BERBERIS_DEFINE_MAKE_IMMEDIATE(Immediate, MakeImmediate, uint32_t) \
339   BERBERIS_DEFINE_MAKE_IMMEDIATE(Immediate, MakeImmediate, int64_t)  \
340   BERBERIS_DEFINE_MAKE_IMMEDIATE(Immediate, MakeImmediate, uint64_t)
BERBERIS_DEFINE_MAKE_IMMEDIATE_SET(BImmediate,MakeBImmediate)341 BERBERIS_DEFINE_MAKE_IMMEDIATE_SET(BImmediate, MakeBImmediate)
342 BERBERIS_DEFINE_MAKE_IMMEDIATE_SET(CsrImmediate, MakeCsrImmediate)
343 BERBERIS_DEFINE_MAKE_IMMEDIATE_SET(IImmediate, MakeIImmediate)
344 BERBERIS_DEFINE_MAKE_IMMEDIATE_SET(JImmediate, MakeJImmediate)
345 BERBERIS_DEFINE_MAKE_IMMEDIATE_SET(PImmediate, MakePImmediate)
346 BERBERIS_DEFINE_MAKE_IMMEDIATE_SET(Shift32Immediate, MakeShift32Immediate)
347 BERBERIS_DEFINE_MAKE_IMMEDIATE_SET(Shift64Immediate, MakeShift64Immediate)
348 BERBERIS_DEFINE_MAKE_IMMEDIATE_SET(SImmediate, MakeSImmediate)
349 BERBERIS_DEFINE_MAKE_IMMEDIATE_SET(UImmediate, MakeUImmediate)
350 #undef BERBERIS_DEFINE_MAKE_IMMEDIATE_SET
351 #undef BERBERIS_DEFINE_MAKE_IMMEDIATE
352 
353 #define BERBERIS_DEFINE_MAKE_IMMEDIATE(IntType)                     \
354   constexpr std::optional<Immediate> MakeImmediate(IntType value) { \
355     return MakeIImmediate(value);                                   \
356   }
357 BERBERIS_DEFINE_MAKE_IMMEDIATE(int8_t)
358 BERBERIS_DEFINE_MAKE_IMMEDIATE(uint8_t)
359 BERBERIS_DEFINE_MAKE_IMMEDIATE(int16_t)
360 BERBERIS_DEFINE_MAKE_IMMEDIATE(uint16_t)
361 BERBERIS_DEFINE_MAKE_IMMEDIATE(int32_t)
362 BERBERIS_DEFINE_MAKE_IMMEDIATE(uint32_t)
363 BERBERIS_DEFINE_MAKE_IMMEDIATE(int64_t)
364 BERBERIS_DEFINE_MAKE_IMMEDIATE(uint64_t)
365 #undef BERBERIS_DEFINE_MAKE_IMMEDIATE
366 
367 // Return true if value would fit into B-immediate.
368 template <typename IntType>
369 constexpr bool BImmediate::AccetableValue(IntType value) {
370   static_assert(std::is_integral_v<IntType>);
371   static_assert(sizeof(IntType) <= sizeof(uint64_t));
372   // B-immediate accepts 12 bits, but encodes signed even values, that's why we only may accept
373   // low 12 bits of any unsigned value.
374   // Encode mask as the largest accepted value plus one and cut it to IntType size.
375   constexpr uint64_t kUnsigned64bitInputMask = 0xffff'ffff'ffff'f001;
376   if constexpr (!std::is_signed_v<IntType>) {
377     constexpr IntType kUnsignedInputMask = static_cast<IntType>(kUnsigned64bitInputMask);
378     return static_cast<IntType>(value & kUnsignedInputMask) == IntType{0};
379   } else {
380     // For signed values we also accept the same values as for unsigned case, but also accept
381     // value that have all bits in am kUnsignedInputMask set.
382     // B-immediate compresses these into one single sign bit, but lowest bit have to be zero.
383     constexpr IntType kSignedInputMask = static_cast<IntType>(kUnsigned64bitInputMask);
384     return static_cast<IntType>(value & kSignedInputMask) == IntType{0} ||
385            static_cast<IntType>(value & kSignedInputMask) == (kSignedInputMask & ~int64_t{1});
386   }
387 }
388 
389 // Return true if value would fit into Csr-immediate.
390 template <typename IntType>
AccetableValue(IntType value)391 constexpr bool CsrImmediate::AccetableValue(IntType value) {
392   static_assert(std::is_integral_v<IntType>);
393   static_assert(sizeof(IntType) <= sizeof(uint64_t));
394   // Csr immediate is unsigned immediate with possible values between 0 and 31.
395   // If we make value unsigned negative numbers would become numbers >127 and would be rejected.
396   return std::make_unsigned_t<IntType>(value) < 32;
397 }
398 
399 // Return true if value would fit into immediate.
400 template <typename IntType>
401 constexpr bool Immediate::AccetableValue(IntType value) {
402   static_assert(std::is_integral_v<IntType>);
403   static_assert(sizeof(IntType) <= sizeof(uint64_t));
404   // I-immediate accepts 12 bits, but encodes signed values, that's why we only may accept low
405   // 11 bits of any unsigned value.
406   // Encode mask as the largest accepted value plus one and cut it to IntType size.
407   constexpr uint64_t kUnsigned64bitInputMask = 0xffff'ffff'ffff'f800;
408   if constexpr (!std::is_signed_v<IntType>) {
409     constexpr IntType kUnsignedInputMask = static_cast<IntType>(kUnsigned64bitInputMask);
410     return static_cast<IntType>(value & kUnsignedInputMask) == IntType{0};
411   } else {
412     // For signed values we accept the same values as for unsigned case, but also accept
413     // values that have all bits in kUnsignedInputMask set.
414     // I-immediate compresses these into one single sign bit.
415     constexpr IntType kSignedInputMask = static_cast<IntType>(kUnsigned64bitInputMask);
416     return static_cast<IntType>(value & kSignedInputMask) == IntType{0} ||
417            static_cast<IntType>(value & kSignedInputMask) == kSignedInputMask;
418   }
419 }
420 
421 // Return true if value would fit into J-immediate.
422 template <typename IntType>
423 constexpr bool JImmediate::AccetableValue(IntType value) {
424   static_assert(std::is_integral_v<IntType>);
425   static_assert(sizeof(IntType) <= sizeof(uint64_t));
426   // J-immediate accepts 20 bits, but encodes signed even values, that's why we only may accept
427   // bits from 1 to 19 of any unsigned value. Encode mask as the largest accepted value plus 1 and
428   // cut it to IntType size.
429   constexpr uint64_t kUnsigned64bitInputMask = 0xffff'ffff'fff0'0001;
430   if constexpr (!std::is_signed_v<IntType>) {
431     constexpr IntType kUnsignedInputMask = static_cast<IntType>(kUnsigned64bitInputMask);
432     return static_cast<IntType>(value & kUnsignedInputMask) == IntType{0};
433   } else {
434     // For signed values we accept the same values as for unsigned case, but also accept
435     // value that have all bits in kUnsignedInputMask set except zero bit (which is zero).
436     // J-immediate compresses these into one single sign bit, but lowest bit have to be zero.
437     constexpr IntType kSignedInputMask = static_cast<IntType>(kUnsigned64bitInputMask);
438     return static_cast<IntType>(value & kSignedInputMask) == IntType{0} ||
439            static_cast<IntType>(value & kSignedInputMask) == (kSignedInputMask & ~int64_t{1});
440   }
441 }
442 
443 // Return true if value would fit into P-immediate.
444 template <typename IntType>
445 constexpr bool PImmediate::AccetableValue(IntType value) {
446   static_assert(std::is_integral_v<IntType>);
447   static_assert(sizeof(IntType) <= sizeof(uint64_t));
448   // P-immediate accepts 7 bits, but encodes only values divisible by 32, that's why we only may
449   // accept bits from 5 to 10 of any unsigned value. Encode mask as the largest accepted value
450   // plus 31 and cut it to IntType size.
451   constexpr uint64_t kUnsigned64bitInputMask = 0xffff'ffff'ffff'f81f;
452   if constexpr (!std::is_signed_v<IntType>) {
453     constexpr IntType kUnsignedInputMask = static_cast<IntType>(kUnsigned64bitInputMask);
454     return static_cast<IntType>(value & kUnsignedInputMask) == IntType{0};
455   } else {
456     // For signed values we accept the same values as for unsigned case, but also accept
457     // value that have all bits in kUnsignedInputMask set except the lowest 5 bits (which are
458     // zero). P-immediate compresses these into one single sign bit, but lowest bits have to be
459     // zero.
460     constexpr IntType kSignedInputMask = static_cast<IntType>(kUnsigned64bitInputMask);
461     return static_cast<IntType>(value & kSignedInputMask) == IntType{0} ||
462            static_cast<IntType>(value & kSignedInputMask) == (kSignedInputMask & ~int64_t{0x1f});
463   }
464 }
465 
466 // Return true if value would fit into Shift32-immediate.
467 template <typename IntType>
468 constexpr bool Shift32Immediate::AccetableValue(IntType value) {
469   static_assert(std::is_integral_v<IntType>);
470   static_assert(sizeof(IntType) <= sizeof(uint64_t));
471   // Shift32 immediate is unsigned immediate with possible values between 0 and 31.
472   // If we make value unsigned negative numbers would become numbers >127 and would be rejected.
473   return std::make_unsigned_t<IntType>(value) < 32;
474 }
475 
476 // Return true if value would fit into Shift64-immediate.
477 template <typename IntType>
478 constexpr bool Shift64Immediate::AccetableValue(IntType value) {
479   static_assert(std::is_integral_v<IntType>);
480   static_assert(sizeof(IntType) <= sizeof(uint64_t));
481   // Shift64 immediate is unsigned immediate with possible values between 0 and 63.
482   // If we make value unsigned negative numbers would become numbers >127 and would be rejected.
483   return std::make_unsigned_t<IntType>(value) < 64;
484 }
485 
486 // Immediate (I-immediate in RISC V documentation) and S-Immediate are siblings: they encode
487 // the same values but in a different way.
488 // AccetableValue are the same for that reason, but MakeRaw are different.
489 template <typename IntType>
490 constexpr bool SImmediate::AccetableValue(IntType value) {
491   return Immediate::AccetableValue(value);
492 }
493 
494 // Return true if value would fit into U-immediate.
495 template <typename IntType>
496 constexpr bool UImmediate::AccetableValue(IntType value) {
497   static_assert(std::is_integral_v<IntType>);
498   static_assert(sizeof(IntType) <= sizeof(uint64_t));
499   // U-immediate accepts 20 bits, but encodes only values divisible by 4096, that's why we only
500   // may accept bits from 12 to 30 of any unsigned value. Encode mask as the largest accepted
501   // value plus 4095 and cut it to IntType size.
502   constexpr uint64_t kUnsigned64bitInputMask = 0xffff'ffff'8000'0fff;
503   if constexpr (!std::is_signed_v<IntType>) {
504     constexpr IntType kUnsignedInputMask = static_cast<IntType>(kUnsigned64bitInputMask);
505     return static_cast<IntType>(value & kUnsignedInputMask) == IntType{0};
506   } else {
507     // For signed values we accept the same values as for unsigned case, but also accept
508     // value that have all bits in kUnsignedInputMask set except lower 12 bits (which are zero).
509     // U-immediate compresses these into one single sign bit, but lowest bits have to be zero.
510     constexpr IntType kSignedInputMask = static_cast<IntType>(kUnsigned64bitInputMask);
511     return static_cast<IntType>(value & kSignedInputMask) == IntType{0} ||
512            static_cast<IntType>(value & kSignedInputMask) == (kSignedInputMask & ~int64_t{0xfff});
513   }
514 }
515 
516 // Make RawImmediate from immediate value.
517 // Note: value is not checked for correctness here! Public interface is MakeBImmediate factory.
518 template <typename IntType>
519 constexpr RawImmediate BImmediate::MakeRaw(IntType value) {
520   static_assert(std::is_integral_v<IntType>);
521   static_assert(sizeof(IntType) <= sizeof(uint64_t));
522   // Note: we have to convert type to int32_t before processing it! Otherwise we would produce
523   // incorrect value for negative inputs since one single input sign in the small immediate would
524   // turn into many bits in the insruction.
525   return (static_cast<int32_t>(value) & static_cast<int32_t>(0x8000'0000)) |
526          ((static_cast<int32_t>(value) & static_cast<int32_t>(0x0000'0800)) >> 4) |
527          ((static_cast<int32_t>(value) & static_cast<int32_t>(0x0000'001f)) << 7) |
528          ((static_cast<int32_t>(value) & static_cast<int32_t>(0x0000'07e0)) << 20);
529 }
530 
531 // Make RawImmediate from immediate value.
532 // Note: value is not checked for correctness here! Public interface is MakeImmediate factory.
533 template <typename IntType>
534 constexpr RawImmediate CsrImmediate::MakeRaw(IntType value) {
535   static_assert(std::is_integral_v<IntType>);
536   static_assert(sizeof(IntType) <= sizeof(uint64_t));
537   // Note: this is correct if input value is between 0 and 31, but that would be checked in
538   // MakeCsrImmediate.
539   return static_cast<int32_t>(value) << 15;
540 }
541 
542 // Make RawImmediate from immediate value.
543 // Note: value is not checked for correctness here! Public interface is MakeImmediate factory.
544 template <typename IntType>
545 constexpr RawImmediate Immediate::MakeRaw(IntType value) {
546   static_assert(std::is_integral_v<IntType>);
547   static_assert(sizeof(IntType) <= sizeof(uint64_t));
548   return static_cast<int32_t>(value) << 20;
549 }
550 
551 // Make RawImmediate from immediate value.
552 // Note: value is not checked for correctness here! Public interface is MakeJImmediate factory.
553 template <typename IntType>
554 constexpr RawImmediate JImmediate::MakeRaw(IntType value) {
555   static_assert(std::is_integral_v<IntType>);
556   static_assert(sizeof(IntType) <= sizeof(uint64_t));
557   // Note: we have to convert type to int32_t before processing it! Otherwise we would produce
558   // incorrect value for negative inputs since one single input sign in the small immediate would
559   // turn into many bits in the insruction.
560   return (static_cast<int32_t>(value) & static_cast<int32_t>(0x800f'f000)) |
561          ((static_cast<int32_t>(value) & static_cast<int32_t>(0x0000'0800)) << 9) |
562          ((static_cast<int32_t>(value) & static_cast<int32_t>(0x0000'07fe)) << 20);
563 }
564 
565 // Make RawImmediate from immediate value.
566 // Note: value is not checked for correctness here! Public interface is MakeImmediate factory.
567 template <typename IntType>
MakeRaw(IntType value)568 constexpr RawImmediate PImmediate::MakeRaw(IntType value) {
569   static_assert(std::is_integral_v<IntType>);
570   static_assert(sizeof(IntType) <= sizeof(uint64_t));
571   // Note: this is correct if input value is divisible by 32, but that would be checked in
572   // MakePImmediate.
573   return static_cast<int32_t>(value) << 20;
574 }
575 
576 // Make RawImmediate from immediate value.
577 // Note: value is not checked for correctness here! Public interface is MakeImmediate factory.
578 template <typename IntType>
MakeRaw(IntType value)579 constexpr RawImmediate Shift32Immediate::MakeRaw(IntType value) {
580   static_assert(std::is_integral_v<IntType>);
581   static_assert(sizeof(IntType) <= sizeof(uint64_t));
582   // Note: this is correct if input value is between 0 and 31, but that would be checked in
583   // MakeShift32Immediate.
584   return static_cast<int32_t>(value) << 20;
585 }
586 
587 // Make RawImmediate from immediate value.
588 // Note: value is not checked for correctness here! Public interface is MakeImmediate factory.
589 template <typename IntType>
MakeRaw(IntType value)590 constexpr RawImmediate Shift64Immediate::MakeRaw(IntType value) {
591   static_assert(std::is_integral_v<IntType>);
592   static_assert(sizeof(IntType) <= sizeof(uint64_t));
593   // Note: this is only correct if input value is between 0 and 63, but that would be checked in
594   // MakeShift64Immediate.
595   return static_cast<int32_t>(value) << 20;
596 }
597 
598 // Make RawImmediate from immediate value.
599 // Note: value is not checked for correctness here! Public interface is MakeSImmediate factory.
600 template <typename IntType>
MakeRaw(IntType value)601 constexpr RawImmediate SImmediate::MakeRaw(IntType value) {
602   static_assert(std::is_integral_v<IntType>);
603   static_assert(sizeof(IntType) <= sizeof(uint64_t));
604   // Here, because we are only using platforms with 32bit ints conversion to 32bit signed int may
605   // happen both before masking and after but we are doing it before for consistency.
606   return ((static_cast<int32_t>(value) & static_cast<int32_t>(0xffff'ffe0)) << 20) |
607          ((static_cast<int32_t>(value) & static_cast<int32_t>(0x0000'001f)) << 7);
608 }
609 
610 // Make RawImmediate from immediate value.
611 // Note: value is not checked for correctness here! Public interface is MakeImmediate factory.
612 template <typename IntType>
MakeRaw(IntType value)613 constexpr RawImmediate UImmediate::MakeRaw(IntType value) {
614   static_assert(std::is_integral_v<IntType>);
615   static_assert(sizeof(IntType) <= sizeof(uint64_t));
616   // Note: this is only correct if input value is between divisible by 4096 , but that would be
617   // checked in MakeUImmediate.
618   return static_cast<int32_t>(value);
619 }
620 
621 template <typename DerivedAssemblerType>
622 class Assembler : public AssemblerBase {
623  public:
Assembler(MachineCode * code)624   explicit Assembler(MachineCode* code) : AssemblerBase(code) {}
625 
626   using Condition = riscv::Condition;
627   using Csr = riscv::Csr;
628   using Rounding = riscv::Rounding;
629 
630   class Register {
631    public:
632     constexpr bool operator==(const Register& reg) const { return num_ == reg.num_; }
633     constexpr bool operator!=(const Register& reg) const { return num_ != reg.num_; }
GetPhysicalIndex()634     constexpr uint8_t GetPhysicalIndex() { return num_; }
ValueForFmtSpec(Register value)635     friend constexpr uint8_t ValueForFmtSpec(Register value) { return value.num_; }
636     friend class Assembler<DerivedAssemblerType>;
637     friend class rv32e::Assembler;
638     friend class rv32i::Assembler;
639     friend class rv64i::Assembler;
640 
641    private:
Register(uint8_t num)642     explicit constexpr Register(uint8_t num) : num_(num) {}
643     uint8_t num_;
644   };
645 
646   // Note: register x0, technically, can be specified in assembler even if it doesn't exist
647   // as separate hardware register. It even have alias “zero” even in clang assembler.
648   static constexpr Register x0{0};
649   static constexpr Register x1{1};
650   static constexpr Register x2{2};
651   static constexpr Register x3{3};
652   static constexpr Register x4{4};
653   static constexpr Register x5{5};
654   static constexpr Register x6{6};
655   static constexpr Register x7{7};
656   static constexpr Register x8{8};
657   static constexpr Register x9{9};
658   static constexpr Register x10{10};
659   static constexpr Register x11{11};
660   static constexpr Register x12{12};
661   static constexpr Register x13{13};
662   static constexpr Register x14{14};
663   static constexpr Register x15{15};
664   static constexpr Register x16{16};
665   static constexpr Register x17{17};
666   static constexpr Register x18{18};
667   static constexpr Register x19{19};
668   static constexpr Register x20{20};
669   static constexpr Register x21{21};
670   static constexpr Register x22{22};
671   static constexpr Register x23{23};
672   static constexpr Register x24{24};
673   static constexpr Register x25{25};
674   static constexpr Register x26{26};
675   static constexpr Register x27{27};
676   static constexpr Register x28{28};
677   static constexpr Register x29{29};
678   static constexpr Register x30{30};
679   static constexpr Register x31{31};
680 
681   // Aliases
682   static constexpr Register no_register{0x80};
683   static constexpr Register zero{0};
684 
685   class FpRegister {
686    public:
687     constexpr bool operator==(const FpRegister& reg) const { return num_ == reg.num_; }
688     constexpr bool operator!=(const FpRegister& reg) const { return num_ != reg.num_; }
GetPhysicalIndex()689     constexpr uint8_t GetPhysicalIndex() { return num_; }
ValueForFmtSpec(FpRegister value)690     friend constexpr uint8_t ValueForFmtSpec(FpRegister value) { return value.num_; }
691     friend class Assembler<DerivedAssemblerType>;
692 
693    private:
FpRegister(uint8_t num)694     explicit constexpr FpRegister(uint8_t num) : num_(num) {}
695     uint8_t num_;
696   };
697 
698   static constexpr FpRegister f0{0};
699   static constexpr FpRegister f1{1};
700   static constexpr FpRegister f2{2};
701   static constexpr FpRegister f3{3};
702   static constexpr FpRegister f4{4};
703   static constexpr FpRegister f5{5};
704   static constexpr FpRegister f6{6};
705   static constexpr FpRegister f7{7};
706   static constexpr FpRegister f8{8};
707   static constexpr FpRegister f9{9};
708   static constexpr FpRegister f10{10};
709   static constexpr FpRegister f11{11};
710   static constexpr FpRegister f12{12};
711   static constexpr FpRegister f13{13};
712   static constexpr FpRegister f14{14};
713   static constexpr FpRegister f15{15};
714   static constexpr FpRegister f16{16};
715   static constexpr FpRegister f17{17};
716   static constexpr FpRegister f18{18};
717   static constexpr FpRegister f19{19};
718   static constexpr FpRegister f20{20};
719   static constexpr FpRegister f21{21};
720   static constexpr FpRegister f22{22};
721   static constexpr FpRegister f23{23};
722   static constexpr FpRegister f24{24};
723   static constexpr FpRegister f25{25};
724   static constexpr FpRegister f26{26};
725   static constexpr FpRegister f27{27};
726   static constexpr FpRegister f28{28};
727   static constexpr FpRegister f29{29};
728   static constexpr FpRegister f30{30};
729   static constexpr FpRegister f31{31};
730 
731   // ABI
732   static constexpr FpRegister ft0{0};
733   static constexpr FpRegister ft1{1};
734   static constexpr FpRegister ft2{2};
735   static constexpr FpRegister ft3{3};
736   static constexpr FpRegister ft4{4};
737   static constexpr FpRegister ft5{5};
738   static constexpr FpRegister ft6{6};
739   static constexpr FpRegister ft7{7};
740   static constexpr FpRegister fs0{8};
741   static constexpr FpRegister fs1{9};
742   static constexpr FpRegister fa0{10};
743   static constexpr FpRegister fa1{11};
744   static constexpr FpRegister fa2{12};
745   static constexpr FpRegister fa3{13};
746   static constexpr FpRegister fa4{14};
747   static constexpr FpRegister fa5{15};
748   static constexpr FpRegister fa6{16};
749   static constexpr FpRegister fa7{17};
750   static constexpr FpRegister fs2{18};
751   static constexpr FpRegister fs3{19};
752   static constexpr FpRegister fs4{20};
753   static constexpr FpRegister fs5{21};
754   static constexpr FpRegister fs6{22};
755   static constexpr FpRegister fs7{23};
756   static constexpr FpRegister fs8{24};
757   static constexpr FpRegister fs9{25};
758   static constexpr FpRegister fs10{26};
759   static constexpr FpRegister fs11{27};
760   static constexpr FpRegister ft8{28};
761   static constexpr FpRegister ft9{29};
762   static constexpr FpRegister ft10{30};
763   static constexpr FpRegister ft11{31};
764 
765   class VRegister {
766    public:
767     constexpr bool operator==(const VRegister& reg) const { return num_ == reg.num_; }
768     constexpr bool operator!=(const VRegister& reg) const { return num_ != reg.num_; }
GetPhysicalIndex()769     constexpr uint8_t GetPhysicalIndex() { return num_; }
ValueForFmtSpec(VRegister value)770     friend constexpr uint8_t ValueForFmtSpec(VRegister value) { return value.num_; }
771     friend class Assembler<DerivedAssemblerType>;
772 
773    private:
VRegister(uint8_t num)774     explicit constexpr VRegister(uint8_t num) : num_(num) {}
775     uint8_t num_;
776   };
777 
778   static constexpr VRegister no_v_register{0x80};
779   static constexpr VRegister v0{0};
780   static constexpr VRegister v1{1};
781   static constexpr VRegister v2{2};
782   static constexpr VRegister v3{3};
783   static constexpr VRegister v4{4};
784   static constexpr VRegister v5{5};
785   static constexpr VRegister v6{6};
786   static constexpr VRegister v7{7};
787   static constexpr VRegister v8{8};
788   static constexpr VRegister v9{9};
789   static constexpr VRegister v10{10};
790   static constexpr VRegister v11{11};
791   static constexpr VRegister v12{12};
792   static constexpr VRegister v13{13};
793   static constexpr VRegister v14{14};
794   static constexpr VRegister v15{15};
795   static constexpr VRegister v16{16};
796   static constexpr VRegister v17{17};
797   static constexpr VRegister v18{18};
798   static constexpr VRegister v19{19};
799   static constexpr VRegister v20{20};
800   static constexpr VRegister v21{21};
801   static constexpr VRegister v22{22};
802   static constexpr VRegister v23{23};
803   static constexpr VRegister v24{24};
804   static constexpr VRegister v25{25};
805   static constexpr VRegister v26{26};
806   static constexpr VRegister v27{27};
807   static constexpr VRegister v28{28};
808   static constexpr VRegister v29{29};
809   static constexpr VRegister v30{30};
810   static constexpr VRegister v31{31};
811 
812   template <typename RegisterType, typename ImmediateType>
813   struct Operand {
814     RegisterType base{0};
815     ImmediateType disp = 0;
816   };
817 
818   using BImmediate = riscv::BImmediate;
819   using CsrImmediate = riscv::CsrImmediate;
820   using IImmediate = riscv::IImmediate;
821   using Immediate = riscv::Immediate;
822   using JImmediate = riscv::JImmediate;
823   using Shift32Immediate = riscv::Shift32Immediate;
824   using Shift64Immediate = riscv::Shift64Immediate;
825   using PImmediate = riscv::PImmediate;
826   using SImmediate = riscv::SImmediate;
827   using UImmediate = riscv::UImmediate;
828 
829   // Don't use templates here to enable implicit conversions.
830 #define BERBERIS_DEFINE_MAKE_IMMEDIATE(Immediate, MakeImmediate)            \
831   static constexpr std::optional<Immediate> MakeImmediate(int8_t value) {   \
832     return riscv::MakeImmediate(value);                                     \
833   }                                                                         \
834   static constexpr std::optional<Immediate> MakeImmediate(uint8_t value) {  \
835     return riscv::MakeImmediate(value);                                     \
836   }                                                                         \
837   static constexpr std::optional<Immediate> MakeImmediate(int16_t value) {  \
838     return riscv::MakeImmediate(value);                                     \
839   }                                                                         \
840   static constexpr std::optional<Immediate> MakeImmediate(uint16_t value) { \
841     return riscv::MakeImmediate(value);                                     \
842   }                                                                         \
843   static constexpr std::optional<Immediate> MakeImmediate(int32_t value) {  \
844     return riscv::MakeImmediate(value);                                     \
845   }                                                                         \
846   static constexpr std::optional<Immediate> MakeImmediate(uint32_t value) { \
847     return riscv::MakeImmediate(value);                                     \
848   }                                                                         \
849   static constexpr std::optional<Immediate> MakeImmediate(int64_t value) {  \
850     return riscv::MakeImmediate(value);                                     \
851   }                                                                         \
852   static constexpr std::optional<Immediate> MakeImmediate(uint64_t value) { \
853     return riscv::MakeImmediate(value);                                     \
854   }
BERBERIS_DEFINE_MAKE_IMMEDIATE(BImmediate,MakeBImmediate)855   BERBERIS_DEFINE_MAKE_IMMEDIATE(BImmediate, MakeBImmediate)
856   BERBERIS_DEFINE_MAKE_IMMEDIATE(CsrImmediate, MakeCsrImmediate)
857   BERBERIS_DEFINE_MAKE_IMMEDIATE(IImmediate, MakeImmediate)
858   BERBERIS_DEFINE_MAKE_IMMEDIATE(IImmediate, MakeIImmediate)
859   BERBERIS_DEFINE_MAKE_IMMEDIATE(JImmediate, MakeJImmediate)
860   BERBERIS_DEFINE_MAKE_IMMEDIATE(PImmediate, MakePImmediate)
861   BERBERIS_DEFINE_MAKE_IMMEDIATE(Shift32Immediate, MakeShift32Immediate)
862   BERBERIS_DEFINE_MAKE_IMMEDIATE(Shift64Immediate, MakeShift64Immediate)
863   BERBERIS_DEFINE_MAKE_IMMEDIATE(SImmediate, MakeSImmediate)
864   BERBERIS_DEFINE_MAKE_IMMEDIATE(UImmediate, MakeUImmediate)
865 #undef BERBERIS_DEFINE_MAKE_IMMEDIATE
866 
867   // Macro operations.
868   void Finalize() { ResolveJumps(); }
869 
870   void ResolveJumps();
871 
872   // Instructions.
873 #include "berberis/assembler/gen_assembler_common_riscv-inl.h"  // NOLINT generated file!
874 
875  protected:
876   // Information about operands.
877   template <typename OperandType, typename = void>
878   class OperandInfo;
879 
880   // Wrapped operand with information of where in the encoded instruction should it be placed.
881   template <typename OperandMarker, typename RegisterType>
882   struct RegisterOperand {
EncodeImmediateRegisterOperand883     constexpr int32_t EncodeImmediate() {
884       return value.GetPhysicalIndex()
885              << OperandInfo<RegisterOperand<OperandMarker, RegisterType>>::kOffset;
886     }
887 
888     RegisterType value;
889   };
890 
891   struct ConditionOperand {
EncodeImmediateConditionOperand892     constexpr int32_t EncodeImmediate() {
893       return static_cast<int32_t>(value) << OperandInfo<ConditionOperand>::kOffset;
894     }
895 
896     Condition value;
897   };
898 
899   struct RoundingOperand {
EncodeImmediateRoundingOperand900     constexpr int32_t EncodeImmediate() {
901       return static_cast<int32_t>(value) << OperandInfo<RoundingOperand>::kOffset;
902     }
903 
904     Rounding value;
905   };
906 
907   // Operand class  markers. Note, these classes shouldn't ever be instantiated, they are just
908   // used to carry information about operands.
909   class RdMarker;
910   class Rs1Marker;
911   class Rs2Marker;
912   class Rs3Marker;
913 
914   template <typename RegisterType>
915   class OperandInfo<RegisterOperand<RdMarker, RegisterType>> {
916    public:
917     static constexpr bool IsImmediate = false;
918     static constexpr uint8_t kOffset = 7;
919     static constexpr uint32_t kMask = 0x0000'0f80;
920   };
921 
922   template <>
923   class OperandInfo<ConditionOperand> {
924    public:
925     static constexpr bool IsImmediate = false;
926     static constexpr uint8_t kOffset = 12;
927     static constexpr uint32_t kMask = 0x0000'7000;
928   };
929 
930   template <>
931   class OperandInfo<RoundingOperand> {
932    public:
933     static constexpr bool IsImmediate = false;
934     static constexpr uint8_t kOffset = 12;
935     static constexpr uint32_t kMask = 0x0000'7000;
936   };
937 
938   template <typename RegisterType>
939   class OperandInfo<RegisterOperand<Rs1Marker, RegisterType>> {
940    public:
941     static constexpr bool IsImmediate = false;
942     static constexpr uint8_t kOffset = 15;
943     static constexpr uint32_t kMask = 0x000f'8000;
944   };
945 
946   template <typename RegisterType>
947   class OperandInfo<RegisterOperand<Rs2Marker, RegisterType>> {
948    public:
949     static constexpr bool IsImmediate = false;
950     static constexpr uint8_t kOffset = 20;
951     static constexpr uint32_t kMask = 0x01f0'0000;
952   };
953 
954   template <typename RegisterType>
955   class OperandInfo<RegisterOperand<Rs3Marker, RegisterType>> {
956    public:
957     static constexpr bool IsImmediate = false;
958     static constexpr uint8_t kOffset = 27;
959     static constexpr uint32_t kMask = 0xf800'0000;
960   };
961 
962   template <typename Immediate>
963   class OperandInfo<Immediate, std::enable_if_t<sizeof(Immediate::kMask) != 0>> {
964    public:
965     static constexpr bool IsImmediate = true;
966     static constexpr uint8_t kOffset = 0;
967     static constexpr uint32_t kMask = Immediate::kMask;
968   };
969 
970   template <typename RegisterType>
Rd(RegisterType value)971   RegisterOperand<RdMarker, RegisterType> Rd(RegisterType value) {
972     return {value};
973   }
974 
Cond(Condition value)975   ConditionOperand Cond(Condition value) { return {value}; }
976 
Rm(Rounding value)977   RoundingOperand Rm(Rounding value) { return {value}; }
978 
979   template <typename RegisterType>
Rs1(RegisterType value)980   RegisterOperand<Rs1Marker, RegisterType> Rs1(RegisterType value) {
981     return {value};
982   }
983 
984   template <typename RegisterType>
Rs2(RegisterType value)985   RegisterOperand<Rs2Marker, RegisterType> Rs2(RegisterType value) {
986     return {value};
987   }
988 
989   template <typename RegisterType>
Rs3(RegisterType value)990   RegisterOperand<Rs3Marker, RegisterType> Rs3(RegisterType value) {
991     return {value};
992   }
993 
994   template <uint32_t kOpcode, uint32_t kOpcodeMask, typename... ArgumentsTypes>
EmitInstruction(ArgumentsTypes...arguments)995   void EmitInstruction(ArgumentsTypes... arguments) {
996     // All uncompressed instructions in RISC-V have two lowest bit set and we don't handle
997     // compressed instructions here.
998     static_assert((kOpcode & 0b11) == 0b11);
999     // Instruction shouldn't have any bits set outside of its opcode mask.
1000     static_assert((kOpcode & ~kOpcodeMask) == 0);
1001     // Places for all operands in the opcode should not intersect with opcode.
1002     static_assert((((kOpcodeMask & OperandInfo<ArgumentsTypes>::kMask) == 0) && ...));
1003     Emit32((kOpcode | ... | [](auto argument) {
1004       if constexpr (OperandInfo<decltype(argument)>::IsImmediate) {
1005         return argument.EncodedValue();
1006       } else {
1007         return argument.EncodeImmediate();
1008       }
1009     }(arguments)));
1010   }
1011 
1012   template <uint32_t kOpcode,
1013             typename ArgumentsType0,
1014             typename ArgumentsType1,
1015             typename ImmediateType>
EmitBTypeInstruction(ArgumentsType0 && argument0,ArgumentsType1 && argument1,ImmediateType && immediate)1016   void EmitBTypeInstruction(ArgumentsType0&& argument0,
1017                             ArgumentsType1&& argument1,
1018                             ImmediateType&& immediate) {
1019     return EmitInstruction<kOpcode, 0x0000'707f>(Rs1(argument0), Rs2(argument1), immediate);
1020   }
1021 
1022   template <uint32_t kOpcode, typename ArgumentsType0, typename OperandType>
1023   void EmitITypeInstruction(ArgumentsType0&& argument0, OperandType&& operand) {
1024     return EmitInstruction<kOpcode, 0x0000'707f>(Rd(argument0), Rs1(operand.base), operand.disp);
1025   }
1026 
1027   // Csr instructions are described as I-type instructions in RISC-V manual, but unlike most
1028   // I-type instructions they use IImmediate to encode Csr register number and it comes as second
1029   // argument, not third. In addition Csr value is defined as unsigned and not as signed which
1030   // means certain Csr values (e.g. kVlenb) wouldn't be accepted as IImmediate!
1031   template <uint32_t kOpcode, typename ArgumentsType0>
EmitITypeInstruction(ArgumentsType0 && argument0,Csr csr,Register argument1)1032   void EmitITypeInstruction(ArgumentsType0&& argument0, Csr csr, Register argument1) {
1033     return EmitInstruction<kOpcode, 0x0000'707f>(
1034         Rd(argument0),
1035         IImmediate{riscv::RawImmediate{static_cast<int32_t>(csr) << 20}},
1036         Rs1(argument1));
1037   }
1038 
1039   template <uint32_t kOpcode, typename ArgumentsType0>
1040   void EmitITypeInstruction(ArgumentsType0&& argument0, Csr csr, CsrImmediate immediate) {
1041     return EmitInstruction<kOpcode, 0x0000'707f>(
1042         Rd(argument0), IImmediate{riscv::RawImmediate{static_cast<int32_t>(csr) << 20}}, immediate);
1043   }
1044 
1045   template <uint32_t kOpcode,
1046             typename ArgumentsType0,
1047             typename ArgumentsType1,
1048             typename ImmediateType>
EmitITypeInstruction(ArgumentsType0 && argument0,ArgumentsType1 && argument1,ImmediateType && immediate)1049   void EmitITypeInstruction(ArgumentsType0&& argument0,
1050                             ArgumentsType1&& argument1,
1051                             ImmediateType&& immediate) {
1052     // Some I-type instructions use immediate as opcode extension. In that case different,
1053     // smaller, immediate with smaller mask is used. 0xfff0'707f &
1054     // ~std::decay_t<ImmediateType>::kMask turns these bits that are not used as immediate into
1055     // parts of opcode. For full I-immediate it produces 0x0000'707f, same as with I-type memory
1056     // operand.
1057     return EmitInstruction<kOpcode, 0xfff0'707f & ~std::decay_t<ImmediateType>::kMask>(
1058         Rd(argument0), Rs1(argument1), immediate);
1059   }
1060 
1061   template <uint32_t kOpcode, typename ArgumentsType0, typename ImmediateType>
1062   void EmitJTypeInstruction(ArgumentsType0&& argument0, ImmediateType&& immediate) {
1063     return EmitInstruction<kOpcode, 0x0000'007f>(Rd(argument0), immediate);
1064   }
1065 
1066   template <uint32_t kOpcode, typename OperandType>
EmitPTypeInstruction(OperandType && operand)1067   void EmitPTypeInstruction(OperandType&& operand) {
1068     return EmitInstruction<kOpcode, 0x01f0'7fff>(Rs1(operand.base), operand.disp);
1069   }
1070 
1071   template <uint32_t kOpcode, typename ArgumentsType0, typename ArgumentsType1>
1072   void EmitRTypeInstruction(ArgumentsType0&& argument0, ArgumentsType1&& argument1) {
1073     return EmitInstruction<kOpcode, 0xfff0'707f>(Rd(argument0), Rs1(argument1));
1074   }
1075 
1076   template <uint32_t kOpcode, typename ArgumentsType0, typename ArgumentsType1>
EmitRTypeInstruction(ArgumentsType0 && argument0,ArgumentsType1 && argument1,Rounding argument2)1077   void EmitRTypeInstruction(ArgumentsType0&& argument0,
1078                             ArgumentsType1&& argument1,
1079                             Rounding argument2) {
1080     return EmitInstruction<kOpcode, 0xfff0'007f>(Rd(argument0), Rs1(argument1), Rm(argument2));
1081   }
1082 
1083   template <uint32_t kOpcode,
1084             typename ArgumentsType0,
1085             typename ArgumentsType1,
1086             typename ArgumentsType2>
1087   void EmitRTypeInstruction(ArgumentsType0&& argument0,
1088                             ArgumentsType1&& argument1,
1089                             ArgumentsType2&& argument2) {
1090     return EmitInstruction<kOpcode, 0xfe00'707f>(Rd(argument0), Rs1(argument1), Rs2(argument2));
1091   }
1092 
1093   template <uint32_t kOpcode, typename ArgumentsType0, typename OperandType>
EmitSTypeInstruction(ArgumentsType0 && argument0,OperandType && operand)1094   void EmitSTypeInstruction(ArgumentsType0&& argument0, OperandType&& operand) {
1095     return EmitInstruction<kOpcode, 0x0000'707f>(Rs2(argument0), Rs1(operand.base), operand.disp);
1096   }
1097 
1098   template <uint32_t kOpcode, typename ArgumentsType0, typename ImmediateType>
1099   void EmitUTypeInstruction(ArgumentsType0&& argument0, ImmediateType&& immediate) {
1100     return EmitInstruction<kOpcode, 0x0000'007f>(Rd(argument0), immediate);
1101   }
1102 
1103  private:
1104   Assembler() = delete;
1105   Assembler(const Assembler&) = delete;
1106   Assembler(Assembler&&) = delete;
1107   void operator=(const Assembler&) = delete;
1108   void operator=(Assembler&&) = delete;
1109 };
1110 
1111 template <typename DerivedAssemblerType>
Bcc(Condition cc,Register argument1,Register argument2,const Label & label)1112 inline void Assembler<DerivedAssemblerType>::Bcc(Condition cc,
1113                                                  Register argument1,
1114                                                  Register argument2,
1115                                                  const Label& label) {
1116   if (cc == Condition::kAlways) {
1117     Jal(zero, label);
1118     return;
1119   } else if (cc == Condition::kNever) {
1120     return;
1121   }
1122   CHECK_EQ(0, static_cast<uint8_t>(cc) & 0xf8);
1123   jumps_.push_back(Jump{&label, pc(), false});
1124   EmitInstruction<0x0000'0063, 0x0000'007f>(Cond(cc), Rs1(argument1), Rs2(argument2));
1125 }
1126 
1127 template <typename DerivedAssemblerType>
Bcc(Condition cc,Register argument1,Register argument2,BImmediate immediate)1128 inline void Assembler<DerivedAssemblerType>::Bcc(Condition cc,
1129                                                  Register argument1,
1130                                                  Register argument2,
1131                                                  BImmediate immediate) {
1132   if (cc == Condition::kAlways) {
1133     int32_t encoded_immediate_value = immediate.EncodedValue();
1134     // Maybe better to provide an official interface to convert BImmediate into JImmediate?
1135     // Most CPUs have uncoditional jump with longer range than condtional one (8086, ARM, RISC-V)
1136     // or the same one (modern x86), thus such conversion is natural.
1137     JImmediate jimmediate =
1138         riscv::RawImmediate{((encoded_immediate_value >> 19) & 0x000f'f000) |
1139                             ((encoded_immediate_value << 13) & 0x01f0'0000) |
1140                             (encoded_immediate_value & static_cast<int32_t>(0xfe00'0000))};
1141     Jal(zero, jimmediate);
1142     return;
1143   } else if (cc == Condition::kNever) {
1144     return;
1145   }
1146   CHECK_EQ(0, static_cast<uint8_t>(cc) & 0xf8);
1147   EmitInstruction<0x0000'0063, 0x0000'007f>(Cond(cc), Rs1(argument1), Rs2(argument2), immediate);
1148 }
1149 
1150 #define BERBERIS_DEFINE_LOAD_OR_STORE_INSTRUCTION(Name, TargetRegister, InstructionType, Opcode) \
1151   template <typename DerivedAssemblerType>                                                       \
1152   inline void Assembler<DerivedAssemblerType>::Name(                                             \
1153       TargetRegister arg0, const Label& label, Register arg2) {                                  \
1154     CHECK_NE(arg2, x0);                                                                          \
1155     jumps_.push_back(Jump{&label, pc(), false});                                                 \
1156     /* First issue auipc to load top 20 bits of difference between pc and target address */      \
1157     EmitUTypeInstruction<uint32_t{0x0000'0017}>(arg2, UImmediate{0});                            \
1158     /* The low 12 bite of difference will be encoded in the memory accessing instruction */      \
1159     Emit##InstructionType##TypeInstruction<uint32_t{Opcode}>(                                    \
1160         arg0, Operand<Register, InstructionType##Immediate>{.base = arg2});                      \
1161   }
1162 BERBERIS_DEFINE_LOAD_OR_STORE_INSTRUCTION(Fld, FpRegister, I, 0x0000'3007)
1163 BERBERIS_DEFINE_LOAD_OR_STORE_INSTRUCTION(Flw, FpRegister, I, 0x0000'2007)
1164 BERBERIS_DEFINE_LOAD_OR_STORE_INSTRUCTION(Fsd, FpRegister, S, 0x0000'3027)
1165 BERBERIS_DEFINE_LOAD_OR_STORE_INSTRUCTION(Fsw, FpRegister, S, 0x0000'2027)
1166 BERBERIS_DEFINE_LOAD_OR_STORE_INSTRUCTION(Sb, Register, S, 0x0000'0023)
1167 BERBERIS_DEFINE_LOAD_OR_STORE_INSTRUCTION(Sh, Register, S, 0x0000'1023)
1168 BERBERIS_DEFINE_LOAD_OR_STORE_INSTRUCTION(Sw, Register, S, 0x0000'2023)
1169 #undef BERBERIS_DEFINE_LOAD_OR_STORE_INSTRUCTION
1170 
1171 #define BERBERIS_DEFINE_LOAD_INSTRUCTION(Name, Opcode)                                         \
1172   template <typename DerivedAssemblerType>                                                     \
1173   inline void Assembler<DerivedAssemblerType>::Name(Register arg0, const Label& label) {       \
1174     CHECK_NE(arg0, x0);                                                                        \
1175     jumps_.push_back(Jump{&label, pc(), false});                                               \
1176     /* First issue auipc to load top 20 bits of difference between pc and target address */    \
1177     EmitUTypeInstruction<uint32_t{0x0000'0017}>(arg0, UImmediate{0});                          \
1178     /* The low 12 bite of difference will be encoded in the memory accessing instruction */    \
1179     EmitITypeInstruction<uint32_t{Opcode}>(arg0, Operand<Register, IImmediate>{.base = arg0}); \
1180   }
1181 BERBERIS_DEFINE_LOAD_INSTRUCTION(Lb, 0x0000'0003)
1182 BERBERIS_DEFINE_LOAD_INSTRUCTION(Lbu, 0x0000'4003)
1183 BERBERIS_DEFINE_LOAD_INSTRUCTION(Lh, 0x0000'1003)
1184 BERBERIS_DEFINE_LOAD_INSTRUCTION(Lhu, 0x0000'5003)
1185 BERBERIS_DEFINE_LOAD_INSTRUCTION(Lw, 0x0000'2003)
1186 #undef BERBERIS_DEFINE_LOAD_INSTRUCTION
1187 
1188 template <typename DerivedAssemblerType>
La(Register arg0,const Label & label)1189 inline void Assembler<DerivedAssemblerType>::La(Register arg0, const Label& label) {
1190   CHECK_NE(arg0, x0);
1191   jumps_.push_back(Jump{&label, pc(), false});
1192   // First issue auipc to load top 20 bits of difference between pc and target address
1193   EmitUTypeInstruction<uint32_t{0x0000'0017}>(arg0, UImmediate{0});
1194   // The low 12 bite of difference will be added with addi instruction
1195   EmitITypeInstruction<uint32_t{0x0000'0013}>(arg0, arg0, IImmediate{0});
1196 }
1197 
1198 #define BERBERIS_DEFINE_CONDITIONAL_INSTRUCTION(Name, Opcode)          \
1199   template <typename DerivedAssemblerType>                             \
1200   inline void Assembler<DerivedAssemblerType>::Name(                   \
1201       Register arg0, Register arg1, const Label& label) {              \
1202     jumps_.push_back(Jump{&label, pc(), false});                       \
1203     EmitBTypeInstruction<uint32_t{Opcode}>(arg0, arg1, BImmediate{0}); \
1204   }
1205 BERBERIS_DEFINE_CONDITIONAL_INSTRUCTION(Beq, 0x0000'0063)
1206 BERBERIS_DEFINE_CONDITIONAL_INSTRUCTION(Bge, 0x0000'5063)
1207 BERBERIS_DEFINE_CONDITIONAL_INSTRUCTION(Bgeu, 0x0000'7063)
1208 BERBERIS_DEFINE_CONDITIONAL_INSTRUCTION(Blt, 0x0000'4063)
1209 BERBERIS_DEFINE_CONDITIONAL_INSTRUCTION(Bltu, 0x0000'6063)
1210 BERBERIS_DEFINE_CONDITIONAL_INSTRUCTION(Bne, 0x0000'1063)
1211 #undef BERBERIS_DEFINE_CONDITIONAL_INSTRUCTION
1212 
1213 template <typename DerivedAssemblerType>
Jal(Register argument0,const Label & label)1214 inline void Assembler<DerivedAssemblerType>::Jal(Register argument0, const Label& label) {
1215   jumps_.push_back(Jump{&label, pc(), false});
1216   EmitInstruction<0x0000'006f, 0x0000'007f>(Rd(argument0));
1217 }
1218 
1219 template <typename DerivedAssemblerType>
1220 inline void Assembler<DerivedAssemblerType>::ResolveJumps() {
1221   for (const auto& jump : jumps_) {
1222     const Label* label = jump.label;
1223     uint32_t pc = jump.pc;
1224     CHECK(label->IsBound());
1225     if (jump.is_recovery) {
1226       // Add pc -> label correspondence to recovery map.
1227       AddRelocation(0, RelocationType::RelocRecoveryPoint, pc, label->position());
1228     } else {
1229       int32_t offset = label->position() - pc;
1230       auto ProcessLabel =
1231           [this, pc, offset]<typename ImmediateType,
1232                              std::optional<ImmediateType> (*MakeImmediate)(int32_t)>() {
1233             auto encoded_immediate = MakeImmediate(offset);
1234             if (!encoded_immediate.has_value()) {
1235               // UImmediate means we are dealing with auipc here, means we may accept any
1236               // ±2GB offset, but need to look at the next instruction to do that.
1237               if constexpr (std::is_same_v<ImmediateType, UImmediate>) {
1238                 // Bottom immediate is decoded with a 12 → 32 bit sign-extended.
1239                 // Compensate that by adding sign-bit of bottom to top.
1240                 // Make calculation as unsigned types to ensure we wouldn't hit any UB here.
1241                 int32_t top = (static_cast<uint32_t>(offset) +
1242                                ((static_cast<uint32_t>(offset) & (1U << 11)) * 2)) &
1243                               0xffff'f000U;
1244                 struct {
1245                   int32_t data : 12;
1246                 } bottom = {offset};
1247                 *AddrAs<int32_t>(pc) |= UImmediate{top}.EncodedValue();
1248                 *AddrAs<int32_t>(pc + 4) |= ((*AddrAs<int32_t>(pc + 4) & 96) == 32)
1249                                                 ? SImmediate{bottom.data}.EncodedValue()
1250                                                 : IImmediate{bottom.data}.EncodedValue();
1251                 return true;
1252               }
1253               return false;
1254             }
1255             *AddrAs<int32_t>(pc) |= encoded_immediate->EncodedValue();
1256             return true;
1257           };
1258       // Check the instruction type:
1259       //   AUIPC uses UImmediate, Jal uses JImmediate, while Bcc uses BImmediate.
1260       bool RelocationInRange;
1261       if (*AddrAs<int32_t>(pc) & 16) {
1262         RelocationInRange = ProcessLabel.template operator()<UImmediate, MakeUImmediate>();
1263       } else if (*AddrAs<int32_t>(pc) & 4) {
1264         RelocationInRange = ProcessLabel.template operator()<JImmediate, MakeJImmediate>();
1265       } else {
1266         RelocationInRange = ProcessLabel.template operator()<BImmediate, MakeBImmediate>();
1267       }
1268       // Maybe need to propagate error to caller?
1269       CHECK(RelocationInRange);
1270     }
1271   }
1272 }
1273 
1274 template <typename DerivedAssemblerType>
1275 inline void Assembler<DerivedAssemblerType>::Mv(Register dest, Register src) {
1276   Addi(dest, src, 0);
1277 }
1278 
1279 template <typename DerivedAssemblerType>
1280 inline void Assembler<DerivedAssemblerType>::Li(Register dest, int32_t imm32) {
1281   // If the value fits into 12bit I-Immediate type, load using addi.
1282   if (-2048 <= imm32 && imm32 <= 2047) {
1283     Addi(dest, Assembler::zero, static_cast<IImmediate>(imm32));
1284   } else {
1285     // Otherwise we need to use 2 instructions: lui to load top 20 bits and addi for bottom 12 bits,
1286     // however since the I-Immediate is signed, we could not just split the number into 2 parts: for
1287     // example loading 4095 should result in loading 1 in upper 20 bits (lui 0x1) and then
1288     // subtracting 1 (addi dest, dest, -1).
1289     // Perform calculations on unsigned type to avoid undefined behavior.
1290     uint32_t uimm = static_cast<uint32_t>(imm32);
1291     // Since bottom 12bits are loaded via a 12-bit signed immediate, we need to add the sign bit to
1292     // the top part.
1293     int32_t top = (uimm + ((uimm & (1U << 11)) << 1)) & 0xffff'f000;
1294     // Sign extends the bottom 12 bits.
1295     struct {
1296       int32_t data : 12;
1297     } bottom = {imm32};
1298     Lui(dest, static_cast<UImmediate>(top));
1299     if (bottom.data) {
1300       Addi(dest, dest, static_cast<IImmediate>(bottom.data));
1301     }
1302   }
1303 }
1304 
1305 template <typename DerivedAssemblerType>
Ret()1306 inline void Assembler<DerivedAssemblerType>::Ret() {
1307   Jalr(Assembler::x0, Assembler::x1, static_cast<IImmediate>(0));
1308 }
1309 
1310 template <typename DerivedAssemblerType>
Call(const Label & label)1311 inline void Assembler<DerivedAssemblerType>::Call(const Label& label) {
1312   jumps_.push_back(Jump{&label, pc(), false});
1313   // First issue auipc to load top 20 bits of difference between pc and target address
1314   EmitUTypeInstruction<uint32_t{0x0000'0017}>(Assembler::x6, UImmediate{0});
1315   // The low 12 bite of difference will be added with jalr instruction
1316   EmitITypeInstruction<uint32_t{0x0000'0067}>(Assembler::x1, Assembler::x6, IImmediate{0});
1317 }
1318 
1319 template <typename DerivedAssemblerType>
Tail(const Label & label)1320 inline void Assembler<DerivedAssemblerType>::Tail(const Label& label) {
1321   jumps_.push_back(Jump{&label, pc(), false});
1322   // First issue auipc to load top 20 bits of difference between pc and target address
1323   EmitUTypeInstruction<uint32_t{0x0000'0017}>(Assembler::x6, UImmediate{0});
1324   // The low 12 bite of difference will be added with jalr instruction
1325   EmitITypeInstruction<uint32_t{0x0000'0067}>(Assembler::x0, Assembler::x6, IImmediate{0});
1326 }
1327 
1328 template <typename DerivedAssemblerType>
Bgt(Register arg0,Register arg1,const Label & label)1329 inline void Assembler<DerivedAssemblerType>::Bgt(Register arg0, Register arg1, const Label& label) {
1330   Blt(arg1, arg0, label);
1331 }
1332 
1333 template <typename DerivedAssemblerType>
Bgtu(Register arg0,Register arg1,const Label & label)1334 inline void Assembler<DerivedAssemblerType>::Bgtu(Register arg0,
1335                                                   Register arg1,
1336                                                   const Label& label) {
1337   Bltu(arg1, arg0, label);
1338 }
1339 
1340 template <typename DerivedAssemblerType>
Ble(Register arg0,Register arg1,const Label & label)1341 inline void Assembler<DerivedAssemblerType>::Ble(Register arg0, Register arg1, const Label& label) {
1342   Bge(arg1, arg0, label);
1343 }
1344 
1345 template <typename DerivedAssemblerType>
Bleu(Register arg0,Register arg1,const Label & label)1346 inline void Assembler<DerivedAssemblerType>::Bleu(Register arg0,
1347                                                   Register arg1,
1348                                                   const Label& label) {
1349   Bgeu(arg1, arg0, label);
1350 }
1351 
1352 template <typename DerivedAssemblerType>
Beqz(Register arg0,const Label & label)1353 inline void Assembler<DerivedAssemblerType>::Beqz(Register arg0, const Label& label) {
1354   Beq(arg0, zero, label);
1355 }
1356 
1357 template <typename DerivedAssemblerType>
Bnez(Register arg0,const Label & label)1358 inline void Assembler<DerivedAssemblerType>::Bnez(Register arg0, const Label& label) {
1359   Bne(arg0, zero, label);
1360 }
1361 
1362 template <typename DerivedAssemblerType>
Blez(Register arg0,const Label & label)1363 inline void Assembler<DerivedAssemblerType>::Blez(Register arg0, const Label& label) {
1364   Ble(arg0, zero, label);
1365 }
1366 
1367 template <typename DerivedAssemblerType>
Bgez(Register arg0,const Label & label)1368 inline void Assembler<DerivedAssemblerType>::Bgez(Register arg0, const Label& label) {
1369   Bge(arg0, zero, label);
1370 }
1371 
1372 template <typename DerivedAssemblerType>
Bltz(Register arg0,const Label & label)1373 inline void Assembler<DerivedAssemblerType>::Bltz(Register arg0, const Label& label) {
1374   Blt(arg0, zero, label);
1375 }
1376 
1377 template <typename DerivedAssemblerType>
Bgtz(Register arg0,const Label & label)1378 inline void Assembler<DerivedAssemblerType>::Bgtz(Register arg0, const Label& label) {
1379   Bgt(arg0, zero, label);
1380 }
1381 
1382 template <typename DerivedAssemblerType>
Seqz(Register arg0,Register arg1)1383 inline void Assembler<DerivedAssemblerType>::Seqz(Register arg0, Register arg1) {
1384   Sltiu(arg0, arg1, static_cast<IImmediate>(1));
1385 }
1386 
1387 template <typename DerivedAssemblerType>
Snez(Register arg0,Register arg1)1388 inline void Assembler<DerivedAssemblerType>::Snez(Register arg0, Register arg1) {
1389   Sltu(arg0, zero, arg1);
1390 }
1391 
1392 template <typename DerivedAssemblerType>
Sltz(Register arg0,Register arg1)1393 inline void Assembler<DerivedAssemblerType>::Sltz(Register arg0, Register arg1) {
1394   Slt(arg0, arg1, zero);
1395 }
1396 
1397 template <typename DerivedAssemblerType>
Sgtz(Register arg0,Register arg1)1398 inline void Assembler<DerivedAssemblerType>::Sgtz(Register arg0, Register arg1) {
1399   Slt(arg0, zero, arg1);
1400 }
1401 
1402 template <typename DerivedAssemblerType>
J(JImmediate arg0)1403 inline void Assembler<DerivedAssemblerType>::J(JImmediate arg0) {
1404   Jal(zero, arg0);
1405 }
1406 
1407 template <typename DerivedAssemblerType>
Jal(JImmediate arg0)1408 inline void Assembler<DerivedAssemblerType>::Jal(JImmediate arg0) {
1409   Jal(x1, arg0);
1410 }
1411 
1412 template <typename DerivedAssemblerType>
Jr(Register arg0)1413 inline void Assembler<DerivedAssemblerType>::Jr(Register arg0) {
1414   Jalr(zero, arg0, 0);
1415 }
1416 
1417 template <typename DerivedAssemblerType>
Jalr(Register arg0)1418 inline void Assembler<DerivedAssemblerType>::Jalr(Register arg0) {
1419   Jalr(x1, arg0, 0);
1420 }
1421 
1422 template <typename DerivedAssemblerType>
Not(Register arg0,Register arg1)1423 inline void Assembler<DerivedAssemblerType>::Not(Register arg0, Register arg1) {
1424   Xori(arg0, arg1, -1);
1425 }
1426 
1427 template <typename DerivedAssemblerType>
Neg(Register arg0,Register arg1)1428 inline void Assembler<DerivedAssemblerType>::Neg(Register arg0, Register arg1) {
1429   Sub(arg0, zero, arg1);
1430 }
1431 
1432 }  // namespace riscv
1433 
1434 }  // namespace berberis
1435 
1436 #endif  // BERBERIS_ASSEMBLER_COMMON_RISCV_H_
1437