mirror of
https://github.com/ziglang/zig.git
synced 2026-02-02 12:43:40 +00:00
stage2 ARM: add extra load/store instructions
This commit is contained in:
parent
fbd5fbe729
commit
d2a297c2b3
@ -2630,21 +2630,34 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
|
||||
.register => |reg| {
|
||||
const abi_size = ty.abiSize(self.target.*);
|
||||
const adj_off = stack_offset + abi_size;
|
||||
const offset = if (adj_off <= math.maxInt(u12)) blk: {
|
||||
break :blk Instruction.Offset.imm(@intCast(u12, adj_off));
|
||||
} else Instruction.Offset.reg(try self.copyToTmpRegister(src, MCValue{ .immediate = adj_off }), 0);
|
||||
|
||||
switch (abi_size) {
|
||||
1 => writeInt(u32, try self.code.addManyAsArray(4), Instruction.strb(.al, reg, .fp, .{
|
||||
.offset = offset,
|
||||
.positive = false,
|
||||
}).toU32()),
|
||||
2 => return self.fail(src, "TODO implement strh", .{}),
|
||||
4 => writeInt(u32, try self.code.addManyAsArray(4), Instruction.str(.al, reg, .fp, .{
|
||||
.offset = offset,
|
||||
.positive = false,
|
||||
}).toU32()),
|
||||
else => return self.fail(src, "TODO a type of size {} is not allowed in a register", .{abi_size}),
|
||||
1, 4 => {
|
||||
const offset = if (adj_off <= math.maxInt(u12)) blk: {
|
||||
break :blk Instruction.Offset.imm(@intCast(u12, adj_off));
|
||||
} else Instruction.Offset.reg(try self.copyToTmpRegister(src, MCValue{ .immediate = adj_off }), 0);
|
||||
const str = switch (abi_size) {
|
||||
1 => Instruction.strb,
|
||||
4 => Instruction.str,
|
||||
else => unreachable,
|
||||
};
|
||||
|
||||
writeInt(u32, try self.code.addManyAsArray(4), str(.al, reg, .fp, .{
|
||||
.offset = offset,
|
||||
.positive = false,
|
||||
}).toU32());
|
||||
},
|
||||
2 => {
|
||||
const offset = if (adj_off <= math.maxInt(u8)) blk: {
|
||||
break :blk Instruction.ExtraLoadStoreOffset.imm(@intCast(u8, adj_off));
|
||||
} else Instruction.ExtraLoadStoreOffset.reg(try self.copyToTmpRegister(src, MCValue{ .immediate = adj_off }));
|
||||
|
||||
writeInt(u32, try self.code.addManyAsArray(4), Instruction.strh(.al, reg, .fp, .{
|
||||
.offset = offset,
|
||||
.positive = false,
|
||||
}).toU32());
|
||||
},
|
||||
else => return self.fail(src, "TODO implement storing other types abi_size={}", .{abi_size}),
|
||||
}
|
||||
},
|
||||
.memory => |vaddr| {
|
||||
@ -2836,20 +2849,33 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
|
||||
// const abi_size = ty.abiSize(self.target.*);
|
||||
const abi_size = 4;
|
||||
const adj_off = unadjusted_off + abi_size;
|
||||
const offset = if (adj_off <= math.maxInt(u12)) blk: {
|
||||
break :blk Instruction.Offset.imm(@intCast(u12, adj_off));
|
||||
} else Instruction.Offset.reg(try self.copyToTmpRegister(src, MCValue{ .immediate = adj_off }), 0);
|
||||
|
||||
switch (abi_size) {
|
||||
1 => writeInt(u32, try self.code.addManyAsArray(4), Instruction.ldrb(.al, reg, .fp, .{
|
||||
.offset = offset,
|
||||
.positive = false,
|
||||
}).toU32()),
|
||||
2 => return self.fail(src, "TODO implement ldrh", .{}),
|
||||
4 => writeInt(u32, try self.code.addManyAsArray(4), Instruction.ldr(.al, reg, .fp, .{
|
||||
.offset = offset,
|
||||
.positive = false,
|
||||
}).toU32()),
|
||||
1, 4 => {
|
||||
const offset = if (adj_off <= math.maxInt(u12)) blk: {
|
||||
break :blk Instruction.Offset.imm(@intCast(u12, adj_off));
|
||||
} else Instruction.Offset.reg(try self.copyToTmpRegister(src, MCValue{ .immediate = adj_off }), 0);
|
||||
const ldr = switch (abi_size) {
|
||||
1 => Instruction.ldrb,
|
||||
4 => Instruction.ldr,
|
||||
else => unreachable,
|
||||
};
|
||||
|
||||
writeInt(u32, try self.code.addManyAsArray(4), ldr(.al, reg, .fp, .{
|
||||
.offset = offset,
|
||||
.positive = false,
|
||||
}).toU32());
|
||||
},
|
||||
2 => {
|
||||
const offset = if (adj_off <= math.maxInt(u8)) blk: {
|
||||
break :blk Instruction.ExtraLoadStoreOffset.imm(@intCast(u8, adj_off));
|
||||
} else Instruction.ExtraLoadStoreOffset.reg(try self.copyToTmpRegister(src, MCValue{ .immediate = adj_off }));
|
||||
|
||||
writeInt(u32, try self.code.addManyAsArray(4), Instruction.ldrh(.al, reg, .fp, .{
|
||||
.offset = offset,
|
||||
.positive = false,
|
||||
}).toU32());
|
||||
},
|
||||
else => return self.fail(src, "TODO a type of size {} is not allowed in a register", .{abi_size}),
|
||||
}
|
||||
},
|
||||
|
||||
@ -240,6 +240,22 @@ pub const Instruction = union(enum) {
|
||||
fixed: u2 = 0b01,
|
||||
cond: u4,
|
||||
},
|
||||
ExtraLoadStore: packed struct {
|
||||
imm4l: u4,
|
||||
fixed_1: u1 = 0b1,
|
||||
op2: u2,
|
||||
fixed_2: u1 = 0b1,
|
||||
imm4h: u4,
|
||||
rt: u4,
|
||||
rn: u4,
|
||||
o1: u1,
|
||||
write_back: u1,
|
||||
imm: u1,
|
||||
up_down: u1,
|
||||
pre_index: u1,
|
||||
fixed_3: u3 = 0b000,
|
||||
cond: u4,
|
||||
},
|
||||
BlockDataTransfer: packed struct {
|
||||
register_list: u16,
|
||||
rn: u4,
|
||||
@ -468,6 +484,29 @@ pub const Instruction = union(enum) {
|
||||
}
|
||||
};
|
||||
|
||||
/// Represents the offset operand of an extra load or store
|
||||
/// instruction.
|
||||
pub const ExtraLoadStoreOffset = union(enum) {
|
||||
immediate: u8,
|
||||
register: u4,
|
||||
|
||||
pub const none = ExtraLoadStoreOffset{
|
||||
.immediate = 0,
|
||||
};
|
||||
|
||||
pub fn reg(register: Register) ExtraLoadStoreOffset {
|
||||
return ExtraLoadStoreOffset{
|
||||
.register = register.id(),
|
||||
};
|
||||
}
|
||||
|
||||
pub fn imm(immediate: u8) ExtraLoadStoreOffset {
|
||||
return ExtraLoadStoreOffset{
|
||||
.immediate = immediate,
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
/// Represents the register list operand to a block data transfer
|
||||
/// instruction
|
||||
pub const RegisterList = packed struct {
|
||||
@ -495,6 +534,7 @@ pub const Instruction = union(enum) {
|
||||
.Multiply => |v| @bitCast(u32, v),
|
||||
.MultiplyLong => |v| @bitCast(u32, v),
|
||||
.SingleDataTransfer => |v| @bitCast(u32, v),
|
||||
.ExtraLoadStore => |v| @bitCast(u32, v),
|
||||
.BlockDataTransfer => |v| @bitCast(u32, v),
|
||||
.Branch => |v| @bitCast(u32, v),
|
||||
.BranchExchange => |v| @bitCast(u32, v),
|
||||
@ -617,6 +657,43 @@ pub const Instruction = union(enum) {
|
||||
};
|
||||
}
|
||||
|
||||
fn extraLoadStore(
|
||||
cond: Condition,
|
||||
pre_index: bool,
|
||||
positive: bool,
|
||||
write_back: bool,
|
||||
o1: u1,
|
||||
op2: u2,
|
||||
rn: Register,
|
||||
rt: Register,
|
||||
offset: ExtraLoadStoreOffset,
|
||||
) Instruction {
|
||||
const imm4l: u4 = switch (offset) {
|
||||
.immediate => |imm| @truncate(u4, imm),
|
||||
.register => |reg| reg,
|
||||
};
|
||||
const imm4h: u4 = switch (offset) {
|
||||
.immediate => |imm| @truncate(u4, imm >> 4),
|
||||
.register => |reg| 0b0000,
|
||||
};
|
||||
|
||||
return Instruction{
|
||||
.ExtraLoadStore = .{
|
||||
.imm4l = imm4l,
|
||||
.op2 = op2,
|
||||
.imm4h = imm4h,
|
||||
.rt = rt.id(),
|
||||
.rn = rn.id(),
|
||||
.o1 = o1,
|
||||
.write_back = @boolToInt(write_back),
|
||||
.imm = @boolToInt(offset == .immediate),
|
||||
.up_down = @boolToInt(positive),
|
||||
.pre_index = @boolToInt(pre_index),
|
||||
.cond = @enumToInt(cond),
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
fn blockDataTransfer(
|
||||
cond: Condition,
|
||||
rn: Register,
|
||||
@ -913,6 +990,23 @@ pub const Instruction = union(enum) {
|
||||
return singleDataTransfer(cond, rd, rn, args.offset, args.pre_index, args.positive, 1, args.write_back, 0);
|
||||
}
|
||||
|
||||
// Extra load/store
|
||||
|
||||
pub const ExtraLoadStoreOffsetArgs = struct {
|
||||
pre_index: bool = true,
|
||||
positive: bool = true,
|
||||
offset: ExtraLoadStoreOffset,
|
||||
write_back: bool = false,
|
||||
};
|
||||
|
||||
pub fn strh(cond: Condition, rt: Register, rn: Register, args: ExtraLoadStoreOffsetArgs) Instruction {
|
||||
return extraLoadStore(cond, args.pre_index, args.positive, args.write_back, 0, 0b01, rn, rt, args.offset);
|
||||
}
|
||||
|
||||
pub fn ldrh(cond: Condition, rt: Register, rn: Register, args: ExtraLoadStoreOffsetArgs) Instruction {
|
||||
return extraLoadStore(cond, args.pre_index, args.positive, args.write_back, 1, 0b01, rn, rt, args.offset);
|
||||
}
|
||||
|
||||
// Block data transfer
|
||||
|
||||
pub fn ldmda(cond: Condition, rn: Register, write_back: bool, reg_list: RegisterList) Instruction {
|
||||
@ -1093,6 +1187,12 @@ test "serialize instructions" {
|
||||
}),
|
||||
.expected = 0b1110_01_0_1_1_0_0_0_0011_0000_000000000000,
|
||||
},
|
||||
.{ // strh r1, [r5]
|
||||
.inst = Instruction.strh(.al, .r1, .r5, .{
|
||||
.offset = Instruction.ExtraLoadStoreOffset.none,
|
||||
}),
|
||||
.expected = 0b1110_000_1_1_1_0_0_0101_0001_0000_1011_0000,
|
||||
},
|
||||
.{ // b #12
|
||||
.inst = Instruction.b(.al, 12),
|
||||
.expected = 0b1110_101_0_0000_0000_0000_0000_0000_0011,
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user