Commit 35b228630c
Changed files (2)
src
codegen
src/codegen/arm.zig
@@ -446,7 +446,7 @@ pub const Instruction = union(enum) {
pre_post: u1,
up_down: u1,
psr_or_user: u1,
- write_back: u1,
+ write_back: bool,
load_store: u1,
) Instruction {
return Instruction{
@@ -454,7 +454,7 @@ pub const Instruction = union(enum) {
.register_list = @bitCast(u16, reg_list),
.rn = rn.id(),
.load_store = load_store,
- .write_back = write_back,
+ .write_back = if (write_back) 1 else 0,
.psr_or_user = psr_or_user,
.up_down = up_down,
.pre_post = pre_post,
@@ -644,14 +644,50 @@ pub const Instruction = union(enum) {
// Block data transfer
- pub fn ldm(cond: Condition, rn: Register, reg_list: RegisterList) Instruction {
- return blockDataTransfer(cond, rn, reg_list, 1, 0, 0, 0, 1);
+ pub fn ldmda(cond: Condition, rn: Register, write_back: bool, reg_list: RegisterList) Instruction {
+ return blockDataTransfer(cond, rn, reg_list, 0, 0, 0, write_back, 1);
}
- pub fn stm(cond: Condition, rn: Register, reg_list: RegisterList) Instruction {
- return blockDataTransfer(cond, rn, reg_list, 1, 0, 0, 0, 0);
+ pub fn ldmdb(cond: Condition, rn: Register, write_back: bool, reg_list: RegisterList) Instruction {
+ return blockDataTransfer(cond, rn, reg_list, 1, 0, 0, write_back, 1);
+ }
+
+ pub fn ldmib(cond: Condition, rn: Register, write_back: bool, reg_list: RegisterList) Instruction {
+ return blockDataTransfer(cond, rn, reg_list, 1, 1, 0, write_back, 1);
+ }
+
+ pub fn ldmia(cond: Condition, rn: Register, write_back: bool, reg_list: RegisterList) Instruction {
+ return blockDataTransfer(cond, rn, reg_list, 0, 1, 0, write_back, 1);
+ }
+
+ pub const ldmfa = ldmda;
+ pub const ldmea = ldmdb;
+ pub const ldmed = ldmib;
+ pub const ldmfd = ldmia;
+ pub const ldm = ldmia;
+
+ pub fn stmda(cond: Condition, rn: Register, write_back: bool, reg_list: RegisterList) Instruction {
+ return blockDataTransfer(cond, rn, reg_list, 0, 0, 0, write_back, 0);
}
+ pub fn stmdb(cond: Condition, rn: Register, write_back: bool, reg_list: RegisterList) Instruction {
+ return blockDataTransfer(cond, rn, reg_list, 1, 0, 0, write_back, 0);
+ }
+
+ pub fn stmib(cond: Condition, rn: Register, write_back: bool, reg_list: RegisterList) Instruction {
+ return blockDataTransfer(cond, rn, reg_list, 1, 1, 0, write_back, 0);
+ }
+
+ pub fn stmia(cond: Condition, rn: Register, write_back: bool, reg_list: RegisterList) Instruction {
+ return blockDataTransfer(cond, rn, reg_list, 0, 1, 0, write_back, 0);
+ }
+
+ pub const stmed = stmda;
+ pub const stmfd = stmdb;
+ pub const stmfa = stmib;
+ pub const stmea = stmia;
+ pub const stm = stmia;
+
// Branch
pub fn b(cond: Condition, offset: i24) Instruction {
@@ -738,10 +774,14 @@ test "serialize instructions" {
.inst = Instruction.bkpt(42),
.expected = 0b1110_0001_0010_000000000010_0111_1010,
},
- .{ // stmfd r9, {r0}
- .inst = Instruction.stm(.al, .r9, .{ .r0 = true }),
+ .{ // stmdb r9, {r0}
+ .inst = Instruction.stmdb(.al, .r9, false, .{ .r0 = true }),
.expected = 0b1110_100_1_0_0_0_0_1001_0000000000000001,
},
+ .{ // ldmea r4!, {r2, r5}
+ .inst = Instruction.ldmea(.al, .r4, true, .{ .r2 = true, .r5 = true }),
+ .expected = 0b1110_100_1_0_0_1_1_0100_0000000000100100,
+ },
};
for (testcases) |case| {
src/codegen.zig
@@ -570,6 +570,35 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
try self.dbgSetEpilogueBegin();
}
},
+ .arm => {
+ const cc = self.fn_type.fnCallingConvention();
+ if (cc != .Naked) {
+ // push {fp, lr}
+ // mov fp, sp
+ // sub sp, sp, #reloc
+ // mem.writeIntLittle(u32, try self.code.addManyAsArray(4), Instruction.mov(.al, .fp, Instruction.Operand.reg(.sp, Instruction.Operand.Shift.none)).toU32());
+ // const backpatch_reloc = try self.code.addManyAsArray(4);
+
+ try self.dbgSetPrologueEnd();
+
+ try self.genBody(self.mod_fn.analysis.success);
+
+ // Backpatch stack offset
+ // const stack_end = self.max_end_stack;
+ // const aligned_stack_end = mem.alignForward(stack_end, self.stack_align);
+ // mem.writeIntLittle(u32, backpatch_reloc, Instruction.sub(.al, .sp, .sp, Instruction.Operand.imm()));
+
+ try self.dbgSetEpilogueBegin();
+
+ // mov sp, fp
+ // pop {fp, pc}
+ mem.writeIntLittle(u32, try self.code.addManyAsArray(4), Instruction.mov(.al, .sp, Instruction.Operand.reg(.fp, Instruction.Operand.Shift.none)).toU32());
+ } else {
+ try self.dbgSetPrologueEnd();
+ try self.genBody(self.mod_fn.analysis.success);
+ try self.dbgSetEpilogueBegin();
+ }
+ },
else => {
try self.dbgSetPrologueEnd();
try self.genBody(self.mod_fn.analysis.success);
@@ -1504,13 +1533,10 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
else
unreachable;
- // TODO only works with leaf functions
- // at the moment, which works fine for
- // Hello World, but not for real code
- // of course. Add pushing lr to stack
- // and popping after call
try self.genSetReg(inst.base.src, .lr, .{ .memory = got_addr });
+ // TODO: add Instruction.supportedOn
+ // function for ARM
if (Target.arm.featureSetHas(self.target.cpu.features, .has_v5t)) {
mem.writeIntLittle(u32, try self.code.addManyAsArray(4), Instruction.blx(.al, .lr).toU32());
} else {
@@ -1636,6 +1662,9 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
},
.arm => {
mem.writeIntLittle(u32, try self.code.addManyAsArray(4), Instruction.bx(.al, .lr).toU32());
+ // // Just add space for an instruction, patch this later
+ // try self.code.resize(self.code.items.len + 4);
+ // try self.exitlude_jump_relocs.append(self.gpa, self.code.items.len - 4);
},
else => return self.fail(src, "TODO implement return for {}", .{self.target.cpu.arch}),
}
@@ -2771,6 +2800,8 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
} else {
return self.fail(src, "TODO MCValues with multiple registers", .{});
}
+ } else if (ncrn < 4 and nsaa == 0) {
+ return self.fail(src, "TODO MCValues split between registers and stack", .{});
} else {
ncrn = 4;
if (ty.abiAlignment(self.target.*) == 8) {