Skip to content

Commit 0534f66

Browse files
stage2 ARM: start adding more instructions, return values, parameters
1 parent c8cd614 commit 0534f66

File tree

2 files changed

+300
-55
lines changed

2 files changed

+300
-55
lines changed

src-self-hosted/codegen.zig

Lines changed: 110 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1460,7 +1460,35 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
14601460
}
14611461
},
14621462
.arm => {
1463-
if (info.args.len > 0) return self.fail(inst.base.src, "TODO implement fn args for {}", .{self.target.cpu.arch});
1463+
for (info.args) |mc_arg, arg_i| {
1464+
const arg = inst.args[arg_i];
1465+
const arg_mcv = try self.resolveInst(inst.args[arg_i]);
1466+
1467+
switch (mc_arg) {
1468+
.none => continue,
1469+
.undef => unreachable,
1470+
.immediate => unreachable,
1471+
.unreach => unreachable,
1472+
.dead => unreachable,
1473+
.embedded_in_code => unreachable,
1474+
.memory => unreachable,
1475+
.compare_flags_signed => unreachable,
1476+
.compare_flags_unsigned => unreachable,
1477+
.register => |reg| {
1478+
try self.genSetReg(arg.src, reg, arg_mcv);
1479+
// TODO interact with the register allocator to mark the instruction as moved.
1480+
},
1481+
.stack_offset => {
1482+
return self.fail(inst.base.src, "TODO implement calling with parameters in memory", .{});
1483+
},
1484+
.ptr_stack_offset => {
1485+
return self.fail(inst.base.src, "TODO implement calling with MCValue.ptr_stack_offset arg", .{});
1486+
},
1487+
.ptr_embedded_in_code => {
1488+
return self.fail(inst.base.src, "TODO implement calling with MCValue.ptr_embedded_in_code arg", .{});
1489+
},
1490+
}
1491+
}
14641492

14651493
if (inst.func.cast(ir.Inst.Constant)) |func_inst| {
14661494
if (func_inst.val.cast(Value.Payload.Function)) |func_val| {
@@ -1481,7 +1509,13 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
14811509
// of course. Add pushing lr to stack
14821510
// and popping after call
14831511
try self.genSetReg(inst.base.src, .lr, .{ .memory = got_addr });
1484-
mem.writeIntLittle(u32, try self.code.addManyAsArray(4), Instruction.blx(.al, .lr).toU32());
1512+
1513+
if (Target.arm.featureSetHas(self.target.cpu.features, .has_v5t)) {
1514+
mem.writeIntLittle(u32, try self.code.addManyAsArray(4), Instruction.blx(.al, .lr).toU32());
1515+
} else {
1516+
mem.writeIntLittle(u32, try self.code.addManyAsArray(4), Instruction.mov(.al, .lr, Instruction.Operand.reg(.pc, Instruction.Operand.Shift.none)).toU32());
1517+
mem.writeIntLittle(u32, try self.code.addManyAsArray(4), Instruction.bx(.al, .lr).toU32());
1518+
}
14851519
} else {
14861520
return self.fail(inst.base.src, "TODO implement calling bitcasted functions", .{});
14871521
}
@@ -2212,14 +2246,14 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
22122246
// least amount of necessary instructions (use
22132247
// more intelligent rotating)
22142248
if (x <= math.maxInt(u8)) {
2215-
mem.writeIntLittle(u32, try self.code.addManyAsArray(4), Instruction.mov(.al, 0, reg, Instruction.Operand.imm(@truncate(u8, x), 0)).toU32());
2249+
mem.writeIntLittle(u32, try self.code.addManyAsArray(4), Instruction.mov(.al, reg, Instruction.Operand.imm(@truncate(u8, x), 0)).toU32());
22162250
return;
22172251
} else if (x <= math.maxInt(u16)) {
22182252
// TODO Use movw Note: Not supported on
22192253
// all ARM targets!
22202254

2221-
mem.writeIntLittle(u32, try self.code.addManyAsArray(4), Instruction.mov(.al, 0, reg, Instruction.Operand.imm(@truncate(u8, x), 0)).toU32());
2222-
mem.writeIntLittle(u32, try self.code.addManyAsArray(4), Instruction.orr(.al, 0, reg, reg, Instruction.Operand.imm(@truncate(u8, x >> 8), 12)).toU32());
2255+
mem.writeIntLittle(u32, try self.code.addManyAsArray(4), Instruction.mov(.al, reg, Instruction.Operand.imm(@truncate(u8, x), 0)).toU32());
2256+
mem.writeIntLittle(u32, try self.code.addManyAsArray(4), Instruction.orr(.al, reg, reg, Instruction.Operand.imm(@truncate(u8, x >> 8), 12)).toU32());
22232257
} else if (x <= math.maxInt(u32)) {
22242258
// TODO Use movw and movt Note: Not
22252259
// supported on all ARM targets! Also TODO
@@ -2231,15 +2265,23 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
22312265
// orr reg, reg, #0xbb, 24
22322266
// orr reg, reg, #0xcc, 16
22332267
// orr reg, reg, #0xdd, 8
2234-
mem.writeIntLittle(u32, try self.code.addManyAsArray(4), Instruction.mov(.al, 0, reg, Instruction.Operand.imm(@truncate(u8, x), 0)).toU32());
2235-
mem.writeIntLittle(u32, try self.code.addManyAsArray(4), Instruction.orr(.al, 0, reg, reg, Instruction.Operand.imm(@truncate(u8, x >> 8), 12)).toU32());
2236-
mem.writeIntLittle(u32, try self.code.addManyAsArray(4), Instruction.orr(.al, 0, reg, reg, Instruction.Operand.imm(@truncate(u8, x >> 16), 8)).toU32());
2237-
mem.writeIntLittle(u32, try self.code.addManyAsArray(4), Instruction.orr(.al, 0, reg, reg, Instruction.Operand.imm(@truncate(u8, x >> 24), 4)).toU32());
2268+
mem.writeIntLittle(u32, try self.code.addManyAsArray(4), Instruction.mov(.al, reg, Instruction.Operand.imm(@truncate(u8, x), 0)).toU32());
2269+
mem.writeIntLittle(u32, try self.code.addManyAsArray(4), Instruction.orr(.al, reg, reg, Instruction.Operand.imm(@truncate(u8, x >> 8), 12)).toU32());
2270+
mem.writeIntLittle(u32, try self.code.addManyAsArray(4), Instruction.orr(.al, reg, reg, Instruction.Operand.imm(@truncate(u8, x >> 16), 8)).toU32());
2271+
mem.writeIntLittle(u32, try self.code.addManyAsArray(4), Instruction.orr(.al, reg, reg, Instruction.Operand.imm(@truncate(u8, x >> 24), 4)).toU32());
22382272
return;
22392273
} else {
22402274
return self.fail(src, "ARM registers are 32-bit wide", .{});
22412275
}
22422276
},
2277+
.register => |src_reg| {
2278+
// If the registers are the same, nothing to do.
2279+
if (src_reg.id() == reg.id())
2280+
return;
2281+
2282+
// mov reg, src_reg
2283+
mem.writeIntLittle(u32, try self.code.addManyAsArray(4), Instruction.mov(.al, reg, Instruction.Operand.reg(src_reg, Instruction.Operand.Shift.none)).toU32());
2284+
},
22432285
.memory => |addr| {
22442286
// The value is in memory at a hard-coded address.
22452287
// If the type is a pointer, it means the pointer address is at this memory location.
@@ -2700,6 +2742,53 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
27002742
else => return self.fail(src, "TODO implement function parameters for {} on x86_64", .{cc}),
27012743
}
27022744
},
2745+
.arm => {
2746+
switch (cc) {
2747+
.Naked => {
2748+
assert(result.args.len == 0);
2749+
result.return_value = .{ .unreach = {} };
2750+
result.stack_byte_count = 0;
2751+
result.stack_align = 1;
2752+
return result;
2753+
},
2754+
.Unspecified, .C => {
2755+
// ARM Procedure Call Standard, Chapter 6.5
2756+
var ncrn: usize = 0; // Next Core Register Number
2757+
var nsaa: u32 = 0; // Next stacked argument address
2758+
2759+
for (param_types) |ty, i| {
2760+
if (ty.abiAlignment(self.target.*) == 8) {
2761+
// Round up NCRN to the next even number
2762+
ncrn += ncrn % 2;
2763+
}
2764+
2765+
const param_size = @intCast(u32, ty.abiSize(self.target.*));
2766+
if (std.math.divCeil(u32, param_size, 4) catch unreachable <= 4 - ncrn) {
2767+
if (param_size <= 4) {
2768+
result.args[i] = .{ .register = c_abi_int_param_regs[ncrn] };
2769+
ncrn += 1;
2770+
} else {
2771+
return self.fail(src, "TODO MCValues with multiple registers", .{});
2772+
}
2773+
} else {
2774+
ncrn = 4;
2775+
if (ty.abiAlignment(self.target.*) == 8) {
2776+
if (nsaa % 8 != 0) {
2777+
nsaa += 8 - (nsaa % 8);
2778+
}
2779+
}
2780+
2781+
result.args[i] = .{ .stack_offset = nsaa };
2782+
nsaa += param_size;
2783+
}
2784+
}
2785+
2786+
result.stack_byte_count = nsaa;
2787+
result.stack_align = 4;
2788+
},
2789+
else => return self.fail(src, "TODO implement function parameters for {} on arm", .{cc}),
2790+
}
2791+
},
27032792
else => if (param_types.len != 0)
27042793
return self.fail(src, "TODO implement codegen parameters for {}", .{self.target.cpu.arch}),
27052794
}
@@ -2718,6 +2807,18 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
27182807
},
27192808
else => return self.fail(src, "TODO implement function return values for {}", .{cc}),
27202809
},
2810+
.arm => switch (cc) {
2811+
.Naked => unreachable,
2812+
.Unspecified, .C => {
2813+
const ret_ty_size = @intCast(u32, ret_ty.abiSize(self.target.*));
2814+
if (ret_ty_size <= 4) {
2815+
result.return_value = .{ .register = c_abi_int_return_regs[0] };
2816+
} else {
2817+
return self.fail(src, "TODO support more return types for ARM backend", .{});
2818+
}
2819+
},
2820+
else => return self.fail(src, "TODO implement function return values for {}", .{cc}),
2821+
},
27212822
else => return self.fail(src, "TODO implement codegen return values for {}", .{self.target.cpu.arch}),
27222823
}
27232824
return result;

0 commit comments

Comments
 (0)