Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
bytecodealliance
GitHub Repository: bytecodealliance/wasmtime
Path: blob/main/cranelift/codegen/src/isa/riscv64/inst/args.rs
1693 views
1
//! Riscv64 ISA definitions: instruction arguments.
2
3
use super::*;
4
use crate::ir::condcodes::CondCode;
5
6
use crate::isa::riscv64::lower::isle::generated_code::{
7
COpcodeSpace, CaOp, CbOp, CiOp, CiwOp, ClOp, CrOp, CsOp, CssOp, CsznOp, FpuOPWidth, ZcbMemOp,
8
};
9
use crate::machinst::isle::WritableReg;
10
11
use std::fmt::Result;
12
13
/// A macro for defining a newtype of `Reg` that enforces some invariant about
14
/// the wrapped `Reg` (such as that it is of a particular register class).
15
macro_rules! newtype_of_reg {
16
(
17
$newtype_reg:ident,
18
$newtype_writable_reg:ident,
19
|$check_reg:ident| $check:expr
20
) => {
21
/// A newtype wrapper around `Reg`.
22
#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
23
pub struct $newtype_reg(Reg);
24
25
impl PartialEq<Reg> for $newtype_reg {
26
fn eq(&self, other: &Reg) -> bool {
27
self.0 == *other
28
}
29
}
30
31
impl From<$newtype_reg> for Reg {
32
fn from(r: $newtype_reg) -> Self {
33
r.0
34
}
35
}
36
37
impl $newtype_reg {
38
/// Create this newtype from the given register, or return `None` if the register
39
/// is not a valid instance of this newtype.
40
pub fn new($check_reg: Reg) -> Option<Self> {
41
if $check { Some(Self($check_reg)) } else { None }
42
}
43
44
/// Get this newtype's underlying `Reg`.
45
pub fn to_reg(self) -> Reg {
46
self.0
47
}
48
}
49
50
// Convenience impl so that people working with this newtype can use it
51
// "just like" a plain `Reg`.
52
//
53
// NB: We cannot implement `DerefMut` because that would let people do
54
// nasty stuff like `*my_xreg.deref_mut() = some_freg`, breaking the
55
// invariants that `XReg` provides.
56
impl std::ops::Deref for $newtype_reg {
57
type Target = Reg;
58
59
fn deref(&self) -> &Reg {
60
&self.0
61
}
62
}
63
64
/// Writable Reg.
65
pub type $newtype_writable_reg = Writable<$newtype_reg>;
66
};
67
}
68
69
// Newtypes for registers classes.
70
newtype_of_reg!(XReg, WritableXReg, |reg| reg.class() == RegClass::Int);
71
newtype_of_reg!(FReg, WritableFReg, |reg| reg.class() == RegClass::Float);
72
newtype_of_reg!(VReg, WritableVReg, |reg| reg.class() == RegClass::Vector);
73
74
/// An addressing mode specified for a load/store operation.
75
#[derive(Clone, Debug, Copy)]
76
pub enum AMode {
77
/// Arbitrary offset from a register. Converted to generation of large
78
/// offsets with multiple instructions as necessary during code emission.
79
RegOffset(Reg, i64),
80
/// Offset from the stack pointer.
81
SPOffset(i64),
82
83
/// Offset from the frame pointer.
84
FPOffset(i64),
85
86
/// Offset into the slot area of the stack, which lies just above the
87
/// outgoing argument area that's setup by the function prologue.
88
/// At emission time, this is converted to `SPOffset` with a fixup added to
89
/// the offset constant. The fixup is a running value that is tracked as
90
/// emission iterates through instructions in linear order, and can be
91
/// adjusted up and down with [Inst::VirtualSPOffsetAdj].
92
///
93
/// The standard ABI is in charge of handling this (by emitting the
94
/// adjustment meta-instructions). See the diagram in the documentation
95
/// for [crate::isa::aarch64::abi](the ABI module) for more details.
96
SlotOffset(i64),
97
98
/// Offset into the argument area.
99
IncomingArg(i64),
100
101
/// A reference to a constant which is placed outside of the function's
102
/// body, typically at the end.
103
Const(VCodeConstant),
104
105
/// A reference to a label.
106
Label(MachLabel),
107
}
108
109
impl AMode {
110
/// Add the registers referenced by this AMode to `collector`.
111
pub(crate) fn get_operands(&mut self, collector: &mut impl OperandVisitor) {
112
match self {
113
AMode::RegOffset(reg, ..) => collector.reg_use(reg),
114
// Registers used in these modes aren't allocatable.
115
AMode::SPOffset(..)
116
| AMode::FPOffset(..)
117
| AMode::SlotOffset(..)
118
| AMode::IncomingArg(..)
119
| AMode::Const(..)
120
| AMode::Label(..) => {}
121
}
122
}
123
124
pub(crate) fn get_base_register(&self) -> Option<Reg> {
125
match self {
126
&AMode::RegOffset(reg, ..) => Some(reg),
127
&AMode::SPOffset(..) => Some(stack_reg()),
128
&AMode::FPOffset(..) => Some(fp_reg()),
129
&AMode::SlotOffset(..) => Some(stack_reg()),
130
&AMode::IncomingArg(..) => Some(stack_reg()),
131
&AMode::Const(..) | AMode::Label(..) => None,
132
}
133
}
134
135
pub(crate) fn get_offset_with_state(&self, state: &EmitState) -> i64 {
136
match self {
137
&AMode::SlotOffset(offset) => {
138
offset + i64::from(state.frame_layout().outgoing_args_size)
139
}
140
141
// Compute the offset into the incoming argument area relative to SP
142
&AMode::IncomingArg(offset) => {
143
let frame_layout = state.frame_layout();
144
let sp_offset = frame_layout.tail_args_size
145
+ frame_layout.setup_area_size
146
+ frame_layout.clobber_size
147
+ frame_layout.fixed_frame_storage_size
148
+ frame_layout.outgoing_args_size;
149
i64::from(sp_offset) - offset
150
}
151
152
&AMode::RegOffset(_, offset) => offset,
153
&AMode::SPOffset(offset) => offset,
154
&AMode::FPOffset(offset) => offset,
155
&AMode::Const(_) | &AMode::Label(_) => 0,
156
}
157
}
158
159
/// Retrieve a MachLabel that corresponds to this addressing mode, if it exists.
160
pub(crate) fn get_label_with_sink(&self, sink: &mut MachBuffer<Inst>) -> Option<MachLabel> {
161
match self {
162
&AMode::Const(addr) => Some(sink.get_label_for_constant(addr)),
163
&AMode::Label(label) => Some(label),
164
&AMode::RegOffset(..)
165
| &AMode::SPOffset(..)
166
| &AMode::FPOffset(..)
167
| &AMode::IncomingArg(..)
168
| &AMode::SlotOffset(..) => None,
169
}
170
}
171
}
172
173
impl Display for AMode {
174
fn fmt(&self, f: &mut Formatter<'_>) -> Result {
175
match self {
176
&AMode::RegOffset(r, offset, ..) => {
177
write!(f, "{}({})", offset, reg_name(r))
178
}
179
&AMode::SPOffset(offset, ..) => {
180
write!(f, "{offset}(sp)")
181
}
182
&AMode::SlotOffset(offset, ..) => {
183
write!(f, "{offset}(slot)")
184
}
185
&AMode::IncomingArg(offset) => {
186
write!(f, "-{offset}(incoming_arg)")
187
}
188
&AMode::FPOffset(offset, ..) => {
189
write!(f, "{offset}(fp)")
190
}
191
&AMode::Const(addr, ..) => {
192
write!(f, "[const({})]", addr.as_u32())
193
}
194
&AMode::Label(label) => {
195
write!(f, "[label{}]", label.as_u32())
196
}
197
}
198
}
199
}
200
201
impl From<StackAMode> for AMode {
202
fn from(stack: StackAMode) -> AMode {
203
match stack {
204
StackAMode::IncomingArg(offset, stack_args_size) => {
205
AMode::IncomingArg(i64::from(stack_args_size) - offset)
206
}
207
StackAMode::OutgoingArg(offset) => AMode::SPOffset(offset),
208
StackAMode::Slot(offset) => AMode::SlotOffset(offset),
209
}
210
}
211
}
212
213
/// risc-v always take two register to compare
214
#[derive(Clone, Copy, Debug)]
215
pub struct IntegerCompare {
216
pub(crate) kind: IntCC,
217
pub(crate) rs1: Reg,
218
pub(crate) rs2: Reg,
219
}
220
221
pub(crate) enum BranchFunct3 {
222
// ==
223
Eq,
224
// !=
225
Ne,
226
// signed <
227
Lt,
228
// signed >=
229
Ge,
230
// unsigned <
231
Ltu,
232
// unsigned >=
233
Geu,
234
}
235
236
impl BranchFunct3 {
237
pub(crate) fn funct3(self) -> u32 {
238
match self {
239
BranchFunct3::Eq => 0b000,
240
BranchFunct3::Ne => 0b001,
241
BranchFunct3::Lt => 0b100,
242
BranchFunct3::Ge => 0b101,
243
BranchFunct3::Ltu => 0b110,
244
BranchFunct3::Geu => 0b111,
245
}
246
}
247
}
248
249
impl IntegerCompare {
250
pub(crate) fn op_code(self) -> u32 {
251
0b1100011
252
}
253
254
// funct3 and if need inverse the register
255
pub(crate) fn funct3(&self) -> (BranchFunct3, bool) {
256
match self.kind {
257
IntCC::Equal => (BranchFunct3::Eq, false),
258
IntCC::NotEqual => (BranchFunct3::Ne, false),
259
IntCC::SignedLessThan => (BranchFunct3::Lt, false),
260
IntCC::SignedGreaterThanOrEqual => (BranchFunct3::Ge, false),
261
262
IntCC::SignedGreaterThan => (BranchFunct3::Lt, true),
263
IntCC::SignedLessThanOrEqual => (BranchFunct3::Ge, true),
264
265
IntCC::UnsignedLessThan => (BranchFunct3::Ltu, false),
266
IntCC::UnsignedGreaterThanOrEqual => (BranchFunct3::Geu, false),
267
268
IntCC::UnsignedGreaterThan => (BranchFunct3::Ltu, true),
269
IntCC::UnsignedLessThanOrEqual => (BranchFunct3::Geu, true),
270
}
271
}
272
273
#[inline]
274
pub(crate) fn op_name(&self) -> &'static str {
275
match self.kind {
276
IntCC::Equal => "beq",
277
IntCC::NotEqual => "bne",
278
IntCC::SignedLessThan => "blt",
279
IntCC::SignedGreaterThanOrEqual => "bge",
280
IntCC::SignedGreaterThan => "bgt",
281
IntCC::SignedLessThanOrEqual => "ble",
282
IntCC::UnsignedLessThan => "bltu",
283
IntCC::UnsignedGreaterThanOrEqual => "bgeu",
284
IntCC::UnsignedGreaterThan => "bgtu",
285
IntCC::UnsignedLessThanOrEqual => "bleu",
286
}
287
}
288
289
pub(crate) fn emit(self) -> u32 {
290
let (funct3, reverse) = self.funct3();
291
let (rs1, rs2) = if reverse {
292
(self.rs2, self.rs1)
293
} else {
294
(self.rs1, self.rs2)
295
};
296
297
self.op_code()
298
| funct3.funct3() << 12
299
| reg_to_gpr_num(rs1) << 15
300
| reg_to_gpr_num(rs2) << 20
301
}
302
303
pub(crate) fn inverse(self) -> Self {
304
Self {
305
kind: self.kind.complement(),
306
..self
307
}
308
}
309
310
pub(crate) fn regs(&self) -> [Reg; 2] {
311
[self.rs1, self.rs2]
312
}
313
}
314
315
#[derive(Debug, Clone, Copy, PartialEq)]
316
pub struct FliConstant(u8);
317
318
impl FliConstant {
319
pub(crate) fn new(value: u8) -> Self {
320
debug_assert!(value <= 31, "Invalid FliConstant: {value}");
321
Self(value)
322
}
323
324
pub(crate) fn maybe_from_u64(ty: Type, imm: u64) -> Option<Self> {
325
// Convert the value into an F64, this allows us to represent
326
// values from both f32 and f64 in the same value.
327
let value = match ty {
328
F16 => {
329
// FIXME(#8312): Use `f16` once it has been stabilised.
330
// Handle special/non-normal values first.
331
match imm {
332
// `f16::MIN_POSITIVE`
333
0x0400 => return Some(Self::new(1)),
334
// 2 pow -16
335
0x0100 => return Some(Self::new(2)),
336
// 2 pow -15
337
0x0200 => return Some(Self::new(3)),
338
// `f16::INFINITY`
339
0x7c00 => return Some(Self::new(30)),
340
// Canonical NaN
341
0x7e00 => return Some(Self::new(31)),
342
_ => {
343
let exponent_bits = imm & 0x7c00;
344
if exponent_bits == 0 || exponent_bits == 0x7c00 {
345
// All non-normal values are handled above.
346
return None;
347
}
348
let sign = (imm & 0x8000) << 48;
349
// Adjust the exponent for the difference between the `f16` exponent bias
350
// and the `f64` exponent bias.
351
let exponent = (exponent_bits + ((1023 - 15) << 10)) << 42;
352
let significand = (imm & 0x3ff) << 42;
353
f64::from_bits(sign | exponent | significand)
354
}
355
}
356
}
357
F32 => f32::from_bits(imm as u32) as f64,
358
F64 => f64::from_bits(imm),
359
_ => unimplemented!(),
360
};
361
362
Some(match (ty, value) {
363
(_, f) if f == -1.0 => Self::new(0),
364
365
// Since f64 can represent all f32 values, f32::min_positive won't be
366
// the same as f64::min_positive, so we need to check for both indepenendtly
367
(F32, f) if f == (f32::MIN_POSITIVE as f64) => Self::new(1),
368
(F64, f) if f == f64::MIN_POSITIVE => Self::new(1),
369
370
(_, f) if f == 2.0f64.powi(-16) => Self::new(2),
371
(_, f) if f == 2.0f64.powi(-15) => Self::new(3),
372
(_, f) if f == 2.0f64.powi(-8) => Self::new(4),
373
(_, f) if f == 2.0f64.powi(-7) => Self::new(5),
374
(_, f) if f == 0.0625 => Self::new(6),
375
(_, f) if f == 0.125 => Self::new(7),
376
(_, f) if f == 0.25 => Self::new(8),
377
(_, f) if f == 0.3125 => Self::new(9),
378
(_, f) if f == 0.375 => Self::new(10),
379
(_, f) if f == 0.4375 => Self::new(11),
380
(_, f) if f == 0.5 => Self::new(12),
381
(_, f) if f == 0.625 => Self::new(13),
382
(_, f) if f == 0.75 => Self::new(14),
383
(_, f) if f == 0.875 => Self::new(15),
384
(_, f) if f == 1.0 => Self::new(16),
385
(_, f) if f == 1.25 => Self::new(17),
386
(_, f) if f == 1.5 => Self::new(18),
387
(_, f) if f == 1.75 => Self::new(19),
388
(_, f) if f == 2.0 => Self::new(20),
389
(_, f) if f == 2.5 => Self::new(21),
390
(_, f) if f == 3.0 => Self::new(22),
391
(_, f) if f == 4.0 => Self::new(23),
392
(_, f) if f == 8.0 => Self::new(24),
393
(_, f) if f == 16.0 => Self::new(25),
394
(_, f) if f == 128.0 => Self::new(26),
395
(_, f) if f == 256.0 => Self::new(27),
396
(_, f) if f == 32768.0 => Self::new(28),
397
(_, f) if f == 65536.0 => Self::new(29),
398
(_, f) if f == f64::INFINITY => Self::new(30),
399
400
// NaN's are not guaranteed to preserve the sign / payload bits, so we need to check
401
// the original bits directly.
402
(F32, f) if f.is_nan() && imm == 0x7fc0_0000 => Self::new(31), // Canonical NaN
403
(F64, f) if f.is_nan() && imm == 0x7ff8_0000_0000_0000 => Self::new(31), // Canonical NaN
404
_ => return None,
405
})
406
}
407
408
pub(crate) fn format(self) -> &'static str {
409
// The preferred assembly syntax for entries 1, 30, and 31 is min, inf, and nan, respectively.
410
// For entries 0 through 29 (including entry 1), the assembler will accept decimal constants
411
// in C-like syntax.
412
match self.0 {
413
0 => "-1.0",
414
1 => "min",
415
2 => "2^-16",
416
3 => "2^-15",
417
4 => "2^-8",
418
5 => "2^-7",
419
6 => "0.0625",
420
7 => "0.125",
421
8 => "0.25",
422
9 => "0.3125",
423
10 => "0.375",
424
11 => "0.4375",
425
12 => "0.5",
426
13 => "0.625",
427
14 => "0.75",
428
15 => "0.875",
429
16 => "1.0",
430
17 => "1.25",
431
18 => "1.5",
432
19 => "1.75",
433
20 => "2.0",
434
21 => "2.5",
435
22 => "3.0",
436
23 => "4.0",
437
24 => "8.0",
438
25 => "16.0",
439
26 => "128.0",
440
27 => "256.0",
441
28 => "32768.0",
442
29 => "65536.0",
443
30 => "inf",
444
31 => "nan",
445
_ => panic!("Invalid FliConstant"),
446
}
447
}
448
449
pub(crate) fn bits(self) -> u8 {
450
self.0
451
}
452
}
453
454
impl FpuOPRRRR {
455
pub(crate) fn op_name(self, width: FpuOPWidth) -> String {
456
match self {
457
Self::Fmadd => format!("fmadd.{width}"),
458
Self::Fmsub => format!("fmsub.{width}"),
459
Self::Fnmsub => format!("fnmsub.{width}"),
460
Self::Fnmadd => format!("fnmadd.{width}"),
461
}
462
}
463
464
pub(crate) fn opcode(self) -> u32 {
465
match self {
466
Self::Fmadd => 0b1000011,
467
Self::Fmsub => 0b1000111,
468
Self::Fnmsub => 0b1001011,
469
Self::Fnmadd => 0b1001111,
470
}
471
}
472
}
473
474
impl FpuOPRR {
475
pub(crate) fn op_name(self, width: FpuOPWidth) -> String {
476
let fmv_width = match width {
477
FpuOPWidth::H => "h",
478
FpuOPWidth::S => "w",
479
FpuOPWidth::D => "d",
480
FpuOPWidth::Q => "q",
481
};
482
match self {
483
Self::Fsqrt => format!("fsqrt.{width}"),
484
Self::Fround => format!("fround.{width}"),
485
Self::Fclass => format!("fclass.{width}"),
486
Self::FcvtWFmt => format!("fcvt.w.{width}"),
487
Self::FcvtWuFmt => format!("fcvt.wu.{width}"),
488
Self::FcvtLFmt => format!("fcvt.l.{width}"),
489
Self::FcvtLuFmt => format!("fcvt.lu.{width}"),
490
Self::FcvtFmtW => format!("fcvt.{width}.w"),
491
Self::FcvtFmtWu => format!("fcvt.{width}.wu"),
492
Self::FcvtFmtL => format!("fcvt.{width}.l"),
493
Self::FcvtFmtLu => format!("fcvt.{width}.lu"),
494
495
// fmv instructions deviate from the normal encoding and instead
496
// encode the width as "w" instead of "s". The ISA manual gives this rationale:
497
//
498
// Instructions FMV.S.X and FMV.X.S were renamed to FMV.W.X and FMV.X.W respectively
499
// to be more consistent with their semantics, which did not change. The old names will continue
500
// to be supported in the tools.
501
Self::FmvXFmt => format!("fmv.x.{fmv_width}"),
502
Self::FmvFmtX => format!("fmv.{fmv_width}.x"),
503
504
Self::FcvtSD => "fcvt.s.d".to_string(),
505
Self::FcvtDS => "fcvt.d.s".to_string(),
506
}
507
}
508
509
pub(crate) fn is_convert_to_int(self) -> bool {
510
match self {
511
Self::FcvtWFmt | Self::FcvtWuFmt | Self::FcvtLFmt | Self::FcvtLuFmt => true,
512
_ => false,
513
}
514
}
515
516
pub(crate) fn has_frm(self) -> bool {
517
match self {
518
FpuOPRR::FmvXFmt | FpuOPRR::FmvFmtX | FpuOPRR::Fclass => false,
519
_ => true,
520
}
521
}
522
523
pub(crate) fn opcode(self) -> u32 {
524
// OP-FP Major opcode
525
0b1010011
526
}
527
528
pub(crate) fn rs2(self) -> u32 {
529
match self {
530
Self::Fsqrt => 0b00000,
531
Self::Fround => 0b00100,
532
Self::Fclass => 0b00000,
533
Self::FcvtWFmt => 0b00000,
534
Self::FcvtWuFmt => 0b00001,
535
Self::FcvtLFmt => 0b00010,
536
Self::FcvtLuFmt => 0b00011,
537
Self::FcvtFmtW => 0b00000,
538
Self::FcvtFmtWu => 0b00001,
539
Self::FcvtFmtL => 0b00010,
540
Self::FcvtFmtLu => 0b00011,
541
Self::FmvXFmt => 0b00000,
542
Self::FmvFmtX => 0b00000,
543
Self::FcvtSD => 0b00001,
544
Self::FcvtDS => 0b00000,
545
}
546
}
547
548
pub(crate) fn funct5(self) -> u32 {
549
match self {
550
Self::Fsqrt => 0b01011,
551
Self::Fround => 0b01000,
552
Self::Fclass => 0b11100,
553
Self::FcvtWFmt => 0b11000,
554
Self::FcvtWuFmt => 0b11000,
555
Self::FcvtLFmt => 0b11000,
556
Self::FcvtLuFmt => 0b11000,
557
Self::FcvtFmtW => 0b11010,
558
Self::FcvtFmtWu => 0b11010,
559
Self::FcvtFmtL => 0b11010,
560
Self::FcvtFmtLu => 0b11010,
561
Self::FmvXFmt => 0b11100,
562
Self::FmvFmtX => 0b11110,
563
Self::FcvtSD => 0b01000,
564
Self::FcvtDS => 0b01000,
565
}
566
}
567
568
pub(crate) fn funct7(self, width: FpuOPWidth) -> u32 {
569
(self.funct5() << 2) | width.as_u32()
570
}
571
}
572
573
impl FpuOPRRR {
574
pub(crate) fn op_name(self, width: FpuOPWidth) -> String {
575
match self {
576
Self::Fadd => format!("fadd.{width}"),
577
Self::Fsub => format!("fsub.{width}"),
578
Self::Fmul => format!("fmul.{width}"),
579
Self::Fdiv => format!("fdiv.{width}"),
580
Self::Fsgnj => format!("fsgnj.{width}"),
581
Self::Fsgnjn => format!("fsgnjn.{width}"),
582
Self::Fsgnjx => format!("fsgnjx.{width}"),
583
Self::Fmin => format!("fmin.{width}"),
584
Self::Fmax => format!("fmax.{width}"),
585
Self::Feq => format!("feq.{width}"),
586
Self::Flt => format!("flt.{width}"),
587
Self::Fle => format!("fle.{width}"),
588
Self::Fminm => format!("fminm.{width}"),
589
Self::Fmaxm => format!("fmaxm.{width}"),
590
}
591
}
592
593
pub(crate) fn opcode(self) -> u32 {
594
// OP-FP Major opcode
595
0b1010011
596
}
597
598
pub(crate) const fn funct5(self) -> u32 {
599
match self {
600
Self::Fadd => 0b00000,
601
Self::Fsub => 0b00001,
602
Self::Fmul => 0b00010,
603
Self::Fdiv => 0b00011,
604
Self::Fsgnj => 0b00100,
605
Self::Fsgnjn => 0b00100,
606
Self::Fsgnjx => 0b00100,
607
Self::Fmin => 0b00101,
608
Self::Fmax => 0b00101,
609
Self::Feq => 0b10100,
610
Self::Flt => 0b10100,
611
Self::Fle => 0b10100,
612
Self::Fminm => 0b00101,
613
Self::Fmaxm => 0b00101,
614
}
615
}
616
617
pub(crate) fn funct7(self, width: FpuOPWidth) -> u32 {
618
(self.funct5() << 2) | width.as_u32()
619
}
620
621
pub(crate) fn has_frm(self) -> bool {
622
match self {
623
FpuOPRRR::Fsgnj
624
| FpuOPRRR::Fsgnjn
625
| FpuOPRRR::Fsgnjx
626
| FpuOPRRR::Fmin
627
| FpuOPRRR::Fmax
628
| FpuOPRRR::Feq
629
| FpuOPRRR::Flt
630
| FpuOPRRR::Fle => false,
631
_ => true,
632
}
633
}
634
}
635
636
impl Display for FpuOPWidth {
637
fn fmt(&self, f: &mut Formatter<'_>) -> Result {
638
write!(
639
f,
640
"{}",
641
match self {
642
FpuOPWidth::H => "h",
643
FpuOPWidth::S => "s",
644
FpuOPWidth::D => "d",
645
FpuOPWidth::Q => "q",
646
}
647
)
648
}
649
}
650
651
impl TryFrom<Type> for FpuOPWidth {
652
type Error = &'static str;
653
654
fn try_from(value: Type) -> std::result::Result<Self, Self::Error> {
655
match value {
656
F16 => Ok(FpuOPWidth::H),
657
F32 => Ok(FpuOPWidth::S),
658
F64 => Ok(FpuOPWidth::D),
659
F128 => Ok(FpuOPWidth::Q),
660
_ => Err("Invalid type for FpuOPWidth"),
661
}
662
}
663
}
664
665
impl FpuOPWidth {
666
pub(crate) fn as_u32(&self) -> u32 {
667
match self {
668
FpuOPWidth::S => 0b00,
669
FpuOPWidth::D => 0b01,
670
FpuOPWidth::H => 0b10,
671
FpuOPWidth::Q => 0b11,
672
}
673
}
674
}
675
676
impl AluOPRRR {
677
pub(crate) const fn op_name(self) -> &'static str {
678
match self {
679
Self::Add => "add",
680
Self::Sub => "sub",
681
Self::Sll => "sll",
682
Self::Slt => "slt",
683
Self::Sgt => "sgt",
684
Self::SltU => "sltu",
685
Self::Sgtu => "sgtu",
686
Self::Xor => "xor",
687
Self::Srl => "srl",
688
Self::Sra => "sra",
689
Self::Or => "or",
690
Self::And => "and",
691
Self::Addw => "addw",
692
Self::Subw => "subw",
693
Self::Sllw => "sllw",
694
Self::Srlw => "srlw",
695
Self::Sraw => "sraw",
696
Self::Mul => "mul",
697
Self::Mulh => "mulh",
698
Self::Mulhsu => "mulhsu",
699
Self::Mulhu => "mulhu",
700
Self::Div => "div",
701
Self::DivU => "divu",
702
Self::Rem => "rem",
703
Self::RemU => "remu",
704
Self::Mulw => "mulw",
705
Self::Divw => "divw",
706
Self::Divuw => "divuw",
707
Self::Remw => "remw",
708
Self::Remuw => "remuw",
709
Self::Adduw => "add.uw",
710
Self::Andn => "andn",
711
Self::Bclr => "bclr",
712
Self::Bext => "bext",
713
Self::Binv => "binv",
714
Self::Bset => "bset",
715
Self::Clmul => "clmul",
716
Self::Clmulh => "clmulh",
717
Self::Clmulr => "clmulr",
718
Self::Max => "max",
719
Self::Maxu => "maxu",
720
Self::Min => "min",
721
Self::Minu => "minu",
722
Self::Orn => "orn",
723
Self::Rol => "rol",
724
Self::Rolw => "rolw",
725
Self::Ror => "ror",
726
Self::Rorw => "rorw",
727
Self::Sh1add => "sh1add",
728
Self::Sh1adduw => "sh1add.uw",
729
Self::Sh2add => "sh2add",
730
Self::Sh2adduw => "sh2add.uw",
731
Self::Sh3add => "sh3add",
732
Self::Sh3adduw => "sh3add.uw",
733
Self::Xnor => "xnor",
734
Self::Pack => "pack",
735
Self::Packw => "packw",
736
Self::Packh => "packh",
737
Self::CzeroEqz => "czero.eqz",
738
Self::CzeroNez => "czero.nez",
739
}
740
}
741
742
pub fn funct3(self) -> u32 {
743
match self {
744
AluOPRRR::Add => 0b000,
745
AluOPRRR::Sll => 0b001,
746
AluOPRRR::Slt => 0b010,
747
AluOPRRR::Sgt => 0b010,
748
AluOPRRR::SltU => 0b011,
749
AluOPRRR::Sgtu => 0b011,
750
AluOPRRR::Xor => 0b100,
751
AluOPRRR::Srl => 0b101,
752
AluOPRRR::Sra => 0b101,
753
AluOPRRR::Or => 0b110,
754
AluOPRRR::And => 0b111,
755
AluOPRRR::Sub => 0b000,
756
757
AluOPRRR::Addw => 0b000,
758
AluOPRRR::Subw => 0b000,
759
AluOPRRR::Sllw => 0b001,
760
AluOPRRR::Srlw => 0b101,
761
AluOPRRR::Sraw => 0b101,
762
763
AluOPRRR::Mul => 0b000,
764
AluOPRRR::Mulh => 0b001,
765
AluOPRRR::Mulhsu => 0b010,
766
AluOPRRR::Mulhu => 0b011,
767
AluOPRRR::Div => 0b100,
768
AluOPRRR::DivU => 0b101,
769
AluOPRRR::Rem => 0b110,
770
AluOPRRR::RemU => 0b111,
771
772
AluOPRRR::Mulw => 0b000,
773
AluOPRRR::Divw => 0b100,
774
AluOPRRR::Divuw => 0b101,
775
AluOPRRR::Remw => 0b110,
776
AluOPRRR::Remuw => 0b111,
777
778
// Zbb
779
AluOPRRR::Adduw => 0b000,
780
AluOPRRR::Andn => 0b111,
781
AluOPRRR::Bclr => 0b001,
782
AluOPRRR::Bext => 0b101,
783
AluOPRRR::Binv => 0b001,
784
AluOPRRR::Bset => 0b001,
785
AluOPRRR::Clmul => 0b001,
786
AluOPRRR::Clmulh => 0b011,
787
AluOPRRR::Clmulr => 0b010,
788
AluOPRRR::Max => 0b110,
789
AluOPRRR::Maxu => 0b111,
790
AluOPRRR::Min => 0b100,
791
AluOPRRR::Minu => 0b101,
792
AluOPRRR::Orn => 0b110,
793
AluOPRRR::Rol => 0b001,
794
AluOPRRR::Rolw => 0b001,
795
AluOPRRR::Ror => 0b101,
796
AluOPRRR::Rorw => 0b101,
797
AluOPRRR::Sh1add => 0b010,
798
AluOPRRR::Sh1adduw => 0b010,
799
AluOPRRR::Sh2add => 0b100,
800
AluOPRRR::Sh2adduw => 0b100,
801
AluOPRRR::Sh3add => 0b110,
802
AluOPRRR::Sh3adduw => 0b110,
803
AluOPRRR::Xnor => 0b100,
804
805
// Zbkb
806
AluOPRRR::Pack => 0b100,
807
AluOPRRR::Packw => 0b100,
808
AluOPRRR::Packh => 0b111,
809
810
// ZiCond
811
AluOPRRR::CzeroEqz => 0b101,
812
AluOPRRR::CzeroNez => 0b111,
813
}
814
}
815
816
pub fn op_code(self) -> u32 {
817
match self {
818
AluOPRRR::Add
819
| AluOPRRR::Sub
820
| AluOPRRR::Sll
821
| AluOPRRR::Slt
822
| AluOPRRR::Sgt
823
| AluOPRRR::SltU
824
| AluOPRRR::Sgtu
825
| AluOPRRR::Xor
826
| AluOPRRR::Srl
827
| AluOPRRR::Sra
828
| AluOPRRR::Or
829
| AluOPRRR::And
830
| AluOPRRR::Pack
831
| AluOPRRR::Packh => 0b0110011,
832
833
AluOPRRR::Addw
834
| AluOPRRR::Subw
835
| AluOPRRR::Sllw
836
| AluOPRRR::Srlw
837
| AluOPRRR::Sraw
838
| AluOPRRR::Packw => 0b0111011,
839
840
AluOPRRR::Mul
841
| AluOPRRR::Mulh
842
| AluOPRRR::Mulhsu
843
| AluOPRRR::Mulhu
844
| AluOPRRR::Div
845
| AluOPRRR::DivU
846
| AluOPRRR::Rem
847
| AluOPRRR::RemU => 0b0110011,
848
849
AluOPRRR::Mulw
850
| AluOPRRR::Divw
851
| AluOPRRR::Divuw
852
| AluOPRRR::Remw
853
| AluOPRRR::Remuw => 0b0111011,
854
855
AluOPRRR::Adduw => 0b0111011,
856
AluOPRRR::Andn
857
| AluOPRRR::Bclr
858
| AluOPRRR::Bext
859
| AluOPRRR::Binv
860
| AluOPRRR::Bset
861
| AluOPRRR::Clmul
862
| AluOPRRR::Clmulh
863
| AluOPRRR::Clmulr
864
| AluOPRRR::Max
865
| AluOPRRR::Maxu
866
| AluOPRRR::Min
867
| AluOPRRR::Minu
868
| AluOPRRR::Orn
869
| AluOPRRR::Rol
870
| AluOPRRR::Ror
871
| AluOPRRR::Sh1add
872
| AluOPRRR::Sh2add
873
| AluOPRRR::Sh3add
874
| AluOPRRR::Xnor
875
| AluOPRRR::CzeroEqz
876
| AluOPRRR::CzeroNez => 0b0110011,
877
878
AluOPRRR::Rolw
879
| AluOPRRR::Rorw
880
| AluOPRRR::Sh2adduw
881
| AluOPRRR::Sh3adduw
882
| AluOPRRR::Sh1adduw => 0b0111011,
883
}
884
}
885
886
pub const fn funct7(self) -> u32 {
887
match self {
888
AluOPRRR::Add => 0b0000000,
889
AluOPRRR::Sub => 0b0100000,
890
AluOPRRR::Sll => 0b0000000,
891
AluOPRRR::Slt => 0b0000000,
892
AluOPRRR::Sgt => 0b0000000,
893
AluOPRRR::SltU => 0b0000000,
894
AluOPRRR::Sgtu => 0b0000000,
895
896
AluOPRRR::Xor => 0b0000000,
897
AluOPRRR::Srl => 0b0000000,
898
AluOPRRR::Sra => 0b0100000,
899
AluOPRRR::Or => 0b0000000,
900
AluOPRRR::And => 0b0000000,
901
902
AluOPRRR::Addw => 0b0000000,
903
AluOPRRR::Subw => 0b0100000,
904
AluOPRRR::Sllw => 0b0000000,
905
AluOPRRR::Srlw => 0b0000000,
906
AluOPRRR::Sraw => 0b0100000,
907
908
AluOPRRR::Mul => 0b0000001,
909
AluOPRRR::Mulh => 0b0000001,
910
AluOPRRR::Mulhsu => 0b0000001,
911
AluOPRRR::Mulhu => 0b0000001,
912
AluOPRRR::Div => 0b0000001,
913
AluOPRRR::DivU => 0b0000001,
914
AluOPRRR::Rem => 0b0000001,
915
AluOPRRR::RemU => 0b0000001,
916
917
AluOPRRR::Mulw => 0b0000001,
918
AluOPRRR::Divw => 0b0000001,
919
AluOPRRR::Divuw => 0b0000001,
920
AluOPRRR::Remw => 0b0000001,
921
AluOPRRR::Remuw => 0b0000001,
922
AluOPRRR::Adduw => 0b0000100,
923
AluOPRRR::Andn => 0b0100000,
924
AluOPRRR::Bclr => 0b0100100,
925
AluOPRRR::Bext => 0b0100100,
926
AluOPRRR::Binv => 0b0110100,
927
AluOPRRR::Bset => 0b0010100,
928
AluOPRRR::Clmul => 0b0000101,
929
AluOPRRR::Clmulh => 0b0000101,
930
AluOPRRR::Clmulr => 0b0000101,
931
AluOPRRR::Max => 0b0000101,
932
AluOPRRR::Maxu => 0b0000101,
933
AluOPRRR::Min => 0b0000101,
934
AluOPRRR::Minu => 0b0000101,
935
AluOPRRR::Orn => 0b0100000,
936
AluOPRRR::Rol => 0b0110000,
937
AluOPRRR::Rolw => 0b0110000,
938
AluOPRRR::Ror => 0b0110000,
939
AluOPRRR::Rorw => 0b0110000,
940
AluOPRRR::Sh1add => 0b0010000,
941
AluOPRRR::Sh1adduw => 0b0010000,
942
AluOPRRR::Sh2add => 0b0010000,
943
AluOPRRR::Sh2adduw => 0b0010000,
944
AluOPRRR::Sh3add => 0b0010000,
945
AluOPRRR::Sh3adduw => 0b0010000,
946
AluOPRRR::Xnor => 0b0100000,
947
948
// Zbkb
949
AluOPRRR::Pack => 0b0000100,
950
AluOPRRR::Packw => 0b0000100,
951
AluOPRRR::Packh => 0b0000100,
952
953
// ZiCond
954
AluOPRRR::CzeroEqz => 0b0000111,
955
AluOPRRR::CzeroNez => 0b0000111,
956
}
957
}
958
959
pub(crate) fn reverse_rs(self) -> bool {
960
// special case.
961
// sgt and sgtu is not defined in isa.
962
// emit should reverse rs1 and rs2.
963
self == AluOPRRR::Sgt || self == AluOPRRR::Sgtu
964
}
965
}
966
967
impl AluOPRRI {
968
pub(crate) fn option_funct6(self) -> Option<u32> {
969
let x: Option<u32> = match self {
970
Self::Slli => Some(0b00_0000),
971
Self::Srli => Some(0b00_0000),
972
Self::Srai => Some(0b01_0000),
973
Self::Bclri => Some(0b010010),
974
Self::Bexti => Some(0b010010),
975
Self::Binvi => Some(0b011010),
976
Self::Bseti => Some(0b001010),
977
Self::Rori => Some(0b011000),
978
Self::SlliUw => Some(0b000010),
979
_ => None,
980
};
981
x
982
}
983
984
pub(crate) fn option_funct7(self) -> Option<u32> {
985
let x = match self {
986
Self::Slliw => Some(0b000_0000),
987
Self::SrliW => Some(0b000_0000),
988
Self::Sraiw => Some(0b010_0000),
989
Self::Roriw => Some(0b0110000),
990
_ => None,
991
};
992
x
993
}
994
995
pub(crate) fn imm12(self, imm12: Imm12) -> u32 {
996
let x = imm12.bits();
997
if let Some(func) = self.option_funct6() {
998
func << 6 | (x & 0b11_1111)
999
} else if let Some(func) = self.option_funct7() {
1000
func << 5 | (x & 0b1_1111)
1001
} else if let Some(func) = self.option_funct12() {
1002
func
1003
} else {
1004
x
1005
}
1006
}
1007
1008
pub(crate) fn option_funct12(self) -> Option<u32> {
1009
match self {
1010
Self::Clz => Some(0b011000000000),
1011
Self::Clzw => Some(0b011000000000),
1012
Self::Cpop => Some(0b011000000010),
1013
Self::Cpopw => Some(0b011000000010),
1014
Self::Ctz => Some(0b011000000001),
1015
Self::Ctzw => Some(0b011000000001),
1016
Self::Rev8 => Some(0b011010111000),
1017
Self::Sextb => Some(0b011000000100),
1018
Self::Sexth => Some(0b011000000101),
1019
Self::Zexth => Some(0b000010000000),
1020
Self::Orcb => Some(0b001010000111),
1021
Self::Brev8 => Some(0b0110_1000_0111),
1022
_ => None,
1023
}
1024
}
1025
1026
pub(crate) fn op_name(self) -> &'static str {
1027
match self {
1028
Self::Addi => "addi",
1029
Self::Slti => "slti",
1030
Self::SltiU => "sltiu",
1031
Self::Xori => "xori",
1032
Self::Ori => "ori",
1033
Self::Andi => "andi",
1034
Self::Slli => "slli",
1035
Self::Srli => "srli",
1036
Self::Srai => "srai",
1037
Self::Addiw => "addiw",
1038
Self::Slliw => "slliw",
1039
Self::SrliW => "srliw",
1040
Self::Sraiw => "sraiw",
1041
Self::Bclri => "bclri",
1042
Self::Bexti => "bexti",
1043
Self::Binvi => "binvi",
1044
Self::Bseti => "bseti",
1045
Self::Rori => "rori",
1046
Self::Roriw => "roriw",
1047
Self::SlliUw => "slli.uw",
1048
Self::Clz => "clz",
1049
Self::Clzw => "clzw",
1050
Self::Cpop => "cpop",
1051
Self::Cpopw => "cpopw",
1052
Self::Ctz => "ctz",
1053
Self::Ctzw => "ctzw",
1054
Self::Rev8 => "rev8",
1055
Self::Sextb => "sext.b",
1056
Self::Sexth => "sext.h",
1057
Self::Zexth => "zext.h",
1058
Self::Orcb => "orc.b",
1059
Self::Brev8 => "brev8",
1060
}
1061
}
1062
1063
pub fn funct3(self) -> u32 {
1064
match self {
1065
AluOPRRI::Addi => 0b000,
1066
AluOPRRI::Slti => 0b010,
1067
AluOPRRI::SltiU => 0b011,
1068
AluOPRRI::Xori => 0b100,
1069
AluOPRRI::Ori => 0b110,
1070
AluOPRRI::Andi => 0b111,
1071
AluOPRRI::Slli => 0b001,
1072
AluOPRRI::Srli => 0b101,
1073
AluOPRRI::Srai => 0b101,
1074
AluOPRRI::Addiw => 0b000,
1075
AluOPRRI::Slliw => 0b001,
1076
AluOPRRI::SrliW => 0b101,
1077
AluOPRRI::Sraiw => 0b101,
1078
AluOPRRI::Bclri => 0b001,
1079
AluOPRRI::Bexti => 0b101,
1080
AluOPRRI::Binvi => 0b001,
1081
AluOPRRI::Bseti => 0b001,
1082
AluOPRRI::Rori => 0b101,
1083
AluOPRRI::Roriw => 0b101,
1084
AluOPRRI::SlliUw => 0b001,
1085
AluOPRRI::Clz => 0b001,
1086
AluOPRRI::Clzw => 0b001,
1087
AluOPRRI::Cpop => 0b001,
1088
AluOPRRI::Cpopw => 0b001,
1089
AluOPRRI::Ctz => 0b001,
1090
AluOPRRI::Ctzw => 0b001,
1091
AluOPRRI::Rev8 => 0b101,
1092
AluOPRRI::Sextb => 0b001,
1093
AluOPRRI::Sexth => 0b001,
1094
AluOPRRI::Zexth => 0b100,
1095
AluOPRRI::Orcb => 0b101,
1096
AluOPRRI::Brev8 => 0b101,
1097
}
1098
}
1099
1100
pub fn op_code(self) -> u32 {
1101
match self {
1102
AluOPRRI::Addi
1103
| AluOPRRI::Slti
1104
| AluOPRRI::SltiU
1105
| AluOPRRI::Xori
1106
| AluOPRRI::Ori
1107
| AluOPRRI::Andi
1108
| AluOPRRI::Slli
1109
| AluOPRRI::Srli
1110
| AluOPRRI::Srai
1111
| AluOPRRI::Bclri
1112
| AluOPRRI::Bexti
1113
| AluOPRRI::Binvi
1114
| AluOPRRI::Bseti
1115
| AluOPRRI::Rori
1116
| AluOPRRI::Clz
1117
| AluOPRRI::Cpop
1118
| AluOPRRI::Ctz
1119
| AluOPRRI::Rev8
1120
| AluOPRRI::Sextb
1121
| AluOPRRI::Sexth
1122
| AluOPRRI::Orcb
1123
| AluOPRRI::Brev8 => 0b0010011,
1124
1125
AluOPRRI::Addiw
1126
| AluOPRRI::Slliw
1127
| AluOPRRI::SrliW
1128
| AluOPRRI::Sraiw
1129
| AluOPRRI::Roriw
1130
| AluOPRRI::SlliUw
1131
| AluOPRRI::Clzw
1132
| AluOPRRI::Cpopw
1133
| AluOPRRI::Ctzw => 0b0011011,
1134
AluOPRRI::Zexth => 0b0111011,
1135
}
1136
}
1137
}
1138
1139
impl Default for FRM {
1140
fn default() -> Self {
1141
Self::Fcsr
1142
}
1143
}
1144
1145
/// float rounding mode.
1146
impl FRM {
1147
pub(crate) fn to_static_str(self) -> &'static str {
1148
match self {
1149
FRM::RNE => "rne",
1150
FRM::RTZ => "rtz",
1151
FRM::RDN => "rdn",
1152
FRM::RUP => "rup",
1153
FRM::RMM => "rmm",
1154
FRM::Fcsr => "fcsr",
1155
}
1156
}
1157
1158
#[inline]
1159
pub(crate) fn bits(self) -> u8 {
1160
match self {
1161
FRM::RNE => 0b000,
1162
FRM::RTZ => 0b001,
1163
FRM::RDN => 0b010,
1164
FRM::RUP => 0b011,
1165
FRM::RMM => 0b100,
1166
FRM::Fcsr => 0b111,
1167
}
1168
}
1169
pub(crate) fn as_u32(self) -> u32 {
1170
self.bits() as u32
1171
}
1172
}
1173
1174
impl FFlagsException {
1175
#[inline]
1176
#[expect(dead_code, reason = "here for future use")]
1177
pub(crate) fn mask(self) -> u32 {
1178
match self {
1179
FFlagsException::NV => 1 << 4,
1180
FFlagsException::DZ => 1 << 3,
1181
FFlagsException::OF => 1 << 2,
1182
FFlagsException::UF => 1 << 1,
1183
FFlagsException::NX => 1 << 0,
1184
}
1185
}
1186
}
1187
1188
impl LoadOP {
1189
pub(crate) fn op_name(self) -> &'static str {
1190
match self {
1191
Self::Lb => "lb",
1192
Self::Lh => "lh",
1193
Self::Lw => "lw",
1194
Self::Lbu => "lbu",
1195
Self::Lhu => "lhu",
1196
Self::Lwu => "lwu",
1197
Self::Ld => "ld",
1198
Self::Flh => "flh",
1199
Self::Flw => "flw",
1200
Self::Fld => "fld",
1201
}
1202
}
1203
1204
pub(crate) fn from_type(ty: Type) -> Self {
1205
match ty {
1206
F16 => Self::Flh,
1207
F32 => Self::Flw,
1208
F64 => Self::Fld,
1209
I8 => Self::Lb,
1210
I16 => Self::Lh,
1211
I32 => Self::Lw,
1212
I64 => Self::Ld,
1213
_ => unreachable!(),
1214
}
1215
}
1216
1217
pub(crate) fn size(&self) -> i64 {
1218
match self {
1219
Self::Lb | Self::Lbu => 1,
1220
Self::Lh | Self::Lhu | Self::Flh => 2,
1221
Self::Lw | Self::Lwu | Self::Flw => 4,
1222
Self::Ld | Self::Fld => 8,
1223
}
1224
}
1225
1226
pub(crate) fn op_code(self) -> u32 {
1227
match self {
1228
Self::Lb | Self::Lh | Self::Lw | Self::Lbu | Self::Lhu | Self::Lwu | Self::Ld => {
1229
0b0000011
1230
}
1231
Self::Flh | Self::Flw | Self::Fld => 0b0000111,
1232
}
1233
}
1234
pub(crate) fn funct3(self) -> u32 {
1235
match self {
1236
Self::Lb => 0b000,
1237
Self::Lh => 0b001,
1238
Self::Lw => 0b010,
1239
Self::Lwu => 0b110,
1240
Self::Lbu => 0b100,
1241
Self::Lhu => 0b101,
1242
Self::Ld => 0b011,
1243
Self::Flh => 0b001,
1244
Self::Flw => 0b010,
1245
Self::Fld => 0b011,
1246
}
1247
}
1248
}
1249
1250
impl StoreOP {
1251
pub(crate) fn op_name(self) -> &'static str {
1252
match self {
1253
Self::Sb => "sb",
1254
Self::Sh => "sh",
1255
Self::Sw => "sw",
1256
Self::Sd => "sd",
1257
Self::Fsh => "fsh",
1258
Self::Fsw => "fsw",
1259
Self::Fsd => "fsd",
1260
}
1261
}
1262
pub(crate) fn from_type(ty: Type) -> Self {
1263
match ty {
1264
F16 => Self::Fsh,
1265
F32 => Self::Fsw,
1266
F64 => Self::Fsd,
1267
I8 => Self::Sb,
1268
I16 => Self::Sh,
1269
I32 => Self::Sw,
1270
I64 => Self::Sd,
1271
_ => unreachable!(),
1272
}
1273
}
1274
1275
pub(crate) fn size(&self) -> i64 {
1276
match self {
1277
Self::Sb => 1,
1278
Self::Sh | Self::Fsh => 2,
1279
Self::Sw | Self::Fsw => 4,
1280
Self::Sd | Self::Fsd => 8,
1281
}
1282
}
1283
1284
pub(crate) fn op_code(self) -> u32 {
1285
match self {
1286
Self::Sb | Self::Sh | Self::Sw | Self::Sd => 0b0100011,
1287
Self::Fsh | Self::Fsw | Self::Fsd => 0b0100111,
1288
}
1289
}
1290
pub(crate) fn funct3(self) -> u32 {
1291
match self {
1292
Self::Sb => 0b000,
1293
Self::Sh => 0b001,
1294
Self::Sw => 0b010,
1295
Self::Sd => 0b011,
1296
Self::Fsh => 0b001,
1297
Self::Fsw => 0b010,
1298
Self::Fsd => 0b011,
1299
}
1300
}
1301
}
1302
1303
impl FClassResult {
1304
pub(crate) const fn bit(self) -> u32 {
1305
match self {
1306
FClassResult::NegInfinite => 1 << 0,
1307
FClassResult::NegNormal => 1 << 1,
1308
FClassResult::NegSubNormal => 1 << 2,
1309
FClassResult::NegZero => 1 << 3,
1310
FClassResult::PosZero => 1 << 4,
1311
FClassResult::PosSubNormal => 1 << 5,
1312
FClassResult::PosNormal => 1 << 6,
1313
FClassResult::PosInfinite => 1 << 7,
1314
FClassResult::SNaN => 1 << 8,
1315
FClassResult::QNaN => 1 << 9,
1316
}
1317
}
1318
1319
#[inline]
1320
#[expect(dead_code, reason = "here for future use")]
1321
pub(crate) const fn is_nan_bits() -> u32 {
1322
Self::SNaN.bit() | Self::QNaN.bit()
1323
}
1324
#[inline]
1325
#[expect(dead_code, reason = "here for future use")]
1326
pub(crate) fn is_zero_bits() -> u32 {
1327
Self::NegZero.bit() | Self::PosZero.bit()
1328
}
1329
1330
#[inline]
1331
#[expect(dead_code, reason = "here for future use")]
1332
pub(crate) fn is_infinite_bits() -> u32 {
1333
Self::PosInfinite.bit() | Self::NegInfinite.bit()
1334
}
1335
}
1336
1337
impl AtomicOP {
1338
#[inline]
1339
pub(crate) fn is_load(self) -> bool {
1340
match self {
1341
Self::LrW | Self::LrD => true,
1342
_ => false,
1343
}
1344
}
1345
1346
#[inline]
1347
pub(crate) fn op_name(self, amo: AMO) -> String {
1348
let s = match self {
1349
Self::LrW => "lr.w",
1350
Self::ScW => "sc.w",
1351
1352
Self::AmoswapW => "amoswap.w",
1353
Self::AmoaddW => "amoadd.w",
1354
Self::AmoxorW => "amoxor.w",
1355
Self::AmoandW => "amoand.w",
1356
Self::AmoorW => "amoor.w",
1357
Self::AmominW => "amomin.w",
1358
Self::AmomaxW => "amomax.w",
1359
Self::AmominuW => "amominu.w",
1360
Self::AmomaxuW => "amomaxu.w",
1361
Self::LrD => "lr.d",
1362
Self::ScD => "sc.d",
1363
Self::AmoswapD => "amoswap.d",
1364
Self::AmoaddD => "amoadd.d",
1365
Self::AmoxorD => "amoxor.d",
1366
Self::AmoandD => "amoand.d",
1367
Self::AmoorD => "amoor.d",
1368
Self::AmominD => "amomin.d",
1369
Self::AmomaxD => "amomax.d",
1370
Self::AmominuD => "amominu.d",
1371
Self::AmomaxuD => "amomaxu.d",
1372
};
1373
format!("{}{}", s, amo.to_static_str())
1374
}
1375
#[inline]
1376
pub(crate) fn op_code(self) -> u32 {
1377
0b0101111
1378
}
1379
1380
#[inline]
1381
pub(crate) fn funct7(self, amo: AMO) -> u32 {
1382
self.funct5() << 2 | amo.as_u32() & 0b11
1383
}
1384
1385
pub(crate) fn funct3(self) -> u32 {
1386
match self {
1387
AtomicOP::LrW
1388
| AtomicOP::ScW
1389
| AtomicOP::AmoswapW
1390
| AtomicOP::AmoaddW
1391
| AtomicOP::AmoxorW
1392
| AtomicOP::AmoandW
1393
| AtomicOP::AmoorW
1394
| AtomicOP::AmominW
1395
| AtomicOP::AmomaxW
1396
| AtomicOP::AmominuW
1397
| AtomicOP::AmomaxuW => 0b010,
1398
AtomicOP::LrD
1399
| AtomicOP::ScD
1400
| AtomicOP::AmoswapD
1401
| AtomicOP::AmoaddD
1402
| AtomicOP::AmoxorD
1403
| AtomicOP::AmoandD
1404
| AtomicOP::AmoorD
1405
| AtomicOP::AmominD
1406
| AtomicOP::AmomaxD
1407
| AtomicOP::AmominuD
1408
| AtomicOP::AmomaxuD => 0b011,
1409
}
1410
}
1411
pub(crate) fn funct5(self) -> u32 {
1412
match self {
1413
AtomicOP::LrW => 0b00010,
1414
AtomicOP::ScW => 0b00011,
1415
AtomicOP::AmoswapW => 0b00001,
1416
AtomicOP::AmoaddW => 0b00000,
1417
AtomicOP::AmoxorW => 0b00100,
1418
AtomicOP::AmoandW => 0b01100,
1419
AtomicOP::AmoorW => 0b01000,
1420
AtomicOP::AmominW => 0b10000,
1421
AtomicOP::AmomaxW => 0b10100,
1422
AtomicOP::AmominuW => 0b11000,
1423
AtomicOP::AmomaxuW => 0b11100,
1424
AtomicOP::LrD => 0b00010,
1425
AtomicOP::ScD => 0b00011,
1426
AtomicOP::AmoswapD => 0b00001,
1427
AtomicOP::AmoaddD => 0b00000,
1428
AtomicOP::AmoxorD => 0b00100,
1429
AtomicOP::AmoandD => 0b01100,
1430
AtomicOP::AmoorD => 0b01000,
1431
AtomicOP::AmominD => 0b10000,
1432
AtomicOP::AmomaxD => 0b10100,
1433
AtomicOP::AmominuD => 0b11000,
1434
AtomicOP::AmomaxuD => 0b11100,
1435
}
1436
}
1437
1438
pub(crate) fn load_op(t: Type) -> Self {
1439
if t.bits() <= 32 { Self::LrW } else { Self::LrD }
1440
}
1441
pub(crate) fn store_op(t: Type) -> Self {
1442
if t.bits() <= 32 { Self::ScW } else { Self::ScD }
1443
}
1444
1445
/// extract
1446
pub(crate) fn extract(rd: WritableReg, offset: Reg, rs: Reg, ty: Type) -> SmallInstVec<Inst> {
1447
let mut insts = SmallInstVec::new();
1448
insts.push(Inst::AluRRR {
1449
alu_op: AluOPRRR::Srl,
1450
rd,
1451
rs1: rs,
1452
rs2: offset,
1453
});
1454
//
1455
insts.push(Inst::Extend {
1456
rd,
1457
rn: rd.to_reg(),
1458
signed: false,
1459
from_bits: ty.bits() as u8,
1460
to_bits: 64,
1461
});
1462
insts
1463
}
1464
1465
/// like extract but sign extend the value.
1466
/// suitable for smax,etc.
1467
pub(crate) fn extract_sext(
1468
rd: WritableReg,
1469
offset: Reg,
1470
rs: Reg,
1471
ty: Type,
1472
) -> SmallInstVec<Inst> {
1473
let mut insts = SmallInstVec::new();
1474
insts.push(Inst::AluRRR {
1475
alu_op: AluOPRRR::Srl,
1476
rd,
1477
rs1: rs,
1478
rs2: offset,
1479
});
1480
//
1481
insts.push(Inst::Extend {
1482
rd,
1483
rn: rd.to_reg(),
1484
signed: true,
1485
from_bits: ty.bits() as u8,
1486
to_bits: 64,
1487
});
1488
insts
1489
}
1490
1491
pub(crate) fn unset(
1492
rd: WritableReg,
1493
tmp: WritableReg,
1494
offset: Reg,
1495
ty: Type,
1496
) -> SmallInstVec<Inst> {
1497
assert!(rd != tmp);
1498
let mut insts = SmallInstVec::new();
1499
insts.extend(Inst::load_int_mask(tmp, ty));
1500
insts.push(Inst::AluRRR {
1501
alu_op: AluOPRRR::Sll,
1502
rd: tmp,
1503
rs1: tmp.to_reg(),
1504
rs2: offset,
1505
});
1506
insts.push(Inst::construct_bit_not(tmp, tmp.to_reg()));
1507
insts.push(Inst::AluRRR {
1508
alu_op: AluOPRRR::And,
1509
rd,
1510
rs1: rd.to_reg(),
1511
rs2: tmp.to_reg(),
1512
});
1513
insts
1514
}
1515
1516
pub(crate) fn set(
1517
rd: WritableReg,
1518
tmp: WritableReg,
1519
offset: Reg,
1520
rs: Reg,
1521
ty: Type,
1522
) -> SmallInstVec<Inst> {
1523
assert!(rd != tmp);
1524
let mut insts = SmallInstVec::new();
1525
// make rs into tmp.
1526
insts.push(Inst::Extend {
1527
rd: tmp,
1528
rn: rs,
1529
signed: false,
1530
from_bits: ty.bits() as u8,
1531
to_bits: 64,
1532
});
1533
insts.push(Inst::AluRRR {
1534
alu_op: AluOPRRR::Sll,
1535
rd: tmp,
1536
rs1: tmp.to_reg(),
1537
rs2: offset,
1538
});
1539
insts.push(Inst::AluRRR {
1540
alu_op: AluOPRRR::Or,
1541
rd,
1542
rs1: rd.to_reg(),
1543
rs2: tmp.to_reg(),
1544
});
1545
insts
1546
}
1547
1548
/// Merge reset part of rs into rd.
1549
/// Call this function must make sure that other part of value is already in rd.
1550
pub(crate) fn merge(
1551
rd: WritableReg,
1552
tmp: WritableReg,
1553
offset: Reg,
1554
rs: Reg,
1555
ty: Type,
1556
) -> SmallInstVec<Inst> {
1557
let mut insts = Self::unset(rd, tmp, offset, ty);
1558
insts.extend(Self::set(rd, tmp, offset, rs, ty));
1559
insts
1560
}
1561
}
1562
1563
///Atomic Memory ordering.
1564
#[derive(Copy, Clone, Debug)]
1565
pub enum AMO {
1566
Relax = 0b00,
1567
Release = 0b01,
1568
Acquire = 0b10,
1569
SeqCst = 0b11,
1570
}
1571
1572
impl AMO {
1573
pub(crate) fn to_static_str(self) -> &'static str {
1574
match self {
1575
AMO::Relax => "",
1576
AMO::Release => ".rl",
1577
AMO::Acquire => ".aq",
1578
AMO::SeqCst => ".aqrl",
1579
}
1580
}
1581
pub(crate) fn as_u32(self) -> u32 {
1582
self as u32
1583
}
1584
}
1585
1586
impl Inst {
1587
/// fence request bits.
1588
pub(crate) const FENCE_REQ_I: u8 = 1 << 3;
1589
pub(crate) const FENCE_REQ_O: u8 = 1 << 2;
1590
pub(crate) const FENCE_REQ_R: u8 = 1 << 1;
1591
pub(crate) const FENCE_REQ_W: u8 = 1 << 0;
1592
pub(crate) fn fence_req_to_string(x: u8) -> String {
1593
let mut s = String::default();
1594
if x & Self::FENCE_REQ_I != 0 {
1595
s.push_str("i");
1596
}
1597
if x & Self::FENCE_REQ_O != 0 {
1598
s.push_str("o");
1599
}
1600
if x & Self::FENCE_REQ_R != 0 {
1601
s.push_str("r");
1602
}
1603
if x & Self::FENCE_REQ_W != 0 {
1604
s.push_str("w");
1605
}
1606
s
1607
}
1608
}
1609
1610
impl CsrRegOP {
1611
pub(crate) fn funct3(self) -> u32 {
1612
match self {
1613
CsrRegOP::CsrRW => 0b001,
1614
CsrRegOP::CsrRS => 0b010,
1615
CsrRegOP::CsrRC => 0b011,
1616
}
1617
}
1618
1619
pub(crate) fn opcode(self) -> u32 {
1620
0b1110011
1621
}
1622
1623
pub(crate) fn name(self) -> &'static str {
1624
match self {
1625
CsrRegOP::CsrRW => "csrrw",
1626
CsrRegOP::CsrRS => "csrrs",
1627
CsrRegOP::CsrRC => "csrrc",
1628
}
1629
}
1630
}
1631
1632
impl Display for CsrRegOP {
1633
fn fmt(&self, f: &mut Formatter<'_>) -> Result {
1634
write!(f, "{}", self.name())
1635
}
1636
}
1637
1638
impl CsrImmOP {
1639
pub(crate) fn funct3(self) -> u32 {
1640
match self {
1641
CsrImmOP::CsrRWI => 0b101,
1642
CsrImmOP::CsrRSI => 0b110,
1643
CsrImmOP::CsrRCI => 0b111,
1644
}
1645
}
1646
1647
pub(crate) fn opcode(self) -> u32 {
1648
0b1110011
1649
}
1650
1651
pub(crate) fn name(self) -> &'static str {
1652
match self {
1653
CsrImmOP::CsrRWI => "csrrwi",
1654
CsrImmOP::CsrRSI => "csrrsi",
1655
CsrImmOP::CsrRCI => "csrrci",
1656
}
1657
}
1658
}
1659
1660
impl Display for CsrImmOP {
1661
fn fmt(&self, f: &mut Formatter<'_>) -> Result {
1662
write!(f, "{}", self.name())
1663
}
1664
}
1665
1666
impl CSR {
1667
pub(crate) fn bits(self) -> Imm12 {
1668
Imm12::from_i16(match self {
1669
CSR::Frm => 0x0002,
1670
})
1671
}
1672
1673
pub(crate) fn name(self) -> &'static str {
1674
match self {
1675
CSR::Frm => "frm",
1676
}
1677
}
1678
}
1679
1680
impl Display for CSR {
1681
fn fmt(&self, f: &mut Formatter<'_>) -> Result {
1682
write!(f, "{}", self.name())
1683
}
1684
}
1685
1686
impl COpcodeSpace {
1687
pub fn bits(&self) -> u32 {
1688
match self {
1689
COpcodeSpace::C0 => 0b00,
1690
COpcodeSpace::C1 => 0b01,
1691
COpcodeSpace::C2 => 0b10,
1692
}
1693
}
1694
}
1695
1696
impl CrOp {
1697
pub fn funct4(&self) -> u32 {
1698
// https://five-embeddev.com/riscv-isa-manual/latest/rvc-opcode-map.html#rvcopcodemap
1699
match self {
1700
// `c.jr` has the same op/funct4 as C.MV, but RS2 is 0, which is illegal for mv.
1701
CrOp::CMv | CrOp::CJr => 0b1000,
1702
CrOp::CAdd | CrOp::CJalr | CrOp::CEbreak => 0b1001,
1703
}
1704
}
1705
1706
pub fn op(&self) -> COpcodeSpace {
1707
// https://five-embeddev.com/riscv-isa-manual/latest/rvc-opcode-map.html#rvcopcodemap
1708
match self {
1709
CrOp::CMv | CrOp::CAdd | CrOp::CJr | CrOp::CJalr | CrOp::CEbreak => COpcodeSpace::C2,
1710
}
1711
}
1712
}
1713
1714
impl CaOp {
1715
pub fn funct2(&self) -> u32 {
1716
// https://github.com/michaeljclark/riscv-meta/blob/master/opcodes
1717
match self {
1718
CaOp::CAnd => 0b11,
1719
CaOp::COr => 0b10,
1720
CaOp::CXor => 0b01,
1721
CaOp::CSub => 0b00,
1722
CaOp::CAddw => 0b01,
1723
CaOp::CSubw => 0b00,
1724
CaOp::CMul => 0b10,
1725
}
1726
}
1727
1728
pub fn funct6(&self) -> u32 {
1729
// https://github.com/michaeljclark/riscv-meta/blob/master/opcodes
1730
match self {
1731
CaOp::CAnd | CaOp::COr | CaOp::CXor | CaOp::CSub => 0b100_011,
1732
CaOp::CSubw | CaOp::CAddw | CaOp::CMul => 0b100_111,
1733
}
1734
}
1735
1736
pub fn op(&self) -> COpcodeSpace {
1737
// https://five-embeddev.com/riscv-isa-manual/latest/rvc-opcode-map.html#rvcopcodemap
1738
match self {
1739
CaOp::CAnd
1740
| CaOp::COr
1741
| CaOp::CXor
1742
| CaOp::CSub
1743
| CaOp::CAddw
1744
| CaOp::CSubw
1745
| CaOp::CMul => COpcodeSpace::C1,
1746
}
1747
}
1748
}
1749
1750
impl CjOp {
1751
pub fn funct3(&self) -> u32 {
1752
// https://github.com/michaeljclark/riscv-meta/blob/master/opcodes
1753
match self {
1754
CjOp::CJ => 0b101,
1755
}
1756
}
1757
1758
pub fn op(&self) -> COpcodeSpace {
1759
// https://five-embeddev.com/riscv-isa-manual/latest/rvc-opcode-map.html#rvcopcodemap
1760
match self {
1761
CjOp::CJ => COpcodeSpace::C1,
1762
}
1763
}
1764
}
1765
1766
impl CiOp {
1767
pub fn funct3(&self) -> u32 {
1768
// https://github.com/michaeljclark/riscv-meta/blob/master/opcodes
1769
match self {
1770
CiOp::CAddi | CiOp::CSlli => 0b000,
1771
CiOp::CAddiw | CiOp::CFldsp => 0b001,
1772
CiOp::CLi | CiOp::CLwsp => 0b010,
1773
CiOp::CAddi16sp | CiOp::CLui | CiOp::CLdsp => 0b011,
1774
}
1775
}
1776
1777
pub fn op(&self) -> COpcodeSpace {
1778
// https://five-embeddev.com/riscv-isa-manual/latest/rvc-opcode-map.html#rvcopcodemap
1779
match self {
1780
CiOp::CAddi | CiOp::CAddiw | CiOp::CAddi16sp | CiOp::CLi | CiOp::CLui => {
1781
COpcodeSpace::C1
1782
}
1783
CiOp::CSlli | CiOp::CLwsp | CiOp::CLdsp | CiOp::CFldsp => COpcodeSpace::C2,
1784
}
1785
}
1786
}
1787
1788
impl CiwOp {
1789
pub fn funct3(&self) -> u32 {
1790
// https://github.com/michaeljclark/riscv-meta/blob/master/opcodes
1791
match self {
1792
CiwOp::CAddi4spn => 0b000,
1793
}
1794
}
1795
1796
pub fn op(&self) -> COpcodeSpace {
1797
// https://five-embeddev.com/riscv-isa-manual/latest/rvc-opcode-map.html#rvcopcodemap
1798
match self {
1799
CiwOp::CAddi4spn => COpcodeSpace::C0,
1800
}
1801
}
1802
}
1803
1804
impl CbOp {
1805
pub fn funct3(&self) -> u32 {
1806
// https://github.com/michaeljclark/riscv-meta/blob/master/opcodes
1807
match self {
1808
CbOp::CSrli | CbOp::CSrai | CbOp::CAndi => 0b100,
1809
}
1810
}
1811
1812
pub fn funct2(&self) -> u32 {
1813
// https://github.com/michaeljclark/riscv-meta/blob/master/opcodes
1814
match self {
1815
CbOp::CSrli => 0b00,
1816
CbOp::CSrai => 0b01,
1817
CbOp::CAndi => 0b10,
1818
}
1819
}
1820
1821
pub fn op(&self) -> COpcodeSpace {
1822
// https://five-embeddev.com/riscv-isa-manual/latest/rvc-opcode-map.html#rvcopcodemap
1823
match self {
1824
CbOp::CSrli | CbOp::CSrai | CbOp::CAndi => COpcodeSpace::C1,
1825
}
1826
}
1827
}
1828
1829
impl CssOp {
1830
pub fn funct3(&self) -> u32 {
1831
// https://github.com/michaeljclark/riscv-meta/blob/master/opcodes
1832
match self {
1833
CssOp::CFsdsp => 0b101,
1834
CssOp::CSwsp => 0b110,
1835
CssOp::CSdsp => 0b111,
1836
}
1837
}
1838
1839
pub fn op(&self) -> COpcodeSpace {
1840
// https://five-embeddev.com/riscv-isa-manual/latest/rvc-opcode-map.html#rvcopcodemap
1841
match self {
1842
CssOp::CSwsp | CssOp::CSdsp | CssOp::CFsdsp => COpcodeSpace::C2,
1843
}
1844
}
1845
}
1846
1847
impl CsOp {
1848
pub fn funct3(&self) -> u32 {
1849
// https://github.com/michaeljclark/riscv-meta/blob/master/opcodes
1850
match self {
1851
CsOp::CFsd => 0b101,
1852
CsOp::CSw => 0b110,
1853
CsOp::CSd => 0b111,
1854
}
1855
}
1856
1857
pub fn op(&self) -> COpcodeSpace {
1858
// https://five-embeddev.com/riscv-isa-manual/latest/rvc-opcode-map.html#rvcopcodemap
1859
match self {
1860
CsOp::CSw | CsOp::CSd | CsOp::CFsd => COpcodeSpace::C0,
1861
}
1862
}
1863
}
1864
1865
impl ClOp {
1866
pub fn funct3(&self) -> u32 {
1867
// https://github.com/michaeljclark/riscv-meta/blob/master/opcodes
1868
match self {
1869
ClOp::CFld => 0b001,
1870
ClOp::CLw => 0b010,
1871
ClOp::CLd => 0b011,
1872
}
1873
}
1874
1875
pub fn op(&self) -> COpcodeSpace {
1876
// https://five-embeddev.com/riscv-isa-manual/latest/rvc-opcode-map.html#rvcopcodemap
1877
match self {
1878
ClOp::CLw | ClOp::CLd | ClOp::CFld => COpcodeSpace::C0,
1879
}
1880
}
1881
}
1882
1883
impl CsznOp {
1884
pub fn funct6(&self) -> u32 {
1885
// https://github.com/michaeljclark/riscv-meta/blob/master/opcodes
1886
match self {
1887
CsznOp::CNot
1888
| CsznOp::CZextw
1889
| CsznOp::CZextb
1890
| CsznOp::CZexth
1891
| CsznOp::CSextb
1892
| CsznOp::CSexth => 0b100_111,
1893
}
1894
}
1895
1896
pub fn funct5(&self) -> u32 {
1897
// https://github.com/michaeljclark/riscv-meta/blob/master/opcodes
1898
match self {
1899
CsznOp::CNot => 0b11_101,
1900
CsznOp::CZextb => 0b11_000,
1901
CsznOp::CZexth => 0b11_010,
1902
CsznOp::CZextw => 0b11_100,
1903
CsznOp::CSextb => 0b11_001,
1904
CsznOp::CSexth => 0b11_011,
1905
}
1906
}
1907
1908
pub fn op(&self) -> COpcodeSpace {
1909
// https://five-embeddev.com/riscv-isa-manual/latest/rvc-opcode-map.html#rvcopcodemap
1910
match self {
1911
CsznOp::CNot
1912
| CsznOp::CZextb
1913
| CsznOp::CZexth
1914
| CsznOp::CZextw
1915
| CsznOp::CSextb
1916
| CsznOp::CSexth => COpcodeSpace::C1,
1917
}
1918
}
1919
}
1920
1921
impl ZcbMemOp {
1922
pub fn funct6(&self) -> u32 {
1923
// https://github.com/michaeljclark/riscv-meta/blob/master/opcodes
1924
match self {
1925
ZcbMemOp::CLbu => 0b100_000,
1926
// These two opcodes are differentiated in the imm field of the instruction.
1927
ZcbMemOp::CLhu | ZcbMemOp::CLh => 0b100_001,
1928
ZcbMemOp::CSb => 0b100_010,
1929
ZcbMemOp::CSh => 0b100_011,
1930
}
1931
}
1932
1933
pub fn imm_bits(&self) -> u8 {
1934
match self {
1935
ZcbMemOp::CLhu | ZcbMemOp::CLh | ZcbMemOp::CSh => 1,
1936
ZcbMemOp::CLbu | ZcbMemOp::CSb => 2,
1937
}
1938
}
1939
1940
pub fn op(&self) -> COpcodeSpace {
1941
// https://five-embeddev.com/riscv-isa-manual/latest/rvc-opcode-map.html#rvcopcodemap
1942
match self {
1943
ZcbMemOp::CLbu | ZcbMemOp::CLhu | ZcbMemOp::CLh | ZcbMemOp::CSb | ZcbMemOp::CSh => {
1944
COpcodeSpace::C0
1945
}
1946
}
1947
}
1948
}
1949
1950