From patchwork Wed Sep 3 13:53:35 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Jovan Dmitrovic X-Patchwork-Id: 119467 Return-Path: X-Original-To: patchwork@sourceware.org Delivered-To: patchwork@sourceware.org Received: from server2.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id 0D0253857B90 for ; Wed, 3 Sep 2025 13:54:29 +0000 (GMT) X-Original-To: libc-alpha@sourceware.org Delivered-To: libc-alpha@sourceware.org Received: from GVXPR05CU001.outbound.protection.outlook.com (mail-swedencentralazon11023118.outbound.protection.outlook.com [52.101.83.118]) by sourceware.org (Postfix) with ESMTPS id C9AD3385841E for ; Wed, 3 Sep 2025 13:53:42 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org C9AD3385841E Authentication-Results: sourceware.org; dmarc=pass (p=reject dis=none) header.from=htecgroup.com Authentication-Results: sourceware.org; spf=pass smtp.mailfrom=htecgroup.com ARC-Filter: OpenARC Filter v1.0.0 sourceware.org C9AD3385841E Authentication-Results: server2.sourceware.org; arc=pass smtp.remote-ip=52.101.83.118 ARC-Seal: i=2; a=rsa-sha256; d=sourceware.org; s=key; t=1756907623; cv=pass; b=jrg5l2DFfoQvcAJihgUjQaurHIoLgacL9NHbAqcIbWiFmwPKMbSfKGbjEinpB1aisTCzjuPbogqWEXJMwcFxa29PdKrLvQMBXzU7KkpTXGnvMqSGx7ZQZP6pp9xDG+jqLh/49q7R9A/xT/Jij8SgBatMrH/dSX7fsqNGkydmmyU= ARC-Message-Signature: i=2; a=rsa-sha256; d=sourceware.org; s=key; t=1756907623; c=relaxed/simple; bh=42jeNAvvxbCGOhlioioeTFYceb+3iJERHVOm35uNvxU=; h=DKIM-Signature:From:To:Subject:Date:Message-ID:MIME-Version; b=oudO/ntftM0jPG06guxy7tNRNJzVMH99kst1O7E7IsFFHv1EPOOdpKixd7206l3ekiEUH8QVzVbjslX5hBxY28KPlYyL/U5C8vjPAD1opUtQJkPN3sW3j23Swm2ax3sQaot/oFpEcwa/lPzUaOYvHbGIIqK5Hi/bhSwxa07KU1M= ARC-Authentication-Results: i=2; server2.sourceware.org ARC-Seal: i=1; a=rsa-sha256; s=arcselector10001; d=microsoft.com; cv=none; b=TomArPi1vrNgQT7MrwR9cFSSxAa2XETxMNX74rso6PjwWgFNL1KEpXqzLsYSyNYbpurXrV3U1nbtXb5Np8lEpfxQ66x/rX9j1xHpmpGQ2UcnQwLnB1APpC/85dZSG3LfyoPhzUBhhzr+ik6kAYTfsV8+5nRQ+kgXRP1jrIvrh4hmex8m6auKcBFaPCUL8DnFWjfeFFTGLNYbjGVR0rpI94j2ycmbsCbWMGfsWsNHA0T+MLiJ+kwfqzPb+TwiVwLy02w8Rk0D0YSlCuXsw2815qe1p/AK+uykXn7S+/SYICXFwIPLqajtjHZCfVR/INUFOXsRU8eGHS8SpQr8Bar6Fw== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=microsoft.com; s=arcselector10001; 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=42jeNAvvxbCGOhlioioeTFYceb+3iJERHVOm35uNvxU=; b=UJnV/qVMwpGWEuE1HP9tkZyH4BSk1jKs1xAA19bsTjiw00930/E+AKvXNx8wS2Xnz1cctcJNH97yk1zR9VISHCwdKGUnCc4ZO3gcIw/NjRBZp4v7z2JwtrpPT30x2V+U1X+O8x7n4PnM7xn6JvFEblQBphC4u8GcmOlkb0hkAswkJBsSTK7ccNkQ07fR6yAXuUmI1DdeTIUi518OKACAQHwv3gmp1m+22i5HFjRlsuYfJrMbKDnYRe84sYLIjwxDJc0SxFGfTMBQ3y/MKmkVBGDMrtmI1OktThnybgQZDZAQ3yd7/4FeSQQaeYFTGW6yQwiCtXmUQlsdgL9webU1yg== ARC-Authentication-Results: i=1; mx.microsoft.com 1; spf=pass smtp.mailfrom=htecgroup.com; dmarc=pass action=none header.from=htecgroup.com; dkim=pass header.d=htecgroup.com; arc=none DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=htecgroup.com; s=selector1; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-SenderADCheck; bh=42jeNAvvxbCGOhlioioeTFYceb+3iJERHVOm35uNvxU=; b=K1vGzOyr2KSmEg1dC2AluViq0jqfI69D1sdAQ5HkJpMonGy0N3lkG8KS09YN8OSwa3NwxXZTSn370xAhd4WDPxhG5KZzXaWgwss1c6GUVcMUSIHlKbt/Rmijq41D1zzrsEnqb289CJ3l7oiKs9ahvttvr/R5w3KOeeD2LAEfLUT3sIJwslb/PKK/6XHb7uhDibC6A5y3em6AC0MDUMCKTMWWOiUrdDbvxklUJqV3BmpfGfSbh5SO84dP6++rvi7gBbK4w447YG9nJ3t2SmO8q9GCnRZt5TyPyG+B+xWJ0BNZyiyDBQ3zlWY74aLlVcISZLy3rvZCbDNDHEvfsWh6LA== Received: from PAVPR09MB6451.eurprd09.prod.outlook.com (2603:10a6:102:304::13) by VI2PR09MB7379.eurprd09.prod.outlook.com (2603:10a6:800:220::22) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.9052.29; Wed, 3 Sep 2025 13:53:35 +0000 Received: from PAVPR09MB6451.eurprd09.prod.outlook.com ([fe80::4569:9af3:a4cf:48d]) by PAVPR09MB6451.eurprd09.prod.outlook.com ([fe80::4569:9af3:a4cf:48d%6]) with mapi id 15.20.9031.023; Wed, 3 Sep 2025 13:53:35 +0000 From: Jovan Dmitrovic To: "libc-alpha@sourceware.org" CC: Djordje Todorovic , "Maciej W . Rozycki" , Aleksandar Rakic , Adhemerval Zanella Netto , Joseph Myers , Jovan Dmitrovic , Faraz Shahbazker Subject: [PATCH v3 4/6] mips: Add C implementation of memcpy/memset Thread-Topic: [PATCH v3 4/6] mips: Add C implementation of memcpy/memset Thread-Index: AQHcHNokmUfx1lLypUWeaCzwqp12Vw== Date: Wed, 3 Sep 2025 13:53:35 +0000 Message-ID: <20250903135251.679132-5-jovan.dmitrovic@htecgroup.com> References: <20250618143327.2665823-1-jovan.dmitrovic@htecgroup.com> <20250903135251.679132-1-jovan.dmitrovic@htecgroup.com> In-Reply-To: <20250903135251.679132-1-jovan.dmitrovic@htecgroup.com> Accept-Language: en-US Content-Language: en-US X-MS-Has-Attach: X-MS-TNEF-Correlator: authentication-results: dkim=none (message not signed) header.d=none;dmarc=none action=none header.from=htecgroup.com; x-ms-publictraffictype: Email x-ms-traffictypediagnostic: PAVPR09MB6451:EE_|VI2PR09MB7379:EE_ x-ms-office365-filtering-correlation-id: 8f21c600-68ee-46fd-136d-08ddeaf146e8 x-ms-exchange-senderadcheck: 1 x-ms-exchange-antispam-relay: 0 x-microsoft-antispam: BCL:0; ARA:13230040|366016|1800799024|376014|13003099007|38070700018; x-microsoft-antispam-message-info: =?utf-8?q?AlliHwyiWQ5sDD49rbg3MuXT02pQb0A?= =?utf-8?q?IsIYPwr7JZX38u+ZJqdBI8J0o4Vtr8poiiomVb/BgwJE4PIN+UgcofHpeHDwTS/uq?= =?utf-8?q?S4mTkPoqEWE/XK9N3KzAyMyAejZlW0Opu5NZ2ofKXXfg37MTYc+TJK4bLWtZMPqOB?= =?utf-8?q?D5AD7KTH2oNDSUVYAmHe3T+s9Lln0ZYQSZNFe8WePOheEbvysfF2c1qhrIgmBUezv?= =?utf-8?q?VT4AQ4e4umt5gPgwXkrMBg6a9BmLlG8GOHBhtsJDBFs5cKLCBNSOkq5LYF4guB4/C?= =?utf-8?q?zfQ17ROluyW4Vtvpd/csng4QCIufSAOc9G8Qvez35TNmkNqs+LIJle/gnnQg+HYlX?= =?utf-8?q?QtfQ022VT6UUioDZkSBPNrFY3wV8u22CS7Ct5SFqJ4JBp6ixp9ppV6Swo1tQpXPmW?= =?utf-8?q?VGC4TshoB1IHMmNxotOS9RRETLMW7EtMtIyi6CbJxteMTgRwE95LdZD7OBRF2KCbc?= =?utf-8?q?lhFJrRjXONFS70L/7XRMEJ5AeToRp0p78W858WwNU9DFqUdSvakN/TcW0+bQ4ARCT?= =?utf-8?q?UAi7ZMaOX7gFahZ4RP/N1sd5Y7KkWM3LkmihXQEA4mVJDeNoxvKo1jtTfgEgeTgVh?= =?utf-8?q?1Bn8f2hP51bc5dbEbgQUIFq1yxG5hmjqCu2e1RPG1NucOvdmn/QItwRhFnIkUCA3q?= =?utf-8?q?DYfe1Yr6jEptP6tc/IkJTCHL/4lXZEJtW7inDVXIN3XKl3Bl0rLnDPcgzNUBYH0WK?= =?utf-8?q?ignbs0kNz2/iNmzbjvHFIZ6Iv7FFNOI5pEA7uT3onUUEJ2aoYeqN8Hca/7L3SwVcy?= =?utf-8?q?04yx5PWzD/ztPYGPMQNgObl1h6GtHA+PZdB9c0z45H7jlkPNFmaVLt/VWGJBg3rpu?= =?utf-8?q?Afu0jsHLObQihiJecITMe5iiZHU7CKi/8ryTApvCi9iY+KG1JZo4fkV6wXp4QMeDY?= =?utf-8?q?NoaPqgZKhLj1AuNfFIUSyzG8clcrRuo+0ylAHiKV2HSBITBHveQXxvYpRZoun5pqP?= =?utf-8?q?4NUkLgEq1u5RMIFAOxzDgjuVYqcMSrwjZrFP1oa+hmyy/vS2QfJvCFMa/TYAja2BQ?= =?utf-8?q?mfOiva8Ky5dV17MTBYLk24FCB9Hf2HO3JwiMq8q4IhGLaFFgnJLDiibmRO+DKiw2m?= =?utf-8?q?KL2ndDQzt05WcOB46xgnR8fkyA4wgCZYgULVUCupyMDcg82+tyHnoCyFP71rqDPRV?= =?utf-8?q?D0lsBqVQN7E69ddeYnqcoJtrYj4upcGqJY6o/ayjyiKcN6zQ2xfAdA4fqZFnjlqxr?= =?utf-8?q?TsbK7w2E/arEscsnYVA6hzRjlP6drpdk4zMClcRharcyRRuxcaWOz1YiXInSdCcAb?= =?utf-8?q?xY6F5mDBNfa79HAHzc+2w6yrHbXh1NT6f9oxh4GhI9jpi8qrctfWe3N5LDXjaqLBN?= =?utf-8?q?a1eeQvCGpXgrMlE6cms/W9hJ1Jh9QppEpQnN10O0N0mldL5UkOcgZCf5WxRAmieMj?= =?utf-8?q?4tRoM6WwvajN93ptM1sioSEnZHZQ5x5PwK6xwe1JW0iNXZgXBaYUqo=3D?= x-forefront-antispam-report: CIP:255.255.255.255; CTRY:; LANG:en; SCL:1; SRV:; IPV:NLI; SFV:NSPM; H:PAVPR09MB6451.eurprd09.prod.outlook.com; PTR:; CAT:NONE; SFS:(13230040)(366016)(1800799024)(376014)(13003099007)(38070700018); DIR:OUT; SFP:1102; x-ms-exchange-antispam-messagedata-chunkcount: 1 x-ms-exchange-antispam-messagedata-0: =?utf-8?q?dEswUOpGF+sl8xltJVCh1tgMU43m?= =?utf-8?q?q/0ezKLRNsbLOZBrnv7WNUDInGLOXoBkSvUKv6P97tiIyJVuRqVq5W7Fye4/cf0Za?= =?utf-8?q?ksxPL6SQcLaqeLL/D7ZD0hgawesZOgu8hVwMs/eJ5okjtp7Zhnn2I8J9oUO6BIiN8?= =?utf-8?q?LeJJ2bkepS3jqT/3+CInP5KnU2GbEFf7f9yUOmAx3UTeX89gnIPdkNa0g6d2dD33n?= =?utf-8?q?rMTPf+egq+oZ1u9BMth5t63J4RotwuwoYkfDN+cuQ/5yqhYXhF4+cWaGG1QenGZ8X?= =?utf-8?q?VEfD7Um+yQ27NLxoB2gGQW3KRxPl78nisXIFVGFBjdKXTMLOFspIm5NSJzGLl8NQB?= =?utf-8?q?kG8XYwRLk2ggEpDrjHK+LwOe5yroK7bHhNIX8Ba3coIRdvmMeTcOOA3++5FkXTObL?= =?utf-8?q?vr9F2US0xYjOcEFvLRcv9sKZ85ocXazltpLGcep6Hp0uqaIhGlZo4/vs7v6lUZ3X1?= =?utf-8?q?SJB/Lv962+CbeeS0o3v94cFRbk8v1T2A6KZAb1O6Atiy9ivS8Wjmm6J3VZmbt392/?= =?utf-8?q?be22Q9mD1kIwmXeq5korpUTexdpsE/WG81mMvtiItkl3kIEAWcFFe5jKi76bb9aQa?= =?utf-8?q?aBejlTW4s4jZvdISegl29lQQtk1qq/kFMA/vDtpL8fz50lZp+kTaKQUnKD9GKSLP1?= =?utf-8?q?2D1M/nzfGB5j8sNc/8ivbUsGZUf83QJWgdWqcrqUMjxecLOHnaghxUJvavdOBNjVl?= =?utf-8?q?4/NjGN1K6BucOYpKlJ4WSUponBu5R++Cpaq1sbh9RXeVs29hcLU/9rU2xcjO5hfn0?= =?utf-8?q?pOsDrS77MIp2q7TjTSTQ9sdZ1cyp8Eeurr4PtIeF/M8QHHwv+IZyKkywCaqoKr1+X?= =?utf-8?q?OjV1dtZ5au0qjUe1fVHnA0Vah+cfLE9KNs5UHgK5b1/2mLdogj1o+H/bFL+5sYSGd?= =?utf-8?q?kuiZZTuGKDp9umATd2Xi71K7TTIkNd6n4z2lkiPQWVtvG0JnD2Oxw+lINdYLo8mH/?= =?utf-8?q?ZI9tPj2rrdBJDKkHvyjMHGoL5lYU8N7HLJfi72syJ/7++sEiNMj9NA5nPS3Wp00S6?= =?utf-8?q?jRWbZXBv+BXQoo9Uso8aZjgSuGbLr4zzkKuYS73YYcmhs9ruy7HjDJJNG8U9njWmT?= =?utf-8?q?8ci7lewNCNvllLtXZwaS6Uc29n5muRtoaupSkFzDYzCJtbJAc+OQwuYNtY2oUq4b6?= =?utf-8?q?D3vRodqv/Yzy1FIYBM6malEfsnUE8dKTREn5klj6tSWr7vYG+F9Mx5UEpD4KQnZMJ?= =?utf-8?q?svpB8PpvNWVXlUX6cfWn3WWzsV08sGhfeF1jLl7dkMGb+T6A9osfFJKaigqyDFGkd?= =?utf-8?q?if1KWKGcorNK0fIBQpBp8uXXL18dUDAdaWxfTtyxhksGCNREpbj7iBXNu/gtbqI3t?= =?utf-8?q?9qiaQY3WJWTX6c2HnAOz/5JunnYAdMRrAtjh6JmR3ppt+1vR6EWBD63J/hBdbTVl/?= =?utf-8?q?3ZLH4fq5spqHCgcxioAMTfHnylO/i49hMBkFnc0LvVjSA8KmK+UJKvDRI+o3pX0l2?= =?utf-8?q?+l3FB1zv3WehpgafCPg6nOds+EitVDUbs2AgkIUYoahHL376uDLeY7HB3KiuhtWw2?= =?utf-8?q?hOI0j5dQFS5dOGyipMM4Elq/lT+h5wjUTXmV3718HNBfBLJ58nCWvsA=3D?= Content-ID: <789D63C9AD9D0F4E9413B4765267D534@eurprd09.prod.outlook.com> MIME-Version: 1.0 X-OriginatorOrg: htecgroup.com X-MS-Exchange-CrossTenant-AuthAs: Internal X-MS-Exchange-CrossTenant-AuthSource: PAVPR09MB6451.eurprd09.prod.outlook.com X-MS-Exchange-CrossTenant-Network-Message-Id: 8f21c600-68ee-46fd-136d-08ddeaf146e8 X-MS-Exchange-CrossTenant-originalarrivaltime: 03 Sep 2025 13:53:35.4043 (UTC) X-MS-Exchange-CrossTenant-fromentityheader: Hosted X-MS-Exchange-CrossTenant-id: 9f85665b-7efd-4776-9dfe-b6bfda2565ee X-MS-Exchange-CrossTenant-mailboxtype: HOSTED X-MS-Exchange-CrossTenant-userprincipalname: 7Ejq+nW/YJ+wJyf08hRJUHLqMp5uuj04HNe17YxKq2aR+q8PIPz3C5lvp1xeaJU/vRvtC7TO1Hks28HV9mhv90LWwTzbawh82PbMxW8RwEM= X-MS-Exchange-Transport-CrossTenantHeadersStamped: VI2PR09MB7379 X-Spam-Status: No, score=-12.7 required=5.0 tests=BAYES_00, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, DKIM_VALID_EF, GIT_PATCH_0, KAM_SHORT, RCVD_IN_DNSWL_NONE, RCVD_IN_MSPIKE_H2, RCVD_IN_VALIDITY_RPBL_BLOCKED, RCVD_IN_VALIDITY_SAFE_BLOCKED, SPF_HELO_NONE, SPF_PASS, TXREP autolearn=ham autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on server2.sourceware.org X-BeenThere: libc-alpha@sourceware.org X-Mailman-Version: 2.1.30 Precedence: list List-Id: Libc-alpha mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: libc-alpha-bounces~patchwork=sourceware.org@sourceware.org Add improved C implementation of memcpy/memset and remove corresponding .S files. Signed-off-by: Faraz Shahbazker Signed-off-by: Aleksandar Rakic Signed-off-by: Jovan Dmitrović --- sysdeps/mips/memcpy.S | 868 ------------------------------------------ sysdeps/mips/memcpy.c | 451 ++++++++++++++++++++++ sysdeps/mips/memset.S | 426 --------------------- sysdeps/mips/memset.c | 178 +++++++++ 4 files changed, 629 insertions(+), 1294 deletions(-) delete mode 100644 sysdeps/mips/memcpy.S create mode 100644 sysdeps/mips/memcpy.c delete mode 100644 sysdeps/mips/memset.S create mode 100644 sysdeps/mips/memset.c -- 2.34.1 diff --git a/sysdeps/mips/memcpy.S b/sysdeps/mips/memcpy.S deleted file mode 100644 index 1b376b6d9c..0000000000 --- a/sysdeps/mips/memcpy.S +++ /dev/null @@ -1,868 +0,0 @@ -/* Copyright (C) 2012-2025 Free Software Foundation, Inc. - This file is part of the GNU C Library. - - The GNU C Library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 2.1 of the License, or (at your option) any later version. - - The GNU C Library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with the GNU C Library. If not, see - . */ - -#ifdef ANDROID_CHANGES -# include "machine/asm.h" -# include "machine/regdef.h" -# define USE_MEMMOVE_FOR_OVERLAP -# define PREFETCH_LOAD_HINT PREFETCH_HINT_LOAD_STREAMED -# define PREFETCH_STORE_HINT PREFETCH_HINT_PREPAREFORSTORE -#elif _LIBC -# include -# include -# include -# define PREFETCH_LOAD_HINT PREFETCH_HINT_LOAD_STREAMED -# define PREFETCH_STORE_HINT PREFETCH_HINT_PREPAREFORSTORE -#elif defined _COMPILING_NEWLIB -# include "machine/asm.h" -# include "machine/regdef.h" -# define PREFETCH_LOAD_HINT PREFETCH_HINT_LOAD_STREAMED -# define PREFETCH_STORE_HINT PREFETCH_HINT_PREPAREFORSTORE -#else -# include -# include -#endif - -#if (_MIPS_ISA == _MIPS_ISA_MIPS4) || (_MIPS_ISA == _MIPS_ISA_MIPS5) || \ - (_MIPS_ISA == _MIPS_ISA_MIPS32) || (_MIPS_ISA == _MIPS_ISA_MIPS64) -# ifndef DISABLE_PREFETCH -# define USE_PREFETCH -# endif -#endif - -#if defined(_MIPS_SIM) && ((_MIPS_SIM == _ABI64) || (_MIPS_SIM == _ABIN32)) -# ifndef DISABLE_DOUBLE -# define USE_DOUBLE -# endif -#endif - -/* Some asm.h files do not have the L macro definition. */ -#ifndef L -# if _MIPS_SIM == _ABIO32 -# define L(label) $L ## label -# else -# define L(label) .L ## label -# endif -#endif - -/* Some asm.h files do not have the PTR_ADDIU macro definition. */ -#ifndef PTR_ADDIU -# ifdef USE_DOUBLE -# define PTR_ADDIU daddiu -# else -# define PTR_ADDIU addiu -# endif -#endif - -/* Some asm.h files do not have the PTR_SRA macro definition. */ -#ifndef PTR_SRA -# ifdef USE_DOUBLE -# define PTR_SRA dsra -# else -# define PTR_SRA sra -# endif -#endif - -/* New R6 instructions that may not be in asm.h. */ -#ifndef PTR_LSA -# if _MIPS_SIM == _ABI64 -# define PTR_LSA dlsa -# else -# define PTR_LSA lsa -# endif -#endif - -/* - * Using PREFETCH_HINT_LOAD_STREAMED instead of PREFETCH_LOAD on load - * prefetches appear to offer a slight performance advantage. - * - * Using PREFETCH_HINT_PREPAREFORSTORE instead of PREFETCH_STORE - * or PREFETCH_STORE_STREAMED offers a large performance advantage - * but PREPAREFORSTORE has some special restrictions to consider. - * - * Prefetch with the 'prepare for store' hint does not copy a memory - * location into the cache, it just allocates a cache line and zeros - * it out. This means that if you do not write to the entire cache - * line before writing it out to memory some data will get zero'ed out - * when the cache line is written back to memory and data will be lost. - * - * Also if you are using this memcpy to copy overlapping buffers it may - * not behave correctly when using the 'prepare for store' hint. If you - * use the 'prepare for store' prefetch on a memory area that is in the - * memcpy source (as well as the memcpy destination), then you will get - * some data zero'ed out before you have a chance to read it and data will - * be lost. - * - * If you are going to use this memcpy routine with the 'prepare for store' - * prefetch you may want to set USE_MEMMOVE_FOR_OVERLAP in order to avoid - * the problem of running memcpy on overlapping buffers. - * - * There are ifdef'ed sections of this memcpy to make sure that it does not - * do prefetches on cache lines that are not going to be completely written. - * This code is only needed and only used when PREFETCH_STORE_HINT is set to - * PREFETCH_HINT_PREPAREFORSTORE. This code assumes that cache lines are - * 32 bytes and if the cache line is larger it will not work correctly. - */ - -#ifdef USE_PREFETCH -# define PREFETCH_HINT_LOAD 0 -# define PREFETCH_HINT_STORE 1 -# define PREFETCH_HINT_LOAD_STREAMED 4 -# define PREFETCH_HINT_STORE_STREAMED 5 -# define PREFETCH_HINT_LOAD_RETAINED 6 -# define PREFETCH_HINT_STORE_RETAINED 7 -# define PREFETCH_HINT_WRITEBACK_INVAL 25 -# define PREFETCH_HINT_PREPAREFORSTORE 30 - -/* - * If we have not picked out what hints to use at this point use the - * standard load and store prefetch hints. - */ -# ifndef PREFETCH_STORE_HINT -# define PREFETCH_STORE_HINT PREFETCH_HINT_STORE -# endif -# ifndef PREFETCH_LOAD_HINT -# define PREFETCH_LOAD_HINT PREFETCH_HINT_LOAD -# endif - -/* - * We double everything when USE_DOUBLE is true so we do 2 prefetches to - * get 64 bytes in that case. The assumption is that each individual - * prefetch brings in 32 bytes. - */ - -# ifdef USE_DOUBLE -# define PREFETCH_CHUNK 64 -# define PREFETCH_FOR_LOAD(chunk, reg) \ - pref PREFETCH_LOAD_HINT, (chunk)*64(reg); \ - pref PREFETCH_LOAD_HINT, ((chunk)*64)+32(reg) -# define PREFETCH_FOR_STORE(chunk, reg) \ - pref PREFETCH_STORE_HINT, (chunk)*64(reg); \ - pref PREFETCH_STORE_HINT, ((chunk)*64)+32(reg) -# else -# define PREFETCH_CHUNK 32 -# define PREFETCH_FOR_LOAD(chunk, reg) \ - pref PREFETCH_LOAD_HINT, (chunk)*32(reg) -# define PREFETCH_FOR_STORE(chunk, reg) \ - pref PREFETCH_STORE_HINT, (chunk)*32(reg) -# endif -/* MAX_PREFETCH_SIZE is the maximum size of a prefetch, it must not be less - * than PREFETCH_CHUNK, the assumed size of each prefetch. If the real size - * of a prefetch is greater than MAX_PREFETCH_SIZE and the PREPAREFORSTORE - * hint is used, the code will not work correctly. If PREPAREFORSTORE is not - * used then MAX_PREFETCH_SIZE does not matter. */ -# define MAX_PREFETCH_SIZE 128 -/* PREFETCH_LIMIT is set based on the fact that we never use an offset greater - * than 5 on a STORE prefetch and that a single prefetch can never be larger - * than MAX_PREFETCH_SIZE. We add the extra 32 when USE_DOUBLE is set because - * we actually do two prefetches in that case, one 32 bytes after the other. */ -# ifdef USE_DOUBLE -# define PREFETCH_LIMIT (5 * PREFETCH_CHUNK) + 32 + MAX_PREFETCH_SIZE -# else -# define PREFETCH_LIMIT (5 * PREFETCH_CHUNK) + MAX_PREFETCH_SIZE -# endif -# if (PREFETCH_STORE_HINT == PREFETCH_HINT_PREPAREFORSTORE) \ - && ((PREFETCH_CHUNK * 4) < MAX_PREFETCH_SIZE) -/* We cannot handle this because the initial prefetches may fetch bytes that - * are before the buffer being copied. We start copies with an offset - * of 4 so avoid this situation when using PREPAREFORSTORE. */ -#error "PREFETCH_CHUNK is too large and/or MAX_PREFETCH_SIZE is too small." -# endif -#else /* USE_PREFETCH not defined */ -# define PREFETCH_FOR_LOAD(offset, reg) -# define PREFETCH_FOR_STORE(offset, reg) -#endif - -#if __mips_isa_rev > 5 -# if (PREFETCH_STORE_HINT == PREFETCH_HINT_PREPAREFORSTORE) -# undef PREFETCH_STORE_HINT -# define PREFETCH_STORE_HINT PREFETCH_HINT_STORE_STREAMED -# endif -# define R6_CODE -#endif - -/* Allow the routine to be named something else if desired. */ -#ifndef MEMCPY_NAME -# define MEMCPY_NAME memcpy -#endif - -/* We use these 32/64 bit registers as temporaries to do the copying. */ -#define REG0 t0 -#define REG1 t1 -#define REG2 t2 -#define REG3 t3 -#if defined(_MIPS_SIM) && ((_MIPS_SIM == _ABIO32) || (_MIPS_SIM == _ABIO64)) -# define REG4 t4 -# define REG5 t5 -# define REG6 t6 -# define REG7 t7 -#else -# define REG4 ta0 -# define REG5 ta1 -# define REG6 ta2 -# define REG7 ta3 -#endif - -/* We load/store 64 bits at a time when USE_DOUBLE is true. - * The C_ prefix stands for CHUNK and is used to avoid macro name - * conflicts with system header files. */ - -#ifdef USE_DOUBLE -# define C_ST sd -# define C_LD ld -# ifdef __MIPSEB -# define C_LDHI ldl /* high part is left in big-endian */ -# define C_STHI sdl /* high part is left in big-endian */ -# define C_LDLO ldr /* low part is right in big-endian */ -# define C_STLO sdr /* low part is right in big-endian */ -# else -# define C_LDHI ldr /* high part is right in little-endian */ -# define C_STHI sdr /* high part is right in little-endian */ -# define C_LDLO ldl /* low part is left in little-endian */ -# define C_STLO sdl /* low part is left in little-endian */ -# endif -# define C_ALIGN dalign /* r6 align instruction */ -#else -# define C_ST sw -# define C_LD lw -# ifdef __MIPSEB -# define C_LDHI lwl /* high part is left in big-endian */ -# define C_STHI swl /* high part is left in big-endian */ -# define C_LDLO lwr /* low part is right in big-endian */ -# define C_STLO swr /* low part is right in big-endian */ -# else -# define C_LDHI lwr /* high part is right in little-endian */ -# define C_STHI swr /* high part is right in little-endian */ -# define C_LDLO lwl /* low part is left in little-endian */ -# define C_STLO swl /* low part is left in little-endian */ -# endif -# define C_ALIGN align /* r6 align instruction */ -#endif - -/* Bookkeeping values for 32 vs. 64 bit mode. */ -#ifdef USE_DOUBLE -# define NSIZE 8 -# define NSIZEMASK 0x3f -# define NSIZEDMASK 0x7f -#else -# define NSIZE 4 -# define NSIZEMASK 0x1f -# define NSIZEDMASK 0x3f -#endif -#define UNIT(unit) ((unit)*NSIZE) -#define UNITM1(unit) (((unit)*NSIZE)-1) - -#ifdef ANDROID_CHANGES -LEAF(MEMCPY_NAME, 0) -#else -LEAF(MEMCPY_NAME) -#endif - .set nomips16 - .set noreorder -/* - * Below we handle the case where memcpy is called with overlapping src and dst. - * Although memcpy is not required to handle this case, some parts of Android - * like Skia rely on such usage. We call memmove to handle such cases. - */ -#ifdef USE_MEMMOVE_FOR_OVERLAP - PTR_SUBU t0,a0,a1 - PTR_SRA t2,t0,31 - xor t1,t0,t2 - PTR_SUBU t0,t1,t2 - sltu t2,t0,a2 - beq t2,zero,L(memcpy) - la t9,memmove - jr t9 - nop -L(memcpy): -#endif -/* - * If the size is less than 2*NSIZE (8 or 16), go to L(lastb). Regardless of - * size, copy dst pointer to v0 for the return value. - */ - slti t2,a2,(2 * NSIZE) - bne t2,zero,L(lasts) -#if defined(RETURN_FIRST_PREFETCH) || defined(RETURN_LAST_PREFETCH) - move v0,zero -#else - move v0,a0 -#endif - -#ifndef R6_CODE - -/* - * If src and dst have different alignments, go to L(unaligned), if they - * have the same alignment (but are not actually aligned) do a partial - * load/store to make them aligned. If they are both already aligned - * we can start copying at L(aligned). - */ - xor t8,a1,a0 - andi t8,t8,(NSIZE-1) /* t8 is a0/a1 word-displacement */ - bne t8,zero,L(unaligned) - PTR_SUBU a3, zero, a0 - - andi a3,a3,(NSIZE-1) /* copy a3 bytes to align a0/a1 */ - beq a3,zero,L(aligned) /* if a3=0, it is already aligned */ - PTR_SUBU a2,a2,a3 /* a2 is the remaining bytes count */ - - C_LDHI t8,0(a1) - PTR_ADDU a1,a1,a3 - C_STHI t8,0(a0) - PTR_ADDU a0,a0,a3 - -#else /* R6_CODE */ - -/* - * Align the destination and hope that the source gets aligned too. If it - * doesn't we jump to L(r6_unaligned*) to do unaligned copies using the r6 - * align instruction. - */ - andi t8,a0,7 - lapc t9,L(atable) - PTR_LSA t9,t8,t9,2 - jrc t9 -L(atable): - bc L(lb0) - bc L(lb7) - bc L(lb6) - bc L(lb5) - bc L(lb4) - bc L(lb3) - bc L(lb2) - bc L(lb1) -L(lb7): - lb a3, 6(a1) - sb a3, 6(a0) -L(lb6): - lb a3, 5(a1) - sb a3, 5(a0) -L(lb5): - lb a3, 4(a1) - sb a3, 4(a0) -L(lb4): - lb a3, 3(a1) - sb a3, 3(a0) -L(lb3): - lb a3, 2(a1) - sb a3, 2(a0) -L(lb2): - lb a3, 1(a1) - sb a3, 1(a0) -L(lb1): - lb a3, 0(a1) - sb a3, 0(a0) - - li t9,8 - subu t8,t9,t8 - PTR_SUBU a2,a2,t8 - PTR_ADDU a0,a0,t8 - PTR_ADDU a1,a1,t8 -L(lb0): - - andi t8,a1,(NSIZE-1) - lapc t9,L(jtable) - PTR_LSA t9,t8,t9,2 - jrc t9 -L(jtable): - bc L(aligned) - bc L(r6_unaligned1) - bc L(r6_unaligned2) - bc L(r6_unaligned3) -# ifdef USE_DOUBLE - bc L(r6_unaligned4) - bc L(r6_unaligned5) - bc L(r6_unaligned6) - bc L(r6_unaligned7) -# endif -#endif /* R6_CODE */ - -L(aligned): - -/* - * Now dst/src are both aligned to (word or double word) aligned addresses - * Set a2 to count how many bytes we have to copy after all the 64/128 byte - * chunks are copied and a3 to the dst pointer after all the 64/128 byte - * chunks have been copied. We will loop, incrementing a0 and a1 until a0 - * equals a3. - */ - - andi t8,a2,NSIZEDMASK /* any whole 64-byte/128-byte chunks? */ - beq a2,t8,L(chkw) /* if a2==t8, no 64-byte/128-byte chunks */ - PTR_SUBU a3,a2,t8 /* subtract from a2 the reminder */ - PTR_ADDU a3,a0,a3 /* Now a3 is the final dst after loop */ - -/* When in the loop we may prefetch with the 'prepare to store' hint, - * in this case the a0+x should not be past the "t0-32" address. This - * means: for x=128 the last "safe" a0 address is "t0-160". Alternatively, - * for x=64 the last "safe" a0 address is "t0-96" In the current version we - * will use "prefetch hint,128(a0)", so "t0-160" is the limit. - */ -#if defined(USE_PREFETCH) && (PREFETCH_STORE_HINT == PREFETCH_HINT_PREPAREFORSTORE) - PTR_ADDU t0,a0,a2 /* t0 is the "past the end" address */ - PTR_SUBU t9,t0,PREFETCH_LIMIT /* t9 is the "last safe pref" address */ -#endif - PREFETCH_FOR_LOAD (0, a1) - PREFETCH_FOR_LOAD (1, a1) - PREFETCH_FOR_LOAD (2, a1) - PREFETCH_FOR_LOAD (3, a1) -#if defined(USE_PREFETCH) && (PREFETCH_STORE_HINT != PREFETCH_HINT_PREPAREFORSTORE) - PREFETCH_FOR_STORE (1, a0) - PREFETCH_FOR_STORE (2, a0) - PREFETCH_FOR_STORE (3, a0) -#endif -#if defined(RETURN_FIRST_PREFETCH) && defined(USE_PREFETCH) -# if PREFETCH_STORE_HINT == PREFETCH_HINT_PREPAREFORSTORE - sltu v1,t9,a0 - bgtz v1,L(skip_set) - nop - PTR_ADDIU v0,a0,(PREFETCH_CHUNK*4) -L(skip_set): -# else - PTR_ADDIU v0,a0,(PREFETCH_CHUNK*1) -# endif -#endif -#if defined(RETURN_LAST_PREFETCH) && defined(USE_PREFETCH) \ - && (PREFETCH_STORE_HINT != PREFETCH_HINT_PREPAREFORSTORE) - PTR_ADDIU v0,a0,(PREFETCH_CHUNK*3) -# ifdef USE_DOUBLE - PTR_ADDIU v0,v0,32 -# endif -#endif -L(loop16w): - C_LD t0,UNIT(0)(a1) -#if defined(USE_PREFETCH) && (PREFETCH_STORE_HINT == PREFETCH_HINT_PREPAREFORSTORE) - sltu v1,t9,a0 /* If a0 > t9 don't use next prefetch */ - bgtz v1,L(skip_pref) -#endif - C_LD t1,UNIT(1)(a1) -#ifdef R6_CODE - PREFETCH_FOR_STORE (2, a0) -#else - PREFETCH_FOR_STORE (4, a0) - PREFETCH_FOR_STORE (5, a0) -#endif -#if defined(RETURN_LAST_PREFETCH) && defined(USE_PREFETCH) - PTR_ADDIU v0,a0,(PREFETCH_CHUNK*5) -# ifdef USE_DOUBLE - PTR_ADDIU v0,v0,32 -# endif -#endif -L(skip_pref): - C_LD REG2,UNIT(2)(a1) - C_LD REG3,UNIT(3)(a1) - C_LD REG4,UNIT(4)(a1) - C_LD REG5,UNIT(5)(a1) - C_LD REG6,UNIT(6)(a1) - C_LD REG7,UNIT(7)(a1) -#ifdef R6_CODE - PREFETCH_FOR_LOAD (3, a1) -#else - PREFETCH_FOR_LOAD (4, a1) -#endif - C_ST t0,UNIT(0)(a0) - C_ST t1,UNIT(1)(a0) - C_ST REG2,UNIT(2)(a0) - C_ST REG3,UNIT(3)(a0) - C_ST REG4,UNIT(4)(a0) - C_ST REG5,UNIT(5)(a0) - C_ST REG6,UNIT(6)(a0) - C_ST REG7,UNIT(7)(a0) - - C_LD t0,UNIT(8)(a1) - C_LD t1,UNIT(9)(a1) - C_LD REG2,UNIT(10)(a1) - C_LD REG3,UNIT(11)(a1) - C_LD REG4,UNIT(12)(a1) - C_LD REG5,UNIT(13)(a1) - C_LD REG6,UNIT(14)(a1) - C_LD REG7,UNIT(15)(a1) -#ifndef R6_CODE - PREFETCH_FOR_LOAD (5, a1) -#endif - C_ST t0,UNIT(8)(a0) - C_ST t1,UNIT(9)(a0) - C_ST REG2,UNIT(10)(a0) - C_ST REG3,UNIT(11)(a0) - C_ST REG4,UNIT(12)(a0) - C_ST REG5,UNIT(13)(a0) - C_ST REG6,UNIT(14)(a0) - C_ST REG7,UNIT(15)(a0) - PTR_ADDIU a0,a0,UNIT(16) /* adding 64/128 to dest */ - bne a0,a3,L(loop16w) - PTR_ADDIU a1,a1,UNIT(16) /* adding 64/128 to src */ - move a2,t8 - -/* Here we have src and dest word-aligned but less than 64-bytes or - * 128 bytes to go. Check for a 32(64) byte chunk and copy if there - * is one. Otherwise jump down to L(chk1w) to handle the tail end of - * the copy. - */ - -L(chkw): - PREFETCH_FOR_LOAD (0, a1) - andi t8,a2,NSIZEMASK /* Is there a 32-byte/64-byte chunk. */ - /* The t8 is the reminder count past 32-bytes */ - beq a2,t8,L(chk1w) /* When a2=t8, no 32-byte chunk */ - nop - C_LD t0,UNIT(0)(a1) - C_LD t1,UNIT(1)(a1) - C_LD REG2,UNIT(2)(a1) - C_LD REG3,UNIT(3)(a1) - C_LD REG4,UNIT(4)(a1) - C_LD REG5,UNIT(5)(a1) - C_LD REG6,UNIT(6)(a1) - C_LD REG7,UNIT(7)(a1) - PTR_ADDIU a1,a1,UNIT(8) - C_ST t0,UNIT(0)(a0) - C_ST t1,UNIT(1)(a0) - C_ST REG2,UNIT(2)(a0) - C_ST REG3,UNIT(3)(a0) - C_ST REG4,UNIT(4)(a0) - C_ST REG5,UNIT(5)(a0) - C_ST REG6,UNIT(6)(a0) - C_ST REG7,UNIT(7)(a0) - PTR_ADDIU a0,a0,UNIT(8) - -/* - * Here we have less than 32(64) bytes to copy. Set up for a loop to - * copy one word (or double word) at a time. Set a2 to count how many - * bytes we have to copy after all the word (or double word) chunks are - * copied and a3 to the dst pointer after all the (d)word chunks have - * been copied. We will loop, incrementing a0 and a1 until a0 equals a3. - */ -L(chk1w): - andi a2,t8,(NSIZE-1) /* a2 is the reminder past one (d)word chunks */ - beq a2,t8,L(lastw) - PTR_SUBU a3,t8,a2 /* a3 is count of bytes in one (d)word chunks */ - PTR_ADDU a3,a0,a3 /* a3 is the dst address after loop */ - -/* copying in words (4-byte or 8-byte chunks) */ -L(wordCopy_loop): - C_LD REG3,UNIT(0)(a1) - PTR_ADDIU a0,a0,UNIT(1) - PTR_ADDIU a1,a1,UNIT(1) - bne a0,a3,L(wordCopy_loop) - C_ST REG3,UNIT(-1)(a0) - -/* If we have been copying double words, see if we can copy a single word - before doing byte copies. We can have, at most, one word to copy. */ - -L(lastw): -#ifdef USE_DOUBLE - andi t8,a2,3 /* a2 is the remainder past 4 byte chunks. */ - beq t8,a2,L(lastb) - move a2,t8 - lw REG3,0(a1) - sw REG3,0(a0) - PTR_ADDIU a0,a0,4 - PTR_ADDIU a1,a1,4 -#endif - -/* Copy the last 8 (or 16) bytes */ -L(lastb): - blez a2,L(leave) - PTR_ADDU a3,a0,a2 /* a3 is the last dst address */ -L(lastbloop): - lb v1,0(a1) - PTR_ADDIU a0,a0,1 - PTR_ADDIU a1,a1,1 - bne a0,a3,L(lastbloop) - sb v1,-1(a0) -L(leave): - j ra - nop - -/* We jump here with a memcpy of less than 8 or 16 bytes, depending on - whether or not USE_DOUBLE is defined. Instead of just doing byte - copies, check the alignment and size and use lw/sw if possible. - Otherwise, do byte copies. */ - -L(lasts): - andi t8,a2,3 - beq t8,a2,L(lastb) - - andi t9,a0,3 - bne t9,zero,L(lastb) - andi t9,a1,3 - bne t9,zero,L(lastb) - - PTR_SUBU a3,a2,t8 - PTR_ADDU a3,a0,a3 - -L(wcopy_loop): - lw REG3,0(a1) - PTR_ADDIU a0,a0,4 - PTR_ADDIU a1,a1,4 - bne a0,a3,L(wcopy_loop) - sw REG3,-4(a0) - - b L(lastb) - move a2,t8 - -#ifndef R6_CODE -/* - * UNALIGNED case, got here with a3 = "negu a0" - * This code is nearly identical to the aligned code above - * but only the destination (not the source) gets aligned - * so we need to do partial loads of the source followed - * by normal stores to the destination (once we have aligned - * the destination). - */ - -L(unaligned): - andi a3,a3,(NSIZE-1) /* copy a3 bytes to align a0/a1 */ - beqz a3,L(ua_chk16w) /* if a3=0, it is already aligned */ - PTR_SUBU a2,a2,a3 /* a2 is the remaining bytes count */ - - C_LDHI v1,UNIT(0)(a1) - C_LDLO v1,UNITM1(1)(a1) - PTR_ADDU a1,a1,a3 - C_STHI v1,UNIT(0)(a0) - PTR_ADDU a0,a0,a3 - -/* - * Now the destination (but not the source) is aligned - * Set a2 to count how many bytes we have to copy after all the 64/128 byte - * chunks are copied and a3 to the dst pointer after all the 64/128 byte - * chunks have been copied. We will loop, incrementing a0 and a1 until a0 - * equals a3. - */ - -L(ua_chk16w): - andi t8,a2,NSIZEDMASK /* any whole 64-byte/128-byte chunks? */ - beq a2,t8,L(ua_chkw) /* if a2==t8, no 64-byte/128-byte chunks */ - PTR_SUBU a3,a2,t8 /* subtract from a2 the reminder */ - PTR_ADDU a3,a0,a3 /* Now a3 is the final dst after loop */ - -# if defined(USE_PREFETCH) && (PREFETCH_STORE_HINT == PREFETCH_HINT_PREPAREFORSTORE) - PTR_ADDU t0,a0,a2 /* t0 is the "past the end" address */ - PTR_SUBU t9,t0,PREFETCH_LIMIT /* t9 is the "last safe pref" address */ -# endif - PREFETCH_FOR_LOAD (0, a1) - PREFETCH_FOR_LOAD (1, a1) - PREFETCH_FOR_LOAD (2, a1) -# if defined(USE_PREFETCH) && (PREFETCH_STORE_HINT != PREFETCH_HINT_PREPAREFORSTORE) - PREFETCH_FOR_STORE (1, a0) - PREFETCH_FOR_STORE (2, a0) - PREFETCH_FOR_STORE (3, a0) -# endif -# if defined(RETURN_FIRST_PREFETCH) && defined(USE_PREFETCH) -# if (PREFETCH_STORE_HINT == PREFETCH_HINT_PREPAREFORSTORE) - sltu v1,t9,a0 - bgtz v1,L(ua_skip_set) - nop - PTR_ADDIU v0,a0,(PREFETCH_CHUNK*4) -L(ua_skip_set): -# else - PTR_ADDIU v0,a0,(PREFETCH_CHUNK*1) -# endif -# endif -L(ua_loop16w): - PREFETCH_FOR_LOAD (3, a1) - C_LDHI t0,UNIT(0)(a1) - C_LDHI t1,UNIT(1)(a1) - C_LDHI REG2,UNIT(2)(a1) -# if defined(USE_PREFETCH) && (PREFETCH_STORE_HINT == PREFETCH_HINT_PREPAREFORSTORE) - sltu v1,t9,a0 - bgtz v1,L(ua_skip_pref) -# endif - C_LDHI REG3,UNIT(3)(a1) - PREFETCH_FOR_STORE (4, a0) - PREFETCH_FOR_STORE (5, a0) -L(ua_skip_pref): - C_LDHI REG4,UNIT(4)(a1) - C_LDHI REG5,UNIT(5)(a1) - C_LDHI REG6,UNIT(6)(a1) - C_LDHI REG7,UNIT(7)(a1) - C_LDLO t0,UNITM1(1)(a1) - C_LDLO t1,UNITM1(2)(a1) - C_LDLO REG2,UNITM1(3)(a1) - C_LDLO REG3,UNITM1(4)(a1) - C_LDLO REG4,UNITM1(5)(a1) - C_LDLO REG5,UNITM1(6)(a1) - C_LDLO REG6,UNITM1(7)(a1) - C_LDLO REG7,UNITM1(8)(a1) - PREFETCH_FOR_LOAD (4, a1) - C_ST t0,UNIT(0)(a0) - C_ST t1,UNIT(1)(a0) - C_ST REG2,UNIT(2)(a0) - C_ST REG3,UNIT(3)(a0) - C_ST REG4,UNIT(4)(a0) - C_ST REG5,UNIT(5)(a0) - C_ST REG6,UNIT(6)(a0) - C_ST REG7,UNIT(7)(a0) - C_LDHI t0,UNIT(8)(a1) - C_LDHI t1,UNIT(9)(a1) - C_LDHI REG2,UNIT(10)(a1) - C_LDHI REG3,UNIT(11)(a1) - C_LDHI REG4,UNIT(12)(a1) - C_LDHI REG5,UNIT(13)(a1) - C_LDHI REG6,UNIT(14)(a1) - C_LDHI REG7,UNIT(15)(a1) - C_LDLO t0,UNITM1(9)(a1) - C_LDLO t1,UNITM1(10)(a1) - C_LDLO REG2,UNITM1(11)(a1) - C_LDLO REG3,UNITM1(12)(a1) - C_LDLO REG4,UNITM1(13)(a1) - C_LDLO REG5,UNITM1(14)(a1) - C_LDLO REG6,UNITM1(15)(a1) - C_LDLO REG7,UNITM1(16)(a1) - PREFETCH_FOR_LOAD (5, a1) - C_ST t0,UNIT(8)(a0) - C_ST t1,UNIT(9)(a0) - C_ST REG2,UNIT(10)(a0) - C_ST REG3,UNIT(11)(a0) - C_ST REG4,UNIT(12)(a0) - C_ST REG5,UNIT(13)(a0) - C_ST REG6,UNIT(14)(a0) - C_ST REG7,UNIT(15)(a0) - PTR_ADDIU a0,a0,UNIT(16) /* adding 64/128 to dest */ - bne a0,a3,L(ua_loop16w) - PTR_ADDIU a1,a1,UNIT(16) /* adding 64/128 to src */ - move a2,t8 - -/* Here we have src and dest word-aligned but less than 64-bytes or - * 128 bytes to go. Check for a 32(64) byte chunk and copy if there - * is one. Otherwise jump down to L(ua_chk1w) to handle the tail end of - * the copy. */ - -L(ua_chkw): - PREFETCH_FOR_LOAD (0, a1) - andi t8,a2,NSIZEMASK /* Is there a 32-byte/64-byte chunk. */ - /* t8 is the reminder count past 32-bytes */ - beq a2,t8,L(ua_chk1w) /* When a2=t8, no 32-byte chunk */ - nop - C_LDHI t0,UNIT(0)(a1) - C_LDHI t1,UNIT(1)(a1) - C_LDHI REG2,UNIT(2)(a1) - C_LDHI REG3,UNIT(3)(a1) - C_LDHI REG4,UNIT(4)(a1) - C_LDHI REG5,UNIT(5)(a1) - C_LDHI REG6,UNIT(6)(a1) - C_LDHI REG7,UNIT(7)(a1) - C_LDLO t0,UNITM1(1)(a1) - C_LDLO t1,UNITM1(2)(a1) - C_LDLO REG2,UNITM1(3)(a1) - C_LDLO REG3,UNITM1(4)(a1) - C_LDLO REG4,UNITM1(5)(a1) - C_LDLO REG5,UNITM1(6)(a1) - C_LDLO REG6,UNITM1(7)(a1) - C_LDLO REG7,UNITM1(8)(a1) - PTR_ADDIU a1,a1,UNIT(8) - C_ST t0,UNIT(0)(a0) - C_ST t1,UNIT(1)(a0) - C_ST REG2,UNIT(2)(a0) - C_ST REG3,UNIT(3)(a0) - C_ST REG4,UNIT(4)(a0) - C_ST REG5,UNIT(5)(a0) - C_ST REG6,UNIT(6)(a0) - C_ST REG7,UNIT(7)(a0) - PTR_ADDIU a0,a0,UNIT(8) -/* - * Here we have less than 32(64) bytes to copy. Set up for a loop to - * copy one word (or double word) at a time. - */ -L(ua_chk1w): - andi a2,t8,(NSIZE-1) /* a2 is the reminder past one (d)word chunks */ - beq a2,t8,L(ua_smallCopy) - PTR_SUBU a3,t8,a2 /* a3 is count of bytes in one (d)word chunks */ - PTR_ADDU a3,a0,a3 /* a3 is the dst address after loop */ - -/* copying in words (4-byte or 8-byte chunks) */ -L(ua_wordCopy_loop): - C_LDHI v1,UNIT(0)(a1) - C_LDLO v1,UNITM1(1)(a1) - PTR_ADDIU a0,a0,UNIT(1) - PTR_ADDIU a1,a1,UNIT(1) - bne a0,a3,L(ua_wordCopy_loop) - C_ST v1,UNIT(-1)(a0) - -/* Copy the last 8 (or 16) bytes */ -L(ua_smallCopy): - beqz a2,L(leave) - PTR_ADDU a3,a0,a2 /* a3 is the last dst address */ -L(ua_smallCopy_loop): - lb v1,0(a1) - PTR_ADDIU a0,a0,1 - PTR_ADDIU a1,a1,1 - bne a0,a3,L(ua_smallCopy_loop) - sb v1,-1(a0) - - j ra - nop - -#else /* R6_CODE */ - -# ifdef __MIPSEB -# define SWAP_REGS(X,Y) X, Y -# define ALIGN_OFFSET(N) (N) -# else -# define SWAP_REGS(X,Y) Y, X -# define ALIGN_OFFSET(N) (NSIZE-N) -# endif -# define R6_UNALIGNED_WORD_COPY(BYTEOFFSET) \ - andi REG7, a2, (NSIZE-1);/* REG7 is # of bytes to by bytes. */ \ - beq REG7, a2, L(lastb); /* Check for bytes to copy by word */ \ - PTR_SUBU a3, a2, REG7; /* a3 is number of bytes to be copied in */ \ - /* (d)word chunks. */ \ - move a2, REG7; /* a2 is # of bytes to copy byte by byte */ \ - /* after word loop is finished. */ \ - PTR_ADDU REG6, a0, a3; /* REG6 is the dst address after loop. */ \ - PTR_SUBU REG2, a1, t8; /* REG2 is the aligned src address. */ \ - PTR_ADDU a1, a1, a3; /* a1 is addr of source after word loop. */ \ - C_LD t0, UNIT(0)(REG2); /* Load first part of source. */ \ -L(r6_ua_wordcopy##BYTEOFFSET): \ - C_LD t1, UNIT(1)(REG2); /* Load second part of source. */ \ - C_ALIGN REG3, SWAP_REGS(t1,t0), ALIGN_OFFSET(BYTEOFFSET); \ - PTR_ADDIU a0, a0, UNIT(1); /* Increment destination pointer. */ \ - PTR_ADDIU REG2, REG2, UNIT(1); /* Increment aligned source pointer.*/ \ - move t0, t1; /* Move second part of source to first. */ \ - bne a0, REG6,L(r6_ua_wordcopy##BYTEOFFSET); \ - C_ST REG3, UNIT(-1)(a0); \ - j L(lastb); \ - nop - - /* We are generating R6 code, the destination is 4 byte aligned and - the source is not 4 byte aligned. t8 is 1, 2, or 3 depending on the - alignment of the source. */ - -L(r6_unaligned1): - R6_UNALIGNED_WORD_COPY(1) -L(r6_unaligned2): - R6_UNALIGNED_WORD_COPY(2) -L(r6_unaligned3): - R6_UNALIGNED_WORD_COPY(3) -# ifdef USE_DOUBLE -L(r6_unaligned4): - R6_UNALIGNED_WORD_COPY(4) -L(r6_unaligned5): - R6_UNALIGNED_WORD_COPY(5) -L(r6_unaligned6): - R6_UNALIGNED_WORD_COPY(6) -L(r6_unaligned7): - R6_UNALIGNED_WORD_COPY(7) -# endif -#endif /* R6_CODE */ - - .set at - .set reorder -END(MEMCPY_NAME) -#ifndef ANDROID_CHANGES -# ifdef _LIBC -libc_hidden_builtin_def (MEMCPY_NAME) -# endif -#endif diff --git a/sysdeps/mips/memcpy.c b/sysdeps/mips/memcpy.c new file mode 100644 index 0000000000..19969c61f7 --- /dev/null +++ b/sysdeps/mips/memcpy.c @@ -0,0 +1,451 @@ +/* Contributed by Wave Computing + Copyright (C) 2025 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library. If not, see + . */ + +#ifdef __GNUC__ + +#undef memcpy + +#include + +/* Typical observed latency in cycles in fetching from DRAM. */ +#ifndef LATENCY_CYCLES + #define LATENCY_CYCLES 63 +#endif + +/* Pre-fetch performance is subject to accurate prefetch ahead, + which in turn depends on both the cache-line size and the amount + of look-ahead. Since cache-line size is not nominally fixed in + a typically library built for multiple platforms, we make conservative + assumptions in the default case. This code will typically operate + on such conservative assumptions, but if compiled with the correct + -mtune=xx options, will perform even better on those specific + platforms. */ +#if defined(_MIPS_TUNE_OCTEON2) || defined(_MIPS_TUNE_OCTEON3) + #define CACHE_LINE 128 + #define BLOCK_CYCLES 30 + #undef LATENCY_CYCLES + #define LATENCY_CYCLES 150 +#elif defined(_MIPS_TUNE_I6400) || defined(_MIPS_TUNE_I6500) + #define CACHE_LINE 64 + #define BLOCK_CYCLES 15 +#elif defined(_MIPS_TUNE_P6600) + #define CACHE_LINE 32 + #define BLOCK_CYCLES 15 +#elif defined(_MIPS_TUNE_INTERAPTIV) || defined(_MIPS_TUNE_INTERAPTIV_MR2) + #define CACHE_LINE 32 + #define BLOCK_CYCLES 30 +#else + #ifndef CACHE_LINE + #define CACHE_LINE 32 + #endif + #ifndef BLOCK_CYCLES + #ifdef __nanomips__ + #define BLOCK_CYCLES 20 + #else + #define BLOCK_CYCLES 11 + #endif + #endif +#endif + +/* Pre-fetch look ahead = ceil (latency / block-cycles) */ +#define PREF_AHEAD (LATENCY_CYCLES / BLOCK_CYCLES \ + + ((LATENCY_CYCLES % BLOCK_CYCLES) == 0 ? 0 : 1)) + +/* The unroll-factor controls how many words at a time in the core loop. */ +#ifndef BLOCK_SIZE + #define BLOCK_SIZE (CACHE_LINE == 128 ? 16 : 8) +#elif BLOCK_SIZE != 8 && BLOCK_SIZE != 16 + #error "BLOCK_SIZE must be 8 or 16" +#endif + +#define __overloadable +#if !defined(UNALIGNED_INSTR_SUPPORT) +/* does target have unaligned lw/ld/ualw/uald instructions? */ + #define UNALIGNED_INSTR_SUPPORT 0 +#if (__mips_isa_rev < 6 && !defined(__mips1)) || defined(__nanomips__) + #undef UNALIGNED_INSTR_SUPPORT + #define UNALIGNED_INSTR_SUPPORT 1 + #endif +#endif +#if !defined(HW_UNALIGNED_SUPPORT) +/* Does target have hardware support for unaligned accesses? */ + #define HW_UNALIGNED_SUPPORT 0 + #if __mips_isa_rev >= 6 && !defined(__nanomips__) + #undef HW_UNALIGNED_SUPPORT + #define HW_UNALIGNED_SUPPORT 1 + #endif +#endif + +#ifndef ENABLE_PREFETCH + #define ENABLE_PREFETCH 1 +#endif + +#ifndef ENABLE_PREFETCH_CHECK + #define ENABLE_PREFETCH_CHECK 0 +#endif + +#if ENABLE_PREFETCH + #if ENABLE_PREFETCH_CHECK +#include +static char *limit; +#define PREFETCH(addr) \ + do { \ + assert ((char *)(addr) < limit); \ + __builtin_prefetch ((addr), 0, 1); \ + } while (0) +#else /* ENABLE_PREFETCH_CHECK */ + #define PREFETCH(addr) __builtin_prefetch (addr, 0, 1) + #endif /* ENABLE_PREFETCH_CHECK */ +#else /* ENABLE_PREFETCH */ + #define PREFETCH(addr) +#endif /* ENABLE_PREFETCH */ + +#include + +#ifdef __mips64 +typedef unsigned long long reg_t; +typedef struct +{ + reg_t B0:8, B1:8, B2:8, B3:8, B4:8, B5:8, B6:8, B7:8; +} bits_t; +#else /* __mips64 */ +typedef unsigned long reg_t; +typedef struct +{ + reg_t B0:8, B1:8, B2:8, B3:8; +} bits_t; +#endif /* __mips64 */ + +#define CACHE_LINES_PER_BLOCK \ + ((BLOCK_SIZE * sizeof (reg_t) > CACHE_LINE) \ + ? (BLOCK_SIZE * sizeof (reg_t) / CACHE_LINE) \ + : 1) + +typedef union +{ + reg_t v; + bits_t b; +} bitfields_t; + +#define DO_BYTE(a, i) \ + a[i] = bw.b.B##i; \ + len--; \ + if (!len) return ret; \ + +/* This code is called when aligning a pointer, there are remaining bytes + after doing word compares, or architecture does not have some form + of unaligned support. */ +static inline void * __attribute__ ((always_inline)) +do_bytes (void *a, const void *b, unsigned long len, void *ret) +{ + unsigned char *x = (unsigned char *) a; + unsigned char *y = (unsigned char *) b; + unsigned long i; + /* 'len' might be zero here, so preloading the first two values + before the loop may access unallocated memory. */ + for (i = 0; i < len; i++) + { + *x = *y; + x++; + y++; + } + return ret; +} + +/* This code is called to copy only remaining bytes within word or doubleword */ +static inline void * __attribute__ ((always_inline)) +do_bytes_remaining (void *a, const void *b, unsigned long len, void *ret) +{ + unsigned char *x = (unsigned char *) a; + bitfields_t bw; + if (len > 0) + { + bw.v = *(reg_t *)b; + DO_BYTE(x, 0); + DO_BYTE(x, 1); + DO_BYTE(x, 2); +#ifdef __mips64 + DO_BYTE(x, 3); + DO_BYTE(x, 4); + DO_BYTE(x, 5); + DO_BYTE(x, 6); +#endif /* __mips64 */ + } + return ret; +} + +static inline void * __attribute__ ((always_inline)) +do_words_remaining (reg_t *a, const reg_t *b, unsigned long words, + unsigned long bytes, void *ret) +{ + /* Use a set-back so that load/stores have incremented addresses in + order to promote bonding. */ + int off = (BLOCK_SIZE - words); + a -= off; + b -= off; + switch (off) + { + case 1: a[1] = b[1]; // Fall through + case 2: a[2] = b[2]; // Fall through + case 3: a[3] = b[3]; // Fall through + case 4: a[4] = b[4]; // Fall through + case 5: a[5] = b[5]; // Fall through + case 6: a[6] = b[6]; // Fall through + case 7: a[7] = b[7]; // Fall through +#if BLOCK_SIZE==16 + case 8: a[8] = b[8]; // Fall through + case 9: a[9] = b[9]; // Fall through + case 10: a[10] = b[10]; // Fall through + case 11: a[11] = b[11]; // Fall through + case 12: a[12] = b[12]; // Fall through + case 13: a[13] = b[13]; // Fall through + case 14: a[14] = b[14]; // Fall through + case 15: a[15] = b[15]; +#endif /* BLOCK_SIZE==16 */ + } + return do_bytes_remaining (a + BLOCK_SIZE, b + BLOCK_SIZE, bytes, ret); +} + +#if !HW_UNALIGNED_SUPPORT +#if UNALIGNED_INSTR_SUPPORT +/* For MIPS GCC, there are no unaligned builtins - so this struct forces + the compiler to treat the pointer access as unaligned. */ +struct ulw +{ + reg_t uli; +} __attribute__ ((packed)); +static inline void * __attribute__ ((always_inline)) +do_uwords_remaining (struct ulw *a, const reg_t *b, unsigned long words, + unsigned long bytes, void *ret) +{ + /* Use a set-back so that load/stores have incremented addresses in + order to promote bonding. */ + int off = (BLOCK_SIZE - words); + a -= off; + b -= off; + switch (off) + { + case 1: a[1].uli = b[1]; // Fall through + case 2: a[2].uli = b[2]; // Fall through + case 3: a[3].uli = b[3]; // Fall through + case 4: a[4].uli = b[4]; // Fall through + case 5: a[5].uli = b[5]; // Fall through + case 6: a[6].uli = b[6]; // Fall through + case 7: a[7].uli = b[7]; // Fall through +#if BLOCK_SIZE==16 + case 8: a[8].uli = b[8]; // Fall through + case 9: a[9].uli = b[9]; // Fall through + case 10: a[10].uli = b[10]; // Fall through + case 11: a[11].uli = b[11]; // Fall through + case 12: a[12].uli = b[12]; // Fall through + case 13: a[13].uli = b[13]; // Fall through + case 14: a[14].uli = b[14]; // Fall through + case 15: a[15].uli = b[15]; +#endif /* BLOCK_SIZE==16 */ + } + return do_bytes_remaining (a + BLOCK_SIZE, b + BLOCK_SIZE, bytes, ret); +} + +/* The first pointer is not aligned while second pointer is. */ +static void * +unaligned_words (struct ulw *a, const reg_t * b, + unsigned long words, unsigned long bytes, void *ret) +{ + unsigned long i, words_by_block, words_by_1; + words_by_1 = words % BLOCK_SIZE; + words_by_block = words / BLOCK_SIZE; + + for (; words_by_block > 0; words_by_block--) + { + /* This condition is deliberately conservative. One could theoretically + pre-fetch another time around in some cases without crossing the page + boundary at the limit, but checking for the right conditions here is + too expensive to be worth it. */ + if (words_by_block > PREF_AHEAD) + for (i = 0; i < CACHE_LINES_PER_BLOCK; i++) + PREFETCH (b + ((BLOCK_SIZE / CACHE_LINES_PER_BLOCK) + * (PREF_AHEAD + i))); + + reg_t y0 = b[0], y1 = b[1], y2 = b[2], y3 = b[3]; + reg_t y4 = b[4], y5 = b[5], y6 = b[6], y7 = b[7]; + a[0].uli = y0; + a[1].uli = y1; + a[2].uli = y2; + a[3].uli = y3; + a[4].uli = y4; + a[5].uli = y5; + a[6].uli = y6; + a[7].uli = y7; +#if BLOCK_SIZE==16 + y0 = b[8], y1 = b[9], y2 = b[10], y3 = b[11]; + y4 = b[12], y5 = b[13], y6 = b[14], y7 = b[15]; + a[8].uli = y0; + a[9].uli = y1; + a[10].uli = y2; + a[11].uli = y3; + a[12].uli = y4; + a[13].uli = y5; + a[14].uli = y6; + a[15].uli = y7; +#endif /* BLOCK_SIZE==16 */ + a += BLOCK_SIZE; + b += BLOCK_SIZE; + } + + /* Mop up any remaining bytes. */ + return do_uwords_remaining (a, b, words_by_1, bytes, ret); +} + +#else /* !UNALIGNED_INSTR_SUPPORT */ + +/* No HW support or unaligned lw/ld/ualw/uald instructions. */ +static void * +unaligned_words (reg_t * a, const reg_t * b, + unsigned long words, unsigned long bytes, void *ret) +{ + unsigned long i; + unsigned char *x; + for (i = 0; i < words; i++) + { + bitfields_t bw; + bw.v = *((reg_t*) b); + x = (unsigned char *) a; + x[0] = bw.b.B0; + x[1] = bw.b.B1; + x[2] = bw.b.B2; + x[3] = bw.b.B3; +#ifdef __mips64 + x[4] = bw.b.B4; + x[5] = bw.b.B5; + x[6] = bw.b.B6; + x[7] = bw.b.B7; +#endif + a += 1; + b += 1; + } + /* Mop up any remaining bytes. */ + return do_bytes_remaining (a, b, bytes, ret); +} + +#endif /* UNALIGNED_INSTR_SUPPORT */ +#endif /* HW_UNALIGNED_SUPPORT */ + +/* both pointers are aligned, or first isn't and HW support for unaligned. */ +static void * +aligned_words (reg_t * a, const reg_t * b, + unsigned long words, unsigned long bytes, void *ret) +{ + unsigned long i, words_by_block, words_by_1; + words_by_1 = words % BLOCK_SIZE; + words_by_block = words / BLOCK_SIZE; + + for (; words_by_block > 0; words_by_block--) + { + if (words_by_block > PREF_AHEAD) + for (i = 0; i < CACHE_LINES_PER_BLOCK; i++) + PREFETCH (b + ((BLOCK_SIZE / CACHE_LINES_PER_BLOCK) + * (PREF_AHEAD + i))); + + reg_t x0 = b[0], x1 = b[1], x2 = b[2], x3 = b[3]; + reg_t x4 = b[4], x5 = b[5], x6 = b[6], x7 = b[7]; + a[0] = x0; + a[1] = x1; + a[2] = x2; + a[3] = x3; + a[4] = x4; + a[5] = x5; + a[6] = x6; + a[7] = x7; +#if BLOCK_SIZE==16 + x0 = b[8], x1 = b[9], x2 = b[10], x3 = b[11]; + x4 = b[12], x5 = b[13], x6 = b[14], x7 = b[15]; + a[8] = x0; + a[9] = x1; + a[10] = x2; + a[11] = x3; + a[12] = x4; + a[13] = x5; + a[14] = x6; + a[15] = x7; +#endif /* BLOCK_SIZE==16 */ + a += BLOCK_SIZE; + b += BLOCK_SIZE; + } + + /* mop up any remaining bytes. */ + return do_words_remaining (a, b, words_by_1, bytes, ret); +} + +void * +memcpy (void *a, const void *b, size_t len) __overloadable +{ + unsigned long bytes, words, i; + void *ret = a; +#if ENABLE_PREFETCH_CHECK + limit = (char *)b + len; +#endif /* ENABLE_PREFETCH_CHECK */ + /* shouldn't hit that often. */ + if (len <= 8) + return do_bytes (a, b, len, a); + + /* Start pre-fetches ahead of time. */ + if (len > CACHE_LINE * PREF_AHEAD) + for (i = 1; i < PREF_AHEAD; i++) + PREFETCH ((char *)b + CACHE_LINE * i); + else + for (i = 1; i < len / CACHE_LINE; i++) + PREFETCH ((char *)b + CACHE_LINE * i); + + /* Align the second pointer to word/dword alignment. + Note that the pointer is only 32-bits for o32/n32 ABIs. For + n32, loads are done as 64-bit while address remains 32-bit. */ + bytes = ((unsigned long) b) % (sizeof (reg_t)); + + if (bytes) + { + bytes = (sizeof (reg_t)) - bytes; + if (bytes > len) + bytes = len; + do_bytes (a, b, bytes, ret); + if (len == bytes) + return ret; + len -= bytes; + a = (void *) (((unsigned char *) a) + bytes); + b = (const void *) (((unsigned char *) b) + bytes); + } + + /* Second pointer now aligned. */ + words = len / sizeof (reg_t); + bytes = len % sizeof (reg_t); + +#if HW_UNALIGNED_SUPPORT + /* treat possible unaligned first pointer as aligned. */ + return aligned_words (a, b, words, bytes, ret); +#else /* !HW_UNALIGNED_SUPPORT */ + if (((unsigned long) a) % sizeof (reg_t) == 0) + return aligned_words (a, b, words, bytes, ret); + /* need to use unaligned instructions on first pointer. */ + return unaligned_words (a, b, words, bytes, ret); +#endif /* HW_UNALIGNED_SUPPORT */ +} + +libc_hidden_builtin_def (memcpy) + +#else +#include +#endif diff --git a/sysdeps/mips/memset.S b/sysdeps/mips/memset.S deleted file mode 100644 index 96a180732c..0000000000 --- a/sysdeps/mips/memset.S +++ /dev/null @@ -1,426 +0,0 @@ -/* Copyright (C) 2013-2025 Free Software Foundation, Inc. - This file is part of the GNU C Library. - - The GNU C Library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 2.1 of the License, or (at your option) any later version. - - The GNU C Library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with the GNU C Library. If not, see - . */ - -#ifdef ANDROID_CHANGES -# include "machine/asm.h" -# include "machine/regdef.h" -# define PREFETCH_STORE_HINT PREFETCH_HINT_PREPAREFORSTORE -#elif _LIBC -# include -# include -# include -# define PREFETCH_STORE_HINT PREFETCH_HINT_PREPAREFORSTORE -#elif defined _COMPILING_NEWLIB -# include "machine/asm.h" -# include "machine/regdef.h" -# define PREFETCH_STORE_HINT PREFETCH_HINT_PREPAREFORSTORE -#else -# include -# include -#endif - -/* Check to see if the MIPS architecture we are compiling for supports - prefetching. */ - -#if (__mips == 4) || (__mips == 5) || (__mips == 32) || (__mips == 64) -# ifndef DISABLE_PREFETCH -# define USE_PREFETCH -# endif -#endif - -#if defined(_MIPS_SIM) && ((_MIPS_SIM == _ABI64) || (_MIPS_SIM == _ABIN32)) -# ifndef DISABLE_DOUBLE -# define USE_DOUBLE -# endif -#endif - -#ifndef USE_DOUBLE -# ifndef DISABLE_DOUBLE_ALIGN -# define DOUBLE_ALIGN -# endif -#endif - - -/* Some asm.h files do not have the L macro definition. */ -#ifndef L -# if _MIPS_SIM == _ABIO32 -# define L(label) $L ## label -# else -# define L(label) .L ## label -# endif -#endif - -/* Some asm.h files do not have the PTR_ADDIU macro definition. */ -#ifndef PTR_ADDIU -# ifdef USE_DOUBLE -# define PTR_ADDIU daddiu -# else -# define PTR_ADDIU addiu -# endif -#endif - -/* New R6 instructions that may not be in asm.h. */ -#ifndef PTR_LSA -# if _MIPS_SIM == _ABI64 -# define PTR_LSA dlsa -# else -# define PTR_LSA lsa -# endif -#endif - -/* Using PREFETCH_HINT_PREPAREFORSTORE instead of PREFETCH_STORE - or PREFETCH_STORE_STREAMED offers a large performance advantage - but PREPAREFORSTORE has some special restrictions to consider. - - Prefetch with the 'prepare for store' hint does not copy a memory - location into the cache, it just allocates a cache line and zeros - it out. This means that if you do not write to the entire cache - line before writing it out to memory some data will get zero'ed out - when the cache line is written back to memory and data will be lost. - - There are ifdef'ed sections of this memcpy to make sure that it does not - do prefetches on cache lines that are not going to be completely written. - This code is only needed and only used when PREFETCH_STORE_HINT is set to - PREFETCH_HINT_PREPAREFORSTORE. This code assumes that cache lines are - less than MAX_PREFETCH_SIZE bytes and if the cache line is larger it will - not work correctly. */ - -#ifdef USE_PREFETCH -# define PREFETCH_HINT_STORE 1 -# define PREFETCH_HINT_STORE_STREAMED 5 -# define PREFETCH_HINT_STORE_RETAINED 7 -# define PREFETCH_HINT_PREPAREFORSTORE 30 - -/* If we have not picked out what hints to use at this point use the - standard load and store prefetch hints. */ -# ifndef PREFETCH_STORE_HINT -# define PREFETCH_STORE_HINT PREFETCH_HINT_STORE -# endif - -/* We double everything when USE_DOUBLE is true so we do 2 prefetches to - get 64 bytes in that case. The assumption is that each individual - prefetch brings in 32 bytes. */ -# ifdef USE_DOUBLE -# define PREFETCH_CHUNK 64 -# define PREFETCH_FOR_STORE(chunk, reg) \ - pref PREFETCH_STORE_HINT, (chunk)*64(reg); \ - pref PREFETCH_STORE_HINT, ((chunk)*64)+32(reg) -# else -# define PREFETCH_CHUNK 32 -# define PREFETCH_FOR_STORE(chunk, reg) \ - pref PREFETCH_STORE_HINT, (chunk)*32(reg) -# endif - -/* MAX_PREFETCH_SIZE is the maximum size of a prefetch, it must not be less - than PREFETCH_CHUNK, the assumed size of each prefetch. If the real size - of a prefetch is greater than MAX_PREFETCH_SIZE and the PREPAREFORSTORE - hint is used, the code will not work correctly. If PREPAREFORSTORE is not - used than MAX_PREFETCH_SIZE does not matter. */ -# define MAX_PREFETCH_SIZE 128 -/* PREFETCH_LIMIT is set based on the fact that we never use an offset greater - than 5 on a STORE prefetch and that a single prefetch can never be larger - than MAX_PREFETCH_SIZE. We add the extra 32 when USE_DOUBLE is set because - we actually do two prefetches in that case, one 32 bytes after the other. */ -# ifdef USE_DOUBLE -# define PREFETCH_LIMIT (5 * PREFETCH_CHUNK) + 32 + MAX_PREFETCH_SIZE -# else -# define PREFETCH_LIMIT (5 * PREFETCH_CHUNK) + MAX_PREFETCH_SIZE -# endif - -# if (PREFETCH_STORE_HINT == PREFETCH_HINT_PREPAREFORSTORE) \ - && ((PREFETCH_CHUNK * 4) < MAX_PREFETCH_SIZE) -/* We cannot handle this because the initial prefetches may fetch bytes that - are before the buffer being copied. We start copies with an offset - of 4 so avoid this situation when using PREPAREFORSTORE. */ -# error "PREFETCH_CHUNK is too large and/or MAX_PREFETCH_SIZE is too small." -# endif -#else /* USE_PREFETCH not defined */ -# define PREFETCH_FOR_STORE(offset, reg) -#endif - -#if __mips_isa_rev > 5 -# if (PREFETCH_STORE_HINT == PREFETCH_HINT_PREPAREFORSTORE) -# undef PREFETCH_STORE_HINT -# define PREFETCH_STORE_HINT PREFETCH_HINT_STORE_STREAMED -# endif -# define R6_CODE -#endif - -/* Allow the routine to be named something else if desired. */ -#ifndef MEMSET_NAME -# define MEMSET_NAME memset -#endif - -/* We load/store 64 bits at a time when USE_DOUBLE is true. - The C_ prefix stands for CHUNK and is used to avoid macro name - conflicts with system header files. */ - -#ifdef USE_DOUBLE -# define C_ST sd -# ifdef __MIPSEB -# define C_STHI sdl /* high part is left in big-endian */ -# else -# define C_STHI sdr /* high part is right in little-endian */ -# endif -#else -# define C_ST sw -# ifdef __MIPSEB -# define C_STHI swl /* high part is left in big-endian */ -# else -# define C_STHI swr /* high part is right in little-endian */ -# endif -#endif - -/* Bookkeeping values for 32 vs. 64 bit mode. */ -#ifdef USE_DOUBLE -# define NSIZE 8 -# define NSIZEMASK 0x3f -# define NSIZEDMASK 0x7f -#else -# define NSIZE 4 -# define NSIZEMASK 0x1f -# define NSIZEDMASK 0x3f -#endif -#define UNIT(unit) ((unit)*NSIZE) -#define UNITM1(unit) (((unit)*NSIZE)-1) - -#ifdef ANDROID_CHANGES -LEAF(MEMSET_NAME,0) -#else -LEAF(MEMSET_NAME) -#endif - - .set nomips16 - .set noreorder -/* If the size is less than 2*NSIZE (8 or 16), go to L(lastb). Regardless of - size, copy dst pointer to v0 for the return value. */ - slti t2,a2,(2 * NSIZE) - bne t2,zero,L(lastb) - move v0,a0 - -/* If memset value is not zero, we copy it to all the bytes in a 32 or 64 - bit word. */ - beq a1,zero,L(set0) /* If memset value is zero no smear */ - PTR_SUBU a3,zero,a0 - nop - - /* smear byte into 32 or 64 bit word */ -#if ((__mips == 64) || (__mips == 32)) && (__mips_isa_rev >= 2) -# ifdef USE_DOUBLE - dins a1, a1, 8, 8 /* Replicate fill byte into half-word. */ - dins a1, a1, 16, 16 /* Replicate fill byte into word. */ - dins a1, a1, 32, 32 /* Replicate fill byte into dbl word. */ -# else - ins a1, a1, 8, 8 /* Replicate fill byte into half-word. */ - ins a1, a1, 16, 16 /* Replicate fill byte into word. */ -# endif -#else -# ifdef USE_DOUBLE - and a1,0xff - dsll t2,a1,8 - or a1,t2 - dsll t2,a1,16 - or a1,t2 - dsll t2,a1,32 - or a1,t2 -# else - and a1,0xff - sll t2,a1,8 - or a1,t2 - sll t2,a1,16 - or a1,t2 -# endif -#endif - -/* If the destination address is not aligned do a partial store to get it - aligned. If it is already aligned just jump to L(aligned). */ -L(set0): -#ifndef R6_CODE - andi t2,a3,(NSIZE-1) /* word-unaligned address? */ - beq t2,zero,L(aligned) /* t2 is the unalignment count */ - PTR_SUBU a2,a2,t2 - C_STHI a1,0(a0) - PTR_ADDU a0,a0,t2 -#else /* R6_CODE */ - andi t2,a0,(NSIZE-1) - lapc t9,L(atable) - PTR_LSA t9,t2,t9,2 - jrc t9 -L(atable): - bc L(aligned) -# ifdef USE_DOUBLE - bc L(lb7) - bc L(lb6) - bc L(lb5) - bc L(lb4) -# endif - bc L(lb3) - bc L(lb2) - bc L(lb1) -L(lb7): - sb a1,6(a0) -L(lb6): - sb a1,5(a0) -L(lb5): - sb a1,4(a0) -L(lb4): - sb a1,3(a0) -L(lb3): - sb a1,2(a0) -L(lb2): - sb a1,1(a0) -L(lb1): - sb a1,0(a0) - - li t9,NSIZE - subu t2,t9,t2 - PTR_SUBU a2,a2,t2 - PTR_ADDU a0,a0,t2 -#endif /* R6_CODE */ - -L(aligned): -/* If USE_DOUBLE is not set we may still want to align the data on a 16 - byte boundary instead of an 8 byte boundary to maximize the opportunity - of proAptiv chips to do memory bonding (combining two sequential 4 - byte stores into one 8 byte store). We know there are at least 4 bytes - left to store or we would have jumped to L(lastb) earlier in the code. */ -#ifdef DOUBLE_ALIGN - andi t2,a3,4 - beq t2,zero,L(double_aligned) - PTR_SUBU a2,a2,t2 - sw a1,0(a0) - PTR_ADDU a0,a0,t2 -L(double_aligned): -#endif - -/* Now the destination is aligned to (word or double word) aligned address - Set a2 to count how many bytes we have to copy after all the 64/128 byte - chunks are copied and a3 to the dest pointer after all the 64/128 byte - chunks have been copied. We will loop, incrementing a0 until it equals - a3. */ - andi t8,a2,NSIZEDMASK /* any whole 64-byte/128-byte chunks? */ - beq a2,t8,L(chkw) /* if a2==t8, no 64-byte/128-byte chunks */ - PTR_SUBU a3,a2,t8 /* subtract from a2 the reminder */ - PTR_ADDU a3,a0,a3 /* Now a3 is the final dst after loop */ - -/* When in the loop we may prefetch with the 'prepare to store' hint, - in this case the a0+x should not be past the "t0-32" address. This - means: for x=128 the last "safe" a0 address is "t0-160". Alternatively, - for x=64 the last "safe" a0 address is "t0-96" In the current version we - will use "prefetch hint,128(a0)", so "t0-160" is the limit. */ -#if defined(USE_PREFETCH) \ - && (PREFETCH_STORE_HINT == PREFETCH_HINT_PREPAREFORSTORE) - PTR_ADDU t0,a0,a2 /* t0 is the "past the end" address */ - PTR_SUBU t9,t0,PREFETCH_LIMIT /* t9 is the "last safe pref" address */ -#endif -#if defined(USE_PREFETCH) \ - && (PREFETCH_STORE_HINT != PREFETCH_HINT_PREPAREFORSTORE) - PREFETCH_FOR_STORE (1, a0) - PREFETCH_FOR_STORE (2, a0) - PREFETCH_FOR_STORE (3, a0) -#endif - -L(loop16w): -#if defined(USE_PREFETCH) \ - && (PREFETCH_STORE_HINT == PREFETCH_HINT_PREPAREFORSTORE) - sltu v1,t9,a0 /* If a0 > t9 don't use next prefetch */ - bgtz v1,L(skip_pref) - nop -#endif -#ifdef R6_CODE - PREFETCH_FOR_STORE (2, a0) -#else - PREFETCH_FOR_STORE (4, a0) - PREFETCH_FOR_STORE (5, a0) -#endif -L(skip_pref): - C_ST a1,UNIT(0)(a0) - C_ST a1,UNIT(1)(a0) - C_ST a1,UNIT(2)(a0) - C_ST a1,UNIT(3)(a0) - C_ST a1,UNIT(4)(a0) - C_ST a1,UNIT(5)(a0) - C_ST a1,UNIT(6)(a0) - C_ST a1,UNIT(7)(a0) - C_ST a1,UNIT(8)(a0) - C_ST a1,UNIT(9)(a0) - C_ST a1,UNIT(10)(a0) - C_ST a1,UNIT(11)(a0) - C_ST a1,UNIT(12)(a0) - C_ST a1,UNIT(13)(a0) - C_ST a1,UNIT(14)(a0) - C_ST a1,UNIT(15)(a0) - PTR_ADDIU a0,a0,UNIT(16) /* adding 64/128 to dest */ - bne a0,a3,L(loop16w) - nop - move a2,t8 - -/* Here we have dest word-aligned but less than 64-bytes or 128 bytes to go. - Check for a 32(64) byte chunk and copy if there is one. Otherwise - jump down to L(chk1w) to handle the tail end of the copy. */ -L(chkw): - andi t8,a2,NSIZEMASK /* is there a 32-byte/64-byte chunk. */ - /* the t8 is the reminder count past 32-bytes */ - beq a2,t8,L(chk1w)/* when a2==t8, no 32-byte chunk */ - nop - C_ST a1,UNIT(0)(a0) - C_ST a1,UNIT(1)(a0) - C_ST a1,UNIT(2)(a0) - C_ST a1,UNIT(3)(a0) - C_ST a1,UNIT(4)(a0) - C_ST a1,UNIT(5)(a0) - C_ST a1,UNIT(6)(a0) - C_ST a1,UNIT(7)(a0) - PTR_ADDIU a0,a0,UNIT(8) - -/* Here we have less than 32(64) bytes to set. Set up for a loop to - copy one word (or double word) at a time. Set a2 to count how many - bytes we have to copy after all the word (or double word) chunks are - copied and a3 to the dest pointer after all the (d)word chunks have - been copied. We will loop, incrementing a0 until a0 equals a3. */ -L(chk1w): - andi a2,t8,(NSIZE-1) /* a2 is the reminder past one (d)word chunks */ - beq a2,t8,L(lastb) - PTR_SUBU a3,t8,a2 /* a3 is count of bytes in one (d)word chunks */ - PTR_ADDU a3,a0,a3 /* a3 is the dst address after loop */ - -/* copying in words (4-byte or 8 byte chunks) */ -L(wordCopy_loop): - PTR_ADDIU a0,a0,UNIT(1) - bne a0,a3,L(wordCopy_loop) - C_ST a1,UNIT(-1)(a0) - -/* Copy the last 8 (or 16) bytes */ -L(lastb): - blez a2,L(leave) - PTR_ADDU a3,a0,a2 /* a3 is the last dst address */ -L(lastbloop): - PTR_ADDIU a0,a0,1 - bne a0,a3,L(lastbloop) - sb a1,-1(a0) -L(leave): - j ra - nop - - .set at - .set reorder -END(MEMSET_NAME) -#ifndef ANDROID_CHANGES -# ifdef _LIBC -libc_hidden_builtin_def (MEMSET_NAME) -# endif -#endif diff --git a/sysdeps/mips/memset.c b/sysdeps/mips/memset.c new file mode 100644 index 0000000000..e696c7f09b --- /dev/null +++ b/sysdeps/mips/memset.c @@ -0,0 +1,178 @@ +/* Contributed by Wave Computing + Copyright (C) 2025 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library. If not, see + . */ + +#ifdef __GNUC__ + +#undef memset + +#include + +#if _MIPS_SIM == _ABIO32 +#define SIZEOF_reg_t 4 +typedef unsigned long reg_t; +#else +#define SIZEOF_reg_t 8 +typedef unsigned long long reg_t; +#endif + +typedef struct bits8 +{ + reg_t B0:8, B1:8, B2:8, B3:8; +#if SIZEOF_reg_t == 8 + reg_t B4:8, B5:8, B6:8, B7:8; +#endif +} bits8_t; +typedef struct bits16 +{ + reg_t B0:16, B1:16; +#if SIZEOF_reg_t == 8 + reg_t B2:16, B3:16; +#endif +} bits16_t; +typedef struct bits32 +{ + reg_t B0:32; +#if SIZEOF_reg_t == 8 + reg_t B1:32; +#endif +} bits32_t; + +/* This union assumes that small structures can be in registers. If + not, then memory accesses will be done - not optimal, but ok. */ +typedef union +{ + reg_t v; + bits8_t b8; + bits16_t b16; + bits32_t b32; +} bitfields_t; + +/* This code is called when aligning a pointer or there are remaining bytes + after doing word sets. */ +static inline void * __attribute__ ((always_inline)) +do_bytes (void *a, void *retval, unsigned char fill, const unsigned long len) +{ + unsigned char *x = ((unsigned char *) a); + unsigned long i; + + for (i = 0; i < len; i++) + *x++ = fill; + + return retval; +} + +/* Pointer is aligned. */ +static void * +do_aligned_words (reg_t * a, void * retval, reg_t fill, + unsigned long words, unsigned long bytes) +{ + unsigned long i, words_by_1, words_by_16; + + words_by_1 = words % 16; + words_by_16 = words / 16; + + /* + * Note: prefetching the store memory is not beneficial on most + * cores since the ls/st unit has store buffers that will be filled + * before the cache line is actually needed. + * + * Also, using prepare-for-store cache op is problematic since we + * don't know the implementation-defined cache line length and we + * don't want to touch unintended memory. + */ + for (i = 0; i < words_by_16; i++) + { + a[0] = fill; + a[1] = fill; + a[2] = fill; + a[3] = fill; + a[4] = fill; + a[5] = fill; + a[6] = fill; + a[7] = fill; + a[8] = fill; + a[9] = fill; + a[10] = fill; + a[11] = fill; + a[12] = fill; + a[13] = fill; + a[14] = fill; + a[15] = fill; + a += 16; + } + + /* do remaining words. */ + for (i = 0; i < words_by_1; i++) + *a++ = fill; + + /* mop up any remaining bytes. */ + return do_bytes (a, retval, fill, bytes); +} + +void * +inhibit_loop_to_libcall +memset (void *a, int ifill, size_t len) +{ + unsigned long bytes, words; + bitfields_t fill; + void *retval = (void *) a; + + /* shouldn't hit that often. */ + if (len < 16) + return do_bytes (a, retval, ifill, len); + + /* Align the pointer to word/dword alignment. + Note that the pointer is only 32-bits for o32/n32 ABIs. For + n32, loads are done as 64-bit while address remains 32-bit. */ + bytes = ((unsigned long) a) % (sizeof (reg_t) * 2); + if (bytes) + { + bytes = (sizeof (reg_t) * 2 - bytes); + if (bytes > len) + bytes = len; + do_bytes (a, retval, ifill, bytes); + if (len == bytes) + return retval; + len -= bytes; + a = (void *) (((unsigned char *) a) + bytes); + } + + /* Create correct fill value for reg_t sized variable. */ + if (ifill != 0) + { + fill.b8.B0 = (unsigned char) ifill; + fill.b8.B1 = fill.b8.B0; + fill.b16.B1 = fill.b16.B0; +#if SIZEOF_reg_t == 8 + fill.b32.B1 = fill.b32.B0; +#endif + } + else + fill.v = 0; + + words = len / sizeof (reg_t); + bytes = len % sizeof (reg_t); + return do_aligned_words (a, retval, fill.v, words, bytes); +} + + +libc_hidden_builtin_def (memset) + +#else +#include +#endif