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 E48F4388451F for ; Wed, 26 Oct 2022 19:23:44 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.1 sourceware.org E48F4388451F 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 (m0246631.ppops.net [127.0.0.1]) by mx0b-00069f02.pphosted.com (8.17.1.5/8.17.1.5) with ESMTP id 29QInLod032718 for ; Wed, 26 Oct 2022 19:23:44 GMT DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=oracle.com; h=from : to : cc : subject : date : message-id : in-reply-to : references : content-transfer-encoding : content-type : mime-version; s=corp-2022-7-12; bh=wH1bsFZNRy/ADFjLOM+yStZbEVnlSfNRoR1RGlJp2Us=; b=BmKTclgre1GU6Mf+fEAnYwHC0IYPk8C1q/7s+dWZaSb1M5Epl1/F/MHsENEW1BpY8tv/ E8jP2+3ktWl1VcRK/PL1wyr2E0MaeMbIUoj4YQQ7YU7uckJs47x3ZxivJ5N8EkVw0mCb jcXhDp3+G7l+nXBF8vfdHpQORaw6jmI9sD05F4+MC/88AFDgMZU56YiPbPF21Si3VXyZ CfZzcO1Vw5ybDP4xZbNb9Fr9A/YK4LFTkQnG4pk38rithLlW1t4DLnj/6JijmJBSxHko NjPwcscO+3Z/TSs+h8YmXfUKArnCh2SWm0SyqSbWD6iKhMfA9hRA5xFjVCGb/VQUOE42 Sg== Received: from phxpaimrmta01.imrmtpd1.prodappphxaev1.oraclevcn.com (phxpaimrmta01.appoci.oracle.com [138.1.114.2]) by mx0b-00069f02.pphosted.com (PPS) with ESMTPS id 3kfagv02un-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=OK) for ; Wed, 26 Oct 2022 19:23:43 +0000 Received: from pps.filterd (phxpaimrmta01.imrmtpd1.prodappphxaev1.oraclevcn.com [127.0.0.1]) by phxpaimrmta01.imrmtpd1.prodappphxaev1.oraclevcn.com (8.17.1.5/8.17.1.5) with ESMTP id 29QImbSg009702 for ; Wed, 26 Oct 2022 19:23:42 GMT Received: from nam02-bn1-obe.outbound.protection.outlook.com (mail-bn1nam07lp2046.outbound.protection.outlook.com [104.47.51.46]) by phxpaimrmta01.imrmtpd1.prodappphxaev1.oraclevcn.com (PPS) with ESMTPS id 3kfage8x7r-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=OK) for ; Wed, 26 Oct 2022 19:23:41 +0000 ARC-Seal: i=1; a=rsa-sha256; s=arcselector9901; d=microsoft.com; cv=none; b=JUt3yHx9C0wq/MkqeG7X9eEQpkhQdsgDpmttxpbi8IYj+QlcYvNPTfdmysfkkcOzCNJQ1G2ErYUo7EvIlj1KeOQM10OHTCLmA2PIDEFnZp0ZCLT6fmm3M2szXwSwFvgabpQzjFwtS4zQ7yrwdTETU2exdmpov7akIGzPIXSi2fgUVH3ZtF1gNnkCsJtp5GnDpM7Y6OFvUIQF8LO+gJ1Op3UlYsAgTEItQMnHnLfAmq598BJLDvwAK1pN8mhIzGa8R+DYF/35nxnEzQEKleXK+o8u3PQLpumNoBxvU4E3bqzHgT6d+pWiNDo3ujWhhqK+HRmisJP/YdAIV2rQiaw2rA== 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=wH1bsFZNRy/ADFjLOM+yStZbEVnlSfNRoR1RGlJp2Us=; b=gh8NCuNNEvnr3iZePrsSaKJDsc9X8loPv/5rGCGpI7aF26+v+zx+6BBkRh612tdfsgYIBll5V6DoeeDlfUB5c0aaTmM4dn/dVfVFozNp/ZXu7iUsLBLXnM3bnxiaMesGJ8xHzmEoWbY6of72kODbAr+Bf2MQ3o/JOORybiMnWntLtx5NFfDNWc0asQeXOksd2XO1GQyN01TsOt15VZSiNKn5GNX5DyC7F50sL34wWJpCPMKZEB0G7pqcgIiT3TguieF5DFtik00BF1VrkGgaMUpdIyg8kqNGg5dYYDHP8hxaqVP/mm8anBwEIqURjT/EBYFEHQSFMsTbt3reQtKi4Q== 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=wH1bsFZNRy/ADFjLOM+yStZbEVnlSfNRoR1RGlJp2Us=; b=t/DC4IDNNHmzf+bJxZ96PM9Dq1qDbgI/9qFYliT7fpHm2rQVLYnr+zZXx42WmIl1zU0IUQSfNjrhXWV3nSu2xrTLPyOWJoXw73NZDIZVPORl5+7elbXTUVWVVCmZ/KPtDCg8yRBfeNNA4TbdrTv8fRvkXGJS5q9+H3BDlyS9Cxk= Received: from MN2PR10MB3213.namprd10.prod.outlook.com (2603:10b6:208:131::33) by CY8PR10MB6635.namprd10.prod.outlook.com (2603:10b6:930:55::12) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.5746.21; Wed, 26 Oct 2022 19:23:38 +0000 Received: from MN2PR10MB3213.namprd10.prod.outlook.com ([fe80::5748:a42:ab8f:f79d]) by MN2PR10MB3213.namprd10.prod.outlook.com ([fe80::5748:a42:ab8f:f79d%7]) with mapi id 15.20.5746.028; Wed, 26 Oct 2022 19:23:38 +0000 From: David Faust To: jose.marchesi@oracle.com Cc: gcc-patches@gcc.gnu.org Subject: [PATCH v3] bpf: add preserve_field_info builtin Date: Wed, 26 Oct 2022 12:23:11 -0700 Message-Id: <20221026192311.12260-1-david.faust@oracle.com> X-Mailer: git-send-email 2.37.3 In-Reply-To: <87o7tzyazk.fsf@oracle.com> References: <87o7tzyazk.fsf@oracle.com> Content-Transfer-Encoding: 8bit Content-Type: text/plain X-ClientProxiedBy: SN7PR04CA0172.namprd04.prod.outlook.com (2603:10b6:806:125::27) To MN2PR10MB3213.namprd10.prod.outlook.com (2603:10b6:208:131::33) MIME-Version: 1.0 X-MS-PublicTrafficType: Email X-MS-TrafficTypeDiagnostic: MN2PR10MB3213:EE_|CY8PR10MB6635:EE_ X-MS-Office365-Filtering-Correlation-Id: 4fc63744-59d7-4109-38f2-08dab787958e X-MS-Exchange-SenderADCheck: 1 X-MS-Exchange-AntiSpam-Relay: 0 X-Microsoft-Antispam: BCL:0; X-Microsoft-Antispam-Message-Info: 5lK+K6ZdjtyP4Lk3tJYGRE9Uc5kMHXMTmh/LhoDqwI6OndCDe4MLU6p9EEDUw4fek1EGfFYbp3h0FHhR1PY8AjMVMKH9PAWijYCTyis7F83QR6L404o7QPmvoRtgcPcj7WKoh3iMKb0tTZ4YboFfLAqbu55fNarQtVjO4lP8U1gXPus9Kq1i8DoB1a4EfeXYPjnkf6aM1DGfGu6I7yBMXu5f3rGRtVYbS2dEKk305DEMRZCf1FUSSCCSaP/4gXjr/Dtz+spRz47aMApdrSho+0aeMPzqn0np/Xu284RzSagLFbgaePCybTGWalSUYFAP+T/O1EQAw5zH+wQDTyZrRQ1BEZ2QWjsC+eCm1LUzvb1iN8K0Nssw9tWEV/Mq7VFLIvz8giMkmaY2nV7VPWWGLb5pXU4w/9sRWe6/5/BJ75a+ylUTSdkyV/i3AMh6Pt+jju2OgGZONphSM+aa9vY6KbiZQtupKqk4ifvZuw/6SVOA5ALpPcwVnmh5J5EobT8efYHYplJ03gPjAuESPOaYHsP/5tV/aF0b2PauEMOoIFQYM5ZYQTEQT67bXqwViwhCvJxi//Z4cbDc6pX+vltMXbo4XWRDkd+458ZrH7KgOyD6HQGZR9x0etjWjUJ8rg8Go/pxlWp8zhgIEBSlj1p8HVrJ7FV5EWCtZCsGnBAAEHK8BVNrjmcTCnIw8UaNGlpNQQHNwE+b6F3ZsWL6mcLlGZV/HTWuguh6DuTQo1d3c+s= X-Forefront-Antispam-Report: CIP:255.255.255.255;CTRY:;LANG:en;SCL:1;SRV:;IPV:NLI;SFV:NSPM;H:MN2PR10MB3213.namprd10.prod.outlook.com;PTR:;CAT:NONE;SFS:(13230022)(136003)(376002)(396003)(366004)(346002)(39860400002)(451199015)(6506007)(6666004)(478600001)(6486002)(37006003)(6636002)(66946007)(316002)(84970400001)(66476007)(66556008)(4326008)(8676002)(2616005)(44832011)(41300700001)(30864003)(186003)(8936002)(1076003)(5660300002)(6512007)(26005)(2906002)(83380400001)(34206002)(36756003)(38100700002)(86362001)(579004);DIR:OUT;SFP:1101; X-MS-Exchange-AntiSpam-MessageData-ChunkCount: 1 X-MS-Exchange-AntiSpam-MessageData-0: =?us-ascii?Q?vqHoOZN5wMD3jnXClqaE3NS/AkKzNSzYiJVB/geMUNQmsxbK1dmUkYPPNzrY?= =?us-ascii?Q?1hUWJAPH04q+lOayrx9f+d3n7V355I7uf1dzhFTr9fwJl0E+RW3+niMESZ1K?= =?us-ascii?Q?895dEXbFEERSOPi95mD0rdC8BLhrNYlLTD9JQUW1aUzxqCCz05F6IaM62eXi?= =?us-ascii?Q?0KY+enoEEg+lrqg/gb8zyzls+2RQFt1Hp6cPh5UCs/zRxyruoGUUWg4DBRgG?= =?us-ascii?Q?W8OX4YZmW86g/KPSc68iOcYDOkYoQx4HK3Vb7ZPCMnzn3kdd5lqq/24CAL8o?= =?us-ascii?Q?1z5hA9XO1Iyws785+z/Pjd7A7eUh0Bt0BO+JKj5RGjg9F75porSkhV4c6wgA?= =?us-ascii?Q?fADwGIygZCEJoVlDBVTBEY9TRmB/29llecHrfDQx47IXt0aJDdyPOK5RUVqA?= =?us-ascii?Q?gdH6K7CWhpjsu+EYewrOJ/z2KGnyGUA3y4XvJxikAkPJIxmlQsggjZxcp2XK?= =?us-ascii?Q?oUPftXKwdyCsJilAwG3jj0iG8uIs4QOkux99kxNCqV4F77HxVmPJ0GmpjSRg?= =?us-ascii?Q?iOd0LfyiqtrwJGmp9hWgXd6RpodoyLj0Gq2aYHWCwA9ayMKUKy6J/BhEvQd0?= =?us-ascii?Q?y5odKlXq9VdLuIOrWmBkpjvqw8Do7ht8b+UpeJhJOonYM19GZDoyfs/BhabO?= =?us-ascii?Q?1rH06cvbC1M/gltBeqWFsCvqVgXBikuA1JOzz/efN6A86XKMSltxRoYJbQL1?= =?us-ascii?Q?xyQL/2sLaun7y2v5pyJve52ZquIdMc83pvpYflYDwFh5bsR+K/CKVQ5Y3y95?= =?us-ascii?Q?cZ/P3/Wt9pzNZRR5ocJo6k4D0GAUE1/EhoKr5YCmGA90jcHC/m0Qle7wjE4u?= =?us-ascii?Q?I19zdgITdRndixE/71hEpDxKdJW5/hXO/0XtMjYl1M/Dy02zmM8T3MoMUgwb?= =?us-ascii?Q?ZYzUiIhfdHoxKLzKgKWHrSeBbARd/mWmIkiSluePXrjZwenw2OhuhX+lJ0TJ?= =?us-ascii?Q?I4+zm1BnHVnL7fl2mJPVMSpzGFbHKmth2boSNa27F6xE2QdqEJk1d6KFCJjQ?= =?us-ascii?Q?uXI8+yQ4MHe8V7gtLzcTrZcgHF1ijhmR08F1UmCo3nWs4MMIo4kRTYjQc1+P?= =?us-ascii?Q?KKoIQYeAFGcQVfF0QZKzaLkkFJ52zlN3zCf7NnyeEcNfzRA0id+x/LeOWKg9?= =?us-ascii?Q?sAKwwClvBHeK2ATYNqMGoXlDAd4UwlboC9AnB9Ng1xcoaDTsH1ixhGeZOTJO?= =?us-ascii?Q?nU6gV1fOFFThxxwGNbTgtsEmk1I4q7jNk3XD4lGDdrKM8Gmy6ml/2KCfluec?= =?us-ascii?Q?VGH33G4FjwIFtF38pI7m9koK0MwiyIpjSPehxOa7mhkZk9WiKC4Dz5EHEGB7?= =?us-ascii?Q?Ro2UY+bLmXpHBVJO/sgPAY1o+a5ly/5UQi/A8NWcVWBNmc4MLydhAkA1INRw?= =?us-ascii?Q?6p+hKGhw52krL5pbr34UiOrdlcrDbQaXULIzyVlkJsJ7lomoozR1eGTNfJ/d?= =?us-ascii?Q?EniUszBM1v9LbdqE96YKA8eluGskRH4iDE0wO8Fux5Lq8xTyQ6H+AnxcR9d0?= =?us-ascii?Q?mutr6ww88GD6T4bi6vU4rTAmdpJZ54SEB2Kx2SIn3nW/VE70HLOeHxZ3heuY?= =?us-ascii?Q?9V9a9xderI4F9yni/O+b7tzmq/YBByKWj30r1Pil?= X-OriginatorOrg: oracle.com X-MS-Exchange-CrossTenant-Network-Message-Id: 4fc63744-59d7-4109-38f2-08dab787958e X-MS-Exchange-CrossTenant-AuthSource: MN2PR10MB3213.namprd10.prod.outlook.com X-MS-Exchange-CrossTenant-AuthAs: Internal X-MS-Exchange-CrossTenant-OriginalArrivalTime: 26 Oct 2022 19:23:38.6283 (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: MQmmcmCSyCblnHbv+9g8qZhwmoMP09IhJdy5jEiTVrC8UwfVaJe89zmxHVB2fSy4oFvLflzAcABVLbZ7f8ljXg== X-MS-Exchange-Transport-CrossTenantHeadersStamped: CY8PR10MB6635 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 bulkscore=0 mlxlogscore=999 suspectscore=0 mlxscore=0 spamscore=0 phishscore=0 malwarescore=0 adultscore=0 classifier=spam adjust=0 reason=mlx scancount=1 engine=8.12.0-2210170000 definitions=main-2210260109 X-Proofpoint-ORIG-GUID: R8dGXe3h-xVixWDBBbuDD-yFobh09ck- X-Proofpoint-GUID: R8dGXe3h-xVixWDBBbuDD-yFobh09ck- X-Spam-Status: No, score=-13.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: >> 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 } } */ -- 2.37.2