From dbe9a5114e2d56f847b674539ffa0d28fc57ea78 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Thu, 16 Sep 2021 21:03:55 -0700 Subject: stage2: implement `@setAlignStack` and 128-bit cmpxchg * test runner is improved to respect `error.SkipZigTest` * start code is improved to `@setAlignStack(16)` before calling main() * the newly passing behavior test has a workaround for the fact that stage2 cannot yet call `std.Target.x86.featureSetHas()` at comptime. This is blocking on comptime closures. The workaround is that there is a new decl `@import("builtin").stage2_x86_cx16` which is a `bool`. * Implement `@setAlignStack`. This language feature should be re-evaluated at some point - I'll file an issue for it. * LLVM backend: apply/remove the cold attribute and noinline attribute where appropriate. * LLVM backend: loads and stores are properly annotated with alignment and volatile attributes. * LLVM backend: allocas are properly annotated with alignment. * Type: fix integers reporting wrong alignment for 256-bit integers and beyond. Once you get to 16 byte aligned, there is no further alignment for larger integers. --- src/codegen/llvm.zig | 79 +++++++++++++++++++++++++++++++++++++++++----------- 1 file changed, 62 insertions(+), 17 deletions(-) (limited to 'src/codegen/llvm.zig') diff --git a/src/codegen/llvm.zig b/src/codegen/llvm.zig index 5720756cc2..ecc1790e6d 100644 --- a/src/codegen/llvm.zig +++ b/src/codegen/llvm.zig @@ -355,6 +355,20 @@ pub const Object = struct { const llvm_func = try dg.resolveLlvmFunction(decl); + if (module.align_stack_fns.get(func)) |align_info| { + dg.addFnAttrInt(llvm_func, "alignstack", align_info.alignment); + dg.addFnAttr(llvm_func, "noinline"); + } else { + DeclGen.removeFnAttr(llvm_func, "alignstack"); + if (!func.is_noinline) DeclGen.removeFnAttr(llvm_func, "noinline"); + } + + if (func.is_cold) { + dg.addFnAttr(llvm_func, "cold"); + } else { + DeclGen.removeFnAttr(llvm_func, "cold"); + } + // This gets the LLVM values from the function and stores them in `dg.args`. const fn_param_len = decl.ty.fnParamLen(); var args = try dg.gpa.alloc(*const llvm.Value, fn_param_len); @@ -512,7 +526,9 @@ pub const DeclGen = struct { } } - /// If the llvm function does not exist, create it + /// If the llvm function does not exist, create it. + /// Note that this can be called before the function's semantic analysis has + /// completed, so if any attributes rely on that, they must be done in updateFunc, not here. fn resolveLlvmFunction(self: *DeclGen, decl: *Module.Decl) !*const llvm.Value { if (self.llvmModule().getNamedFunction(decl.name)) |llvm_fn| return llvm_fn; @@ -895,17 +911,39 @@ pub const DeclGen = struct { } } - // Helper functions - fn addAttr(self: *DeclGen, val: *const llvm.Value, index: llvm.AttributeIndex, name: []const u8) void { + fn addAttr(dg: *DeclGen, val: *const llvm.Value, index: llvm.AttributeIndex, name: []const u8) void { + return dg.addAttrInt(val, index, name, 0); + } + + fn removeAttr(val: *const llvm.Value, index: llvm.AttributeIndex, name: []const u8) void { const kind_id = llvm.getEnumAttributeKindForName(name.ptr, name.len); assert(kind_id != 0); - const llvm_attr = self.context.createEnumAttribute(kind_id, 0); + val.removeEnumAttributeAtIndex(index, kind_id); + } + + fn addAttrInt( + dg: *DeclGen, + val: *const llvm.Value, + index: llvm.AttributeIndex, + name: []const u8, + int: u64, + ) void { + const kind_id = llvm.getEnumAttributeKindForName(name.ptr, name.len); + assert(kind_id != 0); + const llvm_attr = dg.context.createEnumAttribute(kind_id, int); val.addAttributeAtIndex(index, llvm_attr); } - fn addFnAttr(self: *DeclGen, val: *const llvm.Value, attr_name: []const u8) void { - // TODO: improve this API, `addAttr(-1, attr_name)` - self.addAttr(val, std.math.maxInt(llvm.AttributeIndex), attr_name); + fn addFnAttr(dg: *DeclGen, val: *const llvm.Value, name: []const u8) void { + dg.addAttr(val, std.math.maxInt(llvm.AttributeIndex), name); + } + + fn removeFnAttr(fn_val: *const llvm.Value, name: []const u8) void { + removeAttr(fn_val, std.math.maxInt(llvm.AttributeIndex), name); + } + + fn addFnAttrInt(dg: *DeclGen, fn_val: *const llvm.Value, name: []const u8, int: u64) void { + return dg.addAttrInt(fn_val, std.math.maxInt(llvm.AttributeIndex), name, int); } /// If the operand type of an atomic operation is not byte sized we need to @@ -1975,12 +2013,13 @@ pub const FuncGen = struct { return null; // buildAlloca expects the pointee type, not the pointer type, so assert that // a Payload.PointerSimple is passed to the alloc instruction. - const inst_ty = self.air.typeOfIndex(inst); - const pointee_type = inst_ty.castPointer().?.data; - - // TODO: figure out a way to get the name of the var decl. - // TODO: set alignment and volatile - return self.buildAlloca(try self.dg.llvmType(pointee_type)); + const ptr_ty = self.air.typeOfIndex(inst); + const pointee_type = ptr_ty.elemType(); + const pointee_llvm_ty = try self.dg.llvmType(pointee_type); + const target = self.dg.module.getTarget(); + const alloca_inst = self.buildAlloca(pointee_llvm_ty); + alloca_inst.setAlignment(ptr_ty.ptrAlignment(target)); + return alloca_inst; } /// Use this instead of builder.buildAlloca, because this function makes sure to @@ -2200,8 +2239,11 @@ pub const FuncGen = struct { } fn load(self: *FuncGen, ptr: *const llvm.Value, ptr_ty: Type) *const llvm.Value { - _ = ptr_ty; // TODO set volatile and alignment on this load properly - return self.builder.buildLoad(ptr, ""); + const llvm_inst = self.builder.buildLoad(ptr, ""); + const target = self.dg.module.getTarget(); + llvm_inst.setAlignment(ptr_ty.ptrAlignment(target)); + llvm_inst.setVolatile(llvm.Bool.fromBool(ptr_ty.isVolatilePtr())); + return llvm_inst; } fn store( @@ -2210,8 +2252,11 @@ pub const FuncGen = struct { ptr_ty: Type, elem: *const llvm.Value, ) *const llvm.Value { - _ = ptr_ty; // TODO set volatile and alignment on this store properly - return self.builder.buildStore(elem, ptr); + const llvm_inst = self.builder.buildStore(elem, ptr); + const target = self.dg.module.getTarget(); + llvm_inst.setAlignment(ptr_ty.ptrAlignment(target)); + llvm_inst.setVolatile(llvm.Bool.fromBool(ptr_ty.isVolatilePtr())); + return llvm_inst; } }; -- cgit v1.2.3