From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from mx0b-00069f02.pphosted.com (mx0b-00069f02.pphosted.com [205.220.177.32]) by sourceware.org (Postfix) with ESMTPS id D0960388456C for ; Wed, 26 Oct 2022 19:30:07 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.1 sourceware.org D0960388456C Authentication-Results: sourceware.org; dmarc=pass (p=none dis=none) header.from=oracle.com Authentication-Results: sourceware.org; spf=pass smtp.mailfrom=oracle.com Received: from pps.filterd (m0246632.ppops.net [127.0.0.1]) by mx0b-00069f02.pphosted.com (8.17.1.5/8.17.1.5) with ESMTP id 29QJGxer028126 for ; Wed, 26 Oct 2022 19:30:07 GMT DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=oracle.com; h=from : to : cc : subject : references : date : in-reply-to : message-id : content-type : mime-version; s=corp-2022-7-12; bh=CU8yw8K1V2cC/nETi8bGsgKS+EHrntL+7PZaRkQmFD8=; b=pZKwZlDh23BPTqtvwLlLawV0C7vf+WfC+wEMzsxxjWebb5YM5GYsiRg1jMXYTmMuyMjj ARnqzFeK9JKHxU1PgZcsKj+7Nzg/Bu0I5RBJvKH9WJRFPZKqvDTdJpI+CURIgDffXPpC a/jSD5+3K68zowqWFv5zKMm6XejEVWFtlx2sd5v7DLZ2N1M/eixn9gVl3Ecp7+eK2RQ0 jeqn0V2RFbavgRV/0dbnUGE+DTls6vyUcwycx0aw+wUmf6R84T8HYB77NmIC+h9rKxd5 17DkuCNZWJ37znFNDHqVNJo1I+TC+JvhY9TGZwX/ocog1m1FDD1PouDJbfgqnKNlWlx/ BQ== Received: from phxpaimrmta02.imrmtpd1.prodappphxaev1.oraclevcn.com (phxpaimrmta02.appoci.oracle.com [147.154.114.232]) by mx0b-00069f02.pphosted.com (PPS) with ESMTPS id 3kfawrr169-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=OK) for ; Wed, 26 Oct 2022 19:30:06 +0000 Received: from pps.filterd (phxpaimrmta02.imrmtpd1.prodappphxaev1.oraclevcn.com [127.0.0.1]) by phxpaimrmta02.imrmtpd1.prodappphxaev1.oraclevcn.com (8.17.1.5/8.17.1.5) with ESMTP id 29QImd0L017489 for ; Wed, 26 Oct 2022 19:30:05 GMT Received: from nam11-co1-obe.outbound.protection.outlook.com (mail-co1nam11lp2172.outbound.protection.outlook.com [104.47.56.172]) by phxpaimrmta02.imrmtpd1.prodappphxaev1.oraclevcn.com (PPS) with ESMTPS id 3kfagfs29f-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=OK) for ; Wed, 26 Oct 2022 19:30:05 +0000 ARC-Seal: i=1; a=rsa-sha256; s=arcselector9901; d=microsoft.com; cv=none; b=Q/trfD1oJI02LAgvtLJLHYhujATI3dJUEiBvzWAbXM6Y+ZsIHzp8xtoYx+W3/VDxIBt8iGdIG5pKdTXBqj10t7TCWblPZdNnFGpgvC3gbXg7tVkHmniogJeUTJsISt2r10XkOZ4/d5GqyQx9PrU9EdqGKwz2G/QcFH/iQq56HqtImT51MS4wq6kpd+Bu8/K/QpqxrN5UlIue9sO88JiPgWFAKfhfYbR9zsqbhliQTTbLzUtHtDN1BZZhBzzZF1+b9up80yUs+sDnQm0DbNyLNwVruYyYxlWTiXQoXVyo1OJl4ig7ZA8zpdQX6KMzOUcJLwjTvdIXh2pZgF878Jxnug== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=microsoft.com; s=arcselector9901; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-AntiSpam-MessageData-ChunkCount:X-MS-Exchange-AntiSpam-MessageData-0:X-MS-Exchange-AntiSpam-MessageData-1; bh=CU8yw8K1V2cC/nETi8bGsgKS+EHrntL+7PZaRkQmFD8=; b=WWcWPT/ACg9jZCrE1pdjdpON2oM2QfE8fZE5K3/yChGG71w2aEwhoP8aj9cFaFm+ur3SQVcofG0gHPNvahO3hDvQGB6tR+28TS7b93cyCZsrQPHY/sCLzY6uNhEHFF02wytbF8kfc4oe1gFPiaZ7Vlsq7U93prjOly8pBrVzlSrUFqKpFmAzDw9o4NO0P6eKLAl610QpUsGV4bI+6ArMJfrafcVHviU4Elc0I3x9S+vhD1j/4YD0iXklCRDgvyV5qiTc+56qI7H18pIF+O9RQghcOTx7xOpVckxftVrJRPwc8KaNg/dYt77QCG/rCEPq2Lw/yGN/geT8lc7uYiaDBw== ARC-Authentication-Results: i=1; mx.microsoft.com 1; spf=pass smtp.mailfrom=oracle.com; dmarc=pass action=none header.from=oracle.com; dkim=pass header.d=oracle.com; arc=none DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=oracle.onmicrosoft.com; s=selector2-oracle-onmicrosoft-com; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-SenderADCheck; bh=CU8yw8K1V2cC/nETi8bGsgKS+EHrntL+7PZaRkQmFD8=; b=H4rN8l90QrnN9gJWU2gIuMVfrE2meSV7FMFpTf72+S1vc6X3M968La7zM58BCGZUM+87HhOKg8Acnaoj7MI7w0af6Bz2l18cCLfOr3h6X4yFjEX8hv42fh8ACQ+bNuwugOxQsvOqUUF+zxW+eS4tgGqgjSQgMhO/gPQbpwb3dw8= Received: from BYAPR10MB2888.namprd10.prod.outlook.com (2603:10b6:a03:88::32) by SN7PR10MB6286.namprd10.prod.outlook.com (2603:10b6:806:26e::19) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.5746.28; Wed, 26 Oct 2022 19:30:02 +0000 Received: from BYAPR10MB2888.namprd10.prod.outlook.com ([fe80::5095:b148:8def:1049]) by BYAPR10MB2888.namprd10.prod.outlook.com ([fe80::5095:b148:8def:1049%5]) with mapi id 15.20.5723.034; Wed, 26 Oct 2022 19:30:02 +0000 From: "Jose E. Marchesi" To: David Faust Cc: gcc-patches@gcc.gnu.org Subject: Re: [PATCH v3] bpf: add preserve_field_info builtin References: <87o7tzyazk.fsf@oracle.com> <20221026192311.12260-1-david.faust@oracle.com> Date: Wed, 26 Oct 2022 21:33:59 +0200 In-Reply-To: <20221026192311.12260-1-david.faust@oracle.com> (David Faust's message of "Wed, 26 Oct 2022 12:23:11 -0700") Message-ID: <87ilk6v0pk.fsf@oracle.com> User-Agent: Gnus/5.13 (Gnus v5.13) Emacs/28.0.50 (gnu/linux) Content-Type: text/plain X-ClientProxiedBy: SI2PR04CA0008.apcprd04.prod.outlook.com (2603:1096:4:197::20) To BYAPR10MB2888.namprd10.prod.outlook.com (2603:10b6:a03:88::32) MIME-Version: 1.0 X-MS-PublicTrafficType: Email X-MS-TrafficTypeDiagnostic: BYAPR10MB2888:EE_|SN7PR10MB6286:EE_ X-MS-Office365-Filtering-Correlation-Id: f1d22393-252d-44a1-4dad-08dab788799b X-MS-Exchange-SenderADCheck: 1 X-MS-Exchange-AntiSpam-Relay: 0 X-Microsoft-Antispam: BCL:0; X-Microsoft-Antispam-Message-Info: z3y+T7AQ56Ywj7RHGgQkoGUDklqTzsuVTk3YqvqsZG0wT0R4m/dz7c6N40cYg8uc0QxSzsXdxbFsGdp3s/OBupgkG1EYCbMNiOL26v7GpqNBUlG9SUFcVjrRbYT1M6rvWSM8oCWIt/yhYnNWh4YY3ZtI93tX/rzLxyNjAPCHmu8LMFPDYbtsuv2WtaEJ1DGdMgVeTXVpRskU3shZwBTTWCRr/yqeHm62LZ2ImbGwmdC2X4+ijyHF1TykG3BU959lIx91o3Uv+D6JiO1SIPCuJqwE0SzicVNjuE4dY0Z84L2YfpRvAuiFOtCHwtxD4+ry/SFKMno+JlI9EQsFtN6fXdoEuJ7YJOlG6XKT7Pq9B90i8GjuN8IwpX0SlKg6SvQgd+uy6piJzzu2txJmx3NGsKuHSqdw2X7DcwAX46RD0BCSmTPxiLB/oDBtv1Ud2LkoNDQIUhW7hXrNel4hYNJc0dERtT59CsvbQg7rPzdUw+wPl74xT/tdtCIwj31E3+/kdxmc/aucN7X2UYkdSUgHq9IOMiqUzvfA/Ie58GfOvQ/ePQkGybplxmjkeKTfCtr/qLccsocN1ewNw5r7pMgjMdBxlGHxtqYuEz4wvxhPzu6xVluSlZisHkk7VvxI29pWjV07We+k+8wVrmNPX8WZSo3k0CLVr9znjl1znAyfdEVWV0feoz9cQZVbTwdBLCoyGOLLCOzZ4geZFTvH88kSIoj1ylmSxC/r8H/DGf5qIqw= X-Forefront-Antispam-Report: CIP:255.255.255.255;CTRY:;LANG:en;SCL:1;SRV:;IPV:NLI;SFV:NSPM;H:BYAPR10MB2888.namprd10.prod.outlook.com;PTR:;CAT:NONE;SFS:(13230022)(346002)(396003)(136003)(376002)(366004)(39860400002)(451199015)(6486002)(6506007)(4326008)(316002)(66556008)(86362001)(66946007)(66476007)(8676002)(84970400001)(478600001)(6636002)(37006003)(6666004)(6512007)(36756003)(83380400001)(38100700002)(6862004)(8936002)(5660300002)(26005)(41300700001)(2906002)(2616005)(186003)(30864003)(579004)(559001);DIR:OUT;SFP:1101; X-MS-Exchange-AntiSpam-MessageData-ChunkCount: 1 X-MS-Exchange-AntiSpam-MessageData-0: =?us-ascii?Q?wmO5zwiE90dSvgc/L/LVQK0wOFDsBPCwXQHlEdUGr9reQIWRHUS/TYZ72/5S?= =?us-ascii?Q?z3lOz5sBiLw28yr5j+1Y0B3mB4NZXkbVCnSwIylHhz3b8loLuRQodqZTa01x?= =?us-ascii?Q?JjcZMwNbfCey7oU2Xy+Ij5AXxb/yvvBY1n++HxzJ0klNhSNEHBfpFEBsNwYH?= =?us-ascii?Q?uj9jXtxsDz1jwohkzri6Sq7Zgif+bPB77qHb/3W0ZjeGUIG1ISINNkFvnjoJ?= =?us-ascii?Q?oxvGTfjSK8Wqdrlhjd9mEUauuhj7tFAMa839KM+OxpDPiQZTDtRgwb8aWgPv?= =?us-ascii?Q?UVek/qraCKwEsNP1givd6pR3PxcaBjPCdzfvkmgXUurmmjPiprY7stEP/oEm?= =?us-ascii?Q?WTvQBaigRFkxAWwX94m/0CPtITs0Q3UR+qNxQ81BmkyVk4tCm7hlqSNWuUny?= =?us-ascii?Q?DZvE1IKuzwmNBFdUVfqZqaua2uMegd3ieqXYWYbXotIrqSX6U7jX4JHI//4U?= =?us-ascii?Q?eSBcKwVh0NiOn3CjncsXTX1axxkOB0TNmaTM8vBCL4Omv3xKdeX7ALxilwSV?= =?us-ascii?Q?ZYv9k6+WBXk/zD3RyX9aqtAqO7ANyL20FKqEVSJaLYGZnDRIfvIDiWGMzRdI?= =?us-ascii?Q?R++j0k04b/fQ1w43Eongt4xTJrW6O/XSeWL3X4vjeTrFnC9vAzuvvtfdOBSq?= =?us-ascii?Q?89Du4lhT8xAtNPtloskyp/PA7trsbXGBcpUf79z+diEFBSZW+PpSGApEEdrM?= =?us-ascii?Q?jwmv3/rDnJJlZ0h/1AzPxcC2EvXC2e4qMlRUJL1UFsQnclP5o6IH+939QRuk?= =?us-ascii?Q?TQvoQRUH6YaNZ00JO+76wKsYq0bep2L4NjrrkzaTIT7MQfjs5dnWIIGzuqGd?= =?us-ascii?Q?KKbqfGzAvpfedwYorSOiDptzgUoxVwJpHitUakpB/4qE1WyoSFIKDu9PjewH?= =?us-ascii?Q?SSKD0rY1PT25u7Ckv7y8IIRDfvmGC18Z+zyES/q6kEjFlGXGaMpUgdWcdZXK?= =?us-ascii?Q?n9rTDrei+NIKXvtzVsDxEdE+03/BKkrvf2fk/lYpcxKnBwbHgS8YQmCibH2u?= =?us-ascii?Q?80i+c9B34VyNR7oRXJ+D68tTPQt4ORCKXS59oLXs4TlzNdcYvXg6bYsUgdMn?= =?us-ascii?Q?p5yESYSUd7A0lyKIIf/ftriRDjlonjF/dsa13A6O2knQUZZzBrvdQhVxRyvj?= =?us-ascii?Q?vHsEsLTfxucfcYZJKy1Bz+GHbk+yK/RXavvU4bRc4QzT4Ghaxkk4BkWfRLBE?= =?us-ascii?Q?JYeoGWfzYwR0yPPbYQF13SxC8OsfJzBa09WuYKL6XHItRB9/08m3PzJHRn0r?= =?us-ascii?Q?lzy9s6QBHAO9bjVfp/s/xhy3lBRA9t068bS3/a5MQ+HO/1Wddi3imv2mgu0p?= =?us-ascii?Q?bVc5odnuaO+hpO+okfgY74juPrPYhPFgdE2ImHl/qMf+uWlSw/4m9A8DT+LE?= =?us-ascii?Q?OHLJuZwYD9Zjm+doPJejVbbaMD+PZC5y8THKiQJGZs9KUXfSRjpeBc+nBXrx?= =?us-ascii?Q?Dj1uwZlclhAZa1s5ElcwfmpKNpUSA5smv3O/7ERNdtewiFeB+kYVLhujx+AU?= =?us-ascii?Q?HPoG+NCzcPMyaTy1eqZBYSlYUE4oNof9Jn3lYd+Q9JfQF1EwQSn5C2eFEQZx?= =?us-ascii?Q?b436RTPH/0t/5puZ+AGTUJ60oCi0nBD3H6U9hvr8joBSWlPkTsUscgA+fUb4?= =?us-ascii?Q?qg=3D=3D?= X-OriginatorOrg: oracle.com X-MS-Exchange-CrossTenant-Network-Message-Id: f1d22393-252d-44a1-4dad-08dab788799b X-MS-Exchange-CrossTenant-AuthSource: BYAPR10MB2888.namprd10.prod.outlook.com X-MS-Exchange-CrossTenant-AuthAs: Internal X-MS-Exchange-CrossTenant-OriginalArrivalTime: 26 Oct 2022 19:30:02.3595 (UTC) X-MS-Exchange-CrossTenant-FromEntityHeader: Hosted X-MS-Exchange-CrossTenant-Id: 4e2c6054-71cb-48f1-bd6c-3a9705aca71b X-MS-Exchange-CrossTenant-MailboxType: HOSTED X-MS-Exchange-CrossTenant-UserPrincipalName: /KBXj0Cc065iasKJly23D5ecUv6YkO8l1N70wG3GFp4whw2Pxs2CfmrBY6u8OaM99vMWnmHFUakNL1LtQQXS2HKm7O8r5yVrNBzenhxOtOQ= X-MS-Exchange-Transport-CrossTenantHeadersStamped: SN7PR10MB6286 X-Proofpoint-Virus-Version: vendor=baseguard engine=ICAP:2.0.205,Aquarius:18.0.895,Hydra:6.0.545,FMLib:17.11.122.1 definitions=2022-10-26_08,2022-10-26_01,2022-06-22_01 X-Proofpoint-Spam-Details: rule=notspam policy=default score=0 adultscore=0 bulkscore=0 malwarescore=0 phishscore=0 mlxlogscore=999 mlxscore=0 spamscore=0 suspectscore=0 classifier=spam adjust=0 reason=mlx scancount=1 engine=8.12.0-2210170000 definitions=main-2210260109 X-Proofpoint-ORIG-GUID: cUu-4hrJ5v00rqdFUU8jZzrM2xY5Az2d X-Proofpoint-GUID: cUu-4hrJ5v00rqdFUU8jZzrM2xY5Az2d X-Spam-Status: No, score=-12.1 required=5.0 tests=BAYES_00,DKIM_SIGNED,DKIM_VALID,DKIM_VALID_AU,DKIM_VALID_EF,GIT_PATCH_0,KAM_SHORT,RCVD_IN_DNSWL_LOW,RCVD_IN_MSPIKE_H2,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 List-Id: Hi David. Thanks for the updates. OK for master. >>> I'm not sure whether this behavior is a known limitation or an >>> oversight. In my opinion it makes more sense to error at compile time, >>> becuase even after the loader patches the return value it still will >>> not be correct for these cases. >>> >>> So for now I've set these cases to error out, but it would be just as >>> simple to mimic the LLVM behavior. WDYT? >> >> I would say it makes more sense to error out than to return invalid >> data. >> >> However, the divergence wrt LLVM is a concern. What about keeping this >> behavior in the GCC backend and simultaneously raise the issue in >> bpf@vger? If it was a design oversight and the change doesn't impact >> kernel sources, they may be willing to change it. >> > > OK, I will raise the question there. > >>> [...] >>> +@deftypefn {Built-in Function} unsigned int >>> __builtin_preserve_field_info (@var{expr}, unsigned int @var{kind}) >>> +BPF Compile Once-Run Everywhere (CO-RE) support. This builtin is used to >>> +extract information to aid in struct/union relocations. @var{expr} is >>> +an access to a field of a struct or union. Depending on @var{kind}, different >>> +information is returned to the program. A CO-RE relocation for the access in >>> +@var{expr} with kind @var{kind} is recorded if @code{-mco-re} is in effect. >>> + >>> +The following values are supported for @var{kind}: >>> +@table @var >>> +@item FIELD_BYTE_OFFSET = 0 >>> +The returned value is the offset, in bytes, of the field from the >>> +beginning of the containing structure. >> >> What about bit fields? Is this the byte offset of the containing word? > > Yes. > >> >>> +@item FIELD_BYTE_SIZE = 1 >>> +The returned value is the size, in bytes, of the field. >> >> For bit fields, is this the size of the containing word? > > Right again. I have updated the docs for these two in v3. > >> >>> +@item FIELD_EXISTENCE = 2 >>> +The returned value is 1 if the field exists, 0 otherwise. Always 1 at >>> +compile time. >>> + >>> +@item FIELD_SIGNEDNESS = 3 >>> +The returned value is 1 if the field is signed, 0 otherwise. >>> + >>> +@item FIELD_LSHIFT_U64 = 4 >>> +@itemx FIELD_RSHIFT_U64 = 5 >>> +Suppose the field were loaded into a value of FIELD_BYTE_SIZE bytes >>> +and then zero or sign-extended to a 64-bit value. The returned value >>> +is the number of bits of left or right shifting respectively that >>> +would be needed to recover the original value of the field. >> >> What are the semantics for bit fields? > > The semantics for bit fields are the same. These two are primarily > useful for bit fields - a common case in eBPF programs is to read > some field of a struct through a pointer. If it's a kernel struct > that may change between versions and you are reading a bit field, > you would use this builtin to get the eBPF loader to patch the > appropriate steps to extract the field. > > So the process to read a bit field is the following: > > 1. read FIELD_BYTE_SIZE bytes and zero-extend the value of the > read into a u64 > 2. left shift the result FIELD_LSHIFT_U64 bits > 3. if FIELD_SIGNEDNESS > then arithmetic right-shift by FIELD_RSHIFT_U64 bits > otherwise > logical right-shift by FIELD_RSHIFT_U64 bits > > Where all these FIELD_* values might change between kernels and > need patching by the eBPF loader. > > I struggled a bit trying to find the best wording to describe this > in the docs, and settled on adding some example code since I think > that is the most clear. > > Please take a look at the updated version and let me know if you > have any suggestions, I'm happy to hear them. > > Thanks > > --- > > [Changes from v2: update documentation in extend.texi] > > Add BPF __builtin_preserve_field_info. This builtin is used to extract > information to facilitate struct and union relocations performed by the > BPF loader, especially for bitfields. > > The builtin has the following signature: > > unsigned int __builtin_preserve_field_info (EXPR, unsigned int KIND); > > Where EXPR is an expression accessing a field of a struct or union. > Depending on KIND, different information is returned to the program. The > supported values for KIND are as follows: > > enum { > FIELD_BYTE_OFFSET = 0, > FIELD_BYTE_SIZE, > FIELD_EXISTENCE, > FIELD_SIGNEDNESS, > FIELD_LSHIFT_U64, > FIELD_RSHIFT_U64 > }; > > If -mco-re is in effect (explicitly or implicitly specified), a CO-RE > relocation is added for the access in EXPR recording the relevant > information according to KIND. > > gcc/ > > * config/bpf/bpf.cc: Support __builtin_preserve_field_info. > (enum bpf_builtins): Add new builtin. > (bpf_init_builtins): Likewise. > (bpf_core_field_info): New function. > (bpf_expand_builtin): Accomodate new builtin. Refactor adding new > relocation to... > (maybe_make_core_relo): ... here. New function. > (bpf_resolve_overloaded_builtin): Accomodate new builtin. > (bpf_core_newdecl): Likewise. > (bpf_core_walk): Likewise. > (bpf_core_is_maybe_aggregate_access): Improve logic. > (struct core_walk_data): New. > * config/bpf/coreout.cc (bpf_core_reloc_add): Allow adding different > relocation kinds. > * config/bpf/coreout.h: Analogous change. > * doc/extend.texi: Document BPF __builtin_preserve_field_info. > > gcc/testsuite/ > > * gcc.target/bpf/core-builtin-fieldinfo-errors-1.c: New test. > * gcc.target/bpf/core-builtin-fieldinfo-errors-2.c: New test. > * gcc.target/bpf/core-builtin-fieldinfo-existence-1.c: New test. > * gcc.target/bpf/core-builtin-fieldinfo-lshift-1-be.c: New test. > * gcc.target/bpf/core-builtin-fieldinfo-lshift-1-le.c: New test. > * gcc.target/bpf/core-builtin-fieldinfo-lshift-2.c: New test. > * gcc.target/bpf/core-builtin-fieldinfo-offset-1.c: New test. > * gcc.target/bpf/core-builtin-fieldinfo-rshift-1.c: New test. > * gcc.target/bpf/core-builtin-fieldinfo-rshift-2.c: New test. > * gcc.target/bpf/core-builtin-fieldinfo-sign-1.c: New test. > * gcc.target/bpf/core-builtin-fieldinfo-sign-2.c: New test. > * gcc.target/bpf/core-builtin-fieldinfo-size-1.c: New test. > --- > gcc/config/bpf/bpf.cc | 402 ++++++++++++++---- > gcc/config/bpf/coreout.cc | 5 +- > gcc/config/bpf/coreout.h | 2 +- > gcc/doc/extend.texi | 77 ++++ > .../bpf/core-builtin-fieldinfo-errors-1.c | 23 + > .../bpf/core-builtin-fieldinfo-errors-2.c | 23 + > .../bpf/core-builtin-fieldinfo-existence-1.c | 34 ++ > .../bpf/core-builtin-fieldinfo-lshift-1-be.c | 37 ++ > .../bpf/core-builtin-fieldinfo-lshift-1-le.c | 37 ++ > .../bpf/core-builtin-fieldinfo-lshift-2.c | 37 ++ > .../bpf/core-builtin-fieldinfo-offset-1.c | 56 +++ > .../bpf/core-builtin-fieldinfo-rshift-1.c | 36 ++ > .../bpf/core-builtin-fieldinfo-rshift-2.c | 35 ++ > .../bpf/core-builtin-fieldinfo-sign-1.c | 33 ++ > .../bpf/core-builtin-fieldinfo-sign-2.c | 45 ++ > .../bpf/core-builtin-fieldinfo-size-1.c | 43 ++ > 16 files changed, 850 insertions(+), 75 deletions(-) > create mode 100644 gcc/testsuite/gcc.target/bpf/core-builtin-fieldinfo-errors-1.c > create mode 100644 gcc/testsuite/gcc.target/bpf/core-builtin-fieldinfo-errors-2.c > create mode 100644 gcc/testsuite/gcc.target/bpf/core-builtin-fieldinfo-existence-1.c > create mode 100644 gcc/testsuite/gcc.target/bpf/core-builtin-fieldinfo-lshift-1-be.c > create mode 100644 gcc/testsuite/gcc.target/bpf/core-builtin-fieldinfo-lshift-1-le.c > create mode 100644 gcc/testsuite/gcc.target/bpf/core-builtin-fieldinfo-lshift-2.c > create mode 100644 gcc/testsuite/gcc.target/bpf/core-builtin-fieldinfo-offset-1.c > create mode 100644 gcc/testsuite/gcc.target/bpf/core-builtin-fieldinfo-rshift-1.c > create mode 100644 gcc/testsuite/gcc.target/bpf/core-builtin-fieldinfo-rshift-2.c > create mode 100644 gcc/testsuite/gcc.target/bpf/core-builtin-fieldinfo-sign-1.c > create mode 100644 gcc/testsuite/gcc.target/bpf/core-builtin-fieldinfo-sign-2.c > create mode 100644 gcc/testsuite/gcc.target/bpf/core-builtin-fieldinfo-size-1.c > > diff --git a/gcc/config/bpf/bpf.cc b/gcc/config/bpf/bpf.cc > index 51055651707..ea8ca64d1d6 100644 > --- a/gcc/config/bpf/bpf.cc > +++ b/gcc/config/bpf/bpf.cc > @@ -184,13 +184,13 @@ enum bpf_builtins > > /* Compile Once - Run Everywhere (CO-RE) support. */ > BPF_BUILTIN_PRESERVE_ACCESS_INDEX, > + BPF_BUILTIN_PRESERVE_FIELD_INFO, > > BPF_BUILTIN_MAX, > }; > > static GTY (()) tree bpf_builtins[(int) BPF_BUILTIN_MAX]; > > - > void bpf_register_coreattr_pass (void); > > /* Initialize the per-function machine status. */ > @@ -966,6 +966,9 @@ bpf_init_builtins (void) > def_builtin ("__builtin_preserve_access_index", > BPF_BUILTIN_PRESERVE_ACCESS_INDEX, > build_function_type_list (ptr_type_node, ptr_type_node, 0)); > + def_builtin ("__builtin_preserve_field_info", > + BPF_BUILTIN_PRESERVE_FIELD_INFO, > + build_function_type_list (unsigned_type_node, ptr_type_node, unsigned_type_node, 0)); > } > > #undef TARGET_INIT_BUILTINS > @@ -975,6 +978,199 @@ static tree bpf_core_compute (tree, vec *); > static int bpf_core_get_index (const tree); > static bool is_attr_preserve_access (tree); > > +/* BPF Compile Once - Run Everywhere (CO-RE) support. Construct a CO-RE > + relocation record for EXPR of kind KIND to be emitted in the .BTF.ext > + section. Does nothing if we are not targetting BPF CO-RE, or if the > + constructed relocation would be a no-op. */ > + > +static void > +maybe_make_core_relo (tree expr, enum btf_core_reloc_kind kind) > +{ > + /* If we are not targetting BPF CO-RE, do not make a relocation. We > + might not be generating any debug info at all. */ > + if (!TARGET_BPF_CORE) > + return; > + > + auto_vec accessors; > + tree container = bpf_core_compute (expr, &accessors); > + > + /* Any valid use of the builtin must have at least one access. Otherwise, > + there is nothing to record and nothing to do. This is primarily a > + guard against optimizations leading to unexpected expressions in the > + argument of the builtin. For example, if the builtin is used to read > + a field of a structure which can be statically determined to hold a > + constant value, the argument to the builtin will be optimized to that > + constant. This is OK, and means the builtin call is superfluous. > + e.g. > + struct S foo; > + foo.a = 5; > + int x = __preserve_access_index (foo.a); > + ... do stuff with x > + 'foo.a' in the builtin argument will be optimized to '5' with -01+. > + This sequence does not warrant recording a CO-RE relocation. */ > + > + if (accessors.length () < 1) > + return; > + accessors.reverse (); > + > + rtx_code_label *label = gen_label_rtx (); > + LABEL_PRESERVE_P (label) = 1; > + emit_label (label); > + > + /* Determine what output section this relocation will apply to. > + If this function is associated with a section, use that. Otherwise, > + fall back on '.text'. */ > + const char * section_name; > + if (current_function_decl && DECL_SECTION_NAME (current_function_decl)) > + section_name = DECL_SECTION_NAME (current_function_decl); > + else > + section_name = ".text"; > + > + /* Add the CO-RE relocation information to the BTF container. */ > + bpf_core_reloc_add (TREE_TYPE (container), section_name, &accessors, label, > + kind); > +} > + > +/* Expand a call to __builtin_preserve_field_info by evaluating the requested > + information about SRC according to KIND, and return a tree holding > + the result. */ > + > +static tree > +bpf_core_field_info (tree src, enum btf_core_reloc_kind kind) > +{ > + unsigned int result; > + poly_int64 bitsize, bitpos; > + tree var_off = NULL_TREE; > + machine_mode mode; > + int unsignedp, reversep, volatilep; > + location_t loc = EXPR_LOCATION (src); > + > + get_inner_reference (src, &bitsize, &bitpos, &var_off, &mode, &unsignedp, > + &reversep, &volatilep); > + > + /* Note: Use DECL_BIT_FIELD_TYPE rather than DECL_BIT_FIELD here, because it > + remembers whether the field in question was originally declared as a > + bitfield, regardless of how it has been optimized. */ > + bool bitfieldp = (TREE_CODE (src) == COMPONENT_REF > + && DECL_BIT_FIELD_TYPE (TREE_OPERAND (src, 1))); > + > + unsigned int align = TYPE_ALIGN (TREE_TYPE (src)); > + if (TREE_CODE (src) == COMPONENT_REF) > + { > + tree field = TREE_OPERAND (src, 1); > + if (DECL_BIT_FIELD_TYPE (field)) > + align = TYPE_ALIGN (DECL_BIT_FIELD_TYPE (field)); > + else > + align = TYPE_ALIGN (TREE_TYPE (field)); > + } > + > + unsigned int start_bitpos = bitpos & ~(align - 1); > + unsigned int end_bitpos = start_bitpos + align; > + > + switch (kind) > + { > + case BPF_RELO_FIELD_BYTE_OFFSET: > + { > + if (var_off != NULL_TREE) > + { > + error_at (loc, "unsupported variable field offset"); > + return error_mark_node; > + } > + > + if (bitfieldp) > + result = start_bitpos / 8; > + else > + result = bitpos / 8; > + } > + break; > + > + case BPF_RELO_FIELD_BYTE_SIZE: > + { > + if (mode == BLKmode && bitsize == -1) > + { > + error_at (loc, "unsupported variable size field access"); > + return error_mark_node; > + } > + > + if (bitfieldp) > + { > + /* To match LLVM behavior, byte size of bitfields is recorded as > + the full size of the base type. A 3-bit bitfield of type int is > + therefore recorded as having a byte size of 4 bytes. */ > + result = end_bitpos - start_bitpos; > + if (result & (result - 1)) > + { > + error_at (loc, "unsupported field expression"); > + return error_mark_node; > + } > + result = result / 8; > + } > + else > + result = bitsize / 8; > + } > + break; > + > + case BPF_RELO_FIELD_EXISTS: > + /* The field always exists at compile time. */ > + result = 1; > + break; > + > + case BPF_RELO_FIELD_SIGNED: > + result = !unsignedp; > + break; > + > + case BPF_RELO_FIELD_LSHIFT_U64: > + case BPF_RELO_FIELD_RSHIFT_U64: > + { > + if (mode == BLKmode && bitsize == -1) > + { > + error_at (loc, "unsupported variable size field access"); > + return error_mark_node; > + } > + if (var_off != NULL_TREE) > + { > + error_at (loc, "unsupported variable field offset"); > + return error_mark_node; > + } > + > + if (!bitfieldp) > + { > + if (bitsize > 64) > + { > + error_at (loc, "field size too large"); > + return error_mark_node; > + } > + result = 64 - bitsize; > + break; > + } > + > + if (end_bitpos - start_bitpos > 64) > + { > + error_at (loc, "field size too large"); > + return error_mark_node; > + } > + > + if (kind == BPF_RELO_FIELD_LSHIFT_U64) > + { > + if (TARGET_BIG_ENDIAN) > + result = bitpos + 64 - start_bitpos - align; > + else > + result = start_bitpos + 64 - bitpos - bitsize; > + } > + else /* RSHIFT_U64 */ > + result = 64 - bitsize; > + } > + break; > + > + default: > + error ("invalid second argument to built-in function"); > + return error_mark_node; > + break; > + } > + > + return build_int_cst (unsigned_type_node, result); > +} > + > /* Expand a call to a BPF-specific built-in function that was set up > with bpf_init_builtins. */ > > @@ -1025,17 +1221,15 @@ bpf_expand_builtin (tree exp, rtx target ATTRIBUTE_UNUSED, > /* The result of the load is in R0. */ > return gen_rtx_REG (ops[0].mode, BPF_R0); > } > + > else if (code == -1) > { > - /* A resolved overloaded builtin, e.g. __bpf_preserve_access_index_si */ > + /* A resolved overloaded __builtin_preserve_access_index. */ > tree arg = CALL_EXPR_ARG (exp, 0); > > if (arg == NULL_TREE) > return NULL_RTX; > > - auto_vec accessors; > - tree container; > - > if (TREE_CODE (arg) == SSA_NAME) > { > gimple *def_stmt = SSA_NAME_DEF_STMT (arg); > @@ -1049,51 +1243,42 @@ bpf_expand_builtin (tree exp, rtx target ATTRIBUTE_UNUSED, > /* Avoid double-recording information if the argument is an access to > a struct/union marked __attribute__((preserve_access_index)). This > Will be handled by the attribute handling pass. */ > - if (is_attr_preserve_access (arg)) > - return expand_normal (arg); > - > - container = bpf_core_compute (arg, &accessors); > - > - /* Any valid use of the builtin must have at least one access. Otherwise, > - there is nothing to record and nothing to do. This is primarily a > - guard against optimizations leading to unexpected expressions in the > - argument of the builtin. For example, if the builtin is used to read > - a field of a structure which can be statically determined to hold a > - constant value, the argument to the builtin will be optimized to that > - constant. This is OK, and means the builtin call is superfluous. > - e.g. > - struct S foo; > - foo.a = 5; > - int x = __preserve_access_index (foo.a); > - ... do stuff with x > - 'foo.a' in the builtin argument will be optimized to '5' with -01+. > - This sequence does not warrant recording a CO-RE relocation. */ > - > - if (accessors.length () < 1) > - return expand_normal (arg); > - > - accessors.reverse (); > - > - container = TREE_TYPE (container); > - > - rtx_code_label *label = gen_label_rtx (); > - LABEL_PRESERVE_P (label) = 1; > - emit_label (label); > - > - /* Determine what output section this relocation will apply to. > - If this function is associated with a section, use that. Otherwise, > - fall back on '.text'. */ > - const char * section_name; > - if (current_function_decl && DECL_SECTION_NAME (current_function_decl)) > - section_name = DECL_SECTION_NAME (current_function_decl); > + if (!is_attr_preserve_access (arg)) > + maybe_make_core_relo (arg, BPF_RELO_FIELD_BYTE_OFFSET); > + > + return expand_normal (arg); > + } > + > + else if (code == -2) > + { > + /* A resolved overloaded __builtin_preserve_field_info. */ > + tree src = CALL_EXPR_ARG (exp, 0); > + tree kind_tree = CALL_EXPR_ARG (exp, 1); > + unsigned HOST_WIDE_INT kind_val; > + if (tree_fits_uhwi_p (kind_tree)) > + kind_val = tree_to_uhwi (kind_tree); > else > - section_name = ".text"; > + error ("invalid argument to built-in function"); > > - /* Add the CO-RE relocation information to the BTF container. */ > - bpf_core_reloc_add (container, section_name, &accessors, label); > + enum btf_core_reloc_kind kind = (enum btf_core_reloc_kind) kind_val; > > - return expand_normal (arg); > + if (TREE_CODE (src) == SSA_NAME) > + { > + gimple *def_stmt = SSA_NAME_DEF_STMT (src); > + if (is_gimple_assign (def_stmt)) > + src = gimple_assign_rhs1 (def_stmt); > + } > + if (TREE_CODE (src) == ADDR_EXPR) > + src = TREE_OPERAND (src, 0); > + > + tree result = bpf_core_field_info (src, kind); > + > + if (result != error_mark_node) > + maybe_make_core_relo (src, kind); > + > + return expand_normal (result); > } > + > gcc_unreachable (); > } > > @@ -1259,41 +1444,64 @@ bpf_core_get_index (const tree node) > __builtin_preserve_access_index. */ > > static tree > -bpf_core_newdecl (tree type) > +bpf_core_newdecl (tree type, bool is_pai) > { > - tree rettype = build_function_type_list (type, type, NULL); > + tree rettype; > char name[80]; > - int len = snprintf (name, sizeof (name), "%s", "__builtin_pai_"); > + static unsigned long pai_count = 0; > + static unsigned long pfi_count = 0; > > - static unsigned long cnt = 0; > - len = snprintf (name + len, sizeof (name) - len, "%lu", cnt++); > + if (is_pai) > + { > + rettype = build_function_type_list (type, type, NULL); > + int len = snprintf (name, sizeof (name), "%s", "__builtin_pai_"); > + len = snprintf (name + len, sizeof (name) - len, "%lu", pai_count++); > + } > + else > + { > + rettype = build_function_type_list (unsigned_type_node, type, > + unsigned_type_node, NULL); > + int len = snprintf (name, sizeof (name), "%s", "__builtin_pfi_"); > + len = snprintf (name + len, sizeof (name) - len, "%lu", pfi_count++); > + } > > - return add_builtin_function_ext_scope (name, rettype, -1, BUILT_IN_MD, NULL, > - NULL_TREE); > + return add_builtin_function_ext_scope (name, rettype, is_pai ? -1 : -2, > + BUILT_IN_MD, NULL, NULL_TREE); > } > > /* Return whether EXPR could access some aggregate data structure that > BPF CO-RE support needs to know about. */ > > -static int > +static bool > bpf_core_is_maybe_aggregate_access (tree expr) > { > - enum tree_code code = TREE_CODE (expr); > - if (code == COMPONENT_REF || code == ARRAY_REF) > - return 1; > - > - if (code == ADDR_EXPR) > + switch (TREE_CODE (expr)) > + { > + case COMPONENT_REF: > + case BIT_FIELD_REF: > + case ARRAY_REF: > + case ARRAY_RANGE_REF: > + return true; > + case ADDR_EXPR: > + case NOP_EXPR: > return bpf_core_is_maybe_aggregate_access (TREE_OPERAND (expr, 0)); > - > - return 0; > + default: > + return false; > + } > } > > +struct core_walk_data { > + location_t loc; > + tree arg; > +}; > + > /* Callback function used with walk_tree from bpf_resolve_overloaded_builtin. */ > > static tree > bpf_core_walk (tree *tp, int *walk_subtrees, void *data) > { > - location_t loc = *((location_t *) data); > + struct core_walk_data *dat = (struct core_walk_data *) data; > + bool is_pai = dat->arg == NULL_TREE; > > /* If this is a type, don't do anything. */ > if (TYPE_P (*tp)) > @@ -1302,10 +1510,18 @@ bpf_core_walk (tree *tp, int *walk_subtrees, void *data) > return NULL_TREE; > } > > + /* Build a new function call to a resolved builtin for the desired operation. > + If this is a preserve_field_info call, pass along the argument to the > + resolved builtin call. */ > if (bpf_core_is_maybe_aggregate_access (*tp)) > { > - tree newdecl = bpf_core_newdecl (TREE_TYPE (*tp)); > - tree newcall = build_call_expr_loc (loc, newdecl, 1, *tp); > + tree newdecl = bpf_core_newdecl (TREE_TYPE (*tp), is_pai); > + tree newcall; > + if (is_pai) > + newcall = build_call_expr_loc (dat->loc, newdecl, 1, *tp); > + else > + newcall = build_call_expr_loc (dat->loc, newdecl, 2, *tp, dat->arg); > + > *tp = newcall; > *walk_subtrees = 0; > } > @@ -1330,6 +1546,30 @@ bpf_small_register_classes_for_mode_p (machine_mode mode) > #define TARGET_SMALL_REGISTER_CLASSES_FOR_MODE_P \ > bpf_small_register_classes_for_mode_p > > +/* Return whether EXPR is a valid first argument for a call to > + __builtin_preserve_field_info. */ > + > +static bool > +bpf_is_valid_preserve_field_info_arg (tree expr) > +{ > + switch (TREE_CODE (expr)) > + { > + case COMPONENT_REF: > + case BIT_FIELD_REF: > + case ARRAY_REF: > + case ARRAY_RANGE_REF: > + return true; > + case NOP_EXPR: > + return bpf_is_valid_preserve_field_info_arg (TREE_OPERAND (expr, 0)); > + case ADDR_EXPR: > + /* Do not accept ADDR_EXPRs like &foo.bar, but do accept accesses like > + foo.baz where baz is an array. */ > + return (TREE_CODE (TREE_TYPE (TREE_OPERAND (expr, 0))) == ARRAY_TYPE); > + default: > + return false; > + } > +} > + > /* Implement TARGET_RESOLVE_OVERLOADED_BUILTIN (see gccint manual section > Target Macros::Misc.). > We use this for the __builtin_preserve_access_index builtin for CO-RE > @@ -1344,7 +1584,12 @@ bpf_small_register_classes_for_mode_p (machine_mode mode) > static tree > bpf_resolve_overloaded_builtin (location_t loc, tree fndecl, void *arglist) > { > - if (DECL_MD_FUNCTION_CODE (fndecl) != BPF_BUILTIN_PRESERVE_ACCESS_INDEX) > + bool is_pai = DECL_MD_FUNCTION_CODE (fndecl) > + == BPF_BUILTIN_PRESERVE_ACCESS_INDEX; > + bool is_pfi = DECL_MD_FUNCTION_CODE (fndecl) > + == BPF_BUILTIN_PRESERVE_FIELD_INFO; > + > + if (!is_pai && !is_pfi) > return NULL_TREE; > > /* We only expect one argument, but it may be an arbitrarily-complicated > @@ -1352,18 +1597,26 @@ bpf_resolve_overloaded_builtin (location_t loc, tree fndecl, void *arglist) > vec *params = static_cast *> (arglist); > unsigned n_params = params ? params->length() : 0; > > - if (n_params != 1) > + if ((is_pai && n_params != 1) || (is_pfi && n_params != 2)) > { > - error_at (loc, "expected exactly 1 argument"); > - return NULL_TREE; > + error_at (loc, "wrong number of arguments"); > + return error_mark_node; > } > > tree param = (*params)[0]; > > - /* If not generating BPF_CORE information, the builtin does nothing. */ > - if (!TARGET_BPF_CORE) > + /* If not generating BPF_CORE information, preserve_access_index does nothing, > + and simply "resolves to" the argument. */ > + if (!TARGET_BPF_CORE && is_pai) > return param; > > + if (is_pfi && !bpf_is_valid_preserve_field_info_arg (param)) > + { > + error_at (EXPR_LOC_OR_LOC (param, loc), > + "argument is not a field access"); > + return error_mark_node; > + } > + > /* Do remove_c_maybe_const_expr for the arg. > TODO: WHY do we have to do this here? Why doesn't c-typeck take care > of it before or after this hook? */ > @@ -1387,7 +1640,11 @@ bpf_resolve_overloaded_builtin (location_t loc, tree fndecl, void *arglist) > This ensures that all the relevant information remains within the > expression trees the builtin finally gets. */ > > - walk_tree (¶m, bpf_core_walk, (void *) &loc, NULL); > + struct core_walk_data data; > + data.loc = loc; > + data.arg = is_pai ? NULL_TREE : (*params)[1]; > + > + walk_tree (¶m, bpf_core_walk, (void *) &data, NULL); > > return param; > } > @@ -1524,7 +1781,8 @@ handle_attr_preserve (function *fn) > emit_label (label); > > /* Add the CO-RE relocation information to the BTF container. */ > - bpf_core_reloc_add (container, section_name, &accessors, label); > + bpf_core_reloc_add (container, section_name, &accessors, label, > + BPF_RELO_FIELD_BYTE_OFFSET); > } > } > } > diff --git a/gcc/config/bpf/coreout.cc b/gcc/config/bpf/coreout.cc > index 8897a045ea1..9f71040846b 100644 > --- a/gcc/config/bpf/coreout.cc > +++ b/gcc/config/bpf/coreout.cc > @@ -152,7 +152,8 @@ static GTY (()) vec *bpf_core_sections; > > void > bpf_core_reloc_add (const tree type, const char * section_name, > - vec *accessors, rtx_code_label *label) > + vec *accessors, rtx_code_label *label, > + enum btf_core_reloc_kind kind) > { > char buf[40]; > unsigned int i, n = 0; > @@ -173,7 +174,7 @@ bpf_core_reloc_add (const tree type, const char * section_name, > > bpfcr->bpfcr_type = get_btf_id (ctf_lookup_tree_type (ctfc, type)); > bpfcr->bpfcr_insn_label = label; > - bpfcr->bpfcr_kind = BPF_RELO_FIELD_BYTE_OFFSET; > + bpfcr->bpfcr_kind = kind; > > /* Add the CO-RE reloc to the appropriate section. */ > bpf_core_section_ref sec; > diff --git a/gcc/config/bpf/coreout.h b/gcc/config/bpf/coreout.h > index 3c7bdfd8c2f..498853f6e00 100644 > --- a/gcc/config/bpf/coreout.h > +++ b/gcc/config/bpf/coreout.h > @@ -103,7 +103,7 @@ extern void btf_ext_init (void); > extern void btf_ext_output (void); > > extern void bpf_core_reloc_add (const tree, const char *, vec *, > - rtx_code_label *); > + rtx_code_label *, enum btf_core_reloc_kind); > extern int bpf_core_get_sou_member_index (ctf_container_ref, const tree); > > #ifdef __cplusplus > diff --git a/gcc/doc/extend.texi b/gcc/doc/extend.texi > index 04af0584d82..d7bc252fb0b 100644 > --- a/gcc/doc/extend.texi > +++ b/gcc/doc/extend.texi > @@ -15745,6 +15745,83 @@ Load 32-bits from the @code{struct sk_buff} packet data pointed by the register > BPF Compile Once-Run Everywhere (CO-RE) support. Instruct GCC to generate CO-RE relocation records for any accesses to aggregate data structures (struct, union, array types) in @var{expr}. This builtin is otherwise transparent, the return value is whatever @var{expr} evaluates to. It is also overloaded: @var{expr} may be of any type (not necessarily a pointer), the return type is the same. Has no effect if @code{-mco-re} is not in effect (either specified or implied). > @end deftypefn > > +@deftypefn {Built-in Function} unsigned int __builtin_preserve_field_info (@var{expr}, unsigned int @var{kind}) > +BPF Compile Once-Run Everywhere (CO-RE) support. This builtin is used to > +extract information to aid in struct/union relocations. @var{expr} is > +an access to a field of a struct or union. Depending on @var{kind}, different > +information is returned to the program. A CO-RE relocation for the access in > +@var{expr} with kind @var{kind} is recorded if @code{-mco-re} is in effect. > + > +The following values are supported for @var{kind}: > +@table @var > +@item FIELD_BYTE_OFFSET = 0 > +The returned value is the offset, in bytes, of the field from the > +beginning of the containing structure. For bitfields, the byte offset > +of the containing word. > + > +@item FIELD_BYTE_SIZE = 1 > +The returned value is the size, in bytes, of the field. For bitfields, > +the size in bytes of the containing word. > + > +@item FIELD_EXISTENCE = 2 > +The returned value is 1 if the field exists, 0 otherwise. Always 1 at > +compile time. > + > +@item FIELD_SIGNEDNESS = 3 > +The returned value is 1 if the field is signed, 0 otherwise. > + > +@item FIELD_LSHIFT_U64 = 4 > +@itemx FIELD_RSHIFT_U64 = 5 > +The returned value is the number of bits of left- or right-shifting > +respectively needed in order to recover the original value of the field, > +after it has been loaded by a read of FIELD_BYTE_SIZE bytes into an > +unsigned 64-bit value. Primarily useful for reading bitfield values > +from structures which may change between kernel versions. > + > +@end table > + > +Note that the return value is a constant which is known at > +compile-time. If the field has a variable offset then > +FIELD_BYTE_OFFSET, FIELD_LSHIFT_U64 and FIELD_RSHIFT_U64 are not > +supported. Similarly, if the field has a variable size then > +FIELD_BYTE_SIZE, FIELD_LSHIFT_U64 and FIELD_RSHIFT_U64 are not > +supported. > + > +For example, __builtin_preserve_field_info can be used to reliably > +extract bitfield values from a structure which may change between > +kernel versions: > + > +@example > +struct S > +@{ > + short a; > + int x:7; > + int y:5; > +@}; > + > +int > +read_y (struct S *arg) > +@{ > + unsigned long long val; > + unsigned int offset = __builtin_preserve_field_info (arg->y, FIELD_BYTE_OFFSET); > + unsigned int size = __builtin_presrve_field_info (arg->y, FIELD_BYTE_SIZE); > + > + /* Read size bytes from arg + offset into val. */ > + bpf_probe_read (&val, size, arg + offset); > + > + val <<= __builtin_preserve_field_info (arg->y, FIELD_LSHIFT_U64); > + > + if (__builtin_preserve_field_info (arg->y, FIELD_SIGNEDNESS)) > + val = ((long long) val >> __builtin_preserve_field_info (arg->y, FIELD_RSHIFT_U64)); > + else > + val >>= __builtin_preserve_field_info (arg->y, FIELD_RSHIFT_U64); > + > + return val; > +@} > + > +@end example > +@end deftypefn > + > @node FR-V Built-in Functions > @subsection FR-V Built-in Functions > > diff --git a/gcc/testsuite/gcc.target/bpf/core-builtin-fieldinfo-errors-1.c b/gcc/testsuite/gcc.target/bpf/core-builtin-fieldinfo-errors-1.c > new file mode 100644 > index 00000000000..2c67c384004 > --- /dev/null > +++ b/gcc/testsuite/gcc.target/bpf/core-builtin-fieldinfo-errors-1.c > @@ -0,0 +1,23 @@ > +/* { dg-do compile } */ > +/* { dg-options "-O0 -dA -gbtf -mco-re" } */ > + > +struct F { > + int bar; > + char c; > + int baz; > + int arr[]; > +}; > + > +enum { > + FIELD_BYTE_OFFSET = 0, > + FIELD_BYTE_SIZE = 1, > +}; > + > +unsigned int test (struct F *f) { > + > + unsigned x = __builtin_preserve_field_info (f->arr, FIELD_BYTE_SIZE); /* { dg-error "unsupported variable size field access" } */ > + > + unsigned y = __builtin_preserve_field_info (f->baz, 99); /* { dg-error "invalid second argument to built-in function" } */ > + > + return x + y; > +} > diff --git a/gcc/testsuite/gcc.target/bpf/core-builtin-fieldinfo-errors-2.c b/gcc/testsuite/gcc.target/bpf/core-builtin-fieldinfo-errors-2.c > new file mode 100644 > index 00000000000..31d7a03b757 > --- /dev/null > +++ b/gcc/testsuite/gcc.target/bpf/core-builtin-fieldinfo-errors-2.c > @@ -0,0 +1,23 @@ > +/* { dg-do compile } */ > +/* { dg-options "-O0 -dA -gbtf -mco-re" } */ > + > +struct F { > + int bar; > + char c; > + int baz; > +}; > + > +enum { > + FIELD_BYTE_OFFSET = 0, > + FIELD_BYTE_SIZE = 1, > +}; > + > +int test (struct F *f) { > + int a; > + unsigned x = __builtin_preserve_field_info (({ a = f->bar + f->baz; }), FIELD_BYTE_OFFSET); /* { dg-error "argument is not a field access" } */ > + > + int b; > + unsigned y = __builtin_preserve_field_info (&(f->c), FIELD_BYTE_SIZE); /* { dg-error "argument is not a field access" } */ > + > + return a + b + x + y; > +} > diff --git a/gcc/testsuite/gcc.target/bpf/core-builtin-fieldinfo-existence-1.c b/gcc/testsuite/gcc.target/bpf/core-builtin-fieldinfo-existence-1.c > new file mode 100644 > index 00000000000..c55f21a9c11 > --- /dev/null > +++ b/gcc/testsuite/gcc.target/bpf/core-builtin-fieldinfo-existence-1.c > @@ -0,0 +1,34 @@ > +/* { dg-do compile } */ > +/* { dg-options "-O0 -dA -gbtf -mco-re" } */ > + > +enum { > + FIELD_EXISTENCE = 2, > +}; > + > +typedef unsigned uint; > + > +struct S { > + unsigned char c; > + int d; > + uint u; > + short ar[3]; > +}; > + > +unsigned int foo (struct S *s) > +{ > + unsigned c = __builtin_preserve_field_info (s->c, FIELD_EXISTENCE); > + unsigned d = __builtin_preserve_field_info (s->d, FIELD_EXISTENCE); > + unsigned u = __builtin_preserve_field_info (s->u, FIELD_EXISTENCE); > + unsigned ar = __builtin_preserve_field_info (s->ar[1], FIELD_EXISTENCE); > + > + return c + d + u + ar; > +} > + > +/* { dg-final { scan-assembler-times "\[\t \]mov\[\t \]%r\[0-9\],1" 4 } } */ > + > +/* { dg-final { scan-assembler-times "ascii \"0:0.0\"\[\t \]+\[^\n\]*btf_aux_string" 1 } } */ > +/* { dg-final { scan-assembler-times "ascii \"0:1.0\"\[\t \]+\[^\n\]*btf_aux_string" 1 } } */ > +/* { dg-final { scan-assembler-times "ascii \"0:2.0\"\[\t \]+\[^\n\]*btf_aux_string" 1 } } */ > +/* { dg-final { scan-assembler-times "ascii \"0:3:1.0\"\[\t \]+\[^\n\]*btf_aux_string" 1 } } */ > + > +/* { dg-final { scan-assembler-times "0x2\[\t \]+\[^\n\]*bpfcr_kind" 4 } } */ > diff --git a/gcc/testsuite/gcc.target/bpf/core-builtin-fieldinfo-lshift-1-be.c b/gcc/testsuite/gcc.target/bpf/core-builtin-fieldinfo-lshift-1-be.c > new file mode 100644 > index 00000000000..dabf73dd259 > --- /dev/null > +++ b/gcc/testsuite/gcc.target/bpf/core-builtin-fieldinfo-lshift-1-be.c > @@ -0,0 +1,37 @@ > +/* { dg-do compile } */ > +/* { dg-options "-O0 -dA -gbtf -mco-re -mbig-endian" } */ > + > +struct S { > + int x1: 6; > + int x2: 3; > + int x3: 7; > + int x4: 16; > +}; > + > +enum { > + FIELD_LSHIFT_U64 = 4, > +}; > + > +unsigned int foo (struct S *s) > +{ > + /* little endian: x1=58, x2=55, x3=48, x4=32 */ > + /* big endian: x1=32, x2=38, x3=41, x4=48 */ > + unsigned x1 = __builtin_preserve_field_info (s->x1, FIELD_LSHIFT_U64); > + unsigned x2 = __builtin_preserve_field_info (s->x2, FIELD_LSHIFT_U64); > + unsigned x3 = __builtin_preserve_field_info (s->x3, FIELD_LSHIFT_U64); > + unsigned x4 = __builtin_preserve_field_info (s->x4, FIELD_LSHIFT_U64); > + > + return x1 + x2 + x3 + x4; > +} > + > +/* { dg-final { scan-assembler-times "\[\t \]mov\[\t \]%r\[0-9\],32" 1 } } */ > +/* { dg-final { scan-assembler-times "\[\t \]mov\[\t \]%r\[0-9\],38" 1 } } */ > +/* { dg-final { scan-assembler-times "\[\t \]mov\[\t \]%r\[0-9\],41" 1 } } */ > +/* { dg-final { scan-assembler-times "\[\t \]mov\[\t \]%r\[0-9\],48" 1 } } */ > + > +/* { dg-final { scan-assembler-times "ascii \"0:0.0\"\[\t \]+\[^\n\]*btf_aux_string" 1 } } */ > +/* { dg-final { scan-assembler-times "ascii \"0:1.0\"\[\t \]+\[^\n\]*btf_aux_string" 1 } } */ > +/* { dg-final { scan-assembler-times "ascii \"0:2.0\"\[\t \]+\[^\n\]*btf_aux_string" 1 } } */ > +/* { dg-final { scan-assembler-times "ascii \"0:3.0\"\[\t \]+\[^\n\]*btf_aux_string" 1 } } */ > + > +/* { dg-final { scan-assembler-times "0x4\[\t \]+\[^\n\]*bpfcr_kind" 4 } } */ > diff --git a/gcc/testsuite/gcc.target/bpf/core-builtin-fieldinfo-lshift-1-le.c b/gcc/testsuite/gcc.target/bpf/core-builtin-fieldinfo-lshift-1-le.c > new file mode 100644 > index 00000000000..99e3982d932 > --- /dev/null > +++ b/gcc/testsuite/gcc.target/bpf/core-builtin-fieldinfo-lshift-1-le.c > @@ -0,0 +1,37 @@ > +/* { dg-do compile } */ > +/* { dg-options "-O0 -dA -gbtf -mco-re -mlittle-endian" } */ > + > +struct S { > + int x1: 6; > + int x2: 3; > + int x3: 7; > + int x4: 16; > +}; > + > +enum { > + FIELD_LSHIFT_U64 = 4, > +}; > + > +unsigned int foo (struct S *s) > +{ > + /* little endian: x1=58, x2=55, x3=48, x4=32 */ > + /* big endian: x1=32, x2=38, x3=41, x4=48 */ > + unsigned x1 = __builtin_preserve_field_info (s->x1, FIELD_LSHIFT_U64); > + unsigned x2 = __builtin_preserve_field_info (s->x2, FIELD_LSHIFT_U64); > + unsigned x3 = __builtin_preserve_field_info (s->x3, FIELD_LSHIFT_U64); > + unsigned x4 = __builtin_preserve_field_info (s->x4, FIELD_LSHIFT_U64); > + > + return x1 + x2 + x3 + x4; > +} > + > +/* { dg-final { scan-assembler-times "\[\t \]mov\[\t \]%r\[0-9\],58" 1 } } */ > +/* { dg-final { scan-assembler-times "\[\t \]mov\[\t \]%r\[0-9\],55" 1 } } */ > +/* { dg-final { scan-assembler-times "\[\t \]mov\[\t \]%r\[0-9\],48" 1 } } */ > +/* { dg-final { scan-assembler-times "\[\t \]mov\[\t \]%r\[0-9\],32" 1 } } */ > + > +/* { dg-final { scan-assembler-times "ascii \"0:0.0\"\[\t \]+\[^\n\]*btf_aux_string" 1 } } */ > +/* { dg-final { scan-assembler-times "ascii \"0:1.0\"\[\t \]+\[^\n\]*btf_aux_string" 1 } } */ > +/* { dg-final { scan-assembler-times "ascii \"0:2.0\"\[\t \]+\[^\n\]*btf_aux_string" 1 } } */ > +/* { dg-final { scan-assembler-times "ascii \"0:3.0\"\[\t \]+\[^\n\]*btf_aux_string" 1 } } */ > + > +/* { dg-final { scan-assembler-times "0x4\[\t \]+\[^\n\]*bpfcr_kind" 4 } } */ > diff --git a/gcc/testsuite/gcc.target/bpf/core-builtin-fieldinfo-lshift-2.c b/gcc/testsuite/gcc.target/bpf/core-builtin-fieldinfo-lshift-2.c > new file mode 100644 > index 00000000000..25be969e22b > --- /dev/null > +++ b/gcc/testsuite/gcc.target/bpf/core-builtin-fieldinfo-lshift-2.c > @@ -0,0 +1,37 @@ > +/* { dg-do compile } */ > +/* { dg-options "-O0 -dA -gbtf -mco-re" } */ > + > +struct S { > + char c; > + short s; > + int x; > +}; > + > +union U { > + struct S s[2]; > + long long ll; > +}; > + > +enum { > + FIELD_LSHIFT_U64 = 4, > +}; > + > +unsigned int foo (union U *u) > +{ > + /* s0s = 48, s1c = 56, ll = 0; endianness independent. */ > + unsigned s0s = __builtin_preserve_field_info (u->s[0].s, FIELD_LSHIFT_U64); > + unsigned s1c = __builtin_preserve_field_info (u->s[1].c, FIELD_LSHIFT_U64); > + unsigned ll = __builtin_preserve_field_info (u->ll, FIELD_LSHIFT_U64); > + > + return s0s + s1c + ll; > +} > + > +/* { dg-final { scan-assembler-times "\[\t \]mov\[\t \]%r\[0-9\],48" 1 } } */ > +/* { dg-final { scan-assembler-times "\[\t \]mov\[\t \]%r\[0-9\],56" 1 } } */ > +/* { dg-final { scan-assembler-times "\[\t \]mov\[\t \]%r\[0-9\],0" 1 } } */ > + > +/* { dg-final { scan-assembler-times "ascii \"0:0:0:1.0\"\[\t \]+\[^\n\]*btf_aux_string" 1 } } */ > +/* { dg-final { scan-assembler-times "ascii \"0:0:1:0.0\"\[\t \]+\[^\n\]*btf_aux_string" 1 } } */ > +/* { dg-final { scan-assembler-times "ascii \"0:1.0\"\[\t \]+\[^\n\]*btf_aux_string" 1 } } */ > + > +/* { dg-final { scan-assembler-times "0x4\[\t \]+\[^\n\]*bpfcr_kind" 3 } } */ > diff --git a/gcc/testsuite/gcc.target/bpf/core-builtin-fieldinfo-offset-1.c b/gcc/testsuite/gcc.target/bpf/core-builtin-fieldinfo-offset-1.c > new file mode 100644 > index 00000000000..590eea007ae > --- /dev/null > +++ b/gcc/testsuite/gcc.target/bpf/core-builtin-fieldinfo-offset-1.c > @@ -0,0 +1,56 @@ > +/* { dg-do compile } */ > +/* { dg-options "-O0 -dA -gbtf -mco-re" } */ > + > +struct S { > + unsigned int a1: 7; > + unsigned int a2: 4; > + unsigned int a3: 13; > + unsigned int a4: 5; > + int x; > +}; > + > +struct T { > + unsigned int y; > + struct S s[2]; > + char c; > + char d; > +}; > + > +enum { > + FIELD_BYTE_OFFSET = 0, > +}; > + > + > +unsigned int foo (struct T *t) > +{ > + unsigned s0a1 = __builtin_preserve_field_info (t->s[0].a1, FIELD_BYTE_OFFSET); > + unsigned s0a4 = __builtin_preserve_field_info (t->s[0].a4, FIELD_BYTE_OFFSET); > + unsigned s0x = __builtin_preserve_field_info (t->s[0].x, FIELD_BYTE_OFFSET); > + > + unsigned s1a1 = __builtin_preserve_field_info (t->s[1].a1, FIELD_BYTE_OFFSET); > + unsigned s1a4 = __builtin_preserve_field_info (t->s[1].a4, FIELD_BYTE_OFFSET); > + unsigned s1x = __builtin_preserve_field_info (t->s[1].x, FIELD_BYTE_OFFSET); > + > + unsigned c = __builtin_preserve_field_info (t->c, FIELD_BYTE_OFFSET); > + unsigned d = __builtin_preserve_field_info (t->d, FIELD_BYTE_OFFSET); > + > + return s0a1 + s0a4 + s0x + s1a1 + s1a4 + s1x + c + d; > +} > + > +/* { dg-final { scan-assembler-times "\[\t \]mov\[\t \]%r\[0-9\],4" 2 } } */ > +/* { dg-final { scan-assembler-times "\[\t \]mov\[\t \]%r\[0-9\],8" 1 } } */ > +/* { dg-final { scan-assembler-times "\[\t \]mov\[\t \]%r\[0-9\],12" 2 } } */ > +/* { dg-final { scan-assembler-times "\[\t \]mov\[\t \]%r\[0-9\],16" 1 } } */ > +/* { dg-final { scan-assembler-times "\[\t \]mov\[\t \]%r\[0-9\],20" 1 } } */ > +/* { dg-final { scan-assembler-times "\[\t \]mov\[\t \]%r\[0-9\],21" 1 } } */ > + > +/* { dg-final { scan-assembler-times "ascii \"0:1:0:0.0\"\[\t \]+\[^\n\]*btf_aux_string" 1 } } */ > +/* { dg-final { scan-assembler-times "ascii \"0:1:0:3.0\"\[\t \]+\[^\n\]*btf_aux_string" 1 } } */ > +/* { dg-final { scan-assembler-times "ascii \"0:1:0:4.0\"\[\t \]+\[^\n\]*btf_aux_string" 1 } } */ > +/* { dg-final { scan-assembler-times "ascii \"0:1:1:0.0\"\[\t \]+\[^\n\]*btf_aux_string" 1 } } */ > +/* { dg-final { scan-assembler-times "ascii \"0:1:1:3.0\"\[\t \]+\[^\n\]*btf_aux_string" 1 } } */ > +/* { dg-final { scan-assembler-times "ascii \"0:1:1:4.0\"\[\t \]+\[^\n\]*btf_aux_string" 1 } } */ > +/* { dg-final { scan-assembler-times "ascii \"0:2.0\"\[\t \]+\[^\n\]*btf_aux_string" 1 } } */ > +/* { dg-final { scan-assembler-times "ascii \"0:3.0\"\[\t \]+\[^\n\]*btf_aux_string" 1 } } */ > + > +/* { dg-final { scan-assembler-times "0\[\t \]+\[^\n\]*bpfcr_kind" 8 } } */ > diff --git a/gcc/testsuite/gcc.target/bpf/core-builtin-fieldinfo-rshift-1.c b/gcc/testsuite/gcc.target/bpf/core-builtin-fieldinfo-rshift-1.c > new file mode 100644 > index 00000000000..d0c75d944cd > --- /dev/null > +++ b/gcc/testsuite/gcc.target/bpf/core-builtin-fieldinfo-rshift-1.c > @@ -0,0 +1,36 @@ > +/* { dg-do compile } */ > +/* { dg-options "-O0 -dA -gbtf -mco-re" } */ > + > +struct S { > + int x1: 6; > + int x2: 3; > + int x3: 7; > + int x4: 16; > +}; > + > +enum { > + FIELD_RSHIFT_U64 = 5, > +}; > + > +unsigned int foo (struct S *s) > +{ > + /* x1=58, x2=61, x3=57, x4=48; endianness independent. */ > + unsigned x1 = __builtin_preserve_field_info (s->x1, FIELD_RSHIFT_U64); > + unsigned x2 = __builtin_preserve_field_info (s->x2, FIELD_RSHIFT_U64); > + unsigned x3 = __builtin_preserve_field_info (s->x3, FIELD_RSHIFT_U64); > + unsigned x4 = __builtin_preserve_field_info (s->x4, FIELD_RSHIFT_U64); > + > + return x1 + x2 + x3 + x4; > +} > + > +/* { dg-final { scan-assembler-times "\[\t \]mov\[\t \]%r\[0-9\],58" 1 } } */ > +/* { dg-final { scan-assembler-times "\[\t \]mov\[\t \]%r\[0-9\],61" 1 } } */ > +/* { dg-final { scan-assembler-times "\[\t \]mov\[\t \]%r\[0-9\],57" 1 } } */ > +/* { dg-final { scan-assembler-times "\[\t \]mov\[\t \]%r\[0-9\],48" 1 } } */ > + > +/* { dg-final { scan-assembler-times "ascii \"0:0.0\"\[\t \]+\[^\n\]*btf_aux_string" 1 } } */ > +/* { dg-final { scan-assembler-times "ascii \"0:1.0\"\[\t \]+\[^\n\]*btf_aux_string" 1 } } */ > +/* { dg-final { scan-assembler-times "ascii \"0:2.0\"\[\t \]+\[^\n\]*btf_aux_string" 1 } } */ > +/* { dg-final { scan-assembler-times "ascii \"0:3.0\"\[\t \]+\[^\n\]*btf_aux_string" 1 } } */ > + > +/* { dg-final { scan-assembler-times "0x5\[\t \]+\[^\n\]*bpfcr_kind" 4 } } */ > diff --git a/gcc/testsuite/gcc.target/bpf/core-builtin-fieldinfo-rshift-2.c b/gcc/testsuite/gcc.target/bpf/core-builtin-fieldinfo-rshift-2.c > new file mode 100644 > index 00000000000..a71ddc17728 > --- /dev/null > +++ b/gcc/testsuite/gcc.target/bpf/core-builtin-fieldinfo-rshift-2.c > @@ -0,0 +1,35 @@ > +/* { dg-do compile } */ > +/* { dg-options "-O0 -dA -gbtf -mco-re" } */ > + > +struct S { > + int x; > + char c; > +}; > + > +union U { > + int i; > + struct S s; > +}; > + > +enum { > + FIELD_RSHIFT_U64 = 5, > +}; > + > +unsigned int foo (union U *u) > +{ > + /* sx = 32, sc = 56, i = 32; endianness independent. */ > + unsigned sx = __builtin_preserve_field_info (u->s.x, FIELD_RSHIFT_U64); > + unsigned sc = __builtin_preserve_field_info (u->s.c, FIELD_RSHIFT_U64); > + unsigned i = __builtin_preserve_field_info (u->i, FIELD_RSHIFT_U64); > + > + return sx + sc + i; > +} > + > +/* { dg-final { scan-assembler-times "\[\t \]mov\[\t \]%r\[0-9\],32" 2 } } */ > +/* { dg-final { scan-assembler-times "\[\t \]mov\[\t \]%r\[0-9\],56" 1 } } */ > + > +/* { dg-final { scan-assembler-times "ascii \"0:1:0.0\"\[\t \]+\[^\n\]*btf_aux_string" 1 } } */ > +/* { dg-final { scan-assembler-times "ascii \"0:1:1.0\"\[\t \]+\[^\n\]*btf_aux_string" 1 } } */ > +/* { dg-final { scan-assembler-times "ascii \"0:0.0\"\[\t \]+\[^\n\]*btf_aux_string" 1 } } */ > + > +/* { dg-final { scan-assembler-times "0x5\[\t \]+\[^\n\]*bpfcr_kind" 3 } } */ > diff --git a/gcc/testsuite/gcc.target/bpf/core-builtin-fieldinfo-sign-1.c b/gcc/testsuite/gcc.target/bpf/core-builtin-fieldinfo-sign-1.c > new file mode 100644 > index 00000000000..3b2081e197c > --- /dev/null > +++ b/gcc/testsuite/gcc.target/bpf/core-builtin-fieldinfo-sign-1.c > @@ -0,0 +1,33 @@ > +/* { dg-do compile } */ > +/* { dg-options "-O0 -dA -gbtf -mco-re" } */ > + > +enum { > + FIELD_SIGNEDNESS = 3, > +}; > + > +typedef unsigned uint; > + > +struct S { > + unsigned char c; > + int d; > + uint u; > + short ar[3]; > +}; > + > +unsigned int foo (struct S *s) > +{ > + unsigned d = __builtin_preserve_field_info (s->d, FIELD_SIGNEDNESS); > + unsigned u = __builtin_preserve_field_info (s->u, FIELD_SIGNEDNESS); > + unsigned ar = __builtin_preserve_field_info (s->ar[1], FIELD_SIGNEDNESS); > + > + return d + u + ar; > +} > + > +/* { dg-final { scan-assembler-times "\[\t \]mov\[\t \]%r\[0-9\],1" 2 } } */ > +/* { dg-final { scan-assembler-times "\[\t \]mov\[\t \]%r\[0-9\],0" 1 } } */ > + > +/* { dg-final { scan-assembler-times "ascii \"0:1.0\"\[\t \]+\[^\n\]*btf_aux_string" 1 } } */ > +/* { dg-final { scan-assembler-times "ascii \"0:2.0\"\[\t \]+\[^\n\]*btf_aux_string" 1 } } */ > +/* { dg-final { scan-assembler-times "ascii \"0:3:1.0\"\[\t \]+\[^\n\]*btf_aux_string" 1 } } */ > + > +/* { dg-final { scan-assembler-times "0x3\[\t \]+\[^\n\]*bpfcr_kind" 3 } } */ > diff --git a/gcc/testsuite/gcc.target/bpf/core-builtin-fieldinfo-sign-2.c b/gcc/testsuite/gcc.target/bpf/core-builtin-fieldinfo-sign-2.c > new file mode 100644 > index 00000000000..bf184299984 > --- /dev/null > +++ b/gcc/testsuite/gcc.target/bpf/core-builtin-fieldinfo-sign-2.c > @@ -0,0 +1,45 @@ > +/* { dg-do compile } */ > +/* { dg-options "-O0 -dA -gbtf -mco-re" } */ > + > +enum { > + FIELD_SIGNEDNESS = 3, > +}; > + > +enum Esig { > + SA = -1, > + SB, > + SC, > +}; > + > +enum Eun { > + UA = 0, > + UB, > +}; > + > +struct S { > + enum Esig sig : 3; > + enum Eun un : 3; > +}; > + > +union U { > + int i; > + struct S s; > +}; > + > +unsigned int foo (union U *u) > +{ > + unsigned i = __builtin_preserve_field_info (u->i, FIELD_SIGNEDNESS); > + unsigned sig = __builtin_preserve_field_info (u->s.sig, FIELD_SIGNEDNESS); > + unsigned un = __builtin_preserve_field_info (u->s.un, FIELD_SIGNEDNESS); > + > + return i + sig + un; > +} > + > +/* { dg-final { scan-assembler-times "\[\t \]mov\[\t \]%r\[0-9\],1" 2 } } */ > +/* { dg-final { scan-assembler-times "\[\t \]mov\[\t \]%r\[0-9\],0" 1 } } */ > + > +/* { dg-final { scan-assembler-times "ascii \"0:0.0\"\[\t \]+\[^\n\]*btf_aux_string" 1 } } */ > +/* { dg-final { scan-assembler-times "ascii \"0:1:0.0\"\[\t \]+\[^\n\]*btf_aux_string" 1 } } */ > +/* { dg-final { scan-assembler-times "ascii \"0:1:1.0\"\[\t \]+\[^\n\]*btf_aux_string" 1 } } */ > + > +/* { dg-final { scan-assembler-times "3\[\t \]+\[^\n\]*bpfcr_kind" 3 } } */ > diff --git a/gcc/testsuite/gcc.target/bpf/core-builtin-fieldinfo-size-1.c b/gcc/testsuite/gcc.target/bpf/core-builtin-fieldinfo-size-1.c > new file mode 100644 > index 00000000000..8747bdeb9c3 > --- /dev/null > +++ b/gcc/testsuite/gcc.target/bpf/core-builtin-fieldinfo-size-1.c > @@ -0,0 +1,43 @@ > +/* { dg-do compile } */ > +/* { dg-options "-O0 -dA -gbtf -mco-re" } */ > + > +struct S { > + unsigned int a1: 7; > + unsigned int a2: 4; > + unsigned int a3: 13; > + unsigned int a4: 5; > + char carr[5][3]; > +}; > + > +enum { > + FIELD_BYTE_SIZE = 1, > +}; > + > +union U { > + long long l[3]; > + struct S s; > +}; > + > +unsigned int foo (union U *u) > +{ > + unsigned ls = __builtin_preserve_field_info (u->l, FIELD_BYTE_SIZE); > + unsigned s = __builtin_preserve_field_info (u->s, FIELD_BYTE_SIZE); > + unsigned a2 = __builtin_preserve_field_info (u->s.a2, FIELD_BYTE_SIZE); > + unsigned a3 = __builtin_preserve_field_info (u->s.a3, FIELD_BYTE_SIZE); > + unsigned ca = __builtin_preserve_field_info (u->s.carr, FIELD_BYTE_SIZE); > + > + return ls + s + a2 + a3 + ca; > +} > + > +/* { dg-final { scan-assembler-times "\[\t \]mov\[\t \]%r\[0-9\],24" 1 } } */ > +/* { dg-final { scan-assembler-times "\[\t \]mov\[\t \]%r\[0-9\],20" 1 } } */ > +/* { dg-final { scan-assembler-times "\[\t \]mov\[\t \]%r\[0-9\],4" 2 } } */ > +/* { dg-final { scan-assembler-times "\[\t \]mov\[\t \]%r\[0-9\],15" 1 } } */ > + > +/* { dg-final { scan-assembler-times "ascii \"0:0.0\"\[\t \]+\[^\n\]*btf_aux_string" 1 } } */ > +/* { dg-final { scan-assembler-times "ascii \"0:1.0\"\[\t \]+\[^\n\]*btf_aux_string" 1 } } */ > +/* { dg-final { scan-assembler-times "ascii \"0:1:1.0\"\[\t \]+\[^\n\]*btf_aux_string" 1 } } */ > +/* { dg-final { scan-assembler-times "ascii \"0:1:2.0\"\[\t \]+\[^\n\]*btf_aux_string" 1 } } */ > +/* { dg-final { scan-assembler-times "ascii \"0:1:4.0\"\[\t \]+\[^\n\]*btf_aux_string" 1 } } */ > + > +/* { dg-final { scan-assembler-times "0x1\[\t \]+\[^\n\]*bpfcr_kind" 5 } } */