/ externals / biscuit / src / assembler.cpp
assembler.cpp
   1  #include <biscuit/assert.hpp>
   2  #include <biscuit/assembler.hpp>
   3  
   4  #include <bit>
   5  #include <cstring>
   6  #include <utility>
   7  
   8  #include "assembler_util.hpp"
   9  
  10  namespace biscuit {
  11  
  12  Assembler::Assembler(size_t capacity)
  13      : m_buffer(capacity) {}
  14  
  15  Assembler::Assembler(uint8_t* buffer, size_t capacity, ArchFeature features)
  16      : m_buffer(buffer, capacity), m_features{features} {}
  17  
  18  Assembler::~Assembler() = default;
  19  
  20  CodeBuffer& Assembler::GetCodeBuffer() {
  21      return m_buffer;
  22  }
  23  
  24  CodeBuffer Assembler::SwapCodeBuffer(CodeBuffer&& buffer) noexcept {
  25      return std::exchange(m_buffer, std::move(buffer));
  26  }
  27  
  28  void Assembler::Bind(Label* label) {
  29      BindToOffset(label, m_buffer.GetCursorOffset());
  30  }
  31  
  32  void Assembler::ADD(GPR rd, GPR lhs, GPR rhs) noexcept {
  33      EmitRType(m_buffer, 0b0000000, rhs, lhs, 0b000, rd, 0b0110011);
  34  }
  35  
  36  void Assembler::ADDI(GPR rd, GPR rs, int32_t imm) noexcept {
  37      EmitIType(m_buffer, static_cast<uint32_t>(imm), rs, 0b000, rd, 0b0010011);
  38  }
  39  
  40  void Assembler::AND(GPR rd, GPR lhs, GPR rhs) noexcept {
  41      EmitRType(m_buffer, 0b0000000, rhs, lhs, 0b111, rd, 0b0110011);
  42  }
  43  
  44  void Assembler::ANDI(GPR rd, GPR rs, uint32_t imm) noexcept {
  45      EmitIType(m_buffer, imm, rs, 0b111, rd, 0b0010011);
  46  }
  47  
  48  void Assembler::AUIPC(GPR rd, int32_t imm) noexcept {
  49      EmitUType(m_buffer, static_cast<uint32_t>(imm), rd, 0b0010111);
  50  }
  51  
  52  void Assembler::BEQ(GPR rs1, GPR rs2, Label* label) noexcept {
  53      const auto address = LinkAndGetOffset(label);
  54      BEQ(rs1, rs2, static_cast<int32_t>(address));
  55  }
  56  
  57  void Assembler::BEQZ(GPR rs, Label* label) noexcept {
  58      const auto address = LinkAndGetOffset(label);
  59      BEQZ(rs, static_cast<int32_t>(address));
  60  }
  61  
  62  void Assembler::BGE(GPR rs1, GPR rs2, Label* label) noexcept {
  63      const auto address = LinkAndGetOffset(label);
  64      BGE(rs1, rs2, static_cast<int32_t>(address));
  65  }
  66  
  67  void Assembler::BGEU(GPR rs1, GPR rs2, Label* label) noexcept {
  68      const auto address = LinkAndGetOffset(label);
  69      BGEU(rs1, rs2, static_cast<int32_t>(address));
  70  }
  71  
  72  void Assembler::BGEZ(GPR rs, Label* label) noexcept {
  73      const auto address = LinkAndGetOffset(label);
  74      BGEZ(rs, static_cast<int32_t>(address));
  75  }
  76  
  77  void Assembler::BGT(GPR rs, GPR rt, Label* label) noexcept {
  78      const auto address = LinkAndGetOffset(label);
  79      BGT(rs, rt, static_cast<int32_t>(address));
  80  }
  81  
  82  void Assembler::BGTU(GPR rs, GPR rt, Label* label) noexcept {
  83      const auto address = LinkAndGetOffset(label);
  84      BGTU(rs, rt, static_cast<int32_t>(address));
  85  }
  86  
  87  void Assembler::BGTZ(GPR rs, Label* label) noexcept {
  88      const auto address = LinkAndGetOffset(label);
  89      BGTZ(rs, static_cast<int32_t>(address));
  90  }
  91  
  92  void Assembler::BLE(GPR rs, GPR rt, Label* label) noexcept {
  93      const auto address = LinkAndGetOffset(label);
  94      BLE(rs, rt, static_cast<int32_t>(address));
  95  }
  96  
  97  void Assembler::BLEU(GPR rs, GPR rt, Label* label) noexcept {
  98      const auto address = LinkAndGetOffset(label);
  99      BLEU(rs, rt, static_cast<int32_t>(address));
 100  }
 101  
 102  void Assembler::BLEZ(GPR rs, Label* label) noexcept {
 103      const auto address = LinkAndGetOffset(label);
 104      BLEZ(rs, static_cast<int32_t>(address));
 105  }
 106  
 107  void Assembler::BLT(GPR rs1, GPR rs2, Label* label) noexcept {
 108      const auto address = LinkAndGetOffset(label);
 109      BLT(rs1, rs2, static_cast<int32_t>(address));
 110  }
 111  
 112  void Assembler::BLTU(GPR rs1, GPR rs2, Label* label) noexcept {
 113      const auto address = LinkAndGetOffset(label);
 114      BLTU(rs1, rs2, static_cast<int32_t>(address));
 115  }
 116  
 117  void Assembler::BLTZ(GPR rs, Label* label) noexcept {
 118      const auto address = LinkAndGetOffset(label);
 119      BLTZ(rs, static_cast<int32_t>(address));
 120  }
 121  
 122  void Assembler::BNE(GPR rs1, GPR rs2, Label* label) noexcept {
 123      const auto address = LinkAndGetOffset(label);
 124      BNE(rs1, rs2, static_cast<int32_t>(address));
 125  }
 126  
 127  void Assembler::BNEZ(GPR rs, Label* label) noexcept {
 128      const auto address = LinkAndGetOffset(label);
 129      BNEZ(rs, static_cast<int32_t>(address));
 130  }
 131  
 132  void Assembler::BEQ(GPR rs1, GPR rs2, int32_t imm) noexcept {
 133      BISCUIT_ASSERT(IsValidBTypeImm(imm));
 134      EmitBType(m_buffer, static_cast<uint32_t>(imm), rs2, rs1, 0b000, 0b1100011);
 135  }
 136  
 137  void Assembler::BEQZ(GPR rs, int32_t imm) noexcept {
 138      BEQ(rs, x0, imm);
 139  }
 140  
 141  void Assembler::BGE(GPR rs1, GPR rs2, int32_t imm) noexcept {
 142      BISCUIT_ASSERT(IsValidBTypeImm(imm));
 143      EmitBType(m_buffer, static_cast<uint32_t>(imm), rs2, rs1, 0b101, 0b1100011);
 144  }
 145  
 146  void Assembler::BGEU(GPR rs1, GPR rs2, int32_t imm) noexcept {
 147      BISCUIT_ASSERT(IsValidBTypeImm(imm));
 148      EmitBType(m_buffer, static_cast<uint32_t>(imm), rs2, rs1, 0b111, 0b1100011);
 149  }
 150  
 151  void Assembler::BGEZ(GPR rs, int32_t imm) noexcept {
 152      BGE(rs, x0, imm);
 153  }
 154  
 155  void Assembler::BGT(GPR rs, GPR rt, int32_t imm) noexcept {
 156      BLT(rt, rs, imm);
 157  }
 158  
 159  void Assembler::BGTU(GPR rs, GPR rt, int32_t imm) noexcept {
 160      BLTU(rt, rs, imm);
 161  }
 162  
 163  void Assembler::BGTZ(GPR rs, int32_t imm) noexcept {
 164      BLT(x0, rs, imm);
 165  }
 166  
 167  void Assembler::BLE(GPR rs, GPR rt, int32_t imm) noexcept {
 168      BGE(rt, rs, imm);
 169  }
 170  
 171  void Assembler::BLEU(GPR rs, GPR rt, int32_t imm) noexcept {
 172      BGEU(rt, rs, imm);
 173  }
 174  
 175  void Assembler::BLEZ(GPR rs, int32_t imm) noexcept {
 176      BGE(x0, rs, imm);
 177  }
 178  
 179  void Assembler::BLT(GPR rs1, GPR rs2, int32_t imm) noexcept {
 180      BISCUIT_ASSERT(IsValidBTypeImm(imm));
 181      EmitBType(m_buffer, static_cast<uint32_t>(imm), rs2, rs1, 0b100, 0b1100011);
 182  }
 183  
 184  void Assembler::BLTU(GPR rs1, GPR rs2, int32_t imm) noexcept {
 185      BISCUIT_ASSERT(IsValidBTypeImm(imm));
 186      EmitBType(m_buffer, static_cast<uint32_t>(imm), rs2, rs1, 0b110, 0b1100011);
 187  }
 188  
 189  void Assembler::BLTZ(GPR rs, int32_t imm) noexcept {
 190      BLT(rs, x0, imm);
 191  }
 192  
 193  void Assembler::BNE(GPR rs1, GPR rs2, int32_t imm) noexcept {
 194      BISCUIT_ASSERT(IsValidBTypeImm(imm));
 195      EmitBType(m_buffer, static_cast<uint32_t>(imm), rs2, rs1, 0b001, 0b1100011);
 196  }
 197  
 198  void Assembler::BNEZ(GPR rs, int32_t imm) noexcept {
 199      BNE(x0, rs, imm);
 200  }
 201  
 202  void Assembler::CALL(int32_t offset) noexcept {
 203      const auto uimm = static_cast<uint32_t>(offset);
 204      const auto lower = uimm & 0xFFF;
 205      const auto upper = (uimm & 0xFFFFF000) >> 12;
 206      const auto needs_increment = (uimm & 0x800) != 0;
 207  
 208      // Sign-extend the lower portion if the MSB of it is set.
 209      const auto new_lower = needs_increment ? static_cast<int32_t>(lower << 20) >> 20
 210                                             : static_cast<int32_t>(lower);
 211      const auto new_upper = needs_increment ? upper + 1 : upper;
 212  
 213      AUIPC(x1, static_cast<int32_t>(new_upper));
 214      JALR(x1, new_lower, x1);
 215  }
 216  
 217  void Assembler::EBREAK() noexcept {
 218      m_buffer.Emit32(0x00100073);
 219  }
 220  
 221  void Assembler::ECALL() noexcept {
 222      m_buffer.Emit32(0x00000073);
 223  }
 224  
 225  void Assembler::FENCE() noexcept {
 226      FENCE(FenceOrder::IORW, FenceOrder::IORW);
 227  }
 228  
 229  void Assembler::FENCE(FenceOrder pred, FenceOrder succ) noexcept {
 230      EmitFENCE(m_buffer, 0b0000, pred, succ, x0, 0b000, x0, 0b0001111);
 231  }
 232  
 233  void Assembler::FENCEI(GPR rd, GPR rs, uint32_t imm) noexcept {
 234      m_buffer.Emit32(((imm & 0xFFF) << 20) | (rs.Index() << 15) | 0x1000U | (rd.Index() << 7) | 0b0001111);
 235  }
 236  
 237  void Assembler::FENCETSO() noexcept {
 238      EmitFENCE(m_buffer, 0b1000, FenceOrder::RW, FenceOrder::RW, x0, 0b000, x0, 0b0001111);
 239  }
 240  
 241  void Assembler::J(Label* label) noexcept {
 242      const auto address = LinkAndGetOffset(label);
 243      BISCUIT_ASSERT(IsValidJTypeImm(address));
 244      J(static_cast<int32_t>(address));
 245  }
 246  
 247  void Assembler::JAL(Label* label) noexcept {
 248      const auto address = LinkAndGetOffset(label);
 249      BISCUIT_ASSERT(IsValidJTypeImm(address));
 250      JAL(static_cast<int32_t>(address));
 251  }
 252  
 253  void Assembler::JAL(GPR rd, Label* label) noexcept {
 254      const auto address = LinkAndGetOffset(label);
 255      BISCUIT_ASSERT(IsValidJTypeImm(address));
 256      JAL(rd, static_cast<int32_t>(address));
 257  }
 258  
 259  void Assembler::J(int32_t imm) noexcept {
 260      BISCUIT_ASSERT(IsValidJTypeImm(imm));
 261      JAL(x0, imm);
 262  }
 263  
 264  void Assembler::JAL(int32_t imm) noexcept {
 265      BISCUIT_ASSERT(IsValidJTypeImm(imm));
 266      EmitJType(m_buffer, static_cast<uint32_t>(imm), x1, 0b1101111);
 267  }
 268  
 269  void Assembler::JAL(GPR rd, int32_t imm) noexcept {
 270      BISCUIT_ASSERT(IsValidJTypeImm(imm));
 271      EmitJType(m_buffer, static_cast<uint32_t>(imm), rd, 0b1101111);
 272  }
 273  
 274  void Assembler::JALR(GPR rs) noexcept {
 275      JALR(x1, 0, rs);
 276  }
 277  
 278  void Assembler::JALR(GPR rd, int32_t imm, GPR rs1) noexcept {
 279      BISCUIT_ASSERT(IsValidSigned12BitImm(imm));
 280      EmitIType(m_buffer, static_cast<uint32_t>(imm), rs1, 0b000, rd, 0b1100111);
 281  }
 282  
 283  void Assembler::JR(GPR rs) noexcept {
 284      JALR(x0, 0, rs);
 285  }
 286  
 287  void Assembler::LB(GPR rd, int32_t imm, GPR rs) noexcept {
 288      BISCUIT_ASSERT(IsValidSigned12BitImm(imm));
 289      EmitIType(m_buffer, static_cast<uint32_t>(imm), rs, 0b000, rd, 0b0000011);
 290  }
 291  
 292  void Assembler::LBU(GPR rd, int32_t imm, GPR rs) noexcept {
 293      BISCUIT_ASSERT(IsValidSigned12BitImm(imm));
 294      EmitIType(m_buffer, static_cast<uint32_t>(imm), rs, 0b100, rd, 0b0000011);
 295  }
 296  
 297  void Assembler::LH(GPR rd, int32_t imm, GPR rs) noexcept {
 298      BISCUIT_ASSERT(IsValidSigned12BitImm(imm));
 299      EmitIType(m_buffer, static_cast<uint32_t>(imm), rs, 0b001, rd, 0b0000011);
 300  }
 301  
 302  void Assembler::LHU(GPR rd, int32_t imm, GPR rs) noexcept {
 303      BISCUIT_ASSERT(IsValidSigned12BitImm(imm));
 304      EmitIType(m_buffer, static_cast<uint32_t>(imm), rs, 0b101, rd, 0b0000011);
 305  }
 306  
 307  void Assembler::LI(GPR rd, uint64_t imm) noexcept {
 308      if (IsRV32(m_features)) {
 309          // Depending on imm, the following instructions are emitted.
 310          // hi20 == 0              -> ADDI
 311          // lo12 == 0 && hi20 != 0 -> LUI
 312          // otherwise              -> LUI+ADDI
 313  
 314          // Add 0x800 to cancel out the signed extension of ADDI.
 315          const auto uimm32 = static_cast<uint32_t>(imm);
 316          const auto hi20 = (uimm32 + 0x800) >> 12 & 0xFFFFF;
 317          const auto lo12 = static_cast<int32_t>(uimm32) & 0xFFF;
 318          GPR rs1 = zero;
 319  
 320          if (hi20 != 0) {
 321              LUI(rd, hi20);
 322              rs1 = rd;
 323          }
 324  
 325          if (lo12 != 0 || hi20 == 0) {
 326              ADDI(rd, rs1, lo12);
 327          }
 328      } else {
 329          // For 64-bit imm, a sequence of up to 8 instructions (i.e. LUI+ADDIW+SLLI+
 330          // ADDI+SLLI+ADDI+SLLI+ADDI) is emitted.
 331          // In the following, imm is processed from LSB to MSB while instruction emission
 332          // is performed from MSB to LSB by calling LI() recursively. In each recursion,
 333          // the lowest 12 bits are removed from imm and the optimal shift amount is
 334          // calculated. Then, the remaining part of imm is processed recursively and
 335          // LI() get called as soon as it fits into 32 bits.
 336  
 337          if (static_cast<uint64_t>(static_cast<int64_t>(imm << 32) >> 32) == imm) {
 338              // Depending on imm, the following instructions are emitted.
 339              // hi20 == 0              -> ADDIW
 340              // lo12 == 0 && hi20 != 0 -> LUI
 341              // otherwise              -> LUI+ADDIW
 342  
 343              // Add 0x800 to cancel out the signed extension of ADDIW.
 344              const auto hi20 = (static_cast<uint32_t>(imm) + 0x800) >> 12 & 0xFFFFF;
 345              const auto lo12 = static_cast<int32_t>(imm) & 0xFFF;
 346              GPR rs1 = zero;
 347  
 348              if (hi20 != 0) {
 349                  LUI(rd, hi20);
 350                  rs1 = rd;
 351              }
 352  
 353              if (lo12 != 0 || hi20 == 0) {
 354                  ADDIW(rd, rs1, lo12);
 355              }
 356              return;
 357          }
 358  
 359          const auto lo12 = static_cast<int32_t>(static_cast<int64_t>(imm << 52) >> 52);
 360          // Add 0x800 to cancel out the signed extension of ADDI.
 361          uint64_t hi52 = (imm + 0x800) >> 12;
 362          const uint32_t shift = 12 + static_cast<uint32_t>(std::countr_zero(hi52));
 363          hi52 = static_cast<uint64_t>((static_cast<int64_t>(hi52 >> (shift - 12)) << shift) >> shift);
 364          LI(rd, hi52);
 365          SLLI(rd, rd, shift);
 366          if (lo12 != 0) {
 367              ADDI(rd, rd, lo12);
 368          }
 369      }
 370  }
 371  
 372  void Assembler::LUI(GPR rd, uint32_t imm) noexcept {
 373      EmitUType(m_buffer, imm, rd, 0b0110111);
 374  }
 375  
 376  void Assembler::LW(GPR rd, int32_t imm, GPR rs) noexcept {
 377      BISCUIT_ASSERT(IsValidSigned12BitImm(imm));
 378      EmitIType(m_buffer, static_cast<uint32_t>(imm), rs, 0b010, rd, 0b0000011);
 379  }
 380  
 381  void Assembler::MV(GPR rd, GPR rs) noexcept {
 382      ADDI(rd, rs, 0);
 383  }
 384  
 385  void Assembler::NEG(GPR rd, GPR rs) noexcept {
 386      SUB(rd, x0, rs);
 387  }
 388  
 389  void Assembler::NOP() noexcept {
 390      ADDI(x0, x0, 0);
 391  }
 392  
 393  void Assembler::NOT(GPR rd, GPR rs) noexcept {
 394      XORI(rd, rs, UINT32_MAX);
 395  }
 396  
 397  void Assembler::OR(GPR rd, GPR lhs, GPR rhs) noexcept {
 398      EmitRType(m_buffer, 0b0000000, rhs, lhs, 0b110, rd, 0b0110011);
 399  }
 400  
 401  void Assembler::ORI(GPR rd, GPR rs, uint32_t imm) noexcept {
 402      EmitIType(m_buffer, imm, rs, 0b110, rd, 0b0010011);
 403  }
 404  
 405  void Assembler::PAUSE() noexcept {
 406      m_buffer.Emit32(0x0100000F);
 407  }
 408  
 409  void Assembler::RET() noexcept {
 410      JALR(x0, 0, x1);
 411  }
 412  
 413  void Assembler::SB(GPR rs2, int32_t imm, GPR rs1) noexcept {
 414      BISCUIT_ASSERT(IsValidSigned12BitImm(imm));
 415      EmitSType(m_buffer, static_cast<uint32_t>(imm), rs2, rs1, 0b000, 0b0100011);
 416  }
 417  
 418  void Assembler::SEQZ(GPR rd, GPR rs) noexcept {
 419      SLTIU(rd, rs, 1);
 420  }
 421  
 422  void Assembler::SGTZ(GPR rd, GPR rs) noexcept {
 423      SLT(rd, x0, rs);
 424  }
 425  
 426  void Assembler::SH(GPR rs2, int32_t imm, GPR rs1) noexcept {
 427      BISCUIT_ASSERT(IsValidSigned12BitImm(imm));
 428      EmitSType(m_buffer, static_cast<uint32_t>(imm), rs2, rs1, 0b001, 0b0100011);
 429  }
 430  
 431  void Assembler::SLL(GPR rd, GPR lhs, GPR rhs) noexcept {
 432      EmitRType(m_buffer, 0b0000000, rhs, lhs, 0b001, rd, 0b0110011);
 433  }
 434  
 435  void Assembler::SLLI(GPR rd, GPR rs, uint32_t shift) noexcept {
 436      if (IsRV32(m_features)) {
 437          BISCUIT_ASSERT(shift <= 31);
 438          EmitIType(m_buffer, shift & 0x1F, rs, 0b001, rd, 0b0010011);
 439      } else {
 440          BISCUIT_ASSERT(shift <= 63);
 441          EmitIType(m_buffer, shift & 0x3F, rs, 0b001, rd, 0b0010011);
 442      }
 443  }
 444  
 445  void Assembler::SLT(GPR rd, GPR lhs, GPR rhs) noexcept {
 446      EmitRType(m_buffer, 0b0000000, rhs, lhs, 0b010, rd, 0b0110011);
 447  }
 448  
 449  void Assembler::SLTI(GPR rd, GPR rs, int32_t imm) noexcept {
 450      BISCUIT_ASSERT(IsValidSigned12BitImm(imm));
 451      EmitIType(m_buffer, static_cast<uint32_t>(imm), rs, 0b010, rd, 0b0010011);
 452  }
 453  
 454  void Assembler::SLTIU(GPR rd, GPR rs, int32_t imm) noexcept {
 455      BISCUIT_ASSERT(IsValidSigned12BitImm(imm));
 456      EmitIType(m_buffer, static_cast<uint32_t>(imm), rs, 0b011, rd, 0b0010011);
 457  }
 458  
 459  void Assembler::SLTU(GPR rd, GPR lhs, GPR rhs) noexcept {
 460      EmitRType(m_buffer, 0b0000000, rhs, lhs, 0b011, rd, 0b0110011);
 461  }
 462  
 463  void Assembler::SLTZ(GPR rd, GPR rs) noexcept {
 464      SLT(rd, rs, x0);
 465  }
 466  
 467  void Assembler::SNEZ(GPR rd, GPR rs) noexcept {
 468      SLTU(rd, x0, rs);
 469  }
 470  
 471  void Assembler::SRA(GPR rd, GPR lhs, GPR rhs) noexcept {
 472      EmitRType(m_buffer, 0b0100000, rhs, lhs, 0b101, rd, 0b0110011);
 473  }
 474  
 475  void Assembler::SRAI(GPR rd, GPR rs, uint32_t shift) noexcept {
 476      if (IsRV32(m_features)) {
 477          BISCUIT_ASSERT(shift <= 31);
 478          EmitIType(m_buffer, (0b0100000 << 5) | (shift & 0x1F), rs, 0b101, rd, 0b0010011);
 479      } else {
 480          BISCUIT_ASSERT(shift <= 63);
 481          EmitIType(m_buffer, (0b0100000 << 5) | (shift & 0x3F), rs, 0b101, rd, 0b0010011);
 482      }
 483  }
 484  
 485  void Assembler::SRL(GPR rd, GPR lhs, GPR rhs) noexcept {
 486      EmitRType(m_buffer, 0b0000000, rhs, lhs, 0b101, rd, 0b0110011);
 487  }
 488  
 489  void Assembler::SRLI(GPR rd, GPR rs, uint32_t shift) noexcept {
 490      if (IsRV32(m_features)) {
 491          BISCUIT_ASSERT(shift <= 31);
 492          EmitIType(m_buffer, shift & 0x1F, rs, 0b101, rd, 0b0010011);
 493      } else {
 494          BISCUIT_ASSERT(shift <= 63);
 495          EmitIType(m_buffer, shift & 0x3F, rs, 0b101, rd, 0b0010011);
 496      }
 497  }
 498  
 499  void Assembler::SUB(GPR rd, GPR lhs, GPR rhs) noexcept {
 500      EmitRType(m_buffer, 0b0100000, rhs, lhs, 0b000, rd, 0b0110011);
 501  }
 502  
 503  void Assembler::SW(GPR rs2, int32_t imm, GPR rs1) noexcept {
 504      BISCUIT_ASSERT(IsValidSigned12BitImm(imm));
 505      EmitSType(m_buffer, static_cast<uint32_t>(imm), rs2, rs1, 0b010, 0b0100011);
 506  }
 507  
 508  void Assembler::XOR(GPR rd, GPR lhs, GPR rhs) noexcept {
 509      EmitRType(m_buffer, 0b0000000, rhs, lhs, 0b100, rd, 0b0110011);
 510  }
 511  
 512  void Assembler::XORI(GPR rd, GPR rs, uint32_t imm) noexcept {
 513      EmitIType(m_buffer, imm, rs, 0b100, rd, 0b0010011);
 514  }
 515  
 516  // RV64I Instructions
 517  
 518  void Assembler::ADDIW(GPR rd, GPR rs, int32_t imm) noexcept {
 519      BISCUIT_ASSERT(IsRV64(m_features));
 520      EmitIType(m_buffer, static_cast<uint32_t>(imm), rs, 0b000, rd, 0b0011011);
 521  }
 522  
 523  void Assembler::ADDW(GPR rd, GPR lhs, GPR rhs) noexcept {
 524      BISCUIT_ASSERT(IsRV64(m_features));
 525      EmitRType(m_buffer, 0b0000000, rhs, lhs, 0b000, rd, 0b0111011);
 526  }
 527  
 528  void Assembler::LD(GPR rd, int32_t imm, GPR rs) noexcept {
 529      BISCUIT_ASSERT(IsRV64(m_features));
 530      BISCUIT_ASSERT(IsValidSigned12BitImm(imm));
 531      EmitIType(m_buffer, static_cast<uint32_t>(imm), rs, 0b011, rd, 0b0000011);
 532  }
 533  
 534  void Assembler::LWU(GPR rd, int32_t imm, GPR rs) noexcept {
 535      BISCUIT_ASSERT(IsRV64(m_features));
 536      BISCUIT_ASSERT(IsValidSigned12BitImm(imm));
 537      EmitIType(m_buffer, static_cast<uint32_t>(imm), rs, 0b110, rd, 0b0000011);
 538  }
 539  
 540  void Assembler::SD(GPR rs2, int32_t imm, GPR rs1) noexcept {
 541      BISCUIT_ASSERT(IsRV64(m_features));
 542      BISCUIT_ASSERT(IsValidSigned12BitImm(imm));
 543      EmitSType(m_buffer, static_cast<uint32_t>(imm), rs2, rs1, 0b011, 0b0100011);
 544  }
 545  
 546  void Assembler::SLLIW(GPR rd, GPR rs, uint32_t shift) noexcept {
 547      BISCUIT_ASSERT(IsRV64(m_features));
 548      BISCUIT_ASSERT(shift <= 31);
 549      EmitIType(m_buffer, shift & 0x1F, rs, 0b001, rd, 0b0011011);
 550  }
 551  void Assembler::SRAIW(GPR rd, GPR rs, uint32_t shift) noexcept {
 552      BISCUIT_ASSERT(IsRV64(m_features));
 553      BISCUIT_ASSERT(shift <= 31);
 554      EmitIType(m_buffer, (0b0100000 << 5) | (shift & 0x1F), rs, 0b101, rd, 0b0011011);
 555  }
 556  void Assembler::SRLIW(GPR rd, GPR rs, uint32_t shift) noexcept {
 557      BISCUIT_ASSERT(IsRV64(m_features));
 558      BISCUIT_ASSERT(shift <= 31);
 559      EmitIType(m_buffer, shift & 0x1F, rs, 0b101, rd, 0b0011011);
 560  }
 561  
 562  void Assembler::SLLW(GPR rd, GPR lhs, GPR rhs) noexcept {
 563      BISCUIT_ASSERT(IsRV64(m_features));
 564      EmitRType(m_buffer, 0b0000000, rhs, lhs, 0b001, rd, 0b0111011);
 565  }
 566  void Assembler::SRAW(GPR rd, GPR lhs, GPR rhs) noexcept {
 567      BISCUIT_ASSERT(IsRV64(m_features));
 568      EmitRType(m_buffer, 0b0100000, rhs, lhs, 0b101, rd, 0b0111011);
 569  }
 570  void Assembler::SRLW(GPR rd, GPR lhs, GPR rhs) noexcept {
 571      BISCUIT_ASSERT(IsRV64(m_features));
 572      EmitRType(m_buffer, 0b0000000, rhs, lhs, 0b101, rd, 0b0111011);
 573  }
 574  
 575  void Assembler::SUBW(GPR rd, GPR lhs, GPR rhs) noexcept {
 576      BISCUIT_ASSERT(IsRV64(m_features));
 577      EmitRType(m_buffer, 0b0100000, rhs, lhs, 0b000, rd, 0b0111011);
 578  }
 579  
 580  // Zawrs Extension Instructions
 581  
 582  void Assembler::WRS_NTO() noexcept {
 583      EmitIType(m_buffer, 0b01101, x0, 0, x0, 0b1110011);
 584  }
 585  void Assembler::WRS_STO() noexcept {
 586      EmitIType(m_buffer, 0b11101, x0, 0, x0, 0b1110011);
 587  }
 588  
 589  // Zacas Extension Instructions
 590  
 591  void Assembler::AMOCAS_D(Ordering ordering, GPR rd, GPR rs2, GPR rs1) noexcept {
 592      if (IsRV32(m_features)) {
 593          BISCUIT_ASSERT((rd.Index() % 2) == 0);
 594          BISCUIT_ASSERT((rs1.Index() % 2) == 0);
 595          BISCUIT_ASSERT((rs2.Index() % 2) == 0);
 596      }
 597      EmitAtomic(m_buffer, 0b00101, ordering, rs2, rs1, 0b011, rd, 0b0101111);
 598  }
 599  void Assembler::AMOCAS_Q(Ordering ordering, GPR rd, GPR rs2, GPR rs1) noexcept {
 600      BISCUIT_ASSERT(IsRV64(m_features));
 601  
 602      // Both rd and rs2 indicate a register pair, so they need to be even-numbered.
 603      BISCUIT_ASSERT((rd.Index() % 2) == 0);
 604      BISCUIT_ASSERT((rs1.Index() % 2) == 0);
 605      BISCUIT_ASSERT((rs2.Index() % 2) == 0);
 606      EmitAtomic(m_buffer, 0b00101, ordering, rs2, rs1, 0b100, rd, 0b0101111);
 607  }
 608  void Assembler::AMOCAS_W(Ordering ordering, GPR rd, GPR rs2, GPR rs1) noexcept {
 609      EmitAtomic(m_buffer, 0b00101, ordering, rs2, rs1, 0b010, rd, 0b0101111);
 610  }
 611  
 612  // Zicond Extension Instructions
 613  
 614  void Assembler::CZERO_EQZ(GPR rd, GPR value, GPR condition) noexcept {
 615      EmitRType(m_buffer, 0b0000111, condition, value, 0b101, rd, 0b0110011);
 616  }
 617  void Assembler::CZERO_NEZ(GPR rd, GPR value, GPR condition) noexcept {
 618      EmitRType(m_buffer, 0b0000111, condition, value, 0b111, rd, 0b0110011);
 619  }
 620  
 621  // Zicsr Extension Instructions
 622  
 623  void Assembler::CSRRC(GPR rd, CSR csr, GPR rs) noexcept {
 624      EmitIType(m_buffer, static_cast<uint32_t>(csr), rs, 0b011, rd, 0b1110011);
 625  }
 626  void Assembler::CSRRCI(GPR rd, CSR csr, uint32_t imm) noexcept {
 627      BISCUIT_ASSERT(imm <= 0x1F);
 628      EmitIType(m_buffer, static_cast<uint32_t>(csr), GPR{imm & 0x1F}, 0b111, rd, 0b1110011);
 629  }
 630  void Assembler::CSRRS(GPR rd, CSR csr, GPR rs) noexcept {
 631      EmitIType(m_buffer, static_cast<uint32_t>(csr), rs, 0b010, rd, 0b1110011);
 632  }
 633  void Assembler::CSRRSI(GPR rd, CSR csr, uint32_t imm) noexcept {
 634      BISCUIT_ASSERT(imm <= 0x1F);
 635      EmitIType(m_buffer, static_cast<uint32_t>(csr), GPR{imm & 0x1F}, 0b110, rd, 0b1110011);
 636  }
 637  void Assembler::CSRRW(GPR rd, CSR csr, GPR rs) noexcept {
 638      EmitIType(m_buffer, static_cast<uint32_t>(csr), rs, 0b001, rd, 0b1110011);
 639  }
 640  void Assembler::CSRRWI(GPR rd, CSR csr, uint32_t imm) noexcept {
 641      BISCUIT_ASSERT(imm <= 0x1F);
 642      EmitIType(m_buffer, static_cast<uint32_t>(csr), GPR{imm & 0x1F}, 0b101, rd, 0b1110011);
 643  }
 644  
 645  void Assembler::CSRR(GPR rd, CSR csr) noexcept {
 646      CSRRS(rd, csr, x0);
 647  }
 648  void Assembler::CSWR(CSR csr, GPR rs) noexcept {
 649      CSRRW(x0, csr, rs);
 650  }
 651  
 652  void Assembler::CSRS(CSR csr, GPR rs) noexcept {
 653      CSRRS(x0, csr, rs);
 654  }
 655  void Assembler::CSRC(CSR csr, GPR rs) noexcept {
 656      CSRRC(x0, csr, rs);
 657  }
 658  
 659  void Assembler::CSRCI(CSR csr, uint32_t imm) noexcept {
 660      CSRRCI(x0, csr, imm);
 661  }
 662  void Assembler::CSRSI(CSR csr, uint32_t imm) noexcept {
 663      CSRRSI(x0, csr, imm);
 664  }
 665  void Assembler::CSRWI(CSR csr, uint32_t imm) noexcept {
 666      CSRRWI(x0, csr, imm);
 667  }
 668  
 669  void Assembler::FRCSR(GPR rd) noexcept {
 670      CSRRS(rd, CSR::FCSR, x0);
 671  }
 672  void Assembler::FSCSR(GPR rd, GPR rs) noexcept {
 673      CSRRW(rd, CSR::FCSR, rs);
 674  }
 675  void Assembler::FSCSR(GPR rs) noexcept {
 676      CSRRW(x0, CSR::FCSR, rs);
 677  }
 678  
 679  void Assembler::FRRM(GPR rd) noexcept {
 680      CSRRS(rd, CSR::FRM, x0);
 681  }
 682  void Assembler::FSRM(GPR rd, GPR rs) noexcept {
 683      CSRRW(rd, CSR::FRM, rs);
 684  }
 685  void Assembler::FSRM(GPR rs) noexcept {
 686      CSRRW(x0, CSR::FRM, rs);
 687  }
 688  
 689  void Assembler::FSRMI(GPR rd, uint32_t imm) noexcept {
 690      CSRRWI(rd, CSR::FRM, imm);
 691  }
 692  void Assembler::FSRMI(uint32_t imm) noexcept {
 693      CSRRWI(x0, CSR::FRM, imm);
 694  }
 695  
 696  void Assembler::FRFLAGS(GPR rd) noexcept {
 697      CSRRS(rd, CSR::FFlags, x0);
 698  }
 699  void Assembler::FSFLAGS(GPR rd, GPR rs) noexcept {
 700      CSRRW(rd, CSR::FFlags, rs);
 701  }
 702  void Assembler::FSFLAGS(GPR rs) noexcept {
 703      CSRRW(x0, CSR::FFlags, rs);
 704  }
 705  
 706  void Assembler::FSFLAGSI(GPR rd, uint32_t imm) noexcept {
 707      CSRRWI(rd, CSR::FFlags, imm);
 708  }
 709  void Assembler::FSFLAGSI(uint32_t imm) noexcept {
 710      CSRRWI(x0, CSR::FFlags, imm);
 711  }
 712  
 713  void Assembler::RDCYCLE(GPR rd) noexcept {
 714      CSRRS(rd, CSR::Cycle, x0);
 715  }
 716  void Assembler::RDCYCLEH(GPR rd) noexcept {
 717      CSRRS(rd, CSR::CycleH, x0);
 718  }
 719  
 720  void Assembler::RDINSTRET(GPR rd) noexcept {
 721      CSRRS(rd, CSR::InstRet, x0);
 722  }
 723  void Assembler::RDINSTRETH(GPR rd) noexcept {
 724      CSRRS(rd, CSR::InstRetH, x0);
 725  }
 726  
 727  void Assembler::RDTIME(GPR rd) noexcept {
 728      CSRRS(rd, CSR::Time, x0);
 729  }
 730  void Assembler::RDTIMEH(GPR rd) noexcept {
 731      CSRRS(rd, CSR::TimeH, x0);
 732  }
 733  
 734  // Zihintntl Extension Instructions
 735  
 736  void Assembler::C_NTL_ALL() noexcept {
 737      C_ADD(x0, x5);
 738  }
 739  void Assembler::C_NTL_S1() noexcept {
 740      C_ADD(x0, x4);
 741  }
 742  void Assembler::C_NTL_P1() noexcept {
 743      C_ADD(x0, x2);
 744  }
 745  void Assembler::C_NTL_PALL() noexcept {
 746      C_ADD(x0, x3);
 747  }
 748  void Assembler::NTL_ALL() noexcept {
 749      ADD(x0, x0, x5);
 750  }
 751  void Assembler::NTL_S1() noexcept {
 752      ADD(x0, x0, x4);
 753  }
 754  void Assembler::NTL_P1() noexcept {
 755      ADD(x0, x0, x2);
 756  }
 757  void Assembler::NTL_PALL() noexcept {
 758      ADD(x0, x0, x3);
 759  }
 760  
 761  // RV32M Extension Instructions
 762  
 763  void Assembler::DIV(GPR rd, GPR rs1, GPR rs2) noexcept {
 764      EmitRType(m_buffer, 0b0000001, rs2, rs1, 0b100, rd, 0b0110011);
 765  }
 766  void Assembler::DIVU(GPR rd, GPR rs1, GPR rs2) noexcept {
 767      EmitRType(m_buffer, 0b0000001, rs2, rs1, 0b101, rd, 0b0110011);
 768  }
 769  void Assembler::MUL(GPR rd, GPR rs1, GPR rs2) noexcept {
 770      EmitRType(m_buffer, 0b0000001, rs2, rs1, 0b000, rd, 0b0110011);
 771  }
 772  void Assembler::MULH(GPR rd, GPR rs1, GPR rs2) noexcept {
 773      EmitRType(m_buffer, 0b0000001, rs2, rs1, 0b001, rd, 0b0110011);
 774  }
 775  void Assembler::MULHSU(GPR rd, GPR rs1, GPR rs2) noexcept {
 776      EmitRType(m_buffer, 0b0000001, rs2, rs1, 0b010, rd, 0b0110011);
 777  }
 778  void Assembler::MULHU(GPR rd, GPR rs1, GPR rs2) noexcept {
 779      EmitRType(m_buffer, 0b0000001, rs2, rs1, 0b011, rd, 0b0110011);
 780  }
 781  void Assembler::REM(GPR rd, GPR rs1, GPR rs2) noexcept {
 782      EmitRType(m_buffer, 0b0000001, rs2, rs1, 0b110, rd, 0b0110011);
 783  }
 784  void Assembler::REMU(GPR rd, GPR rs1, GPR rs2) noexcept {
 785      EmitRType(m_buffer, 0b0000001, rs2, rs1, 0b111, rd, 0b0110011);
 786  }
 787  
 788  // RV64M Extension Instructions
 789  
 790  void Assembler::DIVW(GPR rd, GPR rs1, GPR rs2) noexcept {
 791      EmitRType(m_buffer, 0b0000001, rs2, rs1, 0b100, rd, 0b0111011);
 792  }
 793  void Assembler::DIVUW(GPR rd, GPR rs1, GPR rs2) noexcept {
 794      EmitRType(m_buffer, 0b0000001, rs2, rs1, 0b101, rd, 0b0111011);
 795  }
 796  void Assembler::MULW(GPR rd, GPR rs1, GPR rs2) noexcept {
 797      EmitRType(m_buffer, 0b0000001, rs2, rs1, 0b000, rd, 0b0111011);
 798  }
 799  void Assembler::REMW(GPR rd, GPR rs1, GPR rs2) noexcept {
 800      EmitRType(m_buffer, 0b0000001, rs2, rs1, 0b110, rd, 0b0111011);
 801  }
 802  void Assembler::REMUW(GPR rd, GPR rs1, GPR rs2) noexcept {
 803      EmitRType(m_buffer, 0b0000001, rs2, rs1, 0b111, rd, 0b0111011);
 804  }
 805  
 806  // RV32A Extension Instructions
 807  
 808  void Assembler::AMOADD_W(Ordering ordering, GPR rd, GPR rs2, GPR rs1) noexcept {
 809      EmitAtomic(m_buffer, 0b00000, ordering, rs2, rs1, 0b010, rd, 0b0101111);
 810  }
 811  void Assembler::AMOAND_W(Ordering ordering, GPR rd, GPR rs2, GPR rs1) noexcept {
 812      EmitAtomic(m_buffer, 0b01100, ordering, rs2, rs1, 0b010, rd, 0b0101111);
 813  }
 814  void Assembler::AMOMAX_W(Ordering ordering, GPR rd, GPR rs2, GPR rs1) noexcept {
 815      EmitAtomic(m_buffer, 0b10100, ordering, rs2, rs1, 0b010, rd, 0b0101111);
 816  }
 817  void Assembler::AMOMAXU_W(Ordering ordering, GPR rd, GPR rs2, GPR rs1) noexcept {
 818      EmitAtomic(m_buffer, 0b11100, ordering, rs2, rs1, 0b010, rd, 0b0101111);
 819  }
 820  void Assembler::AMOMIN_W(Ordering ordering, GPR rd, GPR rs2, GPR rs1) noexcept {
 821      EmitAtomic(m_buffer, 0b10000, ordering, rs2, rs1, 0b010, rd, 0b0101111);
 822  }
 823  void Assembler::AMOMINU_W(Ordering ordering, GPR rd, GPR rs2, GPR rs1) noexcept {
 824      EmitAtomic(m_buffer, 0b11000, ordering, rs2, rs1, 0b010, rd, 0b0101111);
 825  }
 826  void Assembler::AMOOR_W(Ordering ordering, GPR rd, GPR rs2, GPR rs1) noexcept {
 827      EmitAtomic(m_buffer, 0b01000, ordering, rs2, rs1, 0b010, rd, 0b0101111);
 828  }
 829  void Assembler::AMOSWAP_W(Ordering ordering, GPR rd, GPR rs2, GPR rs1) noexcept {
 830      EmitAtomic(m_buffer, 0b00001, ordering, rs2, rs1, 0b010, rd, 0b0101111);
 831  }
 832  void Assembler::AMOXOR_W(Ordering ordering, GPR rd, GPR rs2, GPR rs1) noexcept {
 833      EmitAtomic(m_buffer, 0b00100, ordering, rs2, rs1, 0b010, rd, 0b0101111);
 834  }
 835  void Assembler::LR_W(Ordering ordering, GPR rd, GPR rs) noexcept {
 836      EmitAtomic(m_buffer, 0b00010, ordering, x0, rs, 0b010, rd, 0b0101111);
 837  }
 838  void Assembler::SC_W(Ordering ordering, GPR rd, GPR rs2, GPR rs1) noexcept {
 839      EmitAtomic(m_buffer, 0b00011, ordering, rs2, rs1, 0b010, rd, 0b0101111);
 840  }
 841  
 842  // RV64A Extension Instructions
 843  
 844  void Assembler::AMOADD_D(Ordering ordering, GPR rd, GPR rs2, GPR rs1) noexcept {
 845      BISCUIT_ASSERT(IsRV64(m_features));
 846      EmitAtomic(m_buffer, 0b00000, ordering, rs2, rs1, 0b011, rd, 0b0101111);
 847  }
 848  void Assembler::AMOAND_D(Ordering ordering, GPR rd, GPR rs2, GPR rs1) noexcept {
 849      BISCUIT_ASSERT(IsRV64(m_features));
 850      EmitAtomic(m_buffer, 0b01100, ordering, rs2, rs1, 0b011, rd, 0b0101111);
 851  }
 852  void Assembler::AMOMAX_D(Ordering ordering, GPR rd, GPR rs2, GPR rs1) noexcept {
 853      BISCUIT_ASSERT(IsRV64(m_features));
 854      EmitAtomic(m_buffer, 0b10100, ordering, rs2, rs1, 0b011, rd, 0b0101111);
 855  }
 856  void Assembler::AMOMAXU_D(Ordering ordering, GPR rd, GPR rs2, GPR rs1) noexcept {
 857      BISCUIT_ASSERT(IsRV64(m_features));
 858      EmitAtomic(m_buffer, 0b11100, ordering, rs2, rs1, 0b011, rd, 0b0101111);
 859  }
 860  void Assembler::AMOMIN_D(Ordering ordering, GPR rd, GPR rs2, GPR rs1) noexcept {
 861      BISCUIT_ASSERT(IsRV64(m_features));
 862      EmitAtomic(m_buffer, 0b10000, ordering, rs2, rs1, 0b011, rd, 0b0101111);
 863  }
 864  void Assembler::AMOMINU_D(Ordering ordering, GPR rd, GPR rs2, GPR rs1) noexcept {
 865      BISCUIT_ASSERT(IsRV64(m_features));
 866      EmitAtomic(m_buffer, 0b11000, ordering, rs2, rs1, 0b011, rd, 0b0101111);
 867  }
 868  void Assembler::AMOOR_D(Ordering ordering, GPR rd, GPR rs2, GPR rs1) noexcept {
 869      BISCUIT_ASSERT(IsRV64(m_features));
 870      EmitAtomic(m_buffer, 0b01000, ordering, rs2, rs1, 0b011, rd, 0b0101111);
 871  }
 872  void Assembler::AMOSWAP_D(Ordering ordering, GPR rd, GPR rs2, GPR rs1) noexcept {
 873      BISCUIT_ASSERT(IsRV64(m_features));
 874      EmitAtomic(m_buffer, 0b00001, ordering, rs2, rs1, 0b011, rd, 0b0101111);
 875  }
 876  void Assembler::AMOXOR_D(Ordering ordering, GPR rd, GPR rs2, GPR rs1) noexcept {
 877      BISCUIT_ASSERT(IsRV64(m_features));
 878      EmitAtomic(m_buffer, 0b00100, ordering, rs2, rs1, 0b011, rd, 0b0101111);
 879  }
 880  void Assembler::LR_D(Ordering ordering, GPR rd, GPR rs) noexcept {
 881      BISCUIT_ASSERT(IsRV64(m_features));
 882      EmitAtomic(m_buffer, 0b00010, ordering, x0, rs, 0b011, rd, 0b0101111);
 883  }
 884  void Assembler::SC_D(Ordering ordering, GPR rd, GPR rs2, GPR rs1) noexcept {
 885      BISCUIT_ASSERT(IsRV64(m_features));
 886      EmitAtomic(m_buffer, 0b00011, ordering, rs2, rs1, 0b011, rd, 0b0101111);
 887  }
 888  
 889  // RVB Extension Instructions
 890  
 891  void Assembler::ADDUW(GPR rd, GPR rs1, GPR rs2) noexcept {
 892      BISCUIT_ASSERT(IsRV64(m_features));
 893      EmitRType(m_buffer, 0b0000100, rs2, rs1, 0b000, rd, 0b0111011);
 894  }
 895  
 896  void Assembler::ANDN(GPR rd, GPR rs1, GPR rs2) noexcept {
 897      EmitRType(m_buffer, 0b0100000, rs2, rs1, 0b111, rd, 0b0110011);
 898  }
 899  
 900  void Assembler::BCLR(GPR rd, GPR rs1, GPR rs2) noexcept {
 901      EmitRType(m_buffer, 0b0100100, rs2, rs1, 0b001, rd, 0b0110011);
 902  }
 903  
 904  void Assembler::BCLRI(GPR rd, GPR rs, uint32_t bit) noexcept {
 905      if (IsRV32(m_features)) {
 906          BISCUIT_ASSERT(bit <= 31);
 907      } else {
 908          BISCUIT_ASSERT(bit <= 63);
 909      }
 910  
 911      const auto imm = (0b010010U << 6) | bit;
 912      EmitIType(m_buffer, imm, rs, 0b001, rd, 0b0010011);
 913  }
 914  
 915  void Assembler::BEXT(GPR rd, GPR rs1, GPR rs2) noexcept {
 916      EmitRType(m_buffer, 0b0100100, rs2, rs1, 0b101, rd, 0b0110011);
 917  }
 918  
 919  void Assembler::BEXTI(GPR rd, GPR rs, uint32_t bit) noexcept {
 920      if (IsRV32(m_features)) {
 921          BISCUIT_ASSERT(bit <= 31);
 922      } else {
 923          BISCUIT_ASSERT(bit <= 63);
 924      }
 925  
 926      const auto imm = (0b010010U << 6) | bit;
 927      EmitIType(m_buffer, imm, rs, 0b101, rd, 0b0010011);
 928  }
 929  
 930  void Assembler::BINV(GPR rd, GPR rs1, GPR rs2) noexcept {
 931      EmitRType(m_buffer, 0b0110100, rs2, rs1, 0b001, rd, 0b0110011);
 932  }
 933  
 934  void Assembler::BINVI(GPR rd, GPR rs, uint32_t bit) noexcept {
 935      if (IsRV32(m_features)) {
 936          BISCUIT_ASSERT(bit <= 31);
 937      } else {
 938          BISCUIT_ASSERT(bit <= 63);
 939      }
 940  
 941      const auto imm = (0b011010U << 6) | bit;
 942      EmitIType(m_buffer, imm, rs, 0b001, rd, 0b0010011);
 943  }
 944  
 945  void Assembler::BREV8(GPR rd, GPR rs) noexcept {
 946      EmitIType(m_buffer, 0b011010000111, rs, 0b101, rd, 0b0010011);
 947  }
 948  
 949  void Assembler::BSET(GPR rd, GPR rs1, GPR rs2) noexcept {
 950      EmitRType(m_buffer, 0b0010100, rs2, rs1, 0b001, rd, 0b0110011);
 951  }
 952  
 953  void Assembler::BSETI(GPR rd, GPR rs, uint32_t bit) noexcept {
 954      if (IsRV32(m_features)) {
 955          BISCUIT_ASSERT(bit <= 31);
 956      } else {
 957          BISCUIT_ASSERT(bit <= 63);
 958      }
 959  
 960      const auto imm = (0b001010U << 6) | bit;
 961      EmitIType(m_buffer, imm, rs, 0b001, rd, 0b0110011);
 962  }
 963  
 964  void Assembler::CLMUL(GPR rd, GPR rs1, GPR rs2) noexcept {
 965      EmitRType(m_buffer, 0b0000101, rs2, rs1, 0b001, rd, 0b0110011);
 966  }
 967  
 968  void Assembler::CLMULH(GPR rd, GPR rs1, GPR rs2) noexcept {
 969      EmitRType(m_buffer, 0b0000101, rs2, rs1, 0b011, rd, 0b0110011);
 970  }
 971  
 972  void Assembler::CLMULR(GPR rd, GPR rs1, GPR rs2) noexcept {
 973      EmitRType(m_buffer, 0b0000101, rs2, rs1, 0b010, rd, 0b0110011);
 974  }
 975  
 976  void Assembler::CLZ(GPR rd, GPR rs) noexcept {
 977      EmitIType(m_buffer, 0b011000000000, rs, 0b001, rd, 0b0010011);
 978  }
 979  
 980  void Assembler::CLZW(GPR rd, GPR rs) noexcept {
 981      BISCUIT_ASSERT(IsRV64(m_features));
 982      EmitIType(m_buffer, 0b011000000000, rs, 0b001, rd, 0b0011011);
 983  }
 984  
 985  void Assembler::CPOP(GPR rd, GPR rs) noexcept {
 986      EmitIType(m_buffer, 0b011000000010, rs, 0b001, rd, 0b0010011);
 987  }
 988  
 989  void Assembler::CPOPW(GPR rd, GPR rs) noexcept {
 990      BISCUIT_ASSERT(IsRV64(m_features));
 991      EmitIType(m_buffer, 0b011000000010, rs, 0b001, rd, 0b0011011);
 992  }
 993  
 994  void Assembler::CTZ(GPR rd, GPR rs) noexcept {
 995      EmitIType(m_buffer, 0b011000000001, rs, 0b001, rd, 0b0010011);
 996  }
 997  
 998  void Assembler::CTZW(GPR rd, GPR rs) noexcept {
 999      BISCUIT_ASSERT(IsRV64(m_features));
1000      EmitIType(m_buffer, 0b011000000001, rs, 0b001, rd, 0b0011011);
1001  }
1002  
1003  void Assembler::MAX(GPR rd, GPR rs1, GPR rs2) noexcept {
1004      EmitRType(m_buffer, 0b0000101, rs2, rs1, 0b110, rd, 0b0110011);
1005  }
1006  
1007  void Assembler::MAXU(GPR rd, GPR rs1, GPR rs2) noexcept {
1008      EmitRType(m_buffer, 0b0000101, rs2, rs1, 0b111, rd, 0b0110011);
1009  }
1010  
1011  void Assembler::MIN(GPR rd, GPR rs1, GPR rs2) noexcept {
1012      EmitRType(m_buffer, 0b0000101, rs2, rs1, 0b100, rd, 0b0110011);
1013  }
1014  
1015  void Assembler::MINU(GPR rd, GPR rs1, GPR rs2) noexcept {
1016      EmitRType(m_buffer, 0b0000101, rs2, rs1, 0b101, rd, 0b0110011);
1017  }
1018  
1019  void Assembler::ORCB(GPR rd, GPR rs) noexcept {
1020      EmitIType(m_buffer, 0b001010000111, rs, 0b101, rd, 0b0010011);
1021  }
1022  
1023  void Assembler::ORN(GPR rd, GPR rs1, GPR rs2) noexcept {
1024      EmitRType(m_buffer, 0b0100000, rs2, rs1, 0b110, rd, 0b0110011);
1025  }
1026  
1027  void Assembler::PACK(GPR rd, GPR rs1, GPR rs2) noexcept {
1028      EmitRType(m_buffer, 0b0000100, rs2, rs1, 0b100, rd, 0b0110011);
1029  }
1030  
1031  void Assembler::PACKH(GPR rd, GPR rs1, GPR rs2) noexcept {
1032      EmitRType(m_buffer, 0b0000100, rs2, rs1, 0b111, rd, 0b0110011);
1033  }
1034  
1035  void Assembler::PACKW(GPR rd, GPR rs1, GPR rs2) noexcept {
1036      BISCUIT_ASSERT(IsRV64(m_features));
1037      EmitRType(m_buffer, 0b0000100, rs2, rs1, 0b100, rd, 0b0111011);
1038  }
1039  
1040  void Assembler::REV8(GPR rd, GPR rs) noexcept {
1041      if (IsRV32(m_features)) {
1042          EmitIType(m_buffer, 0b011010011000, rs, 0b101, rd, 0b0010011);
1043      } else {
1044          EmitIType(m_buffer, 0b011010111000, rs, 0b101, rd, 0b0010011);
1045      }
1046  }
1047  
1048  void Assembler::ROL(GPR rd, GPR rs1, GPR rs2) noexcept {
1049      EmitRType(m_buffer, 0b0110000, rs2, rs1, 0b001, rd, 0b0110011);
1050  }
1051  
1052  void Assembler::ROLW(GPR rd, GPR rs1, GPR rs2) noexcept {
1053      BISCUIT_ASSERT(IsRV64(m_features));
1054      EmitRType(m_buffer, 0b0110000, rs2, rs1, 0b001, rd, 0b0111011);
1055  }
1056  
1057  void Assembler::ROR(GPR rd, GPR rs1, GPR rs2) noexcept {
1058      EmitRType(m_buffer, 0b0110000, rs2, rs1, 0b101, rd, 0b0110011);
1059  }
1060  
1061  void Assembler::RORI(GPR rd, GPR rs, uint32_t rotate_amount) noexcept {
1062      BISCUIT_ASSERT(rotate_amount <= 63);
1063      const auto imm = (0b011000U << 6) | rotate_amount;
1064      EmitIType(m_buffer, imm, rs, 0b101, rd, 0b0010011);
1065  }
1066  
1067  void Assembler::RORIW(GPR rd, GPR rs, uint32_t rotate_amount) noexcept {
1068      BISCUIT_ASSERT(IsRV64(m_features));
1069      BISCUIT_ASSERT(rotate_amount <= 63);
1070      const auto imm = (0b011000U << 6) | rotate_amount;
1071      EmitIType(m_buffer, imm, rs, 0b101, rd, 0b0011011);
1072  }
1073  
1074  void Assembler::RORW(GPR rd, GPR rs1, GPR rs2) noexcept {
1075      BISCUIT_ASSERT(IsRV64(m_features));
1076      EmitRType(m_buffer, 0b0110000, rs2, rs1, 0b101, rd, 0b0111011);
1077  }
1078  
1079  void Assembler::SEXTB(GPR rd, GPR rs) noexcept {
1080      EmitIType(m_buffer, 0b011000000100, rs, 0b001, rd, 0b0010011);
1081  }
1082  
1083  void Assembler::SEXTH(GPR rd, GPR rs) noexcept {
1084      EmitIType(m_buffer, 0b011000000101, rs, 0b001, rd, 0b0010011);
1085  }
1086  
1087  void Assembler::SH1ADD(GPR rd, GPR rs1, GPR rs2) noexcept {
1088      EmitRType(m_buffer, 0b0010000, rs2, rs1, 0b010, rd, 0b0110011);
1089  }
1090  
1091  void Assembler::SH1ADDUW(GPR rd, GPR rs1, GPR rs2) noexcept {
1092      BISCUIT_ASSERT(IsRV64(m_features));
1093      EmitRType(m_buffer, 0b0010000, rs2, rs1, 0b010, rd, 0b0111011);
1094  }
1095  
1096  void Assembler::SH2ADD(GPR rd, GPR rs1, GPR rs2) noexcept {
1097      EmitRType(m_buffer, 0b0010000, rs2, rs1, 0b100, rd, 0b0110011);
1098  }
1099  
1100  void Assembler::SH2ADDUW(GPR rd, GPR rs1, GPR rs2) noexcept {
1101      BISCUIT_ASSERT(IsRV64(m_features));
1102      EmitRType(m_buffer, 0b0010000, rs2, rs1, 0b100, rd, 0b0111011);
1103  }
1104  
1105  void Assembler::SH3ADD(GPR rd, GPR rs1, GPR rs2) noexcept {
1106      EmitRType(m_buffer, 0b0010000, rs2, rs1, 0b110, rd, 0b0110011);
1107  }
1108  
1109  void Assembler::SH3ADDUW(GPR rd, GPR rs1, GPR rs2) noexcept {
1110      BISCUIT_ASSERT(IsRV64(m_features));
1111      EmitRType(m_buffer, 0b0010000, rs2, rs1, 0b110, rd, 0b0111011);
1112  }
1113  
1114  void Assembler::SLLIUW(GPR rd, GPR rs, uint32_t shift_amount) noexcept {
1115      BISCUIT_ASSERT(IsRV64(m_features));
1116      BISCUIT_ASSERT(shift_amount <= 63);
1117      const auto imm = (0b000010U << 6) | shift_amount;
1118      EmitIType(m_buffer, imm, rs, 0b001, rd, 0b0011011);
1119  }
1120  
1121  void Assembler::UNZIP(GPR rd, GPR rs) noexcept {
1122      BISCUIT_ASSERT(IsRV32(m_features));
1123      EmitIType(m_buffer, 0b000010011111, rs, 0b101, rd, 0b0010011);
1124  }
1125  
1126  void Assembler::XNOR(GPR rd, GPR rs1, GPR rs2) noexcept {
1127      EmitRType(m_buffer, 0b0100000, rs2, rs1, 0b100, rd, 0b0110011);
1128  }
1129  
1130  void Assembler::XPERM4(GPR rd, GPR rs1, GPR rs2) noexcept {
1131      EmitRType(m_buffer, 0b0010100, rs2, rs1, 0b010, rd, 0b0110011);
1132  }
1133  
1134  void Assembler::XPERM8(GPR rd, GPR rs1, GPR rs2) noexcept {
1135      EmitRType(m_buffer, 0b0010100, rs2, rs1, 0b100, rd, 0b0110011);
1136  }
1137  
1138  void Assembler::ZEXTH(GPR rd, GPR rs) noexcept {
1139      if (IsRV32(m_features)) {
1140          EmitIType(m_buffer, 0b000010000000, rs, 0b100, rd, 0b0110011);
1141      } else {
1142          EmitIType(m_buffer, 0b000010000000, rs, 0b100, rd, 0b0111011);
1143      }
1144  }
1145  
1146  void Assembler::ZEXTW(GPR rd, GPR rs) noexcept {
1147      ADDUW(rd, rs, x0);
1148  }
1149  
1150  void Assembler::ZIP(GPR rd, GPR rs) noexcept {
1151      BISCUIT_ASSERT(IsRV32(m_features));
1152      EmitIType(m_buffer, 0b000010011110, rs, 0b001, rd, 0b0010011);
1153  }
1154  
1155  // Cache Management Operation Extension Instructions
1156  
1157  void Assembler::CBO_CLEAN(GPR rs) noexcept {
1158      EmitRType(m_buffer, 0b0000000, x1, rs, 0b010, x0, 0b0001111);
1159  }
1160  
1161  void Assembler::CBO_FLUSH(GPR rs) noexcept {
1162      EmitRType(m_buffer, 0b0000000, x2, rs, 0b010, x0, 0b0001111);
1163  }
1164  
1165  void Assembler::CBO_INVAL(GPR rs) noexcept {
1166      EmitRType(m_buffer, 0b0000000, x0, rs, 0b010, x0, 0b0001111);
1167  }
1168  
1169  void Assembler::CBO_ZERO(GPR rs) noexcept {
1170      EmitRType(m_buffer, 0b0000000, x4, rs, 0b010, x0, 0b0001111);
1171  }
1172  
1173  void Assembler::PREFETCH_I(GPR rs, int32_t offset) noexcept {
1174      // Offset must be able to fit in a 12-bit signed immediate and be
1175      // cleanly divisible by 32 since the bottom 5 bits are encoded as zero.
1176      BISCUIT_ASSERT(IsValidSigned12BitImm(offset));
1177      BISCUIT_ASSERT(offset % 32 == 0);
1178      EmitIType(m_buffer, static_cast<uint32_t>(offset), rs, 0b110, x0, 0b0010011);
1179  }
1180  
1181  void Assembler::PREFETCH_R(GPR rs, int32_t offset) noexcept {
1182      // Offset must be able to fit in a 12-bit signed immediate and be
1183      // cleanly divisible by 32 since the bottom 5 bits are encoded as zero.
1184      BISCUIT_ASSERT(IsValidSigned12BitImm(offset));
1185      BISCUIT_ASSERT(offset % 32 == 0);
1186      EmitIType(m_buffer, static_cast<uint32_t>(offset) | 0b01, rs, 0b110, x0, 0b0010011);
1187  }
1188  
1189  void Assembler::PREFETCH_W(GPR rs, int32_t offset) noexcept {
1190      // Offset must be able to fit in a 12-bit signed immediate and be
1191      // cleanly divisible by 32 since the bottom 5 bits are encoded as zero.
1192      BISCUIT_ASSERT(IsValidSigned12BitImm(offset));
1193      BISCUIT_ASSERT(offset % 32 == 0);
1194      EmitIType(m_buffer, static_cast<uint32_t>(offset) | 0b11, rs, 0b110, x0, 0b0010011);
1195  }
1196  
1197  // Privileged Instructions
1198  
1199  void Assembler::HFENCE_GVMA(GPR rs1, GPR rs2) noexcept {
1200      EmitRType(m_buffer, 0b0110001, rs2, rs1, 0b000, x0, 0b1110011);
1201  }
1202  
1203  void Assembler::HFENCE_VVMA(GPR rs1, GPR rs2) noexcept {
1204      EmitRType(m_buffer, 0b0010001, rs2, rs1, 0b000, x0, 0b1110011);
1205  }
1206  
1207  void Assembler::HINVAL_GVMA(GPR rs1, GPR rs2) noexcept {
1208      EmitRType(m_buffer, 0b0110011, rs2, rs1, 0b000, x0, 0b1110011);
1209  }
1210  
1211  void Assembler::HINVAL_VVMA(GPR rs1, GPR rs2) noexcept {
1212      EmitRType(m_buffer, 0b0010011, rs2, rs1, 0b000, x0, 0b1110011);
1213  }
1214  
1215  void Assembler::HLV_B(GPR rd, GPR rs) noexcept {
1216      EmitRType(m_buffer, 0b0110000, x0, rs, 0b100, rd, 0b1110011);
1217  }
1218  
1219  void Assembler::HLV_BU(GPR rd, GPR rs) noexcept {
1220      EmitRType(m_buffer, 0b0110000, x1, rs, 0b100, rd, 0b1110011);
1221  }
1222  
1223  void Assembler::HLV_D(GPR rd, GPR rs) noexcept {
1224      BISCUIT_ASSERT(IsRV64(m_features));
1225      EmitRType(m_buffer, 0b0110110, x0, rs, 0b100, rd, 0b1110011);
1226  }
1227  
1228  void Assembler::HLV_H(GPR rd, GPR rs) noexcept {
1229      EmitRType(m_buffer, 0b0110010, x0, rs, 0b100, rd, 0b1110011);
1230  }
1231  
1232  void Assembler::HLV_HU(GPR rd, GPR rs) noexcept {
1233      EmitRType(m_buffer, 0b0110010, x1, rs, 0b100, rd, 0b1110011);
1234  }
1235  
1236  void Assembler::HLV_W(GPR rd, GPR rs) noexcept {
1237      EmitRType(m_buffer, 0b0110100, x0, rs, 0b100, rd, 0b1110011);
1238  }
1239  
1240  void Assembler::HLV_WU(GPR rd, GPR rs) noexcept {
1241      BISCUIT_ASSERT(IsRV64(m_features));
1242      EmitRType(m_buffer, 0b0110100, x1, rs, 0b100, rd, 0b1110011);
1243  }
1244  
1245  void Assembler::HLVX_HU(GPR rd, GPR rs) noexcept {
1246      EmitRType(m_buffer, 0b0110010, x3, rs, 0b100, rd, 0b1110011);
1247  }
1248  
1249  void Assembler::HLVX_WU(GPR rd, GPR rs) noexcept {
1250      EmitRType(m_buffer, 0b0110100, x3, rs, 0b100, rd, 0b1110011);
1251  }
1252  
1253  void Assembler::HSV_B(GPR rs2, GPR rs1) noexcept {
1254      EmitRType(m_buffer, 0b0110001, rs2, rs1, 0b100, x0, 0b1110011);
1255  }
1256  
1257  void Assembler::HSV_D(GPR rs2, GPR rs1) noexcept {
1258      BISCUIT_ASSERT(IsRV64(m_features));
1259      EmitRType(m_buffer, 0b0110111, rs2, rs1, 0b100, x0, 0b1110011);
1260  }
1261  
1262  void Assembler::HSV_H(GPR rs2, GPR rs1) noexcept {
1263      EmitRType(m_buffer, 0b0110011, rs2, rs1, 0b100, x0, 0b1110011);
1264  }
1265  
1266  void Assembler::HSV_W(GPR rs2, GPR rs1) noexcept {
1267      EmitRType(m_buffer, 0b0110101, rs2, rs1, 0b100, x0, 0b1110011);
1268  }
1269  
1270  void Assembler::MRET() noexcept {
1271      m_buffer.Emit32(0x30200073);
1272  }
1273  
1274  void Assembler::SFENCE_INVAL_IR() noexcept {
1275      m_buffer.Emit32(0x18100073U);
1276  }
1277  
1278  void Assembler::SFENCE_VMA(GPR rs1, GPR rs2) noexcept {
1279      EmitRType(m_buffer, 0b0001001, rs2, rs1, 0b000, x0, 0b1110011);
1280  }
1281  
1282  void Assembler::SFENCE_W_INVAL() noexcept {
1283      m_buffer.Emit32(0x18000073U);
1284  }
1285  
1286  void Assembler::SINVAL_VMA(GPR rs1, GPR rs2) noexcept {
1287      EmitRType(m_buffer, 0b0001011, rs2, rs1, 0b000, x0, 0b1110011);
1288  }
1289  
1290  void Assembler::SRET() noexcept {
1291      m_buffer.Emit32(0x10200073);
1292  }
1293  
1294  void Assembler::URET() noexcept {
1295      m_buffer.Emit32(0x00200073);
1296  }
1297  
1298  void Assembler::WFI() noexcept {
1299      m_buffer.Emit32(0x10500073);
1300  }
1301  
1302  void Assembler::BindToOffset(Label* label, Label::LocationOffset offset) {
1303      BISCUIT_ASSERT(label != nullptr);
1304      BISCUIT_ASSERT(offset >= 0 && offset <= m_buffer.GetCursorOffset());
1305  
1306      label->Bind(offset);
1307      ResolveLabelOffsets(label);
1308      label->ClearOffsets();
1309  }
1310  
1311  ptrdiff_t Assembler::LinkAndGetOffset(Label* label) {
1312      BISCUIT_ASSERT(label != nullptr);
1313  
1314      // If we have a bound label, then it's straightforward to calculate
1315      // the offsets.
1316      if (label->IsBound()) {
1317          const auto cursor_address = m_buffer.GetCursorAddress();
1318          const auto label_offset = m_buffer.GetOffsetAddress(*label->GetLocation());
1319          return static_cast<ptrdiff_t>(label_offset - cursor_address);
1320      }
1321  
1322      // If we don't have a bound location, we return an offset of zero.
1323      // While the emitter will emit a bogus branch instruction initially,
1324      // the offset will be patched over once the label has been properly
1325      // bound to a location.
1326      label->AddOffset(m_buffer.GetCursorOffset());
1327      return 0;
1328  }
1329  
1330  void Assembler::ResolveLabelOffsets(Label* label) {
1331      // Conditional branch instructions make use of the B-type immediate encoding for offsets.
1332      const auto is_b_type = [](uint32_t instruction) {
1333          return (instruction & 0x7F) == 0b1100011;
1334      };
1335      // JAL makes use of the J-type immediate encoding for offsets.
1336      const auto is_j_type = [](uint32_t instruction) {
1337          return (instruction & 0x7F) == 0b1101111;
1338      };
1339      // C.BEQZ and C.BNEZ make use of this encoding type.
1340      const auto is_cb_type = [](uint32_t instruction) {
1341          const auto op = instruction & 0b11;
1342          const auto funct3 = instruction & 0xE000;
1343          return op == 0b01 && funct3 >= 0xC000;
1344      };
1345      // C.JAL and C.J make use of this encoding type.
1346      const auto is_cj_type = [](uint32_t instruction) {
1347          const auto op = instruction & 0b11;
1348          const auto funct3 = instruction & 0xE000;
1349          return op == 0b01 && (funct3 == 0x2000 || funct3 == 0xA000);
1350      };
1351      // If we know an instruction is a compressed branch, then it's a 16-bit instruction
1352      // Otherwise it's a regular-sized 32-bit instruction.
1353      const auto determine_inst_size = [&](uint32_t instruction) -> size_t {
1354          if (is_cj_type(instruction) || is_cb_type(instruction)) {
1355              return 2;
1356          } else {
1357              return 4;
1358          }
1359      };
1360  
1361      const auto label_location = *label->GetLocation();
1362  
1363      for (const auto offset : label->m_offsets) {
1364          const auto address = m_buffer.GetOffsetAddress(offset);
1365          auto* const ptr = reinterpret_cast<uint8_t*>(address);
1366          const auto inst_size = determine_inst_size(uint32_t{*ptr} | (uint32_t{*(ptr + 1)} << 8));
1367  
1368          uint32_t instruction = 0;
1369          std::memcpy(&instruction, ptr, inst_size);
1370  
1371          // Given all branch instructions we need to patch have 0 encoded as
1372          // their branch offset, we don't need to worry about any masking work.
1373          //
1374          // It's enough to verify that the immediate is going to be valid
1375          // and then OR it into the instruction.
1376  
1377          const auto encoded_offset = label_location - offset;
1378  
1379          if (inst_size == sizeof(uint32_t)) {
1380              if (is_b_type(instruction)) {
1381                  BISCUIT_ASSERT(IsValidBTypeImm(encoded_offset));
1382                  instruction |= TransformToBTypeImm(static_cast<uint32_t>(encoded_offset));
1383              } else if (is_j_type(instruction)) {
1384                  BISCUIT_ASSERT(IsValidJTypeImm(encoded_offset));
1385                  instruction |= TransformToJTypeImm(static_cast<uint32_t>(encoded_offset));
1386              }
1387          } else {
1388              if (is_cb_type(instruction)) {
1389                  BISCUIT_ASSERT(IsValidCBTypeImm(encoded_offset));
1390                  instruction |= TransformToCBTypeImm(static_cast<uint32_t>(encoded_offset));
1391              } else if (is_cj_type(instruction)) {
1392                  BISCUIT_ASSERT(IsValidCJTypeImm(encoded_offset));
1393                  instruction |= TransformToCJTypeImm(static_cast<uint32_t>(encoded_offset));
1394              }
1395          }
1396  
1397          std::memcpy(ptr, &instruction, inst_size);
1398      }
1399  }
1400  
1401  } // namespace biscuit