From patchwork Mon May 25 13:30:51 2026 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Luis Silva X-Patchwork-Id: 135611 Return-Path: X-Original-To: patchwork@sourceware.org Delivered-To: patchwork@sourceware.org Received: from vm01.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id 981A84BA7987 for ; Mon, 25 May 2026 13:33:23 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 981A84BA7987 Authentication-Results: sourceware.org; dkim=pass (2048-bit key, unprotected) header.d=synopsys.com header.i=@synopsys.com header.a=rsa-sha256 header.s=pfptdkimsnps header.b=E400GV/F; dkim=pass (2048-bit key, unprotected) header.d=synopsys.com header.i=@synopsys.com header.a=rsa-sha256 header.s=mail header.b=EQJx0E+m X-Original-To: binutils@sourceware.org Delivered-To: binutils@sourceware.org Received: from mx0a-00230701.pphosted.com (mx0a-00230701.pphosted.com [148.163.156.19]) by sourceware.org (Postfix) with ESMTPS id 4FE064BA9003 for ; Mon, 25 May 2026 13:31:19 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org 4FE064BA9003 Authentication-Results: sourceware.org; dmarc=pass (p=quarantine dis=none) header.from=synopsys.com Authentication-Results: sourceware.org; spf=pass smtp.mailfrom=synopsys.com ARC-Filter: OpenARC Filter v1.0.0 sourceware.org 4FE064BA9003 Authentication-Results: sourceware.org; arc=none smtp.remote-ip=148.163.156.19 ARC-Seal: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1779715880; cv=none; b=uZeffKYVQaJop20Yxe0E1c3pimqf7DTh3ULlr1Y/wiCGFL6RZ+MATvWKs8sq+hcFkU33UcyEZnEwjbqLHldlWMYhXgw1Fuwfr5TJVxfNkWuAip0o93mbdGTMU+fTG2tyfUEjqKZy2GDsQPP2fwY1YWPURYzw8v6Hhxbn+dAMffA= ARC-Message-Signature: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1779715880; c=relaxed/simple; bh=l7edJaMQyw4rRyZunuWBAj8aRUsQFX/BcZiUN8WvDZo=; h=DKIM-Signature:DKIM-Signature:From:To:Subject:Date:Message-Id: MIME-Version; b=EA4Bn8CTDJPx2xZyy8f6h96sIRieQohPvQeCIku0VW/qtU9/IvzxjZSyxL4+l7WW4TlKgxpjSe5IR7FUws6g59GifhF+2KUSCv2X1qwovNso4zmbwF9+zUx+Bv/2cHu3wF+RZ/xe2SBP4Eih+mRG4ACv9B2n9KIWlU9sekFsxt0= ARC-Authentication-Results: i=1; sourceware.org; dkim=pass (2048-bit key, unprotected) header.d=synopsys.com header.i=@synopsys.com header.a=rsa-sha256 header.s=pfptdkimsnps header.b=E400GV/F; dkim=pass (2048-bit key, unprotected) header.d=synopsys.com header.i=@synopsys.com header.a=rsa-sha256 header.s=mail header.b=EQJx0E+m DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 4FE064BA9003 Received: from pps.filterd (m0297266.ppops.net [127.0.0.1]) by mx0a-00230701.pphosted.com (8.18.1.11/8.18.1.11) with ESMTP id 64P9dJFx3673923; Mon, 25 May 2026 06:31:11 -0700 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=synopsys.com; h= cc:content-transfer-encoding:date:from:in-reply-to:message-id :mime-version:references:subject:to; s=pfptdkimsnps; bh=9SblpzDS WiDnVOR0Fl13Z0QlCgJHV+k2bkVWpHI6+VM=; b=E400GV/Fb9N7+fJQB2cniFH5 ycRxYxFrtftm5Y8HoV4n449Gt253N6YrqHZJwIItdpmQ0Czq3ef446hS6/zPbt0u 6apoK1/+V9JR1jKhffGnqotBdiySYrP9Nk7ZmB8wc+ix7DJuI8pYdDqalu6AQRpv 6qY0y7YC+ExADStYFrwIXosuLyIaCClFsldwcowfWtsgaCUa1tSLj7hBkrYrIG8G CgfguqsdbBLZQgz6ynNmyMlB8x54EaicyMUjfhdWzQo3kUyI5XFKZNw61jru5BpA Yp4e26E8IBbcsKvnQrTCHhFplNlu4PANxYvowd+o8zHjHJPyFK4h3U8KtcjJGw== Received: from smtprelay-out1.synopsys.com (smtprelay-out1.synopsys.com [149.117.73.133]) by mx0a-00230701.pphosted.com (PPS) with ESMTPS id 4ebbg5aw74-1 (version=TLSv1.3 cipher=TLS_AES_256_GCM_SHA384 bits=256 verify=NOT); Mon, 25 May 2026 06:31:11 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=synopsys.com; s=mail; t=1779715871; bh=l7edJaMQyw4rRyZunuWBAj8aRUsQFX/BcZiUN8WvDZo=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=EQJx0E+mO0MCni+P3gSsucAhRIWGuOERQdu4vDZCbAMQFMCyWqYIvcWoxQR6xDquO eSpFQ6Zh0u4wjVcG1f1sDsz5/OleXRSH+WFFBtvbzLgcCO1n20o8yA5SrdEQN3P1xO osKpr3o0P0mCzkLwcbXSxMRgv+D56N6vTJl457N35MlICOo5ifZ6ZSzyBBEkrfr3SD 87ohVwLfatlsGzJiBqNKtddDT1EK7GvcOpk6s5za7E2g2c1RjUOPUlHTbKcK+5lLdj RA1DRFw8iGqMmihj0wcjc/HnJxUXwDlfrg2szXfhV58nppRkis+aAZjji7DI/SZYuw ECh2Ea+oUM+2A== Received: from mailhost.synopsys.com (badc-mailhost1.synopsys.com [10.192.0.17]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits) client-signature RSA-PSS (2048 bits)) (Client CN "mailhost.synopsys.com", Issuer "SNPSica2" (verified OK)) by smtprelay-out1.synopsys.com (Postfix) with ESMTPS id 464E0402B2; Mon, 25 May 2026 13:31:10 +0000 (UTC) Received: from us01arcgnu3.internal.synopsys.com (unknown [10.194.34.166]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits) server-digest SHA256) (Client did not present a certificate) by mailhost.synopsys.com (Postfix) with ESMTPSA id A73D0A00CD; Mon, 25 May 2026 13:31:09 +0000 (UTC) X-SNPS-Relay: synopsys.com From: Luis Silva To: binutils@sourceware.org Cc: Palmer Dabbelt , Andrew Waterman , Jim Wilson , Nelson Chu , Kito Cheng , Jeff Law , Alex Turjan , Luis Silva , Luis Silva Subject: [PATCH 1/2] RISC-V: Add ARC-V APEX assembler support Date: Mon, 25 May 2026 06:30:51 -0700 Message-Id: <20260525133052.1885254-2-luiss@synopsys.com> X-Mailer: git-send-email 2.34.0 In-Reply-To: <20260525133052.1885254-1-luiss@synopsys.com> References: <20260525133052.1885254-1-luiss@synopsys.com> MIME-Version: 1.0 X-Proofpoint-Spam-Details-Enc: AW1haW4tMjYwNTI1MDEzOCBTYWx0ZWRfXxmZoWg9uW9o1 SuD6uX4RYOaAMDWtUU6+FKGZ08ZYqkrxBlYF2Az7EZbHpTnjzMr+HnkQNpeHwP/rd8pGcvQ/RzL YY7K1L6fvD9G2BG4lSOhra4QbHPZ5hqkjNTi0/sjDk0UY2hM37ZzeqrdbCsfcQf/KMZ5PiQJUa7 0zxJXsoDtZdWNMyafvTEoZWckqKpISaODb/Ry8xWYZWUH5im3slXMIY9VZoMMUq6gvx1QYp8Jkt MBvZTh5Dkjd8+eg1oNTR0VPujNwZnPHbrFbL30GOwXmuiYp2sdJwxj03O+ZR3lQHAyzYJKJKZ9Z OK/0RaV0cI5AM3AAO9uicJCxJdt37DxMORUXtXawMV0aej4YQKZdHaPK119oztb/sgQ0ETAorK9 k8TrKD9G99KXK0dpWFp5L8Z5oRRmZOp58Gav9RonolilH6DMxnRoDeq2WawjeWkW+oCCL0FGeca KYWptbJzj4cDXtqvG6Q== X-Proofpoint-GUID: 1guTtB47sg3-M5Ap6MQaTVs60kudiOKc X-Authority-Analysis: v=2.4 cv=cKTQdFeN c=1 sm=1 tr=0 ts=6a144f1f cx=c_pps a=8EbXvwLXkpGsT4ql/pYRAw==:117 a=8EbXvwLXkpGsT4ql/pYRAw==:17 a=NGcC8JguVDcA:10 a=qPHU084jO2kA:10 a=VkNPw1HP01LnGYTKEx00:22 a=tU_645BZ7FZt8VqRJtHG:22 a=Wo6YDfOMAEstGd-0DxeT:22 a=jIQo8A4GAAAA:8 a=XBNpXGST_z4FfiN1M78A:9 X-Proofpoint-ORIG-GUID: 1guTtB47sg3-M5Ap6MQaTVs60kudiOKc X-Proofpoint-Virus-Version: vendor=baseguard engine=ICAP:2.0.293,Aquarius:18.0.1143,Hydra:6.1.51,FMLib:17.12.100.49 definitions=2026-05-25_04,2026-05-18_01,2025-10-01_01 X-Proofpoint-Spam-Details: rule=outbound_active_cloned_notspam policy=outbound_active_cloned score=0 spamscore=0 lowpriorityscore=0 impostorscore=0 clxscore=1011 priorityscore=1501 malwarescore=0 phishscore=0 suspectscore=0 bulkscore=0 adultscore=0 classifier=typeunknown authscore=0 authtc= authcc= route=outbound adjust=0 reason=mlx scancount=1 engine=8.22.0-2605130000 definitions=main-2605250138 X-Spam-Status: No, score=-11.9 required=5.0 tests=BAYES_00, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, DKIM_VALID_EF, GIT_PATCH_0, RCVD_IN_DNSWL_LOW, RCVD_IN_MSPIKE_H2, SPF_HELO_NONE, SPF_NONE, TXREP shortcircuit=no autolearn=ham autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on sourceware.org X-BeenThere: binutils@sourceware.org X-Mailman-Version: 2.1.30 Precedence: list List-Id: Binutils mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: binutils-bounces~patchwork=sourceware.org@sourceware.org Add support for ARC-V APEX (ARC Processor EXtension), which allows users to dynamically define custom instructions that use the Custom-0 encoding space. APEX defines four instruction formats: - XD: 3-register (up to 256 sub-opcodes) - XS: 2-register + 8-bit signed immediate (up to 64 sub-opcodes) - XI: 1-register + 12-bit signed immediate (up to 32 sub-opcodes) - XC: compressed form where rd == rs1 (up to 32 sub-opcodes) Instructions are registered at assembly via the .extInstruction directive: .extInstruction , , [, ] Each registered instruction emits a metadata record into a COMDAT ELF section so that instruction definitions are preserved in the linked object. gas/ChangeLog: * config/tc-riscv.c (validate_riscv_insn): Add APEX vendor operand validation. (riscv_ip): Add 'X' vendor operand handling for APEX. (arcv_apex_xs_xc_pair_p): New function. (arcv_apex_validate_insn): New function. (arcv_apex_check_and_set_insn): New function. (arcv_apex_get_metadata_section): New function. (arcv_apex_write_metadata): New function. (arcv_apex_register_insn): New function. (arcv_apex_section_parser): New function. * doc/c-riscv.texi: Document .extInstruction directive * testsuite/gas/riscv/x-arcv-apex-01.d: New test. * testsuite/gas/riscv/x-arcv-apex-01.s: New test. * testsuite/gas/riscv/x-arcv-apex-02.d: New test. * testsuite/gas/riscv/x-arcv-apex-02.s: New test. * testsuite/gas/riscv/x-arcv-apex-03.d: New test. * testsuite/gas/riscv/x-arcv-apex-04.d: New test. * testsuite/gas/riscv/x-arcv-apex-04.s: New test. * testsuite/gas/riscv/x-arcv-apex-fail-01.d: New test. * testsuite/gas/riscv/x-arcv-apex-fail-01.l: New test. * testsuite/gas/riscv/x-arcv-apex-fail-01.s: New test. * testsuite/gas/riscv/x-arcv-apex-fail-02.d: New test. * testsuite/gas/riscv/x-arcv-apex-fail-02.l: New test. * testsuite/gas/riscv/x-arcv-apex-fail-02.s: New test. * testsuite/gas/riscv/x-arcv-apex-fail-03.d: New test. * testsuite/gas/riscv/x-arcv-apex-fail-03.l: New test. * testsuite/gas/riscv/x-arcv-apex-fail-03.s: New test. * testsuite/gas/riscv/x-arcv-apex-fail-04.d: New test. * testsuite/gas/riscv/x-arcv-apex-fail-04.l: New test. * testsuite/gas/riscv/x-arcv-apex-fail-04.s: New test. * testsuite/gas/riscv/x-arcv-apex-fail-05.d: New test. * testsuite/gas/riscv/x-arcv-apex-fail-05.l: New test. * testsuite/gas/riscv/x-arcv-apex-fail-05.s: New test. * testsuite/gas/riscv/x-arcv-apex-fail-06.d: New test. * testsuite/gas/riscv/x-arcv-apex-fail-06.l: New test. * testsuite/gas/riscv/x-arcv-apex-fail-06.s: New test. * testsuite/gas/riscv/x-arcv-apex-fail-07.d: New test. * testsuite/gas/riscv/x-arcv-apex-fail-07.l: New test. * testsuite/gas/riscv/x-arcv-apex-fail-07.s: New test. * testsuite/gas/riscv/x-arcv-apex-fail-08.d: New test. * testsuite/gas/riscv/x-arcv-apex-fail-08.l: New test. * testsuite/gas/riscv/x-arcv-apex-fail-08.s: New test. * testsuite/gas/riscv/x-arcv-apex-fail-09.d: New test. * testsuite/gas/riscv/x-arcv-apex-fail-09.l: New test. * testsuite/gas/riscv/x-arcv-apex-fail-09.s: New test. * testsuite/gas/riscv/x-arcv-apex-fail-10.d: New test. * testsuite/gas/riscv/x-arcv-apex-fail-10.l: New test. * testsuite/gas/riscv/x-arcv-apex-fail-10.s: New test. include/ChangeLog: * opcode/riscv.h (arcv_apex_match_rd_ne_rs1): New declaration. (arcv_apex_init_dynamic_insn): Likewise. (arcv_apex_setup_xd_insn): Likewise. (arcv_apex_setup_xs_insn): Likewise. (arcv_apex_setup_xi_insn): Likewise. (arcv_apex_setup_xc_insn): Likewise. (enum apex_flags): New enum. (struct apex_insn): New struct. Add APEX encoding masks, offsets, and EXTRACT/ENCODE macros. ld/ChangeLog: * testsuite/ld-riscv-elf/ld-riscv-elf.exp: Add APEX tests. * testsuite/ld-riscv-elf/x-arcv-apex-01-a.s: New test. * testsuite/ld-riscv-elf/x-arcv-apex-01-b.s: New test. * testsuite/ld-riscv-elf/x-arcv-apex-01-c.s: New test. * testsuite/ld-riscv-elf/x-arcv-apex-01.d: New test. * testsuite/ld-riscv-elf/x-arcv-apex-02.d: New test. opcodes/ChangeLog: * riscv-opc.c (arcv_apex_init_dynamic_insn): New function. (arcv_apex_match_rd_ne_rs1): New function. (arcv_apex_setup_xd_insn): New function. (arcv_apex_setup_xs_insn): New function. (arcv_apex_setup_xi_insn): New function. (arcv_apex_setup_xc_insn): New function. Co-Authored-By: Alex Turjan Signed-off-by: Luis Silva --- gas/config/tc-riscv.c | 631 ++++++++++++++++++ gas/doc/c-riscv.texi | 53 ++ gas/testsuite/gas/riscv/x-arcv-apex-01.d | 18 + gas/testsuite/gas/riscv/x-arcv-apex-01.s | 19 + gas/testsuite/gas/riscv/x-arcv-apex-02.d | 13 + gas/testsuite/gas/riscv/x-arcv-apex-02.s | 6 + gas/testsuite/gas/riscv/x-arcv-apex-03.d | 46 ++ gas/testsuite/gas/riscv/x-arcv-apex-04.d | 15 + gas/testsuite/gas/riscv/x-arcv-apex-04.s | 10 + gas/testsuite/gas/riscv/x-arcv-apex-fail-01.d | 1 + gas/testsuite/gas/riscv/x-arcv-apex-fail-01.l | 2 + gas/testsuite/gas/riscv/x-arcv-apex-fail-01.s | 1 + gas/testsuite/gas/riscv/x-arcv-apex-fail-02.d | 1 + gas/testsuite/gas/riscv/x-arcv-apex-fail-02.l | 5 + gas/testsuite/gas/riscv/x-arcv-apex-fail-02.s | 3 + gas/testsuite/gas/riscv/x-arcv-apex-fail-03.d | 1 + gas/testsuite/gas/riscv/x-arcv-apex-fail-03.l | 9 + gas/testsuite/gas/riscv/x-arcv-apex-fail-03.s | 12 + gas/testsuite/gas/riscv/x-arcv-apex-fail-04.d | 1 + gas/testsuite/gas/riscv/x-arcv-apex-fail-04.l | 3 + gas/testsuite/gas/riscv/x-arcv-apex-fail-04.s | 2 + gas/testsuite/gas/riscv/x-arcv-apex-fail-05.d | 1 + gas/testsuite/gas/riscv/x-arcv-apex-fail-05.l | 3 + gas/testsuite/gas/riscv/x-arcv-apex-fail-05.s | 3 + gas/testsuite/gas/riscv/x-arcv-apex-fail-06.d | 1 + gas/testsuite/gas/riscv/x-arcv-apex-fail-06.l | 7 + gas/testsuite/gas/riscv/x-arcv-apex-fail-06.s | 7 + gas/testsuite/gas/riscv/x-arcv-apex-fail-07.d | 1 + gas/testsuite/gas/riscv/x-arcv-apex-fail-07.l | 9 + gas/testsuite/gas/riscv/x-arcv-apex-fail-07.s | 9 + gas/testsuite/gas/riscv/x-arcv-apex-fail-08.d | 1 + gas/testsuite/gas/riscv/x-arcv-apex-fail-08.l | 5 + gas/testsuite/gas/riscv/x-arcv-apex-fail-08.s | 7 + gas/testsuite/gas/riscv/x-arcv-apex-fail-09.d | 1 + gas/testsuite/gas/riscv/x-arcv-apex-fail-09.l | 3 + gas/testsuite/gas/riscv/x-arcv-apex-fail-09.s | 1 + gas/testsuite/gas/riscv/x-arcv-apex-fail-10.d | 1 + gas/testsuite/gas/riscv/x-arcv-apex-fail-10.l | 3 + gas/testsuite/gas/riscv/x-arcv-apex-fail-10.s | 2 + include/opcode/riscv.h | 68 ++ ld/testsuite/ld-riscv-elf/ld-riscv-elf.exp | 10 + ld/testsuite/ld-riscv-elf/x-arcv-apex-01-a.s | 8 + ld/testsuite/ld-riscv-elf/x-arcv-apex-01-b.s | 21 + ld/testsuite/ld-riscv-elf/x-arcv-apex-01-c.s | 21 + ld/testsuite/ld-riscv-elf/x-arcv-apex-01.d | 32 + ld/testsuite/ld-riscv-elf/x-arcv-apex-02.d | 36 + opcodes/riscv-opc.c | 140 ++++ 47 files changed, 1253 insertions(+) create mode 100644 gas/testsuite/gas/riscv/x-arcv-apex-01.d create mode 100644 gas/testsuite/gas/riscv/x-arcv-apex-01.s create mode 100644 gas/testsuite/gas/riscv/x-arcv-apex-02.d create mode 100644 gas/testsuite/gas/riscv/x-arcv-apex-02.s create mode 100644 gas/testsuite/gas/riscv/x-arcv-apex-03.d create mode 100644 gas/testsuite/gas/riscv/x-arcv-apex-04.d create mode 100644 gas/testsuite/gas/riscv/x-arcv-apex-04.s create mode 100644 gas/testsuite/gas/riscv/x-arcv-apex-fail-01.d create mode 100644 gas/testsuite/gas/riscv/x-arcv-apex-fail-01.l create mode 100644 gas/testsuite/gas/riscv/x-arcv-apex-fail-01.s create mode 100644 gas/testsuite/gas/riscv/x-arcv-apex-fail-02.d create mode 100644 gas/testsuite/gas/riscv/x-arcv-apex-fail-02.l create mode 100644 gas/testsuite/gas/riscv/x-arcv-apex-fail-02.s create mode 100644 gas/testsuite/gas/riscv/x-arcv-apex-fail-03.d create mode 100644 gas/testsuite/gas/riscv/x-arcv-apex-fail-03.l create mode 100644 gas/testsuite/gas/riscv/x-arcv-apex-fail-03.s create mode 100644 gas/testsuite/gas/riscv/x-arcv-apex-fail-04.d create mode 100644 gas/testsuite/gas/riscv/x-arcv-apex-fail-04.l create mode 100644 gas/testsuite/gas/riscv/x-arcv-apex-fail-04.s create mode 100644 gas/testsuite/gas/riscv/x-arcv-apex-fail-05.d create mode 100644 gas/testsuite/gas/riscv/x-arcv-apex-fail-05.l create mode 100644 gas/testsuite/gas/riscv/x-arcv-apex-fail-05.s create mode 100644 gas/testsuite/gas/riscv/x-arcv-apex-fail-06.d create mode 100644 gas/testsuite/gas/riscv/x-arcv-apex-fail-06.l create mode 100644 gas/testsuite/gas/riscv/x-arcv-apex-fail-06.s create mode 100644 gas/testsuite/gas/riscv/x-arcv-apex-fail-07.d create mode 100644 gas/testsuite/gas/riscv/x-arcv-apex-fail-07.l create mode 100644 gas/testsuite/gas/riscv/x-arcv-apex-fail-07.s create mode 100644 gas/testsuite/gas/riscv/x-arcv-apex-fail-08.d create mode 100644 gas/testsuite/gas/riscv/x-arcv-apex-fail-08.l create mode 100644 gas/testsuite/gas/riscv/x-arcv-apex-fail-08.s create mode 100644 gas/testsuite/gas/riscv/x-arcv-apex-fail-09.d create mode 100644 gas/testsuite/gas/riscv/x-arcv-apex-fail-09.l create mode 100644 gas/testsuite/gas/riscv/x-arcv-apex-fail-09.s create mode 100644 gas/testsuite/gas/riscv/x-arcv-apex-fail-10.d create mode 100644 gas/testsuite/gas/riscv/x-arcv-apex-fail-10.l create mode 100644 gas/testsuite/gas/riscv/x-arcv-apex-fail-10.s create mode 100644 ld/testsuite/ld-riscv-elf/x-arcv-apex-01-a.s create mode 100644 ld/testsuite/ld-riscv-elf/x-arcv-apex-01-b.s create mode 100644 ld/testsuite/ld-riscv-elf/x-arcv-apex-01-c.s create mode 100644 ld/testsuite/ld-riscv-elf/x-arcv-apex-01.d create mode 100644 ld/testsuite/ld-riscv-elf/x-arcv-apex-02.d diff --git a/gas/config/tc-riscv.c b/gas/config/tc-riscv.c index 7337ad07d8d..278a976b375 100644 --- a/gas/config/tc-riscv.c +++ b/gas/config/tc-riscv.c @@ -195,6 +195,10 @@ static bool start_assemble = false; static bool probing_insn_operands; +/* Global instruction table for APEX extensions. + Indexed by instruction format offset (XD, XS, XI, XC) plus sub-opcode. */ +struct riscv_opcode *arcv_apex_insns[ARCV_APEX_INSN_LIMIT]; + /* Set the default_isa_spec. Return 0 if the spec isn't supported. Otherwise, return 1. */ @@ -1770,6 +1774,18 @@ validate_riscv_insn (const struct riscv_opcode *opc, int length) goto unknown_validate_operand; } break; + case 'a': /* Vendor-specific (ARC-V) operands. */ + switch (*++oparg) + { + case 'd': USE_BITS (OP_MASK_RD, OP_SH_RD); break; + case 's': USE_BITS (OP_MASK_RS1, OP_SH_RS1); break; + case 't': USE_BITS (OP_MASK_RS2, OP_SH_RS2); break; + case 'k': used_bits |= ENCODE_ARCV_APEX_8BIT_IMM (-1U); break; + case 'j': used_bits |= ENCODE_ARCV_APEX_12BIT_IMM (-1U); break; + default: + goto unknown_validate_operand; + } + break; default: goto unknown_validate_operand; } @@ -2835,6 +2851,164 @@ static symbolS *deferred_sym_lastP; static symbolS *orphan_sym_rootP; static symbolS *orphan_sym_lastP; +/* Return true if INSN is the first entry of an APEX XS|XC pair + (i.e. the next contiguous entry has the same name and an XC mask). */ + +static bool +arcv_apex_xs_xc_pair_p (const struct riscv_opcode *insn) +{ + return (insn->mask == ARCV_APEX_MASK_XS + && insn[1].name != NULL + && strcmp (insn->name, insn[1].name) == 0 + && insn[1].mask == ARCV_APEX_MASK_XC); +} + +/* Validate operands of an APEX instruction. + + Verifies that operands match expected argument types for XD, XS, XI, + or XC APEX instruction formats. Ensures operand count matches, register + operands are valid GPRs, and immediate operands conform to constraints. + For XS|XC pairs, an out-of-range immediate requires rd == rs1 (the XC + encoding only has a single register field). Returns true if valid. */ + +static bool +arcv_apex_validate_insn (const char *operands, const struct riscv_opcode *insn) +{ + /* Skip non-APEX instructions. */ + if (insn == NULL + || (insn->mask != ARCV_APEX_MASK_XD + && insn->mask != ARCV_APEX_MASK_XS + && insn->mask != ARCV_APEX_MASK_XI + && insn->mask != ARCV_APEX_MASK_XC)) + return true; + + /* Make local copies for tokenization. */ + char *operands_copy = xstrdup (operands); + char *args_copy = xstrdup (insn->args); + bool ok = true; + + char *operand_tokens[3] = { NULL }; + char *arg_types[3] = { NULL }; + expressionS operand_exprs[3]; + + int operand_count = 0; + + /* Split operands into tokens (at most 3). */ + char *token = strtok (operands_copy, ","); + while (token && operand_count < 3) + { + operand_tokens[operand_count++] = token; + token = strtok (NULL, ","); + } + if (token) + operand_count++; + + /* Split expected argument types into tokens (at most 3). */ + int arg_count = 0; + token = strtok (args_copy, ","); + while (token && arg_count < 3) + { + arg_types[arg_count++] = token; + token = strtok (NULL, ","); + } + + /* Check if operand count matches the expected argument count. */ + if (arg_count != operand_count) + { + as_bad (_("expected %d operands but %d were specified"), + arg_count, operand_count); + ok = false; + } + else + { + for (int i = 0; i < arg_count && ok; i++) + { + const char *arg_type = arg_types[i]; + char *operand = operand_tokens[i]; + while (ISSPACE (*operand)) + operand++; + /* Skip the ARC-V APEX operand prefix "Xa". */ + arg_type += 2; + + my_getExpression (&operand_exprs[i], operand, false); + /* Check that immediate operands are constants. */ + if ((*arg_type == 'k' || *arg_type == 'j') + && operand_exprs[i].X_op != O_constant) + { + as_bad (_("operands do not conform to the " + "specified APEX format")); + ok = false; + } + else if (*arg_type != 'k' && *arg_type != 'j' + && !str_hash_find (reg_names_hash, operand)) + { + as_bad (_("operand must be a general-purpose " + "register")); + ok = false; + } + } + + /* For plain XS instructions (no XC fallback), check the 8-bit + immediate range here so the user gets a specific message + rather than "illegal operands" from the assembly phase. */ + if (ok && insn->mask == ARCV_APEX_MASK_XS + && !arcv_apex_xs_xc_pair_p (insn)) + { + for (int i = 0; i < arg_count && ok; i++) + { + const char *at = arg_types[i]; + if (at[0] == 'X' && at[1] == 'a' && at[2] == 'k') + { + if (operand_exprs[i].X_op == O_constant + && (operand_exprs[i].X_add_number < -128 + || operand_exprs[i].X_add_number > 127)) + { + as_bad (_("integer operand out of range; " + "should be from -128 to 127, " + "inclusive")); + ok = false; + } + } + } + } + + /* For XS|XC pairs: if the immediate exceeds the XS 8-bit range, + the assembler will fall through to the XC encoding which only + has a single register field (dest == src). Reject early if + the registers differ. */ + if (ok && arcv_apex_xs_xc_pair_p (insn) && arg_count == 3) + { + const char *arg2 = arg_types[2]; + if (arg2[0] == 'X' && arg2[1] == 'a' && arg2[2] == 'k') + { + if (operand_exprs[2].X_op == O_constant + && (operand_exprs[2].X_add_number < -128 + || operand_exprs[2].X_add_number > 127)) + { + const char *op0 = operand_tokens[0]; + const char *op1 = operand_tokens[1]; + while (ISSPACE (*op0)) + op0++; + while (ISSPACE (*op1)) + op1++; + if (strcmp (op0, op1) != 0) + { + as_bad (_("APEX XS|XC instruction needs identical " + "destination and source when the " + "immediate is outside the range " + "-128..127")); + ok = false; + } + } + } + } + } + + xfree (operands_copy); + xfree (args_copy); + return ok; +} + /* This routine assembles an instruction into its binary format. As a side effect, it sets the global variable imm_reloc to the type of relocation to do if one of the operands is an address expression. */ @@ -2871,6 +3045,10 @@ riscv_ip (char *str, struct riscv_cl_insn *ip, expressionS *imm_expr, insn = str_hash_find (hash, str); + /* Early validation for APEX instructions. */ + if (!arcv_apex_validate_insn (asarg, insn)) + return error; + probing_insn_operands = true; asargStart = asarg; @@ -4286,6 +4464,64 @@ riscv_ip (char *str, struct riscv_cl_insn *ip, expressionS *imm_expr, } break; + case 'a': /* Vendor-specific (ARC-V) operands. */ + switch (*++oparg) + { + case 'k': /* ARC-V APEX 8-bit immediate. */ + my_getExpression (imm_expr, asarg, false); + check_absolute_expr (ip, imm_expr, false); + if (imm_expr->X_add_number < -128 + || imm_expr->X_add_number > 127) + /* Out of 8-bit range. Break to try next variant + (e.g., XC encoding in XS|XC pairs). Validation + already checked this and provided user feedback. */ + break; + ip->insn_opcode + |= ENCODE_ARCV_APEX_8BIT_IMM (imm_expr->X_add_number); + asarg = expr_parse_end; + continue; + case 'j': /* ARC-V APEX 12-bit immediate. */ + my_getExpression (imm_expr, asarg, false); + check_absolute_expr (ip, imm_expr, false); + if (imm_expr->X_add_number < -2048 + || imm_expr->X_add_number > 2047) + as_bad (_("integer operand out of range; " + "should be from -2048 to 2047, " + "inclusive")); + ip->insn_opcode + |= ENCODE_ARCV_APEX_12BIT_IMM + (imm_expr->X_add_number); + asarg = expr_parse_end; + continue; + case 'd': /* ARC-V APEX destination register. */ + case 's': /* ARC-V APEX source register. */ + case 't': /* ARC-V APEX target register. */ + if (reg_lookup (&asarg, RCLASS_GPR, ®no)) + { + char c = *oparg; + if (*asarg == ' ') + ++asarg; + + switch (c) + { + case 's': + INSERT_OPERAND (RS1, *ip, regno); + break; + case 'd': + INSERT_OPERAND (RD, *ip, regno); + break; + case 't': + INSERT_OPERAND (RS2, *ip, regno); + break; + } + continue; + } + break; + default: + goto unknown_riscv_ip_operand; + } + break; + default: goto unknown_riscv_ip_operand; } @@ -5899,6 +6135,400 @@ s_variant_cc (int ignored ATTRIBUTE_UNUSED) elfsym->internal_elf_sym.st_other |= STO_RISCV_VARIANT_CC; } +/* Record INSN in the arcv_apex_insns table for the given format OFFSET + and function OPCODE. Returns false if that slot is already taken + (duplicate .extInstruction for the same encoding). */ + +static bool +arcv_apex_check_and_set_insn (struct riscv_opcode *insn, + unsigned int opcode, + unsigned int offset) +{ + if (arcv_apex_insns[offset + opcode]) + { + as_bad (_(".extInstruction '%s' duplicates opcode used by '%s'"), + insn->name, arcv_apex_insns[offset + opcode]->name); + return false; + } + arcv_apex_insns[offset + opcode] = insn; + return true; +} + +/* Create and get a read-only COMDAT section for an APEX instruction. + + Section names encode the instruction format flags (XD=1<<0, XS=1<<1, + XI=1<<2, XC=1<<3), followed by the fixed Custom-0 value (11) and the + instruction opcode. + + For example, an instruction declared as: + .extInstruction foo,7,XS,XC + maps to: + .riscvapex..11. + and concretely: + .riscvapex.10.11.7 + + The section is placed in a COMDAT group so that the linker keeps only + one copy when multiple compilation units define the same section. + The COMDAT group name mirrors the section name but uses a ".apex." + prefix instead of ".riscvapex.". */ + +static segT +arcv_apex_get_metadata_section (unsigned int insn_format, + unsigned int sub_opcode) +{ + /* Allocate buffer for full section name. */ + const char *section_name + = xasprintf (".riscvapex.%u.%u.%u", + insn_format, ARCV_APEX_CUSTOM0_OPCODE, sub_opcode); + + /* Create a new section with appropriate flags. */ + segT apex_section = subseg_new (section_name, 0); + bfd_set_section_flags (apex_section, + SEC_READONLY | SEC_HAS_CONTENTS | SEC_LINK_ONCE); + + /* Build the COMDAT group name for the section, prefixed with ".apex.". */ + const char *group_name + = xasprintf (".apex.%u.%u.%u", + insn_format, ARCV_APEX_CUSTOM0_OPCODE, sub_opcode); + + /* Attach the group name to the section. */ + elf_set_group_name (apex_section, group_name); + + return apex_section; +} + +/* Write APEX instruction metadata into the current section. + + Builds an apex_insn record with fixed fields, function code, + flags, and the instruction mnemonic. The record is padded to + maintain 16-bit alignment, ensuring correct layout in the + section. This section is later used by the disassembler to + decode the instruction. */ + +static void +arcv_apex_write_metadata (const char *insn_name, + unsigned int flags, + unsigned int sub_opcode) +{ + struct apex_insn apex; + size_t name_len = strlen (insn_name); + + /* NUL terminator, plus one extra zero byte if needed to + keep the total record length even. */ + size_t nul_pad = (name_len & 1) ? 1 : 2; + + size_t total_size = offsetof (struct apex_insn, name) + + name_len + nul_pad; + + apex.len = total_size; + apex.type = ARCV_APEX_METADATA_TYPE; + apex.opcode = ARCV_APEX_CUSTOM0_OPCODE; + apex.func_t = sub_opcode; + apex.flags = flags; + + /* Emit fixed fields. */ + char *where = frag_more (offsetof (struct apex_insn, name)); + memcpy (where, &apex, offsetof (struct apex_insn, name)); + + /* Emit instruction name. */ + where = frag_more (name_len); + memcpy (where, insn_name, name_len); + + /* Emit NUL terminator (+ alignment padding). */ + where = frag_more (nul_pad); + md_number_to_chars (where, 0x0, nul_pad); +} + +/* Allocate and register an APEX instruction. + + Allocates riscv_opcode structure(s), initializes them according to the + instruction format using the appropriate setup function, and inserts + them into the opcode hash table for later lookup during assembly. + + For combined XS|XC instructions, two contiguous entries are allocated + (XS first, then XC, followed by a NULL sentinel) so that riscv_ip's + opcode iteration loop naturally tries the XS encoding first and falls + through to the wider XC encoding when the immediate does not fit. */ + +static void +arcv_apex_register_insn (const char *insn_name, + unsigned int flags, + unsigned int sub_opcode) +{ + struct riscv_opcode *insn; + unsigned int offset = 0; + unsigned int fmt = flags & (APEX_FLAG_XD | APEX_FLAG_XS + | APEX_FLAG_XI | APEX_FLAG_XC); + unsigned int max_code; + void **hash_slot; + + if (str_hash_find (op_hash, insn_name) != NULL) + { + as_bad (_("instruction `%s' is already defined; " + "`.extInstruction' cannot reuse that name"), + insn_name); + xfree ((void *) insn_name); + return; + } + + if (fmt == APEX_FLAG_XD) + max_code = 255; + else if (fmt == APEX_FLAG_XS) + max_code = 63; + else if (fmt == (APEX_FLAG_XS | APEX_FLAG_XC) + || fmt == APEX_FLAG_XI || fmt == APEX_FLAG_XC) + max_code = 31; + else + { + as_bad (_("`.extInstruction' requires at least one of XD, XS, XI, XC")); + xfree ((void *) insn_name); + return; + } + + if (sub_opcode > max_code) + { + as_bad (_("APEX instruction function code out of range")); + xfree ((void *) insn_name); + return; + } + + if (fmt == (APEX_FLAG_XS | APEX_FLAG_XC)) + { + /* Allocate a contiguous pair of entries plus a NULL sentinel so + that riscv_ip's insn++ iteration finds both encodings. The + XS entry is tried first; its match_func rejects same-register + operands so that they always use the XC encoding. If the 8-bit + immediate does not fit, riscv_ip also falls through to the XC + (12-bit) entry. */ + struct riscv_opcode *entries = XCNEWVEC (struct riscv_opcode, 3); + struct riscv_opcode *xs_insn = &entries[0]; + struct riscv_opcode *xc_insn = &entries[1]; + + arcv_apex_init_dynamic_insn (xs_insn); + xs_insn->name = insn_name; + arcv_apex_setup_xs_insn (xs_insn, flags, sub_opcode); + xs_insn->match_func = arcv_apex_match_rd_ne_rs1; + + arcv_apex_init_dynamic_insn (xc_insn); + xc_insn->name = insn_name; + arcv_apex_setup_xc_insn (xc_insn, sub_opcode); + + /* entries[2] is zero-initialized (name == NULL) by XCNEWVEC, + which acts as the sentinel for the riscv_ip iteration. */ + + if (!arcv_apex_check_and_set_insn (xs_insn, sub_opcode, + ARCV_APEX_OFFSET_XS)) + { + xfree (entries); + xfree ((void *) insn_name); + return; + } + if (!arcv_apex_check_and_set_insn (xc_insn, sub_opcode, + ARCV_APEX_OFFSET_XC)) + { + arcv_apex_insns[sub_opcode + ARCV_APEX_OFFSET_XS] = NULL; + xfree (entries); + xfree ((void *) insn_name); + return; + } + + insn = xs_insn; + } + else + { + /* Allocate a 2-entry array: the instruction plus a zero sentinel + (name == NULL) so that riscv_ip's insn++ loop and helpers like + arcv_apex_xs_xc_pair_p can safely read insn[1]. */ + insn = XCNEWVEC (struct riscv_opcode, 2); + arcv_apex_init_dynamic_insn (insn); + insn->name = insn_name; + + switch (fmt) + { + case APEX_FLAG_XD: + arcv_apex_setup_xd_insn (insn, flags, sub_opcode); + offset = ARCV_APEX_OFFSET_XD; + break; + case APEX_FLAG_XS: + arcv_apex_setup_xs_insn (insn, flags, sub_opcode); + offset = ARCV_APEX_OFFSET_XS; + break; + case APEX_FLAG_XI: + arcv_apex_setup_xi_insn (insn, flags, sub_opcode); + offset = ARCV_APEX_OFFSET_XI; + break; + case APEX_FLAG_XC: + arcv_apex_setup_xc_insn (insn, sub_opcode); + offset = ARCV_APEX_OFFSET_XC; + break; + default: + as_bad (_("internal: bad APEX instruction format in registration")); + xfree (insn); + xfree ((void *) insn_name); + return; + } + + if (!arcv_apex_check_and_set_insn (insn, sub_opcode, offset)) + { + xfree (insn); + xfree ((void *) insn_name); + return; + } + } + + hash_slot = str_hash_insert (op_hash, insn->name, insn, 0); + if (hash_slot != NULL) + { + as_bad (_("internal: cannot register APEX instruction `%s'"), + insn_name); + if (fmt == (APEX_FLAG_XS | APEX_FLAG_XC)) + { + arcv_apex_insns[sub_opcode + ARCV_APEX_OFFSET_XS] = NULL; + arcv_apex_insns[sub_opcode + ARCV_APEX_OFFSET_XC] = NULL; + } + else + arcv_apex_insns[sub_opcode + offset] = NULL; + xfree (insn); + xfree ((void *) insn_name); + return; + } + + segT saved_seg = now_seg; + subsegT saved_subseg = now_subseg; + + segT apex_section = arcv_apex_get_metadata_section (flags & 0xF, sub_opcode); + subseg_set (apex_section, 0); + + arcv_apex_write_metadata (insn_name, flags, sub_opcode); + + subseg_set (saved_seg, saved_subseg); +} + +/* Parse an APEX .extInstruction directive. + + Syntax: .extInstruction , , + + The may include XD, XS, XI, XC, void, no_src0, and no_src1. + Validates attribute combinations and registers the instruction once + successfully parsed. */ + +static void +arcv_apex_section_parser (int ignore ATTRIBUTE_UNUSED) +{ + char *p, c, *insn_name; + char *insn_format; + unsigned int sub_opcode; + /* Skip leading whitespace. */ + SKIP_WHITESPACE (); + + p = input_line_pointer; + c = get_symbol_name (&p); + + insn_name = xstrdup (p); + restore_line_pointer (c); + + /* Convert mnemonic to lowercase for canonical form. */ + for (p = insn_name; *p; ++p) + *p = TOLOWER (*p); + + /* Expect a comma after mnemonic. */ + if (*input_line_pointer != ',') + { + as_bad (_("expected comma after instruction name")); + ignore_rest_of_line (); + xfree (insn_name); + return; + } + + input_line_pointer++; + /* Parse sub-opcode value. */ + sub_opcode = get_absolute_expression (); + + /* Expect a comma after function code. */ + if (*input_line_pointer != ',') + { + as_bad (_("expected comma after instruction opcode")); + ignore_rest_of_line (); + xfree (insn_name); + return; + } + + uint8_t flags = 0; + while (*input_line_pointer == ',') + { + input_line_pointer++; + + p = input_line_pointer; + c = get_symbol_name (&p); + insn_format = xstrdup (p); + + if (strcmp (insn_format, "XD") == 0) + flags |= APEX_FLAG_XD; + else if (strcmp (insn_format, "XS") == 0) + flags |= APEX_FLAG_XS; + else if (strcmp (insn_format, "XI") == 0) + flags |= (APEX_FLAG_XI | APEX_FLAG_NO_SRC1); + else if (strcmp (insn_format, "XC") == 0) + flags |= APEX_FLAG_XC; + else if (strcmp (insn_format, "void") == 0) + flags |= APEX_FLAG_VOID; + else if (strcmp (insn_format, "no_src0") == 0) + flags |= APEX_FLAG_NO_SRC0; + else if (strcmp (insn_format, "no_src1") == 0) + flags |= APEX_FLAG_NO_SRC1; + else + { + as_bad (_("unrecognized APEX attribute; must be one of " + "XD, XS, XI, XC, void, no_src0, no_src1")); + restore_line_pointer (c); + xfree (insn_format); + xfree (insn_name); + ignore_rest_of_line (); + return; + } + + restore_line_pointer (c); + xfree (insn_format); + } + + if (flags & APEX_FLAG_XD + && (flags & (APEX_FLAG_XS | APEX_FLAG_XI | APEX_FLAG_XC))) + { + as_bad (_("XD and non-XD APEX formats cannot be combined")); + xfree (insn_name); + ignore_rest_of_line (); + return; + } + + if ((flags & APEX_FLAG_VOID) && (flags & APEX_FLAG_XC)) + { + as_bad (_("XC and VOID APEX formats cannot be combined")); + xfree (insn_name); + ignore_rest_of_line (); + return; + } + + if (flags & APEX_FLAG_NO_SRC0 + && (flags & (APEX_FLAG_XS | APEX_FLAG_XI | APEX_FLAG_XC))) + { + as_bad (_("NO_SRC0 and non-XD APEX formats cannot be combined")); + xfree (insn_name); + ignore_rest_of_line (); + return; + } + + if (flags & APEX_FLAG_NO_SRC1 + && (flags & (APEX_FLAG_XS | APEX_FLAG_XC))) + { + as_bad (_("NO_SRC1 and non-XD/XI APEX formats cannot be combined")); + xfree (insn_name); + ignore_rest_of_line (); + return; + } + + arcv_apex_register_insn (insn_name, flags, sub_opcode); +} + /* RISC-V pseudo-ops table. */ static const pseudo_typeS riscv_pseudo_table[] = { @@ -5915,6 +6545,7 @@ static const pseudo_typeS riscv_pseudo_table[] = {"variant_cc", s_variant_cc, 0}, {"float16", float_cons, 'h'}, {"bfloat16", float_cons, 'b'}, + {"extinstruction", arcv_apex_section_parser, 0}, { NULL, NULL, 0 }, }; diff --git a/gas/doc/c-riscv.texi b/gas/doc/c-riscv.texi index bd296c3de04..39a588282c0 100644 --- a/gas/doc/c-riscv.texi +++ b/gas/doc/c-riscv.texi @@ -265,6 +265,59 @@ Floating point constructors for the bfloat16 type, example usage: .bfloat16 0b:ffc1 @end smallexample +@cindex @code{.extInstruction} directive, RISC-V +@cindex ARC-V APEX instructions +@item .extInstruction @var{name}, @var{opcode}, @var{attrs}@dots{} +Define a dynamic APEX instruction that uses the Custom-0 encoding space. +The @var{name} is the mnemonic used in subsequent assembly. The +@var{opcode} is the function code (sub-opcode) whose valid range depends +on the format. The @var{attrs} are a comma-separated list drawn from: + +@table @code +@item XD +XD format (3 register operands, 8-bit sub-opcode, range 0--255). +@item XS +XS format (2 registers + 8-bit signed immediate, 6-bit sub-opcode, +range 0--63). +@item XI +XI format (1 register + 12-bit signed immediate, 5-bit sub-opcode, +range 0--31). +@item XC +XC format (1 register acting as both destination and source + +12-bit signed immediate, 5-bit sub-opcode, range 0--31). +@item void +Omit the destination register from the operand list. +@item no_src0 +Omit the first source register from the operand list. +@item no_src1 +Omit the second source register (or immediate) from the operand list. +@end table + +Exactly one of @code{XD}, @code{XS}, @code{XI}, or @code{XC} must be +specified. @code{XS} and @code{XC} may be combined; in that case the +assembler uses the XS encoding when the destination and source registers +differ (and the immediate fits in 8 bits), and the XC encoding when the +registers are the same or the immediate requires 12 bits. + +Examples: + +@smallexample + .extInstruction myalu, 1, XD + myalu a0, a1, a2 + + .extInstruction myimm, 5, XS + myimm a0, a1, 42 + + .extInstruction myflex, 3, XS, XC + myflex a0, a1, 10 + myflex a0, a0, 1000 +@end smallexample + +The assembler emits metadata about each @code{.extInstruction} into +ELF sections named @code{.riscvapex.@var{fmt}.@var{custom0}.@var{opcode}}, +which the disassembler reads to reconstruct instruction names and +operand formats. + @end table @node RISC-V-Modifiers diff --git a/gas/testsuite/gas/riscv/x-arcv-apex-01.d b/gas/testsuite/gas/riscv/x-arcv-apex-01.d new file mode 100644 index 00000000000..e3faa8bd632 --- /dev/null +++ b/gas/testsuite/gas/riscv/x-arcv-apex-01.d @@ -0,0 +1,18 @@ +#source: x-arcv-apex-01.s +#objdump: -d + +.*:[ ]+file format .* + + +Disassembly of section .text: + +0+[0-9a-f]+ <.text>: +[ ]+[0-9a-f]+:[ ]+00c5c50b[ ]+.* +[ ]+[0-9a-f]+:[ ]+02c5800b[ ]+.* +[ ]+[0-9a-f]+:[ ]+0205c00b[ ]+.* +[ ]+[0-9a-f]+:[ ]+0400000b[ ]+.* +[ ]+[0-9a-f]+:[ ]+0b15b50b[ ]+.* +[ ]+[0-9a-f]+:[ ]+0b15d00b[ ]+.* +[ ]+[0-9a-f]+:[ ]+0163a50b[ ]+.* +[ ]+[0-9a-f]+:[ ]+0164200b[ ]+.* +[ ]+[0-9a-f]+:[ ]+0214e50b[ ]+.* diff --git a/gas/testsuite/gas/riscv/x-arcv-apex-01.s b/gas/testsuite/gas/riscv/x-arcv-apex-01.s new file mode 100644 index 00000000000..2090bf28a27 --- /dev/null +++ b/gas/testsuite/gas/riscv/x-arcv-apex-01.s @@ -0,0 +1,19 @@ + .extInstruction foo0,1,XD + .extInstruction foo1,2,XD,void + .extInstruction foo2,3,XD,void,no_src1 + .extInstruction foo3,4,XD,void,no_src0,no_src1 + .extInstruction foo4,5,XS + .extInstruction foo5,6,XS,void + .extInstruction foo6,7,XI + .extInstruction foo7,8,XI,void + .extInstruction foo8,9,XC + + foo0 a0,a1,a2 + foo1 a1,a2 + foo2 a1 + foo3 + foo4 a0,a1,11 + foo5 a1,11 + foo6 a0,22 + foo7 22 + foo8 a0,a0,33 diff --git a/gas/testsuite/gas/riscv/x-arcv-apex-02.d b/gas/testsuite/gas/riscv/x-arcv-apex-02.d new file mode 100644 index 00000000000..6bb08202e2a --- /dev/null +++ b/gas/testsuite/gas/riscv/x-arcv-apex-02.d @@ -0,0 +1,13 @@ +#source: x-arcv-apex-02.s +#objdump: -d + +.*:[ ]+file format .* + + +Disassembly of section .text: + +0+[0-9a-f]+ <.text>: +[ ]+[0-9a-f]+:[ ]+0020e50b[ ]+.* +[ ]+[0-9a-f]+:[ ]+0205b50b[ ]+.* +[ ]+[0-9a-f]+:[ ]+1000e50b[ ]+.* +[ ]+[0-9a-f]+:[ ]+0ff0e50b[ ]+.* diff --git a/gas/testsuite/gas/riscv/x-arcv-apex-02.s b/gas/testsuite/gas/riscv/x-arcv-apex-02.s new file mode 100644 index 00000000000..2fd0da33575 --- /dev/null +++ b/gas/testsuite/gas/riscv/x-arcv-apex-02.s @@ -0,0 +1,6 @@ + .extInstruction foo,1,XS,XC + + foo a0,a0,2 + foo a0,a1,2 + foo a0,a0,256 + foo a0,a0,255 diff --git a/gas/testsuite/gas/riscv/x-arcv-apex-03.d b/gas/testsuite/gas/riscv/x-arcv-apex-03.d new file mode 100644 index 00000000000..fc3bc432de4 --- /dev/null +++ b/gas/testsuite/gas/riscv/x-arcv-apex-03.d @@ -0,0 +1,46 @@ +#source: x-arcv-apex-01.s +#objdump: -s + +.*:[ ]+file format .* + +Contents of section .group: + 0000 01000000 0d000000.* +Contents of section .group: + 0000 01000000 0e000000.* +Contents of section .group: + 0000 01000000 0f000000.* +Contents of section .group: + 0000 01000000 10000000.* +Contents of section .group: + 0000 01000000 11000000.* +Contents of section .group: + 0000 01000000 12000000.* +Contents of section .group: + 0000 01000000 13000000.* +Contents of section .group: + 0000 01000000 14000000.* +Contents of section .group: + 0000 01000000 15000000.* +Contents of section \.text: + 0000 0bc5c500 0b80c502 0bc00502 0b000004.* + 0010 0bb5150b 0bd0150b 0ba56301 0b206401.* + 0020 0be51402.* +Contents of section \.riscvapex\.1\.11\.1: + 0000 0c010b01 0100666f 6f300000.* +Contents of section \.riscvapex\.1\.11\.2: + 0000 0c010b02 1100666f 6f310000.* +Contents of section \.riscvapex\.1\.11\.3: + 0000 0c010b03 5100666f 6f320000.* +Contents of section \.riscvapex\.1\.11\.4: + 0000 0c010b04 7100666f 6f330000.* +Contents of section \.riscvapex\.2\.11\.5: + 0000 0c010b05 0200666f 6f340000.* +Contents of section \.riscvapex\.2\.11\.6: + 0000 0c010b06 1200666f 6f350000.* +Contents of section \.riscvapex\.4\.11\.7: + 0000 0c010b07 4400666f 6f360000.* +Contents of section \.riscvapex\.4\.11\.8: + 0000 0c010b08 5400666f 6f370000.* +Contents of section \.riscvapex\.8\.11\.9: + 0000 0c010b09 0800666f 6f380000.* +#pass diff --git a/gas/testsuite/gas/riscv/x-arcv-apex-04.d b/gas/testsuite/gas/riscv/x-arcv-apex-04.d new file mode 100644 index 00000000000..f62d160a30b --- /dev/null +++ b/gas/testsuite/gas/riscv/x-arcv-apex-04.d @@ -0,0 +1,15 @@ +#source: x-arcv-apex-04.s +#objdump: -d + +.*:[ ]+file format .* + + +Disassembly of section .text: + +0+[0-9a-f]+ <.text>: +[ ]+[0-9a-f]+:[ ]+8005b50b[ ]+.* +[ ]+[0-9a-f]+:[ ]+7f05b50b[ ]+.* +[ ]+[0-9a-f]+:[ ]+8000a50b[ ]+.* +[ ]+[0-9a-f]+:[ ]+7ff0a50b[ ]+.* +[ ]+[0-9a-f]+:[ ]+8000e50b[ ]+.* +[ ]+[0-9a-f]+:[ ]+7ff0e50b[ ]+.* diff --git a/gas/testsuite/gas/riscv/x-arcv-apex-04.s b/gas/testsuite/gas/riscv/x-arcv-apex-04.s new file mode 100644 index 00000000000..c3cd0e2fc46 --- /dev/null +++ b/gas/testsuite/gas/riscv/x-arcv-apex-04.s @@ -0,0 +1,10 @@ + .extInstruction foo0,1,XS + .extInstruction foo1,1,XI + .extInstruction foo2,1,XC + + foo0 a0,a1,-128 + foo0 a0,a1,127 + foo1 a0,-2048 + foo1 a0,2047 + foo2 a0,a0,-2048 + foo2 a0,a0,2047 diff --git a/gas/testsuite/gas/riscv/x-arcv-apex-fail-01.d b/gas/testsuite/gas/riscv/x-arcv-apex-fail-01.d new file mode 100644 index 00000000000..fe85c681d0f --- /dev/null +++ b/gas/testsuite/gas/riscv/x-arcv-apex-fail-01.d @@ -0,0 +1 @@ +#error_output: x-arcv-apex-fail-01.l diff --git a/gas/testsuite/gas/riscv/x-arcv-apex-fail-01.l b/gas/testsuite/gas/riscv/x-arcv-apex-fail-01.l new file mode 100644 index 00000000000..43a5a6adaa7 --- /dev/null +++ b/gas/testsuite/gas/riscv/x-arcv-apex-fail-01.l @@ -0,0 +1,2 @@ +.*: Assembler messages: +.*: Error: unrecognized APEX attribute; must be one of XD, XS, XI, XC, void, no_src0, no_src1 diff --git a/gas/testsuite/gas/riscv/x-arcv-apex-fail-01.s b/gas/testsuite/gas/riscv/x-arcv-apex-fail-01.s new file mode 100644 index 00000000000..d0a9095cd1c --- /dev/null +++ b/gas/testsuite/gas/riscv/x-arcv-apex-fail-01.s @@ -0,0 +1 @@ + .extInstruction foo,1,XY diff --git a/gas/testsuite/gas/riscv/x-arcv-apex-fail-02.d b/gas/testsuite/gas/riscv/x-arcv-apex-fail-02.d new file mode 100644 index 00000000000..9366a34b7a0 --- /dev/null +++ b/gas/testsuite/gas/riscv/x-arcv-apex-fail-02.d @@ -0,0 +1 @@ +#error_output: x-arcv-apex-fail-02.l diff --git a/gas/testsuite/gas/riscv/x-arcv-apex-fail-02.l b/gas/testsuite/gas/riscv/x-arcv-apex-fail-02.l new file mode 100644 index 00000000000..fc7d3cae283 --- /dev/null +++ b/gas/testsuite/gas/riscv/x-arcv-apex-fail-02.l @@ -0,0 +1,5 @@ +.*: Assembler messages: +.*: Error: NO_SRC0 and non-XD APEX formats cannot be combined +.*: Error: NO_SRC0 and non-XD APEX formats cannot be combined +.*: Error: XC and VOID APEX formats cannot be combined + diff --git a/gas/testsuite/gas/riscv/x-arcv-apex-fail-02.s b/gas/testsuite/gas/riscv/x-arcv-apex-fail-02.s new file mode 100644 index 00000000000..48d1e2da885 --- /dev/null +++ b/gas/testsuite/gas/riscv/x-arcv-apex-fail-02.s @@ -0,0 +1,3 @@ + .extInstruction foo0,1,XS,no_src0,no_src1 + .extInstruction foo1,1,XI,no_src0,no_src1 + .extInstruction foo2,1,XC,void,no_src0,no_src1 diff --git a/gas/testsuite/gas/riscv/x-arcv-apex-fail-03.d b/gas/testsuite/gas/riscv/x-arcv-apex-fail-03.d new file mode 100644 index 00000000000..f72280a88b3 --- /dev/null +++ b/gas/testsuite/gas/riscv/x-arcv-apex-fail-03.d @@ -0,0 +1 @@ +#error_output: x-arcv-apex-fail-03.l diff --git a/gas/testsuite/gas/riscv/x-arcv-apex-fail-03.l b/gas/testsuite/gas/riscv/x-arcv-apex-fail-03.l new file mode 100644 index 00000000000..7573ed9ea66 --- /dev/null +++ b/gas/testsuite/gas/riscv/x-arcv-apex-fail-03.l @@ -0,0 +1,9 @@ +.*: Assembler messages: +.*: Error: integer operand out of range; should be from -128 to 127, inclusive +.*: Error: unrecognized opcode `foo0' +.*: Error: integer operand out of range; should be from -128 to 127, inclusive +.*: Error: unrecognized opcode `foo0' +.*: Error: integer operand out of range; should be from -2048 to 2047, inclusive +.*: Error: integer operand out of range; should be from -2048 to 2047, inclusive +.*: Error: integer operand out of range; should be from -2048 to 2047, inclusive +.*: Error: integer operand out of range; should be from -2048 to 2047, inclusive diff --git a/gas/testsuite/gas/riscv/x-arcv-apex-fail-03.s b/gas/testsuite/gas/riscv/x-arcv-apex-fail-03.s new file mode 100644 index 00000000000..b718ac08816 --- /dev/null +++ b/gas/testsuite/gas/riscv/x-arcv-apex-fail-03.s @@ -0,0 +1,12 @@ + .extInstruction foo0,1,XS + .extInstruction foo1,2,XI + .extInstruction foo2,3,XC + + foo0 a0,a1,-129 + foo0 a0,a1,128 + + foo1 a0,-2049 + foo1 a0,2048 + + foo2 a0,a0,-2049 + foo2 a0,a0,2048 diff --git a/gas/testsuite/gas/riscv/x-arcv-apex-fail-04.d b/gas/testsuite/gas/riscv/x-arcv-apex-fail-04.d new file mode 100644 index 00000000000..942e11e5503 --- /dev/null +++ b/gas/testsuite/gas/riscv/x-arcv-apex-fail-04.d @@ -0,0 +1 @@ +#error_output: x-arcv-apex-fail-04.l diff --git a/gas/testsuite/gas/riscv/x-arcv-apex-fail-04.l b/gas/testsuite/gas/riscv/x-arcv-apex-fail-04.l new file mode 100644 index 00000000000..a46a42d3148 --- /dev/null +++ b/gas/testsuite/gas/riscv/x-arcv-apex-fail-04.l @@ -0,0 +1,3 @@ +.*: Assembler messages: +.*: Error: expected comma after instruction name +.*: Error: expected comma after instruction opcode diff --git a/gas/testsuite/gas/riscv/x-arcv-apex-fail-04.s b/gas/testsuite/gas/riscv/x-arcv-apex-fail-04.s new file mode 100644 index 00000000000..72a03e09205 --- /dev/null +++ b/gas/testsuite/gas/riscv/x-arcv-apex-fail-04.s @@ -0,0 +1,2 @@ + .extInstruction foo + .extInstruction bar,1 diff --git a/gas/testsuite/gas/riscv/x-arcv-apex-fail-05.d b/gas/testsuite/gas/riscv/x-arcv-apex-fail-05.d new file mode 100644 index 00000000000..76244da553c --- /dev/null +++ b/gas/testsuite/gas/riscv/x-arcv-apex-fail-05.d @@ -0,0 +1 @@ +#error_output: x-arcv-apex-fail-05.l diff --git a/gas/testsuite/gas/riscv/x-arcv-apex-fail-05.l b/gas/testsuite/gas/riscv/x-arcv-apex-fail-05.l new file mode 100644 index 00000000000..83c052e4099 --- /dev/null +++ b/gas/testsuite/gas/riscv/x-arcv-apex-fail-05.l @@ -0,0 +1,3 @@ +.*: Assembler messages: +.*: Error: expected 3 operands but 2 were specified +#... \ No newline at end of file diff --git a/gas/testsuite/gas/riscv/x-arcv-apex-fail-05.s b/gas/testsuite/gas/riscv/x-arcv-apex-fail-05.s new file mode 100644 index 00000000000..ded33d90c9e --- /dev/null +++ b/gas/testsuite/gas/riscv/x-arcv-apex-fail-05.s @@ -0,0 +1,3 @@ + .extInstruction foo,1,XD + + foo a0,a1 diff --git a/gas/testsuite/gas/riscv/x-arcv-apex-fail-06.d b/gas/testsuite/gas/riscv/x-arcv-apex-fail-06.d new file mode 100644 index 00000000000..7483f348395 --- /dev/null +++ b/gas/testsuite/gas/riscv/x-arcv-apex-fail-06.d @@ -0,0 +1 @@ +#error_output: x-arcv-apex-fail-06.l diff --git a/gas/testsuite/gas/riscv/x-arcv-apex-fail-06.l b/gas/testsuite/gas/riscv/x-arcv-apex-fail-06.l new file mode 100644 index 00000000000..477fb3e0dc1 --- /dev/null +++ b/gas/testsuite/gas/riscv/x-arcv-apex-fail-06.l @@ -0,0 +1,7 @@ +.*: Assembler messages: +.*: Error: operands do not conform to the specified APEX format +#... +.*: Error: operands do not conform to the specified APEX format +#... +.*: Error: operands do not conform to the specified APEX format +#... diff --git a/gas/testsuite/gas/riscv/x-arcv-apex-fail-06.s b/gas/testsuite/gas/riscv/x-arcv-apex-fail-06.s new file mode 100644 index 00000000000..27991596a58 --- /dev/null +++ b/gas/testsuite/gas/riscv/x-arcv-apex-fail-06.s @@ -0,0 +1,7 @@ + .extInstruction foo,1,XS + .extInstruction bar,1,XI + .extInstruction baz,1,XC + + foo a0,a1,a2 + bar a3,a4 + baz a5,a6,a7 diff --git a/gas/testsuite/gas/riscv/x-arcv-apex-fail-07.d b/gas/testsuite/gas/riscv/x-arcv-apex-fail-07.d new file mode 100644 index 00000000000..149f7877e2c --- /dev/null +++ b/gas/testsuite/gas/riscv/x-arcv-apex-fail-07.d @@ -0,0 +1 @@ +#error_output: x-arcv-apex-fail-07.l diff --git a/gas/testsuite/gas/riscv/x-arcv-apex-fail-07.l b/gas/testsuite/gas/riscv/x-arcv-apex-fail-07.l new file mode 100644 index 00000000000..f49a39b4b06 --- /dev/null +++ b/gas/testsuite/gas/riscv/x-arcv-apex-fail-07.l @@ -0,0 +1,9 @@ +.*: Assembler messages: +.*: Error: operand must be a general-purpose register +#... +.*: Error: operand must be a general-purpose register +#... +.*: Error: operand must be a general-purpose register +#... +.*: Error: operand must be a general-purpose register +#... diff --git a/gas/testsuite/gas/riscv/x-arcv-apex-fail-07.s b/gas/testsuite/gas/riscv/x-arcv-apex-fail-07.s new file mode 100644 index 00000000000..e18a09f643a --- /dev/null +++ b/gas/testsuite/gas/riscv/x-arcv-apex-fail-07.s @@ -0,0 +1,9 @@ + .extInstruction foo0,1,XD + .extInstruction foo1,1,XS + .extInstruction foo2,1,XI + .extInstruction foo3,1,XC + + foo0 a0,a1,r2 + foo1 a0,r1,1 + foo2 r0,1 + foo3 a0,r0,1 diff --git a/gas/testsuite/gas/riscv/x-arcv-apex-fail-08.d b/gas/testsuite/gas/riscv/x-arcv-apex-fail-08.d new file mode 100644 index 00000000000..4a1f774f178 --- /dev/null +++ b/gas/testsuite/gas/riscv/x-arcv-apex-fail-08.d @@ -0,0 +1 @@ +#error_output: x-arcv-apex-fail-08.l diff --git a/gas/testsuite/gas/riscv/x-arcv-apex-fail-08.l b/gas/testsuite/gas/riscv/x-arcv-apex-fail-08.l new file mode 100644 index 00000000000..53454166897 --- /dev/null +++ b/gas/testsuite/gas/riscv/x-arcv-apex-fail-08.l @@ -0,0 +1,5 @@ +.*: Assembler messages: +.*: Error: .extInstruction 'bar1' duplicates opcode used by 'foo1' +.*: Error: .extInstruction 'baz1' duplicates opcode used by 'foo1' +.*: Error: .extInstruction 'bar2' duplicates opcode used by 'foo2' +.*: Error: .extInstruction 'baz2' duplicates opcode used by 'foo2' diff --git a/gas/testsuite/gas/riscv/x-arcv-apex-fail-08.s b/gas/testsuite/gas/riscv/x-arcv-apex-fail-08.s new file mode 100644 index 00000000000..3c75537861a --- /dev/null +++ b/gas/testsuite/gas/riscv/x-arcv-apex-fail-08.s @@ -0,0 +1,7 @@ + .extInstruction foo1,1,XS,XC + .extInstruction bar1,1,XC + .extInstruction baz1,1,XS + + .extInstruction foo2,2,XC,XS + .extInstruction bar2,2,XC + .extInstruction baz2,2,XS diff --git a/gas/testsuite/gas/riscv/x-arcv-apex-fail-09.d b/gas/testsuite/gas/riscv/x-arcv-apex-fail-09.d new file mode 100644 index 00000000000..52528816a73 --- /dev/null +++ b/gas/testsuite/gas/riscv/x-arcv-apex-fail-09.d @@ -0,0 +1 @@ +#error_output: x-arcv-apex-fail-09.l diff --git a/gas/testsuite/gas/riscv/x-arcv-apex-fail-09.l b/gas/testsuite/gas/riscv/x-arcv-apex-fail-09.l new file mode 100644 index 00000000000..66fa6c1afcf --- /dev/null +++ b/gas/testsuite/gas/riscv/x-arcv-apex-fail-09.l @@ -0,0 +1,3 @@ +.*: Assembler messages: +.*: Error: instruction `add' is already defined; `\.extInstruction' cannot reuse that name +#... diff --git a/gas/testsuite/gas/riscv/x-arcv-apex-fail-09.s b/gas/testsuite/gas/riscv/x-arcv-apex-fail-09.s new file mode 100644 index 00000000000..b9a2c27b142 --- /dev/null +++ b/gas/testsuite/gas/riscv/x-arcv-apex-fail-09.s @@ -0,0 +1 @@ + .extInstruction add,1,XS diff --git a/gas/testsuite/gas/riscv/x-arcv-apex-fail-10.d b/gas/testsuite/gas/riscv/x-arcv-apex-fail-10.d new file mode 100644 index 00000000000..b11459a30db --- /dev/null +++ b/gas/testsuite/gas/riscv/x-arcv-apex-fail-10.d @@ -0,0 +1 @@ +#error_output: x-arcv-apex-fail-10.l diff --git a/gas/testsuite/gas/riscv/x-arcv-apex-fail-10.l b/gas/testsuite/gas/riscv/x-arcv-apex-fail-10.l new file mode 100644 index 00000000000..4fba5d3a59f --- /dev/null +++ b/gas/testsuite/gas/riscv/x-arcv-apex-fail-10.l @@ -0,0 +1,3 @@ +.*: Assembler messages: +.*: Error: instruction `fooapex' is already defined; `\.extInstruction' cannot reuse that name +#... diff --git a/gas/testsuite/gas/riscv/x-arcv-apex-fail-10.s b/gas/testsuite/gas/riscv/x-arcv-apex-fail-10.s new file mode 100644 index 00000000000..4e067ce5677 --- /dev/null +++ b/gas/testsuite/gas/riscv/x-arcv-apex-fail-10.s @@ -0,0 +1,2 @@ + .extInstruction fooapex,1,XS + .extInstruction fooapex,2,XS diff --git a/include/opcode/riscv.h b/include/opcode/riscv.h index de105f5df8b..fdb23c0958d 100644 --- a/include/opcode/riscv.h +++ b/include/opcode/riscv.h @@ -732,4 +732,72 @@ extern const struct riscv_opcode riscv_insn_types[]; extern unsigned int riscv_get_sp_base (insn_t, unsigned int); +extern int arcv_apex_match_rd_ne_rs1 (const struct riscv_opcode *, insn_t); +extern void arcv_apex_init_dynamic_insn (struct riscv_opcode *); +extern void arcv_apex_setup_xd_insn (struct riscv_opcode *, unsigned int, + unsigned int); +extern void arcv_apex_setup_xs_insn (struct riscv_opcode *, unsigned int, + unsigned int); +extern void arcv_apex_setup_xi_insn (struct riscv_opcode *, unsigned int, + unsigned int); +extern void arcv_apex_setup_xc_insn (struct riscv_opcode *, unsigned int); + +/* ARC-V APEX instruction format flags. Used by .extInstruction directive + and metadata serialization/deserialization. */ +enum apex_flags { + APEX_FLAG_NONE = 0, + APEX_FLAG_XD = 1 << 0, + APEX_FLAG_XS = 1 << 1, + APEX_FLAG_XI = 1 << 2, + APEX_FLAG_XC = 1 << 3, + APEX_FLAG_VOID = 1 << 4, + APEX_FLAG_NO_SRC0 = 1 << 5, + APEX_FLAG_NO_SRC1 = 1 << 6, +}; + +/* ARC-V APEX instruction metadata record. Serialized in ELF .riscvapex.* + sections and read by the disassembler. */ +struct apex_insn +{ + uint8_t len; + uint8_t type; + uint8_t opcode; + uint8_t func_t; + uint16_t flags; + char name[1]; +}; + +/* The XD-type has 8 function bits encoding up to 256 instructions. + The XS-type has 6 function bits encoding up to 64 instructions. + Both the XI-type and the XC-type have 5 function bits each encoding up + to 32 instructions respectively. Thus giving a total of 384 possible + different instructions. */ +#define ARCV_APEX_INSN_LIMIT 384 +#define ARCV_APEX_OFFSET_XD 0 /* 256 entries. */ +#define ARCV_APEX_OFFSET_XS (ARCV_APEX_OFFSET_XD + 256) /* 0 + 256 = 256 */ +#define ARCV_APEX_OFFSET_XI (ARCV_APEX_OFFSET_XS + 64) /* 256 + 64 = 320 */ +#define ARCV_APEX_OFFSET_XC (ARCV_APEX_OFFSET_XI + 32) /* 320 + 32 = 352 */ + +/* Fixed encoding bits that distinguish XS, XI, and XC formats. */ +#define ARCV_APEX_XS_FIXED_BITS 0x1000 +#define ARCV_APEX_XI_FIXED_BITS 0x2000 +#define ARCV_APEX_XC_FIXED_BITS 0x6000 + +#define ARCV_APEX_MASK_XD 0xFE00407F +#define ARCV_APEX_MASK_XS 0xF0707F +#define ARCV_APEX_MASK_XI 0xFA07F +#define ARCV_APEX_MASK_XC 0xFE07F + +/* RISC-V Custom-0 major opcode used by ARC-V APEX instructions. */ +#define ARCV_APEX_CUSTOM0_OPCODE 0xb + +/* Metadata record type for APEX instructions. */ +#define ARCV_APEX_METADATA_TYPE 1 + +#define ENCODE_ARCV_APEX_8BIT_IMM(x) \ + (RV_X(x, 0, 8) << 24) + +#define ENCODE_ARCV_APEX_12BIT_IMM(x) \ + (RV_X(x, 0, 12) << 20) + #endif /* _RISCV_H_ */ diff --git a/ld/testsuite/ld-riscv-elf/ld-riscv-elf.exp b/ld/testsuite/ld-riscv-elf/ld-riscv-elf.exp index 8e26ccff10a..5a145628bdf 100644 --- a/ld/testsuite/ld-riscv-elf/ld-riscv-elf.exp +++ b/ld/testsuite/ld-riscv-elf/ld-riscv-elf.exp @@ -37,6 +37,14 @@ proc riscv_choose_lp64_emul {} { return "elf64lriscv" } +proc riscv_choose_64_or_32_emul {} { + if { [istarget "riscv64*-*"] } { + return [riscv_choose_lp64_emul] + } else { + return [riscv_choose_ilp32_emul] + } +} + # target: rv32 or rv64. # output: Which output you want? (exe, pie, .so) proc run_dump_test_ifunc { name target output} { @@ -174,6 +182,8 @@ if [istarget "riscv*-*-*"] { run_dump_test "uleb128" run_dump_test "pr31179" run_dump_test "pr31179-r" + run_dump_test "x-arcv-apex-01" + run_dump_test "x-arcv-apex-02" run_ld_link_tests [list \ [list "Weak reference 32" "-T weakref.ld -m[riscv_choose_ilp32_emul]" "" \ "-march=rv32i -mabi=ilp32" {weakref32.s} \ diff --git a/ld/testsuite/ld-riscv-elf/x-arcv-apex-01-a.s b/ld/testsuite/ld-riscv-elf/x-arcv-apex-01-a.s new file mode 100644 index 00000000000..0d2a4f72f9d --- /dev/null +++ b/ld/testsuite/ld-riscv-elf/x-arcv-apex-01-a.s @@ -0,0 +1,8 @@ + .extern func_1 + .extern func_2 + .globl _start + + _start: + call func_1 + call func_2 + ret diff --git a/ld/testsuite/ld-riscv-elf/x-arcv-apex-01-b.s b/ld/testsuite/ld-riscv-elf/x-arcv-apex-01-b.s new file mode 100644 index 00000000000..b5073a941fa --- /dev/null +++ b/ld/testsuite/ld-riscv-elf/x-arcv-apex-01-b.s @@ -0,0 +1,21 @@ + .extInstruction foo0,1,XD + .extInstruction foo1,2,XD,void + .extInstruction foo2,3,XD,void,no_src1 + .extInstruction foo3,4,XD,void,no_src0,no_src1 + .extInstruction foo4,5,XS + .extInstruction foo5,6,XS,void + .extInstruction foo6,7,XI + .extInstruction foo7,8,XI,void + .extInstruction foo8,9,XC + + .globl func_1 + func_1: + foo0 a0,a1,a2 + foo1 a1,a2 + foo2 a1 + foo3 + foo4 a0,a1,11 + foo5 a1,11 + foo6 a0,22 + foo7 22 + foo8 a0,a0,33 diff --git a/ld/testsuite/ld-riscv-elf/x-arcv-apex-01-c.s b/ld/testsuite/ld-riscv-elf/x-arcv-apex-01-c.s new file mode 100644 index 00000000000..58fce1a4607 --- /dev/null +++ b/ld/testsuite/ld-riscv-elf/x-arcv-apex-01-c.s @@ -0,0 +1,21 @@ + .extInstruction foo0,1,XD + .extInstruction foo1,2,XD,void + .extInstruction foo2,3,XD,void,no_src1 + .extInstruction foo3,4,XD,void,no_src0,no_src1 + .extInstruction foo4,5,XS + .extInstruction foo5,6,XS,void + .extInstruction foo6,7,XI + .extInstruction foo7,8,XI,void + .extInstruction foo8,9,XC + + .globl func_2 + func_2: + foo0 a0,a1,a2 + foo1 a1,a2 + foo2 a1 + foo3 + foo4 a0,a1,11 + foo5 a1,11 + foo6 a0,22 + foo7 22 + foo8 a0,a0,33 diff --git a/ld/testsuite/ld-riscv-elf/x-arcv-apex-01.d b/ld/testsuite/ld-riscv-elf/x-arcv-apex-01.d new file mode 100644 index 00000000000..e5b407e0889 --- /dev/null +++ b/ld/testsuite/ld-riscv-elf/x-arcv-apex-01.d @@ -0,0 +1,32 @@ +#source: x-arcv-apex-01-a.s +#source: x-arcv-apex-01-b.s +#source: x-arcv-apex-01-c.s +#ld: -m[riscv_choose_64_or_32_emul] +#objdump: -s + +.*:[ ]+file format .* + +#... +Contents of section \.text: +#... +Contents of section \.riscv\.attributes: +#... +Contents of section .riscvapex.1.11.1: + 0000 0c010b01 0100666f 6f300000.* +Contents of section .riscvapex.1.11.2: + 0000 0c010b02 1100666f 6f310000.* +Contents of section .riscvapex.1.11.3: + 0000 0c010b03 5100666f 6f320000.* +Contents of section .riscvapex.1.11.4: + 0000 0c010b04 7100666f 6f330000.* +Contents of section .riscvapex.2.11.5: + 0000 0c010b05 0200666f 6f340000.* +Contents of section .riscvapex.2.11.6: + 0000 0c010b06 1200666f 6f350000.* +Contents of section .riscvapex.4.11.7: + 0000 0c010b07 4400666f 6f360000.* +Contents of section .riscvapex.4.11.8: + 0000 0c010b08 5400666f 6f370000.* +Contents of section .riscvapex.8.11.9: + 0000 0c010b09 0800666f 6f380000.* +#pass diff --git a/ld/testsuite/ld-riscv-elf/x-arcv-apex-02.d b/ld/testsuite/ld-riscv-elf/x-arcv-apex-02.d new file mode 100644 index 00000000000..abebb3566e6 --- /dev/null +++ b/ld/testsuite/ld-riscv-elf/x-arcv-apex-02.d @@ -0,0 +1,36 @@ +#source: x-arcv-apex-01-a.s +#source: x-arcv-apex-01-b.s +#source: x-arcv-apex-01-c.s +#ld: -m[riscv_choose_64_or_32_emul] +#objdump: -D -j .text + +.*:[ ]+file format .* + + +Disassembly of section .text: + +0+[0-9a-f]+ <_start>: +#... + +0+[0-9a-f]+ : +[ ]+[0-9a-f]+:[ ]+00c5c50b[ ]+.* +[ ]+[0-9a-f]+:[ ]+02c5800b[ ]+.* +[ ]+[0-9a-f]+:[ ]+0205c00b[ ]+.* +[ ]+[0-9a-f]+:[ ]+0400000b[ ]+.* +[ ]+[0-9a-f]+:[ ]+0b15b50b[ ]+.* +[ ]+[0-9a-f]+:[ ]+0b15d00b[ ]+.* +[ ]+[0-9a-f]+:[ ]+0163a50b[ ]+.* +[ ]+[0-9a-f]+:[ ]+0164200b[ ]+.* +[ ]+[0-9a-f]+:[ ]+0214e50b[ ]+.* + +0+[0-9a-f]+ : +[ ]+[0-9a-f]+:[ ]+00c5c50b[ ]+.* +[ ]+[0-9a-f]+:[ ]+02c5800b[ ]+.* +[ ]+[0-9a-f]+:[ ]+0205c00b[ ]+.* +[ ]+[0-9a-f]+:[ ]+0400000b[ ]+.* +[ ]+[0-9a-f]+:[ ]+0b15b50b[ ]+.* +[ ]+[0-9a-f]+:[ ]+0b15d00b[ ]+.* +[ ]+[0-9a-f]+:[ ]+0163a50b[ ]+.* +[ ]+[0-9a-f]+:[ ]+0164200b[ ]+.* +[ ]+[0-9a-f]+:[ ]+0214e50b[ ]+.* +#pass diff --git a/opcodes/riscv-opc.c b/opcodes/riscv-opc.c index 54887c97880..a45b8aa5fc6 100644 --- a/opcodes/riscv-opc.c +++ b/opcodes/riscv-opc.c @@ -448,6 +448,146 @@ match_rd_x1x5_opcode (const struct riscv_opcode *op, return match_opcode (op, insn) && (rd == 1 || rd == 5); } +/* Invariant fields for dynamically allocated APEX opcodes (GAS / metadata). + Per-insn name, match, mask, and args are filled by arcv_apex_setup_* or + the XS|XC conversion path. */ + +static const struct riscv_opcode arcv_apex_dynamic_insn_proto = +{ + NULL, /* name. */ + 0, /* xlen_requirement. */ + INSN_CLASS_I, /* insn_class. */ + NULL, /* args. */ + 0, /* match. */ + 0, /* mask. */ + match_opcode, /* match_func. */ + 0 /* pinfo. */ +}; + +void +arcv_apex_init_dynamic_insn (struct riscv_opcode *insn) +{ + memcpy (insn, &arcv_apex_dynamic_insn_proto, sizeof (*insn)); +} + +/* Match only when rd != rs1. Used by the XS entry in an XS|XC pair so + that same-register operands always fall through to the XC encoding. */ + +int +arcv_apex_match_rd_ne_rs1 (const struct riscv_opcode *op, insn_t insn) +{ + int rd = (insn & MASK_RD) >> OP_SH_RD; + int rs1 = (insn & MASK_RS1) >> OP_SH_RS1; + return match_opcode (op, insn) && rd != rs1; +} + +/* Initialize an APEX instruction in XD format. + Sets mask, match, and operand argument string based on flags. + The flags APEX_FLAG_VOID, APEX_FLAG_NO_SRC0, and APEX_FLAG_NO_SRC1 + control which operands are present in the instruction definition. */ + +void +arcv_apex_setup_xd_insn (struct riscv_opcode *insn, + unsigned int flags, + unsigned int sub_opcode) +{ + insn->mask = ARCV_APEX_MASK_XD; + insn->match = ((uint32_t)(sub_opcode & 0xFE) << 24) + | ((uint32_t)(sub_opcode & 0x1) << 14) + | ARCV_APEX_CUSTOM0_OPCODE; + + /* Select operand pattern based on flags. + Operands use vendor prefix Xa (ARC-V APEX): + d = dest, s = src1, t = src2. */ + switch (flags & (APEX_FLAG_VOID | APEX_FLAG_NO_SRC0 | APEX_FLAG_NO_SRC1)) + { + case APEX_FLAG_NO_SRC1: + insn->args = "Xad,Xas"; + break; + case APEX_FLAG_NO_SRC0 | APEX_FLAG_NO_SRC1: + insn->args = "Xad"; + break; + case APEX_FLAG_VOID | APEX_FLAG_NO_SRC0 | APEX_FLAG_NO_SRC1: + insn->args = ""; + break; + case APEX_FLAG_VOID | APEX_FLAG_NO_SRC1: + insn->args = "Xas"; + break; + case APEX_FLAG_VOID: + insn->args = "Xas,Xat"; + break; + case 0: + insn->args = "Xad,Xas,Xat"; + break; + default: + insn->args = "Xad,Xas,Xat"; + break; + } +} + +/* Initialize an APEX instruction in XS format. + Sets mask, match, and operand argument string based on flags. + The APEX_FLAG_VOID flag controls whether the destination operand + is included. */ + +void +arcv_apex_setup_xs_insn (struct riscv_opcode *insn, + unsigned int flags, + unsigned int sub_opcode) +{ + insn->mask = ARCV_APEX_MASK_XS; + insn->match = ((uint32_t)(sub_opcode & 0x3C) << 18) + | ((uint32_t)(sub_opcode & 0x3) << 13) + | ARCV_APEX_CUSTOM0_OPCODE + | ARCV_APEX_XS_FIXED_BITS; + + /* Select operand pattern based on APEX_FLAG_VOID. + Operands: d = dest, s = src1, k = 8-bit immediate. */ + if (flags & APEX_FLAG_VOID) + insn->args = "Xas,Xak"; + else + insn->args = "Xad,Xas,Xak"; +} + +/* Initialize an APEX instruction in XI format. + Sets mask, match, and operand argument string based on flags. + The APEX_FLAG_VOID flag controls whether the destination operand + is included. */ + +void +arcv_apex_setup_xi_insn (struct riscv_opcode *insn, + unsigned int flags, + unsigned int sub_opcode) +{ + insn->mask = ARCV_APEX_MASK_XI; + insn->match = ((uint32_t)(sub_opcode & 0x1F) << 15) + | ARCV_APEX_CUSTOM0_OPCODE + | ARCV_APEX_XI_FIXED_BITS; + + if (flags & APEX_FLAG_VOID) + insn->args = "Xaj"; + else + insn->args = "Xad,Xaj"; +} + +/* Initialize an APEX instruction in XC format. + Sets mask and match. Set fixed operand argument string. + The XC form represents instructions where dest == src. */ + +void +arcv_apex_setup_xc_insn (struct riscv_opcode *insn, + unsigned int sub_opcode) +{ + insn->mask = ARCV_APEX_MASK_XC; + insn->match = ((uint32_t)(sub_opcode & 0x1F) << 15) + | ARCV_APEX_CUSTOM0_OPCODE + | ARCV_APEX_XC_FIXED_BITS; + + /* Fixed operand pattern for XC instructions: + dest, dest, 12-bit immediate (same encoding field as XI). */ + insn->args = "Xad,Xad,Xaj"; +} + const struct riscv_opcode riscv_opcodes[] = { /* name, xlen, isa, operands, match, mask, match_func, pinfo. */