From 01c1f415209f5085e09430cc6df182d7eb2245ee Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Fri, 22 Oct 2021 17:12:12 -0700 Subject: stage2: slice and alignment fixes * Fix backend using wrong union field of the slice instruction. * LLVM backend properly sets alignment on global variables. * Sema: add coercion for *T to *[1]T * Sema: pointers to Decls with explicit alignment now have alignment metadata in them. --- src/Liveness.zig | 3 +-- src/Module.zig | 11 +++++++++++ src/Sema.zig | 42 +++++++++++++++++++++++++++++++++--------- src/arch/aarch64/CodeGen.zig | 3 ++- src/codegen.zig | 3 ++- src/codegen/c.zig | 3 ++- src/codegen/llvm.zig | 5 ++++- src/print_air.zig | 19 ++++++------------- 8 files changed, 61 insertions(+), 28 deletions(-) (limited to 'src') diff --git a/src/Liveness.zig b/src/Liveness.zig index 5f0919a6cb..499500fddb 100644 --- a/src/Liveness.zig +++ b/src/Liveness.zig @@ -267,7 +267,6 @@ fn analyzeInst( .set_union_tag, .min, .max, - .slice, => { const o = inst_datas[inst].bin_op; return trackOperands(a, new_set, inst, main_tomb, .{ o.lhs, o.rhs, .none }); @@ -363,7 +362,7 @@ fn analyzeInst( const extra = a.air.extraData(Air.StructField, inst_datas[inst].ty_pl.payload).data; return trackOperands(a, new_set, inst, main_tomb, .{ extra.struct_operand, .none, .none }); }, - .ptr_elem_ptr, .slice_elem_ptr => { + .ptr_elem_ptr, .slice_elem_ptr, .slice => { const extra = a.air.extraData(Air.Bin, inst_datas[inst].ty_pl.payload).data; return trackOperands(a, new_set, inst, main_tomb, .{ extra.lhs, extra.rhs, .none }); }, diff --git a/src/Module.zig b/src/Module.zig index 3ac523bdc5..de6770d3d7 100644 --- a/src/Module.zig +++ b/src/Module.zig @@ -772,6 +772,17 @@ pub const Decl = struct { else => false, }; } + + pub fn getAlignment(decl: Decl, target: Target) u32 { + assert(decl.has_tv); + if (decl.align_val.tag() != .null_value) { + // Explicit alignment. + return @intCast(u32, decl.align_val.toUnsignedInt()); + } else { + // Natural alignment. + return decl.ty.abiAlignment(target); + } + } }; /// This state is attached to every Decl when Module emit_h is non-null. diff --git a/src/Sema.zig b/src/Sema.zig index 92a3a6a50f..9bd0e1037d 100644 --- a/src/Sema.zig +++ b/src/Sema.zig @@ -11925,18 +11925,37 @@ fn coerce( return sema.coerce(block, dest_ty, inst_as_ptr, inst_src); } + // *T to *[1]T + single_item: { + if (!dest_ty.isSinglePointer()) break :single_item; + if (!inst_ty.isSinglePointer()) break :single_item; + const ptr_elem_ty = inst_ty.childType(); + const array_ty = dest_ty.childType(); + if (array_ty.zigTypeTag() != .Array) break :single_item; + const array_elem_ty = array_ty.childType(); + const dest_is_mut = !dest_ty.isConstPtr(); + if (inst_ty.isConstPtr() and dest_is_mut) break :single_item; + if (inst_ty.isVolatilePtr() and !dest_ty.isVolatilePtr()) break :single_item; + if (inst_ty.ptrAddressSpace() != dest_ty.ptrAddressSpace()) break :single_item; + switch (coerceInMemoryAllowed(array_elem_ty, ptr_elem_ty, dest_is_mut, target)) { + .ok => {}, + .no_match => break :single_item, + } + return sema.coerceCompatiblePtrs(block, dest_ty, inst, inst_src); + } + // Coercions where the source is a single pointer to an array. src_array_ptr: { if (!inst_ty.isSinglePointer()) break :src_array_ptr; - const array_type = inst_ty.elemType(); - if (array_type.zigTypeTag() != .Array) break :src_array_ptr; - const array_elem_type = array_type.elemType(); + const array_ty = inst_ty.childType(); + if (array_ty.zigTypeTag() != .Array) break :src_array_ptr; + const array_elem_type = array_ty.childType(); const dest_is_mut = !dest_ty.isConstPtr(); if (inst_ty.isConstPtr() and dest_is_mut) break :src_array_ptr; if (inst_ty.isVolatilePtr() and !dest_ty.isVolatilePtr()) break :src_array_ptr; if (inst_ty.ptrAddressSpace() != dest_ty.ptrAddressSpace()) break :src_array_ptr; - const dst_elem_type = dest_ty.elemType(); + const dst_elem_type = dest_ty.childType(); switch (coerceInMemoryAllowed(dst_elem_type, array_elem_type, dest_is_mut, target)) { .ok => {}, .no_match => break :src_array_ptr, @@ -11949,20 +11968,20 @@ fn coerce( }, .C => { // *[N]T to [*c]T - return sema.coerceArrayPtrToMany(block, dest_ty, inst, inst_src); + return sema.coerceCompatiblePtrs(block, dest_ty, inst, inst_src); }, .Many => { // *[N]T to [*]T // *[N:s]T to [*:s]T // *[N:s]T to [*]T if (dest_ty.sentinel()) |dst_sentinel| { - if (array_type.sentinel()) |src_sentinel| { + if (array_ty.sentinel()) |src_sentinel| { if (src_sentinel.eql(dst_sentinel, dst_elem_type)) { - return sema.coerceArrayPtrToMany(block, dest_ty, inst, inst_src); + return sema.coerceCompatiblePtrs(block, dest_ty, inst, inst_src); } } } else { - return sema.coerceArrayPtrToMany(block, dest_ty, inst, inst_src); + return sema.coerceCompatiblePtrs(block, dest_ty, inst, inst_src); } }, .One => {}, @@ -12680,7 +12699,7 @@ fn coerceArrayPtrToSlice( return block.addTyOp(.array_to_slice, dest_ty, inst); } -fn coerceArrayPtrToMany( +fn coerceCompatiblePtrs( sema: *Sema, block: *Block, dest_ty: Type, @@ -12888,10 +12907,15 @@ fn analyzeDeclRef(sema: *Sema, decl: *Decl) CompileError!Air.Inst.Ref { const decl_tv = try decl.typedValue(); if (decl_tv.val.castTag(.variable)) |payload| { const variable = payload.data; + const alignment: u32 = if (decl.align_val.tag() == .null_value) + 0 + else + @intCast(u32, decl.align_val.toUnsignedInt()); const ty = try Type.ptr(sema.arena, .{ .pointee_type = decl_tv.ty, .mutable = variable.is_mutable, .@"addrspace" = decl.@"addrspace", + .@"align" = alignment, }); return sema.addConstant(ty, try Value.Tag.decl_ref.create(sema.arena, decl)); } diff --git a/src/arch/aarch64/CodeGen.zig b/src/arch/aarch64/CodeGen.zig index 155ac6de68..2c6feec70c 100644 --- a/src/arch/aarch64/CodeGen.zig +++ b/src/arch/aarch64/CodeGen.zig @@ -876,7 +876,8 @@ fn airMax(self: *Self, inst: Air.Inst.Index) !void { } fn airSlice(self: *Self, inst: Air.Inst.Index) !void { - const bin_op = self.air.instructions.items(.data)[inst].bin_op; + const ty_pl = self.air.instructions.items(.data)[inst].ty_pl; + const bin_op = self.air.extraData(Air.Bin, ty_pl.payload).data; const result: MCValue = if (self.liveness.isUnused(inst)) .dead else return self.fail("TODO implement slice for {}", .{self.target.cpu.arch}); return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none }); } diff --git a/src/codegen.zig b/src/codegen.zig index ac9eaeda2a..5f5ee1b549 100644 --- a/src/codegen.zig +++ b/src/codegen.zig @@ -1246,7 +1246,8 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type { } fn airSlice(self: *Self, inst: Air.Inst.Index) !void { - const bin_op = self.air.instructions.items(.data)[inst].bin_op; + const ty_pl = self.air.instructions.items(.data)[inst].ty_pl; + const bin_op = self.air.extraData(Air.Bin, ty_pl.payload).data; const result: MCValue = if (self.liveness.isUnused(inst)) .dead else switch (arch) { else => return self.fail("TODO implement slice for {}", .{self.target.cpu.arch}), }; diff --git a/src/codegen/c.zig b/src/codegen/c.zig index aa1ece7ba3..dd71590566 100644 --- a/src/codegen/c.zig +++ b/src/codegen/c.zig @@ -1663,7 +1663,8 @@ fn airMinMax(f: *Function, inst: Air.Inst.Index, operator: [*:0]const u8) !CValu fn airSlice(f: *Function, inst: Air.Inst.Index) !CValue { if (f.liveness.isUnused(inst)) return CValue.none; - const bin_op = f.air.instructions.items(.data)[inst].bin_op; + const ty_pl = f.air.instructions.items(.data)[inst].ty_pl; + const bin_op = f.air.extraData(Air.Bin, ty_pl.payload).data; const ptr = try f.resolveInst(bin_op.lhs); const len = try f.resolveInst(bin_op.rhs); diff --git a/src/codegen/llvm.zig b/src/codegen/llvm.zig index d6b41208f2..3f24bb535d 100644 --- a/src/codegen/llvm.zig +++ b/src/codegen/llvm.zig @@ -581,7 +581,9 @@ pub const DeclGen = struct { } else if (decl.val.castTag(.extern_fn)) |extern_fn| { _ = try self.resolveLlvmFunction(extern_fn.data); } else { + const target = self.module.getTarget(); const global = try self.resolveGlobalDecl(decl); + global.setAlignment(decl.getAlignment(target)); assert(decl.has_tv); const init_val = if (decl.val.castTag(.variable)) |payload| init_val: { const variable = payload.data; @@ -2713,7 +2715,8 @@ pub const FuncGen = struct { fn airSlice(self: *FuncGen, inst: Air.Inst.Index) !?*const llvm.Value { if (self.liveness.isUnused(inst)) return null; - const bin_op = self.air.instructions.items(.data)[inst].bin_op; + const ty_pl = self.air.instructions.items(.data)[inst].ty_pl; + const bin_op = self.air.extraData(Air.Bin, ty_pl.payload).data; const ptr = try self.resolveInst(bin_op.lhs); const len = try self.resolveInst(bin_op.rhs); const inst_ty = self.air.typeOfIndex(inst); diff --git a/src/print_air.zig b/src/print_air.zig index 5aec562241..17efa8297d 100644 --- a/src/print_air.zig +++ b/src/print_air.zig @@ -141,7 +141,6 @@ const Writer = struct { .set_union_tag, .min, .max, - .slice, => try w.writeBinOp(s, inst), .is_null, @@ -203,8 +202,11 @@ const Writer = struct { .loop, => try w.writeBlock(s, inst), - .slice_elem_ptr => try w.writeSliceElemPtr(s, inst), - .ptr_elem_ptr => try w.writePtrElemPtr(s, inst), + .slice, + .slice_elem_ptr, + .ptr_elem_ptr, + => try w.writeTyPlBin(s, inst), + .struct_field_ptr => try w.writeStructField(s, inst), .struct_field_val => try w.writeStructField(s, inst), .constant => try w.writeConstant(s, inst), @@ -285,16 +287,7 @@ const Writer = struct { try s.print(", {d}", .{extra.field_index}); } - fn writeSliceElemPtr(w: *Writer, s: anytype, inst: Air.Inst.Index) @TypeOf(s).Error!void { - const ty_pl = w.air.instructions.items(.data)[inst].ty_pl; - const extra = w.air.extraData(Air.Bin, ty_pl.payload).data; - - try w.writeOperand(s, inst, 0, extra.lhs); - try s.writeAll(", "); - try w.writeOperand(s, inst, 1, extra.rhs); - } - - fn writePtrElemPtr(w: *Writer, s: anytype, inst: Air.Inst.Index) @TypeOf(s).Error!void { + fn writeTyPlBin(w: *Writer, s: anytype, inst: Air.Inst.Index) @TypeOf(s).Error!void { const ty_pl = w.air.instructions.items(.data)[inst].ty_pl; const extra = w.air.extraData(Air.Bin, ty_pl.payload).data; -- cgit v1.2.3