From patchwork Wed Aug 9 18:25:14 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jakub Jelinek X-Patchwork-Id: 133413 Return-Path: Delivered-To: ouuuleilei@gmail.com Received: by 2002:a59:c44e:0:b0:3f2:4152:657d with SMTP id w14csp2993107vqr; Wed, 9 Aug 2023 11:26:10 -0700 (PDT) X-Google-Smtp-Source: AGHT+IHO1mVNJIO79KfuD45w3416bj5ExKP7/xvEd6/ZGN5wEyLTRsdt0zQdLZaprPp/6sKlxUkP X-Received: by 2002:adf:f0cd:0:b0:314:15b7:20a5 with SMTP id x13-20020adff0cd000000b0031415b720a5mr130587wro.54.1691605570422; Wed, 09 Aug 2023 11:26:10 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1691605570; cv=none; d=google.com; s=arc-20160816; b=ggg7WjL3WUdsCLjV39eGrIvgWWAzG6u0C4Vh7BRfdBG2HTEPctrL1flP0UYlBc9Wcf 4dGedHLsyHuq2OKH5nE1TpMgaG3S012C0aZlyzRpXrU9yz/gwpNRWZGFbPJQYtb3+LOE J2nkee4exKuu47Ih+LSd5V05dzlpQshGH2tU9XwbvwzlE1NOlncUgYchr58jWTaR23OQ PdSlFhMN/+K7gWTLrGEz40wIjEZ64nkwD/PY1IoV3FP4lXd+bnAru7PXVrDEwxLBoFnZ LlaPbN21pEtfi/+kX8rzLSevmILg4ysjPO/FolhhwTbHcAEzO47NsLybgJOtsO8bAlaG to8w== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=sender:errors-to:reply-to:from:list-subscribe:list-help:list-post :list-archive:list-unsubscribe:list-id:precedence :content-disposition:mime-version:message-id:subject:cc:to:date :dmarc-filter:delivered-to:dkim-signature:dkim-filter; bh=bQiaRRVbcl1kTrvaMMAe0fvJxfvNcgGkVTwCshDsKas=; fh=aeZHQn/lA9+KGzRlDhL1qO9SE/pAMSdkbwH21Dg0FsA=; b=y0WESmQXBD8HyieDpT7GzGUAUlHmutOjQOY4L1Obuwk0vcp5n8gaWjsZJQLXX5RV1n /lKAX0vVnJ8mnQH/SE3sugFd1BHND0y7DujcRk5A21TGA+F9sV14aiJ+vUnHWrXGZfOL gCMmui9q91F/soBgVUncTCrxnhjx+Qo2tVYoCMHiSUPEHcatKCwTlSAfkGXzg0SvioGd ratc45y2bOrTn5WvX538SGhz/1dUxYDRxC8KOLuM0N/ivQx7l5lZOD69Y5j+L3x+mATe 8oFXPL4DNSdaZowwbM5pA9Vknr2ykU96nuF/ptyhr6WpMJ2/uh06WmjE0EpHs6jgrkMo Eexw== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@gcc.gnu.org header.s=default header.b="rg/ZdehB"; spf=pass (google.com: domain of gcc-patches-bounces+ouuuleilei=gmail.com@gcc.gnu.org designates 2620:52:3:1:0:246e:9693:128c as permitted sender) smtp.mailfrom="gcc-patches-bounces+ouuuleilei=gmail.com@gcc.gnu.org"; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=gnu.org Received: from server2.sourceware.org (server2.sourceware.org. [2620:52:3:1:0:246e:9693:128c]) by mx.google.com with ESMTPS id r3-20020aa7d143000000b0052336e17244si2863705edo.646.2023.08.09.11.26.09 for (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 09 Aug 2023 11:26:10 -0700 (PDT) Received-SPF: pass (google.com: domain of gcc-patches-bounces+ouuuleilei=gmail.com@gcc.gnu.org designates 2620:52:3:1:0:246e:9693:128c as permitted sender) client-ip=2620:52:3:1:0:246e:9693:128c; Authentication-Results: mx.google.com; dkim=pass header.i=@gcc.gnu.org header.s=default header.b="rg/ZdehB"; spf=pass (google.com: domain of gcc-patches-bounces+ouuuleilei=gmail.com@gcc.gnu.org designates 2620:52:3:1:0:246e:9693:128c as permitted sender) smtp.mailfrom="gcc-patches-bounces+ouuuleilei=gmail.com@gcc.gnu.org"; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=gnu.org Received: from server2.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id C19E33857835 for ; Wed, 9 Aug 2023 18:26:08 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org C19E33857835 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gcc.gnu.org; s=default; t=1691605568; bh=bQiaRRVbcl1kTrvaMMAe0fvJxfvNcgGkVTwCshDsKas=; h=Date:To:Cc:Subject:List-Id:List-Unsubscribe:List-Archive: List-Post:List-Help:List-Subscribe:From:Reply-To:From; b=rg/ZdehB//bcGBagI0s1GZT0q/l9fYkKRj9fZ6xD0f5JwWHesEZqrJsXGOATK1LRk xmHosUSoONqhBNF3IsPaC6Z4stms3bUTW54TS0AkA1ntbB5HpSvM4mwDsvS+xADDyu RGprycRye1OF1uM59WRvaJDlTxx+ncpGQk2SC4aI= X-Original-To: gcc-patches@gcc.gnu.org Delivered-To: gcc-patches@gcc.gnu.org Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.133.124]) by sourceware.org (Postfix) with ESMTPS id 2C9A53858D20 for ; Wed, 9 Aug 2023 18:25:21 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org 2C9A53858D20 Received: from mimecast-mx02.redhat.com (66.187.233.73 [66.187.233.73]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id us-mta-544-HS8AhfaqP02lT_AWGV5qzA-1; Wed, 09 Aug 2023 14:25:19 -0400 X-MC-Unique: HS8AhfaqP02lT_AWGV5qzA-1 Received: from smtp.corp.redhat.com (int-mx10.intmail.prod.int.rdu2.redhat.com [10.11.54.10]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mimecast-mx02.redhat.com (Postfix) with ESMTPS id C1E023C100A8; Wed, 9 Aug 2023 18:25:18 +0000 (UTC) Received: from tucnak.zalov.cz (unknown [10.45.224.18]) by smtp.corp.redhat.com (Postfix) with ESMTPS id 362F4492C13; Wed, 9 Aug 2023 18:25:18 +0000 (UTC) Received: from tucnak.zalov.cz (localhost [127.0.0.1]) by tucnak.zalov.cz (8.17.1/8.17.1) with ESMTPS id 379IPFRk2043005 (version=TLSv1.3 cipher=TLS_AES_256_GCM_SHA384 bits=256 verify=NOT); Wed, 9 Aug 2023 20:25:16 +0200 Received: (from jakub@localhost) by tucnak.zalov.cz (8.17.1/8.17.1/Submit) id 379IPFS52043004; Wed, 9 Aug 2023 20:25:15 +0200 Date: Wed, 9 Aug 2023 20:25:14 +0200 To: "Joseph S. Myers" Cc: gcc-patches@gcc.gnu.org Subject: [PATCH 10/12] C _BitInt support [PR102989] Message-ID: MIME-Version: 1.0 X-Scanned-By: MIMEDefang 3.1 on 10.11.54.10 X-Mimecast-Spam-Score: 0 X-Mimecast-Originator: redhat.com Content-Disposition: inline X-Spam-Status: No, score=-3.7 required=5.0 tests=BAYES_00, DKIMWL_WL_HIGH, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, DKIM_VALID_EF, RCVD_IN_DNSWL_NONE, RCVD_IN_MSPIKE_H4, RCVD_IN_MSPIKE_WL, SPF_HELO_NONE, SPF_NONE, TXREP autolearn=ham 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.29 Precedence: list List-Id: Gcc-patches mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-Patchwork-Original-From: Jakub Jelinek via Gcc-patches From: Jakub Jelinek Reply-To: Jakub Jelinek Errors-To: gcc-patches-bounces+ouuuleilei=gmail.com@gcc.gnu.org Sender: "Gcc-patches" X-getmail-retrieved-from-mailbox: INBOX X-GMAIL-THRID: 1773777002247056017 X-GMAIL-MSGID: 1773777002247056017 Hi! This patch adds the C FE support, c-family support, small libcpp change so that 123wb and 42uwb suffixes are handled plus glimits.h change to define BITINT_MAXWIDTH macro. The previous patches really do nothing without this, which enables all the support. 2023-08-09 Jakub Jelinek PR c/102989 gcc/ * glimits.h (BITINT_MAXWIDTH): Define if __BITINT_MAXWIDTH__ is predefined. gcc/c-family/ * c-common.cc (c_common_reswords): Add _BitInt as keyword. (c_common_signed_or_unsigned_type): Handle BITINT_TYPE. (check_builtin_function_arguments): Handle BITINT_TYPE like INTEGER_TYPE. (sync_resolve_size): Add ORIG_FORMAT argument. If FETCH && !ORIG_FORMAT, type is BITINT_TYPE, return -1 if size isn't one of 1, 2, 4, 8 or 16 or if it is 16 but TImode is not supported. (atomic_bitint_fetch_using_cas_loop): New function. (resolve_overloaded_builtin): Adjust sync_resolve_size caller. If -1 is returned, use atomic_bitint_fetch_using_cas_loop to lower it. Formatting fix. (keyword_begins_type_specifier): Handle RID_BITINT. * c-common.h (enum rid): Add RID_BITINT enumerator. * c-cppbuiltin.cc (c_cpp_builtins): For C call targetm.c.bitint_type_info and predefine __BITINT_MAXWIDTH__ and for -fbuilding-libgcc also __LIBGCC_BITINT_LIMB_WIDTH__ and __LIBGCC_BITINT_ORDER__ macros if _BitInt is supported. * c-lex.cc (interpret_integer): Handle CPP_N_BITINT. * c-pretty-print.cc (c_pretty_printer::simple_type_specifier, c_pretty_printer::direct_abstract_declarator): Handle BITINT_TYPE. (pp_c_integer_constant): Handle printing of large precision wide_ints which would buffer overflow digit_buffer. gcc/c/ * c-convert.cc (c_convert): Handle BITINT_TYPE like INTEGER_TYPE. * c-decl.cc (check_bitfield_type_and_width): Allow BITINT_TYPE bit-fields. (finish_struct): Prefer to use BITINT_TYPE for BITINT_TYPE bit-fields if possible. (declspecs_add_type): Formatting fixes. Handle cts_bitint. Adjust for added union in *specs. Handle RID_BITINT. (finish_declspecs): Handle cts_bitint. Adjust for added union in *specs. * c-parser.cc (c_keyword_starts_typename, c_token_starts_declspecs, c_parser_declspecs, c_parser_gnu_attribute_any_word): Handle RID_BITINT. * c-tree.h (enum c_typespec_keyword): Mention _BitInt in comment. Add cts_bitint enumerator. (struct c_declspecs): Move int_n_idx and floatn_nx_idx into a union and add bitint_prec there as well. * c-typeck.cc (composite_type, c_common_type, comptypes_internal): Handle BITINT_TYPE. (perform_integral_promotions): Promote BITINT_TYPE bit-fields to their declared type. (build_array_ref, build_unary_op, build_conditional_expr, convert_for_assignment, digest_init, build_binary_op): Likewise. libcpp/ * expr.cc (interpret_int_suffix): Handle wb and WB suffixes. * include/cpplib.h (CPP_N_BITINT): Define. Jakub --- gcc/glimits.h.jj 2023-08-08 15:54:34.481612931 +0200 +++ gcc/glimits.h 2023-08-08 16:12:02.321939910 +0200 @@ -157,6 +157,11 @@ see the files COPYING3 and COPYING.RUNTI # undef BOOL_WIDTH # define BOOL_WIDTH 1 +# ifdef __BITINT_MAXWIDTH__ +# undef BITINT_MAXWIDTH +# define BITINT_MAXWIDTH __BITINT_MAXWIDTH__ +# endif + # define __STDC_VERSION_LIMITS_H__ 202311L #endif --- gcc/c-family/c-common.cc.jj 2023-08-08 15:55:05.243182143 +0200 +++ gcc/c-family/c-common.cc 2023-08-08 16:19:29.102683903 +0200 @@ -349,6 +349,7 @@ const struct c_common_resword c_common_r { "_Alignas", RID_ALIGNAS, D_CONLY }, { "_Alignof", RID_ALIGNOF, D_CONLY }, { "_Atomic", RID_ATOMIC, D_CONLY }, + { "_BitInt", RID_BITINT, D_CONLY }, { "_Bool", RID_BOOL, D_CONLY }, { "_Complex", RID_COMPLEX, 0 }, { "_Imaginary", RID_IMAGINARY, D_CONLY }, @@ -2728,6 +2729,9 @@ c_common_signed_or_unsigned_type (int un || TYPE_UNSIGNED (type) == unsignedp) return type; + if (TREE_CODE (type) == BITINT_TYPE) + return build_bitint_type (TYPE_PRECISION (type), unsignedp); + #define TYPE_OK(node) \ (TYPE_MODE (type) == TYPE_MODE (node) \ && TYPE_PRECISION (type) == TYPE_PRECISION (node)) @@ -6341,8 +6345,10 @@ check_builtin_function_arguments (locati code0 = TREE_CODE (TREE_TYPE (args[0])); code1 = TREE_CODE (TREE_TYPE (args[1])); if (!((code0 == REAL_TYPE && code1 == REAL_TYPE) - || (code0 == REAL_TYPE && code1 == INTEGER_TYPE) - || (code0 == INTEGER_TYPE && code1 == REAL_TYPE))) + || (code0 == REAL_TYPE + && (code1 == INTEGER_TYPE || code1 == BITINT_TYPE)) + || ((code0 == INTEGER_TYPE || code0 == BITINT_TYPE) + && code1 == REAL_TYPE))) { error_at (loc, "non-floating-point arguments in call to " "function %qE", fndecl); @@ -7185,12 +7191,16 @@ speculation_safe_value_resolve_return (t /* A helper function for resolve_overloaded_builtin in resolving the overloaded __sync_ builtins. Returns a positive power of 2 if the first operand of PARAMS is a pointer to a supported data type. - Returns 0 if an error is encountered. + Returns 0 if an error is encountered. Return -1 for _BitInt + __atomic*fetch* with unsupported type which should be handled by + a cas loop. FETCH is true when FUNCTION is one of the _FETCH_OP_ or _OP_FETCH_ + built-ins. ORIG_FORMAT is for __sync_* rather than __atomic_* built-ins. */ static int -sync_resolve_size (tree function, vec *params, bool fetch) +sync_resolve_size (tree function, vec *params, bool fetch, + bool orig_format) { /* Type of the argument. */ tree argtype; @@ -7225,9 +7235,19 @@ sync_resolve_size (tree function, vec *orig_params) +{ + enum tree_code code = ERROR_MARK; + bool return_old_p = false; + switch (orig_code) + { + case BUILT_IN_ATOMIC_ADD_FETCH_N: + code = PLUS_EXPR; + break; + case BUILT_IN_ATOMIC_SUB_FETCH_N: + code = MINUS_EXPR; + break; + case BUILT_IN_ATOMIC_AND_FETCH_N: + code = BIT_AND_EXPR; + break; + case BUILT_IN_ATOMIC_NAND_FETCH_N: + break; + case BUILT_IN_ATOMIC_XOR_FETCH_N: + code = BIT_XOR_EXPR; + break; + case BUILT_IN_ATOMIC_OR_FETCH_N: + code = BIT_IOR_EXPR; + break; + case BUILT_IN_ATOMIC_FETCH_ADD_N: + code = PLUS_EXPR; + return_old_p = true; + break; + case BUILT_IN_ATOMIC_FETCH_SUB_N: + code = MINUS_EXPR; + return_old_p = true; + break; + case BUILT_IN_ATOMIC_FETCH_AND_N: + code = BIT_AND_EXPR; + return_old_p = true; + break; + case BUILT_IN_ATOMIC_FETCH_NAND_N: + return_old_p = true; + break; + case BUILT_IN_ATOMIC_FETCH_XOR_N: + code = BIT_XOR_EXPR; + return_old_p = true; + break; + case BUILT_IN_ATOMIC_FETCH_OR_N: + code = BIT_IOR_EXPR; + return_old_p = true; + break; + default: + gcc_unreachable (); + } + + if (orig_params->length () != 3) + { + if (orig_params->length () < 3) + error_at (loc, "too few arguments to function %qE", orig_function); + else + error_at (loc, "too many arguments to function %qE", orig_function); + return error_mark_node; + } + + tree stmts = push_stmt_list (); + + tree nonatomic_lhs_type = TREE_TYPE (TREE_TYPE ((*orig_params)[0])); + nonatomic_lhs_type = TYPE_MAIN_VARIANT (nonatomic_lhs_type); + gcc_assert (TREE_CODE (nonatomic_lhs_type) == BITINT_TYPE); + + tree lhs_addr = (*orig_params)[0]; + tree val = convert (nonatomic_lhs_type, (*orig_params)[1]); + tree model = convert (integer_type_node, (*orig_params)[2]); + if (TREE_SIDE_EFFECTS (lhs_addr)) + { + tree var = create_tmp_var_raw (TREE_TYPE (lhs_addr)); + lhs_addr = build4 (TARGET_EXPR, TREE_TYPE (lhs_addr), var, lhs_addr, + NULL_TREE, NULL_TREE); + add_stmt (lhs_addr); + } + if (TREE_SIDE_EFFECTS (val)) + { + tree var = create_tmp_var_raw (nonatomic_lhs_type); + val = build4 (TARGET_EXPR, nonatomic_lhs_type, var, val, NULL_TREE, + NULL_TREE); + add_stmt (val); + } + if (TREE_SIDE_EFFECTS (model)) + { + tree var = create_tmp_var_raw (integer_type_node); + model = build4 (TARGET_EXPR, integer_type_node, var, model, NULL_TREE, + NULL_TREE); + add_stmt (model); + } + + tree old = create_tmp_var_raw (nonatomic_lhs_type); + tree old_addr = build_unary_op (loc, ADDR_EXPR, old, false); + TREE_ADDRESSABLE (old) = 1; + suppress_warning (old); + + tree newval = create_tmp_var_raw (nonatomic_lhs_type); + tree newval_addr = build_unary_op (loc, ADDR_EXPR, newval, false); + TREE_ADDRESSABLE (newval) = 1; + suppress_warning (newval); + + tree loop_decl = create_artificial_label (loc); + tree loop_label = build1 (LABEL_EXPR, void_type_node, loop_decl); + + tree done_decl = create_artificial_label (loc); + tree done_label = build1 (LABEL_EXPR, void_type_node, done_decl); + + vec *params; + vec_alloc (params, 6); + + /* __atomic_load (addr, &old, SEQ_CST). */ + tree fndecl = builtin_decl_explicit (BUILT_IN_ATOMIC_LOAD); + params->quick_push (lhs_addr); + params->quick_push (old_addr); + params->quick_push (build_int_cst (integer_type_node, MEMMODEL_RELAXED)); + tree func_call = resolve_overloaded_builtin (loc, fndecl, params); + if (func_call == NULL_TREE) + func_call = build_function_call_vec (loc, vNULL, fndecl, params, NULL); + old = build4 (TARGET_EXPR, nonatomic_lhs_type, old, func_call, NULL_TREE, + NULL_TREE); + add_stmt (old); + params->truncate (0); + + /* loop: */ + add_stmt (loop_label); + + /* newval = old + val; */ + tree rhs; + switch (code) + { + case PLUS_EXPR: + case MINUS_EXPR: + if (!TYPE_OVERFLOW_WRAPS (nonatomic_lhs_type)) + { + tree utype + = build_bitint_type (TYPE_PRECISION (nonatomic_lhs_type), 1); + rhs = convert (nonatomic_lhs_type, + build2_loc (loc, code, utype, + convert (utype, old), + convert (utype, val))); + } + else + rhs = build2_loc (loc, code, nonatomic_lhs_type, old, val); + break; + case BIT_AND_EXPR: + case BIT_IOR_EXPR: + case BIT_XOR_EXPR: + rhs = build2_loc (loc, code, nonatomic_lhs_type, old, val); + break; + case ERROR_MARK: + rhs = build2_loc (loc, BIT_AND_EXPR, nonatomic_lhs_type, + build1_loc (loc, BIT_NOT_EXPR, + nonatomic_lhs_type, old), val); + break; + default: + gcc_unreachable (); + } + rhs = build4 (TARGET_EXPR, nonatomic_lhs_type, newval, rhs, NULL_TREE, + NULL_TREE); + SET_EXPR_LOCATION (rhs, loc); + add_stmt (rhs); + + /* if (__atomic_compare_exchange (addr, &old, &new, false, model, model)) + goto done; */ + fndecl = builtin_decl_explicit (BUILT_IN_ATOMIC_COMPARE_EXCHANGE); + params->quick_push (lhs_addr); + params->quick_push (old_addr); + params->quick_push (newval_addr); + params->quick_push (integer_zero_node); + params->quick_push (model); + if (tree_fits_uhwi_p (model) + && (tree_to_uhwi (model) == MEMMODEL_RELEASE + || tree_to_uhwi (model) == MEMMODEL_ACQ_REL)) + params->quick_push (build_int_cst (integer_type_node, MEMMODEL_RELAXED)); + else + params->quick_push (model); + func_call = resolve_overloaded_builtin (loc, fndecl, params); + if (func_call == NULL_TREE) + func_call = build_function_call_vec (loc, vNULL, fndecl, params, NULL); + + tree goto_stmt = build1 (GOTO_EXPR, void_type_node, done_decl); + SET_EXPR_LOCATION (goto_stmt, loc); + + tree stmt + = build3 (COND_EXPR, void_type_node, func_call, goto_stmt, NULL_TREE); + SET_EXPR_LOCATION (stmt, loc); + add_stmt (stmt); + + /* goto loop; */ + goto_stmt = build1 (GOTO_EXPR, void_type_node, loop_decl); + SET_EXPR_LOCATION (goto_stmt, loc); + add_stmt (goto_stmt); + + /* done: */ + add_stmt (done_label); + + tree ret = create_tmp_var_raw (nonatomic_lhs_type); + stmt = build2_loc (loc, MODIFY_EXPR, void_type_node, ret, + return_old_p ? old : newval); + add_stmt (stmt); + + /* Finish the compound statement. */ + stmts = pop_stmt_list (stmts); + + return build4 (TARGET_EXPR, nonatomic_lhs_type, ret, stmts, NULL_TREE, + NULL_TREE); +} + + /* Some builtin functions are placeholders for other expressions. This function should be called immediately after parsing the call expression before surrounding code has committed to the type of the expression. @@ -8025,19 +8262,22 @@ resolve_overloaded_builtin (location_t l /* The following are not _FETCH_OPs and must be accepted with pointers to _Bool (or C++ bool). */ if (fetch_op) - fetch_op = - (orig_code != BUILT_IN_SYNC_BOOL_COMPARE_AND_SWAP_N - && orig_code != BUILT_IN_SYNC_VAL_COMPARE_AND_SWAP_N - && orig_code != BUILT_IN_SYNC_LOCK_TEST_AND_SET_N - && orig_code != BUILT_IN_SYNC_LOCK_RELEASE_N); + fetch_op = (orig_code != BUILT_IN_SYNC_BOOL_COMPARE_AND_SWAP_N + && orig_code != BUILT_IN_SYNC_VAL_COMPARE_AND_SWAP_N + && orig_code != BUILT_IN_SYNC_LOCK_TEST_AND_SET_N + && orig_code != BUILT_IN_SYNC_LOCK_RELEASE_N); - int n = sync_resolve_size (function, params, fetch_op); + int n = sync_resolve_size (function, params, fetch_op, orig_format); tree new_function, first_param, result; enum built_in_function fncode; if (n == 0) return error_mark_node; + if (n == -1) + return atomic_bitint_fetch_using_cas_loop (loc, orig_code, + function, params); + fncode = (enum built_in_function)((int)orig_code + exact_log2 (n) + 1); new_function = builtin_decl_explicit (fncode); if (!sync_resolve_params (loc, function, new_function, params, @@ -8402,6 +8642,7 @@ keyword_begins_type_specifier (enum rid case RID_FRACT: case RID_ACCUM: case RID_BOOL: + case RID_BITINT: case RID_WCHAR: case RID_CHAR8: case RID_CHAR16: --- gcc/c-family/c-common.h.jj 2023-08-08 15:55:05.244182129 +0200 +++ gcc/c-family/c-common.h 2023-08-08 16:12:02.331939770 +0200 @@ -101,7 +101,7 @@ enum rid RID_ENUM, RID_STRUCT, RID_UNION, RID_IF, RID_ELSE, RID_WHILE, RID_DO, RID_FOR, RID_SWITCH, RID_CASE, RID_DEFAULT, RID_BREAK, RID_CONTINUE, RID_RETURN, RID_GOTO, - RID_SIZEOF, + RID_SIZEOF, RID_BITINT, /* C extensions */ RID_ASM, RID_TYPEOF, RID_TYPEOF_UNQUAL, RID_ALIGNOF, RID_ATTRIBUTE, --- gcc/c-family/c-cppbuiltin.cc.jj 2023-08-08 15:54:33.448627395 +0200 +++ gcc/c-family/c-cppbuiltin.cc 2023-08-08 16:12:02.331939770 +0200 @@ -1190,6 +1190,29 @@ c_cpp_builtins (cpp_reader *pfile) builtin_define_type_width ("__PTRDIFF_WIDTH__", ptrdiff_type_node, NULL_TREE); builtin_define_type_width ("__SIZE_WIDTH__", size_type_node, NULL_TREE); + if (!c_dialect_cxx ()) + { + struct bitint_info info; + /* For now, restrict __BITINT_MAXWIDTH__ to what can be represented in + wide_int and widest_int. */ + if (targetm.c.bitint_type_info (WIDE_INT_MAX_PRECISION - 1, &info)) + { + cpp_define_formatted (pfile, "__BITINT_MAXWIDTH__=%d", + (int) WIDE_INT_MAX_PRECISION - 1); + if (flag_building_libgcc) + { + scalar_int_mode limb_mode + = as_a (info.limb_mode); + cpp_define_formatted (pfile, "__LIBGCC_BITINT_LIMB_WIDTH__=%d", + (int) GET_MODE_PRECISION (limb_mode)); + cpp_define_formatted (pfile, "__LIBGCC_BITINT_ORDER__=%s", + info.big_endian + ? "__ORDER_BIG_ENDIAN__" + : "__ORDER_LITTLE_ENDIAN__"); + } + } + } + if (c_dialect_cxx ()) for (i = 0; i < NUM_INT_N_ENTS; i ++) if (int_n_enabled_p[i]) --- gcc/c-family/c-lex.cc.jj 2023-08-08 15:55:05.245182116 +0200 +++ gcc/c-family/c-lex.cc 2023-08-08 16:12:02.332939756 +0200 @@ -837,6 +837,170 @@ interpret_integer (const cpp_token *toke *overflow = OT_NONE; + if (UNLIKELY (flags & CPP_N_BITINT)) + { + unsigned int suffix_len = 2 + ((flags & CPP_N_UNSIGNED) ? 1 : 0); + int max_bits_per_digit = 4; // ceil (log2 (10)) + unsigned int prefix_len = 0; + bool hex = false; + const int bitint_maxwidth = WIDE_INT_MAX_PRECISION - 1; + if ((flags & CPP_N_RADIX) == CPP_N_OCTAL) + { + max_bits_per_digit = 3; + prefix_len = 1; + } + else if ((flags & CPP_N_RADIX) == CPP_N_HEX) + { + max_bits_per_digit = 4; + prefix_len = 2; + hex = true; + } + else if ((flags & CPP_N_RADIX) == CPP_N_BINARY) + { + max_bits_per_digit = 1; + prefix_len = 2; + } + int max_digits + = TYPE_PRECISION (intmax_type_node) >> max_bits_per_digit; + const int max_buf = 128; + if (max_digits > max_buf) + max_digits = max_buf; + + widest_int wval; + unsigned int prec; + gcc_checking_assert (token->val.str.len > prefix_len + suffix_len + || token->val.str.len == 1 + suffix_len); + if (token->val.str.len - (prefix_len + suffix_len) + <= (unsigned) max_digits) + { + integer = cpp_interpret_integer (parse_in, token, + (flags & CPP_N_RADIX) + | CPP_N_UNSIGNED); + ival[0] = integer.low; + ival[1] = integer.high; + ival[2] = 0; + wval = widest_int::from_array (ival, 3); + } + else + { + unsigned char buf[3 + max_buf]; + memcpy (buf, token->val.str.text, prefix_len); + wval = 0U; + const unsigned char *p = token->val.str.text + prefix_len; + cpp_token tok = *token; + tok.val.str.text = buf; + if (!prefix_len) + max_digits = 19; + do + { + unsigned char *q = buf + prefix_len; + do + { + unsigned char c = *p++; + if (ISDIGIT (c) || (hex && ISXDIGIT (c))) + { + *q++ = c; + if (q == buf + prefix_len + max_digits) + break; + } + else if (c != '\'') + { + --p; + break; + } + } + while (1); + if (q == buf + prefix_len) + break; + else + { + wi::overflow_type wioverflow; + *q = '\0'; + tok.val.str.len = q - buf; + if (wval == 0) + ; + else if (prefix_len) + { + prec = wi::min_precision (wval, UNSIGNED); + unsigned HOST_WIDE_INT shift + = (tok.val.str.len - prefix_len) * max_bits_per_digit; + if (prec + shift > bitint_maxwidth) + goto bitint_overflow; + wval = wi::lshift (wval, shift); + } + else + { + static unsigned HOST_WIDE_INT tens[] + = { 1U, 10U, 100U, 1000U, + HOST_WIDE_INT_UC (10000), + HOST_WIDE_INT_UC (100000), + HOST_WIDE_INT_UC (1000000), + HOST_WIDE_INT_UC (10000000), + HOST_WIDE_INT_UC (100000000), + HOST_WIDE_INT_UC (1000000000), + HOST_WIDE_INT_UC (10000000000), + HOST_WIDE_INT_UC (100000000000), + HOST_WIDE_INT_UC (1000000000000), + HOST_WIDE_INT_UC (10000000000000), + HOST_WIDE_INT_UC (100000000000000), + HOST_WIDE_INT_UC (1000000000000000), + HOST_WIDE_INT_UC (10000000000000000), + HOST_WIDE_INT_UC (100000000000000000), + HOST_WIDE_INT_UC (1000000000000000000), + HOST_WIDE_INT_UC (10000000000000000000) }; + widest_int ten = tens[q - buf]; + wval = wi::umul (wval, ten, &wioverflow); + if (wioverflow) + goto bitint_overflow; + } + integer = cpp_interpret_integer (parse_in, &tok, + (flags & CPP_N_RADIX) + | CPP_N_UNSIGNED); + ival[0] = integer.low; + ival[1] = integer.high; + ival[2] = 0; + if (prefix_len) + wval = wval + widest_int::from_array (ival, 3); + else + { + widest_int addend = widest_int::from_array (ival, 3); + wval = wi::add (wval, addend, UNSIGNED, &wioverflow); + if (wioverflow) + goto bitint_overflow; + } + } + } + while (1); + } + + prec = wi::min_precision (wval, UNSIGNED); + if (prec == 0) + prec = 1; + if ((flags & CPP_N_UNSIGNED) == 0) + ++prec; + if (prec > bitint_maxwidth) + { + bitint_overflow: + if ((flags & CPP_N_UNSIGNED) != 0) + error ("integer constant is too large for " + "% type", bitint_maxwidth); + else + error ("integer constant is too large for " + "%<_BitInt(%d)%> type", bitint_maxwidth); + return integer_zero_node; + } + + struct bitint_info info; + if (!targetm.c.bitint_type_info (prec, &info)) + { + sorry ("%<_BitInt(%d)%> is not supported on this target", prec); + return integer_zero_node; + } + + type = build_bitint_type (prec, (flags & CPP_N_UNSIGNED) != 0); + return wide_int_to_tree (type, wval); + } + integer = cpp_interpret_integer (parse_in, token, flags); if (integer.overflow) *overflow = OT_OVERFLOW; --- gcc/c-family/c-pretty-print.cc.jj 2023-08-08 15:54:33.553625925 +0200 +++ gcc/c-family/c-pretty-print.cc 2023-08-08 16:12:02.332939756 +0200 @@ -399,6 +399,23 @@ c_pretty_printer::simple_type_specifier } break; + case BITINT_TYPE: + if (TYPE_NAME (t)) + { + t = TYPE_NAME (t); + simple_type_specifier (t); + } + else + { + int prec = TYPE_PRECISION (t); + if (TYPE_UNSIGNED (t)) + pp_c_ws_string (this, "unsigned"); + pp_c_ws_string (this, "_BitInt(");; + pp_decimal_int (this, prec); + pp_right_paren (this); + } + break; + case TYPE_DECL: if (DECL_NAME (t)) id_expression (t); @@ -688,6 +705,7 @@ c_pretty_printer::direct_abstract_declar case REAL_TYPE: case FIXED_POINT_TYPE: case ENUMERAL_TYPE: + case BITINT_TYPE: case RECORD_TYPE: case UNION_TYPE: case VECTOR_TYPE: @@ -1019,8 +1037,18 @@ pp_c_integer_constant (c_pretty_printer pp_minus (pp); wi = -wi; } - print_hex (wi, pp_buffer (pp)->digit_buffer); - pp_string (pp, pp_buffer (pp)->digit_buffer); + unsigned int prec = wi.get_precision (); + if ((prec + 3) / 4 > sizeof (pp_buffer (pp)->digit_buffer) - 3) + { + char *buf = XALLOCAVEC (char, (prec + 3) / 4 + 3); + print_hex (wi, buf); + pp_string (pp, buf); + } + else + { + print_hex (wi, pp_buffer (pp)->digit_buffer); + pp_string (pp, pp_buffer (pp)->digit_buffer); + } } } --- gcc/c/c-convert.cc.jj 2023-08-08 15:54:33.642624678 +0200 +++ gcc/c/c-convert.cc 2023-08-08 16:12:02.332939756 +0200 @@ -117,6 +117,7 @@ c_convert (tree type, tree expr, bool in gcc_fallthrough (); case INTEGER_TYPE: + case BITINT_TYPE: if (sanitize_flags_p (SANITIZE_FLOAT_CAST) && current_function_decl != NULL_TREE && SCALAR_FLOAT_TYPE_P (TREE_TYPE (expr)) --- gcc/c/c-decl.cc.jj 2023-08-08 15:55:05.277181667 +0200 +++ gcc/c/c-decl.cc 2023-08-08 16:15:41.006877794 +0200 @@ -6390,7 +6390,8 @@ check_bitfield_type_and_width (location_ /* Detect invalid bit-field type. */ if (TREE_CODE (*type) != INTEGER_TYPE && TREE_CODE (*type) != BOOLEAN_TYPE - && TREE_CODE (*type) != ENUMERAL_TYPE) + && TREE_CODE (*type) != ENUMERAL_TYPE + && TREE_CODE (*type) != BITINT_TYPE) { error_at (loc, "bit-field %qs has invalid type", name); *type = unsigned_type_node; @@ -9330,8 +9331,14 @@ finish_struct (location_t loc, tree t, t tree type = TREE_TYPE (field); if (width != TYPE_PRECISION (type)) { - TREE_TYPE (field) - = c_build_bitfield_integer_type (width, TYPE_UNSIGNED (type)); + if (TREE_CODE (type) == BITINT_TYPE + && (width > 1 || TYPE_UNSIGNED (type))) + TREE_TYPE (field) + = build_bitint_type (width, TYPE_UNSIGNED (type)); + else + TREE_TYPE (field) + = c_build_bitfield_integer_type (width, + TYPE_UNSIGNED (type)); SET_DECL_MODE (field, TYPE_MODE (TREE_TYPE (field))); } DECL_INITIAL (field) = NULL_TREE; @@ -11546,14 +11553,18 @@ declspecs_add_type (location_t loc, stru ("both % and % in " "declaration specifiers")); else if (specs->typespec_word == cts_int_n) - error_at (loc, - ("both % and %<__int%d%> in " - "declaration specifiers"), - int_n_data[specs->int_n_idx].bitsize); + error_at (loc, + ("both % and %<__int%d%> in " + "declaration specifiers"), + int_n_data[specs->u.int_n_idx].bitsize); else if (specs->typespec_word == cts_bool) error_at (loc, ("both % and %<_Bool%> in " "declaration specifiers")); + else if (specs->typespec_word == cts_bitint) + error_at (loc, + ("both % and %<_BitInt%> in " + "declaration specifiers")); else if (specs->typespec_word == cts_char) error_at (loc, ("both % and % in " @@ -11566,8 +11577,8 @@ declspecs_add_type (location_t loc, stru error_at (loc, ("both % and %<_Float%d%s%> in " "declaration specifiers"), - floatn_nx_types[specs->floatn_nx_idx].n, - (floatn_nx_types[specs->floatn_nx_idx].extended + floatn_nx_types[specs->u.floatn_nx_idx].n, + (floatn_nx_types[specs->u.floatn_nx_idx].extended ? "x" : "")); else if (specs->typespec_word == cts_dfloat32) @@ -11606,11 +11617,15 @@ declspecs_add_type (location_t loc, stru error_at (loc, ("both % and %<__int%d%> in " "declaration specifiers"), - int_n_data[specs->int_n_idx].bitsize); + int_n_data[specs->u.int_n_idx].bitsize); else if (specs->typespec_word == cts_bool) error_at (loc, ("both % and %<_Bool%> in " "declaration specifiers")); + else if (specs->typespec_word == cts_bitint) + error_at (loc, + ("both % and %<_BitInt%> in " + "declaration specifiers")); else if (specs->typespec_word == cts_char) error_at (loc, ("both % and % in " @@ -11627,8 +11642,8 @@ declspecs_add_type (location_t loc, stru error_at (loc, ("both % and %<_Float%d%s%> in " "declaration specifiers"), - floatn_nx_types[specs->floatn_nx_idx].n, - (floatn_nx_types[specs->floatn_nx_idx].extended + floatn_nx_types[specs->u.floatn_nx_idx].n, + (floatn_nx_types[specs->u.floatn_nx_idx].extended ? "x" : "")); else if (specs->typespec_word == cts_dfloat32) @@ -11679,8 +11694,8 @@ declspecs_add_type (location_t loc, stru error_at (loc, ("both % and %<_Float%d%s%> in " "declaration specifiers"), - floatn_nx_types[specs->floatn_nx_idx].n, - (floatn_nx_types[specs->floatn_nx_idx].extended + floatn_nx_types[specs->u.floatn_nx_idx].n, + (floatn_nx_types[specs->u.floatn_nx_idx].extended ? "x" : "")); else if (specs->typespec_word == cts_dfloat32) @@ -11731,8 +11746,8 @@ declspecs_add_type (location_t loc, stru error_at (loc, ("both % and %<_Float%d%s%> in " "declaration specifiers"), - floatn_nx_types[specs->floatn_nx_idx].n, - (floatn_nx_types[specs->floatn_nx_idx].extended + floatn_nx_types[specs->u.floatn_nx_idx].n, + (floatn_nx_types[specs->u.floatn_nx_idx].extended ? "x" : "")); else if (specs->typespec_word == cts_dfloat32) @@ -11770,6 +11785,10 @@ declspecs_add_type (location_t loc, stru error_at (loc, ("both % and %<_Bool%> in " "declaration specifiers")); + else if (specs->typespec_word == cts_bitint) + error_at (loc, + ("both % and %<_BitInt%> in " + "declaration specifiers")); else if (specs->typespec_word == cts_dfloat32) error_at (loc, ("both % and %<_Decimal32%> in " @@ -11809,7 +11828,7 @@ declspecs_add_type (location_t loc, stru error_at (loc, ("both %<_Sat%> and %<__int%d%> in " "declaration specifiers"), - int_n_data[specs->int_n_idx].bitsize); + int_n_data[specs->u.int_n_idx].bitsize); } else if (specs->typespec_word == cts_auto_type) error_at (loc, @@ -11823,6 +11842,10 @@ declspecs_add_type (location_t loc, stru error_at (loc, ("both %<_Sat%> and %<_Bool%> in " "declaration specifiers")); + else if (specs->typespec_word == cts_bitint) + error_at (loc, + ("both %<_Sat%> and %<_BitInt%> in " + "declaration specifiers")); else if (specs->typespec_word == cts_char) error_at (loc, ("both %<_Sat%> and % in " @@ -11843,8 +11866,8 @@ declspecs_add_type (location_t loc, stru error_at (loc, ("both %<_Sat%> and %<_Float%d%s%> in " "declaration specifiers"), - floatn_nx_types[specs->floatn_nx_idx].n, - (floatn_nx_types[specs->floatn_nx_idx].extended + floatn_nx_types[specs->u.floatn_nx_idx].n, + (floatn_nx_types[specs->u.floatn_nx_idx].extended ? "x" : "")); else if (specs->typespec_word == cts_dfloat32) @@ -11882,7 +11905,7 @@ declspecs_add_type (location_t loc, stru { /* "void", "_Bool", "char", "int", "float", "double", "_FloatN", "_FloatNx", "_Decimal32", "__intN", - "_Decimal64", "_Decimal128", "_Fract", "_Accum" or + "_Decimal64", "_Decimal128", "_Fract", "_Accum", "_BitInt(N)" or "__auto_type". */ if (specs->typespec_word != cts_none) { @@ -11927,7 +11950,7 @@ declspecs_add_type (location_t loc, stru case RID_INT_N_1: case RID_INT_N_2: case RID_INT_N_3: - specs->int_n_idx = i - RID_INT_N_0; + specs->u.int_n_idx = i - RID_INT_N_0; if (!in_system_header_at (input_location) /* If the INT_N type ends in "__", and so is of the format "__intN__", don't pedwarn. */ @@ -11935,29 +11958,29 @@ declspecs_add_type (location_t loc, stru + (IDENTIFIER_LENGTH (type) - 2), "__", 2) != 0)) pedwarn (loc, OPT_Wpedantic, "ISO C does not support %<__int%d%> types", - int_n_data[specs->int_n_idx].bitsize); + int_n_data[specs->u.int_n_idx].bitsize); if (specs->long_p) error_at (loc, ("both %<__int%d%> and % in " "declaration specifiers"), - int_n_data[specs->int_n_idx].bitsize); + int_n_data[specs->u.int_n_idx].bitsize); else if (specs->saturating_p) error_at (loc, ("both %<_Sat%> and %<__int%d%> in " "declaration specifiers"), - int_n_data[specs->int_n_idx].bitsize); + int_n_data[specs->u.int_n_idx].bitsize); else if (specs->short_p) error_at (loc, ("both %<__int%d%> and % in " "declaration specifiers"), - int_n_data[specs->int_n_idx].bitsize); - else if (! int_n_enabled_p[specs->int_n_idx]) + int_n_data[specs->u.int_n_idx].bitsize); + else if (! int_n_enabled_p[specs->u.int_n_idx]) { specs->typespec_word = cts_int_n; error_at (loc, "%<__int%d%> is not supported on this target", - int_n_data[specs->int_n_idx].bitsize); + int_n_data[specs->u.int_n_idx].bitsize); } else { @@ -12115,12 +12138,12 @@ declspecs_add_type (location_t loc, stru } return specs; CASE_RID_FLOATN_NX: - specs->floatn_nx_idx = i - RID_FLOATN_NX_FIRST; + specs->u.floatn_nx_idx = i - RID_FLOATN_NX_FIRST; if (!in_system_header_at (input_location)) pedwarn (loc, OPT_Wpedantic, "ISO C does not support the %<_Float%d%s%> type", - floatn_nx_types[specs->floatn_nx_idx].n, - (floatn_nx_types[specs->floatn_nx_idx].extended + floatn_nx_types[specs->u.floatn_nx_idx].n, + (floatn_nx_types[specs->u.floatn_nx_idx].extended ? "x" : "")); @@ -12128,49 +12151,49 @@ declspecs_add_type (location_t loc, stru error_at (loc, ("both % and %<_Float%d%s%> in " "declaration specifiers"), - floatn_nx_types[specs->floatn_nx_idx].n, - (floatn_nx_types[specs->floatn_nx_idx].extended + floatn_nx_types[specs->u.floatn_nx_idx].n, + (floatn_nx_types[specs->u.floatn_nx_idx].extended ? "x" : "")); else if (specs->short_p) error_at (loc, ("both % and %<_Float%d%s%> in " "declaration specifiers"), - floatn_nx_types[specs->floatn_nx_idx].n, - (floatn_nx_types[specs->floatn_nx_idx].extended + floatn_nx_types[specs->u.floatn_nx_idx].n, + (floatn_nx_types[specs->u.floatn_nx_idx].extended ? "x" : "")); else if (specs->signed_p) error_at (loc, ("both % and %<_Float%d%s%> in " "declaration specifiers"), - floatn_nx_types[specs->floatn_nx_idx].n, - (floatn_nx_types[specs->floatn_nx_idx].extended + floatn_nx_types[specs->u.floatn_nx_idx].n, + (floatn_nx_types[specs->u.floatn_nx_idx].extended ? "x" : "")); else if (specs->unsigned_p) error_at (loc, ("both % and %<_Float%d%s%> in " "declaration specifiers"), - floatn_nx_types[specs->floatn_nx_idx].n, - (floatn_nx_types[specs->floatn_nx_idx].extended + floatn_nx_types[specs->u.floatn_nx_idx].n, + (floatn_nx_types[specs->u.floatn_nx_idx].extended ? "x" : "")); else if (specs->saturating_p) error_at (loc, ("both %<_Sat%> and %<_Float%d%s%> in " "declaration specifiers"), - floatn_nx_types[specs->floatn_nx_idx].n, - (floatn_nx_types[specs->floatn_nx_idx].extended + floatn_nx_types[specs->u.floatn_nx_idx].n, + (floatn_nx_types[specs->u.floatn_nx_idx].extended ? "x" : "")); - else if (FLOATN_NX_TYPE_NODE (specs->floatn_nx_idx) == NULL_TREE) + else if (FLOATN_NX_TYPE_NODE (specs->u.floatn_nx_idx) == NULL_TREE) { specs->typespec_word = cts_floatn_nx; error_at (loc, "%<_Float%d%s%> is not supported on this target", - floatn_nx_types[specs->floatn_nx_idx].n, - (floatn_nx_types[specs->floatn_nx_idx].extended + floatn_nx_types[specs->u.floatn_nx_idx].n, + (floatn_nx_types[specs->u.floatn_nx_idx].extended ? "x" : "")); } @@ -12267,6 +12290,63 @@ declspecs_add_type (location_t loc, stru pedwarn (loc, OPT_Wpedantic, "ISO C does not support fixed-point types"); return specs; + case RID_BITINT: + if (specs->long_p) + error_at (loc, + ("both % and %<_BitInt%> in " + "declaration specifiers")); + else if (specs->short_p) + error_at (loc, + ("both % and %<_BitInt%> in " + "declaration specifiers")); + else if (specs->complex_p) + error_at (loc, + ("both % and %<_BitInt%> in " + "declaration specifiers")); + else if (specs->saturating_p) + error_at (loc, + ("both %<_Sat%> and %<_BitInt%> in " + "declaration specifiers")); + else + { + specs->typespec_word = cts_bitint; + specs->locations[cdw_typespec] = loc; + specs->u.bitint_prec = -1; + if (error_operand_p (spec.expr)) + return specs; + if (TREE_CODE (spec.expr) != INTEGER_CST + || !INTEGRAL_TYPE_P (TREE_TYPE (spec.expr))) + { + error_at (loc, "%<_BitInt%> argument is not an integer " + "constant expression"); + return specs; + } + if (tree_int_cst_sgn (spec.expr) <= 0) + { + error_at (loc, "%<_BitInt%> argument %qE is not " + "positive integer constant expression", + spec.expr); + return specs; + } + if (wi::to_widest (spec.expr) > WIDE_INT_MAX_PRECISION - 1) + { + error_at (loc, "%<_BitInt%> argument %qE is larger than " + "% %qd", + spec.expr, (int) WIDE_INT_MAX_PRECISION - 1); + return specs; + } + specs->u.bitint_prec = tree_to_uhwi (spec.expr); + struct bitint_info info; + if (!targetm.c.bitint_type_info (specs->u.bitint_prec, + &info)) + { + sorry_at (loc, "%<_BitInt(%d)%> is not supported on " + "this target", specs->u.bitint_prec); + specs->u.bitint_prec = -1; + return specs; + } + } + return specs; default: /* ObjC reserved word "id", handled below. */ break; @@ -12668,12 +12748,12 @@ finish_declspecs (struct c_declspecs *sp case cts_int_n: gcc_assert (!specs->long_p && !specs->short_p && !specs->long_long_p); gcc_assert (!(specs->signed_p && specs->unsigned_p)); - if (! int_n_enabled_p[specs->int_n_idx]) + if (! int_n_enabled_p[specs->u.int_n_idx]) specs->type = integer_type_node; else specs->type = (specs->unsigned_p - ? int_n_trees[specs->int_n_idx].unsigned_type - : int_n_trees[specs->int_n_idx].signed_type); + ? int_n_trees[specs->u.int_n_idx].unsigned_type + : int_n_trees[specs->u.int_n_idx].signed_type); if (specs->complex_p) { pedwarn (specs->locations[cdw_complex], OPT_Wpedantic, @@ -12733,12 +12813,12 @@ finish_declspecs (struct c_declspecs *sp case cts_floatn_nx: gcc_assert (!specs->long_p && !specs->short_p && !specs->signed_p && !specs->unsigned_p); - if (FLOATN_NX_TYPE_NODE (specs->floatn_nx_idx) == NULL_TREE) + if (FLOATN_NX_TYPE_NODE (specs->u.floatn_nx_idx) == NULL_TREE) specs->type = integer_type_node; else if (specs->complex_p) - specs->type = COMPLEX_FLOATN_NX_TYPE_NODE (specs->floatn_nx_idx); + specs->type = COMPLEX_FLOATN_NX_TYPE_NODE (specs->u.floatn_nx_idx); else - specs->type = FLOATN_NX_TYPE_NODE (specs->floatn_nx_idx); + specs->type = FLOATN_NX_TYPE_NODE (specs->u.floatn_nx_idx); break; case cts_dfloat32: case cts_dfloat64: @@ -12840,6 +12920,22 @@ finish_declspecs (struct c_declspecs *sp : accum_type_node; } break; + case cts_bitint: + gcc_assert (!specs->long_p && !specs->short_p + && !specs->complex_p); + if (!specs->unsigned_p && specs->u.bitint_prec == 1) + { + error_at (specs->locations[cdw_typespec], + "% argument must be at least 2"); + specs->type = integer_type_node; + break; + } + if (specs->u.bitint_prec == -1) + specs->type = integer_type_node; + else + specs->type = build_bitint_type (specs->u.bitint_prec, + specs->unsigned_p); + break; default: gcc_unreachable (); } --- gcc/c/c-parser.cc.jj 2023-08-08 15:55:05.286181541 +0200 +++ gcc/c/c-parser.cc 2023-08-08 16:12:02.336939700 +0200 @@ -580,6 +580,7 @@ c_keyword_starts_typename (enum rid keyw case RID_DFLOAT128: CASE_RID_FLOATN_NX: case RID_BOOL: + case RID_BITINT: case RID_ENUM: case RID_STRUCT: case RID_UNION: @@ -783,6 +784,7 @@ c_token_starts_declspecs (c_token *token case RID_DFLOAT128: CASE_RID_FLOATN_NX: case RID_BOOL: + case RID_BITINT: case RID_ENUM: case RID_STRUCT: case RID_UNION: @@ -3358,6 +3360,30 @@ c_parser_declspecs (c_parser *parser, st t = c_parser_typeof_specifier (parser); declspecs_add_type (loc, specs, t); break; + case RID_BITINT: + if (!typespec_ok) + goto out; + else + { + attrs_ok = true; + seen_type = true; + t.kind = ctsk_resword; + t.spec = c_parser_peek_token (parser)->value; + t.expr = error_mark_node; + t.expr_const_operands = true; + t.has_enum_type_specifier = false; + c_parser_consume_token (parser); + matching_parens parens; + if (parens.require_open (parser)) + { + c_expr expr = c_parser_expr_no_commas (parser, NULL); + t.expr = convert_lvalue_to_rvalue (loc, expr, true, + true).value; + parens.skip_until_found_close (parser); + } + declspecs_add_type (loc, specs, t); + } + break; case RID_ATOMIC: /* C parser handling of Objective-C constructs needs checking for correct lvalue-to-rvalue conversions, and @@ -5005,6 +5031,7 @@ c_parser_gnu_attribute_any_word (c_parse case RID_DFLOAT128: CASE_RID_FLOATN_NX: case RID_BOOL: + case RID_BITINT: case RID_FRACT: case RID_ACCUM: case RID_SAT: --- gcc/c/c-tree.h.jj 2023-08-08 15:54:33.812622298 +0200 +++ gcc/c/c-tree.h 2023-08-08 16:12:02.336939700 +0200 @@ -270,7 +270,7 @@ enum c_storage_class { /* A type specifier keyword "void", "_Bool", "char", "int", "float", "double", "_Decimal32", "_Decimal64", "_Decimal128", "_Fract", "_Accum", - or none of these. */ + "_BitInt", or none of these. */ enum c_typespec_keyword { cts_none, cts_void, @@ -286,6 +286,7 @@ enum c_typespec_keyword { cts_floatn_nx, cts_fract, cts_accum, + cts_bitint, cts_auto_type }; @@ -366,11 +367,16 @@ struct c_declspecs { specifier, in bytes, or -1 if no such specifiers with nonzero alignment. */ int align_log; - /* For the __intN declspec, this stores the index into the int_n_* arrays. */ - int int_n_idx; - /* For the _FloatN and _FloatNx declspec, this stores the index into - the floatn_nx_types array. */ - int floatn_nx_idx; + union { + /* For the __intN declspec, this stores the index into the int_n_* + arrays. */ + int int_n_idx; + /* For the _FloatN and _FloatNx declspec, this stores the index into + the floatn_nx_types array. */ + int floatn_nx_idx; + /* For _BitInt(N) this stores the N. */ + int bitint_prec; + } u; /* The storage class specifier, or csc_none if none. */ enum c_storage_class storage_class; /* Any type specifier keyword used such as "int", not reflecting --- gcc/c/c-typeck.cc.jj 2023-08-08 15:54:33.822622158 +0200 +++ gcc/c/c-typeck.cc 2023-08-08 16:15:41.008877766 +0200 @@ -413,10 +413,14 @@ composite_type (tree t1, tree t2) the composite type. */ if (code1 == ENUMERAL_TYPE - && (code2 == INTEGER_TYPE || code2 == BOOLEAN_TYPE)) + && (code2 == INTEGER_TYPE + || code2 == BOOLEAN_TYPE + || code2 == BITINT_TYPE)) return t1; if (code2 == ENUMERAL_TYPE - && (code1 == INTEGER_TYPE || code1 == BOOLEAN_TYPE)) + && (code1 == INTEGER_TYPE + || code1 == BOOLEAN_TYPE + || code1 == BITINT_TYPE)) return t2; gcc_assert (code1 == code2); @@ -764,10 +768,10 @@ c_common_type (tree t1, tree t2) gcc_assert (code1 == VECTOR_TYPE || code1 == COMPLEX_TYPE || code1 == FIXED_POINT_TYPE || code1 == REAL_TYPE - || code1 == INTEGER_TYPE); + || code1 == INTEGER_TYPE || code1 == BITINT_TYPE); gcc_assert (code2 == VECTOR_TYPE || code2 == COMPLEX_TYPE || code2 == FIXED_POINT_TYPE || code2 == REAL_TYPE - || code2 == INTEGER_TYPE); + || code2 == INTEGER_TYPE || code2 == BITINT_TYPE); /* When one operand is a decimal float type, the other operand cannot be a generic float type or a complex type. We also disallow vector types @@ -1004,6 +1008,20 @@ c_common_type (tree t1, tree t2) if (mv1 == FLOATNX_TYPE_NODE (i) || mv2 == FLOATNX_TYPE_NODE (i)) return FLOATNX_TYPE_NODE (i); + if ((code1 == BITINT_TYPE || code2 == BITINT_TYPE) && code1 != code2) + { + /* Prefer any other integral types over bit-precise integer types. */ + if (TYPE_UNSIGNED (t1) == TYPE_UNSIGNED (t2)) + return code1 == BITINT_TYPE ? t2 : t1; + /* If BITINT_TYPE is unsigned and the other type is signed + non-BITINT_TYPE with the same precision, the latter has higher rank. + In that case: + Otherwise, both operands are converted to the unsigned integer type + corresponding to the type of the operand with signed integer type. */ + if (TYPE_UNSIGNED (code1 == BITINT_TYPE ? t1 : t2)) + return c_common_unsigned_type (code1 == BITINT_TYPE ? t2 : t1); + } + /* Otherwise prefer the unsigned one. */ if (TYPE_UNSIGNED (t1)) @@ -1177,6 +1195,7 @@ comptypes_internal (const_tree type1, co case INTEGER_TYPE: case FIXED_POINT_TYPE: case REAL_TYPE: + case BITINT_TYPE: /* With these nodes, we can't determine type equivalence by looking at what is stored in the nodes themselves, because two nodes might have different TYPE_MAIN_VARIANTs but still @@ -2260,12 +2279,17 @@ perform_integral_promotions (tree exp) /* ??? This should no longer be needed now bit-fields have their proper types. */ if (TREE_CODE (exp) == COMPONENT_REF - && DECL_C_BIT_FIELD (TREE_OPERAND (exp, 1)) + && DECL_C_BIT_FIELD (TREE_OPERAND (exp, 1))) + { + if (TREE_CODE (DECL_BIT_FIELD_TYPE (TREE_OPERAND (exp, 1))) + == BITINT_TYPE) + return convert (DECL_BIT_FIELD_TYPE (TREE_OPERAND (exp, 1)), exp); /* If it's thinner than an int, promote it like a c_promoting_integer_type_p, otherwise leave it alone. */ - && compare_tree_int (DECL_SIZE (TREE_OPERAND (exp, 1)), - TYPE_PRECISION (integer_type_node)) < 0) - return convert (integer_type_node, exp); + if (compare_tree_int (DECL_SIZE (TREE_OPERAND (exp, 1)), + TYPE_PRECISION (integer_type_node)) < 0) + return convert (integer_type_node, exp); + } if (c_promoting_integer_type_p (type)) { @@ -2790,7 +2814,8 @@ build_array_ref (location_t loc, tree ar if (index == error_mark_node) return error_mark_node; - gcc_assert (TREE_CODE (TREE_TYPE (index)) == INTEGER_TYPE); + gcc_assert (TREE_CODE (TREE_TYPE (index)) == INTEGER_TYPE + || TREE_CODE (TREE_TYPE (index)) == BITINT_TYPE); bool was_vector = VECTOR_TYPE_P (TREE_TYPE (array)); bool non_lvalue = convert_vector_to_array_for_subscript (loc, &array, index); @@ -4558,6 +4583,7 @@ build_unary_op (location_t location, enu associativity, but won't generate any code. */ if (!(typecode == INTEGER_TYPE || typecode == REAL_TYPE || typecode == FIXED_POINT_TYPE || typecode == COMPLEX_TYPE + || typecode == BITINT_TYPE || gnu_vector_type_p (TREE_TYPE (arg)))) { error_at (location, "wrong type argument to unary plus"); @@ -4571,6 +4597,7 @@ build_unary_op (location_t location, enu case NEGATE_EXPR: if (!(typecode == INTEGER_TYPE || typecode == REAL_TYPE || typecode == FIXED_POINT_TYPE || typecode == COMPLEX_TYPE + || typecode == BITINT_TYPE || gnu_vector_type_p (TREE_TYPE (arg)))) { error_at (location, "wrong type argument to unary minus"); @@ -4583,6 +4610,7 @@ build_unary_op (location_t location, enu case BIT_NOT_EXPR: /* ~ works on integer types and non float vectors. */ if (typecode == INTEGER_TYPE + || typecode == BITINT_TYPE || (gnu_vector_type_p (TREE_TYPE (arg)) && !VECTOR_FLOAT_TYPE_P (TREE_TYPE (arg)))) { @@ -4657,7 +4685,8 @@ build_unary_op (location_t location, enu case TRUTH_NOT_EXPR: if (typecode != INTEGER_TYPE && typecode != FIXED_POINT_TYPE && typecode != REAL_TYPE && typecode != POINTER_TYPE - && typecode != COMPLEX_TYPE && typecode != NULLPTR_TYPE) + && typecode != COMPLEX_TYPE && typecode != NULLPTR_TYPE + && typecode != BITINT_TYPE) { error_at (location, "wrong type argument to unary exclamation mark"); @@ -4769,7 +4798,7 @@ build_unary_op (location_t location, enu if (typecode != POINTER_TYPE && typecode != FIXED_POINT_TYPE && typecode != INTEGER_TYPE && typecode != REAL_TYPE - && typecode != COMPLEX_TYPE + && typecode != COMPLEX_TYPE && typecode != BITINT_TYPE && !gnu_vector_type_p (TREE_TYPE (arg))) { if (code == PREINCREMENT_EXPR || code == POSTINCREMENT_EXPR) @@ -5394,9 +5423,9 @@ build_conditional_expr (location_t colon result_type = TYPE_MAIN_VARIANT (type1); } else if ((code1 == INTEGER_TYPE || code1 == REAL_TYPE - || code1 == COMPLEX_TYPE) + || code1 == COMPLEX_TYPE || code1 == BITINT_TYPE) && (code2 == INTEGER_TYPE || code2 == REAL_TYPE - || code2 == COMPLEX_TYPE)) + || code2 == COMPLEX_TYPE || code2 == BITINT_TYPE)) { /* In C11, a conditional expression between a floating-point type and an integer type should convert the integer type to @@ -5583,7 +5612,8 @@ build_conditional_expr (location_t colon (build_qualified_type (void_type_node, qual)); } } - else if (code1 == POINTER_TYPE && code2 == INTEGER_TYPE) + else if (code1 == POINTER_TYPE + && (code2 == INTEGER_TYPE || code2 == BITINT_TYPE)) { if (!null_pointer_constant_p (orig_op2)) pedwarn (colon_loc, 0, @@ -5594,7 +5624,8 @@ build_conditional_expr (location_t colon } result_type = type1; } - else if (code2 == POINTER_TYPE && code1 == INTEGER_TYPE) + else if (code2 == POINTER_TYPE + && (code1 == INTEGER_TYPE || code1 == BITINT_TYPE)) { if (!null_pointer_constant_p (orig_op1)) pedwarn (colon_loc, 0, @@ -7131,11 +7162,11 @@ convert_for_assignment (location_t locat else if ((codel == INTEGER_TYPE || codel == REAL_TYPE || codel == FIXED_POINT_TYPE || codel == ENUMERAL_TYPE || codel == COMPLEX_TYPE - || codel == BOOLEAN_TYPE) + || codel == BOOLEAN_TYPE || codel == BITINT_TYPE) && (coder == INTEGER_TYPE || coder == REAL_TYPE || coder == FIXED_POINT_TYPE || coder == ENUMERAL_TYPE || coder == COMPLEX_TYPE - || coder == BOOLEAN_TYPE)) + || coder == BOOLEAN_TYPE || coder == BITINT_TYPE)) { if (warnopt && errtype == ic_argpass) maybe_warn_builtin_no_proto_arg (expr_loc, fundecl, parmnum, type, @@ -8562,7 +8593,8 @@ digest_init (location_t init_loc, tree t if (code == INTEGER_TYPE || code == REAL_TYPE || code == FIXED_POINT_TYPE || code == POINTER_TYPE || code == ENUMERAL_TYPE || code == BOOLEAN_TYPE - || code == COMPLEX_TYPE || code == VECTOR_TYPE || code == NULLPTR_TYPE) + || code == COMPLEX_TYPE || code == VECTOR_TYPE || code == NULLPTR_TYPE + || code == BITINT_TYPE) { tree unconverted_init = inside_init; if (TREE_CODE (TREE_TYPE (init)) == ARRAY_TYPE @@ -12357,12 +12389,14 @@ build_binary_op (location_t location, en { case PLUS_EXPR: /* Handle the pointer + int case. */ - if (code0 == POINTER_TYPE && code1 == INTEGER_TYPE) + if (code0 == POINTER_TYPE + && (code1 == INTEGER_TYPE || code1 == BITINT_TYPE)) { ret = pointer_int_sum (location, PLUS_EXPR, op0, op1); goto return_build_binary_op; } - else if (code1 == POINTER_TYPE && code0 == INTEGER_TYPE) + else if (code1 == POINTER_TYPE + && (code0 == INTEGER_TYPE || code0 == BITINT_TYPE)) { ret = pointer_int_sum (location, PLUS_EXPR, op1, op0); goto return_build_binary_op; @@ -12381,7 +12415,8 @@ build_binary_op (location_t location, en goto return_build_binary_op; } /* Handle pointer minus int. Just like pointer plus int. */ - else if (code0 == POINTER_TYPE && code1 == INTEGER_TYPE) + else if (code0 == POINTER_TYPE + && (code1 == INTEGER_TYPE || code1 == BITINT_TYPE)) { ret = pointer_int_sum (location, MINUS_EXPR, op0, op1); goto return_build_binary_op; @@ -12403,11 +12438,11 @@ build_binary_op (location_t location, en warn_for_div_by_zero (location, op1); if ((code0 == INTEGER_TYPE || code0 == REAL_TYPE - || code0 == FIXED_POINT_TYPE + || code0 == FIXED_POINT_TYPE || code0 == BITINT_TYPE || code0 == COMPLEX_TYPE || gnu_vector_type_p (type0)) && (code1 == INTEGER_TYPE || code1 == REAL_TYPE - || code1 == FIXED_POINT_TYPE + || code1 == FIXED_POINT_TYPE || code1 == BITINT_TYPE || code1 == COMPLEX_TYPE || gnu_vector_type_p (type1))) { @@ -12418,8 +12453,9 @@ build_binary_op (location_t location, en if (code1 == COMPLEX_TYPE || code1 == VECTOR_TYPE) tcode1 = TREE_CODE (TREE_TYPE (TREE_TYPE (op1))); - if (!((tcode0 == INTEGER_TYPE && tcode1 == INTEGER_TYPE) - || (tcode0 == FIXED_POINT_TYPE && tcode1 == FIXED_POINT_TYPE))) + if (!(((tcode0 == INTEGER_TYPE || tcode0 == BITINT_TYPE) + && (tcode1 == INTEGER_TYPE || tcode1 == BITINT_TYPE)) + || (tcode0 == FIXED_POINT_TYPE && tcode1 == FIXED_POINT_TYPE))) resultcode = RDIV_EXPR; else /* Although it would be tempting to shorten always here, that @@ -12435,7 +12471,8 @@ build_binary_op (location_t location, en case BIT_AND_EXPR: case BIT_IOR_EXPR: case BIT_XOR_EXPR: - if (code0 == INTEGER_TYPE && code1 == INTEGER_TYPE) + if ((code0 == INTEGER_TYPE || code0 == BITINT_TYPE) + && (code1 == INTEGER_TYPE || code1 == BITINT_TYPE)) shorten = -1; /* Allow vector types which are not floating point types. */ else if (gnu_vector_type_p (type0) @@ -12455,7 +12492,8 @@ build_binary_op (location_t location, en && TREE_CODE (TREE_TYPE (type0)) == INTEGER_TYPE && TREE_CODE (TREE_TYPE (type1)) == INTEGER_TYPE) common = 1; - else if (code0 == INTEGER_TYPE && code1 == INTEGER_TYPE) + else if ((code0 == INTEGER_TYPE || code0 == BITINT_TYPE) + && (code1 == INTEGER_TYPE || code1 == BITINT_TYPE)) { /* Although it would be tempting to shorten always here, that loses on some targets, since the modulo instruction is undefined if the @@ -12473,10 +12511,12 @@ build_binary_op (location_t location, en case TRUTH_XOR_EXPR: if ((code0 == INTEGER_TYPE || code0 == POINTER_TYPE || code0 == REAL_TYPE || code0 == COMPLEX_TYPE - || code0 == FIXED_POINT_TYPE || code0 == NULLPTR_TYPE) + || code0 == FIXED_POINT_TYPE || code0 == NULLPTR_TYPE + || code0 == BITINT_TYPE) && (code1 == INTEGER_TYPE || code1 == POINTER_TYPE || code1 == REAL_TYPE || code1 == COMPLEX_TYPE - || code1 == FIXED_POINT_TYPE || code1 == NULLPTR_TYPE)) + || code1 == FIXED_POINT_TYPE || code1 == NULLPTR_TYPE + || code1 == BITINT_TYPE)) { /* Result of these operations is always an int, but that does not mean the operands should be @@ -12539,9 +12579,10 @@ build_binary_op (location_t location, en converted = 1; } else if ((code0 == INTEGER_TYPE || code0 == FIXED_POINT_TYPE + || code0 == BITINT_TYPE || (gnu_vector_type_p (type0) && TREE_CODE (TREE_TYPE (type0)) == INTEGER_TYPE)) - && code1 == INTEGER_TYPE) + && (code1 == INTEGER_TYPE || code1 == BITINT_TYPE)) { doing_shift = true; if (TREE_CODE (op1) == INTEGER_CST) @@ -12599,9 +12640,10 @@ build_binary_op (location_t location, en converted = 1; } else if ((code0 == INTEGER_TYPE || code0 == FIXED_POINT_TYPE + || code0 == BITINT_TYPE || (gnu_vector_type_p (type0) && TREE_CODE (TREE_TYPE (type0)) == INTEGER_TYPE)) - && code1 == INTEGER_TYPE) + && (code1 == INTEGER_TYPE || code1 == BITINT_TYPE)) { doing_shift = true; if (TREE_CODE (op0) == INTEGER_CST @@ -12715,9 +12757,10 @@ build_binary_op (location_t location, en /* Result of comparison is always int, but don't convert the args to int! */ build_type = integer_type_node; - if ((code0 == INTEGER_TYPE || code0 == REAL_TYPE + if ((code0 == INTEGER_TYPE || code0 == REAL_TYPE || code0 == BITINT_TYPE || code0 == FIXED_POINT_TYPE || code0 == COMPLEX_TYPE) && (code1 == INTEGER_TYPE || code1 == REAL_TYPE + || code1 == BITINT_TYPE || code1 == FIXED_POINT_TYPE || code1 == COMPLEX_TYPE)) short_compare = 1; else if (code0 == POINTER_TYPE @@ -12778,12 +12821,14 @@ build_binary_op (location_t location, en (build_qualified_type (void_type_node, qual)); } } - else if (code0 == POINTER_TYPE && code1 == INTEGER_TYPE) + else if (code0 == POINTER_TYPE + && (code1 == INTEGER_TYPE || code1 == BITINT_TYPE)) { result_type = type0; pedwarn (location, 0, "comparison between pointer and integer"); } - else if (code0 == INTEGER_TYPE && code1 == POINTER_TYPE) + else if ((code0 == INTEGER_TYPE || code0 == BITINT_TYPE) + && code1 == POINTER_TYPE) { result_type = type1; pedwarn (location, 0, "comparison between pointer and integer"); @@ -12871,9 +12916,9 @@ build_binary_op (location_t location, en } build_type = integer_type_node; if ((code0 == INTEGER_TYPE || code0 == REAL_TYPE - || code0 == FIXED_POINT_TYPE) + || code0 == BITINT_TYPE || code0 == FIXED_POINT_TYPE) && (code1 == INTEGER_TYPE || code1 == REAL_TYPE - || code1 == FIXED_POINT_TYPE)) + || code1 == BITINT_TYPE || code1 == FIXED_POINT_TYPE)) short_compare = 1; else if (code0 == POINTER_TYPE && code1 == POINTER_TYPE) { @@ -12932,12 +12977,14 @@ build_binary_op (location_t location, en warning_at (location, OPT_Wextra, "ordered comparison of pointer with integer zero"); } - else if (code0 == POINTER_TYPE && code1 == INTEGER_TYPE) + else if (code0 == POINTER_TYPE + && (code1 == INTEGER_TYPE || code1 == BITINT_TYPE)) { result_type = type0; pedwarn (location, 0, "comparison between pointer and integer"); } - else if (code0 == INTEGER_TYPE && code1 == POINTER_TYPE) + else if ((code0 == INTEGER_TYPE || code0 == BITINT_TYPE) + && code1 == POINTER_TYPE) { result_type = type1; pedwarn (location, 0, "comparison between pointer and integer"); @@ -12991,12 +13038,11 @@ build_binary_op (location_t location, en } if ((code0 == INTEGER_TYPE || code0 == REAL_TYPE || code0 == COMPLEX_TYPE - || code0 == FIXED_POINT_TYPE + || code0 == FIXED_POINT_TYPE || code0 == BITINT_TYPE || gnu_vector_type_p (type0)) - && - (code1 == INTEGER_TYPE || code1 == REAL_TYPE || code1 == COMPLEX_TYPE - || code1 == FIXED_POINT_TYPE - || gnu_vector_type_p (type1))) + && (code1 == INTEGER_TYPE || code1 == REAL_TYPE || code1 == COMPLEX_TYPE + || code1 == FIXED_POINT_TYPE || code1 == BITINT_TYPE + || gnu_vector_type_p (type1))) { bool first_complex = (code0 == COMPLEX_TYPE); bool second_complex = (code1 == COMPLEX_TYPE); --- libcpp/expr.cc.jj 2023-08-08 15:54:35.666596337 +0200 +++ libcpp/expr.cc 2023-08-08 16:12:02.346939560 +0200 @@ -327,9 +327,9 @@ static unsigned int interpret_int_suffix (cpp_reader *pfile, const uchar *s, size_t len) { size_t orig_len = len; - size_t u, l, i, z; + size_t u, l, i, z, wb; - u = l = i = z = 0; + u = l = i = z = wb = 0; while (len--) switch (s[len]) @@ -343,11 +343,23 @@ interpret_int_suffix (cpp_reader *pfile, if (l == 2 && s[len] != s[len + 1]) return 0; break; + case 'b': + if (len == 0 || s[len - 1] != 'w') + return 0; + wb++; + len--; + break; + case 'B': + if (len == 0 || s[len - 1] != 'W') + return 0; + wb++; + len--; + break; default: return 0; } - if (l > 2 || u > 1 || i > 1 || z > 1) + if (l > 2 || u > 1 || i > 1 || z > 1 || wb > 1) return 0; if (z) @@ -358,6 +370,14 @@ interpret_int_suffix (cpp_reader *pfile, return 0; } + if (wb) + { + if (CPP_OPTION (pfile, cplusplus)) + return 0; + if (l > 0 || i > 0 || z > 0) + return 0; + } + if (i) { if (!CPP_OPTION (pfile, ext_numeric_literals)) @@ -376,7 +396,8 @@ interpret_int_suffix (cpp_reader *pfile, | (u ? CPP_N_UNSIGNED : 0) | ((l == 0) ? CPP_N_SMALL : (l == 1) ? CPP_N_MEDIUM : CPP_N_LARGE) - | (z ? CPP_N_SIZE_T : 0)); + | (z ? CPP_N_SIZE_T : 0) + | (wb ? CPP_N_BITINT : 0)); } /* Return the classification flags for an int suffix. */ --- libcpp/include/cpplib.h.jj 2023-08-08 15:54:35.691595987 +0200 +++ libcpp/include/cpplib.h 2023-08-08 16:12:02.346939560 +0200 @@ -1284,6 +1284,7 @@ struct cpp_num #define CPP_N_SIZE_T 0x2000000 /* C++23 size_t literal. */ #define CPP_N_BFLOAT16 0x4000000 /* std::bfloat16_t type. */ +#define CPP_N_BITINT 0x8000000 /* C2X _BitInt literal. */ #define CPP_N_WIDTH_FLOATN_NX 0xF0000000 /* _FloatN / _FloatNx value of N, divided by 16. */