authorgravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2022-01-01 17:02:31+01:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2022-01-01 17:02:31+01:00
log885d96735de0fb771403c06d258cac316b792de3
treee2dcea50fff56f8a2e3840a9e4c4914d071d01af
parent557268a4480d88411dd6f0278afb767320ca66f8
parenta722e1fc0bcbae55c6a143ece9f20db8a3212818
signaturebadge-question-mark Signed by PGP key 4AEE18F83AFDEB23

Merge pull request #10480 from joachimschmidt557/stage2-arm

stage2 ARM: zig test working

3 files changed, 162 insertions(+), 53 deletions(-)

src/arch/arm/CodeGen.zig+77-53
......@@ -1099,15 +1099,22 @@ fn airOptionalPayloadPtrSet(self: *Self, inst: Air.Inst.Index) !void {
10991099
11001100fn airUnwrapErrErr(self: *Self, inst: Air.Inst.Index) !void {
11011101 const ty_op = self.air.instructions.items(.data)[inst].ty_op;
1102 const result: MCValue = if (self.liveness.isUnused(inst)) .dead else return self.fail("TODO implement unwrap error union error for {}", .{self.target.cpu.arch});
1102 const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: {
1103 const error_union_ty = self.air.typeOf(ty_op.operand);
1104 const payload_ty = error_union_ty.errorUnionPayload();
1105 const mcv = try self.resolveInst(ty_op.operand);
1106 if (!payload_ty.hasCodeGenBits()) break :result mcv;
1107
1108 return self.fail("TODO implement unwrap error union error for non-empty payloads", .{});
1109 };
11031110 return self.finishAir(inst, result, .{ ty_op.operand, .none, .none });
11041111}
11051112
11061113fn airUnwrapErrPayload(self: *Self, inst: Air.Inst.Index) !void {
11071114 const ty_op = self.air.instructions.items(.data)[inst].ty_op;
11081115 const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: {
1109 const err_ty = self.air.typeOf(ty_op.operand);
1110 const payload_ty = err_ty.errorUnionPayload();
1116 const error_union_ty = self.air.typeOf(ty_op.operand);
1117 const payload_ty = error_union_ty.errorUnionPayload();
11111118 if (!payload_ty.hasCodeGenBits()) break :result MCValue.none;
11121119
11131120 return self.fail("TODO implement unwrap error union payload for non-empty payloads", .{});
......@@ -2238,10 +2245,16 @@ fn airFence(self: *Self) !void {
22382245
22392246fn airCall(self: *Self, inst: Air.Inst.Index) !void {
22402247 const pl_op = self.air.instructions.items(.data)[inst].pl_op;
2241 const fn_ty = self.air.typeOf(pl_op.operand);
22422248 const callee = pl_op.operand;
22432249 const extra = self.air.extraData(Air.Call, pl_op.payload);
22442250 const args = @bitCast([]const Air.Inst.Ref, self.air.extra[extra.end..][0..extra.data.args_len]);
2251 const ty = self.air.typeOf(callee);
2252
2253 const fn_ty = switch (ty.zigTypeTag()) {
2254 .Fn => ty,
2255 .Pointer => ty.childType(),
2256 else => unreachable,
2257 };
22452258
22462259 var info = try self.resolveCallingConventionValues(fn_ty);
22472260 defer info.deinit(self);
......@@ -2310,39 +2323,42 @@ fn airCall(self: *Self, inst: Air.Inst.Index) !void {
23102323 unreachable;
23112324
23122325 try self.genSetReg(Type.initTag(.usize), .lr, .{ .memory = got_addr });
2313
2314 // TODO: add Instruction.supportedOn
2315 // function for ARM
2316 if (Target.arm.featureSetHas(self.target.cpu.features, .has_v5t)) {
2317 _ = try self.addInst(.{
2318 .tag = .blx,
2319 .cond = .al,
2320 .data = .{ .reg = .lr },
2321 });
2322 } else {
2323 return self.fail("TODO fix blx emulatio for ARM <v5", .{});
2324 // _ = try self.addInst(.{
2325 // .tag = .mov,
2326 // .cond = .al,
2327 // .data = .{ .rr_op = .{
2328 // .rd = .lr,
2329 // .rn = .r0,
2330 // .op = Instruction.Operand.reg(.pc, Instruction.Operand.Shift.none),
2331 // } },
2332 // });
2333 // _ = try self.addInst(.{
2334 // .tag = .bx,
2335 // .cond = .al,
2336 // .data = .{ .reg = .lr },
2337 // });
2338 }
23392326 } else if (func_value.castTag(.extern_fn)) |_| {
23402327 return self.fail("TODO implement calling extern functions", .{});
23412328 } else {
23422329 return self.fail("TODO implement calling bitcasted functions", .{});
23432330 }
23442331 } else {
2345 return self.fail("TODO implement calling runtime known function pointer", .{});
2332 assert(ty.zigTypeTag() == .Pointer);
2333 const mcv = try self.resolveInst(callee);
2334
2335 try self.genSetReg(Type.initTag(.usize), .lr, mcv);
2336 }
2337
2338 // TODO: add Instruction.supportedOn
2339 // function for ARM
2340 if (Target.arm.featureSetHas(self.target.cpu.features, .has_v5t)) {
2341 _ = try self.addInst(.{
2342 .tag = .blx,
2343 .cond = .al,
2344 .data = .{ .reg = .lr },
2345 });
2346 } else {
2347 return self.fail("TODO fix blx emulation for ARM <v5", .{});
2348 // _ = try self.addInst(.{
2349 // .tag = .mov,
2350 // .cond = .al,
2351 // .data = .{ .rr_op = .{
2352 // .rd = .lr,
2353 // .rn = .r0,
2354 // .op = Instruction.Operand.reg(.pc, Instruction.Operand.Shift.none),
2355 // } },
2356 // });
2357 // _ = try self.addInst(.{
2358 // .tag = .bx,
2359 // .cond = .al,
2360 // .data = .{ .reg = .lr },
2361 // });
23462362 }
23472363 } else if (self.bin_file.cast(link.File.MachO)) |_| {
23482364 unreachable; // unsupported architecture for MachO
......@@ -2402,19 +2418,26 @@ fn airRetLoad(self: *Self, inst: Air.Inst.Index) !void {
24022418
24032419fn airCmp(self: *Self, inst: Air.Inst.Index, op: math.CompareOperator) !void {
24042420 const bin_op = self.air.instructions.items(.data)[inst].bin_op;
2405 if (self.liveness.isUnused(inst))
2406 return self.finishAir(inst, .dead, .{ bin_op.lhs, bin_op.rhs, .none });
2407 const ty = self.air.typeOf(bin_op.lhs);
2408 assert(ty.eql(self.air.typeOf(bin_op.rhs)));
2409 if (ty.zigTypeTag() == .ErrorSet)
2410 return self.fail("TODO implement cmp for errors", .{});
2421 const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: {
2422 const lhs = try self.resolveInst(bin_op.lhs);
2423 const rhs = try self.resolveInst(bin_op.rhs);
2424 const lhs_ty = self.air.typeOf(bin_op.lhs);
24112425
2412 try self.spillCompareFlagsIfOccupied();
2413 self.compare_flags_inst = inst;
2426 if (lhs_ty.abiSize(self.target.*) > 4) {
2427 return self.fail("TODO cmp for types with size > 4", .{});
2428 }
2429
2430 const signedness: std.builtin.Signedness = blk: {
2431 // by default we tell the operand type is unsigned (i.e. bools and enum values)
2432 if (lhs_ty.zigTypeTag() != .Int) break :blk .unsigned;
2433
2434 // incase of an actual integer, we emit the correct signedness
2435 break :blk lhs_ty.intInfo(self.target.*).signedness;
2436 };
2437
2438 try self.spillCompareFlagsIfOccupied();
2439 self.compare_flags_inst = inst;
24142440
2415 const lhs = try self.resolveInst(bin_op.lhs);
2416 const rhs = try self.resolveInst(bin_op.rhs);
2417 const result: MCValue = result: {
24182441 const lhs_is_register = lhs == .register;
24192442 const rhs_is_register = rhs == .register;
24202443 // lhs should always be a register
......@@ -2448,11 +2471,11 @@ fn airCmp(self: *Self, inst: Air.Inst.Index, op: math.CompareOperator) !void {
24482471 // Move the operands to the newly allocated registers
24492472 const branch = &self.branch_stack.items[self.branch_stack.items.len - 1];
24502473 if (lhs_mcv == .register and !lhs_is_register) {
2451 try self.genSetReg(ty, lhs_mcv.register, lhs);
2474 try self.genSetReg(lhs_ty, lhs_mcv.register, lhs);
24522475 branch.inst_table.putAssumeCapacity(Air.refToIndex(bin_op.lhs).?, lhs);
24532476 }
24542477 if (rhs_mcv == .register and !rhs_is_register) {
2455 try self.genSetReg(ty, rhs_mcv.register, rhs);
2478 try self.genSetReg(lhs_ty, rhs_mcv.register, rhs);
24562479 branch.inst_table.putAssumeCapacity(Air.refToIndex(bin_op.rhs).?, rhs);
24572480 }
24582481
......@@ -2460,9 +2483,9 @@ fn airCmp(self: *Self, inst: Air.Inst.Index, op: math.CompareOperator) !void {
24602483 // The signedness of the integer does not matter for the cmp instruction
24612484 try self.genArmBinOpCode(undefined, lhs_mcv, rhs_mcv, false, .cmp_eq, undefined);
24622485
2463 break :result switch (ty.isSignedInt()) {
2464 true => MCValue{ .compare_flags_signed = op },
2465 false => MCValue{ .compare_flags_unsigned = op },
2486 break :result switch (signedness) {
2487 .signed => MCValue{ .compare_flags_signed = op },
2488 .unsigned => MCValue{ .compare_flags_unsigned = op },
24662489 };
24672490 };
24682491 return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none });
......@@ -3157,17 +3180,18 @@ fn genSetStack(self: *Self, ty: Type, stack_offset: u32, mcv: MCValue) InnerErro
31573180 // TODO optimize the register allocation
31583181 const regs = try self.register_manager.allocRegs(5, .{ null, null, null, null, null }, &.{});
31593182 const src_reg = regs[0];
3160 const dst_reg = regs[2];
3183 const dst_reg = regs[1];
31613184 const len_reg = regs[2];
31623185 const count_reg = regs[3];
31633186 const tmp_reg = regs[4];
31643187
3165 // add src_reg, fp, #off
3166 const src_offset_op: Instruction.Operand = if (Instruction.Operand.fromU32(off)) |x| x else {
3188 // sub src_reg, fp, #off
3189 const adj_src_offset = off + @intCast(u32, ty.abiSize(self.target.*));
3190 const src_offset_op: Instruction.Operand = if (Instruction.Operand.fromU32(adj_src_offset)) |x| x else {
31673191 return self.fail("TODO load: set reg to stack offset with all possible offsets", .{});
31683192 };
31693193 _ = try self.addInst(.{
3170 .tag = .add,
3194 .tag = .sub,
31713195 .cond = .al,
31723196 .data = .{ .rr_op = .{
31733197 .rd = src_reg,
......@@ -3177,8 +3201,8 @@ fn genSetStack(self: *Self, ty: Type, stack_offset: u32, mcv: MCValue) InnerErro
31773201 });
31783202
31793203 // sub dst_reg, fp, #stack_offset
3180 const adj_stack_offset = stack_offset + @intCast(u32, ty.abiSize(self.target.*));
3181 const dst_offset_op: Instruction.Operand = if (Instruction.Operand.fromU32(adj_stack_offset)) |x| x else {
3204 const adj_dst_offset = stack_offset + @intCast(u32, ty.abiSize(self.target.*));
3205 const dst_offset_op: Instruction.Operand = if (Instruction.Operand.fromU32(adj_dst_offset)) |x| x else {
31823206 return self.fail("TODO load: set reg to stack offset with all possible offsets", .{});
31833207 };
31843208 _ = try self.addInst(.{
src/codegen.zig+8
......@@ -400,6 +400,14 @@ pub fn generateSymbol(
400400
401401 return Result{ .appended = {} };
402402 },
403 .Optional => {
404 // TODO generateSymbol for optionals
405 const target = bin_file.options.target;
406 const abi_size = try math.cast(usize, typed_value.ty.abiSize(target));
407 try code.writer().writeByteNTimes(0xaa, abi_size);
408
409 return Result{ .appended = {} };
410 },
403411 else => |t| {
404412 return Result{
405413 .fail = try ErrorMsg.create(
test/stage2/arm.zig+77
......@@ -636,6 +636,35 @@ pub fn addCases(ctx: *TestContext) !void {
636636 ,
637637 "Hello, World!\n",
638638 );
639
640 case.addCompareOutput(
641 \\pub fn main() void {
642 \\ foo() catch |err| {
643 \\ assert(err == error.Foo);
644 \\ assert(err != error.Bar);
645 \\ assert(err != error.Baz);
646 \\ };
647 \\ bar() catch |err| {
648 \\ assert(err != error.Foo);
649 \\ assert(err == error.Bar);
650 \\ assert(err != error.Baz);
651 \\ };
652 \\}
653 \\
654 \\fn assert(ok: bool) void {
655 \\ if (!ok) unreachable;
656 \\}
657 \\
658 \\fn foo() anyerror!void {
659 \\ return error.Foo;
660 \\}
661 \\
662 \\fn bar() anyerror!void {
663 \\ return error.Bar;
664 \\}
665 ,
666 "",
667 );
639668 }
640669
641670 {
......@@ -704,4 +733,52 @@ pub fn addCases(ctx: *TestContext) !void {
704733 "",
705734 );
706735 }
736
737 {
738 var case = ctx.exe("function pointers", linux_arm);
739 case.addCompareOutput(
740 \\const PrintFn = fn () void;
741 \\
742 \\pub fn main() void {
743 \\ var printFn: PrintFn = stopSayingThat;
744 \\ var i: u32 = 0;
745 \\ while (i < 4) : (i += 1) printFn();
746 \\
747 \\ printFn = moveEveryZig;
748 \\ printFn();
749 \\}
750 \\
751 \\fn stopSayingThat() void {
752 \\ asm volatile ("svc #0"
753 \\ :
754 \\ : [number] "{r7}" (4),
755 \\ [arg1] "{r0}" (1),
756 \\ [arg2] "{r1}" (@ptrToInt("Hello, my name is Inigo Montoya; you killed my father, prepare to die.\n")),
757 \\ [arg3] "{r2}" ("Hello, my name is Inigo Montoya; you killed my father, prepare to die.\n".len),
758 \\ : "memory"
759 \\ );
760 \\ return;
761 \\}
762 \\
763 \\fn moveEveryZig() void {
764 \\ asm volatile ("svc #0"
765 \\ :
766 \\ : [number] "{r7}" (4),
767 \\ [arg1] "{r0}" (1),
768 \\ [arg2] "{r1}" (@ptrToInt("All your codebase are belong to us\n")),
769 \\ [arg3] "{r2}" ("All your codebase are belong to us\n".len),
770 \\ : "memory"
771 \\ );
772 \\ return;
773 \\}
774 ,
775 \\Hello, my name is Inigo Montoya; you killed my father, prepare to die.
776 \\Hello, my name is Inigo Montoya; you killed my father, prepare to die.
777 \\Hello, my name is Inigo Montoya; you killed my father, prepare to die.
778 \\Hello, my name is Inigo Montoya; you killed my father, prepare to die.
779 \\All your codebase are belong to us
780 \\
781 ,
782 );
783 }
707784}