Skip to content

Commit 92267a7

Browse files
committed
BR instruction
1 parent 1d81a1c commit 92267a7

File tree

2 files changed

+57
-19
lines changed

2 files changed

+57
-19
lines changed

yjit/src/asm/arm64/inst/branch.rs

Lines changed: 33 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,39 @@
1+
/// Which operation to perform.
2+
enum Op {
3+
/// Perform a BR instruction.
4+
Br = 0b00,
5+
6+
/// Perform a RET instruction.
7+
Ret = 0b10
8+
}
9+
110
/// The struct that represents an A64 branch instruction that can be encoded.
211
///
3-
/// RET
412
/// +-------------+-------------+-------------+-------------+-------------+-------------+-------------+-------------+
513
/// | 31 30 29 28 | 27 26 25 24 | 23 22 21 20 | 19 18 17 16 | 15 14 13 12 | 11 10 09 08 | 07 06 05 04 | 03 02 01 00 |
6-
/// | 1 1 0 1 0 1 1 0 0 1 0 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 |
7-
/// | rn.............. rm.............. |
14+
/// | 1 1 0 1 0 1 1 0 0 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 |
15+
/// | op... rn.............. rm.............. |
816
/// +-------------+-------------+-------------+-------------+-------------+-------------+-------------+-------------+
917
///
1018
pub struct Branch {
1119
/// The register holding the address to be branched to.
12-
rn: u8
20+
rn: u8,
21+
22+
/// The operation to perform.
23+
op: Op
1324
}
1425

1526
impl Branch {
27+
/// BR
28+
/// https://developer.arm.com/documentation/ddi0602/2022-03/Base-Instructions/BR--Branch-to-Register-?lang=en
29+
pub fn br(rn: u8) -> Self {
30+
Self { rn, op: Op::Br }
31+
}
32+
1633
/// RET
1734
/// https://developer.arm.com/documentation/ddi0596/2021-12/Base-Instructions/RET--Return-from-subroutine-?lang=en
1835
pub fn ret(rn: u8) -> Self {
19-
Self { rn }
36+
Self { rn, op: Op::Ret }
2037
}
2138
}
2239

@@ -29,7 +46,9 @@ impl From<Branch> for u32 {
2946
0
3047
| (0b11 << 30)
3148
| (FAMILY << 26)
32-
| (0b1001011111 << 16)
49+
| (1 << 25)
50+
| ((inst.op as u32) << 21)
51+
| (0b11111 << 16)
3352
| ((inst.rn as u32) << 5)
3453
}
3554
}
@@ -46,17 +65,21 @@ impl From<Branch> for [u8; 4] {
4665
mod tests {
4766
use super::*;
4867

68+
#[test]
69+
fn test_br() {
70+
let result: u32 = Branch::br(0).into();
71+
assert_eq!(0xd61f0000, result);
72+
}
73+
4974
#[test]
5075
fn test_ret() {
51-
let inst = Branch::ret(30);
52-
let result: u32 = inst.into();
76+
let result: u32 = Branch::ret(30).into();
5377
assert_eq!(0xd65f03C0, result);
5478
}
5579

5680
#[test]
5781
fn test_ret_rn() {
58-
let inst = Branch::ret(20);
59-
let result: u32 = inst.into();
82+
let result: u32 = Branch::ret(20).into();
6083
assert_eq!(0xd65f0280, result);
6184
}
6285
}

yjit/src/asm/arm64/inst/mod.rs

Lines changed: 24 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ use mov::Mov;
1414
use crate::asm::{CodeBlock, imm_num_bits};
1515
use super::opnd::*;
1616

17-
/// ADD
17+
/// ADD - add rn and rm, put the result in rd, don't update flags
1818
pub fn add(cb: &mut CodeBlock, rd: A64Opnd, rn: A64Opnd, rm: A64Opnd) {
1919
let bytes: [u8; 4] = match (rd, rn, rm) {
2020
(A64Opnd::Reg(rd), A64Opnd::Reg(rn), A64Opnd::Reg(rm)) => {
@@ -37,7 +37,7 @@ pub fn add(cb: &mut CodeBlock, rd: A64Opnd, rn: A64Opnd, rm: A64Opnd) {
3737
cb.write_bytes(&bytes);
3838
}
3939

40-
/// ADDS
40+
/// ADDS - add rn and rm, put the result in rd, update flags
4141
pub fn adds(cb: &mut CodeBlock, rd: A64Opnd, rn: A64Opnd, rm: A64Opnd) {
4242
let bytes: [u8; 4] = match (rd, rn, rm) {
4343
(A64Opnd::Reg(rd), A64Opnd::Reg(rn), A64Opnd::Reg(rm)) => {
@@ -60,7 +60,17 @@ pub fn adds(cb: &mut CodeBlock, rd: A64Opnd, rn: A64Opnd, rm: A64Opnd) {
6060
cb.write_bytes(&bytes);
6161
}
6262

63-
/// LDUR
63+
/// BR - branch to a register
64+
pub fn br(cb: &mut CodeBlock, rn: A64Opnd) {
65+
let bytes: [u8; 4] = match rn {
66+
A64Opnd::Reg(rn) => Branch::br(rn.reg_no).into(),
67+
_ => panic!("Invalid operand to br instruction."),
68+
};
69+
70+
cb.write_bytes(&bytes);
71+
}
72+
73+
/// LDUR - load a memory address into a register
6474
pub fn ldur(cb: &mut CodeBlock, rt: A64Opnd, rn: A64Opnd) {
6575
let bytes: [u8; 4] = match (rt, rn) {
6676
(A64Opnd::Reg(rt), A64Opnd::Mem(rn)) => {
@@ -75,7 +85,7 @@ pub fn ldur(cb: &mut CodeBlock, rt: A64Opnd, rn: A64Opnd) {
7585
cb.write_bytes(&bytes);
7686
}
7787

78-
/// MOVK
88+
/// MOVK - move a 16 bit immediate into a register, keep the other bits in place
7989
pub fn movk(cb: &mut CodeBlock, rd: A64Opnd, imm16: A64Opnd, shift: u8) {
8090
let bytes: [u8; 4] = match (rd, imm16) {
8191
(A64Opnd::Reg(rd), A64Opnd::UImm(imm16)) => {
@@ -89,7 +99,7 @@ pub fn movk(cb: &mut CodeBlock, rd: A64Opnd, imm16: A64Opnd, shift: u8) {
8999
cb.write_bytes(&bytes);
90100
}
91101

92-
/// MOVZ
102+
/// MOVZ - move a 16 bit immediate into a register, zero the other bits
93103
pub fn movz(cb: &mut CodeBlock, rd: A64Opnd, imm16: A64Opnd, shift: u8) {
94104
let bytes: [u8; 4] = match (rd, imm16) {
95105
(A64Opnd::Reg(rd), A64Opnd::UImm(imm16)) => {
@@ -103,7 +113,7 @@ pub fn movz(cb: &mut CodeBlock, rd: A64Opnd, imm16: A64Opnd, shift: u8) {
103113
cb.write_bytes(&bytes);
104114
}
105115

106-
/// SUB
116+
/// SUB - subtract rm from rn, put the result in rd, don't update flags
107117
pub fn sub(cb: &mut CodeBlock, rd: A64Opnd, rn: A64Opnd, rm: A64Opnd) {
108118
let bytes: [u8; 4] = match (rd, rn, rm) {
109119
(A64Opnd::Reg(rd), A64Opnd::Reg(rn), A64Opnd::Reg(rm)) => {
@@ -126,7 +136,7 @@ pub fn sub(cb: &mut CodeBlock, rd: A64Opnd, rn: A64Opnd, rm: A64Opnd) {
126136
cb.write_bytes(&bytes);
127137
}
128138

129-
/// SUBS
139+
/// SUBS - subtract rm from rn, put the result in rd, update flags
130140
pub fn subs(cb: &mut CodeBlock, rd: A64Opnd, rn: A64Opnd, rm: A64Opnd) {
131141
let bytes: [u8; 4] = match (rd, rn, rm) {
132142
(A64Opnd::Reg(rd), A64Opnd::Reg(rn), A64Opnd::Reg(rm)) => {
@@ -149,12 +159,12 @@ pub fn subs(cb: &mut CodeBlock, rd: A64Opnd, rn: A64Opnd, rm: A64Opnd) {
149159
cb.write_bytes(&bytes);
150160
}
151161

152-
/// RET
162+
/// RET - unconditionally return to a location in a register, defaults to X30
153163
pub fn ret(cb: &mut CodeBlock, rn: A64Opnd) {
154164
let bytes: [u8; 4] = match rn {
155165
A64Opnd::None => Branch::ret(30).into(),
156166
A64Opnd::Reg(reg) => Branch::ret(reg.reg_no).into(),
157-
_ => panic!("Invalid operand for RET")
167+
_ => panic!("Invalid operand to ret instruction.")
158168
};
159169

160170
cb.write_bytes(&bytes);
@@ -191,6 +201,11 @@ mod tests {
191201
check_bytes("201c00b1", |cb| adds(cb, X0, X1, A64Opnd::new_uimm(7)));
192202
}
193203

204+
#[test]
205+
fn test_br() {
206+
check_bytes("80021fd6", |cb| br(cb, X20));
207+
}
208+
194209
#[test]
195210
fn test_ldur() {
196211
check_bytes("20b047f8", |cb| ldur(cb, X0, A64Opnd::new_mem(X1, 123)));

0 commit comments

Comments
 (0)