summaryrefslogtreecommitdiffstats
path: root/js/src/jit/riscv64/extension/base-riscv-i.h
blob: cca342c960149439a996a9703016f392eabf1331 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
// Copyright 2022 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef jit_riscv64_extension_Base_riscv_i_h_
#define jit_riscv64_extension_Base_riscv_i_h_
#include "mozilla/Assertions.h"

#include <stdint.h>

#include "jit/riscv64/constant/Constant-riscv64.h"
#include "jit/riscv64/extension/base-assembler-riscv.h"
namespace js {
namespace jit {

class AssemblerRISCVI : public AssemblerRiscvBase {
 public:
  void lui(Register rd, int32_t imm20);
  void auipc(Register rd, int32_t imm20);

  // Jumps
  void jal(Register rd, int32_t imm20);
  void jalr(Register rd, Register rs1, int16_t imm12);

  // Branches
  void beq(Register rs1, Register rs2, int16_t imm12);
  void bne(Register rs1, Register rs2, int16_t imm12);
  void blt(Register rs1, Register rs2, int16_t imm12);
  void bge(Register rs1, Register rs2, int16_t imm12);
  void bltu(Register rs1, Register rs2, int16_t imm12);
  void bgeu(Register rs1, Register rs2, int16_t imm12);
  // Loads
  void lb(Register rd, Register rs1, int16_t imm12);
  void lh(Register rd, Register rs1, int16_t imm12);
  void lw(Register rd, Register rs1, int16_t imm12);
  void lbu(Register rd, Register rs1, int16_t imm12);
  void lhu(Register rd, Register rs1, int16_t imm12);

  // Stores
  void sb(Register source, Register base, int16_t imm12);
  void sh(Register source, Register base, int16_t imm12);
  void sw(Register source, Register base, int16_t imm12);

  // Arithmetic with immediate
  void addi(Register rd, Register rs1, int16_t imm12);
  void slti(Register rd, Register rs1, int16_t imm12);
  void sltiu(Register rd, Register rs1, int16_t imm12);
  void xori(Register rd, Register rs1, int16_t imm12);
  void ori(Register rd, Register rs1, int16_t imm12);
  void andi(Register rd, Register rs1, int16_t imm12);
  void slli(Register rd, Register rs1, uint8_t shamt);
  void srli(Register rd, Register rs1, uint8_t shamt);
  void srai(Register rd, Register rs1, uint8_t shamt);

  // Arithmetic
  void add(Register rd, Register rs1, Register rs2);
  void sub(Register rd, Register rs1, Register rs2);
  void sll(Register rd, Register rs1, Register rs2);
  void slt(Register rd, Register rs1, Register rs2);
  void sltu(Register rd, Register rs1, Register rs2);
  void xor_(Register rd, Register rs1, Register rs2);
  void srl(Register rd, Register rs1, Register rs2);
  void sra(Register rd, Register rs1, Register rs2);
  void or_(Register rd, Register rs1, Register rs2);
  void and_(Register rd, Register rs1, Register rs2);

  // Other pseudo instructions that are not part of RISCV pseudo assemly
  void nor(Register rd, Register rs, Register rt) {
    or_(rd, rs, rt);
    not_(rd, rd);
  }

  // Memory fences
  void fence(uint8_t pred, uint8_t succ);
  void fence_tso();

  // Environment call / break
  void ecall();
  void ebreak();

  void sync() { fence(0b1111, 0b1111); }

  // This is a de facto standard (as set by GNU binutils) 32-bit unimplemented
  // instruction (i.e., it should always trap, if your implementation has
  // invalid instruction traps).
  void unimp();

  static int JumpOffset(Instr instr);
  static int AuipcOffset(Instr instr);
  static int JalrOffset(Instr instr);
  static int LoadOffset(Instr instr);
  static int BranchOffset(Instr instr);
  static int BrachlongOffset(Instr auipc, Instr instr_I);
  static inline Instr SetBranchOffset(int32_t pos, int32_t target_pos,
                                      Instr instr) {
    int32_t imm = target_pos - pos;
    MOZ_ASSERT((imm & 1) == 0);
    MOZ_ASSERT(is_intn(imm, kBranchOffsetBits));

    instr &= ~kBImm12Mask;
    int32_t imm12 = ((imm & 0x800) >> 4) |   // bit  11
                    ((imm & 0x1e) << 7) |    // bits 4-1
                    ((imm & 0x7e0) << 20) |  // bits 10-5
                    ((imm & 0x1000) << 19);  // bit 12

    return instr | (imm12 & kBImm12Mask);
  }

  static inline Instr SetJalOffset(int32_t pos, int32_t target_pos,
                                   Instr instr) {
    MOZ_ASSERT(IsJal(instr));
    int32_t imm = target_pos - pos;
    MOZ_ASSERT((imm & 1) == 0);
    MOZ_ASSERT(is_intn(imm, kJumpOffsetBits));

    instr &= ~kImm20Mask;
    int32_t imm20 = (imm & 0xff000) |          // bits 19-12
                    ((imm & 0x800) << 9) |     // bit  11
                    ((imm & 0x7fe) << 20) |    // bits 10-1
                    ((imm & 0x100000) << 11);  // bit  20

    return instr | (imm20 & kImm20Mask);
  }

  static inline Instr SetJalrOffset(int32_t offset, Instr instr) {
    MOZ_ASSERT(IsJalr(instr));
    MOZ_ASSERT(is_int12(offset));
    instr &= ~kImm12Mask;
    int32_t imm12 = offset << kImm12Shift;
    MOZ_ASSERT(IsJalr(instr | (imm12 & kImm12Mask)));
    MOZ_ASSERT(JalrOffset(instr | (imm12 & kImm12Mask)) == offset);
    return instr | (imm12 & kImm12Mask);
  }

  static inline Instr SetLoadOffset(int32_t offset, Instr instr) {
#if JS_CODEGEN_RISCV64
    MOZ_ASSERT(IsLd(instr));
#elif JS_CODEGEN_RISCV32
    MOZ_ASSERT(IsLw(instr));
#endif
    MOZ_ASSERT(is_int12(offset));
    instr &= ~kImm12Mask;
    int32_t imm12 = offset << kImm12Shift;
    return instr | (imm12 & kImm12Mask);
  }

  static inline Instr SetAuipcOffset(int32_t offset, Instr instr) {
    MOZ_ASSERT(IsAuipc(instr));
    MOZ_ASSERT(is_int20(offset));
    instr = (instr & ~kImm31_12Mask) | ((offset & kImm19_0Mask) << 12);
    return instr;
  }

  // Check if an instruction is a branch of some kind.
  static bool IsBranch(Instr instr);
  static bool IsNop(Instr instr);
  static bool IsJump(Instr instr);
  static bool IsJal(Instr instr);
  static bool IsJalr(Instr instr);
  static bool IsLui(Instr instr);
  static bool IsAuipc(Instr instr);
  static bool IsAddi(Instr instr);
  static bool IsOri(Instr instr);
  static bool IsSlli(Instr instr);
  static bool IsLw(Instr instr);

  inline int32_t branch_offset(Label* L) {
    return branch_offset_helper(L, OffsetSize::kOffset13);
  }
  inline int32_t jump_offset(Label* L) {
    return branch_offset_helper(L, OffsetSize::kOffset21);
  }

  // Branches
  void beq(Register rs1, Register rs2, Label* L) {
    beq(rs1, rs2, branch_offset(L));
  }
  void bne(Register rs1, Register rs2, Label* L) {
    bne(rs1, rs2, branch_offset(L));
  }
  void blt(Register rs1, Register rs2, Label* L) {
    blt(rs1, rs2, branch_offset(L));
  }
  void bge(Register rs1, Register rs2, Label* L) {
    bge(rs1, rs2, branch_offset(L));
  }
  void bltu(Register rs1, Register rs2, Label* L) {
    bltu(rs1, rs2, branch_offset(L));
  }
  void bgeu(Register rs1, Register rs2, Label* L) {
    bgeu(rs1, rs2, branch_offset(L));
  }

  void beqz(Register rs, int16_t imm13) { beq(rs, zero_reg, imm13); }
  void beqz(Register rs1, Label* L) { beqz(rs1, branch_offset(L)); }
  void bnez(Register rs, int16_t imm13) { bne(rs, zero_reg, imm13); }
  void bnez(Register rs1, Label* L) { bnez(rs1, branch_offset(L)); }
  void blez(Register rs, int16_t imm13) { bge(zero_reg, rs, imm13); }
  void blez(Register rs1, Label* L) { blez(rs1, branch_offset(L)); }
  void bgez(Register rs, int16_t imm13) { bge(rs, zero_reg, imm13); }
  void bgez(Register rs1, Label* L) { bgez(rs1, branch_offset(L)); }
  void bltz(Register rs, int16_t imm13) { blt(rs, zero_reg, imm13); }
  void bltz(Register rs1, Label* L) { bltz(rs1, branch_offset(L)); }
  void bgtz(Register rs, int16_t imm13) { blt(zero_reg, rs, imm13); }

  void bgtz(Register rs1, Label* L) { bgtz(rs1, branch_offset(L)); }
  void bgt(Register rs1, Register rs2, int16_t imm13) { blt(rs2, rs1, imm13); }
  void bgt(Register rs1, Register rs2, Label* L) {
    bgt(rs1, rs2, branch_offset(L));
  }
  void ble(Register rs1, Register rs2, int16_t imm13) { bge(rs2, rs1, imm13); }
  void ble(Register rs1, Register rs2, Label* L) {
    ble(rs1, rs2, branch_offset(L));
  }
  void bgtu(Register rs1, Register rs2, int16_t imm13) {
    bltu(rs2, rs1, imm13);
  }
  void bgtu(Register rs1, Register rs2, Label* L) {
    bgtu(rs1, rs2, branch_offset(L));
  }
  void bleu(Register rs1, Register rs2, int16_t imm13) {
    bgeu(rs2, rs1, imm13);
  }
  void bleu(Register rs1, Register rs2, Label* L) {
    bleu(rs1, rs2, branch_offset(L));
  }

  void j(int32_t imm21) { jal(zero_reg, imm21); }
  void j(Label* L) { j(jump_offset(L)); }
  void b(Label* L) { j(L); }
  void jal(int32_t imm21) { jal(ra, imm21); }
  void jal(Label* L) { jal(jump_offset(L)); }
  void jr(Register rs) { jalr(zero_reg, rs, 0); }
  void jr(Register rs, int32_t imm12) { jalr(zero_reg, rs, imm12); }
  void jalr(Register rs, int32_t imm12) { jalr(ra, rs, imm12); }
  void jalr(Register rs) { jalr(ra, rs, 0); }
  void call(int32_t offset) {
    auipc(ra, (offset >> 12) + ((offset & 0x800) >> 11));
    jalr(ra, ra, offset << 20 >> 20);
  }

  void mv(Register rd, Register rs) { addi(rd, rs, 0); }
  void not_(Register rd, Register rs) { xori(rd, rs, -1); }
  void neg(Register rd, Register rs) { sub(rd, zero_reg, rs); }
  void seqz(Register rd, Register rs) { sltiu(rd, rs, 1); }
  void snez(Register rd, Register rs) { sltu(rd, zero_reg, rs); }
  void sltz(Register rd, Register rs) { slt(rd, rs, zero_reg); }
  void sgtz(Register rd, Register rs) { slt(rd, zero_reg, rs); }

#if JS_CODEGEN_RISCV64
  void lwu(Register rd, Register rs1, int16_t imm12);
  void ld(Register rd, Register rs1, int16_t imm12);
  void sd(Register source, Register base, int16_t imm12);
  void addiw(Register rd, Register rs1, int16_t imm12);
  void slliw(Register rd, Register rs1, uint8_t shamt);
  void srliw(Register rd, Register rs1, uint8_t shamt);
  void sraiw(Register rd, Register rs1, uint8_t shamt);
  void addw(Register rd, Register rs1, Register rs2);
  void subw(Register rd, Register rs1, Register rs2);
  void sllw(Register rd, Register rs1, Register rs2);
  void srlw(Register rd, Register rs1, Register rs2);
  void sraw(Register rd, Register rs1, Register rs2);
  void negw(Register rd, Register rs) { subw(rd, zero_reg, rs); }
  void sext_w(Register rd, Register rs) { addiw(rd, rs, 0); }

  static bool IsAddiw(Instr instr);
  static bool IsLd(Instr instr);
#endif
};

}  // namespace jit
}  // namespace js

#endif  // jit_riscv64_extension_Base_riscv_I_h_