From 1aab8b87ec30cd8d50c01292f910e94279596a3f Mon Sep 17 00:00:00 2001 From: Christoffer Lerno Date: Thu, 1 Aug 2024 22:57:26 +0200 Subject: [PATCH] Add experimental `@noalias` attribute. --- releasenotes.md | 1 + src/compiler/compiler_internal.h | 1 + src/compiler/enums.h | 1 + src/compiler/llvm_codegen.c | 17 ++++++++++++----- src/compiler/sema_decls.c | 11 ++++++++++- src/compiler/symtab.c | 1 + 6 files changed, 26 insertions(+), 6 deletions(-) diff --git a/releasenotes.md b/releasenotes.md index ec5d562df..1bc510a52 100644 --- a/releasenotes.md +++ b/releasenotes.md @@ -20,6 +20,7 @@ - `$expand` macro, to expand a string into code. - && doesn't work correctly with lambdas #1279. - Fix incorrect override of optimization levels when using projects. +- Add experimental `@noalias` attribute. ### Fixes diff --git a/src/compiler/compiler_internal.h b/src/compiler/compiler_internal.h index c4fc0d971..25540e64d 100644 --- a/src/compiler/compiler_internal.h +++ b/src/compiler/compiler_internal.h @@ -472,6 +472,7 @@ typedef struct VarDecl_ bool is_addr : 1; bool is_threadlocal : 1; bool no_init : 1; + bool no_alias : 1; bool bit_is_expr : 1; TypeInfoId type_info; union diff --git a/src/compiler/enums.h b/src/compiler/enums.h index 707a4aa46..51d4f53d6 100644 --- a/src/compiler/enums.h +++ b/src/compiler/enums.h @@ -824,6 +824,7 @@ typedef enum ATTRIBUTE_LOCAL, ATTRIBUTE_MAYDISCARD, ATTRIBUTE_NAKED, + ATTRIBUTE_NOALIAS, ATTRIBUTE_NODISCARD, ATTRIBUTE_NOINIT, ATTRIBUTE_NOINLINE, diff --git a/src/compiler/llvm_codegen.c b/src/compiler/llvm_codegen.c index b0ef23b13..5bb5c14e6 100644 --- a/src/compiler/llvm_codegen.c +++ b/src/compiler/llvm_codegen.c @@ -1069,7 +1069,8 @@ LLVMValueRef llvm_get_opt_ref(GenContext *c, Decl *decl) return decl->var.optional_ref; } -static void llvm_emit_param_attributes(GenContext *c, LLVMValueRef function, ABIArgInfo *info, bool is_return, int index, int last_index) +static void llvm_emit_param_attributes(GenContext *c, LLVMValueRef function, ABIArgInfo *info, bool is_return, + int index, int last_index, Decl *decl) { assert(last_index == index || info->kind == ABI_ARG_DIRECT_PAIR || info->kind == ABI_ARG_IGNORE || info->kind == ABI_ARG_EXPAND || info->kind == ABI_ARG_DIRECT || info->kind == ABI_ARG_DIRECT_COERCE @@ -1094,13 +1095,18 @@ static void llvm_emit_param_attributes(GenContext *c, LLVMValueRef function, ABI } switch (info->kind) { + case ABI_ARG_DIRECT: + if (decl && decl->var.no_alias) + { + llvm_attribute_add(c, function, attribute_id.noalias, 1); + } + break; case ABI_ARG_EXPAND: case ABI_ARG_IGNORE: case ABI_ARG_DIRECT_SPLIT_STRUCT_I32: case ABI_ARG_DIRECT_COERCE: case ABI_ARG_DIRECT_COERCE_INT: case ABI_ARG_DIRECT_PAIR: - case ABI_ARG_DIRECT: case ABI_ARG_EXPAND_COERCE: break; case ABI_ARG_INDIRECT: @@ -1127,7 +1133,7 @@ void llvm_append_function_attributes(GenContext *c, Decl *decl) LLVMValueRef function = decl->backend_ref; ABIArgInfo *ret_abi_info = prototype->ret_abi_info; - llvm_emit_param_attributes(c, function, ret_abi_info, true, 0, 0); + llvm_emit_param_attributes(c, function, ret_abi_info, true, 0, 0, NULL); unsigned params = vec_size(prototype->param_types); if (c->debug.enable_stacktrace) { @@ -1140,12 +1146,13 @@ void llvm_append_function_attributes(GenContext *c, Decl *decl) if (prototype->ret_by_ref) { ABIArgInfo *info = prototype->ret_by_ref_abi_info; - llvm_emit_param_attributes(c, function, prototype->ret_by_ref_abi_info, false, info->param_index_start + 1, info->param_index_end); + llvm_emit_param_attributes(c, function, prototype->ret_by_ref_abi_info, false, info->param_index_start + 1, + info->param_index_end, NULL); } for (unsigned i = 0; i < params; i++) { ABIArgInfo *info = prototype->abi_args[i]; - llvm_emit_param_attributes(c, function, info, false, info->param_index_start + 1, info->param_index_end); + llvm_emit_param_attributes(c, function, info, false, info->param_index_start + 1, info->param_index_end, decl->func_decl.signature.params[i]); } // We ignore decl->func_decl.attr_inline and place it in every call instead. if (decl->func_decl.attr_noinline) diff --git a/src/compiler/sema_decls.c b/src/compiler/sema_decls.c index ac6e605bf..a20d76ec7 100644 --- a/src/compiler/sema_decls.c +++ b/src/compiler/sema_decls.c @@ -1200,12 +1200,17 @@ static inline bool sema_analyse_signature(SemaContext *context, Signature *sig, : RESOLVE_TYPE_DEFAULT)) return decl_poison(param); param->type = type_info->type; } + if (type_info && param->var.no_alias && !type_is_pointer(param->type) && type_flatten(param->type)->type_kind != TYPE_SLICE) + { + SEMA_ERROR(param, "The parameter was set to @noalias, but it was neither a slice nor a pointer. You need to either remove '@noalias' or use pointer/slice type."); + return decl_poison(param); + } switch (var_kind) { case VARDECL_PARAM_REF: if (type_info && !type_is_pointer(param->type)) { - RETURN_SEMA_ERROR(type_info, "A pointer type was expected for a ref argument, did you mean %s?", + SEMA_ERROR(type_info, "A pointer type was expected for a ref argument, did you mean %s?", type_quoted_error_string(type_get_ptr(param->type))); return decl_poison(param); } @@ -2359,6 +2364,7 @@ static bool sema_analyse_attribute(SemaContext *context, Decl *decl, Attr *attr, [ATTRIBUTE_LOCAL] = ATTR_FUNC | ATTR_MACRO | ATTR_GLOBAL | ATTR_CONST | USER_DEFINED_TYPES | ATTR_DEF | ATTR_INTERFACE, [ATTRIBUTE_MAYDISCARD] = CALLABLE_TYPE, [ATTRIBUTE_NAKED] = ATTR_FUNC, + [ATTRIBUTE_NOALIAS] = ATTR_PARAM, [ATTRIBUTE_NODISCARD] = CALLABLE_TYPE, [ATTRIBUTE_NOINIT] = ATTR_GLOBAL | ATTR_LOCAL, [ATTRIBUTE_NOINLINE] = ATTR_FUNC | ATTR_CALL, @@ -2519,6 +2525,9 @@ static bool sema_analyse_attribute(SemaContext *context, Decl *decl, Attr *attr, case ATTRIBUTE_NOSTRIP: decl->no_strip = true; return true; + case ATTRIBUTE_NOALIAS: + decl->var.no_alias = true; + return true; case ATTRIBUTE_IF: if (!expr) RETURN_SEMA_ERROR(attr, "'@if' requires a boolean argument."); if (!sema_analyse_expr(context, expr)) return false; diff --git a/src/compiler/symtab.c b/src/compiler/symtab.c index f9a1365b9..52cfe6ae4 100644 --- a/src/compiler/symtab.c +++ b/src/compiler/symtab.c @@ -326,6 +326,7 @@ void symtab_init(uint32_t capacity) attribute_list[ATTRIBUTE_LOCAL] = KW_DEF("@local"); attribute_list[ATTRIBUTE_MAYDISCARD] = KW_DEF("@maydiscard"); attribute_list[ATTRIBUTE_NAKED] = KW_DEF("@naked"); + attribute_list[ATTRIBUTE_NOALIAS] = KW_DEF("@noalias"); attribute_list[ATTRIBUTE_NODISCARD] = KW_DEF("@nodiscard"); attribute_list[ATTRIBUTE_NOINIT] = KW_DEF("@noinit"); attribute_list[ATTRIBUTE_NOINLINE] = KW_DEF("@noinline");