From patchwork Tue Jan 30 12:07:27 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Arthur Cohen X-Patchwork-Id: 1892904 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@legolas.ozlabs.org Authentication-Results: legolas.ozlabs.org; dkim=pass (2048-bit key; unprotected) header.d=embecosm.com header.i=@embecosm.com header.a=rsa-sha256 header.s=google header.b=FoK4jJtX; dkim-atps=neutral Authentication-Results: legolas.ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=gcc.gnu.org (client-ip=2620:52:3:1:0:246e:9693:128c; helo=server2.sourceware.org; envelope-from=gcc-patches-bounces+incoming=patchwork.ozlabs.org@gcc.gnu.org; receiver=patchwork.ozlabs.org) Received: from server2.sourceware.org (server2.sourceware.org [IPv6:2620:52:3:1:0:246e:9693:128c]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature ECDSA (secp384r1) server-digest SHA384) (No client certificate requested) by legolas.ozlabs.org (Postfix) with ESMTPS id 4TPPxC4WpPz23gZ for ; Tue, 30 Jan 2024 23:43:59 +1100 (AEDT) Received: from server2.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id 7F787387547B for ; Tue, 30 Jan 2024 12:43:57 +0000 (GMT) X-Original-To: gcc-patches@gcc.gnu.org Delivered-To: gcc-patches@gcc.gnu.org Received: from mail-wm1-x335.google.com (mail-wm1-x335.google.com [IPv6:2a00:1450:4864:20::335]) by sourceware.org (Postfix) with ESMTPS id 8BEC23857705 for ; Tue, 30 Jan 2024 12:11:47 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org 8BEC23857705 Authentication-Results: sourceware.org; dmarc=none (p=none dis=none) header.from=embecosm.com Authentication-Results: sourceware.org; spf=pass smtp.mailfrom=embecosm.com ARC-Filter: OpenARC Filter v1.0.0 sourceware.org 8BEC23857705 Authentication-Results: server2.sourceware.org; arc=none smtp.remote-ip=2a00:1450:4864:20::335 ARC-Seal: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1706616751; cv=none; b=eM1NMVtJ6uf42/kgxUzw9/4bohO9DXamCOF9zL45vRXm693NVlWTtjsgCzZbwXb6IdDf6QeB9sLHHQkPd01C12EFVWfDUAF+gMzT9jc4LBmGpNPSw8aDeB4CVMlY5jfFlvGECrdhx/BoGbez4uVjMhuA1R07I9bqCiJb0jD9UCY= ARC-Message-Signature: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1706616751; c=relaxed/simple; bh=SyLSnjGmAd/B8MT0i0weOcH7Ffm9jJaqBV8/roBexOI=; h=DKIM-Signature:From:To:Subject:Date:Message-ID:MIME-Version; b=EV0uZ7hvwF5nfxAnJcgNqG+gPG/habHVqDrscqqlqnMWx5O+xwdkeMPL7LLUjplXwdPg5Qpaog2fSdJqi4uGEGCf9kMWNT3yQfgS3FfUrKMU4baQq5P4L11Bv9sxc7ruiPvFebBoeSSOG7WiIxACKLFovQbzjq/QGCG1Ul2lyr4= ARC-Authentication-Results: i=1; server2.sourceware.org Received: by mail-wm1-x335.google.com with SMTP id 5b1f17b1804b1-40eebe7767cso31014905e9.1 for ; Tue, 30 Jan 2024 04:11:47 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=embecosm.com; s=google; t=1706616703; x=1707221503; darn=gcc.gnu.org; h=content-transfer-encoding:mime-version:reply-to:references :in-reply-to:message-id:date:subject:cc:to:from:from:to:cc:subject :date:message-id:reply-to; bh=lwxEWujRnQIh8vJNgpoR0d7qlGYsvBIdMke/MAVY2w8=; b=FoK4jJtXW40M7UX0Hd/LHtm2aNHl8WrXDyx9N1r278w2KS/Di6ukAYlY1qwAhJpNg7 eSCn/z5MIBNb1pkfKfMPh49JzKs7faIltb9pkO9rVxWIVnAX3AMlotx6Eu31CYXg0m6E BEe78vXPs+QL8Bsfq/9STwIbftd0PXeVY3dOxT9+GfAz3Of3uKrBC5jG7sburf7FvNAq Nq1A2W8ujrE6YcT2V/iqbkcM8xcdV5iZM4wyqz/YpyhXcbj5n2BZVKrZZyNatTWbj7yN 7CoG6JWs+waxMGH7QjtqEHo2wtSLsETa6IE1JG1MPoK+kuqBa9TVYqT7OCbDm5E+RwA6 J6ow== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1706616703; x=1707221503; h=content-transfer-encoding:mime-version:reply-to:references :in-reply-to:message-id:date:subject:cc:to:from:x-gm-message-state :from:to:cc:subject:date:message-id:reply-to; bh=lwxEWujRnQIh8vJNgpoR0d7qlGYsvBIdMke/MAVY2w8=; b=f3YXmc7f46wHEUTmLOnFa91gZU3VTODSNT7enSJHkS8Pu7qTpKle+E7l+BvdjIqhoV KFWhPYkil/g4HA/cvXr4xcJbNV9K7sdzbPi0Jyd0U4dgAZ0z8JQnyFvnqBzHYRfSn+VG Hh5+p3Nu0jdS/Ur7VLZOLIkMqhJtQt4Ma4mVF/ysvNuwiB4iSuR/HwZj0qCMlxfSeWn7 Tt3/+JSRjlFjYxlgZF7aZ7AhCyqBXhcQsTkp1nSkm6HTmrnWg5hiCyJuDxyVHNDkX9cW WOsOjemQ4Dqec/mmDSkTrISc27RxSIveD8b8vHTjdc4pgOi1EZBoq/FGqaxh3a3Om1PW uTtQ== X-Gm-Message-State: AOJu0YzNs3GptWtL09sLcW3fJokiaxGqc6d0I5PZXbHD8yOP+SbfdRpN /8s5Y/QWUXEpjyLNmgk7BGSNIiLAUExcCLpBEvVEMn4JFrDwrKfMDa7402sLRtYy7425Z/oVCdQ 8sA== X-Google-Smtp-Source: AGHT+IErsyxJeDzZGujwGdilVmxbSFWg8zz2DCN4CfTcfNBf9KiJnWwEFqCf3B1GInvaOVV0wFkbDw== X-Received: by 2002:a05:600c:4685:b0:40e:b195:6bf3 with SMTP id p5-20020a05600c468500b0040eb1956bf3mr7869697wmo.2.1706616702332; Tue, 30 Jan 2024 04:11:42 -0800 (PST) Received: from platypus.localdomain ([62.23.166.218]) by smtp.gmail.com with ESMTPSA id f9-20020a056000036900b00339307d9d31sm10569894wrf.112.2024.01.30.04.11.41 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 30 Jan 2024 04:11:41 -0800 (PST) From: arthur.cohen@embecosm.com To: gcc-patches@gcc.gnu.org Cc: gcc-rust@gcc.gnu.org, Arthur Cohen , =?utf-8?q?Marc_Poulhi=C3=A8s?= Subject: [COMMITTED 071/101] gccrs: refactor builtins initialization and attributes Date: Tue, 30 Jan 2024 13:07:27 +0100 Message-ID: <20240130121026.807464-74-arthur.cohen@embecosm.com> X-Mailer: git-send-email 2.42.1 In-Reply-To: <20240130121026.807464-2-arthur.cohen@embecosm.com> References: <20240130121026.807464-2-arthur.cohen@embecosm.com> MIME-Version: 1.0 X-Spam-Status: No, score=-13.7 required=5.0 tests=BAYES_00, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, DKIM_VALID_EF, GIT_PATCH_0, KAM_SHORT, RCVD_IN_DNSWL_NONE, SCC_5_SHORT_WORD_LINES, SPF_HELO_NONE, SPF_PASS, TXREP, T_SCC_BODY_TEXT_LINE autolearn=unavailable autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on server2.sourceware.org X-BeenThere: gcc-patches@gcc.gnu.org X-Mailman-Version: 2.1.30 Precedence: list List-Id: Gcc-patches mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Reply-To: arthur.cohen@embecosm.com Errors-To: gcc-patches-bounces+incoming=patchwork.ozlabs.org@gcc.gnu.org From: Arthur Cohen This commit performs builtin initialization in a more "GCC-y" way, similarly to what the D frontend is doing. This way, we no longer have to worry about invalid attributes or types when initializing them by hand. Also add attributes support through LANG_HOOKS_COMMON_ATTRIBUTE_TABLE lang hook. Most of these changes are based on D frontend. gcc/rust/ChangeLog: * Make-lang.in (GRS_OBJS): Add rust-attribs.o. * backend/rust-builtins.cc (builtin_const, builtin_noreturn) (builtin_novops): Remove. (BuiltinsContext::lookup_simple_builtin): Adjust. (BuiltinsContext::setup_overflow_fns): Remove. (BuiltinsContext::define_function_type): Set builtin type to errormark so the builtin is considered unavailable. (BuiltinsContext::setup_math_fns): Remove. (BuiltinsContext::setup_atomic_fns): Remove. (build_c_type_nodes): Refactor based on D frontend. (BuiltinsContext::define_builtin_types): Likewise. (DEF_PRIMITIVE_TYPE): New. (DEF_FUNCTION_TYPE_0): New. (DEF_FUNCTION_TYPE_1): New. (DEF_FUNCTION_TYPE_2): New. (DEF_FUNCTION_TYPE_3): New. (DEF_FUNCTION_TYPE_4): New. (DEF_FUNCTION_TYPE_5): New. (DEF_FUNCTION_TYPE_6): New. (DEF_FUNCTION_TYPE_7): New. (DEF_FUNCTION_TYPE_8): New. (DEF_FUNCTION_TYPE_9): New. (DEF_FUNCTION_TYPE_10): New. (DEF_FUNCTION_TYPE_11): New. (DEF_FUNCTION_TYPE_VAR_0): New. (DEF_FUNCTION_TYPE_VAR_1): New. (DEF_FUNCTION_TYPE_VAR_2): New. (DEF_FUNCTION_TYPE_VAR_3): New. (DEF_FUNCTION_TYPE_VAR_4): New. (DEF_FUNCTION_TYPE_VAR_5): New. (DEF_FUNCTION_TYPE_VAR_6): New. (DEF_FUNCTION_TYPE_VAR_7): New. (DEF_FUNCTION_TYPE_VAR_11): New. (DEF_POINTER_TYPE): New. (BuiltinsContext::setup): Adjust. (BuiltinsContext::define_builtin_attributes): New. (DEF_ATTR_NULL_TREE): New. (DEF_ATTR_INT): New. (DEF_ATTR_STRING): New. (DEF_ATTR_IDENT): New. (DEF_ATTR_TREE_LIST): New. (handle_flags): Remove. (BuiltinsContext::define_builtins): New. (DEF_BUILTIN): New. (BuiltinsContext::define_builtin): Remove. (BuiltinsContext::register_rust_mappings): New. Add all missing builtins. (BuiltinsContext::lookup_gcc_builtin): Adjust. * backend/rust-builtins.h (DEF_PRIMITIVE_TYPE): New. (DEF_FUNCTION_TYPE_0): New. (DEF_FUNCTION_TYPE_1): New. (DEF_FUNCTION_TYPE_2): New. (DEF_FUNCTION_TYPE_3): New. (DEF_FUNCTION_TYPE_4): New. (DEF_FUNCTION_TYPE_5): New. (DEF_FUNCTION_TYPE_6): New. (DEF_FUNCTION_TYPE_7): New. (DEF_FUNCTION_TYPE_8): New. (DEF_FUNCTION_TYPE_9): New. (DEF_FUNCTION_TYPE_10): New. (DEF_FUNCTION_TYPE_11): New. (DEF_FUNCTION_TYPE_VAR_0): New. (DEF_FUNCTION_TYPE_VAR_1): New. (DEF_FUNCTION_TYPE_VAR_2): New. (DEF_FUNCTION_TYPE_VAR_3): New. (DEF_FUNCTION_TYPE_VAR_4): New. (DEF_FUNCTION_TYPE_VAR_5): New. (DEF_FUNCTION_TYPE_VAR_6): New. (DEF_FUNCTION_TYPE_VAR_7): New. (DEF_FUNCTION_TYPE_VAR_11): New. (DEF_POINTER_TYPE): New. (DEF_ATTR_NULL_TREE): New. (DEF_ATTR_INT): New. (DEF_ATTR_STRING): New. (DEF_ATTR_IDENT): New. (DEF_ATTR_TREE_LIST): New. * backend/rust-compile-intrinsic.cc (Intrinsics::compile): Add comment. (op_with_overflow_inner): Adjust. (copy_handler_inner): Adjust. (prefetch_data_handler): Adjust. (build_atomic_builtin_name): Adjust. (atomic_load_handler_inner): Adjust. (uninit_handler): Adjust. (move_val_init_handler): Adjust. (expect_handler_inner): Adjust. * rust-gcc.cc (fetch_overflow_builtins): Adjust. * rust-lang.cc (rust_localize_identifier): Adjust. (LANG_HOOKS_COMMON_ATTRIBUTE_TABLE): New. * rust-attribs.cc: New file. gcc/testsuite/ChangeLog: * rust/compile/torture/intrinsics-4.rs: Adjust. * rust/compile/torture/intrinsics-math.rs: Adjust. * rust/execute/torture/atomic_load.rs: Adjust. * rust/execute/torture/atomic_store.rs: Adjust. * rust/compile/torture/intrinsics-1.rs: Removed. * rust/compile/torture/builtin_abort.rs: New test. * rust/execute/torture/builtin_abort.rs: New test. Signed-off-by: Marc Poulhiès Co-authored-by: Arthur Cohen --- gcc/rust/Make-lang.in | 1 + gcc/rust/backend/rust-builtins.cc | 524 ++++++++++-------- gcc/rust/backend/rust-builtins.h | 118 +++- gcc/rust/backend/rust-compile-intrinsic.cc | 68 ++- gcc/rust/rust-attribs.cc | 370 +++++++++++++ gcc/rust/rust-gcc.cc | 8 +- gcc/rust/rust-lang.cc | 6 + .../rust/compile/torture/builtin_abort.rs | 18 + .../rust/compile/torture/intrinsics-1.rs | 22 - .../rust/compile/torture/intrinsics-4.rs | 2 +- .../rust/compile/torture/intrinsics-math.rs | 80 +-- .../rust/execute/torture/atomic_load.rs | 4 +- .../rust/execute/torture/atomic_store.rs | 4 +- .../rust/execute/torture/builtin_abort.rs | 14 + 14 files changed, 899 insertions(+), 340 deletions(-) create mode 100644 gcc/rust/rust-attribs.cc create mode 100644 gcc/testsuite/rust/compile/torture/builtin_abort.rs delete mode 100644 gcc/testsuite/rust/compile/torture/intrinsics-1.rs create mode 100644 gcc/testsuite/rust/execute/torture/builtin_abort.rs diff --git a/gcc/rust/Make-lang.in b/gcc/rust/Make-lang.in index 47cc87750be..b138ba26801 100644 --- a/gcc/rust/Make-lang.in +++ b/gcc/rust/Make-lang.in @@ -64,6 +64,7 @@ gccrs$(exeext): $(GCCRS_D_OBJS) $(EXTRA_GCC_OBJS) libcommon-target.a $(LIBDEPS) # The compiler proper, not driver GRS_OBJS = \ rust/rust-lang.o \ + rust/rust-attribs.o \ rust/rust-object-export.o \ rust/rust-linemap.o \ rust/rust-diagnostics.o \ diff --git a/gcc/rust/backend/rust-builtins.cc b/gcc/rust/backend/rust-builtins.cc index cd06379fcb0..1a87f869206 100644 --- a/gcc/rust/backend/rust-builtins.cc +++ b/gcc/rust/backend/rust-builtins.cc @@ -14,15 +14,16 @@ // along with GCC; see the file COPYING3. If not see // . +#include "rust-diagnostics.h" +#include "rust-system.h" #include "rust-builtins.h" +#include "target.h" +#include "stringpool.h" + namespace Rust { namespace Compile { -static const int builtin_const = 1 << 0; -static const int builtin_noreturn = 1 << 1; -static const int builtin_novops = 1 << 2; - BuiltinsContext & BuiltinsContext::get () { @@ -33,280 +34,317 @@ BuiltinsContext::get () bool BuiltinsContext::lookup_simple_builtin (const std::string &name, tree *builtin) { + auto *to_search = &name; + auto it = rust_intrinsic_to_gcc_builtin.find (name); - if (it == rust_intrinsic_to_gcc_builtin.end ()) - return false; + if (it != rust_intrinsic_to_gcc_builtin.end ()) + to_search = &it->second; - return lookup_gcc_builtin (it->second, builtin); + return lookup_gcc_builtin (*to_search, builtin); } BuiltinsContext::BuiltinsContext () { setup (); } +/** + * Define a function type according to `builtin-types.def` + * + * *Heavily* inspired by the D frontend's `def_fn_type` function + */ void -BuiltinsContext::setup_overflow_fns () +BuiltinsContext::define_function_type (Type def_idx, Type ret_idx, + bool is_variadic, size_t n, ...) { - tree overflow_type - = build_varargs_function_type_list (boolean_type_node, NULL_TREE); - - define_builtin ("add_overflow", BUILT_IN_ADD_OVERFLOW, - "__builtin_add_overflow", "add_overflow", overflow_type, 0); - define_builtin ("sub_overflow", BUILT_IN_SUB_OVERFLOW, - "__builtin_sub_overflow", "sub_overflow", overflow_type, 0); - define_builtin ("mul_overflow", BUILT_IN_MUL_OVERFLOW, - "__builtin_mul_overflow", "mul_overflow", overflow_type, 0); + va_list list; + va_start (list, n); + + auto args = std::vector (); + + for (size_t i = 0; i < n; i++) + { + // The argument is an enum Type, but it's promoted to int when passed + // though '...'. + auto arg_idx = va_arg (list, int); + auto arg_type = builtin_types[arg_idx]; + + args.emplace_back (arg_type); + } + + auto return_type = builtin_types[ret_idx]; + if (return_type == error_mark_node) + { + // Mark the builtin as not available. + builtin_types[def_idx] = error_mark_node; + va_end (list); + return; + } + + auto fn_type = NULL_TREE; + if (is_variadic) + fn_type = build_varargs_function_type_array (return_type, n, args.data ()); + else + fn_type = build_function_type_array (return_type, n, args.data ()); + + builtin_types[def_idx] = fn_type; + va_end (list); } -void -BuiltinsContext::setup_math_fns () +// Taken directly from the D frontend +static void +build_c_type_nodes (void) { - tree fn_type_f32_to_f32 - = build_function_type_list (float_type_node, float_type_node, NULL_TREE); - tree fn_type_f64_to_f64 - = build_function_type_list (double_type_node, double_type_node, NULL_TREE); - tree fn_type_f32_f32_to_f32 - = build_function_type_list (float_type_node, float_type_node, - float_type_node, NULL_TREE); - tree fn_type_f64_f64_to_f64 - = build_function_type_list (double_type_node, double_type_node, - double_type_node, NULL_TREE); - tree fn_type_f32_i32_to_f32 - = build_function_type_list (float_type_node, float_type_node, - integer_type_node, NULL_TREE); - tree fn_type_f64_i32_to_f64 - = build_function_type_list (double_type_node, double_type_node, - integer_type_node, NULL_TREE); - - define_builtin ("sqrtf32", BUILT_IN_SQRTF, "__builtin_sqrtf", "sqrtf", - fn_type_f32_to_f32, builtin_const); - define_builtin ("sqrtf64", BUILT_IN_SQRT, "__builtin_sqrt", "sqrt", - fn_type_f64_to_f64, builtin_const); - - define_builtin ("powif32", BUILT_IN_POWIF, "__builtin_powif", "powif", - fn_type_f32_i32_to_f32, builtin_const); - define_builtin ("powif64", BUILT_IN_POWI, "__builtin_powi", "powi", - fn_type_f64_i32_to_f64, builtin_const); - - define_builtin ("sinf32", BUILT_IN_SINF, "__builtin_sinf", "sinf", - fn_type_f32_to_f32, builtin_const); - define_builtin ("sinf64", BUILT_IN_SIN, "__builtin_sin", "sin", - fn_type_f64_to_f64, builtin_const); - - define_builtin ("cosf32", BUILT_IN_COSF, "__builtin_cosf", "cosf", - fn_type_f32_to_f32, builtin_const); - define_builtin ("cosf64", BUILT_IN_COS, "__builtin_cos", "cos", - fn_type_f64_to_f64, builtin_const); - - define_builtin ("powf32", BUILT_IN_POWF, "__builtin_powf", "powf", - fn_type_f32_f32_to_f32, builtin_const); - define_builtin ("powf64", BUILT_IN_POW, "__builtin_pow", "pow", - fn_type_f64_f64_to_f64, builtin_const); - - define_builtin ("expf32", BUILT_IN_EXPF, "__builtin_expf", "expf", - fn_type_f32_to_f32, builtin_const); - define_builtin ("expf64", BUILT_IN_EXP, "__builtin_exp", "exp", - fn_type_f64_to_f64, builtin_const); - - define_builtin ("exp2f32", BUILT_IN_EXP2F, "__builtin_exp2f", "exp2f", - fn_type_f32_to_f32, builtin_const); - define_builtin ("exp2f64", BUILT_IN_EXP2, "__builtin_exp2", "exp2", - fn_type_f64_to_f64, builtin_const); - - define_builtin ("logf32", BUILT_IN_LOGF, "__builtin_logf", "logf", - fn_type_f32_to_f32, builtin_const); - define_builtin ("logf64", BUILT_IN_LOG, "__builtin_log", "log", - fn_type_f64_to_f64, builtin_const); - - define_builtin ("log10f32", BUILT_IN_LOG10F, "__builtin_log10f", "log10f", - fn_type_f32_to_f32, builtin_const); - define_builtin ("log10f64", BUILT_IN_LOG10, "__builtin_log10", "log10", - fn_type_f64_to_f64, builtin_const); - - define_builtin ("log2f32", BUILT_IN_LOG2F, "__builtin_log2f", "log2f", - fn_type_f32_to_f32, builtin_const); - define_builtin ("log2f64", BUILT_IN_LOG2, "__builtin_log2", "log2", - fn_type_f64_to_f64, builtin_const); - - define_builtin ("fmaf32", BUILT_IN_FMAF, "__builtin_fmaf", "fmaf", - fn_type_f32_f32_to_f32, builtin_const); - define_builtin ("fmaf64", BUILT_IN_FMA, "__builtin_fma", "fma", - fn_type_f64_f64_to_f64, builtin_const); - - define_builtin ("fabsf32", BUILT_IN_FABSF, "__builtin_fabsf", "fabsf", - fn_type_f32_to_f32, builtin_const); - define_builtin ("fabsf64", BUILT_IN_FABS, "__builtin_fabs", "fabs", - fn_type_f64_to_f64, builtin_const); - - define_builtin ("minnumf32", BUILT_IN_FMINF, "__builtin_fminf", "fminf", - fn_type_f32_f32_to_f32, builtin_const); - define_builtin ("minnumf64", BUILT_IN_FMIN, "__builtin_fmin", "fmin", - fn_type_f64_f64_to_f64, builtin_const); - - define_builtin ("maxnumf32", BUILT_IN_FMAXF, "__builtin_fmaxf", "fmaxf", - fn_type_f32_f32_to_f32, builtin_const); - define_builtin ("maxnumf64", BUILT_IN_FMAX, "__builtin_fmax", "fmax", - fn_type_f64_f64_to_f64, builtin_const); - - define_builtin ("copysignf32", BUILT_IN_COPYSIGNF, "__builtin_copysignf", - "copysignf", fn_type_f32_f32_to_f32, builtin_const); - define_builtin ("copysignf64", BUILT_IN_COPYSIGN, "__builtin_copysign", - "copysign", fn_type_f64_f64_to_f64, builtin_const); - - define_builtin ("floorf32", BUILT_IN_FLOORF, "__builtin_floorf", "floorf", - fn_type_f32_to_f32, builtin_const); - define_builtin ("floorf64", BUILT_IN_FLOOR, "__builtin_floor", "floor", - fn_type_f64_to_f64, builtin_const); - - define_builtin ("ceilf32", BUILT_IN_CEILF, "__builtin_ceilf", "ceilf", - fn_type_f32_to_f32, builtin_const); - define_builtin ("ceilf64", BUILT_IN_CEIL, "__builtin_ceil", "ceil", - fn_type_f64_to_f64, builtin_const); - - define_builtin ("truncf32", BUILT_IN_TRUNCF, "__builtin_truncf", "truncf", - fn_type_f32_to_f32, builtin_const); - define_builtin ("truncf64", BUILT_IN_TRUNC, "__builtin_trunc", "trunc", - fn_type_f64_to_f64, builtin_const); - - define_builtin ("rintf32", BUILT_IN_RINTF, "__builtin_rintf", "rintf", - fn_type_f32_to_f32, builtin_const); - define_builtin ("rintf64", BUILT_IN_RINT, "__builtin_rint", "rint", - fn_type_f64_to_f64, builtin_const); - - define_builtin ("nearbyintf32", BUILT_IN_NEARBYINTF, "__builtin_nearbyintf", - "nearbyintf", fn_type_f32_to_f32, builtin_const); - define_builtin ("nearbyintf64", BUILT_IN_NEARBYINT, "__builtin_nearbyint", - "nearbyint", fn_type_f64_to_f64, builtin_const); - - define_builtin ("roundf32", BUILT_IN_ROUNDF, "__builtin_roundf", "roundf", - fn_type_f32_to_f32, builtin_const); - define_builtin ("roundf64", BUILT_IN_ROUND, "__builtin_round", "round", - fn_type_f64_to_f64, builtin_const); + string_type_node = build_pointer_type (char_type_node); + const_string_type_node = build_pointer_type ( + build_qualified_type (char_type_node, TYPE_QUAL_CONST)); + + if (strcmp (UINTMAX_TYPE, "unsigned int") == 0) + { + intmax_type_node = integer_type_node; + uintmax_type_node = unsigned_type_node; + } + else if (strcmp (UINTMAX_TYPE, "long unsigned int") == 0) + { + intmax_type_node = long_integer_type_node; + uintmax_type_node = long_unsigned_type_node; + } + else if (strcmp (UINTMAX_TYPE, "long long unsigned int") == 0) + { + intmax_type_node = long_long_integer_type_node; + uintmax_type_node = long_long_unsigned_type_node; + } + else + gcc_unreachable (); + + signed_size_type_node = signed_type_for (size_type_node); + wint_type_node = unsigned_type_node; + pid_type_node = integer_type_node; } +/** + * Define all builtin types in the `builtin_types` array + */ void -BuiltinsContext::setup_atomic_fns () +BuiltinsContext::define_builtin_types () { - auto atomic_store_type - = build_varargs_function_type_list (void_type_node, NULL_TREE); - auto atomic_load_type = [] (tree ret_type_node) { - return build_function_type_list (ret_type_node, - ptr_type_node, // const_ptr_type_node? - integer_type_node, NULL_TREE); + // This is taken directly from the D frontend's handling of builtins + auto va_list_ref_type_node = build_reference_type (va_list_type_node); + auto va_list_arg_type_node = va_list_type_node; + + build_c_type_nodes (); + + auto builtin_type_for_size = [] (int size, bool unsignedp) { + tree type = lang_hooks.types.type_for_size (size, unsignedp); + return type ? type : error_mark_node; }; - // FIXME: These should be the definition for the generic version of the - // atomic_store builtins, but I cannot get them to work properly. Revisit - // later. define_builtin ("atomic_store", BUILT_IN_ATOMIC_STORE, - // "__atomic_store", NULL, - // atomic_store_type, 0); - // define_builtin ("atomic_store_n", BUILT_IN_ATOMIC_STORE_N, - // "__atomic_store_n", - // NULL, atomic_store_type, 0); - - define_builtin ("atomic_store_1", BUILT_IN_ATOMIC_STORE_1, "__atomic_store_1", - NULL, atomic_store_type, 0); - define_builtin ("atomic_store_2", BUILT_IN_ATOMIC_STORE_2, "__atomic_store_2", - NULL, atomic_store_type, 0); - define_builtin ("atomic_store_4", BUILT_IN_ATOMIC_STORE_4, "__atomic_store_4", - NULL, atomic_store_type, 0); - define_builtin ("atomic_store_8", BUILT_IN_ATOMIC_STORE_8, "__atomic_store_8", - NULL, atomic_store_type, 0); - define_builtin ("atomic_store_16", BUILT_IN_ATOMIC_STORE_16, - "__atomic_store_16", NULL, atomic_store_type, 0); - - define_builtin ("atomic_load_1", BUILT_IN_ATOMIC_LOAD_1, "__atomic_load_1", - NULL, atomic_load_type (integer_type_node), 0); - define_builtin ("atomic_load_2", BUILT_IN_ATOMIC_LOAD_2, "__atomic_load_2", - NULL, atomic_load_type (integer_type_node), 0); - define_builtin ("atomic_load_4", BUILT_IN_ATOMIC_LOAD_4, "__atomic_load_4", - NULL, atomic_load_type (integer_type_node), 0); - define_builtin ("atomic_load_8", BUILT_IN_ATOMIC_LOAD_8, "__atomic_load_8", - NULL, atomic_load_type (integer_type_node), 0); +#define DEF_PRIMITIVE_TYPE(ENUM, VALUE) builtin_types[ENUM] = VALUE; +#define DEF_FUNCTION_TYPE_0(ENUM, RETURN) \ + define_function_type (ENUM, RETURN, 0, 0); +#define DEF_FUNCTION_TYPE_1(ENUM, RETURN, A1) \ + define_function_type (ENUM, RETURN, 0, 1, A1); +#define DEF_FUNCTION_TYPE_2(ENUM, RETURN, A1, A2) \ + define_function_type (ENUM, RETURN, 0, 2, A1, A2); +#define DEF_FUNCTION_TYPE_3(ENUM, RETURN, A1, A2, A3) \ + define_function_type (ENUM, RETURN, 0, 3, A1, A2, A3); +#define DEF_FUNCTION_TYPE_4(ENUM, RETURN, A1, A2, A3, A4) \ + define_function_type (ENUM, RETURN, 0, 4, A1, A2, A3, A4); +#define DEF_FUNCTION_TYPE_5(ENUM, RETURN, A1, A2, A3, A4, A5) \ + define_function_type (ENUM, RETURN, 0, 5, A1, A2, A3, A4, A5); +#define DEF_FUNCTION_TYPE_6(ENUM, RETURN, A1, A2, A3, A4, A5, A6) \ + define_function_type (ENUM, RETURN, 0, 6, A1, A2, A3, A4, A5, A6); +#define DEF_FUNCTION_TYPE_7(ENUM, RETURN, A1, A2, A3, A4, A5, A6, A7) \ + define_function_type (ENUM, RETURN, 0, 7, A1, A2, A3, A4, A5, A6, A7); +#define DEF_FUNCTION_TYPE_8(ENUM, RETURN, A1, A2, A3, A4, A5, A6, A7, A8) \ + define_function_type (ENUM, RETURN, 0, 8, A1, A2, A3, A4, A5, A6, A7, A8); +#define DEF_FUNCTION_TYPE_9(ENUM, RETURN, A1, A2, A3, A4, A5, A6, A7, A8, A9) \ + define_function_type (ENUM, RETURN, 0, 9, A1, A2, A3, A4, A5, A6, A7, A8, A9); +#define DEF_FUNCTION_TYPE_10(ENUM, RETURN, A1, A2, A3, A4, A5, A6, A7, A8, A9, \ + A10) \ + define_function_type (ENUM, RETURN, 0, 10, A1, A2, A3, A4, A5, A6, A7, A8, \ + A9, A10); +#define DEF_FUNCTION_TYPE_11(ENUM, RETURN, A1, A2, A3, A4, A5, A6, A7, A8, A9, \ + A10, A11) \ + define_function_type (ENUM, RETURN, 0, 11, A1, A2, A3, A4, A5, A6, A7, A8, \ + A9, A10, A11); +#define DEF_FUNCTION_TYPE_VAR_0(ENUM, RETURN) \ + define_function_type (ENUM, RETURN, 1, 0); +#define DEF_FUNCTION_TYPE_VAR_1(ENUM, RETURN, A1) \ + define_function_type (ENUM, RETURN, 1, 1, A1); +#define DEF_FUNCTION_TYPE_VAR_2(ENUM, RETURN, A1, A2) \ + define_function_type (ENUM, RETURN, 1, 2, A1, A2); +#define DEF_FUNCTION_TYPE_VAR_3(ENUM, RETURN, A1, A2, A3) \ + define_function_type (ENUM, RETURN, 1, 3, A1, A2, A3); +#define DEF_FUNCTION_TYPE_VAR_4(ENUM, RETURN, A1, A2, A3, A4) \ + define_function_type (ENUM, RETURN, 1, 4, A1, A2, A3, A4); +#define DEF_FUNCTION_TYPE_VAR_5(ENUM, RETURN, A1, A2, A3, A4, A5) \ + define_function_type (ENUM, RETURN, 1, 5, A1, A2, A3, A4, A5); +#define DEF_FUNCTION_TYPE_VAR_6(ENUM, RETURN, A1, A2, A3, A4, A5, A6) \ + define_function_type (ENUM, RETURN, 1, 6, A1, A2, A3, A4, A5, A6); +#define DEF_FUNCTION_TYPE_VAR_7(ENUM, RETURN, A1, A2, A3, A4, A5, A6, A7) \ + define_function_type (ENUM, RETURN, 1, 7, A1, A2, A3, A4, A5, A6, A7); +#define DEF_FUNCTION_TYPE_VAR_11(ENUM, RETURN, A1, A2, A3, A4, A5, A6, A7, A8, \ + A9, A10, A11) \ + define_function_type (ENUM, RETURN, 1, 11, A1, A2, A3, A4, A5, A6, A7, A8, \ + A9, A10, A11); +#define DEF_POINTER_TYPE(ENUM, TYPE) \ + builtin_types[ENUM] = build_pointer_type (builtin_types[TYPE]); + +#include "builtin-types.def" + +#undef DEF_PRIMITIVE_TYPE +#undef DEF_FUNCTION_TYPE_1 +#undef DEF_FUNCTION_TYPE_2 +#undef DEF_FUNCTION_TYPE_3 +#undef DEF_FUNCTION_TYPE_4 +#undef DEF_FUNCTION_TYPE_5 +#undef DEF_FUNCTION_TYPE_6 +#undef DEF_FUNCTION_TYPE_7 +#undef DEF_FUNCTION_TYPE_8 +#undef DEF_FUNCTION_TYPE_9 +#undef DEF_FUNCTION_TYPE_10 +#undef DEF_FUNCTION_TYPE_11 +#undef DEF_FUNCTION_TYPE_VAR_0 +#undef DEF_FUNCTION_TYPE_VAR_1 +#undef DEF_FUNCTION_TYPE_VAR_2 +#undef DEF_FUNCTION_TYPE_VAR_3 +#undef DEF_FUNCTION_TYPE_VAR_4 +#undef DEF_FUNCTION_TYPE_VAR_5 +#undef DEF_FUNCTION_TYPE_VAR_6 +#undef DEF_FUNCTION_TYPE_VAR_7 +#undef DEF_FUNCTION_TYPE_VAR_11 +#undef DEF_POINTER_TYPE + + builtin_types[Type::BT_LAST] = NULL_TREE; } +/** + * Define all builtin attributes in the `builtin_types` array + */ void -BuiltinsContext::setup () +BuiltinsContext::define_builtin_attributes () + { - setup_math_fns (); - setup_overflow_fns (); - setup_atomic_fns (); - - define_builtin ("unreachable", BUILT_IN_UNREACHABLE, "__builtin_unreachable", - NULL, build_function_type (void_type_node, void_list_node), - builtin_const | builtin_noreturn); - - define_builtin ("abort", BUILT_IN_ABORT, "__builtin_abort", "abort", - build_function_type (void_type_node, void_list_node), - builtin_const | builtin_noreturn); - - define_builtin ("breakpoint", BUILT_IN_TRAP, "__builtin_trap", "breakpoint", - build_function_type (void_type_node, void_list_node), - builtin_const | builtin_noreturn); - - define_builtin ("expect", BUILT_IN_EXPECT, "__builtin_expect", "expect", - build_function_type_list (long_integer_type_node, - long_integer_type_node, - long_integer_type_node, NULL_TREE), - builtin_const); - - define_builtin ("memcpy", BUILT_IN_MEMCPY, "__builtin_memcpy", "memcpy", - build_function_type_list (build_pointer_type (void_type_node), - build_pointer_type (void_type_node), - build_pointer_type (void_type_node), - size_type_node, NULL_TREE), - 0); - - define_builtin ("memset", BUILT_IN_MEMSET, "__builtin_memset", "memset", - build_function_type_list (void_type_node, ptr_type_node, - integer_type_node, size_type_node, - NULL_TREE), - 0); - - define_builtin ("prefetch", BUILT_IN_PREFETCH, "__builtin_prefetch", - "prefetch", - build_varargs_function_type_list ( - build_pointer_type (const_ptr_type_node), NULL_TREE), - builtin_const); + auto *built_in_attributes = builtin_attributes; + +#define DEF_ATTR_NULL_TREE(ENUM) built_in_attributes[(int) ENUM] = NULL_TREE; +#define DEF_ATTR_INT(ENUM, VALUE) \ + built_in_attributes[ENUM] = build_int_cst (NULL_TREE, VALUE); +#define DEF_ATTR_STRING(ENUM, VALUE) \ + built_in_attributes[ENUM] = build_string (strlen (VALUE), VALUE); +#define DEF_ATTR_IDENT(ENUM, STRING) \ + built_in_attributes[ENUM] = get_identifier (STRING); +#define DEF_ATTR_TREE_LIST(ENUM, PURPOSE, VALUE, CHAIN) \ + built_in_attributes[ENUM] \ + = tree_cons (built_in_attributes[PURPOSE], built_in_attributes[VALUE], \ + built_in_attributes[CHAIN]); +#include "builtin-attrs.def" +#undef DEF_ATTR_NULL_TREE +#undef DEF_ATTR_INT +#undef DEF_ATTR_STRING +#undef DEF_ATTR_IDENT +#undef DEF_ATTR_TREE_LIST } -static void -handle_flags (tree decl, int flags) +/** + * Define all builtin functions during the first initialization of the + * `BuiltinsContext`. + */ +void +BuiltinsContext::define_builtins () { - if (flags & builtin_const) - TREE_READONLY (decl) = 1; - if (flags & builtin_noreturn) - TREE_READONLY (decl) = 1; - if (flags & builtin_novops) - DECL_IS_NOVOPS (decl) = 1; + auto *built_in_attributes = builtin_attributes; + auto build_builtin = [this] (built_in_function fn_code, const char *fn_name, + built_in_class fn_class, tree fn_type, bool both, + bool fallback, tree attributes, bool implicit) { + if (fn_type == error_mark_node) + return; + + static auto to_skip = strlen ("__builtin_"); + + auto libname = fn_name + to_skip; + auto decl = add_builtin_function (fn_name, fn_type, fn_code, fn_class, + fallback ? libname : NULL, attributes); + + set_builtin_decl (fn_code, decl, implicit); + + builtin_functions.insert ({std::string (fn_name), decl}); + }; + +#define DEF_BUILTIN(ENUM, NAME, CLASS, TYPE, LIBTYPE, BOTH_P, FALLBACK_P, \ + NONANSI_P, ATTRS, IMPLICIT, COND) \ + if (NAME && COND) \ + build_builtin (ENUM, NAME, CLASS, builtin_types[TYPE], BOTH_P, FALLBACK_P, \ + built_in_attributes[ATTRS], IMPLICIT); +#include "builtins.def" +#undef DEF_BUILTIN } +/** + * Register direct mappings between Rust functions and GCC builtins + */ void -BuiltinsContext::define_builtin (const std::string rust_name, - built_in_function bcode, const char *name, - const char *libname, tree fntype, int flags) +BuiltinsContext::register_rust_mappings () { - tree decl = add_builtin_function (name, fntype, bcode, BUILT_IN_NORMAL, - libname, NULL_TREE); - handle_flags (decl, flags); - set_builtin_decl (bcode, decl, true); - - this->builtin_functions_[name] = decl; - if (libname != NULL) - { - decl = add_builtin_function (libname, fntype, bcode, BUILT_IN_NORMAL, - NULL, NULL_TREE); - handle_flags (decl, flags); + rust_intrinsic_to_gcc_builtin = { + {"sinf32", "__builtin_sinf"}, + {"sqrtf32", "__builtin_sqrtf"}, + {"sqrtf64", "__builtin_sqrt"}, + {"unreachable", "__builtin_unreachable"}, + {"abort", "__builtin_abort"}, + {"sinf64", "__builtin_sin"}, + {"cosf32", "__builtin_cosf"}, + {"cosf64", "__builtin_cos"}, + {"powf32", "__builtin_powf"}, + {"powf64", "__builtin_pow"}, + {"expf32", "__builtin_expf"}, + {"expf64", "__builtin_exp"}, + {"exp2f32", "__builtin_exp2f"}, + {"exp2f64", "__builtin_exp2"}, + {"logf32", "__builtin_logf"}, + {"logf64", "__builtin_log"}, + {"log10f32", "__builtin_log10f"}, + {"log10f64", "__builtin_log10"}, + {"log2f32", "__builtin_log2f"}, + {"log2f64", "__builtin_log2"}, + {"fmaf32", "__builtin_fmaf"}, + {"fmaf64", "__builtin_fma"}, + {"fabsf32", "__builtin_fabsf"}, + {"fabsf64", "__builtin_fabs"}, + {"minnumf32", "__builtin_fminf"}, + {"minnumf64", "__builtin_fmin"}, + {"maxnumf32", "__builtin_fmaxf"}, + {"maxnumf64", "__builtin_fmax"}, + {"copysignf32", "__builtin_copysignf"}, + {"copysignf64", "__builtin_copysign"}, + {"floorf32", "__builtin_floorf"}, + {"floorf64", "__builtin_floor"}, + {"ceilf32", "__builtin_ceilf"}, + {"ceilf64", "__builtin_ceil"}, + {"truncf32", "__builtin_truncf"}, + {"truncf64", "__builtin_trunc"}, + {"rintf32", "__builtin_rintf"}, + {"rintf64", "__builtin_rint"}, + {"nearbyintf32", "__builtin_nearbyintf"}, + {"nearbyintf64", "__builtin_nearbyint"}, + {"roundf32", "__builtin_roundf"}, + {"roundf64", "__builtin_round"}, + }; +} - this->builtin_functions_[libname] = decl; - } +void +BuiltinsContext::setup () +{ + define_builtin_types (); + define_builtin_attributes (); + define_builtins (); - rust_intrinsic_to_gcc_builtin[rust_name] = name; + register_rust_mappings (); } bool BuiltinsContext::lookup_gcc_builtin (const std::string &name, tree *builtin) { - auto it = builtin_functions_.find (name); - if (it == builtin_functions_.end ()) + auto it = builtin_functions.find (name); + if (it == builtin_functions.end ()) return false; *builtin = it->second; diff --git a/gcc/rust/backend/rust-builtins.h b/gcc/rust/backend/rust-builtins.h index c2825107faf..5052edad51e 100644 --- a/gcc/rust/backend/rust-builtins.h +++ b/gcc/rust/backend/rust-builtins.h @@ -21,6 +21,7 @@ #include "rust-tree.h" #include "langhooks.h" #include "tree.h" +#include "selftest.h" namespace Rust { namespace Compile { @@ -75,6 +76,7 @@ namespace Compile { // _ => return None, // }; // Some(cx.get_intrinsic(&llvm_name)) + class BuiltinsContext { public: @@ -83,6 +85,110 @@ public: bool lookup_simple_builtin (const std::string &name, tree *builtin); private: + enum Type + { +#define DEF_PRIMITIVE_TYPE(NAME, V) NAME, +#define DEF_FUNCTION_TYPE_0(NAME, R) NAME, +#define DEF_FUNCTION_TYPE_1(NAME, R, A1) NAME, +#define DEF_FUNCTION_TYPE_2(NAME, R, A1, A2) NAME, +#define DEF_FUNCTION_TYPE_3(NAME, R, A1, A2, A3) NAME, +#define DEF_FUNCTION_TYPE_4(NAME, R, A1, A2, A3, A4) NAME, +#define DEF_FUNCTION_TYPE_5(NAME, R, A1, A2, A3, A4, A5) NAME, +#define DEF_FUNCTION_TYPE_6(NAME, R, A1, A2, A3, A4, A5, A6) NAME, +#define DEF_FUNCTION_TYPE_7(NAME, R, A1, A2, A3, A4, A5, A6, A7) NAME, +#define DEF_FUNCTION_TYPE_8(NAME, R, A1, A2, A3, A4, A5, A6, A7, A8) NAME, +#define DEF_FUNCTION_TYPE_9(NAME, R, A1, A2, A3, A4, A5, A6, A7, A8, A9) NAME, +#define DEF_FUNCTION_TYPE_10(NAME, R, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10) \ + NAME, +#define DEF_FUNCTION_TYPE_11(NAME, R, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, \ + A11) \ + NAME, +#define DEF_FUNCTION_TYPE_VAR_0(NAME, R) NAME, +#define DEF_FUNCTION_TYPE_VAR_1(NAME, R, A1) NAME, +#define DEF_FUNCTION_TYPE_VAR_2(NAME, R, A1, A2) NAME, +#define DEF_FUNCTION_TYPE_VAR_3(NAME, R, A1, A2, A3) NAME, +#define DEF_FUNCTION_TYPE_VAR_4(NAME, R, A1, A2, A3, A4) NAME, +#define DEF_FUNCTION_TYPE_VAR_5(NAME, R, A1, A2, A3, A4, A5) NAME, +#define DEF_FUNCTION_TYPE_VAR_6(NAME, R, A1, A2, A3, A4, A5, A6) NAME, +#define DEF_FUNCTION_TYPE_VAR_7(NAME, R, A1, A2, A3, A4, A5, A6, A7) NAME, +#define DEF_FUNCTION_TYPE_VAR_11(NAME, R, A1, A2, A3, A4, A5, A6, A7, A8, A9, \ + A10, A11) \ + NAME, +#define DEF_POINTER_TYPE(NAME, TYPE) NAME, + +#include "builtin-types.def" + +#undef DEF_PRIMITIVE_TYPE +#undef DEF_FUNCTION_TYPE_0 +#undef DEF_FUNCTION_TYPE_1 +#undef DEF_FUNCTION_TYPE_2 +#undef DEF_FUNCTION_TYPE_3 +#undef DEF_FUNCTION_TYPE_4 +#undef DEF_FUNCTION_TYPE_5 +#undef DEF_FUNCTION_TYPE_6 +#undef DEF_FUNCTION_TYPE_7 +#undef DEF_FUNCTION_TYPE_8 +#undef DEF_FUNCTION_TYPE_9 +#undef DEF_FUNCTION_TYPE_10 +#undef DEF_FUNCTION_TYPE_11 +#undef DEF_FUNCTION_TYPE_VAR_0 +#undef DEF_FUNCTION_TYPE_VAR_1 +#undef DEF_FUNCTION_TYPE_VAR_2 +#undef DEF_FUNCTION_TYPE_VAR_3 +#undef DEF_FUNCTION_TYPE_VAR_4 +#undef DEF_FUNCTION_TYPE_VAR_5 +#undef DEF_FUNCTION_TYPE_VAR_6 +#undef DEF_FUNCTION_TYPE_VAR_7 +#undef DEF_FUNCTION_TYPE_VAR_11 +#undef DEF_POINTER_TYPE + + BT_LAST, + }; + + enum Attr + { +#define DEF_ATTR_NULL_TREE(ENUM) ENUM, +#define DEF_ATTR_INT(ENUM, VALUE) ENUM, +#define DEF_ATTR_STRING(ENUM, VALUE) ENUM, +#define DEF_ATTR_IDENT(ENUM, STRING) ENUM, +#define DEF_ATTR_TREE_LIST(ENUM, PURPOSE, VALUE, CHAIN) ENUM, + +#include "builtin-attrs.def" + +#undef DEF_ATTR_NULL_TREE +#undef DEF_ATTR_INT +#undef DEF_ATTR_STRING +#undef DEF_ATTR_IDENT +#undef DEF_ATTR_TREE_LIST + + ATTR_LAST, + }; + + /** + * All builtin types, as defined in `builtin-types.def` + * + * This array is filled by the `define_builtin_types` method, during the first + * initialization of the `BuiltinsContext` + */ + tree builtin_types[Type::BT_LAST + 1]; + + /** + * Similarly, this array contains all builtin attributes, as defined in + * `builtin-attr.def` + * + * This array is filled by the `define_builtin_attributes` method, during the + * first initialization of the `BuiltinsContext` + */ + tree builtin_attributes[Attr::ATTR_LAST + 1]; + + void define_function_type (Type def, Type ret, bool is_variadic, size_t n, + ...); + void define_builtin_types (); + void define_builtin_attributes (); + void define_builtins (); + + void register_rust_mappings (); + BuiltinsContext (); void setup_overflow_fns (); @@ -91,20 +197,10 @@ private: void setup (); - // Define a builtin function. BCODE is the builtin function code - // defined by builtins.def. NAME is the name of the builtin function. - // LIBNAME is the name of the corresponding library function, and is - // NULL if there isn't one. FNTYPE is the type of the function. - // CONST_P is true if the function has the const attribute. - // NORETURN_P is true if the function has the noreturn attribute. - void define_builtin (const std::string rust_name, built_in_function bcode, - const char *name, const char *libname, tree fntype, - int flags); - bool lookup_gcc_builtin (const std::string &name, tree *builtin); // A mapping of the GCC built-ins exposed to GCC Rust. - std::map builtin_functions_; + std::map builtin_functions; std::map rust_intrinsic_to_gcc_builtin; }; diff --git a/gcc/rust/backend/rust-compile-intrinsic.cc b/gcc/rust/backend/rust-compile-intrinsic.cc index feaf74dff7b..49ee4c0ead9 100644 --- a/gcc/rust/backend/rust-compile-intrinsic.cc +++ b/gcc/rust/backend/rust-compile-intrinsic.cc @@ -29,6 +29,8 @@ #include "print-tree.h" #include "fold-const.h" #include "langhooks.h" +#include "rust-gcc.h" +#include "rust-constexpr.h" #include "print-tree.h" @@ -243,6 +245,14 @@ static const std::mapget_identifier (), &builtin)) return builtin; @@ -653,17 +664,17 @@ op_with_overflow_inner (Context *ctx, TyTy::FnType *fntype, tree_code op) switch (op) { case PLUS_EXPR: - BuiltinsContext::get ().lookup_simple_builtin ("add_overflow", + BuiltinsContext::get ().lookup_simple_builtin ("__builtin_add_overflow", &overflow_builtin); break; case MINUS_EXPR: - BuiltinsContext::get ().lookup_simple_builtin ("sub_overflow", + BuiltinsContext::get ().lookup_simple_builtin ("__builtin_sub_overflow", &overflow_builtin); break; case MULT_EXPR: - BuiltinsContext::get ().lookup_simple_builtin ("mul_overflow", + BuiltinsContext::get ().lookup_simple_builtin ("__builtin_mul_overflow", &overflow_builtin); break; @@ -749,8 +760,8 @@ copy_handler_inner (Context *ctx, TyTy::FnType *fntype, bool overlaps) = build2 (MULT_EXPR, size_type_node, TYPE_SIZE_UNIT (param_type), count); tree memcpy_raw = nullptr; - BuiltinsContext::get ().lookup_simple_builtin (overlaps ? "memmove" - : "memcpy", + BuiltinsContext::get ().lookup_simple_builtin (overlaps ? "__builtin_memmove" + : "__builtin_memcpy", &memcpy_raw); rust_assert (memcpy_raw); auto memcpy = build_fold_addr_expr_loc (UNKNOWN_LOCATION, memcpy_raw); @@ -797,18 +808,34 @@ prefetch_data_handler (Context *ctx, TyTy::FnType *fntype, Prefetch kind) enter_intrinsic_block (ctx, fndecl); auto addr = Backend::var_expression (args[0], UNDEF_LOCATION); - auto locality = Backend::var_expression (args[1], UNDEF_LOCATION); + + // The core library technically allows you to pass any i32 value as a + // locality, but LLVM will then complain if the value cannot be constant + // evaluated. For now, we ignore the locality argument and instead always + // pass `3` (the most restrictive value). This allows us to still have + // prefetch behavior, just not as granular as expected. In future Rust + // versions, we hope that prefetch intrinsics will be split up according to + // locality, similarly to atomic intrinsics. + // The solution is to try and perform constant folding for the locality + // argument, or instead of creating a new function definition, modify the call + // site directly This has the bad side-effect of creating warnings about + // `unused name - locality`, which we hack away here: + // TODO: Take care of handling locality properly + Backend::var_expression (args[1], UNDEF_LOCATION); + auto rw_flag = make_unsigned_long_tree (kind == Prefetch::Write ? 1 : 0); auto prefetch_raw = NULL_TREE; - auto ok - = BuiltinsContext::get ().lookup_simple_builtin ("prefetch", &prefetch_raw); + auto ok = BuiltinsContext::get ().lookup_simple_builtin ("__builtin_prefetch", + &prefetch_raw); rust_assert (ok); auto prefetch = build_fold_addr_expr_loc (UNKNOWN_LOCATION, prefetch_raw); - auto prefetch_call - = Backend::call_expression (prefetch, {addr, rw_flag, locality}, nullptr, - UNDEF_LOCATION); + auto prefetch_call = Backend::call_expression (prefetch, + {addr, rw_flag, + // locality arg + make_unsigned_long_tree (3)}, + nullptr, UNDEF_LOCATION); TREE_READONLY (prefetch_call) = 0; TREE_SIDE_EFFECTS (prefetch_call) = 1; @@ -833,7 +860,7 @@ build_atomic_builtin_name (const std::string &prefix, location_t locus, // TODO: Can we maybe get the generic version (atomic_store_n) to work... This // would be so much better - std::string result = prefix; + std::string result = "__" + prefix; // + "n"; auto type_name = operand_type->get_name (); if (type_name == "usize" || type_name == "isize") @@ -843,6 +870,13 @@ build_atomic_builtin_name (const std::string &prefix, location_t locus, return ""; } + if (type_name.at (0) == 'i') + { + rust_sorry_at (locus, "atomics are not yet supported for signed " + "integer types (i8, i16, i32, i64, i128)"); + return ""; + } + auto type_size_str = allowed_types.find (type_name); if (!check_for_basic_integer_type ("atomic", locus, operand_type)) @@ -970,6 +1004,7 @@ atomic_load_handler_inner (Context *ctx, TyTy::FnType *fntype, int ordering) TREE_SIDE_EFFECTS (load_call) = 1; ctx->add_statement (return_statement); + finalize_intrinsic_block (ctx, fndecl); return fndecl; @@ -1060,7 +1095,8 @@ uninit_handler (Context *ctx, TyTy::FnType *fntype) // BUILTIN size_of FN BODY BEGIN tree memset_builtin = error_mark_node; - BuiltinsContext::get ().lookup_simple_builtin ("memset", &memset_builtin); + BuiltinsContext::get ().lookup_simple_builtin ("__builtin_memset", + &memset_builtin); rust_assert (memset_builtin != error_mark_node); // call memset with 0x01 and size of the thing see @@ -1123,7 +1159,8 @@ move_val_init_handler (Context *ctx, TyTy::FnType *fntype) tree size = TYPE_SIZE_UNIT (template_parameter_type); tree memcpy_builtin = error_mark_node; - BuiltinsContext::get ().lookup_simple_builtin ("memcpy", &memcpy_builtin); + BuiltinsContext::get ().lookup_simple_builtin ("__builtin_memcpy", + &memcpy_builtin); rust_assert (memcpy_builtin != error_mark_node); src = build_fold_addr_expr_loc (BUILTINS_LOCATION, src); @@ -1157,7 +1194,8 @@ expect_handler_inner (Context *ctx, TyTy::FnType *fntype, bool likely) compile_fn_params (ctx, fntype, fndecl, ¶m_vars); tree expr = Backend::var_expression (param_vars[0], UNDEF_LOCATION); tree expect_fn_raw = nullptr; - BuiltinsContext::get ().lookup_simple_builtin ("expect", &expect_fn_raw); + BuiltinsContext::get ().lookup_simple_builtin ("__builtin_expect", + &expect_fn_raw); rust_assert (expect_fn_raw); auto expect_fn = build_fold_addr_expr_loc (BUILTINS_LOCATION, expect_fn_raw); diff --git a/gcc/rust/rust-attribs.cc b/gcc/rust/rust-attribs.cc new file mode 100644 index 00000000000..134dcf9eeca --- /dev/null +++ b/gcc/rust/rust-attribs.cc @@ -0,0 +1,370 @@ +/* rust-attribs.c -- Rust attributes handling. + Copyright (C) 2015-2023 Free Software Foundation, Inc. + +GCC is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 3, or (at your option) +any later version. + +GCC is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GCC; see the file COPYING3. If not see +. */ + +#include "config.h" +#include "system.h" +#include "coretypes.h" + +#include "tree.h" +#include "diagnostic.h" +#include "tm.h" +#include "cgraph.h" +#include "toplev.h" +#include "target.h" +#include "common/common-target.h" +#include "stringpool.h" +#include "attribs.h" +#include "varasm.h" +#include "fold-const.h" +#include "opts.h" + +/* Heavily based on the D frontend Only a subset of the attributes found in the + * D frontend have been pulled, the goal being to have the builtin function + * correctly setup. It's possible we may need to add extra attributes in the + * future. + */ + +extern const attribute_spec grs_langhook_common_attribute_table[]; + +/* Internal attribute handlers for built-in functions. */ +static tree +handle_noreturn_attribute (tree *, tree, tree, int, bool *); +static tree +handle_leaf_attribute (tree *, tree, tree, int, bool *); +static tree +handle_const_attribute (tree *, tree, tree, int, bool *); +static tree +handle_malloc_attribute (tree *, tree, tree, int, bool *); +static tree +handle_pure_attribute (tree *, tree, tree, int, bool *); +static tree +handle_novops_attribute (tree *, tree, tree, int, bool *); +static tree +handle_nonnull_attribute (tree *, tree, tree, int, bool *); +static tree +handle_nothrow_attribute (tree *, tree, tree, int, bool *); +static tree +handle_type_generic_attribute (tree *, tree, tree, int, bool *); +static tree +handle_transaction_pure_attribute (tree *, tree, tree, int, bool *); +static tree +handle_returns_twice_attribute (tree *, tree, tree, int, bool *); +static tree +handle_fnspec_attribute (tree *, tree, tree, int, bool *); +static tree +handle_omp_declare_simd_attribute (tree *, tree, tree, int, bool *); + +/* Helper to define attribute exclusions. */ +#define ATTR_EXCL(name, function, type, variable) \ + { \ + name, function, type, variable \ + } + +static const struct attribute_spec::exclusions attr_noreturn_exclusions[] = { + // ATTR_EXCL ("alloc_size", true, true, true), + ATTR_EXCL ("const", true, true, true), + // ATTR_EXCL ("malloc", true, true, true), + ATTR_EXCL ("pure", true, true, true), + ATTR_EXCL ("returns_twice", true, true, true), + ATTR_EXCL (NULL, false, false, false), +}; + +static const struct attribute_spec::exclusions attr_returns_twice_exclusions[] + = { + ATTR_EXCL ("noreturn", true, true, true), + ATTR_EXCL (NULL, false, false, false), +}; + +static const struct attribute_spec::exclusions attr_const_pure_exclusions[] = { + // ATTR_EXCL ("alloc_size", true, true, true), + ATTR_EXCL ("const", true, true, true), + ATTR_EXCL ("noreturn", true, true, true), + ATTR_EXCL ("pure", true, true, true), ATTR_EXCL (NULL, false, false, false)}; + +/* Helper to define an attribute. */ +#define ATTR_SPEC(name, min_len, max_len, decl_req, type_req, fn_type_req, \ + affects_type_identity, handler, exclude) \ + { \ + name, min_len, max_len, decl_req, type_req, fn_type_req, \ + affects_type_identity, handler, exclude \ + } + +/* Table of machine-independent attributes. + For internal use (marking of built-ins) only. */ +const attribute_spec grs_langhook_common_attribute_table[] = { + ATTR_SPEC ("noreturn", 0, 0, true, false, false, false, + handle_noreturn_attribute, attr_noreturn_exclusions), + ATTR_SPEC ("leaf", 0, 0, true, false, false, false, handle_leaf_attribute, + NULL), + ATTR_SPEC ("const", 0, 0, true, false, false, false, handle_const_attribute, + attr_const_pure_exclusions), + ATTR_SPEC ("malloc", 0, 0, true, false, false, false, handle_malloc_attribute, + NULL), + ATTR_SPEC ("returns_twice", 0, 0, true, false, false, false, + handle_returns_twice_attribute, attr_returns_twice_exclusions), + ATTR_SPEC ("pure", 0, 0, true, false, false, false, handle_pure_attribute, + attr_const_pure_exclusions), + ATTR_SPEC ("nonnull", 0, -1, false, true, true, false, + handle_nonnull_attribute, NULL), + ATTR_SPEC ("nothrow", 0, 0, true, false, false, false, + handle_nothrow_attribute, NULL), + ATTR_SPEC ("transaction_pure", 0, 0, false, true, true, false, + handle_transaction_pure_attribute, NULL), + ATTR_SPEC ("no vops", 0, 0, true, false, false, false, + handle_novops_attribute, NULL), + ATTR_SPEC ("type generic", 0, 0, false, true, true, false, + handle_type_generic_attribute, NULL), + ATTR_SPEC ("fn spec", 1, 1, false, true, true, false, handle_fnspec_attribute, + NULL), + ATTR_SPEC ("omp declare simd", 0, -1, true, false, false, false, + handle_omp_declare_simd_attribute, NULL), + ATTR_SPEC (NULL, 0, 0, false, false, false, false, NULL, NULL), +}; + +/* Built-in attribute handlers. + These functions take the arguments: + (tree *node, tree name, tree args, int flags, bool *no_add_attrs) */ + +/* Handle a "noreturn" attribute; arguments as in + struct attribute_spec.handler. */ + +static tree +handle_noreturn_attribute (tree *node, tree, tree, int, bool *) +{ + tree type = TREE_TYPE (*node); + + if (TREE_CODE (*node) == FUNCTION_DECL) + TREE_THIS_VOLATILE (*node) = 1; + else if (TREE_CODE (type) == POINTER_TYPE + && TREE_CODE (TREE_TYPE (type)) == FUNCTION_TYPE) + TREE_TYPE (*node) = build_pointer_type ( + build_type_variant (TREE_TYPE (type), TYPE_READONLY (TREE_TYPE (type)), + 1)); + else + gcc_unreachable (); + + return NULL_TREE; +} + +/* Handle a "leaf" attribute; arguments as in + struct attribute_spec.handler. */ + +static tree +handle_leaf_attribute (tree *node, tree name, tree, int, bool *no_add_attrs) +{ + if (TREE_CODE (*node) != FUNCTION_DECL) + { + warning (OPT_Wattributes, "%qE attribute ignored", name); + *no_add_attrs = true; + } + if (!TREE_PUBLIC (*node)) + { + warning (OPT_Wattributes, "%qE attribute has no effect", name); + *no_add_attrs = true; + } + + return NULL_TREE; +} + +/* Handle a "const" attribute; arguments as in + struct attribute_spec.handler. */ + +static tree +handle_const_attribute (tree *node, tree, tree, int, bool *) +{ + tree type = TREE_TYPE (*node); + + if (TREE_CODE (*node) == FUNCTION_DECL) + TREE_READONLY (*node) = 1; + else if (TREE_CODE (type) == POINTER_TYPE + && TREE_CODE (TREE_TYPE (type)) == FUNCTION_TYPE) + TREE_TYPE (*node) = build_pointer_type ( + build_type_variant (TREE_TYPE (type), 1, + TREE_THIS_VOLATILE (TREE_TYPE (type)))); + else + gcc_unreachable (); + + return NULL_TREE; +} + +/* Handle a "malloc" attribute; arguments as in + struct attribute_spec.handler. */ + +tree +handle_malloc_attribute (tree *node, tree, tree, int, bool *) +{ + gcc_assert (TREE_CODE (*node) == FUNCTION_DECL + && POINTER_TYPE_P (TREE_TYPE (TREE_TYPE (*node)))); + DECL_IS_MALLOC (*node) = 1; + return NULL_TREE; +} + +/* Handle a "pure" attribute; arguments as in + struct attribute_spec.handler. */ + +static tree +handle_pure_attribute (tree *node, tree, tree, int, bool *) +{ + gcc_assert (TREE_CODE (*node) == FUNCTION_DECL); + DECL_PURE_P (*node) = 1; + return NULL_TREE; +} + +/* Handle a "no vops" attribute; arguments as in + struct attribute_spec.handler. */ + +static tree +handle_novops_attribute (tree *node, tree, tree, int, bool *) +{ + gcc_assert (TREE_CODE (*node) == FUNCTION_DECL); + DECL_IS_NOVOPS (*node) = 1; + return NULL_TREE; +} + +/* Helper for nonnull attribute handling; fetch the operand number + from the attribute argument list. */ + +static bool +get_nonnull_operand (tree arg_num_expr, unsigned HOST_WIDE_INT *valp) +{ + /* Verify the arg number is a constant. */ + if (!tree_fits_uhwi_p (arg_num_expr)) + return false; + + *valp = TREE_INT_CST_LOW (arg_num_expr); + return true; +} + +/* Handle the "nonnull" attribute. */ + +static tree +handle_nonnull_attribute (tree *node, tree, tree args, int, bool *) +{ + tree type = *node; + + /* If no arguments are specified, all pointer arguments should be + non-null. Verify a full prototype is given so that the arguments + will have the correct types when we actually check them later. + Avoid diagnosing type-generic built-ins since those have no + prototype. */ + if (!args) + { + gcc_assert (prototype_p (type) || !TYPE_ATTRIBUTES (type) + || lookup_attribute ("type generic", TYPE_ATTRIBUTES (type))); + + return NULL_TREE; + } + + /* Argument list specified. Verify that each argument number references + a pointer argument. */ + for (; args; args = TREE_CHAIN (args)) + { + tree argument; + unsigned HOST_WIDE_INT arg_num = 0, ck_num; + + if (!get_nonnull_operand (TREE_VALUE (args), &arg_num)) + gcc_unreachable (); + + argument = TYPE_ARG_TYPES (type); + if (argument) + { + for (ck_num = 1;; ck_num++) + { + if (!argument || ck_num == arg_num) + break; + argument = TREE_CHAIN (argument); + } + + gcc_assert (argument + && TREE_CODE (TREE_VALUE (argument)) == POINTER_TYPE); + } + } + + return NULL_TREE; +} + +/* Handle a "nothrow" attribute; arguments as in + struct attribute_spec.handler. */ + +static tree +handle_nothrow_attribute (tree *node, tree, tree, int, bool *) +{ + gcc_assert (TREE_CODE (*node) == FUNCTION_DECL); + TREE_NOTHROW (*node) = 1; + return NULL_TREE; +} + +/* Handle a "type generic" attribute; arguments as in + struct attribute_spec.handler. */ + +static tree +handle_type_generic_attribute (tree *node, tree, tree, int, bool *) +{ + /* Ensure we have a function type. */ + gcc_assert (TREE_CODE (*node) == FUNCTION_TYPE); + + /* Ensure we have a variadic function. */ + gcc_assert (!prototype_p (*node) || stdarg_p (*node)); + + return NULL_TREE; +} + +/* Handle a "transaction_pure" attribute; arguments as in + struct attribute_spec.handler. */ + +static tree +handle_transaction_pure_attribute (tree *node, tree, tree, int, bool *) +{ + /* Ensure we have a function type. */ + gcc_assert (TREE_CODE (*node) == FUNCTION_TYPE); + + return NULL_TREE; +} + +/* Handle a "returns_twice" attribute; arguments as in + struct attribute_spec.handler. */ + +static tree +handle_returns_twice_attribute (tree *node, tree, tree, int, bool *) +{ + gcc_assert (TREE_CODE (*node) == FUNCTION_DECL); + + DECL_IS_RETURNS_TWICE (*node) = 1; + + return NULL_TREE; +} + +/* Handle a "fn spec" attribute; arguments as in + struct attribute_spec.handler. */ + +tree +handle_fnspec_attribute (tree *, tree, tree args, int, bool *) +{ + gcc_assert (args && TREE_CODE (TREE_VALUE (args)) == STRING_CST + && !TREE_CHAIN (args)); + return NULL_TREE; +} + +/* Handle an "omp declare simd" attribute; arguments as in + struct attribute_spec.handler. */ + +tree +handle_omp_declare_simd_attribute (tree *node, tree, tree, int, bool *) +{ + gcc_assert (TREE_CODE (*node) == FUNCTION_DECL); + return NULL_TREE; +} diff --git a/gcc/rust/rust-gcc.cc b/gcc/rust/rust-gcc.cc index 580bda7f00a..f17e19a2dfc 100644 --- a/gcc/rust/rust-gcc.cc +++ b/gcc/rust/rust-gcc.cc @@ -1131,20 +1131,20 @@ fetch_overflow_builtins (ArithmeticOrLogicalOperator op) switch (op) { case ArithmeticOrLogicalOperator::ADD: - builtin_ctx.lookup_simple_builtin ("add_overflow", &builtin); + builtin_ctx.lookup_simple_builtin ("__builtin_add_overflow", &builtin); break; case ArithmeticOrLogicalOperator::SUBTRACT: - builtin_ctx.lookup_simple_builtin ("sub_overflow", &builtin); + builtin_ctx.lookup_simple_builtin ("__builtin_sub_overflow", &builtin); break; case ArithmeticOrLogicalOperator::MULTIPLY: - builtin_ctx.lookup_simple_builtin ("mul_overflow", &builtin); + builtin_ctx.lookup_simple_builtin ("__builtin_mul_overflow", &builtin); break; default: rust_unreachable (); break; }; - builtin_ctx.lookup_simple_builtin ("abort", &abort); + builtin_ctx.lookup_simple_builtin ("__builtin_abort", &abort); rust_assert (abort); rust_assert (builtin); diff --git a/gcc/rust/rust-lang.cc b/gcc/rust/rust-lang.cc index f9bec3f7c1e..8b76ba28ea2 100644 --- a/gcc/rust/rust-lang.cc +++ b/gcc/rust/rust-lang.cc @@ -380,6 +380,8 @@ rust_localize_identifier (const char *ident) return identifier_to_locale (ident); } +extern const attribute_spec grs_langhook_common_attribute_table[]; + /* The language hooks data structure. This is the main interface between the GCC * front-end and the GCC middle-end/back-end. A list of language hooks could be * found in /langhooks.h @@ -400,6 +402,8 @@ rust_localize_identifier (const char *ident) #undef LANG_HOOKS_GIMPLIFY_EXPR #undef LANG_HOOKS_EH_PERSONALITY +#undef LANG_HOOKS_COMMON_ATTRIBUTE_TABLE + #define LANG_HOOKS_NAME "GNU Rust" #define LANG_HOOKS_INIT grs_langhook_init #define LANG_HOOKS_OPTION_LANG_MASK grs_langhook_option_lang_mask @@ -420,6 +424,8 @@ rust_localize_identifier (const char *ident) #define LANG_HOOKS_GIMPLIFY_EXPR grs_langhook_gimplify_expr #define LANG_HOOKS_EH_PERSONALITY grs_langhook_eh_personality +#define LANG_HOOKS_COMMON_ATTRIBUTE_TABLE grs_langhook_common_attribute_table + #if CHECKING_P #undef LANG_HOOKS_RUN_LANG_SELFTESTS diff --git a/gcc/testsuite/rust/compile/torture/builtin_abort.rs b/gcc/testsuite/rust/compile/torture/builtin_abort.rs new file mode 100644 index 00000000000..3112cdc67f7 --- /dev/null +++ b/gcc/testsuite/rust/compile/torture/builtin_abort.rs @@ -0,0 +1,18 @@ +// { dg-options "-fdump-tree-original" } + +// { dg-final { scan-assembler-not "__builtin_abort\[^\"\]" } } +// { dg-final { scan-tree-dump "__builtin_abort" "original" } } + +#![feature(rustc_attrs)] +#![feature(intrinsics)] + +mod intrinsics { + extern "rust-intrinsic" { + pub fn abort() -> !; + } +} + +pub fn main () -> i32 { + abort(); + 0 +} diff --git a/gcc/testsuite/rust/compile/torture/intrinsics-1.rs b/gcc/testsuite/rust/compile/torture/intrinsics-1.rs deleted file mode 100644 index 6704c0210d1..00000000000 --- a/gcc/testsuite/rust/compile/torture/intrinsics-1.rs +++ /dev/null @@ -1,22 +0,0 @@ -// { dg-additional-options -fdump-tree-original } - -#![feature(intrinsics)] - -extern "rust-intrinsic" { - pub fn sqrtf32(x: f32) -> f32; - pub fn sinf32(x: f32) -> f32; -} - -fn main() { - unsafe fn foo() { - let mut f32; - - f32 = sqrtf32(5f32); - // { dg-final { scan-tree-dump-times {(?n)f32 = __builtin_sqrtf \(5\.0e\+0\);$} 1 original } } - - f32 = sinf32(39f32); - // { dg-final { scan-tree-dump-times {(?n)f32 = __builtin_sinf \(3\.9e\+1\);$} 1 original } } - } - - unsafe { foo() }; -} diff --git a/gcc/testsuite/rust/compile/torture/intrinsics-4.rs b/gcc/testsuite/rust/compile/torture/intrinsics-4.rs index 1f6c0d6608a..3d26e999b9e 100644 --- a/gcc/testsuite/rust/compile/torture/intrinsics-4.rs +++ b/gcc/testsuite/rust/compile/torture/intrinsics-4.rs @@ -67,7 +67,7 @@ extern "rust-intrinsic" { } fn main() { - let mut dst = 15; + let mut dst = 15u32; let new_value = 14; unsafe { diff --git a/gcc/testsuite/rust/compile/torture/intrinsics-math.rs b/gcc/testsuite/rust/compile/torture/intrinsics-math.rs index fb329baafdd..42acdde1494 100644 --- a/gcc/testsuite/rust/compile/torture/intrinsics-math.rs +++ b/gcc/testsuite/rust/compile/torture/intrinsics-math.rs @@ -69,104 +69,104 @@ fn main() { let mut f64; f32 = sqrtf32(1f32); - // { dg-final { scan-tree-dump-times {(?n)f32 = __builtin_sqrtf \(1\.0e\+0\);$} 1 original } } + // { dg-final { scan-tree-dump-times {(?n)f32 .* __builtin_sqrt. \(.*.*1\.0e\+0\);$} 1 original } } f64 = sqrtf64(2f64); - // { dg-final { scan-tree-dump-times {(?n)f64 = __builtin_sqrt \(2\.0e\+0\);$} 1 original } } + // { dg-final { scan-tree-dump-times {(?n)f64 .* __builtin_sqrt.? \(.*2\.0e\+0\);$} 1 original } } f32 = sinf32(39f32); - // { dg-final { scan-tree-dump-times {(?n)f32 = __builtin_sinf \(3\.9e\+1\);$} 1 original } } + // { dg-final { scan-tree-dump-times {(?n)f32 .* __builtin_sin. \(.*3\.9e\+1\);$} 1 original } } f64 = sinf64(40f64); - // { dg-final { scan-tree-dump-times {(?n)f64 = __builtin_sin \(4\.0e\+1\);$} 1 original } } + // { dg-final { scan-tree-dump-times {(?n)f64 .* __builtin_sin.? \(.*4\.0e\+1\);$} 1 original } } f32 = cosf32(5f32); - // { dg-final { scan-tree-dump-times {(?n)f32 = __builtin_cosf \(5\.0e\+0\);$} 1 original } } + // { dg-final { scan-tree-dump-times {(?n)f32 .* __builtin_cos. \(.*5\.0e\+0\);$} 1 original } } f64 = cosf64(6f64); - // { dg-final { scan-tree-dump-times {(?n)f64 = __builtin_cos \(6\.0e\+0\);$} 1 original } } + // { dg-final { scan-tree-dump-times {(?n)f64 .* __builtin_cos.? \(.*6\.0e\+0\);$} 1 original } } f32 = powf32(7f32, 8f32); - // { dg-final { scan-tree-dump-times {(?n)f32 = __builtin_powf \(7\.0e\+0, 8\.0e\+0\);$} 1 original } } + // { dg-final { scan-tree-dump-times {(?n)f32 .* __builtin_pow. \(.*7\.0e\+0, .*8\.0e\+0\);$} 1 original } } f64 = powf64(9f64, 10f64); - // { dg-final { scan-tree-dump-times {(?n)f64 = __builtin_pow \(9\.0e\+0, 1\.0e\+1\);$} 1 original } } + // { dg-final { scan-tree-dump-times {(?n)f64 .* __builtin_pow.? \(.*9\.0e\+0, .*1\.0e\+1\);$} 1 original } } f32 = expf32(11f32); - // { dg-final { scan-tree-dump-times {(?n)f32 = __builtin_expf \(1\.1e\+1\);$} 1 original } } + // { dg-final { scan-tree-dump-times {(?n)f32 .* __builtin_exp. \(.*1\.1e\+1\);$} 1 original } } f64 = expf64(12f64); - // { dg-final { scan-tree-dump-times {(?n)f64 = __builtin_exp \(1\.2e\+1\);$} 1 original } } + // { dg-final { scan-tree-dump-times {(?n)f64 .* __builtin_exp.? \(.*1\.2e\+1\);$} 1 original } } f32 = exp2f32(13f32); - // { dg-final { scan-tree-dump-times {(?n)f32 = __builtin_expf \(1\.1e\+1\);$} 1 original } } + // { dg-final { scan-tree-dump-times {(?n)f32 .* __builtin_exp. \(.*1\.1e\+1\);$} 1 original } } f64 = exp2f64(14f64); - // { dg-final { scan-tree-dump-times {(?n)f64 = __builtin_exp \(1\.2e\+1\);$} 1 original } } + // { dg-final { scan-tree-dump-times {(?n)f64 .* __builtin_exp.? \(.*1\.2e\+1\);$} 1 original } } f32 = logf32(15f32); - // { dg-final { scan-tree-dump-times {(?n)f32 = __builtin_logf \(1\.5e\+1\);$} 1 original } } + // { dg-final { scan-tree-dump-times {(?n)f32 .* __builtin_log. \(.*1\.5e\+1\);$} 1 original } } f64 = logf64(16f64); - // { dg-final { scan-tree-dump-times {(?n)f64 = __builtin_log \(1\.6e\+1\);$} 1 original } } + // { dg-final { scan-tree-dump-times {(?n)f64 .* __builtin_log.? \(.*1\.6e\+1\);$} 1 original } } f32 = log10f32(17f32); - // { dg-final { scan-tree-dump-times {(?n)f32 = __builtin_log10f \(1\.7e\+1\);$} 1 original } } + // { dg-final { scan-tree-dump-times {(?n)f32 .* __builtin_log10. \(.*1\.7e\+1\);$} 1 original } } f64 = log10f64(18f64); - // { dg-final { scan-tree-dump-times {(?n)f64 = __builtin_log10 \(1\.8e\+1\);$} 1 original } } + // { dg-final { scan-tree-dump-times {(?n)f64 .* __builtin_log10.? \(.*1\.8e\+1\);$} 1 original } } f32 = log2f32(19f32); - // { dg-final { scan-tree-dump-times {(?n)f32 = __builtin_log2f \(1\.9e\+1\);$} 1 original } } + // { dg-final { scan-tree-dump-times {(?n)f32 .* __builtin_log2. \(.*1\.9e\+1\);$} 1 original } } f64 = log2f64(20f64); - // { dg-final { scan-tree-dump-times {(?n)f64 = __builtin_log2 \(2\.0e\+1\);$} 1 original } } + // { dg-final { scan-tree-dump-times {(?n)f64 .* __builtin_log2.? \(.*2\.0e\+1\);$} 1 original } } f32 = fmaf32(21f32, 22f32, 23f32); - // { dg-final { scan-tree-dump-times {(?n)f32 = __builtin_fmaf \(2\.1e\+1, 2\.2e\+1, 2\.3e\+1\);$} 1 original } } + // { dg-final { scan-tree-dump-times {(?n)f32 .* __builtin_fma. \(.*2\.1e\+1, .*2\.2e\+1, .*2\.3e\+1\);$} 1 original } } f64 = fmaf64(24f64, 25f64, 26f64); - // { dg-final { scan-tree-dump-times {(?n)f64 = __builtin_fma \(2\.4e\+1, 2\.5e\+1, 2\.6e\+1\);$} 1 original } } + // { dg-final { scan-tree-dump-times {(?n)f64 .* __builtin_fma.? \(.*2\.4e\+1, .*2\.5e\+1, .*2\.6e\+1\);$} 1 original } } f32 = fabsf32(27f32); - // { dg-final { scan-tree-dump-times {(?n)f32 = __builtin_fabsf \(2\.7e\+1\);$} 1 original } } + // { dg-final { scan-tree-dump-times {(?n)f32 .* __builtin_fabs. \(.*2\.7e\+1\);$} 1 original } } f64 = fabsf64(28f64); - // { dg-final { scan-tree-dump-times {(?n)f64 = __builtin_fabs \(2\.8e\+1\);$} 1 original } } + // { dg-final { scan-tree-dump-times {(?n)f64 .* __builtin_fabs.? \(.*2\.8e\+1\);$} 1 original } } f32 = minnumf32(29f32, 30f32); - // { dg-final { scan-tree-dump-times {(?n)f32 = __builtin_fminf \(2\.9e\+1, 3\.0e\+1\);$} 1 original } } + // { dg-final { scan-tree-dump-times {(?n)f32 .* __builtin_fmin. \(.*2\.9e\+1, .*3\.0e\+1\);$} 1 original } } f64 = minnumf64(31f64, 32f64); - // { dg-final { scan-tree-dump-times {(?n)f64 = __builtin_fmin \(3\.1e\+1, 3\.2e\+1\);$} 1 original } } + // { dg-final { scan-tree-dump-times {(?n)f64 .* __builtin_fmin.? \(.*3\.1e\+1, .*3\.2e\+1\);$} 1 original } } f32 = maxnumf32(33f32, 34f32); - // { dg-final { scan-tree-dump-times {(?n)f32 = __builtin_fmaxf \(3\.3e\+1, 3\.4e\+1\);$} 1 original } } + // { dg-final { scan-tree-dump-times {(?n)f32 .* __builtin_fmax. \(.*3\.3e\+1, .*3\.4e\+1\);$} 1 original } } f64 = maxnumf64(35f64, 36f64); - // { dg-final { scan-tree-dump-times {(?n)f64 = __builtin_fmax \(3\.5e\+1, 3\.6e\+1\);$} 1 original } } + // { dg-final { scan-tree-dump-times {(?n)f64 .* __builtin_fmax.? \(.*3\.5e\+1, .*3\.6e\+1\);$} 1 original } } f32 = copysignf32(37f32, 38f32); - // { dg-final { scan-tree-dump-times {(?n)f32 = __builtin_copysignf \(3\.7e\+1, 3\.8e\+1\);$} 1 original } } + // { dg-final { scan-tree-dump-times {(?n)f32 .* __builtin_copysign. \(.*3\.7e\+1, .*3\.8e\+1\);$} 1 original } } f64 = copysignf64(39f64, 40f64); - // { dg-final { scan-tree-dump-times {(?n)f64 = __builtin_copysign \(3\.9e\+1, 4\.0e\+1\);$} 1 original } } + // { dg-final { scan-tree-dump-times {(?n)f64 .* __builtin_copysign.? \(.*3\.9e\+1, .*4\.0e\+1\);$} 1 original } } f32 = floorf32(41f32); - // { dg-final { scan-tree-dump-times {(?n)f32 = __builtin_floorf \(4\.1e\+1\);$} 1 original } } + // { dg-final { scan-tree-dump-times {(?n)f32 .* __builtin_floor. \(.*4\.1e\+1\);$} 1 original } } f64 = floorf64(42f64); - // { dg-final { scan-tree-dump-times {(?n)f64 = __builtin_floor \(4\.2e\+1\);$} 1 original } } + // { dg-final { scan-tree-dump-times {(?n)f64 .* __builtin_floor.? \(.*4\.2e\+1\);$} 1 original } } f32 = ceilf32(43f32); - // { dg-final { scan-tree-dump-times {(?n)f32 = __builtin_ceilf \(4\.3e\+1\);$} 1 original } } + // { dg-final { scan-tree-dump-times {(?n)f32 .* __builtin_ceil. \(.*4\.3e\+1\);$} 1 original } } f64 = ceilf64(44f64); - // { dg-final { scan-tree-dump-times {(?n)f64 = __builtin_ceil \(4\.4e\+1\);$} 1 original } } + // { dg-final { scan-tree-dump-times {(?n)f64 .* __builtin_ceil.? \(.*4\.4e\+1\);$} 1 original } } f32 = truncf32(45f32); - // { dg-final { scan-tree-dump-times {(?n)f32 = __builtin_truncf \(4\.5e\+1\);$} 1 original } } + // { dg-final { scan-tree-dump-times {(?n)f32 .* __builtin_trunc. \(.*4\.5e\+1\);$} 1 original } } f64 = truncf64(46f64); - // { dg-final { scan-tree-dump-times {(?n)f64 = __builtin_trunc \(4\.6e\+1\);$} 1 original } } + // { dg-final { scan-tree-dump-times {(?n)f64 .* __builtin_trunc.? \(.*4\.6e\+1\);$} 1 original } } f32 = rintf32(47f32); - // { dg-final { scan-tree-dump-times {(?n)f32 = __builtin_rintf \(4\.7e\+1\);$} 1 original } } + // { dg-final { scan-tree-dump-times {(?n)f32 .* __builtin_rint. \(.*4\.7e\+1\);$} 1 original } } f64 = rintf64(48f64); - // { dg-final { scan-tree-dump-times {(?n)f64 = __builtin_rint \(4\.8e\+1\);$} 1 original } } + // { dg-final { scan-tree-dump-times {(?n)f64 .* __builtin_rint.? \(.*4\.8e\+1\);$} 1 original } } f32 = nearbyintf32(49f32); - // { dg-final { scan-tree-dump-times {(?n)f32 = __builtin_nearbyintf \(4\.9e\+1\);$} 1 original } } + // { dg-final { scan-tree-dump-times {(?n)f32 .* __builtin_nearbyint. \(.*4\.9e\+1\);$} 1 original } } f64 = nearbyintf64(50f64); - // { dg-final { scan-tree-dump-times {(?n)f64 = __builtin_nearbyint \(5\.0e\+1\);$} 1 original } } + // { dg-final { scan-tree-dump-times {(?n)f64 .* __builtin_nearbyint.? \(.*5\.0e\+1\);$} 1 original } } f32 = roundf32(51f32); - // { dg-final { scan-tree-dump-times {(?n)f32 = __builtin_roundf \(5\.1e\+1\);$} 1 original } } + // { dg-final { scan-tree-dump-times {(?n)f32 .* __builtin_round. \(.*5\.1e\+1\);$} 1 original } } f64 = roundf64(52f64); - // { dg-final { scan-tree-dump-times {(?n)f64 = __builtin_round \(5\.2e\+1\);$} 1 original } } + // { dg-final { scan-tree-dump-times {(?n)f64 .* __builtin_round.? \(.*5\.2e\+1\);$} 1 original } } } unsafe { foo() }; diff --git a/gcc/testsuite/rust/execute/torture/atomic_load.rs b/gcc/testsuite/rust/execute/torture/atomic_load.rs index b66c4641424..11da8484494 100644 --- a/gcc/testsuite/rust/execute/torture/atomic_load.rs +++ b/gcc/testsuite/rust/execute/torture/atomic_load.rs @@ -66,14 +66,14 @@ extern "rust-intrinsic" { pub fn atomic_load_unordered(src: *const T) -> T; } -fn main() -> i32 { +fn main() -> u32 { let one; let two; let three; let four; unsafe { - let mut src = 1; + let mut src = 1u32; one = atomic_load_seqcst(&src); src = 2; diff --git a/gcc/testsuite/rust/execute/torture/atomic_store.rs b/gcc/testsuite/rust/execute/torture/atomic_store.rs index dcbb2a90f19..1b46678ba38 100644 --- a/gcc/testsuite/rust/execute/torture/atomic_store.rs +++ b/gcc/testsuite/rust/execute/torture/atomic_store.rs @@ -66,8 +66,8 @@ extern "rust-intrinsic" { pub fn atomic_store_unordered(dst: *mut T, val: T); } -fn main() -> i32 { - let mut dst = 15; +fn main() -> u32 { + let mut dst = 15u32; let one; let two; let three; diff --git a/gcc/testsuite/rust/execute/torture/builtin_abort.rs b/gcc/testsuite/rust/execute/torture/builtin_abort.rs new file mode 100644 index 00000000000..9f2d8c2d9f3 --- /dev/null +++ b/gcc/testsuite/rust/execute/torture/builtin_abort.rs @@ -0,0 +1,14 @@ +// { dg-shouldfail "abort should stop the program" } +#![feature(rustc_attrs)] +#![feature(intrinsics)] + +mod intrinsics { + extern "rust-intrinsic" { + pub fn abort() -> !; + } +} + +pub fn main () -> i32 { + abort(); + 0 +}