Skip to content

Commit 960c142

Browse files
joachimschmidt557kubkon
authored andcommitted
stage2 ARM: implement basic intCast and error union wrapping
1 parent 76b28ed commit 960c142

31 files changed

+53
-113
lines changed

src/arch/arm/CodeGen.zig

Lines changed: 53 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1002,18 +1002,35 @@ fn airIntCast(self: *Self, inst: Air.Inst.Index) !void {
10021002
if (self.liveness.isUnused(inst))
10031003
return self.finishAir(inst, .dead, .{ ty_op.operand, .none, .none });
10041004

1005-
const operand_ty = self.air.typeOf(ty_op.operand);
10061005
const operand = try self.resolveInst(ty_op.operand);
1006+
const operand_ty = self.air.typeOf(ty_op.operand);
1007+
const dest_ty = self.air.typeOfIndex(inst);
1008+
1009+
const operand_abi_size = operand_ty.abiSize(self.target.*);
1010+
const dest_abi_size = dest_ty.abiSize(self.target.*);
10071011
const info_a = operand_ty.intInfo(self.target.*);
1008-
const info_b = self.air.typeOfIndex(inst).intInfo(self.target.*);
1009-
if (info_a.signedness != info_b.signedness)
1010-
return self.fail("TODO gen intcast sign safety in semantic analysis", .{});
1012+
const info_b = dest_ty.intInfo(self.target.*);
1013+
1014+
const dst_mcv: MCValue = blk: {
1015+
if (info_a.bits == info_b.bits) {
1016+
break :blk operand;
1017+
}
1018+
if (operand_abi_size > 4 or dest_abi_size > 4) {
1019+
return self.fail("TODO implement intCast for abi sizes larger than 4", .{});
1020+
}
1021+
1022+
const operand_lock: ?RegisterLock = switch (operand) {
1023+
.register => |reg| self.register_manager.lockRegAssumeUnused(reg),
1024+
else => null,
1025+
};
1026+
defer if (operand_lock) |lock| self.register_manager.unlockReg(lock);
10111027

1012-
if (info_a.bits == info_b.bits)
1013-
return self.finishAir(inst, operand, .{ ty_op.operand, .none, .none });
1028+
const reg = try self.register_manager.allocReg(inst, gp);
1029+
try self.genSetReg(dest_ty, reg, operand);
1030+
break :blk MCValue{ .register = reg };
1031+
};
10141032

1015-
return self.fail("TODO implement intCast for {}", .{self.target.cpu.arch});
1016-
// return self.finishAir(inst, result, .{ ty_op.operand, .none, .none });
1033+
return self.finishAir(inst, dst_mcv, .{ ty_op.operand, .none, .none });
10171034
}
10181035

10191036
fn truncRegister(
@@ -1880,7 +1897,22 @@ fn airSetErrReturnTrace(self: *Self, inst: Air.Inst.Index) !void {
18801897
/// T to E!T
18811898
fn airWrapErrUnionPayload(self: *Self, inst: Air.Inst.Index) !void {
18821899
const ty_op = self.air.instructions.items(.data)[inst].ty_op;
1883-
const result: MCValue = if (self.liveness.isUnused(inst)) .dead else return self.fail("TODO implement wrap errunion payload for {}", .{self.target.cpu.arch});
1900+
const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: {
1901+
const error_union_ty = self.air.getRefType(ty_op.ty);
1902+
const payload_ty = error_union_ty.errorUnionPayload();
1903+
const operand = try self.resolveInst(ty_op.operand);
1904+
if (!payload_ty.hasRuntimeBitsIgnoreComptime()) break :result operand;
1905+
1906+
const abi_size = @intCast(u32, error_union_ty.abiSize(self.target.*));
1907+
const abi_align = error_union_ty.abiAlignment(self.target.*);
1908+
const stack_offset = @intCast(u32, try self.allocMem(inst, abi_size, abi_align));
1909+
const payload_off = errUnionPayloadOffset(payload_ty, self.target.*);
1910+
const err_off = errUnionErrorOffset(payload_ty, self.target.*);
1911+
try self.genSetStack(payload_ty, stack_offset - @intCast(u32, payload_off), operand);
1912+
try self.genSetStack(Type.anyerror, stack_offset - @intCast(u32, err_off), .{ .immediate = 0 });
1913+
1914+
break :result MCValue{ .stack_offset = stack_offset };
1915+
};
18841916
return self.finishAir(inst, result, .{ ty_op.operand, .none, .none });
18851917
}
18861918

@@ -1890,10 +1922,18 @@ fn airWrapErrUnionErr(self: *Self, inst: Air.Inst.Index) !void {
18901922
const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: {
18911923
const error_union_ty = self.air.getRefType(ty_op.ty);
18921924
const payload_ty = error_union_ty.errorUnionPayload();
1893-
const mcv = try self.resolveInst(ty_op.operand);
1894-
if (!payload_ty.hasRuntimeBits()) break :result mcv;
1925+
const operand = try self.resolveInst(ty_op.operand);
1926+
if (!payload_ty.hasRuntimeBitsIgnoreComptime()) break :result operand;
1927+
1928+
const abi_size = @intCast(u32, error_union_ty.abiSize(self.target.*));
1929+
const abi_align = error_union_ty.abiAlignment(self.target.*);
1930+
const stack_offset = @intCast(u32, try self.allocMem(inst, abi_size, abi_align));
1931+
const payload_off = errUnionPayloadOffset(payload_ty, self.target.*);
1932+
const err_off = errUnionErrorOffset(payload_ty, self.target.*);
1933+
try self.genSetStack(Type.anyerror, stack_offset - @intCast(u32, err_off), operand);
1934+
try self.genSetStack(payload_ty, stack_offset - @intCast(u32, payload_off), .undef);
18951935

1896-
return self.fail("TODO implement wrap errunion error for non-empty payloads", .{});
1936+
break :result MCValue{ .stack_offset = stack_offset };
18971937
};
18981938
return self.finishAir(inst, result, .{ ty_op.operand, .none, .none });
18991939
}
@@ -4273,7 +4313,7 @@ fn br(self: *Self, block: Air.Inst.Index, operand: Air.Inst.Ref) !void {
42734313
block_data.mcv = switch (operand_mcv) {
42744314
.none, .dead, .unreach => unreachable,
42754315
.register, .stack_offset, .memory => operand_mcv,
4276-
.immediate, .stack_argument_offset => blk: {
4316+
.immediate, .stack_argument_offset, .cpsr_flags => blk: {
42774317
const new_mcv = try self.allocRegOrMem(block, true);
42784318
try self.setRegOrMem(self.air.typeOfIndex(block), new_mcv, operand_mcv);
42794319
break :blk new_mcv;

test/behavior/align.zig

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,6 @@ var foo: u8 align(4) = 100;
88

99
test "global variable alignment" {
1010
if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
11-
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
1211

1312
comptime try expect(@typeInfo(@TypeOf(&foo)).Pointer.alignment == 4);
1413
comptime try expect(@TypeOf(&foo) == *align(4) u8);
@@ -223,7 +222,6 @@ fn testBytesAlign(b: u8) !void {
223222
test "@alignCast slices" {
224223
if (builtin.zig_backend == .stage2_c) return error.SkipZigTest;
225224
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
226-
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
227225

228226
var array align(4) = [_]u32{ 1, 1 };
229227
const slice = array[0..];

test/behavior/array.zig

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,6 @@ test "array init with mult" {
5959

6060
test "array literal with explicit type" {
6161
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
62-
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
6362

6463
const hex_mult: [4]u16 = .{ 4096, 256, 16, 1 };
6564

@@ -112,7 +111,6 @@ test "array with sentinels" {
112111
}
113112

114113
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
115-
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
116114

117115
const S = struct {
118116
fn doTheTest(is_ct: bool) !void {
@@ -162,7 +160,6 @@ test "nested arrays of strings" {
162160

163161
test "nested arrays of integers" {
164162
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
165-
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
166163
if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
167164

168165
const array_of_numbers = [_][2]u8{
@@ -190,7 +187,6 @@ fn plusOne(x: u32) u32 {
190187

191188
test "single-item pointer to array indexing and slicing" {
192189
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
193-
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
194190

195191
try testSingleItemPtrArrayIndexSlice();
196192
comptime try testSingleItemPtrArrayIndexSlice();
@@ -313,7 +309,6 @@ test "comptime evaluating function that takes array by value" {
313309

314310
test "runtime initialize array elem and then implicit cast to slice" {
315311
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
316-
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
317312

318313
var two: i32 = 2;
319314
const x: []const i32 = &[_]i32{two};
@@ -322,7 +317,6 @@ test "runtime initialize array elem and then implicit cast to slice" {
322317

323318
test "array literal as argument to function" {
324319
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
325-
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
326320

327321
const S = struct {
328322
fn entry(two: i32) !void {

test/behavior/basic.zig

Lines changed: 0 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -204,7 +204,6 @@ test "opaque types" {
204204
}
205205

206206
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
207-
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
208207

209208
try expect(*OpaqueA != *OpaqueB);
210209

@@ -365,7 +364,6 @@ fn testMemcpyMemset() !void {
365364
}
366365

367366
test "variable is allowed to be a pointer to an opaque type" {
368-
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
369367
if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
370368

371369
var x: i32 = 1234;
@@ -457,7 +455,6 @@ fn testArray2DConstDoublePtr(ptr: *const f32) !void {
457455

458456
test "double implicit cast in same expression" {
459457
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
460-
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
461458

462459
var x = @as(i32, @as(u16, nine()));
463460
try expect(x == 9);
@@ -616,8 +613,6 @@ test "self reference through fn ptr field" {
616613
}
617614

618615
test "global variable initialized to global variable array element" {
619-
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
620-
621616
try expect(global_ptr == &gdt[0]);
622617
}
623618
const GDTEntry = struct {
@@ -681,7 +676,6 @@ test "explicit cast optional pointers" {
681676
}
682677

683678
test "pointer comparison" {
684-
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
685679
if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
686680

687681
const a = @as([]const u8, "a");
@@ -787,7 +781,6 @@ test "pointer to thread local array" {
787781
threadlocal var buffer: [11]u8 = undefined;
788782

789783
test "auto created variables have correct alignment" {
790-
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
791784
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
792785

793786
const S = struct {
@@ -889,7 +882,6 @@ test "labeled block implicitly ends in a break" {
889882
test "catch in block has correct result location" {
890883
if (builtin.zig_backend == .stage2_c) return error.SkipZigTest;
891884
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
892-
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
893885

894886
const S = struct {
895887
fn open() error{A}!@This() {
@@ -920,7 +912,6 @@ test "labeled block with runtime branch forwards its result location type to bre
920912

921913
test "try in labeled block doesn't cast to wrong type" {
922914
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
923-
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
924915

925916
const S = struct {
926917
a: u32,

test/behavior/bitreverse.zig

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -157,7 +157,6 @@ test "bitReverse vectors u0" {
157157
if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest;
158158
if (builtin.zig_backend == .stage2_c) return error.SkipZigTest;
159159
if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
160-
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
161160

162161
comptime try vector0();
163162
try vector0();

test/behavior/bugs/1076.zig

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@ const expect = std.testing.expect;
55

66
test "comptime code should not modify constant data" {
77
if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
8-
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
98
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
109

1110
try testCastPtrOfArrayToSliceAndPtr();

test/behavior/bugs/11165.zig

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,6 @@
11
const builtin = @import("builtin");
22

33
test "bytes" {
4-
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
5-
64
const S = struct {
75
a: u32,
86
c: [5]u8,
@@ -23,8 +21,6 @@ test "bytes" {
2321
}
2422

2523
test "aggregate" {
26-
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
27-
2824
const S = struct {
2925
a: u32,
3026
c: [5]u8,

test/behavior/bugs/11213.zig

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@ const testing = std.testing;
44

55
test {
66
if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
7-
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
87

98
const g: error{Test}!void = error.Test;
109

test/behavior/bugs/3779.zig

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,6 @@ const ptr_tag_name: [*:0]const u8 = tag_name;
88
test "@tagName() returns a string literal" {
99
if (builtin.zig_backend == .stage1) return error.SkipZigTest; // stage1 gets the type wrong
1010
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
11-
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
1211

1312
try std.testing.expect(*const [13:0]u8 == @TypeOf(tag_name));
1413
try std.testing.expect(std.mem.eql(u8, "TestEnumValue", tag_name));
@@ -22,7 +21,6 @@ const ptr_error_name: [*:0]const u8 = error_name;
2221
test "@errorName() returns a string literal" {
2322
if (builtin.zig_backend == .stage1) return error.SkipZigTest; // stage1 gets the type wrong
2423
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
25-
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
2624

2725
try std.testing.expect(*const [13:0]u8 == @TypeOf(error_name));
2826
try std.testing.expect(std.mem.eql(u8, "TestErrorCode", error_name));
@@ -36,7 +34,6 @@ const ptr_type_name: [*:0]const u8 = type_name;
3634
test "@typeName() returns a string literal" {
3735
if (builtin.zig_backend == .stage1) return error.SkipZigTest; // stage1 gets the type wrong
3836
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
39-
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
4037

4138
try std.testing.expect(*const [type_name.len:0]u8 == @TypeOf(type_name));
4239
try std.testing.expect(std.mem.eql(u8, "behavior.bugs.3779.TestType", type_name));
@@ -49,7 +46,6 @@ const expected_contents = "hello zig\n";
4946

5047
test "@embedFile() returns a string literal" {
5148
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
52-
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
5349

5450
try std.testing.expect(*const [expected_contents.len:0]u8 == @TypeOf(actual_contents));
5551
try std.testing.expect(std.mem.eql(u8, expected_contents, actual_contents));
@@ -63,7 +59,6 @@ fn testFnForSrc() std.builtin.SourceLocation {
6359

6460
test "@src() returns a struct containing 0-terminated string slices" {
6561
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
66-
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
6762

6863
const src = testFnForSrc();
6964
try std.testing.expect([:0]const u8 == @TypeOf(src.file));

test/behavior/bugs/394.zig

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,6 @@ const expect = @import("std").testing.expect;
1111
const builtin = @import("builtin");
1212

1313
test "fixed" {
14-
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
1514
if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
1615
const x = S{
1716
.x = 3,

test/behavior/bugs/7187.zig

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,6 @@ const builtin = @import("builtin");
33
const expect = std.testing.expect;
44

55
test "miscompilation with bool return type" {
6-
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
7-
86
var x: usize = 1;
97
var y: bool = getFalse();
108
_ = y;

test/behavior/byteswap.zig

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -118,7 +118,6 @@ test "@byteSwap vectors u0" {
118118
if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest;
119119
if (builtin.zig_backend == .stage2_c) return error.SkipZigTest;
120120
if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
121-
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
122121

123122
comptime try vector0();
124123
try vector0();

test/behavior/byval_arg_var.zig

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@ var result: []const u8 = "wrong";
66
test "pass string literal byvalue to a generic var param" {
77
if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
88
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
9-
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
109

1110
start();
1211
blowUpStack(10);

0 commit comments

Comments
 (0)