Commit 0a7801236c

Jakub Konka <kubkon@jakubkonka.com>
2022-02-07 15:29:14
stage2,arm: add lowering of unnamed consts
* implement `struct_field_ptr` when `MCValue == .stack_argument_offset` * enable simple `struct` test for ARM
1 parent 9acf06d
Changed files (2)
src
arch
test
behavior
src/arch/arm/CodeGen.zig
@@ -1643,7 +1643,8 @@ fn airStructFieldPtrIndex(self: *Self, inst: Air.Inst.Index, index: u8) !void {
 fn structFieldPtr(self: *Self, inst: Air.Inst.Index, operand: Air.Inst.Ref, index: u32) !MCValue {
     return if (self.liveness.isUnused(inst)) .dead else result: {
         const mcv = try self.resolveInst(operand);
-        const struct_ty = self.air.typeOf(operand).childType();
+        const ptr_ty = self.air.typeOf(operand);
+        const struct_ty = ptr_ty.childType();
         const struct_size = @intCast(u32, struct_ty.abiSize(self.target.*));
         const struct_field_offset = @intCast(u32, struct_ty.structFieldOffset(index, self.target.*));
         const struct_field_ty = struct_ty.structFieldType(index);
@@ -1652,6 +1653,28 @@ fn structFieldPtr(self: *Self, inst: Air.Inst.Index, operand: Air.Inst.Ref, inde
             .ptr_stack_offset => |off| {
                 break :result MCValue{ .ptr_stack_offset = off + struct_size - struct_field_offset - struct_field_size };
             },
+            .stack_argument_offset => {
+                const offset_reg = try self.copyToTmpRegister(ptr_ty, .{
+                    .immediate = struct_field_offset,
+                });
+                self.register_manager.freezeRegs(&.{offset_reg});
+                defer self.register_manager.unfreezeRegs(&.{offset_reg});
+
+                const addr_reg = try self.copyToTmpRegister(ptr_ty, mcv);
+                self.register_manager.freezeRegs(&.{addr_reg});
+                defer self.register_manager.unfreezeRegs(&.{addr_reg});
+
+                const dst_reg = try self.register_manager.allocReg(inst);
+                try self.genBinOpCode(
+                    dst_reg,
+                    .{ .register = addr_reg },
+                    .{ .register = offset_reg },
+                    false,
+                    .add,
+                    .unsigned,
+                );
+                break :result MCValue{ .register = dst_reg };
+            },
             else => return self.fail("TODO implement codegen struct_field_ptr for {}", .{mcv}),
         }
     };
@@ -3841,6 +3864,24 @@ fn lowerDeclRef(self: *Self, tv: TypedValue, decl: *Module.Decl) InnerError!MCVa
     _ = tv;
 }
 
+fn lowerUnnamedConst(self: *Self, tv: TypedValue) InnerError!MCValue {
+    const local_sym_index = self.bin_file.lowerUnnamedConst(tv, self.mod_fn.owner_decl) catch |err| {
+        return self.fail("lowering unnamed constant failed: {s}", .{@errorName(err)});
+    };
+    if (self.bin_file.cast(link.File.Elf)) |elf_file| {
+        const vaddr = elf_file.local_symbols.items[local_sym_index].st_value;
+        return MCValue{ .memory = vaddr };
+    } else if (self.bin_file.cast(link.File.MachO)) |_| {
+        unreachable;
+    } else if (self.bin_file.cast(link.File.Coff)) |_| {
+        return self.fail("TODO lower unnamed const in COFF", .{});
+    } else if (self.bin_file.cast(link.File.Plan9)) |_| {
+        return self.fail("TODO lower unnamed const in Plan9", .{});
+    } else {
+        return self.fail("TODO lower unnamed const", .{});
+    }
+}
+
 fn genTypedValue(self: *Self, typed_value: TypedValue) InnerError!MCValue {
     if (typed_value.val.isUndef())
         return MCValue{ .undef = {} };
@@ -3953,6 +3994,9 @@ fn genTypedValue(self: *Self, typed_value: TypedValue) InnerError!MCValue {
                 return self.fail("TODO implement error union const of type '{}' (error)", .{typed_value.ty});
             }
         },
+        .Struct => {
+            return self.lowerUnnamedConst(typed_value);
+        },
         else => return self.fail("TODO implement const of type '{}'", .{typed_value.ty}),
     }
 }
test/behavior/struct.zig
@@ -53,20 +53,18 @@ test "non-packed struct has fields padded out to the required alignment" {
 
 const SmallStruct = struct {
     a: u8,
-    b: u32,
+    b: u8,
 
     fn first(self: *SmallStruct) u8 {
         return self.a;
     }
 
-    fn second(self: *SmallStruct) u32 {
+    fn second(self: *SmallStruct) u8 {
         return self.b;
     }
 };
 
 test "lower unnamed constants" {
-    if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
-
     var foo = SmallStruct{ .a = 1, .b = 255 };
     try expect(foo.first() == 1);
     try expect(foo.second() == 255);