Commit d7a89f9876
Changed files (3)
src
codegen
src/codegen/aarch64.zig
@@ -200,7 +200,7 @@ test "FloatingPointRegister.toX" {
/// Represents an instruction in the AArch64 instruction set
pub const Instruction = union(enum) {
- MoveWideImmediate: packed struct {
+ move_wide_immediate: packed struct {
rd: u5,
imm16: u16,
hw: u2,
@@ -208,14 +208,14 @@ pub const Instruction = union(enum) {
opc: u2,
sf: u1,
},
- PCRelativeAddress: packed struct {
+ pc_relative_address: packed struct {
rd: u5,
immhi: u19,
fixed: u5 = 0b10000,
immlo: u2,
op: u1,
},
- LoadStoreRegister: packed struct {
+ load_store_register: packed struct {
rt: u5,
rn: u5,
offset: u12,
@@ -225,7 +225,7 @@ pub const Instruction = union(enum) {
fixed: u3 = 0b111,
size: u2,
},
- LoadStorePairOfRegisters: packed struct {
+ load_store_register_pair: packed struct {
rt1: u5,
rn: u5,
rt2: u5,
@@ -235,20 +235,20 @@ pub const Instruction = union(enum) {
fixed: u5 = 0b101_0_0,
opc: u2,
},
- LoadLiteral: packed struct {
+ load_literal: packed struct {
rt: u5,
imm19: u19,
fixed: u6 = 0b011_0_00,
opc: u2,
},
- ExceptionGeneration: packed struct {
+ exception_generation: packed struct {
ll: u2,
op2: u3,
imm16: u16,
opc: u3,
fixed: u8 = 0b1101_0100,
},
- UnconditionalBranchRegister: packed struct {
+ unconditional_branch_register: packed struct {
op4: u5,
rn: u5,
op3: u6,
@@ -256,15 +256,15 @@ pub const Instruction = union(enum) {
opc: u4,
fixed: u7 = 0b1101_011,
},
- UnconditionalBranchImmediate: packed struct {
+ unconditional_branch_immediate: packed struct {
imm26: u26,
fixed: u5 = 0b00101,
op: u1,
},
- NoOperation: packed struct {
+ no_operation: packed struct {
fixed: u32 = 0b1101010100_0_00_011_0010_0000_000_11111,
},
- LogicalShiftedRegister: packed struct {
+ logical_shifted_register: packed struct {
rd: u5,
rn: u5,
imm6: u6,
@@ -275,7 +275,7 @@ pub const Instruction = union(enum) {
opc: u2,
sf: u1,
},
- AddSubtractImmediate: packed struct {
+ add_subtract_immediate: packed struct {
rd: u5,
rn: u5,
imm12: u12,
@@ -285,6 +285,20 @@ pub const Instruction = union(enum) {
op: u1,
sf: u1,
},
+ conditional_branch: struct {
+ cond: u4,
+ o0: u1,
+ imm19: u19,
+ o1: u1,
+ fixed: u7 = 0b0101010,
+ },
+ compare_and_branch: struct {
+ rt: u5,
+ imm19: u19,
+ op: u1,
+ fixed: u6 = 0b011010,
+ sf: u1,
+ },
pub const Shift = struct {
shift: Type = .lsl,
@@ -303,19 +317,73 @@ pub const Instruction = union(enum) {
};
};
+ pub const Condition = enum(u4) {
+ /// Integer: Equal
+ /// Floating point: Equal
+ eq,
+ /// Integer: Not equal
+ /// Floating point: Not equal or unordered
+ ne,
+ /// Integer: Carry set
+ /// Floating point: Greater than, equal, or unordered
+ cs,
+ /// Integer: Carry clear
+ /// Floating point: Less than
+ cc,
+ /// Integer: Minus, negative
+ /// Floating point: Less than
+ mi,
+ /// Integer: Plus, positive or zero
+ /// Floating point: Greater than, equal, or unordered
+ pl,
+ /// Integer: Overflow
+ /// Floating point: Unordered
+ vs,
+ /// Integer: No overflow
+ /// Floating point: Ordered
+ vc,
+ /// Integer: Unsigned higher
+ /// Floating point: Greater than, or unordered
+ hi,
+ /// Integer: Unsigned lower or same
+ /// Floating point: Less than or equal
+ ls,
+ /// Integer: Signed greater than or equal
+ /// Floating point: Greater than or equal
+ ge,
+ /// Integer: Signed less than
+ /// Floating point: Less than, or unordered
+ lt,
+ /// Integer: Signed greater than
+ /// Floating point: Greater than
+ gt,
+ /// Integer: Signed less than or equal
+ /// Floating point: Less than, equal, or unordered
+ le,
+ /// Integer: Always
+ /// Floating point: Always
+ al,
+ /// Integer: Always
+ /// Floating point: Always
+ nv,
+ };
+
pub fn toU32(self: Instruction) u32 {
return switch (self) {
- .MoveWideImmediate => |v| @bitCast(u32, v),
- .PCRelativeAddress => |v| @bitCast(u32, v),
- .LoadStoreRegister => |v| @bitCast(u32, v),
- .LoadStorePairOfRegisters => |v| @bitCast(u32, v),
- .LoadLiteral => |v| @bitCast(u32, v),
- .ExceptionGeneration => |v| @bitCast(u32, v),
- .UnconditionalBranchRegister => |v| @bitCast(u32, v),
- .UnconditionalBranchImmediate => |v| @bitCast(u32, v),
- .NoOperation => |v| @bitCast(u32, v),
- .LogicalShiftedRegister => |v| @bitCast(u32, v),
- .AddSubtractImmediate => |v| @bitCast(u32, v),
+ .move_wide_immediate => |v| @bitCast(u32, v),
+ .pc_relative_address => |v| @bitCast(u32, v),
+ .load_store_register => |v| @bitCast(u32, v),
+ .load_store_register_pair => |v| @bitCast(u32, v),
+ .load_literal => |v| @bitCast(u32, v),
+ .exception_generation => |v| @bitCast(u32, v),
+ .unconditional_branch_register => |v| @bitCast(u32, v),
+ .unconditional_branch_immediate => |v| @bitCast(u32, v),
+ .no_operation => |v| @bitCast(u32, v),
+ .logical_shifted_register => |v| @bitCast(u32, v),
+ .add_subtract_immediate => |v| @bitCast(u32, v),
+ // TODO once packed structs work, this can be refactored
+ .conditional_branch => |v| @as(u32, v.cond) | (@as(u32, v.o0) << 4) | (@as(u32, v.imm19) << 5) | (@as(u32, v.o1) << 24) | (@as(u32, v.fixed) << 25),
+ .compare_and_branch => |v| @as(u32, v.rt) | (@as(u32, v.imm19) << 5) | (@as(u32, v.op) << 24) | (@as(u32, v.fixed) << 25) | (@as(u32, v.sf) << 31),
};
}
@@ -329,7 +397,7 @@ pub const Instruction = union(enum) {
32 => {
assert(shift % 16 == 0 and shift <= 16);
return Instruction{
- .MoveWideImmediate = .{
+ .move_wide_immediate = .{
.rd = rd.id(),
.imm16 = imm16,
.hw = @intCast(u2, shift / 16),
@@ -341,7 +409,7 @@ pub const Instruction = union(enum) {
64 => {
assert(shift % 16 == 0 and shift <= 48);
return Instruction{
- .MoveWideImmediate = .{
+ .move_wide_immediate = .{
.rd = rd.id(),
.imm16 = imm16,
.hw = @intCast(u2, shift / 16),
@@ -358,7 +426,7 @@ pub const Instruction = union(enum) {
assert(rd.size() == 64);
const imm21_u = @bitCast(u21, imm21);
return Instruction{
- .PCRelativeAddress = .{
+ .pc_relative_address = .{
.rd = rd.id(),
.immlo = @truncate(u2, imm21_u),
.immhi = @truncate(u19, imm21_u >> 2),
@@ -522,7 +590,7 @@ pub const Instruction = union(enum) {
.str, .strh, .strb => 0b00,
};
return Instruction{
- .LoadStoreRegister = .{
+ .load_store_register = .{
.rt = rt.id(),
.rn = rn.id(),
.offset = off,
@@ -544,7 +612,7 @@ pub const Instruction = union(enum) {
};
}
- fn loadStorePairOfRegisters(
+ fn loadStoreRegisterPair(
rt1: Register,
rt2: Register,
rn: Register,
@@ -557,7 +625,7 @@ pub const Instruction = union(enum) {
assert(-256 <= offset and offset <= 252);
const imm7 = @truncate(u7, @bitCast(u9, offset >> 2));
return Instruction{
- .LoadStorePairOfRegisters = .{
+ .load_store_register_pair = .{
.rt1 = rt1.id(),
.rn = rn.id(),
.rt2 = rt2.id(),
@@ -572,7 +640,7 @@ pub const Instruction = union(enum) {
assert(-512 <= offset and offset <= 504);
const imm7 = @truncate(u7, @bitCast(u9, offset >> 3));
return Instruction{
- .LoadStorePairOfRegisters = .{
+ .load_store_register_pair = .{
.rt1 = rt1.id(),
.rn = rn.id(),
.rt2 = rt2.id(),
@@ -591,7 +659,7 @@ pub const Instruction = union(enum) {
switch (rt.size()) {
32 => {
return Instruction{
- .LoadLiteral = .{
+ .load_literal = .{
.rt = rt.id(),
.imm19 = imm19,
.opc = 0b00,
@@ -600,7 +668,7 @@ pub const Instruction = union(enum) {
},
64 => {
return Instruction{
- .LoadLiteral = .{
+ .load_literal = .{
.rt = rt.id(),
.imm19 = imm19,
.opc = 0b01,
@@ -618,7 +686,7 @@ pub const Instruction = union(enum) {
imm16: u16,
) Instruction {
return Instruction{
- .ExceptionGeneration = .{
+ .exception_generation = .{
.ll = ll,
.op2 = op2,
.imm16 = imm16,
@@ -637,7 +705,7 @@ pub const Instruction = union(enum) {
assert(rn.size() == 64);
return Instruction{
- .UnconditionalBranchRegister = .{
+ .unconditional_branch_register = .{
.op4 = op4,
.rn = rn.id(),
.op3 = op3,
@@ -652,7 +720,7 @@ pub const Instruction = union(enum) {
offset: i28,
) Instruction {
return Instruction{
- .UnconditionalBranchImmediate = .{
+ .unconditional_branch_immediate = .{
.imm26 = @bitCast(u26, @intCast(i26, offset >> 2)),
.op = op,
},
@@ -671,7 +739,7 @@ pub const Instruction = union(enum) {
32 => {
assert(shift.amount < 32);
return Instruction{
- .LogicalShiftedRegister = .{
+ .logical_shifted_register = .{
.rd = rd.id(),
.rn = rn.id(),
.imm6 = shift.amount,
@@ -685,7 +753,7 @@ pub const Instruction = union(enum) {
},
64 => {
return Instruction{
- .LogicalShiftedRegister = .{
+ .logical_shifted_register = .{
.rd = rd.id(),
.rn = rn.id(),
.imm6 = shift.amount,
@@ -710,7 +778,7 @@ pub const Instruction = union(enum) {
shift: bool,
) Instruction {
return Instruction{
- .AddSubtractImmediate = .{
+ .add_subtract_immediate = .{
.rd = rd.id(),
.rn = rn.id(),
.imm12 = imm12,
@@ -726,6 +794,43 @@ pub const Instruction = union(enum) {
};
}
+ fn conditionalBranch(
+ o0: u1,
+ o1: u1,
+ cond: Condition,
+ offset: i21,
+ ) Instruction {
+ assert(offset & 0b11 == 0b00);
+ return Instruction{
+ .conditional_branch = .{
+ .cond = @enumToInt(cond),
+ .o0 = o0,
+ .imm19 = @bitCast(u19, @intCast(i19, offset >> 2)),
+ .o1 = o1,
+ },
+ };
+ }
+
+ fn compareAndBranch(
+ op: u1,
+ rt: Register,
+ offset: i21,
+ ) Instruction {
+ assert(offset & 0b11 == 0b00);
+ return Instruction{
+ .compare_and_branch = .{
+ .rt = rt.id(),
+ .imm19 = @bitCast(u19, @intCast(i19, offset >> 2)),
+ .op = op,
+ .sf = switch (rt.size()) {
+ 32 => 0b0,
+ 64 => 0b1,
+ else => unreachable, // unexpected register size
+ },
+ },
+ };
+ }
+
// Helper functions for assembly syntax functions
// Move wide (immediate)
@@ -821,19 +926,19 @@ pub const Instruction = union(enum) {
};
pub fn ldp(rt1: Register, rt2: Register, rn: Register, offset: LoadStorePairOffset) Instruction {
- return loadStorePairOfRegisters(rt1, rt2, rn, offset.offset, @enumToInt(offset.encoding), true);
+ return loadStoreRegisterPair(rt1, rt2, rn, offset.offset, @enumToInt(offset.encoding), true);
}
pub fn ldnp(rt1: Register, rt2: Register, rn: Register, offset: i9) Instruction {
- return loadStorePairOfRegisters(rt1, rt2, rn, offset, 0, true);
+ return loadStoreRegisterPair(rt1, rt2, rn, offset, 0, true);
}
pub fn stp(rt1: Register, rt2: Register, rn: Register, offset: LoadStorePairOffset) Instruction {
- return loadStorePairOfRegisters(rt1, rt2, rn, offset.offset, @enumToInt(offset.encoding), false);
+ return loadStoreRegisterPair(rt1, rt2, rn, offset.offset, @enumToInt(offset.encoding), false);
}
pub fn stnp(rt1: Register, rt2: Register, rn: Register, offset: i9) Instruction {
- return loadStorePairOfRegisters(rt1, rt2, rn, offset, 0, false);
+ return loadStoreRegisterPair(rt1, rt2, rn, offset, 0, false);
}
// Exception generation
@@ -885,7 +990,7 @@ pub const Instruction = union(enum) {
// Nop
pub fn nop() Instruction {
- return Instruction{ .NoOperation = .{} };
+ return Instruction{ .no_operation = .{} };
}
// Logical (shifted register)
@@ -939,6 +1044,22 @@ pub const Instruction = union(enum) {
pub fn subs(rd: Register, rn: Register, imm: u12, shift: bool) Instruction {
return addSubtractImmediate(0b1, 0b1, rd, rn, imm, shift);
}
+
+ // Conditional branch
+
+ pub fn bCond(cond: Condition, offset: i21) Instruction {
+ return conditionalBranch(0b0, 0b0, cond, offset);
+ }
+
+ // Compare and branch
+
+ pub fn cbz(rt: Register, offset: i21) Instruction {
+ return compareAndBranch(0b0, rt, offset);
+ }
+
+ pub fn cbnz(rt: Register, offset: i21) Instruction {
+ return compareAndBranch(0b1, rt, offset);
+ }
};
test {
@@ -1092,6 +1213,14 @@ test "serialize instructions" {
.inst = Instruction.subs(.x0, .x5, 11, true),
.expected = 0b1_1_1_100010_1_0000_0000_1011_00101_00000,
},
+ .{ // b.hi #-4
+ .inst = Instruction.bCond(.hi, -4),
+ .expected = 0b0101010_0_1111111111111111111_0_1000,
+ },
+ .{ // cbz x10, #40
+ .inst = Instruction.cbz(.x10, 40),
+ .expected = 0b1_011010_0_0000000000000001010_01010,
+ },
};
for (testcases) |case| {
src/link/MachO/Zld.zig
@@ -1668,7 +1668,7 @@ fn doRelocs(self: *Zld) !void {
var parsed = mem.bytesAsValue(
meta.TagPayload(
aarch64.Instruction,
- aarch64.Instruction.UnconditionalBranchImmediate,
+ aarch64.Instruction.unconditional_branch_immediate,
),
inst,
);
@@ -1688,7 +1688,7 @@ fn doRelocs(self: *Zld) !void {
var parsed = mem.bytesAsValue(
meta.TagPayload(
aarch64.Instruction,
- aarch64.Instruction.PCRelativeAddress,
+ aarch64.Instruction.pc_relative_address,
),
inst,
);
@@ -1706,7 +1706,7 @@ fn doRelocs(self: *Zld) !void {
var parsed = mem.bytesAsValue(
meta.TagPayload(
aarch64.Instruction,
- aarch64.Instruction.AddSubtractImmediate,
+ aarch64.Instruction.add_subtract_immediate,
),
inst,
);
@@ -1719,7 +1719,7 @@ fn doRelocs(self: *Zld) !void {
var parsed = mem.bytesAsValue(
meta.TagPayload(
aarch64.Instruction,
- aarch64.Instruction.LoadStoreRegister,
+ aarch64.Instruction.load_store_register,
),
inst,
);
@@ -1774,7 +1774,7 @@ fn doRelocs(self: *Zld) !void {
const curr = mem.bytesAsValue(
meta.TagPayload(
aarch64.Instruction,
- aarch64.Instruction.AddSubtractImmediate,
+ aarch64.Instruction.add_subtract_immediate,
),
inst,
);
@@ -1783,7 +1783,7 @@ fn doRelocs(self: *Zld) !void {
const curr = mem.bytesAsValue(
meta.TagPayload(
aarch64.Instruction,
- aarch64.Instruction.LoadStoreRegister,
+ aarch64.Instruction.load_store_register,
),
inst,
);
src/link/MachO.zig
@@ -1256,7 +1256,7 @@ pub fn updateDecl(self: *MachO, module: *Module, decl: *Module.Decl) !void {
const inst = code_buffer.items[fixup.offset..][0..4];
var parsed = mem.bytesAsValue(meta.TagPayload(
aarch64.Instruction,
- aarch64.Instruction.PCRelativeAddress,
+ aarch64.Instruction.pc_relative_address,
), inst);
const this_page = @intCast(i32, this_addr >> 12);
const target_page = @intCast(i32, target_addr >> 12);
@@ -1268,7 +1268,7 @@ pub fn updateDecl(self: *MachO, module: *Module, decl: *Module.Decl) !void {
const inst = code_buffer.items[fixup.offset + 4 ..][0..4];
var parsed = mem.bytesAsValue(meta.TagPayload(
aarch64.Instruction,
- aarch64.Instruction.LoadStoreRegister,
+ aarch64.Instruction.load_store_register,
), inst);
const narrowed = @truncate(u12, target_addr);
const offset = try math.divExact(u12, narrowed, 8);